Compare commits

..

113 Commits

Author SHA1 Message Date
Frank
43ab4d5f38 Update Warehouse.lua
- Removed trace output of qitem and queue because it stalls the game when written to log file
2024-12-18 22:04:38 +01:00
Applevangelist
0427c0d3a7 #CTLD - Added GetLoadedCargo(Unit) 2024-12-18 12:34:30 +01:00
Applevangelist
014750ea7f #SET - Documentation fixes 2024-12-18 11:35:13 +01:00
Applevangelist
e4bbfce314 #MANTIS
- Better status overview
- Some fixes for SHORAD setup
2024-12-17 12:45:45 +01:00
Applevangelist
359429b17e #GROUP added Teleport(Coordinate) function leveraging Respawn(). Now also translate routes if there are any. 2024-12-15 13:34:13 +01:00
Applevangelist
6001f6abda #EVENT - another fix for scenery without getName function 2024-12-15 11:41:24 +01:00
Applevangelist
fd9b5d8d16 #AIRBASE type fix for single Helipad 2024-12-15 11:33:01 +01:00
Frank
b6f184388a ATIS
- Fixed length of niner sound file
2024-12-15 10:00:59 +01:00
Frank
d8471698ab Merge pull request #2197 from FlightControl-Master/FF/MasterDevel
SPAWNSTATIC
2024-12-14 16:54:50 +01:00
Frank
6204cecbbd SPAWNSTATIC
- moved AddStatic to after static spawn fixing registration of spawned static
2024-12-14 16:54:39 +01:00
Frank
ddeca49916 Merge pull request #2196 from FlightControl-Master/FF/MasterDevel
DATABASE (fix for SPAWNSTATIC)
2024-12-14 13:48:40 +01:00
Frank
d8dcf37886 DATABASE
- Fixed error that static was not returned in `DATABASE:AddStatic()` (leads to issues if a static object with the same name is spawned)
- Other minor changes
2024-12-14 13:48:04 +01:00
Frank
5ae41a208b Merge branch 'master' into FF/MasterDevel 2024-12-14 11:29:57 +01:00
Applevangelist
0462d900e6 xx 2024-12-13 12:08:54 +01:00
Frank
0f962461e1 DCS Iraq update
- `AIRBASE`: Added Iraq airports to enums
- `ATIS`: Added missing maps to enums
- `UTILS`: Added missing maps to enums
2024-12-12 00:22:44 +01:00
Applevangelist
aadc03c38d #CTLD Added option/value for my_ctld.TroopUnloadDistHoverHook 2024-12-11 14:17:58 +01:00
Applevangelist
683fa13bb2 #WEAPON - fix for name not available on target 2024-12-11 13:57:55 +01:00
Applevangelist
e4408a964d #MANTIS - update CHM assets 2024-12-11 13:54:01 +01:00
Frank
f97f33ab59 ATIS v1.1.0
- Added dynamic fog
2024-12-06 00:09:15 +01:00
Frank
f59102ee09 Merge branch 'master' into FF/MasterDevel 2024-12-05 21:06:06 +01:00
Frank
e42e4e1ddf Merge branch 'master' into FF/MasterDevel 2024-12-03 21:15:46 +01:00
Thomas
a30079c45b Update Mantis.lua
Less noise
2024-12-03 18:07:38 +01:00
Applevangelist
50ffd9aba6 #MANTIS - Correct detail data check is run even if automode isn't defined 2024-11-30 16:19:51 +01:00
Frank
936fec1f49 Update Range.lua 2024-11-26 23:06:31 +01:00
Applevangelist
9625d87dd5 #NET - fix for net.force_player_slot(PlayerID, SideID, SlotID ) not working at all - destroy blocked client instead 2024-11-26 10:43:20 +01:00
Frank
802139205c Update Unit.lua
- Fixed bug in `UNIT:GetDCSObject()` when DCS unit does not exist.
2024-11-24 21:54:05 +01:00
Frank
fb918cb2a4 Update DCS.lua 2024-11-21 23:43:58 +01:00
Frank
abb4de46d7 Controllable Detection Improvements/Fixes
- Fixed bug in detection functions for optical detection (enum incorrect)
- Fixed bug in order of return values of `CONTROLLABLE:IsTargetDetected` (both hoggit and DCS are WRONG and MOOSE adopted it).
2024-11-21 23:13:05 +01:00
Frank
dce9631399 Update Event.lua
- Set `Event.IniGroupName` from db in case group does not exist any more
2024-11-15 23:21:50 +01:00
Thomas
6c773786d2 Merge pull request #2186 from FlightControl-Master/Applevangelist-patch-2
Update Enums.lua
2024-11-10 13:46:00 +01:00
Thomas
8939963187 Update Enums.lua
OH58d weapons
2024-11-10 13:45:44 +01:00
Thomas
f9747d1c4c Merge pull request #2184 from FlightControl-Master/Applevangelist-pwsh-1
Update SRS.lua
2024-11-04 14:49:56 +01:00
Thomas
60a3d3409e Update SRS.lua
#MSRS Test to get the pwsh window to minimize
2024-11-04 14:49:26 +01:00
Applevangelist
b72124c0d9 #CONTROLLABLE Corrected parameter omissions 2024-10-31 18:16:02 +01:00
Applevangelist
d51e761b26 #CONTROLLABLE - Rollback changes for EPLRS command 2024-10-31 16:05:24 +01:00
Applevangelist
1445ef61a0 #AIRBASE - added bases from 2.9.9.2280 2024-10-30 17:09:38 +01:00
Applevangelist
dfe2ed2a98 #EVENT - Fix for TgtUnit Name being unobtainable 2024-10-29 13:57:21 +01:00
Applevangelist
be87103b53 #CTLD - fixed a collision when extracting on a possible distance key duplication 2024-10-29 13:18:55 +01:00
Applevangelist
2fb460c4bb #ATC_Ground - stop kicking players immediately for speeding 2024-10-29 11:37:06 +01:00
Applevangelist
216ea230a8 #BASE - Roll back to "old" serialize method for Trace 2024-10-27 13:25:13 +01:00
Applevangelist
90096163ee EPLRS - give group ID only if ground 2024-10-26 18:45:01 +02:00
Thomas
cd178d6a8c Merge pull request #2182 from FlightControl-Master/Applevangelist-patch-1
Update MarkerOps_Base.lua
2024-10-21 11:33:14 +02:00
Thomas
2aa0b5ddfb Update MarkerOps_Base.lua
Added data to FSM events
2024-10-21 11:32:47 +02:00
Applevangelist
37f819458a #AIRBOSS - Change event Land to event RunwayTouch 2024-10-11 08:06:05 +02:00
Applevangelist
168f4301d2 #GROUP - extended options to create callsigns for TTS with own function 2024-10-08 10:05:31 +02:00
Applevangelist
d5a406c60f #MSRS experimental - option to use PowerShell to execute SRS-TTS - set MSRS.UsePowerShell = true to test it. Known issue - PS window does not close until everything is executed. 2024-10-03 14:05:51 +02:00
Applevangelist
cb16210577 #SEAD - better event management of weapons, return earlier if no (H)ARM, return if SEAD Plane is nil 2024-10-03 14:03:06 +02:00
Applevangelist
8c0e0de45f xx 2024-10-01 12:10:21 +02:00
Applevangelist
3524cba4ef xx 2024-10-01 12:08:51 +02:00
Frank
5f8d1cf5b0 Update Warehouse.lua
- Added check for incorrect plane attribute
2024-10-01 09:07:51 +02:00
Applevangelist
846aa823d4 fixes for #SEAD and #SPAWN 2024-09-30 11:35:25 +02:00
Applevangelist
68298fc585 #EVENT Fix for scenery sometimes nit having a getName() function 2024-09-27 11:57:40 +02:00
Applevangelist
e9d75f6d94 #CSAR Beacon Name Fix 2024-09-26 09:06:57 +02:00
Thomas
8fa5277417 Merge pull request #2178 from brykeller/patch-2
Kiowa rescues sit on the skids, no doors need to be opened
2024-09-26 06:55:02 +02:00
Thomas
231f1f236d Merge pull request #2180 from brykeller/patch-3
Update CTLD.lua to update the correct Kiowa typename to OH58D
2024-09-26 06:53:21 +02:00
Bryan Keller
ece0a46f97 Update CTLD.lua to update the correct Kiowa typename to OH58D
Update CTLD.lua to update the correct Kiowa typename to OH58D
2024-09-25 18:59:26 -07:00
Bryan Keller
2c9b0b8376 Kiowa rescues sit on the skids, no doors need to be opened
Kiowa rescues sit on the skids, no doors need to be opened
2024-09-25 18:51:31 -07:00
Applevangelist
a798f2d61c Small fixes 2024-09-23 12:43:39 +02:00
Applevangelist
ae08c87822 #CTLD 2024-09-15 19:24:24 +02:00
Thomas
ae880e9d1c Merge pull request #2176 from Maintenance-Partnership-Systems/Minor-Doco-Fixes
Minor doco fixes
2024-09-15 11:16:08 +02:00
Michael Barnes
101d2e1de5 More incorrect AIRBASE constants in examples. 2024-09-15 18:48:42 +10:00
Michael Barnes
f6b7708567 Fixed some outdated references to AIRBASE constants in examples. 2024-09-15 18:34:18 +10:00
Applevangelist
051286acd1 #SPAWN - Tuning measures from DEVELOP encorporated 2024-09-08 13:24:09 +02:00
Applevangelist
7f572a1a9b Small changes
#CSAR - add option for IR strobe
2024-09-08 13:22:10 +02:00
Applevangelist
d62025dfe0 Small fixes 2024-09-08 11:43:33 +02:00
Thomas
07009630c6 Update CSAR.lua
Small fix
2024-09-07 09:01:58 +02:00
Applevangelist
865042a843 #CTLD #CSAR Function to add own SET_GROUP for pilots 2024-09-06 16:40:41 +02:00
Applevangelist
f00d0dc871 QoL 2024-09-06 13:40:27 +02:00
Applevangelist
d6adcdf8bd #CONTROLLABLE - Added IR Marker Beacons for UNIT and GROUP objects 2024-09-01 15:36:41 +02:00
Applevangelist
2c192fba30 #SET - include checking functional filters in all sub-classes 2024-09-01 13:36:47 +02:00
Applevangelist
97f11c93bb #CTLD 2024-09-01 12:41:36 +02:00
Applevangelist
f531fdaa70 #RANGE less noise 2024-08-29 10:25:13 +02:00
Applevangelist
81f8e84ca4 xx 2024-08-29 10:22:14 +02:00
Applevangelist
d74de11b8b CTLD small fix of container shape 2024-08-27 18:37:21 +02:00
Applevangelist
30f2097d7a #AIRBOSS - small fix in Numer2Sound etc 2024-08-27 13:18:53 +02:00
Applevangelist
f903844059 #CTLD - fix for type name restrictions in other functions 2024-08-27 10:56:14 +02:00
Applevangelist
68b2b452cc xx 2024-08-26 18:30:41 +02:00
Applevangelist
668d120d60 CTLD Small fix for crate removal 2024-08-26 18:22:32 +02:00
Applevangelist
7543f31c85 #CTLD
* Added option for crates to have any static shape (per crate type option)
* Added option for crates only to be transported by defined helo type names (per crate type option)
2024-08-26 15:52:50 +02:00
Thomas
56d84e7b25 Update Utils.lua
Small fix
2024-08-25 11:22:30 +02:00
Applevangelist
ed2d3d856b Small fix 2024-08-24 18:18:08 +02:00
Applevangelist
1e5c3a3c21 #ENUMS storage AH64D weapons additions 2024-08-23 16:28:35 +02:00
Applevangelist
37d5b6a0fc #Add'l storage items 2024-08-23 13:55:18 +02:00
Applevangelist
c58a954d18 #CTLD
* Fix for spawning the correct number of crates on inject
* Simplified example docu section 7 on how to build a FARP
* Some prep work for additional stuff
2024-08-23 12:44:17 +02:00
Applevangelist
0d481afa16 #SET_GROUP - small fix for FilterPrefixes compute 2024-08-22 18:26:34 +02:00
Applevangelist
016875d724 #ENUMS - added a couple of items to ENUMS.Storage.weapons for the Gazelle and CH-47 which do not have a name representation in the object warehouse
#UTILS Added function `UTILS.SpawnFARPAndFunctionalStatics()` to spawn a functional FARP with static items (and some options)
#UTILS Added VHF Beacon Frequencies for newer maps to avoid overlaps in `UTILS.GenerateVHFrequencies()`
2024-08-22 17:17:10 +02:00
Applevangelist
5df0d60135 Smaller Fixes 2024-08-20 18:03:18 +02:00
Applevangelist
e77d61c4cb small correction 2024-08-20 10:55:41 +02:00
Applevangelist
504142c585 #CTLD Added self.TroopUnloadDistGround = 1.5, and self.TroopUnloadDistHover = 5,
#CSAR Added option to switch off ADF beacons
2024-08-20 10:47:28 +02:00
Applevangelist
80df849d18 #SET_GROUP small enhancement for prefix filter 2024-08-18 19:37:00 +02:00
Frank
e74c79b5d6 Merge branch 'master' of https://github.com/FlightControl-Master/MOOSE 2024-08-18 16:56:44 +02:00
Frank
f738ddfca8 Update Positionable.lua
- Added cargo bay of "MaxxPro_MRAP"
2024-08-18 16:56:42 +02:00
Applevangelist
af45b0d709 #EVENT DynamicCargoRemove fix is name is empty 2024-08-18 14:08:46 +02:00
Applevangelist
e746617139 #Rap up changes 2024-08-18 13:58:18 +02:00
Thomas
3105f7407d Merge pull request #2169 from FlightControl-Master/Applevangelist-patch-1
Update ATIS.lua
2024-08-18 13:14:13 +02:00
Thomas
2f568bca17 Update ATIS.lua
#ATIS New Light Rain presets
2024-08-18 13:11:58 +02:00
Applevangelist
aeb1664134 CTLD 2024-08-17 11:36:01 +02:00
Frank
b7702ab933 Merge pull request #2166 from FlightControl-Master/Statua-patch-1
Update ClientWatch.lua
2024-08-16 23:10:25 +02:00
Statua
cc14f82e85 Update ClientWatch.lua
-Added check to verify the aircraft is controlled by a player
-Added :FilterByCoalition() and :FilterByCategory()
-Added ability to get ALL CLIENTS by leaving param1 of :New() blank
-Added more console outputs if CLIENTWATCH.Debug is true
-Minor documentation fixes
2024-08-16 15:19:26 -05:00
Applevangelist
5aea17e20e #SET_DYNAMICCARGO Docu 2024-08-16 16:23:13 +02:00
Applevangelist
ad9eaea010 #SET - many less calls 2024-08-16 15:46:07 +02:00
Applevangelist
284a770daa Added #SET_DYNAMICCARGO 2024-08-16 15:21:46 +02:00
Applevangelist
ccd190a8b1 xx 2024-08-16 09:44:00 +02:00
Applevangelist
19f6a8d8f6 #DYNAMICCARGO - Added functionalty 2024-08-16 09:36:29 +02:00
Applevangelist
24264bd885 #ATIS French Translations 2024-08-14 15:42:46 +02:00
Applevangelist
872bb3d775 #RANGE Fix trying to get a playername on dynamic cargo spawns 2024-08-14 11:33:13 +02:00
Applevangelist
d36cd8e284 #UNIT - Fix getting skill from N/A Templates 2024-08-14 09:46:10 +02:00
Applevangelist
eab643268f #ATIS - Polar circle fixes 2024-08-13 10:30:46 +02:00
Applevangelist
9356794112 bit of performance tuning 2024-08-12 19:05:32 +02:00
Applevangelist
35c24810f9 xx 2024-08-12 17:00:52 +02:00
Thomas
a54944b021 Update CTLD.lua (#2164)
#CTLD 
* Fix for helo being no Chinook not finding crates e.g. on a ship or FARP
* `nil` check for static cargo position check
2024-08-12 11:39:03 +02:00
Thomas
bc9938d08a Update Spawn.lua (#2161)
Updating this class as it calls BASE I,F,T a lot. Making it less noisy for some performance tuning
2024-08-12 10:16:40 +02:00
Thomas
b77f179acc Update Base.lua (#2159)
Performance tuning - the BASE:I, F, T calls rank very high in overall number of calls taken from Moose. Ensure only the minimum number of actions based on trace state and level is taken
2024-08-12 09:44:13 +02:00
137 changed files with 5867 additions and 89288 deletions

View File

@@ -57,7 +57,6 @@ jobs:
- name: Update apt-get (needed for act docker image)
run: |
sudo rm /etc/apt/sources.list.d/microsoft-prod.list
sudo apt-get -qq update
- name: Install tree

View File

@@ -110,7 +110,7 @@ jobs:
- name: Run LuaSrcDiet
run: |
luasrcdiet --basic --opt-emptylines ./build/result/Moose_Include_Static/Moose.lua -o ./build/result/Moose_Include_Static/Moose_.lua
#########################################################################
# Push to MOOSE_INCLUDE
#########################################################################

7
.gitignore vendored
View File

@@ -28,13 +28,6 @@ local.properties
.buildpath
#####################
## Visual Studio Code
#####################
*.code-workspace
.vscode/
#################
## Visual Studio
#################

View File

@@ -1,17 +1,7 @@
{
"Lua.workspace.preloadFileSize": 10000,
"Lua.workspace.preloadFileSize": 1000,
"Lua.diagnostics.disable": [
"undefined-doc-name",
"duplicate-set-field",
"trailing-space",
"need-check-nil",
"ambiguity-1",
"undefined-doc-param",
"redundant-parameter",
"param-type-mismatch",
"deprecated",
"undefined-global",
"lowercase-global"
"undefined-doc-name"
],
"Lua.diagnostics.globals": [
"BASE",

View File

@@ -11,7 +11,7 @@
-- @module AI.AI_A2A_Cap
-- @image AI_Combat_Air_Patrol.JPG
-- @type AI_A2A_CAP
--- @type AI_A2A_CAP
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE

View File

@@ -13,8 +13,8 @@
-- @type AI_A2A_GCI
-- @extends AI.AI_A2A#AI_A2A
--- @type AI_A2A_GCI
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
@@ -39,8 +39,6 @@
--
-- ## 2. AI_A2A_GCI is a FSM
--
-- ![Process](..\Presentations\AI_GCI\Dia2.JPG)
--
-- ### 2.1 AI_A2A_GCI States
--
-- * **None** ( Group ): The process is not started yet.

View File

@@ -10,8 +10,8 @@
-- @image AI_Air_Patrolling.JPG
-- @type AI_A2A_PATROL
-- @extends AI.AI_A2A#AI_A2A
--- @type AI_A2A_PATROL
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}.
--

View File

@@ -11,8 +11,9 @@
-- @module AI.AI_A2G_BAI
-- @image AI_Air_To_Ground_Engage.JPG
-- @type AI_A2G_BAI
-- @extends AI.AI_A2A_Engage#AI_A2A_Engage -- TODO: Documentation. This class does not exist, unable to determine what it extends.
--- @type AI_A2G_BAI
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
--
@@ -46,7 +47,7 @@ AI_A2G_BAI = {
function AI_A2G_BAI:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
local AI_Air = AI_AIR:New( AIGroup )
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
local self = BASE:Inherit( self, AI_Air_Engage )

View File

@@ -11,8 +11,9 @@
-- @module AI.AI_A2G_CAS
-- @image AI_Air_To_Ground_Engage.JPG
-- @type AI_A2G_CAS
-- @extends AI.AI_A2G_Patrol#AI_AIR_PATROL TODO: Documentation. This class does not exist, unable to determine what it extends.
--- @type AI_A2G_CAS
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
--
@@ -46,7 +47,7 @@ AI_A2G_CAS = {
function AI_A2G_CAS:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
local AI_Air = AI_AIR:New( AIGroup )
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
local self = BASE:Inherit( self, AI_Air_Engage )

View File

@@ -3895,10 +3895,14 @@ do -- AI_A2G_DISPATCHER
if Squadron then
local FirstUnit = AttackSetUnit:GetRandomSurely()
if FirstUnit then
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
if self.SetSendPlayerMessages then
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", on route to ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
end
else
return
end
end
self:GetParent(self).onafterEngageRoute( self, DefenderGroup, From, Event, To, AttackSetUnit )
end
@@ -4784,4 +4788,5 @@ end
Squadron.ResourceCount = Squadron.ResourceCount - Amount
end
self:T({Squadron = Squadron.Name,SquadronResourceCount = Squadron.ResourceCount})
end
end

View File

@@ -13,8 +13,9 @@
-- @type AI_A2G_SEAD
-- @extends AI.AI_A2G_Patrol#AI_AIR_PATROL
--- @type AI_A2G_SEAD
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
--- Implements the core functions to SEAD intruders. Use the Engage trigger to intercept intruders.

View File

@@ -9,6 +9,7 @@
-- @module AI.AI_Air
-- @image MOOSE.JPG
---
-- @type AI_AIR
-- @extends Core.Fsm#FSM_CONTROLLABLE

View File

@@ -9,7 +9,7 @@
-- @module AI.AI_Air_Patrol
-- @image AI_Air_To_Ground_Patrol.JPG
-- @type AI_AIR_PATROL
--- @type AI_AIR_PATROL
-- @extends AI.AI_Air#AI_AIR
--- The AI_AIR_PATROL class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group}

View File

@@ -408,7 +408,7 @@ function AI_BAI_ZONE:onafterStart( Controllable, From, Event, To )
self:SetDetectionDeactivated() -- When not engaging, set the detection off.
end
-- @param Wrapper.Controllable#CONTROLLABLE AIControllable
--- @param Wrapper.Controllable#CONTROLLABLE AIControllable
function _NewEngageRoute( AIControllable )
AIControllable:T( "NewEngageRoute" )
@@ -417,7 +417,7 @@ function _NewEngageRoute( AIControllable )
end
-- @param #AI_BAI_ZONE self
--- @param #AI_BAI_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -429,7 +429,7 @@ function AI_BAI_ZONE:onbeforeEngage( Controllable, From, Event, To )
end
end
-- @param #AI_BAI_ZONE self
--- @param #AI_BAI_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -478,7 +478,7 @@ function AI_BAI_ZONE:onafterTarget( Controllable, From, Event, To )
end
-- @param #AI_BAI_ZONE self
--- @param #AI_BAI_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -488,7 +488,7 @@ function AI_BAI_ZONE:onafterAbort( Controllable, From, Event, To )
self:__Route( 1 )
end
-- @param #AI_BAI_ZONE self
--- @param #AI_BAI_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -612,7 +612,7 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
end
-- @param #AI_BAI_ZONE self
--- @param #AI_BAI_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -623,7 +623,7 @@ function AI_BAI_ZONE:onafterAccomplish( Controllable, From, Event, To )
end
-- @param #AI_BAI_ZONE self
--- @param #AI_BAI_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -637,7 +637,7 @@ function AI_BAI_ZONE:onafterDestroy( Controllable, From, Event, To, EventData )
end
-- @param #AI_BAI_ZONE self
--- @param #AI_BAI_ZONE self
-- @param Core.Event#EVENTDATA EventData
function AI_BAI_ZONE:OnEventDead( EventData )
self:F( { "EventDead", EventData } )

View File

@@ -27,7 +27,7 @@
-- @module AI.AI_Balancer
-- @image AI_Balancing.JPG
-- @type AI_BALANCER
--- @type AI_BALANCER
-- @field Core.Set#SET_CLIENT SetClient
-- @field Core.Spawn#SPAWN SpawnAI
-- @field Wrapper.Group#GROUP Test

View File

@@ -31,7 +31,7 @@
-- @module AI.AI_CAP
-- @image AI_Combat_Air_Patrol.JPG
-- @type AI_CAP_ZONE
--- @type AI_CAP_ZONE
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
-- @field Core.Zone#ZONE_BASE TargetZone The @{Core.Zone} where the patrol needs to be executed.
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
@@ -344,7 +344,7 @@ function AI_CAP_ZONE:onafterStart( Controllable, From, Event, To )
end
-- @param AI.AI_CAP#AI_CAP_ZONE
--- @param AI.AI_CAP#AI_CAP_ZONE
-- @param Wrapper.Group#GROUP EngageGroup
function AI_CAP_ZONE.EngageRoute( EngageGroup, Fsm )
@@ -355,7 +355,7 @@ function AI_CAP_ZONE.EngageRoute( EngageGroup, Fsm )
end
end
-- @param #AI_CAP_ZONE self
--- @param #AI_CAP_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -367,7 +367,7 @@ function AI_CAP_ZONE:onbeforeEngage( Controllable, From, Event, To )
end
end
-- @param #AI_CAP_ZONE self
--- @param #AI_CAP_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -395,7 +395,7 @@ function AI_CAP_ZONE:onafterDetected( Controllable, From, Event, To )
end
end
-- @param #AI_CAP_ZONE self
--- @param #AI_CAP_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -405,7 +405,7 @@ function AI_CAP_ZONE:onafterAbort( Controllable, From, Event, To )
self:__Route( 1 )
end
-- @param #AI_CAP_ZONE self
--- @param #AI_CAP_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -505,7 +505,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
end
end
-- @param #AI_CAP_ZONE self
--- @param #AI_CAP_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -515,7 +515,7 @@ function AI_CAP_ZONE:onafterAccomplish( Controllable, From, Event, To )
self:SetDetectionOff()
end
-- @param #AI_CAP_ZONE self
--- @param #AI_CAP_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -528,7 +528,7 @@ function AI_CAP_ZONE:onafterDestroy( Controllable, From, Event, To, EventData )
end
end
-- @param #AI_CAP_ZONE self
--- @param #AI_CAP_ZONE self
-- @param Core.Event#EVENTDATA EventData
function AI_CAP_ZONE:OnEventDead( EventData )
self:F( { "EventDead", EventData } )

View File

@@ -363,7 +363,7 @@ function AI_CAS_ZONE:onafterStart( Controllable, From, Event, To )
self:SetDetectionDeactivated() -- When not engaging, set the detection off.
end
-- @param AI.AI_CAS#AI_CAS_ZONE
--- @param AI.AI_CAS#AI_CAS_ZONE
-- @param Wrapper.Group#GROUP EngageGroup
function AI_CAS_ZONE.EngageRoute( EngageGroup, Fsm )
@@ -375,7 +375,7 @@ function AI_CAS_ZONE.EngageRoute( EngageGroup, Fsm )
end
-- @param #AI_CAS_ZONE self
--- @param #AI_CAS_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -387,7 +387,7 @@ function AI_CAS_ZONE:onbeforeEngage( Controllable, From, Event, To )
end
end
-- @param #AI_CAS_ZONE self
--- @param #AI_CAS_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -420,7 +420,7 @@ function AI_CAS_ZONE:onafterTarget( Controllable, From, Event, To )
end
-- @param #AI_CAS_ZONE self
--- @param #AI_CAS_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -430,7 +430,7 @@ function AI_CAS_ZONE:onafterAbort( Controllable, From, Event, To )
self:__Route( 1 )
end
-- @param #AI_CAS_ZONE self
--- @param #AI_CAS_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -530,7 +530,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
end
-- @param #AI_CAS_ZONE self
--- @param #AI_CAS_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -541,7 +541,7 @@ function AI_CAS_ZONE:onafterAccomplish( Controllable, From, Event, To )
end
-- @param #AI_CAS_ZONE self
--- @param #AI_CAS_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -555,7 +555,7 @@ function AI_CAS_ZONE:onafterDestroy( Controllable, From, Event, To, EventData )
end
-- @param #AI_CAS_ZONE self
--- @param #AI_CAS_ZONE self
-- @param Core.Event#EVENTDATA EventData
function AI_CAS_ZONE:OnEventDead( EventData )
self:F( { "EventDead", EventData } )

View File

@@ -9,7 +9,7 @@
-- @module AI.AI_Cargo_APC
-- @image AI_Cargo_Dispatching_For_APC.JPG
-- @type AI_CARGO_APC
--- @type AI_CARGO_APC
-- @extends AI.AI_Cargo#AI_CARGO

View File

@@ -9,7 +9,7 @@
-- @module AI.AI_Cargo_Airplane
-- @image AI_Cargo_Dispatching_For_Airplanes.JPG
-- @type AI_CARGO_AIRPLANE
--- @type AI_CARGO_AIRPLANE
-- @extends Core.Fsm#FSM_CONTROLLABLE

View File

@@ -30,7 +30,7 @@
-- @module AI.AI_Cargo_Dispatcher_APC
-- @image AI_Cargo_Dispatching_For_APC.JPG
-- @type AI_CARGO_DISPATCHER_APC
--- @type AI_CARGO_DISPATCHER_APC
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER

View File

@@ -24,7 +24,7 @@
-- @image AI_Cargo_Dispatching_For_Airplanes.JPG
-- @type AI_CARGO_DISPATCHER_AIRPLANE
--- @type AI_CARGO_DISPATCHER_AIRPLANE
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER

View File

@@ -25,7 +25,7 @@
-- @module AI.AI_Cargo_Dispatcher_Helicopter
-- @image AI_Cargo_Dispatching_For_Helicopters.JPG
-- @type AI_CARGO_DISPATCHER_HELICOPTER
--- @type AI_CARGO_DISPATCHER_HELICOPTER
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER

View File

@@ -23,7 +23,7 @@
-- @module AI.AI_Cargo_Dispatcher_Ship
-- @image AI_Cargo_Dispatcher.JPG
-- @type AI_CARGO_DISPATCHER_SHIP
--- @type AI_CARGO_DISPATCHER_SHIP
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER
@@ -160,7 +160,7 @@ AI_CARGO_DISPATCHER_SHIP = {
-- local SetPickupZones = SET_ZONE:New():FilterPrefixes( "Pickup" ):FilterStart()
-- local SetDeployZones = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
-- NEED MORE THOUGHT - ShippingLane is part of Warehouse.......
-- local ShippingLane = SET_GROUP:New():FilterPrefixes( "ShippingLane" ):FilterOnce():GetSetObjects()
-- local ShippingLane = GROUP:New():FilterPrefixes( "ShippingLane" ):FilterStart()
--
-- AICargoDispatcherShip = AI_CARGO_DISPATCHER_SHIP:New( SetShip, SetCargoInfantry, SetPickupZones, SetDeployZones, ShippingLane )
-- AICargoDispatcherShip:Start()

View File

@@ -9,7 +9,7 @@
-- @module AI.AI_Cargo_Helicopter
-- @image AI_Cargo_Dispatching_For_Helicopters.JPG
-- @type AI_CARGO_HELICOPTER
--- @type AI_CARGO_HELICOPTER
-- @extends Core.Fsm#FSM_CONTROLLABLE
@@ -287,7 +287,7 @@ function AI_CARGO_HELICOPTER:SetLandingSpeedAndHeight(speed, height)
return self
end
-- @param #AI_CARGO_HELICOPTER self
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @param From
-- @param Event
@@ -326,7 +326,7 @@ function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To )
end
-- @param #AI_CARGO_HELICOPTER self
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @param From
-- @param Event
@@ -409,7 +409,7 @@ function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordina
end
-- @param #AI_CARGO_HELICOPTER self
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @param From
-- @param Event

View File

@@ -9,7 +9,7 @@
-- @module AI.AI_Cargo_Ship
-- @image AI_Cargo_Dispatcher.JPG
-- @type AI_CARGO_SHIP
--- @type AI_CARGO_SHIP
-- @extends AI.AI_Cargo#AI_CARGO
--- Brings a dynamic cargo handling capability for an AI naval group.

View File

@@ -15,7 +15,7 @@
-- @image MOOSE.JPG
-- @type AI_ESCORT_DISPATCHER_REQUEST
--- @type AI_ESCORT_DISPATCHER_REQUEST
-- @extends Core.Fsm#FSM
@@ -33,7 +33,7 @@ AI_ESCORT_DISPATCHER_REQUEST = {
ClassName = "AI_ESCORT_DISPATCHER_REQUEST",
}
-- @field #list
--- @field #list
AI_ESCORT_DISPATCHER_REQUEST.AI_Escorts = {}
@@ -80,7 +80,7 @@ function AI_ESCORT_DISPATCHER_REQUEST:onafterStart( From, Event, To )
end
-- @param #AI_ESCORT_DISPATCHER_REQUEST self
--- @param #AI_ESCORT_DISPATCHER_REQUEST self
-- @param Core.Event#EVENTDATA EventData
function AI_ESCORT_DISPATCHER_REQUEST:OnEventExit( EventData )
@@ -97,7 +97,7 @@ function AI_ESCORT_DISPATCHER_REQUEST:OnEventExit( EventData )
end
-- @param #AI_ESCORT_DISPATCHER_REQUEST self
--- @param #AI_ESCORT_DISPATCHER_REQUEST self
-- @param Core.Event#EVENTDATA EventData
function AI_ESCORT_DISPATCHER_REQUEST:OnEventBirth( EventData )

View File

@@ -136,12 +136,12 @@
--
-- Escort groups can have their own mission. This menu item will allow the escort group to resume their Mission from a given waypoint.
-- Note that this is really fantastic, as you now have the dynamic of taking control of the escort groups, and allowing them to resume their path or mission.
--
-- # Developer Note
--
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
-- Therefore, this class is considered to be deprecated
--
--
-- # Developer Note
--
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
-- Therefore, this class is considered to be deprecated
--
-- ===
--
-- ### Authors: **FlightControl**
@@ -153,7 +153,7 @@
-- @type AI_ESCORT_REQUEST
--- @type AI_ESCORT_REQUEST
-- @extends AI.AI_Escort#AI_ESCORT
--- AI_ESCORT_REQUEST class
@@ -228,7 +228,7 @@ function AI_ESCORT_REQUEST:New( EscortUnit, EscortSpawn, EscortAirbase, EscortNa
return self
end
-- @param #AI_ESCORT_REQUEST self
--- @param #AI_ESCORT_REQUEST self
function AI_ESCORT_REQUEST:SpawnEscort()
local EscortGroup = self.EscortSpawn:SpawnAtAirbase( self.EscortAirbase, SPAWN.Takeoff.Hot )
@@ -253,7 +253,7 @@ function AI_ESCORT_REQUEST:SpawnEscort()
self:_InitEscortMenus( EscortGroup )
self:_InitEscortRoute( EscortGroup )
-- @param #AI_ESCORT self
--- @param #AI_ESCORT self
-- @param Core.Event#EVENTDATA EventData
function EscortGroup:OnEventDeadOrCrash( EventData )
self:F( { "EventDead", EventData } )
@@ -268,7 +268,7 @@ function AI_ESCORT_REQUEST:SpawnEscort()
end
-- @param #AI_ESCORT_REQUEST self
--- @param #AI_ESCORT_REQUEST self
-- @param Core.Set#SET_GROUP EscortGroupSet
function AI_ESCORT_REQUEST:onafterStart( EscortGroupSet )
@@ -290,14 +290,14 @@ function AI_ESCORT_REQUEST:onafterStart( EscortGroupSet )
end
-- @param #AI_ESCORT_REQUEST self
--- @param #AI_ESCORT_REQUEST self
-- @param Core.Set#SET_GROUP EscortGroupSet
function AI_ESCORT_REQUEST:onafterStop( EscortGroupSet )
self:F()
EscortGroupSet:ForEachGroup(
-- @param Core.Group#GROUP EscortGroup
--- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup )
EscortGroup:WayPointInitialize()

View File

@@ -34,8 +34,8 @@
-- @field Core.Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class.
-- @field #number FollowDistance The current follow distance.
-- @field #boolean ReportTargets If true, nearby targets are reported.
-- @Field DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the FollowGroup.
-- @field DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the FollowGroup.
-- @field DCS#AI.Option.Air.val.ROE OptionROE Which ROE is set to the FollowGroup.
-- @field DCS#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the FollowGroup.
-- @field #number dtFollow Time step between position updates.
@@ -92,12 +92,12 @@
-- local LargeFormation = AI_FORMATION:New( LeaderUnit, FollowGroupSet, "Center Wing Formation", "Briefing" )
-- LargeFormation:FormationCenterWing( 500, 50, 0, 250, 250 )
-- LargeFormation:__Start( 1 )
--
-- # Developer Note
--
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
-- Therefore, this class is considered to be deprecated
--
--
-- # Developer Note
--
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
-- Therefore, this class is considered to be deprecated
--
-- @field #AI_FORMATION
AI_FORMATION = {
ClassName = "AI_FORMATION",
@@ -117,7 +117,7 @@ AI_FORMATION = {
AI_FORMATION.__Enum = {}
-- @type AI_FORMATION.__Enum.Formation
--- @type AI_FORMATION.__Enum.Formation
-- @field #number None
-- @field #number Line
-- @field #number Trail
@@ -142,7 +142,7 @@ AI_FORMATION.__Enum.Formation = {
Box = 10,
}
-- @type AI_FORMATION.__Enum.Mode
--- @type AI_FORMATION.__Enum.Mode
-- @field #number Mission
-- @field #number Formation
AI_FORMATION.__Enum.Mode = {
@@ -152,13 +152,13 @@ AI_FORMATION.__Enum.Mode = {
Reconnaissance = "R",
}
-- @type AI_FORMATION.__Enum.ReportType
--- @type AI_FORMATION.__Enum.ReportType
-- @field #number All
-- @field #number Airborne
-- @field #number GroundRadar
-- @field #number Ground
AI_FORMATION.__Enum.ReportType = {
All = "*",
Airborne = "*",
Airborne = "A",
GroundRadar = "R",
Ground = "G",
@@ -996,7 +996,7 @@ function AI_FORMATION:SetFlightModeMission( FollowGroup )
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission )
else
self.FollowGroupSet:ForSomeGroupAlive(
-- @param Core.Group#GROUP EscortGroup
--- @param Wrapper.Group#GROUP EscortGroup
function( FollowGroup )
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission )
@@ -1020,7 +1020,7 @@ function AI_FORMATION:SetFlightModeAttack( FollowGroup )
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Attack )
else
self.FollowGroupSet:ForSomeGroupAlive(
-- @param Core.Group#GROUP EscortGroup
--- @param Wrapper.Group#GROUP EscortGroup
function( FollowGroup )
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Attack )
@@ -1044,7 +1044,7 @@ function AI_FORMATION:SetFlightModeFormation( FollowGroup )
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation )
else
self.FollowGroupSet:ForSomeGroupAlive(
-- @param Core.Group#GROUP EscortGroup
--- @param Wrapper.Group#GROUP EscortGroup
function( FollowGroup )
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation )
@@ -1222,7 +1222,7 @@ function AI_FORMATION:FollowMe(FollowGroup, ClientUnit, CT1, CV1, CT2, CV2)
local CVI = {
x = CV2.x + CS * 10 * math.sin(Ca),
y = GH2.y + Inclination, -- + FollowFormation.y,
--y = GH2.y,
y = GH2.y,
z = CV2.z + CS * 10 * math.cos(Ca),
}

View File

@@ -274,7 +274,7 @@ do -- ACT_ACCOUNT_DEADS
--- DCS Events
-- @param #ACT_ACCOUNT_DEADS self
--- @param #ACT_ACCOUNT_DEADS self
-- @param Core.Event#EVENTDATA EventData
function ACT_ACCOUNT_DEADS:OnEventHit( EventData )
self:T( { "EventDead", EventData } )
@@ -285,7 +285,7 @@ do -- ACT_ACCOUNT_DEADS
end
end
-- @param #ACT_ACCOUNT_DEADS self
--- @param #ACT_ACCOUNT_DEADS self
-- @param Core.Event#EVENTDATA EventData
function ACT_ACCOUNT_DEADS:onfuncEventDead( EventData )
self:T( { "EventDead", EventData } )
@@ -297,7 +297,7 @@ do -- ACT_ACCOUNT_DEADS
--- DCS Events
-- @param #ACT_ACCOUNT_DEADS self
--- @param #ACT_ACCOUNT_DEADS self
-- @param Core.Event#EVENTDATA EventData
function ACT_ACCOUNT_DEADS:onfuncEventCrash( EventData )
self:T( { "EventDead", EventData } )

View File

@@ -200,7 +200,7 @@ do -- ACT_ASSIST_SMOKE_TARGETS_ZONE
function ACT_ASSIST_SMOKE_TARGETS_ZONE:onenterSmoking( ProcessUnit, From, Event, To )
self.TargetSetUnit:ForEachUnit(
-- @param Wrapper.Unit#UNIT SmokeUnit
--- @param Wrapper.Unit#UNIT SmokeUnit
function( SmokeUnit )
if math.random( 1, ( 100 * self.TargetSetUnit:Count() ) / 4 ) <= 100 then
SCHEDULER:New( self,

View File

@@ -78,7 +78,7 @@ do -- CARGO_CRATE
return self
end
-- @param #CARGO_CRATE self
--- @param #CARGO_CRATE self
-- @param Core.Event#EVENTDATA EventData
function CARGO_CRATE:OnEventCargoDead( EventData )

View File

@@ -598,7 +598,7 @@ do -- CARGO_GROUP
end
--- Get the underlying GROUP object from the CARGO_GROUP.
--- Get the amount of cargo units in the group.
-- @param #CARGO_GROUP self
-- @return #CARGO_GROUP
function CARGO_GROUP:GetGroup( Cargo )

View File

@@ -72,7 +72,7 @@ do -- CARGO_SLINGLOAD
end
-- @param #CARGO_SLINGLOAD self
--- @param #CARGO_SLINGLOAD self
-- @param Core.Event#EVENTDATA EventData
function CARGO_SLINGLOAD:OnEventCargoDead( EventData )

View File

@@ -26,7 +26,7 @@
-- @module Core.Base
-- @image Core_Base.JPG
local _TraceOnOff = true
local _TraceOnOff = false -- default to no tracing
local _TraceLevel = 1
local _TraceAll = false
local _TraceClass = {}
@@ -34,11 +34,12 @@ local _TraceClassMethod = {}
local _ClassID = 0
---
--- Base class of everything
-- @type BASE
-- @field ClassName The name of the class.
-- @field ClassID The ID number of the class.
-- @field ClassNameAndID The name of the class concatenated with the ID number of the class.
-- @field #string ClassName The name of the class.
-- @field #number ClassID The ID number of the class.
-- @field #string ClassNameAndID The name of the class concatenated with the ID number of the class.
-- @field Core.Scheduler#SCHEDULER Scheduler The scheduler object.
--- BASE class
--
@@ -210,14 +211,6 @@ BASE._ = {
Schedules = {}, --- Contains the Schedulers Active
}
--- The Formation Class
-- @type FORMATION
-- @field Cone A cone formation.
FORMATION = {
Cone = "Cone",
Vee = "Vee",
}
--- BASE constructor.
--
-- This is an example how to use the BASE:New() constructor in a new class definition when inheriting from BASE.
@@ -741,7 +734,31 @@ do -- Event Handling
-- @function [parent=#BASE] OnEventPlayerEnterAircraft
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a player creates a dynamic cargo object from the F8 ground crew menu.
-- *** NOTE *** this is a workarounf for DCS not creating these events as of Aug 2024.
-- @function [parent=#BASE] OnEventNewDynamicCargo
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a player loads a dynamic cargo object with the F8 ground crew menu into a helo.
-- *** NOTE *** this is a workarounf for DCS not creating these events as of Aug 2024.
-- @function [parent=#BASE] OnEventDynamicCargoLoaded
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a player unloads a dynamic cargo object with the F8 ground crew menu from a helo.
-- *** NOTE *** this is a workarounf for DCS not creating these events as of Aug 2024.
-- @function [parent=#BASE] OnEventDynamicCargoUnloaded
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a dynamic cargo crate is removed.
-- *** NOTE *** this is a workarounf for DCS not creating these events as of Aug 2024.
-- @function [parent=#BASE] OnEventDynamicCargoRemoved
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
end
--- Creation of a Birth Event.
@@ -862,6 +879,62 @@ end
world.onEvent(Event)
end
--- Creation of a S_EVENT_NEW_DYNAMIC_CARGO event.
-- @param #BASE self
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
function BASE:CreateEventNewDynamicCargo(DynamicCargo)
self:F({DynamicCargo})
local Event = {
id = EVENTS.NewDynamicCargo,
time = timer.getTime(),
dynamiccargo = DynamicCargo,
initiator = DynamicCargo:GetDCSObject(),
}
world.onEvent( Event )
end
--- Creation of a S_EVENT_DYNAMIC_CARGO_LOADED event.
-- @param #BASE self
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
function BASE:CreateEventDynamicCargoLoaded(DynamicCargo)
self:F({DynamicCargo})
local Event = {
id = EVENTS.DynamicCargoLoaded,
time = timer.getTime(),
dynamiccargo = DynamicCargo,
initiator = DynamicCargo:GetDCSObject(),
}
world.onEvent( Event )
end
--- Creation of a S_EVENT_DYNAMIC_CARGO_UNLOADED event.
-- @param #BASE self
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
function BASE:CreateEventDynamicCargoUnloaded(DynamicCargo)
self:F({DynamicCargo})
local Event = {
id = EVENTS.DynamicCargoUnloaded,
time = timer.getTime(),
dynamiccargo = DynamicCargo,
initiator = DynamicCargo:GetDCSObject(),
}
world.onEvent( Event )
end
--- Creation of a S_EVENT_DYNAMIC_CARGO_REMOVED event.
-- @param #BASE self
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
function BASE:CreateEventDynamicCargoRemoved(DynamicCargo)
self:F({DynamicCargo})
local Event = {
id = EVENTS.DynamicCargoRemoved,
time = timer.getTime(),
dynamiccargo = DynamicCargo,
initiator = DynamicCargo:GetDCSObject(),
}
world.onEvent( Event )
end
--- The main event handling function... This function captures all events generated for the class.
-- @param #BASE self
@@ -1200,7 +1273,7 @@ end
-- @param Arguments A #table or any field.
function BASE:F( Arguments )
if BASE.Debug and _TraceOnOff then
if BASE.Debug and _TraceOnOff == true then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
@@ -1215,7 +1288,7 @@ end
-- @param Arguments A #table or any field.
function BASE:F2( Arguments )
if BASE.Debug and _TraceOnOff then
if BASE.Debug and _TraceOnOff == true and _TraceLevel >= 2 then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
@@ -1230,7 +1303,7 @@ end
-- @param Arguments A #table or any field.
function BASE:F3( Arguments )
if BASE.Debug and _TraceOnOff then
if BASE.Debug and _TraceOnOff == true and _TraceLevel >= 3 then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
@@ -1274,7 +1347,7 @@ end
-- @param Arguments A #table or any field.
function BASE:T( Arguments )
if BASE.Debug and _TraceOnOff then
if BASE.Debug and _TraceOnOff == true then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
@@ -1289,7 +1362,7 @@ end
-- @param Arguments A #table or any field.
function BASE:T2( Arguments )
if BASE.Debug and _TraceOnOff then
if BASE.Debug and _TraceOnOff == true and _TraceLevel >= 2 then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
@@ -1304,7 +1377,7 @@ end
-- @param Arguments A #table or any field.
function BASE:T3( Arguments )
if BASE.Debug and _TraceOnOff then
if BASE.Debug and _TraceOnOff == true and _TraceLevel >= 3 then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
@@ -1336,7 +1409,7 @@ function BASE:E( Arguments )
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
else
env.info( string.format( "%1s:%30s%05d(%s)", "E", self.ClassName, self.ClassID, BASE:_Serialize(Arguments) ) )
env.info( string.format( "%1s:%30s%05d(%s)", "E", self.ClassName, self.ClassID, UTILS.BasicSerialize(Arguments) ) )
end
end
@@ -1363,7 +1436,7 @@ function BASE:I( Arguments )
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
else
env.info( string.format( "%1s:%30s%05d(%s)", "I", self.ClassName, self.ClassID, BASE:_Serialize(Arguments)) )
env.info( string.format( "%1s:%30s%05d(%s)", "I", self.ClassName, self.ClassID, UTILS.BasicSerialize(Arguments)) )
end
end

View File

@@ -1,920 +0,0 @@
--- **Core** - Client Menu Management.
--
-- **Main Features:**
--
-- * For complex, non-static menu structures
-- * Lightweigt implementation as alternative to MENU
-- * Separation of menu tree creation from menu on the clients's side
-- * Works with a SET_CLIENT set of clients
-- * Allow manipulation of the shadow tree in various ways
-- * Push to all or only one client
-- * Change entries' menu text
-- * Option to make an entry usable once only across all clients
-- * Auto appends GROUP and CLIENT objects to menu calls
--
-- ===
--
-- ### Author: **applevangelist**
--
-- ===
--
-- @module Core.ClientMenu
-- @image Core_Menu.JPG
-- last change: May 2024
-- TODO
----------------------------------------------------------------------------------------------------------------
--
-- CLIENTMENU
--
----------------------------------------------------------------------------------------------------------------
---
-- @type CLIENTMENU
-- @field #string ClassName Class Name
-- @field #string lid Lid for log entries
-- @field #string version Version string
-- @field #string name Name
-- @field #string groupname Group name
-- @field #table path
-- @field #table parentpath
-- @field #CLIENTMENU Parent
-- @field Wrapper.Client#CLIENT client
-- @field #number GroupID Group ID
-- @field #number ID Entry ID
-- @field Wrapper.Group#GROUP group
-- @field #string UUID Unique ID based on path+name
-- @field #string Function
-- @field #table Functionargs
-- @field #table Children
-- @field #boolean Once
-- @field #boolean Generic
-- @field #boolean debug
-- @field #CLIENTMENUMANAGER Controller
-- @field #active boolean
-- @extends Core.Base#BASE
---
-- @field #CLIENTMENU
CLIENTMENU = {
ClassName = "CLIENTMENUE",
lid = "",
version = "0.1.2",
name = nil,
path = nil,
group = nil,
client = nil,
GroupID = nil,
Children = {},
Once = false,
Generic = false,
debug = false,
Controller = nil,
groupname = nil,
active = false,
}
---
-- @field #CLIENTMENU_ID
CLIENTMENU_ID = 0
--- Create an new CLIENTMENU object.
-- @param #CLIENTMENU self
-- @param Wrapper.Client#CLIENT Client The client for whom this entry is. Leave as nil for a generic entry.
-- @param #string Text Text of the F10 menu entry.
-- @param #CLIENTMENU Parent The parent menu entry.
-- @param #string Function (optional) Function to call when the entry is used.
-- @param ... (optional) Arguments for the Function, comma separated
-- @return #CLIENTMENU self
function CLIENTMENU:NewEntry(Client,Text,Parent,Function,...)
-- Inherit everything from BASE class.
local self=BASE:Inherit(self, BASE:New()) -- #CLIENTMENU
CLIENTMENU_ID = CLIENTMENU_ID + 1
self.ID = CLIENTMENU_ID
if Client then
self.group = Client:GetGroup()
self.client = Client
self.GroupID = self.group:GetID()
self.groupname = self.group:GetName() or "Unknown Groupname"
else
self.Generic = true
end
self.name = Text or "unknown entry"
if Parent then
if Parent:IsInstanceOf("MENU_BASE") then
self.parentpath = Parent.MenuPath
else
self.parentpath = Parent:GetPath()
Parent:AddChild(self)
end
end
self.Parent = Parent
self.Function = Function
self.Functionargs = arg or {}
table.insert(self.Functionargs,self.group)
table.insert(self.Functionargs,self.client)
if self.Functionargs and self.debug then
self:T({"Functionargs",self.Functionargs})
end
if not self.Generic and self.active == false then
if Function ~= nil then
local ErrorHandler = function( errmsg )
env.info( "MOOSE Error in CLIENTMENU COMMAND function: " .. errmsg )
if BASE.Debug ~= nil then
env.info( BASE.Debug.traceback() )
end
return errmsg
end
self.CallHandler = function()
local function MenuFunction()
return self.Function( unpack( self.Functionargs ) )
end
local Status, Result = xpcall( MenuFunction, ErrorHandler)
if self.Once == true then
self:Clear()
end
end
self.path = missionCommands.addCommandForGroup(self.GroupID,Text,self.parentpath, self.CallHandler)
self.active = true
else
self.path = missionCommands.addSubMenuForGroup(self.GroupID,Text,self.parentpath)
self.active = true
end
else
if self.parentpath then
self.path = UTILS.DeepCopy(self.parentpath)
else
self.path = {}
end
self.path[#self.path+1] = Text
end
self.UUID = table.concat(self.path,";")
self:T({self.UUID})
self.Once = false
-- Log id.
self.lid=string.format("CLIENTMENU %s | %s | ", self.ID, self.name)
self:T(self.lid.."Created")
return self
end
--- Create a UUID
-- @param #CLIENTMENU self
-- @param #CLIENTMENU Parent The parent object if any
-- @param #string Text The menu entry text
-- @return #string UUID
function CLIENTMENU:CreateUUID(Parent,Text)
local path = {}
if Parent and Parent.path then
path = Parent.path
end
path[#path+1] = Text
local UUID = table.concat(path,";")
return UUID
end
--- Set the CLIENTMENUMANAGER for this entry.
-- @param #CLIENTMENU self
-- @param #CLIENTMENUMANAGER Controller The controlling object.
-- @return #CLIENTMENU self
function CLIENTMENU:SetController(Controller)
self.Controller = Controller
return self
end
--- The entry will be deleted after being used used - for menu entries with functions only.
-- @param #CLIENTMENU self
-- @return #CLIENTMENU self
function CLIENTMENU:SetOnce()
self:T(self.lid.."SetOnce")
self.Once = true
return self
end
--- Remove the entry from the F10 menu.
-- @param #CLIENTMENU self
-- @return #CLIENTMENU self
function CLIENTMENU:RemoveF10()
self:T(self.lid.."RemoveF10")
if self.GroupID then
--self:I(self.lid.."Removing "..table.concat(self.path,";"))
local function RemoveFunction()
return missionCommands.removeItemForGroup(self.GroupID , self.path )
end
local status, err = pcall(RemoveFunction)
if not status then
self:I(string.format("**** Error Removing Menu Entry %s for %s!",tostring(self.name),self.groupname))
end
self.active = false
end
return self
end
--- Get the menu path table.
-- @param #CLIENTMENU self
-- @return #table Path
function CLIENTMENU:GetPath()
self:T(self.lid.."GetPath")
return self.path
end
--- Get the UUID.
-- @param #CLIENTMENU self
-- @return #string UUID
function CLIENTMENU:GetUUID()
self:T(self.lid.."GetUUID")
return self.UUID
end
--- Link a child entry.
-- @param #CLIENTMENU self
-- @param #CLIENTMENU Child The entry to link as a child.
-- @return #CLIENTMENU self
function CLIENTMENU:AddChild(Child)
self:T(self.lid.."AddChild "..Child.ID)
table.insert(self.Children,Child.ID,Child)
return self
end
--- Remove a child entry.
-- @param #CLIENTMENU self
-- @param #CLIENTMENU Child The entry to remove from the children.
-- @return #CLIENTMENU self
function CLIENTMENU:RemoveChild(Child)
self:T(self.lid.."RemoveChild "..Child.ID)
table.remove(self.Children,Child.ID)
return self
end
--- Remove all subentries (children) from this entry.
-- @param #CLIENTMENU self
-- @return #CLIENTMENU self
function CLIENTMENU:RemoveSubEntries()
self:T(self.lid.."RemoveSubEntries")
self:T({self.Children})
for _id,_entry in pairs(self.Children) do
self:T("Removing ".._id)
if _entry then
_entry:RemoveSubEntries()
_entry:RemoveF10()
if _entry.Parent then
_entry.Parent:RemoveChild(self)
end
--if self.Controller then
--self.Controller:_RemoveByID(_entry.ID)
--end
--_entry = nil
end
end
return self
end
--- Remove this entry and all subentries (children) from this entry.
-- @param #CLIENTMENU self
-- @return #CLIENTMENU self
function CLIENTMENU:Clear()
self:T(self.lid.."Clear")
for _id,_entry in pairs(self.Children) do
if _entry then
_entry:RemoveSubEntries()
_entry = nil
end
end
self:RemoveF10()
if self.Parent then
self.Parent:RemoveChild(self)
end
--if self.Controller then
--self.Controller:_RemoveByID(self.ID)
--end
return self
end
-- TODO
----------------------------------------------------------------------------------------------------------------
--
-- CLIENTMENUMANAGER
--
----------------------------------------------------------------------------------------------------------------
--- Class CLIENTMENUMANAGER
-- @type CLIENTMENUMANAGER
-- @field #string ClassName Class Name
-- @field #string lid Lid for log entries
-- @field #string version Version string
-- @field #string name Name
-- @field Core.Set#SET_CLIENT clientset The set of clients this menu manager is for
-- @field #table flattree
-- @field #table rootentries
-- @field #table menutree
-- @field #number entrycount
-- @field #boolean debug
-- @field #table PlayerMenu
-- @field #number Coalition
-- @extends Core.Base#BASE
--- *As a child my family's menu consisted of two choices: take it, or leave it.*
--
-- ===
--
-- ## CLIENTMENU and CLIENTMENUMANAGER
--
-- Manage menu structures for a SET_CLIENT of clients.
--
-- ## Concept
--
-- Separate creation of a menu tree structure from pushing it to each client. Create a shadow "reference" menu structure tree for your client pilot's in a mission.
-- This can then be propagated to all clients. Manipulate the entries in the structure with removing, clearing or changing single entries, create replacement sub-structures
-- for entries etc, push to one or all clients.
--
-- Many functions can either change the tree for one client or for all clients.
--
-- ## Conceptual remarks
--
-- There's a couple of things to fully understand:
--
-- 1) **CLIENTMENUMANAGER** manages a set of entries from **CLIENTMENU**, it's main purpose is to administer the *shadow menu tree*, ie. a menu structure which is not
-- (yet) visible to any client
-- 2) The entries are **CLIENTMENU** objects, which are linked in a tree form. There's two ways to create them:
-- A) in the manager with ":NewEntry()" which initially
-- adds it to the shadow menu **only**
-- B) stand-alone directly as `CLIENTMENU:NewEntry()` - here it depends on whether or not you gave a CLIENT object if the entry is created as generic entry or pushed
-- a **specific** client. **Be aware** though that the entries are not managed by the CLIENTMANAGER before the next step!
-- A generic entry can be added to the manager (and the shadow tree) with `:AddEntry()` - this will also push it to all clients(!) if no client is given, or a specific client only.
-- 3) Pushing only works for alive clients.
-- 4) Live and shadow tree entries are managed via the CLIENTMENUMANAGER object.
-- 5) `Propagate()`refreshes the menu tree for all, or a single client.
--
-- ## Create a base reference tree and send to all clients
--
-- local clientset = SET_CLIENT:New():FilterStart()
--
-- local menumgr = CLIENTMENUMANAGER:New(clientset,"Dayshift")
-- local mymenu = menumgr:NewEntry("Top")
-- local mymenu_lv1a = menumgr:NewEntry("Level 1 a",mymenu)
-- local mymenu_lv1b = menumgr:NewEntry("Level 1 b",mymenu)
-- -- next one is a command menu entry, which can only be used once
-- local mymenu_lv1c = menumgr:NewEntry("Action Level 1 c",mymenu, testfunction, "testtext"):SetOnce()
--
-- local mymenu_lv2a = menumgr:NewEntry("Go here",mymenu_lv1a)
-- local mymenu_lv2b = menumgr:NewEntry("Level 2 ab",mymenu_lv1a)
-- local mymenu_lv2c = menumgr:NewEntry("Level 2 ac",mymenu_lv1a)
--
-- local mymenu_lv2ba = menumgr:NewEntry("Level 2 ba",mymenu_lv1b)
-- local mymenu_lv2bb = menumgr:NewEntry("Level 2 bb",mymenu_lv1b)
-- local mymenu_lv2bc = menumgr:NewEntry("Level 2 bc",mymenu_lv1b)
--
-- local mymenu_lv3a = menumgr:NewEntry("Level 3 aaa",mymenu_lv2a)
-- local mymenu_lv3b = menumgr:NewEntry("Level 3 aab",mymenu_lv2a)
-- local mymenu_lv3c = menumgr:NewEntry("Level 3 aac",mymenu_lv2a)
--
-- menumgr:Propagate() -- propagate **once** to all clients in the SET_CLIENT
--
-- ## Remove a single entry's subtree
--
-- menumgr:RemoveSubEntries(mymenu_lv3a)
--
-- ## Remove a single entry and also it's subtree
--
-- menumgr:DeleteEntry(mymenu_lv3a)
--
-- ## Add a single entry
--
-- local baimenu = menumgr:NewEntry("BAI",mymenu_lv1b)
--
-- menumgr:AddEntry(baimenu)
--
-- ## Add an entry with a function
--
-- local baimenu = menumgr:NewEntry("Task Action", mymenu_lv1b, TestFunction, Argument1, Argument1)
--
-- Now, the class will **automatically append the call with GROUP and CLIENT objects**, as this is can only be done when pushing the entry to the clients. So, the actual function implementation needs to look like this:
--
-- function TestFunction( Argument1, Argument2, Group, Client)
--
-- **Caveat is**, that you need to ensure your arguments are not **nil** or **false**, as LUA will optimize those away. You would end up having Group and Client in wrong places in the function call. Hence,
-- if you need/ want to send **nil** or **false**, send a place holder instead and ensure your function can handle this, e.g.
--
-- local baimenu = menumgr:NewEntry("Task Action", mymenu_lv1b, TestFunction, "nil", Argument1)
--
-- ## Change the text of a leaf entry in the menu tree
--
-- menumgr:ChangeEntryTextForAll(mymenu_lv1b,"Attack")
--
-- ## Reset a single clients menu tree
--
-- menumgr:ResetMenu(client)
--
-- ## Reset all and clear the reference tree
--
-- menumgr:ResetMenuComplete()
--
-- ## Set to auto-propagate for CLIENTs joining the SET_CLIENT **after** the script is loaded - handy if you have a single menu tree.
--
-- menumgr:InitAutoPropagation()
--
-- @field #CLIENTMENUMANAGER
CLIENTMENUMANAGER = {
ClassName = "CLIENTMENUMANAGER",
lid = "",
version = "0.1.6",
name = nil,
clientset = nil,
menutree = {},
flattree = {},
playertree = {},
entrycount = 0,
rootentries = {},
debug = true,
PlayerMenu = {},
Coalition = nil,
}
--- Create a new ClientManager instance.
-- @param #CLIENTMENUMANAGER self
-- @param Core.Set#SET_CLIENT ClientSet The set of clients to manage.
-- @param #string Alias The name of this manager.
-- @param #number Coalition (Optional) Coalition of this Manager, defaults to coalition.side.BLUE
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:New(ClientSet, Alias, Coalition)
-- Inherit everything from FSM class.
local self=BASE:Inherit(self, BASE:New()) -- #CLIENTMENUMANAGER
self.clientset = ClientSet
self.PlayerMenu = {}
self.name = Alias or "Nightshift"
self.Coalition = Coalition or coalition.side.BLUE
-- Log id.
self.lid=string.format("CLIENTMENUMANAGER %s | %s | ", self.version, self.name)
if self.debug then
self:I(self.lid.."Created")
end
return self
end
--- [Internal] Event handling
-- @param #CLIENTMENUMANAGER self
-- @param Core.Event#EVENTDATA EventData
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:_EventHandler(EventData)
self:T(self.lid.."_EventHandler: "..EventData.id)
--self:I(self.lid.."_EventHandler: "..tostring(EventData.IniPlayerName))
if EventData.id == EVENTS.PlayerLeaveUnit or EventData.id == EVENTS.Ejection or EventData.id == EVENTS.Crash or EventData.id == EVENTS.PilotDead then
self:T(self.lid.."Leave event for player: "..tostring(EventData.IniPlayerName))
local Client = _DATABASE:FindClient( EventData.IniUnitName )
if Client then
self:ResetMenu(Client)
end
elseif (EventData.id == EVENTS.PlayerEnterAircraft) and EventData.IniCoalition == self.Coalition then
if EventData.IniPlayerName and EventData.IniGroup then
if (not self.clientset:IsIncludeObject(_DATABASE:FindClient( EventData.IniUnitName ))) then
self:T(self.lid.."Client not in SET: "..EventData.IniPlayerName)
return self
end
--self:I(self.lid.."Join event for player: "..EventData.IniPlayerName)
local player = _DATABASE:FindClient( EventData.IniUnitName )
self:Propagate(player)
end
elseif EventData.id == EVENTS.PlayerEnterUnit then
-- special for CA slots
local grp = GROUP:FindByName(EventData.IniGroupName)
if grp:IsGround() then
self:T(string.format("Player %s entered GROUND unit %s!",EventData.IniPlayerName,EventData.IniUnitName))
local IsPlayer = EventData.IniDCSUnit:getPlayerName()
if IsPlayer then
local client=_DATABASE.CLIENTS[EventData.IniDCSUnitName] --Wrapper.Client#CLIENT
-- Add client in case it does not exist already.
if not client then
-- Debug info.
self:I(string.format("Player '%s' joined ground unit '%s' of group '%s'", tostring(EventData.IniPlayerName), tostring(EventData.IniDCSUnitName), tostring(EventData.IniDCSGroupName)))
client=_DATABASE:AddClient(EventData.IniDCSUnitName)
-- Add player.
client:AddPlayer(EventData.IniPlayerName)
-- Add player.
if not _DATABASE.PLAYERS[EventData.IniPlayerName] then
_DATABASE:AddPlayer( EventData.IniUnitName, EventData.IniPlayerName )
end
-- Player settings.
local Settings = SETTINGS:Set( EventData.IniPlayerName )
Settings:SetPlayerMenu(EventData.IniUnit)
end
--local player = _DATABASE:FindClient( EventData.IniPlayerName )
self:Propagate(client)
end
end
end
return self
end
--- Set this Client Manager to auto-propagate menus **once** to newly joined players. Useful if you have **one** menu structure only. Does not automatically push follow-up changes to the client(s).
-- @param #CLIENTMENUMANAGER self
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:InitAutoPropagation()
-- Player Events
self:HandleEvent(EVENTS.PlayerLeaveUnit, self._EventHandler)
self:HandleEvent(EVENTS.Ejection, self._EventHandler)
self:HandleEvent(EVENTS.Crash, self._EventHandler)
self:HandleEvent(EVENTS.PilotDead, self._EventHandler)
self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler)
self:HandleEvent(EVENTS.PlayerEnterUnit, self._EventHandler)
self:SetEventPriority(5)
return self
end
--- Create a new entry in the **generic** structure.
-- @param #CLIENTMENUMANAGER self
-- @param #string Text Text of the F10 menu entry.
-- @param #CLIENTMENU Parent The parent menu entry.
-- @param #string Function (optional) Function to call when the entry is used.
-- @param ... (optional) Arguments for the Function, comma separated.
-- @return #CLIENTMENU Entry
function CLIENTMENUMANAGER:NewEntry(Text,Parent,Function,...)
self:T(self.lid.."NewEntry "..Text or "None")
self.entrycount = self.entrycount + 1
local entry = CLIENTMENU:NewEntry(nil,Text,Parent,Function,unpack(arg))
if not Parent then
self.rootentries[self.entrycount] = entry
end
local depth = #entry.path
if not self.menutree[depth] then self.menutree[depth] = {} end
table.insert(self.menutree[depth],entry.UUID)
self.flattree[entry.UUID] = entry
return entry
end
--- Check matching entry in the generic structure by UUID.
-- @param #CLIENTMENUMANAGER self
-- @param #string UUID UUID of the menu entry.
-- @return #boolean Exists
function CLIENTMENUMANAGER:EntryUUIDExists(UUID)
local exists = self.flattree[UUID] and true or false
return exists
end
--- Find matching entry in the generic structure by UUID.
-- @param #CLIENTMENUMANAGER self
-- @param #string UUID UUID of the menu entry.
-- @return #CLIENTMENU Entry The #CLIENTMENU object found or nil.
function CLIENTMENUMANAGER:FindEntryByUUID(UUID)
self:T(self.lid.."FindEntryByUUID "..UUID or "None")
local entry = nil
for _gid,_entry in pairs(self.flattree) do
local Entry = _entry -- #CLIENTMENU
if Entry and Entry.UUID == UUID then
entry = Entry
end
end
return entry
end
--- Find matching entries by text in the generic structure by UUID.
-- @param #CLIENTMENUMANAGER self
-- @param #string Text Text or partial text of the menu entry to find.
-- @param #CLIENTMENU Parent (Optional) Only find entries under this parent entry.
-- @return #table Table of matching UUIDs of #CLIENTMENU objects
-- @return #table Table of matching #CLIENTMENU objects
-- @return #number Number of matches
function CLIENTMENUMANAGER:FindUUIDsByText(Text,Parent)
self:T(self.lid.."FindUUIDsByText "..Text or "None")
local matches = {}
local entries = {}
local n = 0
for _uuid,_entry in pairs(self.flattree) do
local Entry = _entry -- #CLIENTMENU
if Parent then
if Entry and string.find(Entry.name,Text,1,true) and string.find(Entry.UUID,Parent.UUID,1,true) then
table.insert(matches,_uuid)
table.insert(entries,Entry )
n=n+1
end
else
if Entry and string.find(Entry.name,Text,1,true) then
table.insert(matches,_uuid)
table.insert(entries,Entry )
n=n+1
end
end
end
return matches, entries, n
end
--- Find matching entries in the generic structure by the menu text.
-- @param #CLIENTMENUMANAGER self
-- @param #string Text Text or partial text of the F10 menu entry.
-- @param #CLIENTMENU Parent (Optional) Only find entries under this parent entry.
-- @return #table Table of matching #CLIENTMENU objects.
-- @return #number Number of matches
function CLIENTMENUMANAGER:FindEntriesByText(Text,Parent)
self:T(self.lid.."FindEntriesByText "..Text or "None")
local matches, objects, number = self:FindUUIDsByText(Text, Parent)
return objects, number
end
--- Find matching entries under a parent in the generic structure by UUID.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Parent Find entries under this parent entry.
-- @return #table Table of matching UUIDs of #CLIENTMENU objects
-- @return #table Table of matching #CLIENTMENU objects
-- @return #number Number of matches
function CLIENTMENUMANAGER:FindUUIDsByParent(Parent)
self:T(self.lid.."FindUUIDsByParent")
local matches = {}
local entries = {}
local n = 0
for _uuid,_entry in pairs(self.flattree) do
local Entry = _entry -- #CLIENTMENU
if Parent then
if Entry and string.find(Entry.UUID,Parent.UUID,1,true) then
table.insert(matches,_uuid)
table.insert(entries,Entry )
n=n+1
end
end
end
return matches, entries, n
end
--- Find matching entries in the generic structure under a parent.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Parent Find entries under this parent entry.
-- @return #table Table of matching #CLIENTMENU objects.
-- @return #number Number of matches
function CLIENTMENUMANAGER:FindEntriesByParent(Parent)
self:T(self.lid.."FindEntriesByParent")
local matches, objects, number = self:FindUUIDsByParent(Parent)
return objects, number
end
--- Alter the text of a leaf entry in the generic structure and push to one specific client's F10 menu.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The menu entry.
-- @param #string Text New Text of the F10 menu entry.
-- @param Wrapper.Client#CLIENT Client (optional) The client for whom to alter the entry, if nil done for all clients.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:ChangeEntryText(Entry, Text, Client)
self:T(self.lid.."ChangeEntryText "..Text or "None")
local newentry = CLIENTMENU:NewEntry(nil,Text,Entry.Parent,Entry.Function,unpack(Entry.Functionargs))
self:DeleteF10Entry(Entry,Client)
self:DeleteGenericEntry(Entry)
if not Entry.Parent then
self.rootentries[self.entrycount] = newentry
end
local depth = #newentry.path
if not self.menutree[depth] then self.menutree[depth] = {} end
table.insert(self.menutree[depth],newentry.UUID)
self.flattree[newentry.UUID] = newentry
self:AddEntry(newentry,Client)
return self
end
--- Push the complete menu structure to each of the clients in the set - refresh the menu tree of the clients.
-- @param #CLIENTMENUMANAGER self
-- @param Wrapper.Client#CLIENT Client (optional) If given, propagate only for this client.
-- @return #CLIENTMENU Entry
function CLIENTMENUMANAGER:Propagate(Client)
self:T(self.lid.."Propagate")
--self:I(UTILS.PrintTableToLog(Client,1))
local knownunits = {} -- track so we can ID multi seated
local Set = self.clientset.Set
if Client then
Set = {Client}
end
self:ResetMenu(Client)
for _,_client in pairs(Set) do
local client = _client -- Wrapper.Client#CLIENT
if client and client:IsAlive() then
local playerunit = client:GetName()
--local playergroup = client:GetGroup()
local playername = client:GetPlayerName() or "none"
if not knownunits[playerunit] then
knownunits[playerunit] = true
else
self:I("Player in multi seat unit: "..playername)
break -- multi seat already build
end
if not self.playertree[playername] then
self.playertree[playername] = {}
end
for level,branch in pairs (self.menutree) do
self:T("Building branch:" .. level)
for _,leaf in pairs(branch) do
self:T("Building leaf:" .. leaf)
local entry = self:FindEntryByUUID(leaf)
if entry then
self:T("Found generic entry:" .. entry.UUID)
local parent = nil
if entry.Parent and entry.Parent.UUID then
parent = self.playertree[playername][entry.Parent.UUID] or self:FindEntryByUUID(entry.Parent.UUID)
end
self.playertree[playername][entry.UUID] = CLIENTMENU:NewEntry(client,entry.name,parent,entry.Function,unpack(entry.Functionargs))
self.playertree[playername][entry.UUID].Once = entry.Once
else
self:T("NO generic entry for:" .. leaf)
end
end
end
end
end
return self
end
--- Push a single previously created entry into the F10 menu structure of all clients.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The entry to add.
-- @param Wrapper.Client#CLIENT Client (optional) If given, make this change only for this client.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:AddEntry(Entry,Client)
self:T(self.lid.."AddEntry")
local Set = self.clientset.Set
local knownunits = {}
if Client then
Set = {Client}
end
for _,_client in pairs(Set) do
local client = _client -- Wrapper.Client#CLIENT
if client and client:IsAlive() then
local playername = client:GetPlayerName() or "None"
local unitname = client:GetName()
if not knownunits[unitname] then
knownunits[unitname] = true
else
self:I("Player in multi seat unit: "..playername)
break
end
if Entry then
self:T("Adding generic entry:" .. Entry.UUID)
local parent = nil
if not self.playertree[playername] then
self.playertree[playername] = {}
end
if Entry.Parent and Entry.Parent.UUID then
parent = self.playertree[playername][Entry.Parent.UUID] or self:FindEntryByUUID(Entry.Parent.UUID)
end
self.playertree[playername][Entry.UUID] = CLIENTMENU:NewEntry(client,Entry.name,parent,Entry.Function,unpack(Entry.Functionargs))
self.playertree[playername][Entry.UUID].Once = Entry.Once
else
self:T("NO generic entry given")
end
end
end
return self
end
--- Blank out the menu - remove **all root entries** and all entries below from the client's F10 menus, leaving the generic structure untouched.
-- @param #CLIENTMENUMANAGER self
-- @param Wrapper.Client#CLIENT Client (optional) If given, remove only for this client.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:ResetMenu(Client)
self:T(self.lid.."ResetMenu")
for _,_entry in pairs(self.rootentries) do
--local RootEntry = self.structure.generic[_entry]
if _entry then
self:DeleteF10Entry(_entry,Client)
end
end
return self
end
--- Blank out the menu - remove **all root entries** and all entries below from all clients' F10 menus, and **delete** the generic structure.
-- @param #CLIENTMENUMANAGER self
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:ResetMenuComplete()
self:T(self.lid.."ResetMenuComplete")
for _,_entry in pairs(self.rootentries) do
--local RootEntry = self.structure.generic[_entry]
if _entry then
self:DeleteF10Entry(_entry)
end
end
self.playertree = nil
self.playertree = {}
self.rootentries = nil
self.rootentries = {}
self.menutree = nil
self.menutree = {}
return self
end
--- Remove the entry and all entries below the given entry from the client's F10 menus.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The entry to remove
-- @param Wrapper.Client#CLIENT Client (optional) If given, make this change only for this client.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:DeleteF10Entry(Entry,Client)
self:T(self.lid.."DeleteF10Entry")
local Set = self.clientset.Set
if Client then
Set = {Client}
end
for _,_client in pairs(Set) do
if _client and _client:IsAlive() then
local playername = _client:GetPlayerName()
if self.playertree[playername] then
local centry = self.playertree[playername][Entry.UUID] -- #CLIENTMENU
if centry then
--self:I("Match for "..Entry.UUID)
centry:Clear()
end
end
end
end
return self
end
--- Remove the entry and all entries below the given entry from the generic tree.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The entry to remove
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:DeleteGenericEntry(Entry)
self:T(self.lid.."DeleteGenericEntry")
if Entry.Children and #Entry.Children > 0 then
self:RemoveGenericSubEntries(Entry)
end
local depth = #Entry.path
local uuid = Entry.UUID
local tbl = UTILS.DeepCopy(self.menutree)
if tbl[depth] then
for i=depth,#tbl do
--self:I("Level = "..i)
for _id,_uuid in pairs(tbl[i]) do
self:T(_uuid)
if string.find(_uuid,uuid,1,true) or _uuid == uuid then
--self:I("Match for ".._uuid)
self.menutree[i][_id] = nil
self.flattree[_uuid] = nil
end
end
end
end
return self
end
--- Remove all entries below the given entry from the generic tree.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The entry where to start. This entry stays.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:RemoveGenericSubEntries(Entry)
self:T(self.lid.."RemoveGenericSubEntries")
local depth = #Entry.path + 1
local uuid = Entry.UUID
local tbl = UTILS.DeepCopy(self.menutree)
if tbl[depth] then
for i=depth,#tbl do
self:T("Level = "..i)
for _id,_uuid in pairs(tbl[i]) do
self:T(_uuid)
if string.find(_uuid,uuid,1,true) then
self:T("Match for ".._uuid)
self.menutree[i][_id] = nil
self.flattree[_uuid] = nil
end
end
end
end
return self
end
--- Remove all entries below the given entry from the client's F10 menus.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The entry where to start. This entry stays.
-- @param Wrapper.Client#CLIENT Client (optional) If given, make this change only for this client. In this case the generic structure will not be touched.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:RemoveF10SubEntries(Entry,Client)
self:T(self.lid.."RemoveSubEntries")
local Set = self.clientset.Set
if Client then
Set = {Client}
end
for _,_client in pairs(Set) do
if _client and _client:IsAlive() then
local playername = _client:GetPlayerName()
if self.playertree[playername] then
local centry = self.playertree[playername][Entry.UUID] -- #CLIENTMENU
centry:RemoveSubEntries()
end
end
end
return self
end
----------------------------------------------------------------------------------------------------------------
--
-- End ClientMenu
--
----------------------------------------------------------------------------------------------------------------

View File

@@ -20,6 +20,7 @@
-- * Manage database of hits to units and statics.
-- * Manage database of destroys of units and statics.
-- * Manage database of @{Core.Zone#ZONE_BASE} objects.
-- * Manage database of @{Wrapper.DynamicCargo#DYNAMICCARGO} objects alive in the mission.
--
-- ===
--
@@ -39,6 +40,7 @@
-- @field #table STORAGES DCS warehouse storages.
-- @field #table STNS Used Link16 octal numbers for F16/15/18/AWACS planes.
-- @field #table SADL Used Link16 octal numbers for A10/C-II planes.
-- @field #table DYNAMICCARGO Dynamic Cargo objects.
-- @extends Core.Base#BASE
--- Contains collections of wrapper objects defined within MOOSE that reflect objects within the simulator.
@@ -54,6 +56,7 @@
-- * PLAYERS
-- * CARGOS
-- * STORAGES (DCS warehouses)
-- * DYNAMICCARGO
--
-- On top, for internal MOOSE administration purposes, the DATABASE administers the Unit and Group TEMPLATES as defined within the Mission Editor.
--
@@ -97,6 +100,7 @@ DATABASE = {
STORAGES = {},
STNS={},
SADL={},
DYNAMICCARGO={},
}
local _DATABASECoalition =
@@ -143,6 +147,8 @@ function DATABASE:New()
self:HandleEvent( EVENTS.DeleteZone )
--self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit ) -- This is not working anymore!, handling this through the birth event.
self:HandleEvent( EVENTS.PlayerLeaveUnit, self._EventOnPlayerLeaveUnit )
-- DCS 2.9.7 Moose own dynamic cargo events
self:HandleEvent( EVENTS.DynamicCargoRemoved, self._EventOnDynamicCargoRemoved)
self:_RegisterTemplates()
self:_RegisterGroupsAndUnits()
@@ -173,16 +179,20 @@ end
-- @param #boolean force
-- @return Wrapper.Unit#UNIT The added unit.
function DATABASE:AddUnit( DCSUnitName, force )
if not self.UNITS[DCSUnitName] or force == true then
local DCSunitName = DCSUnitName
if type(DCSunitName) == "number" then DCSunitName = string.format("%d",DCSUnitName) end
if not self.UNITS[DCSunitName] or force == true then
-- Debug info.
self:T( { "Add UNIT:", DCSUnitName } )
self:T( { "Add UNIT:", DCSunitName } )
-- Register unit
self.UNITS[DCSUnitName]=UNIT:Register(DCSUnitName)
self.UNITS[DCSunitName]=UNIT:Register(DCSunitName)
end
return self.UNITS[DCSUnitName]
return self.UNITS[DCSunitName]
end
@@ -201,10 +211,9 @@ function DATABASE:AddStatic( DCSStaticName )
if not self.STATICS[DCSStaticName] then
self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
return self.STATICS[DCSStaticName]
end
return nil
return self.STATICS[DCSStaticName]
end
@@ -214,16 +223,42 @@ function DATABASE:DeleteStatic( DCSStaticName )
self.STATICS[DCSStaticName] = nil
end
--- Finds a STATIC based on the StaticName.
--- Finds a STATIC based on the Static Name.
-- @param #DATABASE self
-- @param #string StaticName
-- @param #string StaticName Name of the static object.
-- @return Wrapper.Static#STATIC The found STATIC.
function DATABASE:FindStatic( StaticName )
local StaticFound = self.STATICS[StaticName]
return StaticFound
end
--- Add a DynamicCargo to the database.
-- @param #DATABASE self
-- @param #string Name Name of the dynamic cargo.
-- @return Wrapper.DynamicCargo#DYNAMICCARGO The dynamic cargo object.
function DATABASE:AddDynamicCargo( Name )
if not self.DYNAMICCARGO[Name] then
self.DYNAMICCARGO[Name] = DYNAMICCARGO:Register(Name)
end
return self.DYNAMICCARGO[Name]
end
--- Finds a DYNAMICCARGO based on the Dynamic Cargo Name.
-- @param #DATABASE self
-- @param #string DynamicCargoName
-- @return Wrapper.DynamicCargo#DYNAMICCARGO The found DYNAMICCARGO.
function DATABASE:FindDynamicCargo( DynamicCargoName )
local StaticFound = self.DYNAMICCARGO[DynamicCargoName]
return StaticFound
end
--- Deletes a DYNAMICCARGO from the DATABASE based on the Dynamic Cargo Name.
-- @param #DATABASE self
function DATABASE:DeleteDynamicCargo( DynamicCargoName )
self.DYNAMICCARGO[DynamicCargoName] = nil
return self
end
--- Adds a Airbase based on the Airbase Name in the DATABASE.
-- @param #DATABASE self
-- @param #string AirbaseName The name of the airbase.
@@ -818,12 +853,16 @@ end
-- @param #boolean Force (optional) Force registration of client.
-- @return Wrapper.Client#CLIENT The client object.
function DATABASE:AddClient( ClientName, Force )
if not self.CLIENTS[ClientName] or Force == true then
self.CLIENTS[ClientName] = CLIENT:Register( ClientName )
local DCSUnitName = ClientName
if type(DCSUnitName) == "number" then DCSUnitName = string.format("%d",ClientName) end
if not self.CLIENTS[DCSUnitName] or Force == true then
self.CLIENTS[DCSUnitName] = CLIENT:Register( DCSUnitName )
end
return self.CLIENTS[ClientName]
return self.CLIENTS[DCSUnitName]
end
@@ -863,9 +902,11 @@ end
--- Adds a player based on the Player Name in the DATABASE.
-- @param #DATABASE self
function DATABASE:AddPlayer( UnitName, PlayerName )
if type(UnitName) == "number" then UnitName = string.format("%d",UnitName) end
if PlayerName then
self:T( { "Add player for unit:", UnitName, PlayerName } )
self:I( { "Add player for unit:", UnitName, PlayerName } )
self.PLAYERS[PlayerName] = UnitName
self.PLAYERUNITS[PlayerName] = self:FindUnit( UnitName )
self.PLAYERSJOINED[PlayerName] = PlayerName
@@ -873,6 +914,21 @@ function DATABASE:AddPlayer( UnitName, PlayerName )
end
--- Get a PlayerName by UnitName from PLAYERS in DATABASE.
-- @param #DATABASE self
-- @return #string PlayerName
-- @return Wrapper.Unit#UNIT PlayerUnit
function DATABASE:_FindPlayerNameByUnitName(UnitName)
if UnitName then
for playername,unitname in pairs(self.PLAYERS) do
if unitname == UnitName and self.PLAYERUNITS[playername] and self.PLAYERUNITS[playername]:IsAlive() then
return playername, self.PLAYERUNITS[playername]
end
end
end
return nil
end
--- Deletes a player from the DATABASE based on the Player Name.
-- @param #DATABASE self
function DATABASE:DeletePlayer( UnitName, PlayerName )
@@ -1244,7 +1300,7 @@ function DATABASE:_GetGenericStaticCargoGroupTemplate(Name,Typename,Mass,Coaliti
StaticTemplate.CategoryID = "static"
StaticTemplate.CoalitionID = Coalition or coalition.side.BLUE
StaticTemplate.CountryID = Country or country.id.GERMANY
UTILS.PrintTableToLog(StaticTemplate)
--UTILS.PrintTableToLog(StaticTemplate)
return StaticTemplate
end
@@ -1324,7 +1380,7 @@ function DATABASE:GetCoalitionFromClientTemplate( ClientName )
if self.Templates.ClientsByName[ClientName] then
return self.Templates.ClientsByName[ClientName].CoalitionID
end
self:E("ERROR: Template does not exist for client "..tostring(ClientName))
self:E("WARNING: Template does not exist for client "..tostring(ClientName))
return nil
end
@@ -1336,7 +1392,7 @@ function DATABASE:GetCategoryFromClientTemplate( ClientName )
if self.Templates.ClientsByName[ClientName] then
return self.Templates.ClientsByName[ClientName].CategoryID
end
self:E("ERROR: Template does not exist for client "..tostring(ClientName))
self:E("WARNING: Template does not exist for client "..tostring(ClientName))
return nil
end
@@ -1348,7 +1404,7 @@ function DATABASE:GetCountryFromClientTemplate( ClientName )
if self.Templates.ClientsByName[ClientName] then
return self.Templates.ClientsByName[ClientName].CountryID
end
self:E("ERROR: Template does not exist for client "..tostring(ClientName))
self:E("WARNING: Template does not exist for client "..tostring(ClientName))
return nil
end
@@ -1417,7 +1473,7 @@ function DATABASE:_RegisterDynamicGroup(Groupname)
-- Add unit.
self:I(string.format("Register Unit: %s", tostring(DCSUnitName)))
self:AddUnit( DCSUnitName, true )
self:AddUnit( tostring(DCSUnitName), true )
end
else
@@ -1523,12 +1579,29 @@ end
-- @param DCS#Airbase airbase Airbase.
-- @return #DATABASE self
function DATABASE:_RegisterAirbase(airbase)
local IsSyria = UTILS.GetDCSMap() == "Syria" and true or false
local countHSyria = 0
if airbase then
-- Get the airbase name.
local DCSAirbaseName = airbase:getName()
-- DCS 2.9.8.1107 added 143 helipads all named H with the same object ID ..
if IsSyria and DCSAirbaseName == "H" and countHSyria > 0 then
--[[
local p = airbase:getPosition().p
local mgrs = COORDINATE:New(p.x,p.z,p.y):ToStringMGRS()
self:I("Airbase on Syria map named H @ "..mgrs)
countHSyria = countHSyria + 1
if countHSyria > 1 then return self end
--]]
return self
elseif IsSyria and DCSAirbaseName == "H" and countHSyria == 0 then
countHSyria = countHSyria + 1
end
-- This gave the incorrect value to be inserted into the airdromeID for DCS 2.5.6. Is fixed now.
local airbaseID=airbase:getID()
@@ -1568,7 +1641,7 @@ end
-- @param #DATABASE self
-- @param Core.Event#EVENTDATA Event
function DATABASE:_EventOnBirth( Event )
self:F( { Event } )
self:T( { Event } )
if Event.IniDCSUnit then
@@ -1576,7 +1649,17 @@ function DATABASE:_EventOnBirth( Event )
-- Add static object to DB.
self:AddStatic( Event.IniDCSUnitName )
elseif Event.IniObjectCategory == Object.Category.CARGO and string.match(Event.IniUnitName,".+|%d%d:%d%d|PKG%d+") then
-- Add dynamic cargo object to DB
local cargo = self:AddDynamicCargo(Event.IniDCSUnitName)
self:I(string.format("Adding dynamic cargo %s", tostring(Event.IniDCSUnitName)))
self:CreateEventNewDynamicCargo( cargo )
else
if Event.IniObjectCategory == Object.Category.UNIT then
@@ -1762,6 +1845,15 @@ function DATABASE:_EventOnPlayerEnterUnit( Event )
end
end
--- Handles the OnDynamicCargoRemoved event to clean the active dynamic cargo table.
-- @param #DATABASE self
-- @param Core.Event#EVENTDATA Event
function DATABASE:_EventOnDynamicCargoRemoved( Event )
self:T( { Event } )
if Event.IniDynamicCargoName then
self:DeleteDynamicCargo(Event.IniDynamicCargoName)
end
end
--- Handles the OnPlayerLeaveUnit event to clean the active players table.
-- @param #DATABASE self

View File

@@ -194,6 +194,11 @@ world.event.S_EVENT_NEW_ZONE_GOAL = world.event.S_EVENT_MAX + 1004
world.event.S_EVENT_DELETE_ZONE_GOAL = world.event.S_EVENT_MAX + 1005
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1006
world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT = world.event.S_EVENT_MAX + 1007
-- dynamic cargo
world.event.S_EVENT_NEW_DYNAMIC_CARGO = world.event.S_EVENT_MAX + 1008
world.event.S_EVENT_DYNAMIC_CARGO_LOADED = world.event.S_EVENT_MAX + 1009
world.event.S_EVENT_DYNAMIC_CARGO_UNLOADED = world.event.S_EVENT_MAX + 1010
world.event.S_EVENT_DYNAMIC_CARGO_REMOVED = world.event.S_EVENT_MAX + 1011
--- The different types of events supported by MOOSE.
@@ -275,7 +280,12 @@ EVENTS = {
SimulationFreeze = world.event.S_EVENT_SIMULATION_FREEZE or -1,
SimulationUnfreeze = world.event.S_EVENT_SIMULATION_UNFREEZE or -1,
HumanAircraftRepairStart = world.event.S_EVENT_HUMAN_AIRCRAFT_REPAIR_START or -1,
HumanAircraftRepairFinish = world.event.S_EVENT_HUMAN_AIRCRAFT_REPAIR_FINISH or -1,
HumanAircraftRepairFinish = world.event.S_EVENT_HUMAN_AIRCRAFT_REPAIR_FINISH or -1,
-- dynamic cargo
NewDynamicCargo = world.event.S_EVENT_NEW_DYNAMIC_CARGO or -1,
DynamicCargoLoaded = world.event.S_EVENT_DYNAMIC_CARGO_LOADED or -1,
DynamicCargoUnloaded = world.event.S_EVENT_DYNAMIC_CARGO_UNLOADED or -1,
DynamicCargoRemoved = world.event.S_EVENT_DYNAMIC_CARGO_REMOVED or -1,
}
@@ -334,6 +344,9 @@ EVENTS = {
--
-- @field Core.Zone#ZONE Zone The zone object.
-- @field #string ZoneName The name of the zone.
--
-- @field Wrapper.DynamicCargo#DYNAMICCARGO IniDynamicCargo The dynamic cargo object.
-- @field #string IniDynamicCargoName The dynamic cargo unit name.
@@ -730,6 +743,31 @@ local _EVENTMETA = {
Side = "I",
Event = "OnEventHumanAircraftRepairFinish",
Text = "S_EVENT_HUMAN_AIRCRAFT_REPAIR_FINISH"
},
-- dynamic cargo
[EVENTS.NewDynamicCargo] = {
Order = 1,
Side = "I",
Event = "OnEventNewDynamicCargo",
Text = "S_EVENT_NEW_DYNAMIC_CARGO"
},
[EVENTS.DynamicCargoLoaded] = {
Order = 1,
Side = "I",
Event = "OnEventDynamicCargoLoaded",
Text = "S_EVENT_DYNAMIC_CARGO_LOADED"
},
[EVENTS.DynamicCargoUnloaded] = {
Order = 1,
Side = "I",
Event = "OnEventDynamicCargoUnloaded",
Text = "S_EVENT_DYNAMIC_CARGO_UNLOADED"
},
[EVENTS.DynamicCargoRemoved] = {
Order = 1,
Side = "I",
Event = "OnEventDynamicCargoRemoved",
Text = "S_EVENT_DYNAMIC_CARGO_REMOVED"
},
}
@@ -1146,7 +1184,63 @@ do -- Event Creation
world.onEvent( Event )
end
--- Creation of a S_EVENT_NEW_DYNAMIC_CARGO event.
-- @param #EVENT self
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
function EVENT:CreateEventNewDynamicCargo(DynamicCargo)
self:F({DynamicCargo})
local Event = {
id = EVENTS.NewDynamicCargo,
time = timer.getTime(),
dynamiccargo = DynamicCargo,
initiator = DynamicCargo:GetDCSObject(),
}
world.onEvent( Event )
end
--- Creation of a S_EVENT_DYNAMIC_CARGO_LOADED event.
-- @param #EVENT self
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
function EVENT:CreateEventDynamicCargoLoaded(DynamicCargo)
self:F({DynamicCargo})
local Event = {
id = EVENTS.DynamicCargoLoaded,
time = timer.getTime(),
dynamiccargo = DynamicCargo,
initiator = DynamicCargo:GetDCSObject(),
}
world.onEvent( Event )
end
--- Creation of a S_EVENT_DYNAMIC_CARGO_UNLOADED event.
-- @param #EVENT self
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
function EVENT:CreateEventDynamicCargoUnloaded(DynamicCargo)
self:F({DynamicCargo})
local Event = {
id = EVENTS.DynamicCargoUnloaded,
time = timer.getTime(),
dynamiccargo = DynamicCargo,
initiator = DynamicCargo:GetDCSObject(),
}
world.onEvent( Event )
end
--- Creation of a S_EVENT_DYNAMIC_CARGO_REMOVED event.
-- @param #EVENT self
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
function EVENT:CreateEventDynamicCargoRemoved(DynamicCargo)
self:F({DynamicCargo})
local Event = {
id = EVENTS.DynamicCargoRemoved,
time = timer.getTime(),
dynamiccargo = DynamicCargo,
initiator = DynamicCargo:GetDCSObject(),
}
world.onEvent( Event )
end
end
--- Main event function.
@@ -1235,6 +1329,7 @@ function EVENT:onEvent( Event )
end
Event.IniDCSGroupName = Event.IniUnit and Event.IniUnit.GroupName or ""
Event.IniGroupName=Event.IniDCSGroupName --At least set the group name because group might not exist any more
if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
Event.IniDCSGroupName = Event.IniDCSGroup:getName()
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
@@ -1261,7 +1356,13 @@ function EVENT:onEvent( Event )
Event.IniDCSUnit = Event.initiator
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
Event.IniUnitName = Event.IniDCSUnitName
Event.IniUnit = CARGO:FindByName( Event.IniDCSUnitName )
if string.match(Event.IniUnitName,".+|%d%d:%d%d|PKG%d+") then
Event.IniDynamicCargo = DYNAMICCARGO:FindByName(Event.IniUnitName)
Event.IniDynamicCargoName = Event.IniUnitName
Event.IniPlayerName = string.match(Event.IniUnitName,"^(.+)|%d%d:%d%d|PKG%d+")
else
Event.IniUnit = CARGO:FindByName( Event.IniDCSUnitName )
end
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
Event.IniCategory = Event.IniDCSUnit:getDesc().category
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
@@ -1271,7 +1372,7 @@ function EVENT:onEvent( Event )
-- Scenery
---
Event.IniDCSUnit = Event.initiator
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
Event.IniDCSUnitName = Event.IniDCSUnit.getName and Event.IniDCSUnit:getName() or "Scenery no name "..math.random(1,20000)
Event.IniUnitName = Event.IniDCSUnitName
Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator )
Event.IniCategory = Event.IniDCSUnit:getDesc().category
@@ -1373,16 +1474,18 @@ function EVENT:onEvent( Event )
-- SCENERY
---
Event.TgtDCSUnit = Event.target
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
Event.TgtUnitName = Event.TgtDCSUnitName
Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target )
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
Event.TgtDCSUnitName = Event.TgtDCSUnit.getName and Event.TgtDCSUnit.getName() or nil
if Event.TgtDCSUnitName~=nil then
Event.TgtUnitName = Event.TgtDCSUnitName
Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target )
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
end
end
end
-- Weapon.
if Event.weapon and type(Event.weapon) == "table" then
if Event.weapon and type(Event.weapon) == "table" and Event.weapon.isExist and Event.weapon:isExist() then
Event.Weapon = Event.weapon
Event.WeaponName = Event.weapon:isExist() and Event.weapon:getTypeName() or "Unknown Weapon"
Event.WeaponUNIT = CLIENT:Find( Event.Weapon, '', true ) -- Sometimes, the weapon is a player unit!
@@ -1425,6 +1528,15 @@ function EVENT:onEvent( Event )
Event.Cargo = Event.cargo
Event.CargoName = Event.cargo.Name
end
-- Dynamic cargo Object
if Event.dynamiccargo then
Event.IniDynamicCargo = Event.dynamiccargo
Event.IniDynamicCargoName = Event.IniDynamicCargo.StaticName
if Event.IniDynamicCargo.Owner or Event.IniUnitName then
Event.IniPlayerName = Event.IniDynamicCargo.Owner or string.match(Event.IniUnitName or "None|00:00|PKG00","^(.+)|%d%d:%d%d|PKG%d+")
end
end
-- Zone object.
if Event.zone then

View File

@@ -79,7 +79,7 @@
do -- FSM
-- @type FSM
--- @type FSM
-- @field #string ClassName Name of the class.
-- @field Core.Scheduler#SCHEDULER CallScheduler Call scheduler.
-- @field #table options Options.
@@ -949,7 +949,7 @@ end
do -- FSM_CONTROLLABLE
-- @type FSM_CONTROLLABLE
--- @type FSM_CONTROLLABLE
-- @field Wrapper.Controllable#CONTROLLABLE Controllable
-- @extends Core.Fsm#FSM
@@ -1082,7 +1082,7 @@ end
do -- FSM_PROCESS
-- @type FSM_PROCESS
--- @type FSM_PROCESS
-- @field Tasking.Task#TASK Task
-- @extends Core.Fsm#FSM_CONTROLLABLE

View File

@@ -24,7 +24,7 @@
do -- Goal
-- @type GOAL
--- @type GOAL
-- @extends Core.Fsm#FSM
--- Models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized.
@@ -71,10 +71,10 @@ do -- Goal
ClassName = "GOAL",
}
-- @field #table GOAL.Players
--- @field #table GOAL.Players
GOAL.Players = {}
-- @field #number GOAL.TotalContributions
--- @field #number GOAL.TotalContributions
GOAL.TotalContributions = 0
--- GOAL Constructor.
@@ -145,7 +145,7 @@ do -- Goal
self.TotalContributions = self.TotalContributions + 1
end
-- @param #GOAL self
--- @param #GOAL self
-- @param #number Player contribution.
function GOAL:GetPlayerContribution( PlayerName )
return self.Players[PlayerName] or 0

View File

@@ -108,26 +108,30 @@ function MARKEROPS_BASE:New(Tagname,Keywords,Casesensitive)
--- On after "MarkAdded" event. Triggered when a Marker is added to the F10 map.
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkAdded
-- @param #MARKEROPS_BASE self
-- @param #string From The From state
-- @param #string Event The Event called
-- @param #string To The To state
-- @param #string Text The text on the marker
-- @param #table Keywords Table of matching keywords found in the Event text
-- @param #string From The From state.
-- @param #string Event The Event called.
-- @param #string To The To state.
-- @param #string Text The text on the marker.
-- @param #table Keywords Table of matching keywords found in the Event text.
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
-- @param #number MarkerID Id of this marker
-- @param #number CoalitionNumber Coalition of the marker creator
-- @param #number MarkerID Id of this marker.
-- @param #number CoalitionNumber Coalition of the marker creator.
-- @param #string PlayerName Name of the player creating/changing the mark. nil if it cannot be obtained.
-- @param Core.Event#EVENTDATA EventData the event data table.
--- On after "MarkChanged" event. Triggered when a Marker is changed on the F10 map.
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkChanged
-- @param #MARKEROPS_BASE self
-- @param #string From The From state
-- @param #string Event The Event called
-- @param #string To The To state
-- @param #string Text The text on the marker
-- @param #table Keywords Table of matching keywords found in the Event text
-- @param #string From The From state.
-- @param #string Event The Event called.
-- @param #string To The To state.
-- @param #string Text The text on the marker.
-- @param #table Keywords Table of matching keywords found in the Event text.
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
-- @param #number MarkerID Id of this marker
-- @param #number CoalitionNumber Coalition of the marker creator
-- @param #number MarkerID Id of this marker.
-- @param #number CoalitionNumber Coalition of the marker creator.
-- @param #string PlayerName Name of the player creating/changing the mark. nil if it cannot be obtained.
-- @param Core.Event#EVENTDATA EventData the event data table
--- On after "MarkDeleted" event. Triggered when a Marker is deleted from the F10 map.
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkDeleted
@@ -167,7 +171,7 @@ function MARKEROPS_BASE:OnEventMark(Event)
if Eventtext~=nil then
if self:_MatchTag(Eventtext) then
local matchtable = self:_MatchKeywords(Eventtext)
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition)
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
end
end
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
@@ -177,7 +181,7 @@ function MARKEROPS_BASE:OnEventMark(Event)
if Eventtext~=nil then
if self:_MatchTag(Eventtext) then
local matchtable = self:_MatchKeywords(Eventtext)
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition)
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
end
end
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then

View File

@@ -75,35 +75,37 @@ MESSAGE.Type = {
--- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{#MESSAGE.ToClient} or @{#MESSAGE.ToCoalition} or @{#MESSAGE.ToAll} to send these Messages to the respective recipients.
-- @param self
-- @param #string MessageText is the text of the Message.
-- @param #number MessageDuration is a number in seconds of how long the MESSAGE should be shown on the display panel.
-- @param #string MessageCategory (optional) is a string expressing the "category" of the Message. The category will be shown as the first text in the message followed by a ": ".
-- @param #string Text is the text of the Message.
-- @param #number Duration Duration in seconds how long the message text is shown.
-- @param #string Category (Optional) String expressing the "category" of the Message. The category will be shown as the first text in the message followed by a ": ".
-- @param #boolean ClearScreen (optional) Clear all previous messages if true.
-- @return #MESSAGE
-- @return #MESSAGE self
-- @usage
--
-- -- Create a series of new Messages.
-- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score".
-- -- MessageRED is meant to be sent to the RED players only, for 10 seconds, and is classified as "End of Mission", with ID "Win".
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
-- -- Create a series of new Messages.
-- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score".
-- -- MessageRED is meant to be sent to the RED players only, for 10 seconds, and is classified as "End of Mission", with ID "Win".
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", 25, "End of Mission" )
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" )
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" )
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score")
--
function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen )
function MESSAGE:New( Text, Duration, Category, ClearScreen )
local self = BASE:Inherit( self, BASE:New() )
self:F( { MessageText, MessageDuration, MessageCategory } )
self:F( { Text, Duration, Category } )
self.MessageType = nil
-- When no MessageCategory is given, we don't show it as a title...
if MessageCategory and MessageCategory ~= "" then
if MessageCategory:sub( -1 ) ~= "\n" then
self.MessageCategory = MessageCategory .. ": "
if Category and Category ~= "" then
if Category:sub( -1 ) ~= "\n" then
self.MessageCategory = Category .. ": "
else
self.MessageCategory = MessageCategory:sub( 1, -2 ) .. ":\n"
self.MessageCategory = Category:sub( 1, -2 ) .. ":\n"
end
else
self.MessageCategory = ""
@@ -114,9 +116,9 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen
self.ClearScreen = ClearScreen
end
self.MessageDuration = MessageDuration or 5
self.MessageDuration = Duration or 5
self.MessageTime = timer.getTime()
self.MessageText = MessageText:gsub( "^\n", "", 1 ):gsub( "\n$", "", 1 )
self.MessageText = Text:gsub( "^\n", "", 1 ):gsub( "\n$", "", 1 )
self.MessageSent = false
self.MessageGroup = false

View File

@@ -2669,9 +2669,9 @@ do -- COORDINATE
local date=UTILS.GetDCSMissionDate()
-- Debug output.
--self:I(string.format("Sun rise at lat=%.3f long=%.3f on %s (DayOfYear=%d): %s (%d sec of the day) (GMT %d)", Latitude, Longitude, date, DayOfYear, tostring(UTILS.SecondsToClock(sunrise)), sunrise, Tdiff))
--self:I(string.format("Sun rise at lat=%.3f long=%.3f on %s (DayOfYear=%d): %s (%s sec of the day) (GMT %d)", Latitude, Longitude, date, DayOfYear, tostring(UTILS.SecondsToClock(sunrise)), tonumber(sunrise) or "0", Tdiff))
if InSeconds then
if InSeconds or type(sunrise) == "string" then
return sunrise
else
return UTILS.SecondsToClock(sunrise, true)
@@ -2837,9 +2837,9 @@ do -- COORDINATE
local date=UTILS.GetDCSMissionDate()
-- Debug output.
--self:I(string.format("Sun set at lat=%.3f long=%.3f on %s (DayOfYear=%d): %s (%d sec of the day) (GMT %d)", Latitude, Longitude, date, DayOfYear, tostring(UTILS.SecondsToClock(sunrise)), sunrise, Tdiff))
--self:I(string.format("Sun set at lat=%.3f long=%.3f on %s (DayOfYear=%d): %s (%s sec of the day) (GMT %d)", Latitude, Longitude, date, DayOfYear, tostring(UTILS.SecondsToClock(sunrise)), tostring(sunrise) or "0", Tdiff))
if InSeconds then
if InSeconds or type(sunrise) == "string" then
return sunrise
else
return UTILS.SecondsToClock(sunrise, true)

View File

@@ -15,8 +15,7 @@
-- @module Core.Report
-- @image Core_Report.JPG
---
-- @type REPORT
--- @type REPORT
-- @extends Core.Base#BASE
--- Provides a handy means to create messages and reports.

View File

@@ -1,4 +1,4 @@
---- **Core** - SCHEDULEDISPATCHER dispatches the different schedules.
--- **Core** - SCHEDULEDISPATCHER dispatches the different schedules.
--
-- ===
--

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -535,12 +535,6 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
-- Name of the spawned static.
Template.name = self.InitStaticName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex)
-- Add and register the new static.
local mystatic=_DATABASE:AddStatic(Template.name)
-- Debug output.
self:T(Template)
-- Add static to the game.
local Static=nil --DCS#StaticObject
@@ -577,12 +571,28 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
self:T("Spawning Static")
self:T2({Template=Template})
Static=coalition.addStaticObject(CountryID, Template)
if Static then
self:T(string.format("Succesfully spawned static object \"%s\" ID=%d", Static:getName(), Static:getID()))
--[[
local static=StaticObject.getByName(Static:getName())
if static then
env.info(string.format("FF got static from StaticObject.getByName"))
else
env.error(string.format("FF error did NOT get static from StaticObject.getByName"))
end ]]
else
self:E(string.format("ERROR: DCS static object \"%s\" is nil!", tostring(Template.name)))
end
end
-- Add and register the new static.
local mystatic=_DATABASE:AddStatic(Template.name)
-- If there is a SpawnFunction hook defined, call it.
if self.SpawnFunctionHook then
-- delay calling this for .3 seconds so that it hopefully comes after the BIRTH event of the group.
self:ScheduleOnce(0.3,self.SpawnFunctionHook,mystatic, unpack(self.SpawnFunctionArguments))
self:ScheduleOnce(0.3, self.SpawnFunctionHook, mystatic, unpack(self.SpawnFunctionArguments))
end
return mystatic

View File

@@ -18,7 +18,7 @@
do -- UserFlag
-- @type USERFLAG
--- @type USERFLAG
-- @field #string ClassName Name of the class
-- @field #string UserFlagName Name of the flag.
-- @extends Core.Base#BASE

View File

@@ -20,7 +20,7 @@
do -- Velocity
-- @type VELOCITY
--- @type VELOCITY
-- @extends Core.Base#BASE
@@ -127,7 +127,7 @@ end
do -- VELOCITY_POSITIONABLE
-- @type VELOCITY_POSITIONABLE
--- @type VELOCITY_POSITIONABLE
-- @extends Core.Base#BASE

View File

@@ -2,8 +2,7 @@
-- @module Core.Zone_Detection
-- @image MOOSE.JPG
---
-- @type ZONE_DETECTION
--- @type ZONE_DETECTION
-- @field DCS#Vec2 Vec2 The current location of the zone.
-- @field DCS#Distance Radius The radius of the zone.
-- @extends #ZONE_BASE

View File

@@ -14,6 +14,7 @@ do -- world
-- @field #world.event event [https://wiki.hoggitworld.com/view/DCS_enum_world](https://wiki.hoggitworld.com/view/DCS_enum_world)
-- @field #world.BirthPlace BirthPlace The birthplace enumerator is used to define where an aircraft or helicopter has spawned in association with birth events.
-- @field #world.VolumeType VolumeType The volumeType enumerator defines the types of 3d geometery used within the [world.searchObjects](https://wiki.hoggitworld.com/view/DCS_func_searchObjects) function.
-- @field #world.weather weather Weather functions for fog etc.
--- The world singleton contains functions centered around two different but extremely useful functions.
-- * Events and event handlers are all governed within world.
@@ -132,6 +133,36 @@ do -- world
-- @function [parent=#world] getAirbases
-- @param #number coalitionId The coalition side number ID. Default is all airbases are returned.
-- @return #table Table of DCS airbase objects.
--- Weather functions.
-- @type world.weather
--- Fog animation data structure.
-- @type world.FogAnimation
-- @field #number time
-- @field #number visibility
-- @field #number thickness
--- Returns the current fog thickness.
-- @function [parent=#world.weather] getFogThickness Returns the fog thickness.
-- @return #number Fog thickness in meters. If there is no fog, zero is returned.
--- Sets the fog thickness instantly. Any current fog animation is discarded.
-- @function [parent=#world.weather] setFogThickness
-- @param #number thickness Fog thickness in meters. Set to zero to disable fog.
--- Returns the current fog visibility distance.
-- @function [parent=#world.weather] getFogVisibilityDistance Returns the current maximum visibility distance in meters. Returns zero if fog is not present.
--- Instantly sets the maximum visibility distance of fog at sea level when looking at the horizon. Any current fog animation is discarded. Set zero to disable the fog.
-- @function [parent=#world.weather] setFogVisibilityDistance
-- @param #number visibility Max fog visibility in meters. Set to zero to disable fog.
--- Sets fog animation keys. Time is set in seconds and relative to the current simulation time, where time=0 is the current moment.
-- Time must be increasing. Previous animation is always discarded despite the data being correct.
-- @function [parent=#world.weather] setFogAnimation
-- @param #world.FogAnimation animation List of fog animations
end -- world
@@ -407,7 +438,7 @@ do -- coalition
-- @param #table groupData Group data table.
-- @return DCS#Group The spawned Group object.
--- Dynamically spawns a static object. See [hoggit](https://wiki.hoggitworld.com/view/DCS_func_addGroup)
--- Dynamically spawns a static object. See [hoggit](https://wiki.hoggitworld.com/view/DCS_func_addStaticObject)
-- @function [parent=#coalition] addStaticObject
-- @param #number countryId Id of the country.
-- @param #table groupData Group data table.
@@ -420,6 +451,7 @@ end -- coalition
do -- Types
--- Descriptors.
-- @type Desc
-- @field #number speedMax0 Max speed in meters/second at zero altitude.
-- @field #number massEmpty Empty mass in kg.
@@ -1013,14 +1045,16 @@ do -- Spot
end -- Spot
do -- Controller
--- Controller is an object that performs A.I.-tasks. Other words controller is an instance of A.I.. Controller stores current main task, active enroute tasks and behavior options. Controller performs commands. Please, read DCS A-10C GUI Manual EN.pdf chapter "Task Planning for Unit Groups", page 91 to understand A.I. system of DCS:A-10C.
--
-- This class has 2 types of functions:
--
-- * Tasks
-- * Commands: Commands are instant actions those required zero time to perform. Commands may be used both for control unit/group behavior and control game mechanics.
-- * Commands: Commands are instant actions those required zero time to perform. Commands may be used both for control unit/group behavior and control game mechanics.
--
-- @type Controller
-- @field #Controller.Detection Detection Enum contains identifiers of surface types.
-- @field #Controller.Detection Detection Enum contains identifiers of surface types.
--- Enables and disables the controller.
-- Note: Now it works only for ground / naval groups!
@@ -1079,18 +1113,18 @@ do -- Controller
-- Detection
--- Enum contains identifiers of surface types.
--- Enum containing detection types.
-- @type Controller.Detection
-- @field VISUAL
-- @field OPTIC
-- @field RADAR
-- @field IRST
-- @field RWR
-- @field DLINK
-- @field #number VISUAL Visual detection. Numeric value 1.
-- @field #number OPTIC Optical detection. Numeric value 2.
-- @field #number RADAR Radar detection. Numeric value 4.
-- @field #number IRST Infra-red search and track detection. Numeric value 8.
-- @field #number RWR Radar Warning Receiver detection. Numeric value 16.
-- @field #number DLINK Data link detection. Numeric value 32.
--- Detected target.
-- @type DetectedTarget
-- @field Wrapper.Object#Object object The target
-- @type Controller.DetectedTarget
-- @field DCS#Object object The target
-- @field #boolean visible The target is visible
-- @field #boolean type The target type is known
-- @field #boolean distance Distance to the target is known
@@ -1103,9 +1137,9 @@ do -- Controller
-- @param #Controller.Detection detection Controller.Detection detection1, Controller.Detection detection2, ... Controller.Detection detectionN
-- @return #boolean detected True if the target is detected.
-- @return #boolean visible Has effect only if detected is true. True if the target is visible now.
-- @return #boolean type Has effect only if detected is true. True if the target type is known.
-- @return #boolean distance Has effect only if detected is true. True if the distance to the target is known.
-- @return #ModelTime lastTime Has effect only if visible is false. Last time when target was seen.
-- @return #boolean type Has effect only if detected is true. True if the target type is known.
-- @return #boolean distance Has effect only if detected is true. True if the distance to the target is known.
-- @return #Vec3 lastPos Has effect only if visible is false. Last position of the target when it was seen.
-- @return #Vec3 lastVel Has effect only if visible is false. Last velocity of the target when it was seen.
@@ -1131,6 +1165,7 @@ end -- Controller
do -- Unit
--- Unit.
-- @type Unit
-- @extends #CoalitionObject
-- @field ID Identifier of an unit. It assigned to an unit by the Mission Editor automatically.

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,7 @@
-- ### Author: FlightControl - Framework Design & Programming
-- ### Refactoring to use the Runway auto-detection: Applevangelist
-- @date August 2022
-- Last Update Nov 2023
-- Last Update Oct 2024
--
-- ===
--
@@ -721,14 +721,18 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
if NotInRunwayZone then
local Taxi = Client:GetState( self, "Taxi" )
if IsOnGround then
local Taxi = Client:GetState( self, "Taxi" )
self:T( Taxi )
if Taxi == false then
local Velocity = VELOCITY:New( AirbaseMeta.KickSpeed or self.KickSpeed )
Client:Message( "Welcome to " .. AirbaseID .. ". The maximum taxiing speed is " ..
Velocity:ToString() , 20, "ATC" )
Client:SetState( self, "Taxi", true )
Client:SetState( self, "Speeding", false )
Client:SetState( self, "Warnings", 0 )
end
-- TODO: GetVelocityKMH function usage
@@ -737,7 +741,7 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
local IsAboveRunway = Client:IsAboveRunway()
self:T( {IsAboveRunway, IsOnGround, Velocity:Get() })
if IsOnGround then
if IsOnGround and not Taxi then
local Speeding = false
if AirbaseMeta.MaximumKickSpeed then
if Velocity:Get() > AirbaseMeta.MaximumKickSpeed then
@@ -749,15 +753,17 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
end
end
if Speeding == true then
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() ..
" has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
Client:Destroy()
Client:SetState( self, "Speeding", false )
Client:SetState( self, "Warnings", 0 )
--MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() ..
-- " has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
--Client:Destroy()
Client:SetState( self, "Speeding", true )
local SpeedingWarnings = Client:GetState( self, "Warnings" )
Client:SetState( self, "Warnings", SpeedingWarnings + 1 )
Client:Message( "Warning " .. SpeedingWarnings .. "/3! Airbase traffic rule violation! Slow down now! Your speed is " ..
Velocity:ToString(), 5, "ATC" )
end
end
if IsOnGround then
local Speeding = false
@@ -1035,23 +1041,23 @@ end
-- The following airbases are monitored at the Nevada region.
-- Use the @{Wrapper.Airbase#AIRBASE.Nevada} enumeration to select the airbases to be monitored.
--
-- * `AIRBASE.Nevada.Beatty_Airport`
-- * `AIRBASE.Nevada.Boulder_City_Airport`
-- * `AIRBASE.Nevada.Creech_AFB`
-- * `AIRBASE.Nevada.Beatty`
-- * `AIRBASE.Nevada.Boulder_City`
-- * `AIRBASE.Nevada.Creech`
-- * `AIRBASE.Nevada.Echo_Bay`
-- * `AIRBASE.Nevada.Groom_Lake_AFB`
-- * `AIRBASE.Nevada.Henderson_Executive_Airport`
-- * `AIRBASE.Nevada.Jean_Airport`
-- * `AIRBASE.Nevada.Laughlin_Airport`
-- * `AIRBASE.Nevada.Groom_Lake`
-- * `AIRBASE.Nevada.Henderson_Executive`
-- * `AIRBASE.Nevada.Jean`
-- * `AIRBASE.Nevada.Laughlin`
-- * `AIRBASE.Nevada.Lincoln_County`
-- * `AIRBASE.Nevada.McCarran_International_Airport`
-- * `AIRBASE.Nevada.McCarran_International`
-- * `AIRBASE.Nevada.Mesquite`
-- * `AIRBASE.Nevada.Mina_Airport`
-- * `AIRBASE.Nevada.Nellis_AFB`
-- * `AIRBASE.Nevada.Mina`
-- * `AIRBASE.Nevada.Nellis`
-- * `AIRBASE.Nevada.North_Las_Vegas`
-- * `AIRBASE.Nevada.Pahute_Mesa_Airstrip`
-- * `AIRBASE.Nevada.Tonopah_Airport`
-- * `AIRBASE.Nevada.Tonopah_Test_Range_Airfield`
-- * `AIRBASE.Nevada.Pahute_Mesa`
-- * `AIRBASE.Nevada.Tonopah`
-- * `AIRBASE.Nevada.Tonopah_Test_Range`
--
-- # Installation
--
@@ -1088,10 +1094,10 @@ end
--
-- -- Monitor specific airbases.
-- ATC_Ground = ATC_GROUND_NEVADA:New(
-- { AIRBASE.Nevada.Laughlin_Airport,
-- { AIRBASE.Nevada.Laughlin,
-- AIRBASE.Nevada.Lincoln_County,
-- AIRBASE.Nevada.North_Las_Vegas,
-- AIRBASE.Nevada.McCarran_International_Airport
-- AIRBASE.Nevada.McCarran_International
-- }
-- )
--
@@ -1330,33 +1336,33 @@ end
-- The following airbases are monitored at the PersianGulf region.
-- Use the @{Wrapper.Airbase#AIRBASE.PersianGulf} enumeration to select the airbases to be monitored.
--
-- * `AIRBASE.PersianGulf.Abu_Musa_Island_Airport`
-- * `AIRBASE.PersianGulf.Al_Dhafra_AB`
-- * `AIRBASE.PersianGulf.Abu_Musa_Island`
-- * `AIRBASE.PersianGulf.Al_Dhafra_AFB`
-- * `AIRBASE.PersianGulf.Al_Maktoum_Intl`
-- * `AIRBASE.PersianGulf.Al_Minhad_AB`
-- * `AIRBASE.PersianGulf.Al_Minhad_AFB`
-- * `AIRBASE.PersianGulf.Bandar_Abbas_Intl`
-- * `AIRBASE.PersianGulf.Bandar_Lengeh`
-- * `AIRBASE.PersianGulf.Dubai_Intl`
-- * `AIRBASE.PersianGulf.Fujairah_Intl`
-- * `AIRBASE.PersianGulf.Havadarya`
-- * `AIRBASE.PersianGulf.Kerman_Airport`
-- * `AIRBASE.PersianGulf.Kerman`
-- * `AIRBASE.PersianGulf.Khasab`
-- * `AIRBASE.PersianGulf.Lar_Airbase`
-- * `AIRBASE.PersianGulf.Lar`
-- * `AIRBASE.PersianGulf.Qeshm_Island`
-- * `AIRBASE.PersianGulf.Sharjah_Intl`
-- * `AIRBASE.PersianGulf.Shiraz_International_Airport`
-- * `AIRBASE.PersianGulf.Shiraz_Intl`
-- * `AIRBASE.PersianGulf.Sir_Abu_Nuayr`
-- * `AIRBASE.PersianGulf.Sirri_Island`
-- * `AIRBASE.PersianGulf.Tunb_Island_AFB`
-- * `AIRBASE.PersianGulf.Tunb_Kochak`
-- * `AIRBASE.PersianGulf.Sas_Al_Nakheel_Airport`
-- * `AIRBASE.PersianGulf.Bandar_e_Jask_airfield`
-- * `AIRBASE.PersianGulf.Abu_Dhabi_International_Airport`
-- * `AIRBASE.PersianGulf.Al_Bateen_Airport`
-- * `AIRBASE.PersianGulf.Kish_International_Airport`
-- * `AIRBASE.PersianGulf.Al_Ain_International_Airport`
-- * `AIRBASE.PersianGulf.Lavan_Island_Airport`
-- * `AIRBASE.PersianGulf.Jiroft_Airport`
-- * `AIRBASE.PersianGulf.Sas_Al_Nakheel`
-- * `AIRBASE.PersianGulf.Bandar_e_Jask`
-- * `AIRBASE.PersianGulf.Abu_Dhabi_Intl`
-- * `AIRBASE.PersianGulf.Al_Bateen`
-- * `AIRBASE.PersianGulf.Kish_Intl`
-- * `AIRBASE.PersianGulf.Al_Ain_Intl`
-- * `AIRBASE.PersianGulf.Lavan_Island`
-- * `AIRBASE.PersianGulf.Jiroft`
--
-- # Installation
--
@@ -1391,8 +1397,8 @@ end
-- AirbasePoliceCaucasus = ATC_GROUND_PERSIANGULF:New()
--
-- ATC_Ground = ATC_GROUND_PERSIANGULF:New(
-- { AIRBASE.PersianGulf.Kerman_Airport,
-- AIRBASE.PersianGulf.Al_Minhad_AB
-- { AIRBASE.PersianGulf.Kerman,
-- AIRBASE.PersianGulf.Al_Minhad_AFB
-- }
-- )
--

View File

@@ -1,806 +0,0 @@
--- **Functional** -- Send a truck to supply artillery groups.
--
-- ===
--
-- **AMMOTRUCK** - Send a truck to supply artillery groups.
--
-- ===
--
-- ## Missions:
--
-- Demo missions can be found on [GitHub](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Functional/AmmoTruck)
--
-- ===
--
-- ### Author : **applevangelist**
--
-- @module Functional.AmmoTruck
-- @image Artillery.JPG
--
-- Last update: July 2023
-------------------------------------------------------------------------
--- **AMMOTRUCK** class, extends Core.Fsm#FSM
-- @type AMMOTRUCK
-- @field #string ClassName Class Name
-- @field #string lid Lid for log entries
-- @field #string version Version string
-- @field #string alias Alias name
-- @field #boolean debug Debug flag
-- @field #table trucklist List of (alive) #AMMOTRUCK.data trucks
-- @field #table targetlist List of (alive) #AMMOTRUCK.data artillery
-- @field #number coalition Coalition this is for
-- @field Core.Set#SET_GROUP truckset SET of trucks
-- @field Core.Set#SET_GROUP targetset SET of artillery
-- @field #table remunitionqueue List of (alive) #AMMOTRUCK.data artillery to be reloaded
-- @field #table waitingtargets List of (alive) #AMMOTRUCK.data artillery waiting
-- @field #number ammothreshold Threshold (min) ammo before sending a truck
-- @field #number remunidist Max distance trucks will go
-- @field #number monitor Monitor interval in seconds
-- @field #number unloadtime Unload time in seconds
-- @field #number waitingtime Max waiting time in seconds
-- @field #boolean routeonroad Route truck on road if true (default)
-- @field #number reloads Number of reloads a single truck can do before he must return home
-- @extends Core.Fsm#FSM
--- *Amateurs talk about tactics, but professionals study logistics.* - General Robert H Barrow, USMC
--
-- Simple Class to re-arm your artillery with trucks.
--
-- #AMMOTRUCK
--
-- * Controls a SET\_GROUP of trucks which will re-arm a SET\_GROUP of artillery groups when they run out of ammunition.
--
-- ## 1 The AMMOTRUCK concept
--
-- A SET\_GROUP of trucks which will re-arm a SET\_GROUP of artillery groups when they run out of ammunition. They will be based on a
-- homebase and drive from there to the artillery groups and then back home.
-- Trucks are the **only known in-game mechanic** to re-arm artillery and other units in DCS. Working units are e.g.: M-939 (blue), Ural-375 and ZIL-135 (both red).
--
-- ## 2 Set-up
--
-- Define a set of trucks and a set of artillery:
--
-- local truckset = SET_GROUP:New():FilterCoalitions("blue"):FilterActive(true):FilterCategoryGround():FilterPrefixes("Ammo Truck"):FilterStart()
-- local ariset = SET_GROUP:New():FilterCoalitions("blue"):FilterActive(true):FilterCategoryGround():FilterPrefixes("Artillery"):FilterStart()
--
-- Create an AMMOTRUCK object to take care of the artillery using the trucks, with a homezone:
--
-- local ammotruck = AMMOTRUCK:New(truckset,ariset,coalition.side.BLUE,"Logistics",ZONE:FindByName("HomeZone")
--
-- ## 2 Options and their default values
--
-- ammotruck.ammothreshold = 5 -- send a truck when down to this many rounds
-- ammotruck.remunidist = 20000 -- 20km - send trucks max this far from home
-- ammotruck.unloadtime = 600 -- 10 minutes - min time to unload ammunition
-- ammotruck.waitingtime = 1800 -- 30 mintes - wait max this long until remunition is done
-- ammotruck.monitor = -60 -- 1 minute - AMMOTRUCK checks run every one minute
-- ammotruck.routeonroad = true -- Trucks will **try** to drive on roads
-- ammotruck.usearmygroup = false -- If true, will make use of ARMYGROUP in the background (if used in DEV branch)
-- ammotruck.reloads = 5 -- Maxn re-arms a truck can do before he needs to go home and restock. Set to -1 for unlimited
--
-- ## 3 FSM Events to shape mission
--
-- Truck has been sent off:
--
-- function ammotruck:OnAfterRouteTruck(From, Event, To, Truckdata, Aridata)
-- ...
-- end
--
-- Truck has arrived:
--
-- function ammotruck:OnAfterTruckArrived(From, Event, To, Truckdata)
-- ...
-- end
--
-- Truck is unloading:
--
-- function ammotruck:OnAfterTruckUnloading(From, Event, To, Truckdata)
-- ...
-- end
--
-- Truck is returning home:
--
-- function ammotruck:OnAfterTruckReturning(From, Event, To, Truckdata)
-- ...
-- end
--
-- Truck is arrived at home:
--
-- function ammotruck:OnAfterTruckHome(From, Event, To, Truckdata)
-- ...
-- end
--
-- @field #AMMOTRUCK
AMMOTRUCK = {
ClassName = "AMMOTRUCK",
lid = "",
version = "0.0.12",
alias = "",
debug = false,
trucklist = {},
targetlist = {},
coalition = nil,
truckset = nil,
targetset = nil,
remunitionqueue = {},
waitingtargets = {},
ammothreshold = 5,
remunidist = 20000,
monitor = -60,
unloadtime = 600,
waitingtime = 1800,
routeonroad = true,
reloads = 5,
}
---
-- @type AMMOTRUCK.State
AMMOTRUCK.State = {
IDLE = "idle",
DRIVING = "driving",
ARRIVED = "arrived",
UNLOADING = "unloading",
RETURNING = "returning",
WAITING = "waiting",
RELOADING = "reloading",
OUTOFAMMO = "outofammo",
REQUESTED = "requested",
}
---
--@type AMMOTRUCK.data
--@field Wrapper.Group#GROUP group
--@field #string name
--@field #AMMOTRUCK.State statusquo
--@field #number timestamp
--@field #number ammo
--@field Core.Point#COORDINATE coordinate
--@field #string targetname
--@field Wrapper.Group#GROUP targetgroup
--@field Core.Point#COORDINATE targetcoordinate
--@field #number reloads
---
-- @param #AMMOTRUCK self
-- @param Core.Set#SET_GROUP Truckset Set of truck groups
-- @param Core.Set#SET_GROUP Targetset Set of artillery groups
-- @param #number Coalition Coalition
-- @param #string Alias Alias Name
-- @param Core.Zone#ZONE Homezone Home, return zone for trucks
-- @return #AMMOTRUCK self
-- @usage
-- Define a set of trucks and a set of artillery:
-- local truckset = SET_GROUP:New():FilterCoalitions("blue"):FilterActive(true):FilterCategoryGround():FilterPrefixes("Ammo Truck"):FilterStart()
-- local ariset = SET_GROUP:New():FilterCoalitions("blue"):FilterActive(true):FilterCategoryGround():FilterPrefixes("Artillery"):FilterStart()
--
-- Create an AMMOTRUCK object to take care of the artillery using the trucks, with a homezone:
-- local ammotruck = AMMOTRUCK:New(truckset,ariset,coalition.side.BLUE,"Logistics",ZONE:FindByName("HomeZone")
function AMMOTRUCK:New(Truckset,Targetset,Coalition,Alias,Homezone)
-- Inherit everything from BASE class.
local self=BASE:Inherit(self, FSM:New()) -- #AMMOTRUCK
self.truckset = Truckset -- Core.Set#SET_GROUP
self.targetset = Targetset -- Core.Set#SET_GROUP
self.coalition = Coalition -- #number
self.alias = Alias -- #string
self.debug = false
self.remunitionqueue = {}
self.trucklist = {}
self.targetlist = {}
self.ammothreshold = 5
self.remunidist = 20000
self.homezone = Homezone -- Core.Zone#ZONE
self.waitingtime = 1800
self.usearmygroup = false
self.hasarmygroup = false
-- Log id.
self.lid=string.format("AMMOTRUCK %s | %s | ", self.version, self.alias)
self:SetStartState("Stopped")
self:AddTransition("Stopped", "Start", "Running")
self:AddTransition("*", "Monitor", "*")
self:AddTransition("*", "RouteTruck", "*")
self:AddTransition("*", "TruckArrived", "*")
self:AddTransition("*", "TruckUnloading", "*")
self:AddTransition("*", "TruckReturning", "*")
self:AddTransition("*", "TruckHome", "*")
self:AddTransition("*", "Stop", "Stopped")
self:__Start(math.random(5,10))
self:I(self.lid .. "Started")
------------------------
--- Pseudo Functions ---
------------------------
--- Triggers the FSM event "Stop". Stops the AMMOTRUCK and all its event handlers.
-- @function [parent=#AMMOTRUCK] Stop
-- @param #AMMOTRUCK self
--- Triggers the FSM event "Stop" after a delay. Stops the AMMOTRUCK and all its event handlers.
-- @function [parent=#AMMOTRUCK] __Stop
-- @param #AMMOTRUCK self
-- @param #number delay Delay in seconds.
--- On after "RouteTruck" event.
-- @function [parent=#AMMOTRUCK] OnAfterRouteTruck
-- @param #AMMOTRUCK self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #AMMOTRUCK.data Truck
-- @param #AMMOTRUCK.data Artillery
--- On after "TruckUnloading" event.
-- @function [parent=#AMMOTRUCK] OnAfterTruckUnloading
-- @param #AMMOTRUCK self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #AMMOTRUCK.data Truck
--- On after "TruckReturning" event.
-- @function [parent=#AMMOTRUCK] OnAfterTruckReturning
-- @param #AMMOTRUCK self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #AMMOTRUCK.data Truck
--- On after "RouteTruck" event.
-- @function [parent=#AMMOTRUCK] OnAfterRouteTruck
-- @param #AMMOTRUCK self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #AMMOTRUCK.data Truck
--- On after "TruckHome" event.
-- @function [parent=#AMMOTRUCK] OnAfterTruckHome
-- @param #AMMOTRUCK self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #AMMOTRUCK.data Truck
return self
end
---
-- @param #AMMOTRUCK self
-- @param #table dataset table of #AMMOTRUCK.data entries
-- @return #AMMOTRUCK self
function AMMOTRUCK:CheckDrivingTrucks(dataset)
self:T(self.lid .. " CheckDrivingTrucks")
local data = dataset
for _,_data in pairs (data) do
local truck = _data -- #AMMOTRUCK.data
-- see if we arrived at destination
local coord = truck.group:GetCoordinate()
local tgtcoord = truck.targetcoordinate
local dist = coord:Get2DDistance(tgtcoord)
if dist <= 150 then
-- arrived
truck.statusquo = AMMOTRUCK.State.ARRIVED
truck.timestamp = timer.getAbsTime()
truck.coordinate = coord
self:__TruckArrived(1,truck)
end
-- still driving?
local Tnow = timer.getAbsTime()
if Tnow - truck.timestamp > 30 then
local group = truck.group
if self.usearmygroup then
group = truck.group:GetGroup()
end
local currspeed = group:GetVelocityKMH()
if truck.lastspeed then
if truck.lastspeed == 0 and currspeed == 0 then
self:T(truck.group:GetName().." Is not moving!")
-- try and move it
truck.timestamp = timer.getAbsTime()
if self.routeonroad then
group:RouteGroundOnRoad(truck.targetcoordinate,30,2,"Vee")
else
group:RouteGroundTo(truck.targetcoordinate,30,"Vee",2)
end
end
truck.lastspeed = currspeed
else
truck.lastspeed = currspeed
truck.timestamp = timer.getAbsTime()
end
self:I({truck=truck.group:GetName(),currspeed=currspeed,lastspeed=truck.lastspeed})
end
end
return self
end
---
-- @param #AMMOTRUCK self
-- @param Wrapper.Group#GROUP Group
-- @return #AMMOTRUCK self
function AMMOTRUCK:GetAmmoStatus(Group)
local ammotot, shells, rockets, bombs, missiles, narti = Group:GetAmmunition()
return rockets+missiles+narti
end
---
-- @param #AMMOTRUCK self
-- @param #table dataset table of #AMMOTRUCK.data entries
-- @return #AMMOTRUCK self
function AMMOTRUCK:CheckWaitingTargets(dataset)
self:T(self.lid .. " CheckWaitingTargets")
local data = dataset
for _,_data in pairs (data) do
local truck = _data -- #AMMOTRUCK.data
-- see how long we're waiting - maybe ammo truck is dead?
local Tnow = timer.getAbsTime()
local Tdiff = Tnow - truck.timestamp
if Tdiff > self.waitingtime then
local hasammo = self:GetAmmoStatus(truck.group)
if hasammo <= self.ammothreshold then
truck.statusquo = AMMOTRUCK.State.OUTOFAMMO
else
truck.statusquo = AMMOTRUCK.State.IDLE
end
end
end
return self
end
---
-- @param #AMMOTRUCK self
-- @param #table dataset table of #AMMOTRUCK.data entries
-- @return #AMMOTRUCK self
function AMMOTRUCK:CheckReturningTrucks(dataset)
self:T(self.lid .. " CheckReturningTrucks")
local data = dataset
local tgtcoord = self.homezone:GetCoordinate()
local radius = self.homezone:GetRadius()
for _,_data in pairs (data) do
local truck = _data -- #AMMOTRUCK.data
-- see if we arrived at destination
local coord = truck.group:GetCoordinate()
local dist = coord:Get2DDistance(tgtcoord)
self:T({name=truck.name,radius=radius,distance=dist})
if dist <= radius then
-- arrived
truck.statusquo = AMMOTRUCK.State.IDLE
truck.timestamp = timer.getAbsTime()
truck.coordinate = coord
truck.reloads = self.reloads or 5
self:__TruckHome(1,truck)
end
end
return self
end
---
-- @param #AMMOTRUCK self
-- @param #string name Artillery group name to find
-- @return #AMMOTRUCK.data Data
function AMMOTRUCK:FindTarget(name)
self:T(self.lid .. " FindTarget")
local data = nil
local dataset = self.targetlist
for _,_entry in pairs(dataset) do
local entry = _entry -- #AMMOTRUCK.data
if entry.name == name then
data = entry
break
end
end
return data
end
---
-- @param #AMMOTRUCK self
-- @param #string name Truck group name to find
-- @return #AMMOTRUCK.data Data
function AMMOTRUCK:FindTruck(name)
self:T(self.lid .. " FindTruck")
local data = nil
local dataset = self.trucklist
for _,_entry in pairs(dataset) do
local entry = _entry -- #AMMOTRUCK.data
if entry.name == name then
data = entry
break
end
end
return data
end
---
-- @param #AMMOTRUCK self
-- @param #table dataset table of #AMMOTRUCK.data entries
-- @return #AMMOTRUCK self
function AMMOTRUCK:CheckArrivedTrucks(dataset)
self:T(self.lid .. " CheckArrivedTrucks")
local data = dataset
for _,_data in pairs (data) do
-- set to unloading
local truck = _data -- #AMMOTRUCK.data
truck.statusquo = AMMOTRUCK.State.UNLOADING
truck.timestamp = timer.getAbsTime()
self:__TruckUnloading(2,truck)
-- set target to reloading
local aridata = self:FindTarget(truck.targetname) -- #AMMOTRUCK.data
if aridata then
aridata.statusquo = AMMOTRUCK.State.RELOADING
aridata.timestamp = timer.getAbsTime()
end
end
return self
end
---
-- @param #AMMOTRUCK self
-- @param #table dataset table of #AMMOTRUCK.data entries
-- @return #AMMOTRUCK self
function AMMOTRUCK:CheckUnloadingTrucks(dataset)
self:T(self.lid .. " CheckUnloadingTrucks")
local data = dataset
for _,_data in pairs (data) do
-- check timestamp
local truck = _data -- #AMMOTRUCK.data
local Tnow = timer.getAbsTime()
local Tpassed = Tnow - truck.timestamp
local hasammo = self:GetAmmoStatus(truck.targetgroup)
if Tpassed > self.unloadtime and hasammo > self.ammothreshold then
truck.statusquo = AMMOTRUCK.State.RETURNING
truck.timestamp = timer.getAbsTime()
self:__TruckReturning(2,truck)
-- set target to reloaded
local aridata = self:FindTarget(truck.targetname) -- #AMMOTRUCK.data
if aridata then
aridata.statusquo = AMMOTRUCK.State.IDLE
aridata.timestamp = timer.getAbsTime()
end
end
end
return self
end
---
-- @param #AMMOTRUCK self
-- @return #AMMOTRUCK self
function AMMOTRUCK:CheckTargetsAlive()
self:T(self.lid .. " CheckTargetsAlive")
local arilist = self.targetlist
for _,_ari in pairs(arilist) do
local ari = _ari -- #AMMOTRUCK.data
if ari.group and ari.group:IsAlive() then
-- everything fine
else
-- ari dead
self.targetlist[ari.name] = nil
end
end
-- new arrivals?
local aritable = self.targetset:GetSetObjects() --#table
for _,_ari in pairs(aritable) do
local ari = _ari -- Wrapper.Group#GROUP
if ari and ari:IsAlive() and not self.targetlist[ari:GetName()] then
local name = ari:GetName()
local newari = {} -- #AMMOTRUCK.data
newari.name = name
newari.group = ari
newari.statusquo = AMMOTRUCK.State.IDLE
newari.timestamp = timer.getAbsTime()
newari.coordinate = ari:GetCoordinate()
local hasammo = self:GetAmmoStatus(ari)
--newari.ammo = ari:GetAmmunition()
newari.ammo = hasammo
self.targetlist[name] = newari
end
end
return self
end
---
-- @param #AMMOTRUCK self
-- @return #AMMOTRUCK self
function AMMOTRUCK:CheckTrucksAlive()
self:T(self.lid .. " CheckTrucksAlive")
local trucklist = self.trucklist
for _,_truck in pairs(trucklist) do
local truck = _truck -- #AMMOTRUCK.data
if truck.group and truck.group:IsAlive() then
-- everything fine
else
-- truck dead
local tgtname = truck.targetname
local targetdata = self:FindTarget(tgtname) -- #AMMOTRUCK.data
if targetdata then
if targetdata.statusquo ~= AMMOTRUCK.State.IDLE then
targetdata.statusquo = AMMOTRUCK.State.IDLE
end
end
self.trucklist[truck.name] = nil
end
end
-- new arrivals?
local trucktable = self.truckset:GetSetObjects() --#table
for _,_truck in pairs(trucktable) do
local truck = _truck -- Wrapper.Group#GROUP
if truck and truck:IsAlive() and not self.trucklist[truck:GetName()] then
local name = truck:GetName()
local newtruck = {} -- #AMMOTRUCK.data
newtruck.name = name
newtruck.group = truck
if self.hasarmygroup then
-- is (not) already ARMYGROUP?
if truck.ClassName and truck.ClassName == "GROUP" then
local trucker = ARMYGROUP:New(truck)
trucker:Activate()
newtruck.group = trucker
end
end
newtruck.statusquo = AMMOTRUCK.State.IDLE
newtruck.timestamp = timer.getAbsTime()
newtruck.coordinate = truck:GetCoordinate()
newtruck.reloads = self.reloads or 5
self.trucklist[name] = newtruck
end
end
return self
end
---
-- @param #AMMOTRUCK self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #AMMOTRUCK self
function AMMOTRUCK:onafterStart(From, Event, To)
self:T({From, Event, To})
if ARMYGROUP and self.usearmygroup then
self.hasarmygroup = true
else
self.hasarmygroup = false
end
if self.debug then
BASE:TraceOn()
BASE:TraceClass("AMMOTRUCK")
end
self:CheckTargetsAlive()
self:CheckTrucksAlive()
self:__Monitor(-30)
return self
end
---
-- @param #AMMOTRUCK self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #AMMOTRUCK self
function AMMOTRUCK:onafterMonitor(From, Event, To)
self:T({From, Event, To})
self:CheckTargetsAlive()
self:CheckTrucksAlive()
-- update ammo state
local remunition = false
local remunitionqueue = {}
local waitingtargets = {}
for _,_ari in pairs(self.targetlist) do
local data = _ari -- #AMMOTRUCK.data
if data.group and data.group:IsAlive() then
data.ammo = self:GetAmmoStatus(data.group)
data.timestamp = timer.getAbsTime()
local text = string.format("Ari %s | Ammo %d | State %s",data.name,data.ammo,data.statusquo)
self:T(text)
if data.ammo <= self.ammothreshold and (data.statusquo == AMMOTRUCK.State.IDLE or data.statusquo == AMMOTRUCK.State.OUTOFAMMO) then
-- add to remu queue
data.statusquo = AMMOTRUCK.State.OUTOFAMMO
remunitionqueue[#remunitionqueue+1] = data
remunition = true
elseif data.statusquo == AMMOTRUCK.State.WAITING then
waitingtargets[#waitingtargets+1] = data
end
else
self.targetlist[data.name] = nil
end
end
-- sort trucks in buckets
local idletrucks = {}
local drivingtrucks = {}
local unloadingtrucks = {}
local arrivedtrucks = {}
local returningtrucks = {}
local found = false
for _,_truckdata in pairs(self.trucklist) do
local data = _truckdata -- #AMMOTRUCK.data
if data.group and data.group:IsAlive() then
-- check state
local text = string.format("Truck %s | State %s",data.name,data.statusquo)
self:T(text)
if data.statusquo == AMMOTRUCK.State.IDLE then
idletrucks[#idletrucks+1] = data
found = true
elseif data.statusquo == AMMOTRUCK.State.DRIVING then
drivingtrucks[#drivingtrucks+1] = data
elseif data.statusquo == AMMOTRUCK.State.ARRIVED then
arrivedtrucks[#arrivedtrucks+1] = data
elseif data.statusquo == AMMOTRUCK.State.UNLOADING then
unloadingtrucks[#unloadingtrucks+1] = data
elseif data.statusquo == AMMOTRUCK.State.RETURNING then
returningtrucks[#returningtrucks+1] = data
if data.reloads > 0 or data.reloads == -1 then
idletrucks[#idletrucks+1] = data
found = true
end
end
else
self.truckset[data.name] = nil
end
end
-- see if we can/need route one
local n=0
if found and remunition then
-- match
--local match = false
for _,_truckdata in pairs(idletrucks) do
local truckdata = _truckdata -- #AMMOTRUCK.data
local truckcoord = truckdata.group:GetCoordinate() -- Core.Point#COORDINATE
for _,_aridata in pairs(remunitionqueue) do
local aridata = _aridata -- #AMMOTRUCK.data
local aricoord = aridata.coordinate
local distance = truckcoord:Get2DDistance(aricoord)
if distance <= self.remunidist and aridata.statusquo == AMMOTRUCK.State.OUTOFAMMO and n <= #idletrucks then
n = n + 1
aridata.statusquo = AMMOTRUCK.State.REQUESTED
self:__RouteTruck(n*5,truckdata,aridata)
break
end
end
end
end
-- check driving trucks
if #drivingtrucks > 0 then
self:CheckDrivingTrucks(drivingtrucks)
end
-- check arrived trucks
if #arrivedtrucks > 0 then
self:CheckArrivedTrucks(arrivedtrucks)
end
-- check unloading trucks
if #unloadingtrucks > 0 then
self:CheckUnloadingTrucks(unloadingtrucks)
end
-- check returningtrucks trucks
if #returningtrucks > 0 then
self:CheckReturningTrucks(returningtrucks)
end
-- check waiting targets
if #waitingtargets > 0 then
self:CheckWaitingTargets(waitingtargets)
end
self:__Monitor(self.monitor)
return self
end
---
-- @param #AMMOTRUCK self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param #AMMOTRUCK.data Truckdata
-- @param #AMMOTRUCK.data Aridata
-- @return #AMMOTRUCK self
function AMMOTRUCK:onafterRouteTruck(From, Event, To, Truckdata, Aridata)
self:T({From, Event, To, Truckdata.name, Aridata.name})
local truckdata = Truckdata -- #AMMOTRUCK.data
local aridata = Aridata -- #AMMOTRUCK.data
local tgtgrp = aridata.group
local tgtzone = ZONE_GROUP:New(aridata.name,tgtgrp,30)
local tgtcoord = tgtzone:GetRandomCoordinate(15)
if self.hasarmygroup then
local mission = AUFTRAG:NewONGUARD(tgtcoord)
local oldmission = truckdata.group:GetMissionCurrent()
if oldmission then oldmission:Cancel() end
mission:SetTime(5)
mission:SetTeleport(false)
truckdata.group:AddMission(mission)
elseif self.routeonroad then
truckdata.group:RouteGroundOnRoad(tgtcoord,30)
else
truckdata.group:RouteGroundTo(tgtcoord,30)
end
truckdata.statusquo = AMMOTRUCK.State.DRIVING
truckdata.targetgroup = tgtgrp
truckdata.targetname = aridata.name
truckdata.targetcoordinate = tgtcoord
aridata.statusquo = AMMOTRUCK.State.WAITING
aridata.timestamp = timer.getAbsTime()
return self
end
---
-- @param #AMMOTRUCK self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param #AMMOTRUCK.data Truckdata
-- @return #AMMOTRUCK self
function AMMOTRUCK:onafterTruckUnloading(From, Event, To, Truckdata)
local m = MESSAGE:New("Truck "..Truckdata.name.." unloading!",15,"AmmoTruck"):ToCoalitionIf(self.coalition,self.debug)
local truck = Truckdata -- Functional.AmmoTruck#AMMOTRUCK.data
local coord = truck.group:GetCoordinate()
local heading = truck.group:GetHeading()
heading = heading < 180 and (360-heading) or (heading - 180)
local cid = self.coalition == coalition.side.BLUE and country.id.USA or country.id.RUSSIA
cid = self.coalition == coalition.side.NEUTRAL and country.id.UN_PEACEKEEPERS or cid
local ammo = {}
for i=1,5 do
ammo[i] = SPAWNSTATIC:NewFromType("ammo_cargo","Cargos",cid)
:InitCoordinate(coord:Translate((15+((i-1)*4)),heading))
:Spawn(0,"AmmoCrate-"..math.random(1,10000))
end
local function destroyammo(ammo)
for _,_crate in pairs(ammo) do
_crate:Destroy(false)
end
end
local scheduler = SCHEDULER:New(nil,destroyammo,{ammo},self.waitingtime)
-- one reload less
if truck.reloads ~= -1 then
truck.reloads = truck.reloads - 1
end
return self
end
---
-- @param #AMMOTRUCK self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param #AMMOTRUCK.data Truck
-- @return #AMMOTRUCK self
function AMMOTRUCK:onafterTruckReturning(From, Event, To, Truck)
self:T({From, Event, To, Truck.name})
-- route home
local truckdata = Truck -- #AMMOTRUCK.data
local tgtzone = self.homezone
local tgtcoord = tgtzone:GetRandomCoordinate()
if self.hasarmygroup then
local mission = AUFTRAG:NewONGUARD(tgtcoord)
local oldmission = truckdata.group:GetMissionCurrent()
if oldmission then oldmission:Cancel() end
mission:SetTime(5)
mission:SetTeleport(false)
truckdata.group:AddMission(mission)
elseif self.routeonroad then
truckdata.group:RouteGroundOnRoad(tgtcoord,30,1,"Cone")
else
truckdata.group:RouteGroundTo(tgtcoord,30,"Cone",1)
end
return self
end
---
-- @param #AMMOTRUCK self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #AMMOTRUCK self
function AMMOTRUCK:onafterStop(From, Event, To)
self:T({From, Event, To})
return self
end

View File

@@ -2301,12 +2301,12 @@ function ARTY:OnEventShot(EventData)
self.Nukes=self.Nukes-1
end
-- Decrease available illumination shells because we just fired one.
-- Decrease available illuminatin shells because we just fired one.
if self.currentTarget.weapontype==ARTY.WeaponType.IlluminationShells then
self.Nillu=self.Nillu-1
end
-- Decrease available smoke shells because we just fired one.
-- Decrease available illuminatin shells because we just fired one.
if self.currentTarget.weapontype==ARTY.WeaponType.SmokeShells then
self.Nsmoke=self.Nsmoke-1
end
@@ -3717,6 +3717,51 @@ function ARTY:_NuclearBlast(_coord)
ignite(_fires)
end
--[[
local ZoneNuke=ZONE_RADIUS:New("Nukezone", _coord:GetVec2(), 2000)
-- Scan for Scenery objects.
ZoneNuke:Scan(Object.Category.SCENERY)
-- Array with all possible hideouts, i.e. scenery objects in the vicinity of the group.
local scenery={}
for SceneryTypeName, SceneryData in pairs(ZoneNuke:GetScannedScenery()) do
for SceneryName, SceneryObject in pairs(SceneryData) do
local SceneryObject = SceneryObject -- Wrapper.Scenery#SCENERY
-- Position of the scenery object.
local spos=SceneryObject:GetCoordinate()
-- Distance from group to impact point.
local distance= spos:Get2DDistance(_coord)
-- Place markers on every possible scenery object.
if self.Debug then
local MarkerID=spos:MarkToAll(string.format("%s scenery object %s", self.Controllable:GetName(), SceneryObject:GetTypeName()))
local text=string.format("%s scenery: %s, Coord %s", self.Controllable:GetName(), SceneryObject:GetTypeName(), SceneryObject:GetCoordinate():ToStringLLDMS())
self:T2(SUPPRESSION.id..text)
end
-- Add to table.
table.insert(scenery, {object=SceneryObject, distance=distance})
--SceneryObject:Destroy()
end
end
-- Sort scenery wrt to distance from impact point.
-- local _sort = function(a,b) return a.distance < b.distance end
-- table.sort(scenery,_sort)
-- for _,object in pairs(scenery) do
-- local sobject=object -- Wrapper.Scenery#SCENERY
-- sobject:Destroy()
-- end
]]
end
--- Route group to a certain point.

File diff suppressed because it is too large Load Diff

View File

@@ -52,13 +52,11 @@
-- @module Functional.CleanUp
-- @image CleanUp_Airbases.JPG
---
-- @type CLEANUP_AIRBASE.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-)
--- @type CLEANUP_AIRBASE.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-)
-- @field #map<#string,Wrapper.Airbase#AIRBASE> Airbases Map of Airbases.
-- @extends Core.Base#BASE
---
-- @type CLEANUP_AIRBASE
--- @type CLEANUP_AIRBASE
-- @extends #CLEANUP_AIRBASE.__
--- Keeps airbases clean, and tries to guarantee continuous airbase operations, even under combat.
@@ -95,7 +93,7 @@ CLEANUP_AIRBASE = {
-- @field #CLEANUP_AIRBASE.__
CLEANUP_AIRBASE.__ = {}
-- @field #CLEANUP_AIRBASE.__.Airbases
--- @field #CLEANUP_AIRBASE.__.Airbases
CLEANUP_AIRBASE.__.Airbases = {}
--- Creates the main object which is handling the cleaning of the debris within the given Zone Names.
@@ -242,8 +240,7 @@ function CLEANUP_AIRBASE.__:DestroyMissile( MissileObject )
end
end
---
-- @param #CLEANUP_AIRBASE self
--- @param #CLEANUP_AIRBASE self
-- @param Core.Event#EVENTDATA EventData
function CLEANUP_AIRBASE.__:OnEventBirth( EventData )
self:F( { EventData } )

View File

@@ -20,7 +20,7 @@
--
-- ====
-- @module Functional.ClientWatch
-- @image ClientWatch.JPG
-- @image clientwatch.jpg
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- CLIENTWATCH class
@@ -28,6 +28,8 @@
-- @field #string ClassName Name of the class.
-- @field #boolean Debug Write Debug messages to DCS log file and send Debug messages to all players.
-- @field #string lid String for DCS log file.
-- @field #number FilterCoalition If not nil, will only activate for aircraft of the given coalition value.
-- @field #number FilterCategory If not nil, will only activate for aircraft of the given category value.
-- @extends Core.Fsm#FSM_CONTROLLABLE
--- Manage and track client slots easily to add your own client-based menus and modules to.
@@ -66,7 +68,7 @@
--
-- -- Create an instance with a client unit prefix and send them a message when they spawn
-- local clientInstance = CLIENTWATCH:New("Rotary")
-- function clientInstance:OnAfterSpawn(From,Event,To,ClientObject)
-- function clientInstance:OnAfterSpawn(From,Event,To,ClientObject,EventData)
-- MESSAGE:New("Welcome to your aircraft!",10):ToUnit(ClientObject.Unit)
-- end
--
@@ -108,7 +110,7 @@
--
-- -- Show a message to player when they take damage from a weapon
-- local clientInstance = CLIENTWATCH:New("Rotary")
-- function clientInstance:OnAfterSpawn(From,Event,To,ClientObject)
-- function clientInstance:OnAfterSpawn(From,Event,To,ClientObject,EventData)
-- function ClientObject:OnAfterHit(From,Event,To,EventData)
-- local typeShooter = EventData.IniTypeName
-- local nameWeapon = EventData.weapon_name
@@ -120,6 +122,7 @@
CLIENTWATCH = {}
CLIENTWATCH.ClassName = "CLIENTWATCH"
CLIENTWATCH.Debug = false
CLIENTWATCH.DebugEventData = false
CLIENTWATCH.lid = nil
-- @type CLIENTWATCHTools
@@ -139,7 +142,10 @@ CLIENTWATCH.version="1.0.1"
--- Creates a new instance of CLIENTWATCH to add scripts to. Can be used multiple times with the same client/prefixes if you need it for multiple scripts.
-- @param #CLIENTWATCH self
-- @param #string, #table, or Wrapper.Client#CLIENT client Takes multiple inputs. If provided a #string, it will watch for clients whos UNIT NAME or GROUP NAME matches part of the #string as a prefix. You can also provide it with a #table containing multiple #string prefixes. Lastly, you can provide it with a Wrapper.Client#CLIENT of the specific client you want to apply this to.
-- @param #string Will watch for clients whos UNIT NAME or GROUP NAME matches part of the #string as a prefix.
-- @param #table Put strings in a table to use multiple prefixes for the above method.
-- @param Wrapper.Client#CLIENT Provide a Moose CLIENT object to apply to that specific aircraft slot (static slots only!)
-- @param #nil Leave blank to activate for ALL CLIENTS
-- @return #CLIENTWATCH self
function CLIENTWATCH:New(client)
--Init FSM
@@ -147,6 +153,9 @@ function CLIENTWATCH:New(client)
self:SetStartState( "Idle" )
self:AddTransition( "*", "Spawn", "*" )
self.FilterCoalition = nil
self.FilterCategory = nil
--- User function for OnAfter "Spawn" event.
-- @function [parent=#CLIENTWATCH] OnAfterSpawn
-- @param #CLIENTWATCH self
@@ -155,27 +164,50 @@ function CLIENTWATCH:New(client)
-- @param #string Event Event.
-- @param #string To To state.
-- @param #table clientObject Custom object that handles events and stores Moose object data. See top documentation for more details.
-- @param #table eventdata Data from EVENTS.Birth.
--Set up spawn tracking
if type(client) == "table" or type(client) == "string" then
if not client then
if self.Debug then self:I({"New client instance created. ClientType = All clients"}) end
self:HandleEvent(EVENTS.Birth)
function self:OnEventBirth(eventdata)
if (eventdata.IniCategory == 0 or eventdata.IniCategory == 1) and eventdata.IniPlayerName
and (not self.FilterCoalition or self.FilterCoalition == eventdata.IniCoalition)
and (not self.FilterCategory or self.FilterCategory == eventdata.IniCategory) then
if self.Debug then
self:I({"Client spawned in.",IniCategory = eventdata.IniCategory})
end
local clientWatchDebug = self.Debug
local clientObject = CLIENTWATCHTools:_newClient(clientWatchDebug,eventdata)
self:Spawn(clientObject,eventdata)
end
end
elseif type(client) == "table" or type(client) == "string" then
if type(client) == "table" then
--CLIENT TABLE
if client.ClassName == "CLIENT" then
if self.Debug then self:I({"New client instance created. ClientType = Wrapper.CLIENT",client}) end
self.ClientName = client:GetName()
self:HandleEvent(EVENTS.Birth)
function self:OnEventBirth(eventdata)
if self.Debug then UTILS.PrintTableToLog(eventdata) end
if eventdata.IniCategory and eventdata.IniCategory <= 1 then
if (eventdata.IniCategory == 0 or eventdata.IniCategory == 1) and eventdata.IniPlayerName
and (not self.FilterCoalition or self.FilterCoalition == eventdata.IniCoalition)
and (not self.FilterCategory or self.FilterCategory == eventdata.IniCategory) then
if self.ClientName == eventdata.IniUnitName then
local clientObject = CLIENTWATCHTools:_newClient(eventdata)
self:Spawn(clientObject)
if self.Debug then
self:I({"Client spawned in.",IniCategory = eventdata.IniCategory})
end
local clientWatchDebug = self.Debug
local clientObject = CLIENTWATCHTools:_newClient(clientWatchDebug,eventdata)
self:Spawn(clientObject,eventdata)
end
end
end
--STRING TABLE
else
if self.Debug then self:I({"New client instance created. ClientType = Multiple Prefixes",client}) end
local tableValid = true
for _,entry in pairs(client) do
if type(entry) ~= "string" then
@@ -187,12 +219,17 @@ function CLIENTWATCH:New(client)
if tableValid then
self:HandleEvent(EVENTS.Birth)
function self:OnEventBirth(eventdata)
if self.Debug then UTILS.PrintTableToLog(eventdata) end
for _,entry in pairs(client) do
if eventdata.IniCategory and eventdata.IniCategory <= 1 then
if (eventdata.IniCategory == 0 or eventdata.IniCategory == 1) and eventdata.IniPlayerName
and (not self.FilterCoalition or self.FilterCoalition == eventdata.IniCoalition)
and (not self.FilterCategory or self.FilterCategory == eventdata.IniCategory) then
if string.match(eventdata.IniUnitName,entry) or string.match(eventdata.IniGroupName,entry) then
local clientObject = CLIENTWATCHTools:_newClient(eventdata)
self:Spawn(clientObject)
if self.Debug then
self:I({"Client spawned in.",IniCategory = eventdata.IniCategory})
end
local clientWatchDebug = self.Debug
local clientObject = CLIENTWATCHTools:_newClient(clientWatchDebug,eventdata)
self:Spawn(clientObject,eventdata)
break
end
end
@@ -201,15 +238,21 @@ function CLIENTWATCH:New(client)
end
end
else
if self.Debug then self:I({"New client instance created. ClientType = Single Prefix",client}) end
--SOLO STRING
self:HandleEvent(EVENTS.Birth)
function self:OnEventBirth(eventdata)
if self.Debug then UTILS.PrintTableToLog(eventdata) end
if eventdata.IniCategory and eventdata.IniCategory <= 1 then
if (eventdata.IniCategory == 0 or eventdata.IniCategory == 1) and eventdata.IniPlayerName
and (not self.FilterCoalition or self.FilterCoalition == eventdata.IniCoalition)
and (not self.FilterCategory or self.FilterCategory == eventdata.IniCategory) then
if string.match(eventdata.IniUnitName,client) or string.match(eventdata.IniGroupName,client) then
local clientObject = CLIENTWATCHTools:_newClient(eventdata)
self:Spawn(clientObject)
if self.Debug then
self:I({"Client spawned in.",IniCategory = eventdata.IniCategory})
end
local clientWatchDebug = self.Debug
local clientObject = CLIENTWATCHTools:_newClient(clientWatchDebug,eventdata)
self:Spawn(clientObject,eventdata)
end
end
end
@@ -222,13 +265,41 @@ function CLIENTWATCH:New(client)
return self
end
--- Filter out all clients not belonging to the provided coalition
-- @param #CLIENTWATCH self
-- @param #number Coalition number (1 = red, 2 = blue)
-- @param #string Coalition string ('red' or 'blue')
function CLIENTWATCH:FilterByCoalition(value)
if value == 1 or value == "red" then
self.FilterCoalition = 1
else
self.FilterCoalition = 2
end
return self
end
--- Filter out all clients that are not of the given category
-- @param #CLIENTWATCH self
-- @param #number Category number (0 = airplane, 1 = helicopter)
-- @param #string Category string ('airplane' or 'helicopter')
function CLIENTWATCH:FilterByCategory(value)
if value == 1 or value == "helicopter" then
self.FilterCategory = 1
else
self.FilterCategory = 0
end
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Internal function for creating a new client on birth. Do not use!!!.
-- @param #CLIENTWATCHTools self
-- @param #EVENTS.Birth EventData
-- @return #CLIENTWATCHTools self
function CLIENTWATCHTools:_newClient(eventdata)
function CLIENTWATCHTools:_newClient(clientWatchDebug,eventdata)
--Init FSM
local self=BASE:Inherit(self, FSM:New())
self:SetStartState( "Alive" )
@@ -299,78 +370,130 @@ function CLIENTWATCHTools:_newClient(eventdata)
function self:OnEventHit(EventData)
if EventData.TgtUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered hit event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:Hit(EventData)
end
end
function self:OnEventKill(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered kill event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:Kill(EventData)
end
end
function self:OnEventScore(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered score event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:Score(EventData)
end
end
function self:OnEventShot(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered shot event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:Shot(EventData)
end
end
function self:OnEventShootingStart(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered shooting start event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:ShootingStart(EventData)
end
end
function self:OnEventShootingEnd(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered shooting end event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:ShootingEnd(EventData)
end
end
function self:OnEventLand(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered land event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:Land(EventData)
end
end
function self:OnEventTakeoff(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered takeoff event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:Takeoff(EventData)
end
end
function self:OnEventRunwayTakeoff(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered runway takeoff event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:RunwayTakeoff(EventData)
end
end
function self:OnEventRunwayTouch(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered runway touch event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:RunwayTouch(EventData)
end
end
function self:OnEventRefueling(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered refueling event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:Refueling(EventData)
end
end
function self:OnEventRefuelingStop(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered refueling event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:RefuelingStop(EventData)
end
end
function self:OnEventPlayerLeaveUnit(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered leave unit event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:PlayerLeaveUnit(EventData)
self._deadRoutine()
end
@@ -378,6 +501,10 @@ function CLIENTWATCHTools:_newClient(eventdata)
function self:OnEventCrash(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered crash event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:Crash(EventData)
self._deadRoutine()
end
@@ -385,6 +512,10 @@ function CLIENTWATCHTools:_newClient(eventdata)
function self:OnEventDead(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered dead event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:Dead(EventData)
self._deadRoutine()
end
@@ -392,6 +523,10 @@ function CLIENTWATCHTools:_newClient(eventdata)
function self:OnEventPilotDead(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered pilot dead event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:PilotDead(EventData)
self._deadRoutine()
end
@@ -399,6 +534,10 @@ function CLIENTWATCHTools:_newClient(eventdata)
function self:OnEventUnitLost(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered unit lost event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:UnitLost(EventData)
self._deadRoutine()
end
@@ -406,6 +545,10 @@ function CLIENTWATCHTools:_newClient(eventdata)
function self:OnEventEjection(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered ejection event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:Ejection(EventData)
self._deadRoutine()
end
@@ -413,6 +556,10 @@ function CLIENTWATCHTools:_newClient(eventdata)
function self:OnEventHumanFailure(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered human failure event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:HumanFailure(EventData)
if not self.Unit:IsAlive() then
self._deadRoutine()
@@ -422,42 +569,70 @@ function CLIENTWATCHTools:_newClient(eventdata)
function self:OnEventHumanAircraftRepairFinish(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered repair finished event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:HumanAircraftRepairFinish(EventData)
end
end
function self:OnEventHumanAircraftRepairStart(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered repair start event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:HumanAircraftRepairStart(EventData)
end
end
function self:OnEventEngineShutdown(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered engine shutdown event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:EngineShutdown(EventData)
end
end
function self:OnEventEngineStartup(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered engine startup event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:EngineStartup(EventData)
end
end
function self:OnEventWeaponAdd(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered weapon add event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:WeaponAdd(EventData)
end
end
function self:OnEventWeaponDrop(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered weapon drop event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:WeaponDrop(EventData)
end
end
function self:OnEventWeaponRearm(EventData)
if EventData.IniUnitName == self.UnitName then
if clientWatchDebug then
self:I({"Client triggered weapon rearm event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self:WeaponRearm(EventData)
end
end
@@ -466,6 +641,9 @@ function CLIENTWATCHTools:_newClient(eventdata)
--Fallback timer
self.FallbackTimer = TIMER:New(function()
if not self.Unit:IsAlive() then
if clientWatchDebug then
self:I({"Client is registered as dead without an event trigger. Running fallback dead routine.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
end
self._deadRoutine()
end
end)
@@ -473,6 +651,7 @@ function CLIENTWATCHTools:_newClient(eventdata)
--Stop event handlers and trigger Despawn
function self._deadRoutine()
if clientWatchDebug then self:I({"Client dead routine triggered. Shutting down tracking...",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName}) end
self:UnHandleEvent( EVENTS.Hit )
self:UnHandleEvent( EVENTS.Kill )
self:UnHandleEvent( EVENTS.Score )
@@ -503,6 +682,6 @@ function CLIENTWATCHTools:_newClient(eventdata)
self:Despawn()
end
self:I({"CLIENT SPAWN EVENT", PlayerName = self.PlayerName, UnitName = self.UnitName, GroupName = self.GroupName})
self:I({"Detected client spawn and applied internal functions and events.", PlayerName = self.PlayerName, UnitName = self.UnitName, GroupName = self.GroupName})
return self
end

View File

@@ -595,7 +595,8 @@ do -- DETECTION_BASE
return self
end
---
-- @param #DETECTION_BASE self
-- @param #string From The From State string.
-- @param #string Event The Event string.
@@ -615,7 +616,7 @@ do -- DETECTION_BASE
self:T( { "DetectionGroup is Alive", Detection:GetName() } )
local DetectionGroupName = Detection:GetName()
local DetectionUnit = Detection:GetUnit( 1 )
local DetectionUnit = Detection:GetFirstUnitAlive()
local DetectedUnits = {}
@@ -632,26 +633,26 @@ do -- DETECTION_BASE
--self:T(UTILS.PrintTableToLog(DetectedTargets))
for DetectionObjectID, Detection in pairs( DetectedTargets ) do
for DetectionObjectID, Detection in pairs( DetectedTargets or {}) do
local DetectedObject = Detection.object -- DCS#Object
if DetectedObject and DetectedObject:isExist() and DetectedObject.id_ < 50000000 then -- and ( DetectedObject:getCategory() == Object.Category.UNIT or DetectedObject:getCategory() == Object.Category.STATIC ) then
local DetectedObjectName = DetectedObject:getName()
if not self.DetectedObjects[DetectedObjectName] then
self.DetectedObjects[DetectedObjectName] = self.DetectedObjects[DetectedObjectName] or {}
self.DetectedObjects[DetectedObjectName].Name = DetectedObjectName
self.DetectedObjects[DetectedObjectName].Name = DetectedObjectName
self.DetectedObjects[DetectedObjectName].Object = DetectedObject
end
end
end
for DetectionObjectName, DetectedObjectData in pairs( self.DetectedObjects ) do
for DetectionObjectName, DetectedObjectData in pairs( self.DetectedObjects or {}) do
local DetectedObject = DetectedObjectData.Object
if DetectedObject:isExist() then
local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity = DetectionUnit:IsTargetDetected(
local TargetIsDetected, TargetIsVisible, TargetKnowType, TargetKnowDistance, TargetLastTime, TargetLastPos, TargetLastVelocity = DetectionUnit:IsTargetDetected(
DetectedObject,
self.DetectVisual,
self.DetectOptical,

View File

@@ -4,7 +4,7 @@
do -- DETECTION_ZONES
-- @type DETECTION_ZONES
--- @type DETECTION_ZONES
-- @field DCS#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
-- @field #DETECTION_BASE.DetectedItems DetectedItems A list of areas containing the set of @{Wrapper.Unit}s, @{Core.Zone}s, the center @{Wrapper.Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
-- @extends Functional.Detection#DETECTION_BASE
@@ -68,7 +68,7 @@ do -- DETECTION_ZONES
return self
end
-- @param #DETECTION_ZONES self
--- @param #DETECTION_ZONES self
-- @param #number The amount of alive recce.
function DETECTION_ZONES:CountAliveRecce()
@@ -76,7 +76,7 @@ do -- DETECTION_ZONES
end
-- @param #DETECTION_ZONES self
--- @param #DETECTION_ZONES self
function DETECTION_ZONES:ForEachAliveRecce( IteratorFunction, ... )
self:F2( arg )
@@ -352,7 +352,7 @@ do -- DETECTION_ZONES
--DetectedSet:Flush( self )
DetectedSet:ForEachUnit(
-- @param Wrapper.Unit#UNIT DetectedUnit
--- @param Wrapper.Unit#UNIT DetectedUnit
function( DetectedUnit )
if DetectedUnit:IsAlive() then
--self:T( "Detected Set #" .. DetectedItem.ID .. ":" .. DetectedUnit:GetName() )
@@ -380,7 +380,7 @@ do -- DETECTION_ZONES
end
-- @param #DETECTION_ZONES self
--- @param #DETECTION_ZONES self
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.

View File

@@ -141,7 +141,7 @@ FOX = {
explosiondist = 200,
explosiondist2 = 500,
bigmissilemass = 50,
--destroy = nil,
destroy = nil,
dt50 = 5,
dt10 = 1,
dt05 = 0.5,

View File

@@ -22,7 +22,7 @@
-- @module Functional.Mantis
-- @image Functional.Mantis.jpg
--
-- Last Update: July 2024
-- Last Update: Sep 2024
-------------------------------------------------------------------------
--- **MANTIS** class, extends Core.Base#BASE
@@ -439,27 +439,50 @@ MANTIS.SamDataSMA = {
-- @field #string Type #MANTIS.SamType of SAM, i.e. SHORT, MEDIUM or LONG (range)
-- @field #string Radar Radar typename on unit level (used as key)
MANTIS.SamDataCH = {
-- units from CH (Military Assets by Currenthill)
-- https://www.currenthill.com/
-- group name MUST contain CHM to ID launcher type correctly!
["2S38 CH"] = { Range=8, Blindspot=0.5, Height=6, Type="Short", Radar="2S38" },
["PantsirS1 CH"] = { Range=20, Blindspot=1.2, Height=15, Type="Short", Radar="PantsirS1" },
["PantsirS2 CH"] = { Range=30, Blindspot=1.2, Height=18, Type="Medium", Radar="PantsirS2" },
["PGL-625 CH"] = { Range=10, Blindspot=0.5, Height=5, Type="Short", Radar="PGL_625" },
["HQ-17A CH"] = { Range=20, Blindspot=1.5, Height=10, Type="Short", Radar="HQ17A" },
["M903PAC2 CH"] = { Range=160, Blindspot=3, Height=24.5, Type="Long", Radar="MIM104_M903_PAC2" },
["M903PAC3 CH"] = { Range=120, Blindspot=1, Height=40, Type="Long", Radar="MIM104_M903_PAC3" },
["TorM2 CH"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2" },
["TorM2K CH"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2K" },
["TorM2M CH"] = { Range=16, Blindspot=1, Height=10, Type="Short", Radar="TorM2M" },
["NASAMS3-AMRAAMER CH"] = { Range=50, Blindspot=2, Height=35.7, Type="Medium", Radar="CH_NASAMS3_LN_AMRAAM_ER" },
["NASAMS3-AIM9X2 CH"] = { Range=20, Blindspot=0.2, Height=18, Type="Short", Radar="CH_NASAMS3_LN_AIM9X2" },
["C-RAM CH"] = { Range=2, Blindspot=0, Height=2, Type="Short", Radar="CH_Centurion_C_RAM" },
["PGZ-09 CH"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="CH_PGZ09" },
["S350-9M100 CH"] = { Range=15, Blindspot=1.5, Height=8, Type="Short", Radar="CH_S350_50P6_9M100" },
["S350-9M96D CH"] = { Range=150, Blindspot=2.5, Height=30, Type="Long", Radar="CH_S350_50P6_9M96D" },
["LAV-AD CH"] = { Range=8, Blindspot=0.2, Height=4.8, Type="Short", Radar="CH_LAVAD" },
["HQ-22 CH"] = { Range=170, Blindspot=5, Height=27, Type="Long", Radar="CH_HQ22_LN" },
-- units from CH (Military Assets by Currenthill)
-- https://www.currenthill.com/
-- group name MUST contain CHM to ID launcher type correctly!
["2S38 CHM"] = { Range=8, Blindspot=0.5, Height=6, Type="Short", Radar="2S38" },
["PantsirS1 CHM"] = { Range=20, Blindspot=1.2, Height=15, Type="Short", Radar="PantsirS1" },
["PantsirS2 CHM"] = { Range=30, Blindspot=1.2, Height=18, Type="Medium", Radar="PantsirS2" },
["PGL-625 CHM"] = { Range=10, Blindspot=0.5, Height=5, Type="Short", Radar="PGL_625" },
["HQ-17A CHM"] = { Range=20, Blindspot=1.5, Height=10, Type="Short", Radar="HQ17A" },
["M903PAC2 CHM"] = { Range=160, Blindspot=3, Height=24.5, Type="Long", Radar="MIM104_M903_PAC2" },
["M903PAC3 CHM"] = { Range=120, Blindspot=1, Height=40, Type="Long", Radar="MIM104_M903_PAC3" },
["TorM2 CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2" },
["TorM2K CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2K" },
["TorM2M CHM"] = { Range=16, Blindspot=1, Height=10, Type="Short", Radar="TorM2M" },
["NASAMS3-AMRAAMER CHM"] = { Range=50, Blindspot=2, Height=35.7, Type="Medium", Radar="CH_NASAMS3_LN_AMRAAM_ER" },
["NASAMS3-AIM9X2 CHM"] = { Range=20, Blindspot=0.2, Height=18, Type="Short", Radar="CH_NASAMS3_LN_AIM9X2" },
["C-RAM CHM"] = { Range=2, Blindspot=0, Height=2, Type="Short", Radar="CH_Centurion_C_RAM" },
["PGZ-09 CHM"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="CH_PGZ09" },
["S350-9M100 CHM"] = { Range=15, Blindspot=1.5, Height=8, Type="Short", Radar="CH_S350_50P6_9M100" },
["S350-9M96D CHM"] = { Range=150, Blindspot=2.5, Height=30, Type="Long", Radar="CH_S350_50P6_9M96D" },
["LAV-AD CHM"] = { Range=8, Blindspot=0.2, Height=4.8, Type="Short", Radar="CH_LAVAD" },
["HQ-22 CHM"] = { Range=170, Blindspot=5, Height=27, Type="Long", Radar="CH_HQ22_LN" },
["PGZ-95 CHM"] = { Range=2, Blindspot=0, Height=2, Type="Short", Radar="CH_PGZ95" },
["LD-3000 CHM"] = { Range=3, Blindspot=0, Height=3, Type="Short", Radar="CH_LD3000_stationary" },
["LD-3000M CHM"] = { Range=3, Blindspot=0, Height=3, Type="Short", Radar="CH_LD3000" },
["FlaRakRad CHM"] = { Range=8, Blindspot=1.5, Height=6, Type="Short", Radar="HQ17A" },
["IRIS-T SLM CHM"] = { Range=40, Blindspot=0.5, Height=20, Type="Medium", Radar="CH_IRIST_SLM" },
["M903PAC2KAT1 CHM"] = { Range=160, Blindspot=3, Height=24.5, Type="Long", Radar="CH_MIM104_M903_PAC2_KAT1" },
["Skynex CHM"] = { Range=3.5, Blindspot=0, Height=3.5, Type="Short", Radar="CH_SkynexHX" },
["Skyshield CHM"] = { Range=3.5, Blindspot=0, Height=3.5, Type="Short", Radar="CH_Skyshield_Gun" },
["WieselOzelot CHM"] = { Range=8, Blindspot=0.2, Height=4.8, Type="Short", Radar="CH_Wiesel2Ozelot" },
["BukM3-9M317M CHM"] = { Range=70, Blindspot=0.25, Height=35, Type="Medium", Radar="CH_BukM3_9A317M" },
["BukM3-9M317MA CHM"] = { Range=70, Blindspot=0.25, Height=35, Type="Medium", Radar="CH_BukM3_9A317MA" },
["SkySabre CHM"] = { Range=30, Blindspot=0.5, Height=10, Type="Medium", Radar="CH_SkySabreLN" },
["Stormer CHM"] = { Range=7.5, Blindspot=0.3, Height=7, Type="Short", Radar="CH_StormerHVM" },
["THAAD CHM"] = { Range=200, Blindspot=40, Height=150, Type="Long", Radar="CH_THAAD_M1120" },
["USInfantryFIM92K CHM"] = { Range=8, Blindspot=0.2, Height=4.8, Type="Short", Radar="CH_USInfantry_FIM92" },
["RBS98M CHM"] = { Range=20, Blindspot=0, Height=8, Type="Short", Radar="RBS-98" },
["RBS70 CHM"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="RBS-70" },
["RBS90 CHM"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="RBS-90" },
["RBS103A CHM"] = { Range=150, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_Rb103A" },
["RBS103B CHM"] = { Range=35, Blindspot=0, Height=36, Type="Medium", Radar="LvS-103_Lavett103_Rb103B" },
["RBS103AM CHM"] = { Range=150, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_HX_Rb103A" },
["RBS103BM CHM"] = { Range=35, Blindspot=0, Height=36, Type="Medium", Radar="LvS-103_Lavett103_HX_Rb103B" },
["Lvkv9040M CHM"] = { Range=4, Blindspot=0, Height=2.5, Type="Short", Radar="LvKv9040" },
}
-----------------------------------------------------------------------
@@ -640,7 +663,7 @@ do
-- TODO Version
-- @field #string version
self.version="0.8.18"
self.version="0.8.20"
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
--- FSM Functions ---
@@ -1396,7 +1419,7 @@ do
-- @return #string type Long, medium or short range
-- @return #number blind "blind" spot
function MANTIS:_GetSAMDataFromUnits(grpname,mod,sma,chm)
self:T(self.lid.."_GetSAMRangeFromUnits")
self:T(self.lid.."_GetSAMDataFromUnits")
local found = false
local range = self.checkradius
local height = 3000
@@ -1449,7 +1472,7 @@ do
-- @return #string type Long, medium or short range
-- @return #number blind "blind" spot
function MANTIS:_GetSAMRange(grpname)
self:T(self.lid.."_GetSAMRange")
self:T(self.lid.."_GetSAMRange for "..tostring(grpname))
local range = self.checkradius
local height = 3000
local type = MANTIS.SamType.MEDIUM
@@ -1466,9 +1489,9 @@ do
elseif string.find(grpname,"CHM",1,true) then
CHMod = true
end
if self.automode then
--if self.automode then
for idx,entry in pairs(self.SamData) do
--self:I("ID = " .. idx)
self:T("ID = " .. idx)
if string.find(grpname,idx,1,true) then
local _entry = entry -- #MANTIS.SamData
type = _entry.Type
@@ -1476,18 +1499,21 @@ do
range = _entry.Range * 1000 * radiusscale -- max firing range
height = _entry.Height * 1000 -- max firing height
blind = _entry.Blindspot
--self:I("Matching Groupname = " .. grpname .. " Range= " .. range)
self:T("Matching Groupname = " .. grpname .. " Range= " .. range)
found = true
break
end
end
end
--end
-- secondary filter if not found
if (not found and self.automode) or HDSmod or SMAMod or CHMod then
if (not found) or HDSmod or SMAMod or CHMod then
range, height, type = self:_GetSAMDataFromUnits(grpname,HDSmod,SMAMod,CHMod)
elseif not found then
self:E(self.lid .. string.format("*****Could not match radar data for %s! Will default to midrange values!",grpname))
end
if string.find(grpname,"SHORAD",1,true) then
type = MANTIS.SamType.SHORT -- force short on match
end
return range, height, type, blind
end
@@ -1651,6 +1677,10 @@ do
function MANTIS:_CheckLoop(samset,detset,dlink,limit)
self:T(self.lid .. "CheckLoop " .. #detset .. " Coordinates")
local switchedon = 0
local statusreport = REPORT:New("\nMANTIS Status")
local instatusred = 0
local instatusgreen = 0
local SEADactive = 0
for _,_data in pairs (samset) do
local samcoordinate = _data[2]
local name = _data[1]
@@ -1673,7 +1703,7 @@ do
elseif (not self.UseEmOnOff) and switchedon < limit then
samgroup:OptionAlarmStateRed()
switchedon = switchedon + 1
switch = true
switch = true
end
if self.SamStateTracker[name] ~= "RED" and switch then
self:__RedState(1,samgroup)
@@ -1691,7 +1721,7 @@ do
-- debug output
if (self.debug or self.verbose) and switch then
local text = string.format("SAM %s in alarm state RED!", name)
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
--local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug
if self.verbose then self:I(self.lid..text) end
end
end --end alive
@@ -1709,12 +1739,26 @@ do
end
if self.debug or self.verbose then
local text = string.format("SAM %s in alarm state GREEN!", name)
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
--local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
if self.verbose then self:I(self.lid..text) end
end
end --end alive
end --end check
end --for for loop
end --end check
end --for loop
if self.debug then
for _,_status in pairs(self.SamStateTracker) do
if _status == "GREEN" then
instatusgreen=instatusgreen+1
elseif _status == "RED" then
instatusred=instatusred+1
end
end
statusreport:Add("+-----------------------------+")
statusreport:Add(string.format("+ SAM in RED State: %2d",instatusred))
statusreport:Add(string.format("+ SAM in GREEN State: %2d",instatusgreen))
statusreport:Add("+-----------------------------+")
MESSAGE:New(statusreport:Text(),10,nil,true):ToAll():ToLog()
end
return self
end
@@ -1828,7 +1872,7 @@ do
end
--]]
if self.autoshorad then
self.Shorad = SHORAD:New(self.name.."-SHORAD",self.name.."-SHORAD",self.SAM_Group,self.ShoradActDistance,self.ShoradTime,self.coalition,self.UseEmOnOff)
self.Shorad = SHORAD:New(self.name.."-SHORAD","SHORAD",self.SAM_Group,self.ShoradActDistance,self.ShoradTime,self.coalition,self.UseEmOnOff)
self.Shorad:SetDefenseLimits(80,95)
self.ShoradLink = true
self.Shorad.Groupset=self.ShoradGroupSet

File diff suppressed because it is too large Load Diff

View File

@@ -1340,7 +1340,7 @@ end
-- @return #RANGE self
function RANGE:SetSoundfilesPath( path )
self.soundpath = tostring( path or "Range Soundfiles/" )
self:I( self.lid .. string.format( "Setting sound files path to %s", self.soundpath ) )
self:T2( self.lid .. string.format( "Setting sound files path to %s", self.soundpath ) )
return self
end
@@ -1636,9 +1636,9 @@ function RANGE:AddBombingTargetUnit( unit, goodhitrange, randommove )
-- Debug or error output.
if _isstatic == true then
self:I( self.lid .. string.format( "Adding STATIC bombing target %s with good hit range %d. Random move = %s.", name, goodhitrange, tostring( randommove ) ) )
self:T( self.lid .. string.format( "Adding STATIC bombing target %s with good hit range %d. Random move = %s.", name, goodhitrange, tostring( randommove ) ) )
elseif _isstatic == false then
self:I( self.lid .. string.format( "Adding UNIT bombing target %s with good hit range %d. Random move = %s.", name, goodhitrange, tostring( randommove ) ) )
self:T( self.lid .. string.format( "Adding UNIT bombing target %s with good hit range %d. Random move = %s.", name, goodhitrange, tostring( randommove ) ) )
else
self:E( self.lid .. string.format( "ERROR! No bombing target with name %s could be found. Carefully check all UNIT and STATIC names defined in the mission editor!", name ) )
end
@@ -1706,7 +1706,7 @@ function RANGE:AddBombingTargetScenery( scenery, goodhitrange)
-- Debug or error output.
if name then
self:I( self.lid .. string.format( "Adding SCENERY bombing target %s with good hit range %d", name, goodhitrange) )
self:T( self.lid .. string.format( "Adding SCENERY bombing target %s with good hit range %d", name, goodhitrange) )
else
self:E( self.lid .. string.format( "ERROR! No bombing target with name %s could be found!", name ) )
end
@@ -1811,7 +1811,7 @@ function RANGE:OnEventBirth( EventData )
if not EventData.IniPlayerName then return end
local _unitName = EventData.IniUnitName
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName )
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName, EventData.IniPlayerName )
self:T3( self.lid .. "BIRTH: unit = " .. tostring( EventData.IniUnitName ) )
self:T3( self.lid .. "BIRTH: group = " .. tostring( EventData.IniGroupName ) )
@@ -1967,7 +1967,9 @@ end
-- @param #number attackAlt Attack altitude.
-- @param #number attackVel Attack velocity.
function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackVel)
if not playerData then return end
-- Get closet target to last position.
local _closetTarget = nil -- #RANGE.BombTarget
local _distance = nil
@@ -1984,13 +1986,13 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV
-- Coordinate of impact point.
local impactcoord = weapon:GetImpactCoordinate()
-- Check if impact happened in range zone.
-- Check if impact happened in range zone.+
local insidezone = self.rangezone:IsCoordinateInZone( impactcoord )
-- Smoke impact point of bomb.
if playerData.smokebombimpact and insidezone then
if playerData.delaysmoke then
if playerData and playerData.smokebombimpact and insidezone then
if playerData and playerData.delaysmoke then
timer.scheduleFunction( self._DelayedSmoke, { coord = impactcoord, color = playerData.smokecolor }, timer.getTime() + self.TdelaySmoke )
else
impactcoord:Smoke( playerData.smokecolor )
@@ -2115,7 +2117,7 @@ function RANGE:OnEventShot( EventData )
local _unitName = EventData.IniUnitName
-- Get player unit and name.
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName )
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName, EventData.IniPlayerName )
-- Distance Player-to-Range. Set this to larger value than the threshold.
local dPR = self.BombtrackThreshold * 2
@@ -2127,11 +2129,13 @@ function RANGE:OnEventShot( EventData )
end
-- Only track if distance player to range is < 25 km. Also check that a player shot. No need to track AI weapons.
if _track and dPR <= self.BombtrackThreshold and _unit and _playername then
if _track and dPR <= self.BombtrackThreshold and _unit and _playername and self.PlayerSettings[_playername] then
-- Player data.
local playerData = self.PlayerSettings[_playername] -- #RANGE.PlayerData
if not playerData then return end
-- Attack parameters.
local attackHdg=_unit:GetHeading()
local attackAlt=_unit:GetHeight()
@@ -2192,7 +2196,7 @@ function RANGE:onafterStatus( From, Event, To )
end
-- Check range status.
self:I( self.lid .. text )
self:T( self.lid .. text )
end
@@ -2393,7 +2397,7 @@ function RANGE:onafterSave( From, Event, To )
if f then
f:write( data )
f:close()
self:I( self.lid .. string.format( "Saving player results to file %s", tostring( filename ) ) )
self:T( self.lid .. string.format( "Saving player results to file %s", tostring( filename ) ) )
else
self:E( self.lid .. string.format( "ERROR: Could not save results to file %s", tostring( filename ) ) )
end
@@ -2472,7 +2476,7 @@ function RANGE:onafterLoad( From, Event, To )
-- Info message.
local text = string.format( "Loading player bomb results from file %s", filename )
self:I( self.lid .. text )
self:T( self.lid .. text )
-- Load asset data from file.
local data = _loadfile( filename )
@@ -2845,7 +2849,7 @@ function RANGE:_DisplayRangeInfo( _unitname )
-- Check if we have a player.
if unit and playername then
self:I(playername)
--self:I(playername)
-- Message text.
local text = ""
@@ -2983,7 +2987,7 @@ function RANGE:_DisplayBombTargets( _unitname )
end
end
self:_DisplayMessageToGroup( _unit, _text, 120, true, true, _multiplayer )
self:_DisplayMessageToGroup( _unit, _text, 150, true, true, _multiplayer )
end
end
@@ -3449,10 +3453,10 @@ function RANGE:_AddF10Commands( _unitName )
-- Range menu
local _rangePath = MENU_GROUP:New( group, self.rangename, _rootMenu )
local _statsPath = MENU_GROUP:New( group, "Statistics", _rangePath )
local _markPath = MENU_GROUP:New( group, "Mark Targets", _rangePath )
local _settingsPath = MENU_GROUP:New( group, "My Settings", _rangePath )
local _infoPath = MENU_GROUP:New( group, "Range Info", _rangePath )
local _markPath = MENU_GROUP:New( group, "Mark Targets", _rangePath )
local _statsPath = MENU_GROUP:New( group, "Statistics", _rangePath )
local _settingsPath = MENU_GROUP:New( group, "My Settings", _rangePath )
-- F10/On the Range/<Range Name>/My Settings/
local _mysmokePath = MENU_GROUP:New( group, "Smoke Color", _settingsPath )
@@ -4099,8 +4103,8 @@ end
-- @return Wrapper.Unit#UNIT Unit of player.
-- @return #string Name of the player.
-- @return #boolean If true, group has > 1 player in it
function RANGE:_GetPlayerUnitAndName( _unitName )
self:F2( _unitName )
function RANGE:_GetPlayerUnitAndName( _unitName, PlayerName )
--self:I( _unitName )
if _unitName ~= nil then
@@ -4109,9 +4113,9 @@ function RANGE:_GetPlayerUnitAndName( _unitName )
-- Get DCS unit from its name.
local DCSunit = Unit.getByName( _unitName )
if DCSunit then
if DCSunit and DCSunit.getPlayerName then
local playername = DCSunit:getPlayerName()
local playername = DCSunit:getPlayerName() or PlayerName or "None"
local unit = UNIT:Find( DCSunit )
self:T2( { DCSunit = DCSunit, unit = unit, playername = playername } )

View File

@@ -19,7 +19,7 @@
--
-- ### Authors: **applevangelist**, **FlightControl**
--
-- Last Update: Dec 2023
-- Last Update: Oct 2024
--
-- ===
--
@@ -28,6 +28,16 @@
---
-- @type SEAD
-- @field #string ClassName The Class Name.
-- @field #table TargetSkill Table of target skills.
-- @field #table SEADGroupPrefixes Table of SEAD prefixes.
-- @field #table SuppressedGroups Table of currently suppressed groups.
-- @field #number EngagementRange Engagement Range.
-- @field #number Padding Padding in seconds.
-- @field #function CallBack Callback function for suppression plans.
-- @field #boolean UseCallBack Switch for callback function to be used.
-- @field #boolean debug Debug switch.
-- @field #boolen WeaponTrack Track switch, if true track weapon speed for 30 secs.
-- @extends Core.Base#BASE
--- Make SAM sites execute evasive and defensive behaviour when being fired upon.
@@ -56,10 +66,11 @@ SEAD = {
SEADGroupPrefixes = {},
SuppressedGroups = {},
EngagementRange = 75, -- default 75% engagement range Feature Request #1355
Padding = 10,
Padding = 15,
CallBack = nil,
UseCallBack = false,
debug = false,
WeaponTrack = false,
}
--- Missile enumerators
@@ -144,7 +155,7 @@ function SEAD:New( SEADGroupPrefixes, Padding )
self:AddTransition("*", "ManageEvasion", "*")
self:AddTransition("*", "CalculateHitZone", "*")
self:I("*** SEAD - Started Version 0.4.6")
self:I("*** SEAD - Started Version 0.4.8")
return self
end
@@ -371,7 +382,7 @@ function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADP
reach = wpndata[1] * 1.1
local mach = wpndata[2]
wpnspeed = math.floor(mach * 340.29)
if Weapon then
if Weapon and Weapon:GetSpeed() > 0 then
wpnspeed = Weapon:GetSpeed()
self:T(string.format("*** SEAD - Weapon Speed from WEAPON: %f m/s",wpnspeed))
end
@@ -452,22 +463,30 @@ end
-- @return #SEAD self
function SEAD:HandleEventShot( EventData )
self:T( { EventData.id } )
local SEADPlane = EventData.IniUnit -- Wrapper.Unit#UNIT
local SEADGroup = EventData.IniGroup -- Wrapper.Group#GROUP
local SEADPlanePos = SEADPlane:GetCoordinate() -- Core.Point#COORDINATE
local SEADUnit = EventData.IniDCSUnit
local SEADUnitName = EventData.IniDCSUnitName
local SEADWeapon = EventData.Weapon -- Identify the weapon fired
local SEADWeaponName = EventData.WeaponName -- return weapon type
local WeaponWrapper = WEAPON:New(EventData.Weapon)
--local SEADWeaponSpeed = WeaponWrapper:GetSpeed() -- mps
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
--self:T({ SEADWeapon })
local SEADWeapon = EventData.Weapon -- Identify the weapon fired
local SEADWeaponName = EventData.WeaponName or "None" -- return weapon type
if self:_CheckHarms(SEADWeaponName) then
local SEADPlane = EventData.IniUnit -- Wrapper.Unit#UNIT
if not SEADPlane then return self end -- case IniUnit is empty
local SEADGroup = EventData.IniGroup -- Wrapper.Group#GROUP
local SEADPlanePos = SEADPlane:GetCoordinate() -- Core.Point#COORDINATE
local SEADUnit = EventData.IniDCSUnit
local SEADUnitName = EventData.IniDCSUnitName
local WeaponWrapper = WEAPON:New(EventData.Weapon) -- Wrapper.Weapon#WEAPON
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
self:T( '*** SEAD - Weapon Match' )
if self.WeaponTrack == true then
WeaponWrapper:SetFuncTrack(function(weapon) env.info(string.format("*** Weapon Speed: %d m/s",weapon:GetSpeed() or -1)) end)
WeaponWrapper:StartTrack(0.1)
WeaponWrapper:StopTrack(30)
end
local _targetskill = "Random"
local _targetgroupname = "none"
local _target = EventData.Weapon:getTarget() -- Identify target
@@ -520,7 +539,7 @@ function SEAD:HandleEventShot( EventData )
end
if SEADGroupFound == true then -- yes we are being attacked
if string.find(SEADWeaponName,"ADM_141",1,true) then
self:__ManageEvasion(2,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,0,WeaponWrapper)
self:__ManageEvasion(2,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,2,WeaponWrapper)
else
self:ManageEvasion(_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,0,WeaponWrapper)
end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,591 +0,0 @@
--- **Functional** - TIRESIAS - manages AI behaviour.
--
-- ===
--
-- The @{#TIRESIAS} class is working in the back to keep your large-scale ground units in check.
--
-- ## Features:
--
-- * Designed to keep CPU and Network usage lower on missions with a lot of ground units.
-- * Does not affect ships to keep the Navy guys happy.
-- * Does not affect OpsGroup type groups.
-- * Distinguishes between SAM groups, AAA groups and other ground groups.
-- * Exceptions can be defined to keep certain actions going.
-- * Works coalition-independent in the back
-- * Easy setup.
--
-- ===
--
-- ## Missions:
--
-- ### [TIRESIAS](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master)
--
-- ===
--
-- ### Author : **applevangelist **
--
-- @module Functional.Tiresias
-- @image Functional.Tiresias.jpg
--
-- Last Update: Dec 2023
-------------------------------------------------------------------------
--- **TIRESIAS** class, extends Core.Base#BASE
-- @type TIRESIAS
-- @field #string ClassName
-- @field #booelan debug
-- @field #string version
-- @field #number Interval
-- @field Core.Set#SET_GROUP GroundSet
-- @field #number Coalition
-- @field Core.Set#SET_GROUP VehicleSet
-- @field Core.Set#SET_GROUP AAASet
-- @field Core.Set#SET_GROUP SAMSet
-- @field Core.Set#SET_GROUP ExceptionSet
-- @field Core.Set#SET_OPSGROUP OpsGroupSet
-- @field #number AAARange
-- @field #number HeloSwitchRange
-- @field #number PlaneSwitchRange
-- @field Core.Set#SET_GROUP FlightSet
-- @field #boolean SwitchAAA
-- @extends Core.Fsm#FSM
---
-- @type TIRESIAS.Data
-- @field #string type
-- @field #number range
-- @field #boolean invisible
-- @field #boolean AIOff
-- @field #boolean exception
--- *Tiresias, Greek demi-god and shapeshifter, blinded by the Gods, works as oracle for you.* (Wiki)
--
-- ===
--
-- ## TIRESIAS Concept
--
-- * Designed to keep CPU and Network usage lower on missions with a lot of ground units.
-- * Does not affect ships to keep the Navy guys happy.
-- * Does not affect OpsGroup type groups.
-- * Distinguishes between SAM groups, AAA groups and other ground groups.
-- * Exceptions can be defined in SET_GROUP objects to keep certain actions going.
-- * Works coalition-independent in the back
-- * Easy setup.
--
-- ## Setup
--
-- Setup is a one-liner:
--
-- local blinder = TIRESIAS:New()
--
-- Optionally you can set up exceptions, e.g. for convoys driving around
--
-- local exceptionset = SET_GROUP:New():FilterCoalitions("red"):FilterPrefixes("Convoy"):FilterStart()
-- local blinder = TIRESIAS:New()
-- blinder:AddExceptionSet(exceptionset)
--
-- Options
--
-- -- Setup different radius for activation around helo and airplane groups (applies to AI and humans)
-- blinder:SetActivationRanges(10,25) -- defaults are 10, and 25
--
-- -- Setup engagement ranges for AAA (non-advanced SAM units like Flaks etc) and if you want them to be AIOff
-- blinder:SetAAARanges(60,true) -- defaults are 60, and true
--
-- @field #TIRESIAS
TIRESIAS = {
ClassName = "TIRESIAS",
debug = false,
version = "0.0.5",
Interval = 20,
GroundSet = nil,
VehicleSet = nil,
AAASet = nil,
SAMSet = nil,
ExceptionSet = nil,
AAARange = 60, -- 60%
HeloSwitchRange = 10, -- NM
PlaneSwitchRange = 25, -- NM
SwitchAAA = true,
}
--- [USER] Create a new Tiresias object and start it up.
-- @param #TIRESIAS self
-- @return #TIRESIAS self
function TIRESIAS:New()
-- Inherit everything from FSM class.
local self = BASE:Inherit(self, FSM:New()) -- #TIRESIAS
--- FSM Functions ---
-- Start State.
self:SetStartState("Stopped")
-- Add FSM transitions.
-- From State --> Event --> To State
self:AddTransition("Stopped", "Start", "Running") -- Start FSM.
self:AddTransition("*", "Status", "*") -- TIRESIAS status update.
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
self.ExceptionSet = SET_GROUP:New():Clear(false)
self:HandleEvent(EVENTS.PlayerEnterAircraft,self._EventHandler)
self.lid = string.format("TIRESIAS %s | ",self.version)
self:I(self.lid.."Managing ground groups!")
--- Triggers the FSM event "Stop". Stops TIRESIAS and all its event handlers.
-- @function [parent=#TIRESIAS] Stop
-- @param #TIRESIAS self
--- Triggers the FSM event "Stop" after a delay. Stops TIRESIAS and all its event handlers.
-- @function [parent=#TIRESIAS] __Stop
-- @param #TIRESIAS self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "Start". Starts TIRESIAS and all its event handlers. Note - `:New()` already starts the instance.
-- @function [parent=#TIRESIAS] Start
-- @param #TIRESIAS self
--- Triggers the FSM event "Start" after a delay. Starts TIRESIAS and all its event handlers. Note - `:New()` already starts the instance.
-- @function [parent=#TIRESIAS] __Start
-- @param #TIRESIAS self
-- @param #number delay Delay in seconds.
self:__Start(1)
return self
end
-------------------------------------------------------------------------------------------------------------
--
-- Helper Functions
--
-------------------------------------------------------------------------------------------------------------
---[USER] Set activation radius for Helos and Planes in Nautical Miles.
-- @param #TIRESIAS self
-- @param #number HeloMiles Radius around a Helicopter in which AI ground units will be activated. Defaults to 10NM.
-- @param #number PlaneMiles Radius around an Airplane in which AI ground units will be activated. Defaults to 25NM.
-- @return #TIRESIAS self
function TIRESIAS:SetActivationRanges(HeloMiles,PlaneMiles)
self.HeloSwitchRange = HeloMiles or 10
self.PlaneSwitchRange = PlaneMiles or 25
return self
end
---[USER] Set AAA Ranges - AAA equals non-SAM systems which qualify as AAA in DCS world.
-- @param #TIRESIAS self
-- @param #number FiringRange The engagement range that AAA units will be set to. Can be 0 to 100 (percent). Defaults to 60.
-- @param #boolean SwitchAAA Decide if these system will have their AI switched off, too. Defaults to true.
-- @return #TIRESIAS self
function TIRESIAS:SetAAARanges(FiringRange,SwitchAAA)
self.AAARange = FiringRange or 60
self.SwitchAAA = (SwitchAAA == false) and false or true
return self
end
--- [USER] Add a SET_GROUP of GROUP objects as exceptions. Can be done multiple times. Does **not** work work for GROUP objects spawned into the SET after start, i.e. the groups need to exist in the game already.
-- @param #TIRESIAS self
-- @param Core.Set#SET_GROUP Set to add to the exception list.
-- @return #TIRESIAS self
function TIRESIAS:AddExceptionSet(Set)
self:T(self.lid.."AddExceptionSet")
local exceptions = self.ExceptionSet
Set:ForEachGroupAlive(
function(grp)
if not grp.Tiresias then
grp.Tiresias = { -- #TIRESIAS.Data
type = "Exception",
exception = true,
}
exceptions:AddGroup(grp,true)
end
BASE:T("TIRESIAS: Added exception group: "..grp:GetName())
end
)
return self
end
--- [INTERNAL] Filter Function
-- @param Wrapper.Group#GROUP Group
-- @return #boolean isin
function TIRESIAS._FilterNotAAA(Group)
local grp = Group -- Wrapper.Group#GROUP
local isaaa = grp:IsAAA()
if isaaa == true and grp:IsGround() and not grp:IsShip() then
return false -- remove from SET
else
return true -- keep in SET
end
end
--- [INTERNAL] Filter Function
-- @param Wrapper.Group#GROUP Group
-- @return #boolean isin
function TIRESIAS._FilterNotSAM(Group)
local grp = Group -- Wrapper.Group#GROUP
local issam = grp:IsSAM()
if issam == true and grp:IsGround() and not grp:IsShip() then
return false -- remove from SET
else
return true -- keep in SET
end
end
--- [INTERNAL] Filter Function
-- @param Wrapper.Group#GROUP Group
-- @return #boolean isin
function TIRESIAS._FilterAAA(Group)
local grp = Group -- Wrapper.Group#GROUP
local isaaa = grp:IsAAA()
if isaaa == true and grp:IsGround() and not grp:IsShip() then
return true -- remove from SET
else
return false -- keep in SET
end
end
--- [INTERNAL] Filter Function
-- @param Wrapper.Group#GROUP Group
-- @return #boolean isin
function TIRESIAS._FilterSAM(Group)
local grp = Group -- Wrapper.Group#GROUP
local issam = grp:IsSAM()
if issam == true and grp:IsGround() and not grp:IsShip() then
return true -- remove from SET
else
return false -- keep in SET
end
end
--- [INTERNAL] Init Groups
-- @param #TIRESIAS self
-- @return #TIRESIAS self
function TIRESIAS:_InitGroups()
self:T(self.lid.."_InitGroups")
-- Set all groups invisible/motionless
local EngageRange = self.AAARange
local SwitchAAA = self.SwitchAAA
--- AAA
self.AAASet:ForEachGroupAlive(
function(grp)
if not grp.Tiresias then
grp:OptionEngageRange(EngageRange)
grp:SetCommandInvisible(true)
if SwitchAAA then
grp:SetAIOff()
grp:EnableEmission(false)
end
grp.Tiresias = { -- #TIRESIAS.Data
type = "AAA",
invisible = true,
range = EngageRange,
exception = false,
AIOff = SwitchAAA,
}
end
if grp.Tiresias and (not grp.Tiresias.exception == true) then
if grp.Tiresias.invisible and grp.Tiresias.invisible == false then
grp:SetCommandInvisible(true)
grp.Tiresias.invisible = true
if SwitchAAA then
grp:SetAIOff()
grp:EnableEmission(false)
grp.Tiresias.AIOff = true
end
end
end
--BASE:I(string.format("Init/Switch off AAA %s (Exception %s)",grp:GetName(),tostring(grp.Tiresias.exception)))
end
)
--- Vehicles
self.VehicleSet:ForEachGroupAlive(
function(grp)
if not grp.Tiresias then
grp:SetAIOff()
grp:SetCommandInvisible(true)
grp.Tiresias = { -- #TIRESIAS.Data
type = "Vehicle",
invisible = true,
AIOff = true,
exception = false,
}
end
if grp.Tiresias and (not grp.Tiresias.exception == true) then
if grp.Tiresias and grp.Tiresias.invisible and grp.Tiresias.invisible == false then
grp:SetCommandInvisible(true)
grp:SetAIOff()
grp.Tiresias.invisible = true
end
end
--BASE:I(string.format("Init/Switch off Vehicle %s (Exception %s)",grp:GetName(),tostring(grp.Tiresias.exception)))
end
)
--- SAM
self.SAMSet:ForEachGroupAlive(
function(grp)
if not grp.Tiresias then
grp:SetCommandInvisible(true)
grp.Tiresias = { -- #TIRESIAS.Data
type = "SAM",
invisible = true,
exception = false,
}
end
if grp.Tiresias and (not grp.Tiresias.exception == true) then
if grp.Tiresias and grp.Tiresias.invisible and grp.Tiresias.invisible == false then
grp:SetCommandInvisible(true)
grp.Tiresias.invisible = true
end
end
--BASE:I(string.format("Init/Switch off SAM %s (Exception %s)",grp:GetName(),tostring(grp.Tiresias.exception)))
end
)
return self
end
--- [INTERNAL] Event handler function
-- @param #TIRESIAS self
-- @param Core.Event#EVENTDATA EventData
-- @return #TIRESIAS self
function TIRESIAS:_EventHandler(EventData)
self:T(string.format("%s Event = %d",self.lid, EventData.id))
local event = EventData -- Core.Event#EVENTDATA
if event.id == EVENTS.PlayerEnterAircraft or event.id == EVENTS.PlayerEnterUnit then
--local _coalition = event.IniCoalition
--if _coalition ~= self.Coalition then
-- return --ignore!
--end
local unitname = event.IniUnitName or "none"
local _unit = event.IniUnit
local _group = event.IniGroup
if _group and _group:IsAlive() then
local radius = self.PlaneSwitchRange
if _group:IsHelicopter() then
radius = self.HeloSwitchRange
end
self:_SwitchOnGroups(_group,radius)
end
end
return self
end
--- [INTERNAL] Switch Groups Behaviour
-- @param #TIRESIAS self
-- @param Wrapper.Group#GROUP group
-- @param #number radius Radius in NM
-- @return #TIRESIAS self
function TIRESIAS:_SwitchOnGroups(group,radius)
self:T(self.lid.."_SwitchOnGroups "..group:GetName().." Radius "..radius.." NM")
local zone = ZONE_GROUP:New("Zone-"..group:GetName(),group,UTILS.NMToMeters(radius))
local ground = SET_GROUP:New():FilterCategoryGround():FilterZones({zone}):FilterOnce()
local count = ground:CountAlive()
if self.debug then
local text = string.format("There are %d groups around this plane or helo!",count)
self:I(text)
end
local SwitchAAA = self.SwitchAAA
if ground:CountAlive() > 0 then
ground:ForEachGroupAlive(
function(grp)
local name = grp:GetName()
if grp.Tiresias and grp.Tiresias.type and (not grp.Tiresias.exception == true ) then
if grp.Tiresias.invisible == true then
grp:SetCommandInvisible(false)
grp.Tiresias.invisible = false
end
if grp.Tiresias.type == "Vehicle" and grp.Tiresias.AIOff and grp.Tiresias.AIOff == true then
grp:SetAIOn()
grp.Tiresias.AIOff = false
end
if SwitchAAA and grp.Tiresias.type == "AAA" and grp.Tiresias.AIOff and grp.Tiresias.AIOff == true then
grp:SetAIOn()
grp:EnableEmission(true)
grp.Tiresias.AIOff = false
end
--BASE:I(string.format("TIRESIAS - Switch on %s %s (Exception %s)",tostring(grp.Tiresias.type),grp:GetName(),tostring(grp.Tiresias.exception)))
else
BASE:T("TIRESIAS - This group "..tostring(name).. " has not been initialized or is an exception!")
end
end
)
end
return self
end
-------------------------------------------------------------------------------------------------------------
--
-- FSM Functions
--
-------------------------------------------------------------------------------------------------------------
--- [INTERNAL] FSM Function
-- @param #TIRESIAS self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #TIRESIAS self
function TIRESIAS:onafterStart(From, Event, To)
self:T({From, Event, To})
local VehicleSet = SET_GROUP:New():FilterCategoryGround():FilterFunction(TIRESIAS._FilterNotAAA):FilterFunction(TIRESIAS._FilterNotSAM):FilterStart()
local AAASet = SET_GROUP:New():FilterCategoryGround():FilterFunction(TIRESIAS._FilterAAA):FilterStart()
local SAMSet = SET_GROUP:New():FilterCategoryGround():FilterFunction(TIRESIAS._FilterSAM):FilterStart()
local OpsGroupSet = SET_OPSGROUP:New():FilterActive(true):FilterStart()
self.FlightSet = SET_GROUP:New():FilterCategories({"plane","helicopter"}):FilterStart()
local EngageRange = self.AAARange
local ExceptionSet = self.ExceptionSet
if self.ExceptionSet then
function ExceptionSet:OnAfterAdded(From,Event,To,ObjectName,Object)
BASE:I("TIRESIAS: EXCEPTION Object Added: "..Object:GetName())
if Object and Object:IsAlive() then
Object.Tiresias = { -- #TIRESIAS.Data
type = "Exception",
exception = true,
}
Object:SetAIOn()
Object:SetCommandInvisible(false)
Object:EnableEmission(true)
end
end
local OGS = OpsGroupSet:GetAliveSet()
for _,_OG in pairs(OGS or {}) do
local OG = _OG -- Ops.OpsGroup#OPSGROUP
local grp = OG:GetGroup()
ExceptionSet:AddGroup(grp,true)
end
function OpsGroupSet:OnAfterAdded(From,Event,To,ObjectName,Object)
local grp = Object:GetGroup()
ExceptionSet:AddGroup(grp,true)
end
end
function VehicleSet:OnAfterAdded(From,Event,To,ObjectName,Object)
BASE:I("TIRESIAS: VEHCILE Object Added: "..Object:GetName())
if Object and Object:IsAlive() then
Object:SetAIOff()
Object:SetCommandInvisible(true)
Object.Tiresias = { -- #TIRESIAS.Data
type = "Vehicle",
invisible = true,
AIOff = true,
exception = false,
}
end
end
local SwitchAAA = self.SwitchAAA
function AAASet:OnAfterAdded(From,Event,To,ObjectName,Object)
if Object and Object:IsAlive() then
BASE:I("TIRESIAS: AAA Object Added: "..Object:GetName())
Object:OptionEngageRange(EngageRange)
Object:SetCommandInvisible(true)
if SwitchAAA then
Object:SetAIOff()
Object:EnableEmission(false)
end
Object.Tiresias = { -- #TIRESIAS.Data
type = "AAA",
invisible = true,
range = EngageRange,
exception = false,
AIOff = SwitchAAA,
}
end
end
function SAMSet:OnAfterAdded(From,Event,To,ObjectName,Object)
if Object and Object:IsAlive() then
BASE:I("TIRESIAS: SAM Object Added: "..Object:GetName())
Object:SetCommandInvisible(true)
Object.Tiresias = { -- #TIRESIAS.Data
type = "SAM",
invisible = true,
exception = false,
}
end
end
self.VehicleSet = VehicleSet
self.AAASet = AAASet
self.SAMSet = SAMSet
self.OpsGroupSet = OpsGroupSet
self:_InitGroups()
self:__Status(1)
return self
end
--- [INTERNAL] FSM Function
-- @param #TIRESIAS self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #TIRESIAS self
function TIRESIAS:onbeforeStatus(From, Event, To)
self:T({From, Event, To})
if self:GetState() == "Stopped" then
return false
end
return self
end
--- [INTERNAL] FSM Function
-- @param #TIRESIAS self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #TIRESIAS self
function TIRESIAS:onafterStatus(From, Event, To)
self:T({From, Event, To})
if self.debug then
local count = self.VehicleSet:CountAlive()
local AAAcount = self.AAASet:CountAlive()
local SAMcount = self.SAMSet:CountAlive()
local text = string.format("Overall: %d | Vehicles: %d | AAA: %d | SAM: %d",count+AAAcount+SAMcount,count,AAAcount,SAMcount)
self:I(text)
end
self:_InitGroups()
if self.FlightSet:CountAlive() > 0 then
local Set = self.FlightSet:GetAliveSet()
for _,_plane in pairs(Set) do
local plane = _plane -- Wrapper.Group#GROUP
local radius = self.PlaneSwitchRange
if plane:IsHelicopter() then
radius = self.HeloSwitchRange
end
self:_SwitchOnGroups(_plane,radius)
end
end
if self:GetState() ~= "Stopped" then
self:__Status(self.Interval)
end
return self
end
--- [INTERNAL] FSM Function
-- @param #TIRESIAS self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #TIRESIAS self
function TIRESIAS:onafterStop(From, Event, To)
self:T({From, Event, To})
self:UnHandleEvent(EVENTS.PlayerEnterAircraft)
return self
end
-------------------------------------------------------------------------------------------------------------
--
-- End
--
-------------------------------------------------------------------------------------------------------------

View File

@@ -6732,7 +6732,7 @@ end
-- @param Wrapper.Group#GROUP deadgroup Group of unit that died.
-- @param #WAREHOUSE.Pendingitem request Request that needs to be updated.
function WAREHOUSE:_UnitDead(deadunit, deadgroup, request)
self:F(self.lid.."FF unit dead "..deadunit:GetName())
--self:F(self.lid.."FF unit dead "..deadunit:GetName())
-- Find opsgroup.
local opsgroup=_DATABASE:FindOpsGroup(deadgroup)
@@ -8433,12 +8433,14 @@ function WAREHOUSE:_GetAttribute(group)
local attribute=WAREHOUSE.Attribute.OTHER_UNKNOWN --#WAREHOUSE.Attribute
if group then
local groupCat=group:GetCategory()
-----------
--- Air ---
-----------
-- Planes
local transportplane=group:HasAttribute("Transports") and group:HasAttribute("Planes")
local transportplane=group:HasAttribute("Transports") and group:HasAttribute("Planes") and groupCat==Group.Category.AIRPLANE
local awacs=group:HasAttribute("AWACS")
local fighter=group:HasAttribute("Fighters") or group:HasAttribute("Interceptors") or group:HasAttribute("Multirole fighters") or (group:HasAttribute("Bombers") and not group:HasAttribute("Strategic bombers"))
local bomber=group:HasAttribute("Strategic bombers")
@@ -8593,7 +8595,6 @@ end
-- @param #WAREHOUSE.Queueitem qitem Item of queue to be removed.
-- @param #table queue The queue from which the item should be deleted.
function WAREHOUSE:_DeleteQueueItem(qitem, queue)
self:F({qitem=qitem, queue=queue})
for i=1,#queue do
local _item=queue[i] --#WAREHOUSE.Queueitem

View File

@@ -48,7 +48,7 @@
do -- ZONE_CAPTURE_COALITION
-- @type ZONE_CAPTURE_COALITION
--- @type ZONE_CAPTURE_COALITION
-- @field #string ClassName Name of the class.
-- @field #number MarkBlue ID of blue F10 mark.
-- @field #number MarkRed ID of red F10 mark.
@@ -161,7 +161,7 @@ do -- ZONE_CAPTURE_COALITION
-- The mission designer can use these values to alter the logic.
-- For example:
--
-- -- @param Functional.ZoneCaptureCoalition#ZONE_CAPTURE_COALITION self
-- --- @param Functional.ZoneCaptureCoalition#ZONE_CAPTURE_COALITION self
-- function ZoneCaptureCoalition:OnEnterGuarded( From, Event, To )
-- if From ~= "Empty" then
-- -- Display a message
@@ -172,7 +172,7 @@ do -- ZONE_CAPTURE_COALITION
--
-- ## Example Event Handler.
--
-- -- @param Functional.ZoneCaptureCoalition#ZONE_CAPTURE_COALITION self
-- --- @param Functional.ZoneCaptureCoalition#ZONE_CAPTURE_COALITION self
-- function ZoneCaptureCoalition:OnEnterGuarded( From, Event, To )
-- if From ~= To then
-- local Coalition = self:GetCoalition()
@@ -273,7 +273,7 @@ do -- ZONE_CAPTURE_COALITION
-- Depending on the zone ownership, different messages are sent.
-- Note the methods `ZoneCaptureCoalition:GetZoneName()`.
--
-- -- @param Functional.ZoneCaptureCoalition#ZONE_CAPTURE_COALITION self
-- --- @param Functional.ZoneCaptureCoalition#ZONE_CAPTURE_COALITION self
-- function ZoneCaptureCoalition:OnEnterGuarded( From, Event, To )
-- if From ~= To then
-- local Coalition = self:GetCoalition()
@@ -294,7 +294,7 @@ do -- ZONE_CAPTURE_COALITION
-- Next is the Event Handler when the **Empty** state transition is triggered.
-- Now we smoke the ZoneCaptureCoalition with a green color, using `self:Smoke( SMOKECOLOR.Green )`.
--
-- -- @param Functional.Protect#ZONE_CAPTURE_COALITION self
-- --- @param Functional.Protect#ZONE_CAPTURE_COALITION self
-- function ZoneCaptureCoalition:OnEnterEmpty()
-- self:Smoke( SMOKECOLOR.Green )
-- US_CC:MessageTypeToCoalition( string.format( "%s is unprotected, and can be captured!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
@@ -304,7 +304,7 @@ do -- ZONE_CAPTURE_COALITION
-- The next Event Handlers speak for itself.
-- When the zone is Attacked, we smoke the zone white and send some messages to each coalition.
--
-- -- @param Functional.Protect#ZONE_CAPTURE_COALITION self
-- --- @param Functional.Protect#ZONE_CAPTURE_COALITION self
-- function ZoneCaptureCoalition:OnEnterAttacked()
-- ZoneCaptureCoalition:Smoke( SMOKECOLOR.White )
-- local Coalition = self:GetCoalition()
@@ -321,7 +321,7 @@ do -- ZONE_CAPTURE_COALITION
-- When the zone is Captured, we send some victory or loss messages to the correct coalition.
-- And we add some score.
--
-- -- @param Functional.Protect#ZONE_CAPTURE_COALITION self
-- --- @param Functional.Protect#ZONE_CAPTURE_COALITION self
-- function ZoneCaptureCoalition:OnEnterCaptured()
-- local Coalition = self:GetCoalition()
-- self:E({Coalition = Coalition})
@@ -641,7 +641,7 @@ do -- ZONE_CAPTURE_COALITION
--
-- @usage
-- -- For example, one could stop the monitoring when the zone was captured!
-- -- @param Functional.Protect#ZONE_CAPTURE_COALITION self
-- --- @param Functional.Protect#ZONE_CAPTURE_COALITION self
-- function ZoneCaptureCoalition:OnEnterCaptured()
-- local Coalition = self:GetCoalition()
-- self:E({Coalition = Coalition})

View File

@@ -17,7 +17,7 @@
do -- Zone
-- @type ZONE_GOAL
--- @type ZONE_GOAL
-- @field #string ClassName Name of the class.
-- @field Core.Goal#GOAL Goal The goal object.
-- @field #number SmokeTime Time stamp in seconds when the last smoke of the zone was triggered.
@@ -178,7 +178,7 @@ do -- Zone
end
-- @param #ZONE_GOAL self
--- @param #ZONE_GOAL self
-- @param Core.Event#EVENTDATA EventData Event data table.
function ZONE_GOAL:__Destroyed( EventData )
self:F( { "EventDead", EventData } )

View File

@@ -21,7 +21,7 @@
do -- ZoneGoal
-- @type ZONE_GOAL_CARGO
--- @type ZONE_GOAL_CARGO
-- @extends Functional.ZoneGoal#ZONE_GOAL
@@ -55,7 +55,7 @@ do -- ZoneGoal
ClassName = "ZONE_GOAL_CARGO",
}
-- @field #table ZONE_GOAL_CARGO.States
--- @field #table ZONE_GOAL_CARGO.States
ZONE_GOAL_CARGO.States = {}
--- ZONE_GOAL_CARGO Constructor.

View File

@@ -1,4 +1,4 @@
--- **Functional (WIP)** - Base class modeling processes to achieve goals involving coalition zones.
--- **Functional** - Base class that models processes to achieve goals involving a Zone for a Coalition.
--
-- ===
--
@@ -16,7 +16,7 @@
do -- ZoneGoal
-- @type ZONE_GOAL_COALITION
--- @type ZONE_GOAL_COALITION
-- @field #string ClassName Name of the Class.
-- @field #number Coalition The current coalition ID of the zone owner.
-- @field #number PreviousCoalition The previous owner of the zone.
@@ -48,7 +48,7 @@ do -- ZoneGoal
ObjectCategories = nil,
}
-- @field #table ZONE_GOAL_COALITION.States
--- @field #table ZONE_GOAL_COALITION.States
ZONE_GOAL_COALITION.States = {}
--- ZONE_GOAL_COALITION Constructor.

View File

@@ -2,7 +2,7 @@ __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/Enums.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/Utils.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/Profiler.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/Templates.lua' )
--__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/STTS.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/STTS.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/FiFo.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/Socket.lua' )
@@ -33,7 +33,6 @@ __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Core/Spot.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Core/MarkerOps_Base.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Core/TextAndSound.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Core/Pathline.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Core/ClientMenu.lua')
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Wrapper/Object.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Wrapper/Identifiable.lua' )
@@ -49,6 +48,7 @@ __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Wrapper/Marker.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Wrapper/Weapon.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Wrapper/Net.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Wrapper/Storage.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Wrapper/DynamicCargo.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Cargo/Cargo.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Cargo/CargoUnit.lua' )
@@ -78,13 +78,7 @@ __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/Warehouse.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/Fox.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/Mantis.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/Shorad.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/AICSAR.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/AmmoTruck.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/Autolase.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/ZoneGoalCargo.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/Tiresias.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/Stratego.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/ClientWatch.lua')
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/ClientWatch.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Airboss.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/RecoveryTanker.lua' )
@@ -92,31 +86,6 @@ __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/RescueHelo.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/ATIS.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/CTLD.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/CSAR.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/AirWing.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/ArmyGroup.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Auftrag.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Awacs.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Brigade.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Chief.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Cohort.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Commander.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Fleet.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/FlightControl.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/FlightGroup.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Flotilla.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Intelligence.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Legion.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/NavyGroup.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Operation.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/OpsGroup.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/OpsTransport.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/OpsZone.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Platoon.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/PlayerTask.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/PlayerRecce.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Squadron.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Target.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/EasyGCICAP.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/AI/AI_Balancer.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/AI/AI_Air.lua' )

View File

@@ -1,179 +0,0 @@
__Moose.Include( 'Utilities\\Enums.lua' )
__Moose.Include( 'Utilities\\Utils.lua' )
__Moose.Include( 'Utilities\\Profiler.lua' )
--__Moose.Include( 'Utilities\\STTS.lua' )
__Moose.Include( 'Utilities\\FiFo.lua' )
__Moose.Include( 'Utilities\\Socket.lua' )
__Moose.Include( 'Core\\Base.lua' )
__Moose.Include( 'Core\\Beacon.lua' )
__Moose.Include( 'Core\\UserFlag.lua' )
__Moose.Include( 'Core\\Report.lua' )
__Moose.Include( 'Core\\Scheduler.lua' )
__Moose.Include( 'Core\\ScheduleDispatcher.lua' )
__Moose.Include( 'Core\\Event.lua' )
__Moose.Include( 'Core\\Settings.lua' )
__Moose.Include( 'Core\\Menu.lua' )
__Moose.Include( 'Core\\Zone.lua' )
__Moose.Include( 'Core\\Velocity.lua' )
__Moose.Include( 'Core\\Database.lua' )
__Moose.Include( 'Core\\Set.lua' )
__Moose.Include( 'Core\\Point.lua' )
__Moose.Include( 'Core\\Pathline.lua' )
__Moose.Include( 'Core\\Message.lua' )
__Moose.Include( 'Core\\Fsm.lua' )
__Moose.Include( 'Core\\Spawn.lua' )
__Moose.Include( 'Core\\SpawnStatic.lua' )
__Moose.Include( 'Core\\Timer.lua' )
__Moose.Include( 'Core\\Goal.lua' )
__Moose.Include( 'Core\\Spot.lua' )
__Moose.Include( 'Core\\Astar.lua' )
__Moose.Include( 'Core\\MarkerOps_Base.lua' )
__Moose.Include( 'Core\\TextAndSound.lua' )
__Moose.Include( 'Core\\Condition.lua' )
__Moose.Include( 'Core\\ClientMenu.lua' )
__Moose.Include( 'Wrapper\\Object.lua' )
__Moose.Include( 'Wrapper\\Identifiable.lua' )
__Moose.Include( 'Wrapper\\Positionable.lua' )
__Moose.Include( 'Wrapper\\Controllable.lua' )
__Moose.Include( 'Wrapper\\Group.lua' )
__Moose.Include( 'Wrapper\\Unit.lua' )
__Moose.Include( 'Wrapper\\Client.lua' )
__Moose.Include( 'Wrapper\\Static.lua' )
__Moose.Include( 'Wrapper\\Airbase.lua' )
__Moose.Include( 'Wrapper\\Scenery.lua' )
__Moose.Include( 'Wrapper\\Marker.lua' )
__Moose.Include( 'Wrapper\\Net.lua' )
__Moose.Include( 'Wrapper\\Weapon.lua' )
__Moose.Include( 'Wrapper\\Storage.lua' )
__Moose.Include( 'Cargo\\Cargo.lua' )
__Moose.Include( 'Cargo\\CargoUnit.lua' )
__Moose.Include( 'Cargo\\CargoSlingload.lua' )
__Moose.Include( 'Cargo\\CargoCrate.lua' )
__Moose.Include( 'Cargo\\CargoGroup.lua' )
__Moose.Include( 'Functional\\Scoring.lua' )
__Moose.Include( 'Functional\\CleanUp.lua' )
__Moose.Include( 'Functional\\Movement.lua' )
__Moose.Include( 'Functional\\Sead.lua' )
__Moose.Include( 'Functional\\Escort.lua' )
__Moose.Include( 'Functional\\MissileTrainer.lua' )
__Moose.Include( 'Functional\\ATC_Ground.lua' )
__Moose.Include( 'Functional\\Detection.lua' )
__Moose.Include( 'Functional\\DetectionZones.lua' )
__Moose.Include( 'Functional\\Designate.lua' )
__Moose.Include( 'Functional\\RAT.lua' )
__Moose.Include( 'Functional\\Range.lua' )
__Moose.Include( 'Functional\\ZoneGoal.lua' )
__Moose.Include( 'Functional\\ZoneGoalCoalition.lua' )
__Moose.Include( 'Functional\\ZoneCaptureCoalition.lua' )
__Moose.Include( 'Functional\\Artillery.lua' )
__Moose.Include( 'Functional\\Suppression.lua' )
__Moose.Include( 'Functional\\PseudoATC.lua' )
__Moose.Include( 'Functional\\Warehouse.lua' )
__Moose.Include( 'Functional\\Fox.lua' )
__Moose.Include( 'Functional\\Mantis.lua' )
__Moose.Include( 'Functional\\Shorad.lua' )
__Moose.Include( 'Functional\\Autolase.lua' )
__Moose.Include( 'Functional\\AICSAR.lua' )
__Moose.Include( 'Functional\\AmmoTruck.lua' )
__Moose.Include( 'Functional\\Tiresias.lua' )
__Moose.Include( 'Functional\\Stratego.lua' )
__Moose.Include( 'Ops\\Airboss.lua' )
__Moose.Include( 'Ops\\RecoveryTanker.lua' )
__Moose.Include( 'Ops\\RescueHelo.lua' )
__Moose.Include( 'Ops\\ATIS.lua' )
__Moose.Include( 'Ops\\Auftrag.lua' )
__Moose.Include( 'Ops\\Target.lua' )
__Moose.Include( 'Ops\\OpsGroup.lua' )
__Moose.Include( 'Ops\\FlightGroup.lua' )
__Moose.Include( 'Ops\\NavyGroup.lua' )
__Moose.Include( 'Ops\\ArmyGroup.lua' )
__Moose.Include( 'Ops\\Cohort.lua' )
__Moose.Include( 'Ops\\Squadron.lua' )
__Moose.Include( 'Ops\\Platoon.lua' )
__Moose.Include( 'Ops\\Legion.lua' )
__Moose.Include( 'Ops\\AirWing.lua' )
__Moose.Include( 'Ops\\Brigade.lua' )
__Moose.Include( 'Ops\\Intelligence.lua' )
__Moose.Include( 'Ops\\Commander.lua' )
__Moose.Include( 'Ops\\OpsTransport.lua' )
__Moose.Include( 'Ops\\CSAR.lua' )
__Moose.Include( 'Ops\\CTLD.lua' )
__Moose.Include( 'Ops\\OpsZone.lua' )
__Moose.Include( 'Ops\\Chief.lua' )
__Moose.Include( 'Ops\\Flotilla.lua' )
__Moose.Include( 'Ops\\Fleet.lua' )
__Moose.Include( 'Ops\\Awacs.lua' )
__Moose.Include( 'Ops\\PlayerTask.lua' )
__Moose.Include( 'Ops\\Operation.lua' )
__Moose.Include( 'Ops\\FlightControl.lua' )
__Moose.Include( 'Ops\\PlayerRecce.lua' )
__Moose.Include( 'Ops\\EasyGCICAP.lua' )
__Moose.Include( 'Ops\\EasyA2G.lua' )
__Moose.Include( 'AI\\AI_Balancer.lua' )
__Moose.Include( 'AI\\AI_Air.lua' )
__Moose.Include( 'AI\\AI_Air_Patrol.lua' )
__Moose.Include( 'AI\\AI_Air_Engage.lua' )
__Moose.Include( 'AI\\AI_A2A_Patrol.lua' )
__Moose.Include( 'AI\\AI_A2A_Cap.lua' )
__Moose.Include( 'AI\\AI_A2A_Gci.lua' )
__Moose.Include( 'AI\\AI_A2A_Dispatcher.lua' )
__Moose.Include( 'AI\\AI_A2G_BAI.lua' )
__Moose.Include( 'AI\\AI_A2G_CAS.lua' )
__Moose.Include( 'AI\\AI_A2G_SEAD.lua' )
__Moose.Include( 'AI\\AI_A2G_Dispatcher.lua' )
__Moose.Include( 'AI\\AI_Patrol.lua' )
__Moose.Include( 'AI\\AI_Cap.lua' )
__Moose.Include( 'AI\\AI_Cas.lua' )
__Moose.Include( 'AI\\AI_Bai.lua' )
__Moose.Include( 'AI\\AI_Formation.lua' )
__Moose.Include( 'AI\\AI_Escort.lua' )
__Moose.Include( 'AI\\AI_Escort_Request.lua' )
__Moose.Include( 'AI\\AI_Escort_Dispatcher.lua' )
__Moose.Include( 'AI\\AI_Escort_Dispatcher_Request.lua' )
__Moose.Include( 'AI\\AI_Cargo.lua' )
__Moose.Include( 'AI\\AI_Cargo_APC.lua' )
__Moose.Include( 'AI\\AI_Cargo_Helicopter.lua' )
__Moose.Include( 'AI\\AI_Cargo_Airplane.lua' )
__Moose.Include( 'AI\\AI_Cargo_Ship.lua' )
__Moose.Include( 'AI\\AI_Cargo_Dispatcher.lua' )
__Moose.Include( 'AI\\AI_Cargo_Dispatcher_APC.lua' )
__Moose.Include( 'AI\\AI_Cargo_Dispatcher_Helicopter.lua' )
__Moose.Include( 'AI\\AI_Cargo_Dispatcher_Airplane.lua' )
__Moose.Include( 'AI\\AI_Cargo_Dispatcher_Ship.lua' )
__Moose.Include( 'Actions\\Act_Assign.lua' )
__Moose.Include( 'Actions\\Act_Route.lua' )
__Moose.Include( 'Actions\\Act_Account.lua' )
__Moose.Include( 'Actions\\Act_Assist.lua' )
__Moose.Include( 'Sound\\UserSound.lua' )
__Moose.Include( 'Sound\\SoundOutput.lua' )
__Moose.Include( 'Sound\\Radio.lua' )
__Moose.Include( 'Sound\\RadioQueue.lua' )
__Moose.Include( 'Sound\\RadioSpeech.lua' )
__Moose.Include( 'Sound\\SRS.lua' )
__Moose.Include( 'Tasking\\CommandCenter.lua' )
__Moose.Include( 'Tasking\\Mission.lua' )
__Moose.Include( 'Tasking\\Task.lua' )
__Moose.Include( 'Tasking\\TaskInfo.lua' )
__Moose.Include( 'Tasking\\Task_Manager.lua' )
__Moose.Include( 'Tasking\\DetectionManager.lua' )
__Moose.Include( 'Tasking\\Task_A2G_Dispatcher.lua' )
__Moose.Include( 'Tasking\\Task_A2G.lua' )
__Moose.Include( 'Tasking\\Task_A2A_Dispatcher.lua' )
__Moose.Include( 'Tasking\\Task_A2A.lua' )
__Moose.Include( 'Tasking\\Task_Cargo.lua' )
__Moose.Include( 'Tasking\\Task_Cargo_Transport.lua' )
__Moose.Include( 'Tasking\\Task_Cargo_CSAR.lua' )
__Moose.Include( 'Tasking\\Task_Cargo_Dispatcher.lua' )
__Moose.Include( 'Tasking\\Task_Capture_Zone.lua' )
__Moose.Include( 'Tasking\\Task_Capture_Dispatcher.lua' )
__Moose.Include( 'Globals.lua' )

View File

@@ -291,7 +291,7 @@
-- ## Nevada: Nellis AFB
--
-- -- ATIS Nellis AFB on 270.10 MHz AM.
-- atisNellis=ATIS:New(AIRBASE.Nevada.Nellis_AFB, 270.1)
-- atisNellis=ATIS:New(AIRBASE.Nevada.Nellis, 270.1)
-- atisNellis:SetRadioRelayUnitName("Radio Relay Nellis")
-- atisNellis:SetActiveRunway("21L")
-- atisNellis:SetTowerFrequencies({327.000, 132.550})
@@ -302,7 +302,7 @@
-- ## Persian Gulf: Abu Dhabi International Airport
--
-- -- ATIS Abu Dhabi International on 125.1 MHz AM.
-- atisAbuDhabi=ATIS:New(AIRBASE.PersianGulf.Abu_Dhabi_International_Airport, 125.1)
-- atisAbuDhabi=ATIS:New(AIRBASE.PersianGulf.Abu_Dhabi_Intl, 125.1)
-- atisAbuDhabi:SetRadioRelayUnitName("Radio Relay Abu Dhabi International Airport")
-- atisAbuDhabi:SetMetricUnits()
-- atisAbuDhabi:SetActiveRunway("L")
@@ -498,6 +498,9 @@ ATIS.Alphabet = {
-- @field #number Syria +5° (East).
-- @field #number MarianaIslands +2° (East).
-- @field #number SinaiMap +5° (East).
-- @field #number Kola +15° (East).
-- @field #number Afghanistan +3° (East).
-- @field #number Iraq +4.4° (East).
ATIS.RunwayM2T = {
Caucasus = 0,
Nevada = 12,
@@ -508,6 +511,9 @@ ATIS.RunwayM2T = {
MarianaIslands = 2,
Falklands = 12,
SinaiMap = 5,
Kola = 15,
Afghanistan = 3,
Iraq=4.4
}
--- Whether ICAO phraseology is used for ATIS broadcasts.
@@ -521,6 +527,9 @@ ATIS.RunwayM2T = {
-- @field #boolean MarianaIslands true.
-- @field #boolean Falklands true.
-- @field #boolean SinaiMap true.
-- @field #boolean Kola true.
-- @field #boolean Afghanistan true.
-- @field #boolean Iraq true.
ATIS.ICAOPhraseology = {
Caucasus = true,
Nevada = false,
@@ -531,6 +540,9 @@ ATIS.ICAOPhraseology = {
MarianaIslands = true,
Falklands = true,
SinaiMap = true,
Kola = true,
Afghanistan = true,
Iraq = true,
}
--- Nav point data.
@@ -619,83 +631,83 @@ ATIS.ICAOPhraseology = {
-- @field #ATIS.Soundfile TACANChannel
-- @field #ATIS.Soundfile VORFrequency
ATIS.Sound = {
ActiveRunway = { filename = "ActiveRunway.ogg", duration = 0.99 },
ActiveRunwayDeparture = { filename = "ActiveRunwayDeparture.ogg", duration = 0.99 },
ActiveRunwayArrival = { filename = "ActiveRunwayArrival.ogg", duration = 0.99 },
AdviceOnInitial = { filename = "AdviceOnInitial.ogg", duration = 3.00 },
Airport = { filename = "Airport.ogg", duration = 0.66 },
Altimeter = { filename = "Altimeter.ogg", duration = 0.68 },
At = { filename = "At.ogg", duration = 0.41 },
CloudBase = { filename = "CloudBase.ogg", duration = 0.82 },
CloudCeiling = { filename = "CloudCeiling.ogg", duration = 0.61 },
CloudsBroken = { filename = "CloudsBroken.ogg", duration = 1.07 },
CloudsFew = { filename = "CloudsFew.ogg", duration = 0.99 },
CloudsNo = { filename = "CloudsNo.ogg", duration = 1.01 },
CloudsNotAvailable = { filename = "CloudsNotAvailable.ogg", duration = 2.35 },
CloudsOvercast = { filename = "CloudsOvercast.ogg", duration = 0.83 },
CloudsScattered = { filename = "CloudsScattered.ogg", duration = 1.18 },
Decimal = { filename = "Decimal.ogg", duration = 0.54 },
DegreesCelsius = { filename = "DegreesCelsius.ogg", duration = 1.27 },
DegreesFahrenheit = { filename = "DegreesFahrenheit.ogg", duration = 1.23 },
DewPoint = { filename = "DewPoint.ogg", duration = 0.65 },
Dust = { filename = "Dust.ogg", duration = 0.54 },
Elevation = { filename = "Elevation.ogg", duration = 0.78 },
EndOfInformation = { filename = "EndOfInformation.ogg", duration = 1.15 },
Feet = { filename = "Feet.ogg", duration = 0.45 },
Fog = { filename = "Fog.ogg", duration = 0.47 },
Gusting = { filename = "Gusting.ogg", duration = 0.55 },
HectoPascal = { filename = "HectoPascal.ogg", duration = 1.15 },
Hundred = { filename = "Hundred.ogg", duration = 0.47 },
InchesOfMercury = { filename = "InchesOfMercury.ogg", duration = 1.16 },
Information = { filename = "Information.ogg", duration = 0.85 },
Kilometers = { filename = "Kilometers.ogg", duration = 0.78 },
Knots = { filename = "Knots.ogg", duration = 0.59 },
Left = { filename = "Left.ogg", duration = 0.54 },
MegaHertz = { filename = "MegaHertz.ogg", duration = 0.87 },
Meters = { filename = "Meters.ogg", duration = 0.59 },
MetersPerSecond = { filename = "MetersPerSecond.ogg", duration = 1.14 },
Miles = { filename = "Miles.ogg", duration = 0.60 },
MillimetersOfMercury = { filename = "MillimetersOfMercury.ogg", duration = 1.53 },
Minus = { filename = "Minus.ogg", duration = 0.64 },
N0 = { filename = "N-0.ogg", duration = 0.55 },
N1 = { filename = "N-1.ogg", duration = 0.41 },
N2 = { filename = "N-2.ogg", duration = 0.37 },
N3 = { filename = "N-3.ogg", duration = 0.41 },
N4 = { filename = "N-4.ogg", duration = 0.37 },
N5 = { filename = "N-5.ogg", duration = 0.43 },
N6 = { filename = "N-6.ogg", duration = 0.55 },
N7 = { filename = "N-7.ogg", duration = 0.43 },
N8 = { filename = "N-8.ogg", duration = 0.38 },
N9 = { filename = "N-9.ogg", duration = 0.55 },
NauticalMiles = { filename = "NauticalMiles.ogg", duration = 1.04 },
None = { filename = "None.ogg", duration = 0.43 },
QFE = { filename = "QFE.ogg", duration = 0.63 },
QNH = { filename = "QNH.ogg", duration = 0.71 },
Rain = { filename = "Rain.ogg", duration = 0.41 },
Right = { filename = "Right.ogg", duration = 0.44 },
Snow = { filename = "Snow.ogg", duration = 0.48 },
SnowStorm = { filename = "SnowStorm.ogg", duration = 0.82 },
StatuteMiles = { filename = "StatuteMiles.ogg", duration = 1.15 },
SunriseAt = { filename = "SunriseAt.ogg", duration = 0.92 },
SunsetAt = { filename = "SunsetAt.ogg", duration = 0.95 },
Temperature = { filename = "Temperature.ogg", duration = 0.64 },
Thousand = { filename = "Thousand.ogg", duration = 0.55 },
ThunderStorm = { filename = "ThunderStorm.ogg", duration = 0.81 },
TimeLocal = { filename = "TimeLocal.ogg", duration = 0.90 },
TimeZulu = { filename = "TimeZulu.ogg", duration = 0.86 },
TowerFrequency = { filename = "TowerFrequency.ogg", duration = 1.19 },
Visibilty = { filename = "Visibility.ogg", duration = 0.79 },
WeatherPhenomena = { filename = "WeatherPhenomena.ogg", duration = 1.07 },
WindFrom = { filename = "WindFrom.ogg", duration = 0.60 },
ActiveRunway = { filename = "ActiveRunway.ogg", duration = 0.85 },
ActiveRunwayDeparture = { filename = "ActiveRunwayDeparture.ogg", duration = 1.50 },
ActiveRunwayArrival = { filename = "ActiveRunwayArrival.ogg", duration = 1.38 },
AdviceOnInitial = { filename = "AdviceOnInitial.ogg", duration = 2.98 },
Airport = { filename = "Airport.ogg", duration = 0.55 },
Altimeter = { filename = "Altimeter.ogg", duration = 0.91 },
At = { filename = "At.ogg", duration = 0.32 },
CloudBase = { filename = "CloudBase.ogg", duration = 0.69 },
CloudCeiling = { filename = "CloudCeiling.ogg", duration = 0.53 },
CloudsBroken = { filename = "CloudsBroken.ogg", duration = 0.81 },
CloudsFew = { filename = "CloudsFew.ogg", duration = 0.74 },
CloudsNo = { filename = "CloudsNo.ogg", duration = 0.69},
CloudsNotAvailable = { filename = "CloudsNotAvailable.ogg", duration = 2.64 },
CloudsOvercast = { filename = "CloudsOvercast.ogg", duration = 0.82 },
CloudsScattered = { filename = "CloudsScattered.ogg", duration = 0.89 },
Decimal = { filename = "Decimal.ogg", duration = 0.71 },
DegreesCelsius = { filename = "DegreesCelsius.ogg", duration = 1.08 },
DegreesFahrenheit = { filename = "DegreesFahrenheit.ogg", duration = 1.07 },
DewPoint = { filename = "DewPoint.ogg", duration = 0.59 },
Dust = { filename = "Dust.ogg", duration = 0.37 },
Elevation = { filename = "Elevation.ogg", duration = 0.92 },
EndOfInformation = { filename = "EndOfInformation.ogg", duration = 1.24 },
Feet = { filename = "Feet.ogg", duration = 0.34 },
Fog = { filename = "Fog.ogg", duration = 0.41 },
Gusting = { filename = "Gusting.ogg", duration = 0.58 },
HectoPascal = { filename = "HectoPascal.ogg", duration = 0.92 },
Hundred = { filename = "Hundred.ogg", duration = 0.53 },
ILSFrequency = { filename = "ILSFrequency.ogg", duration = 1.30 },
InnerNDBFrequency = { filename = "InnerNDBFrequency.ogg", duration = 1.56 },
OuterNDBFrequency = { filename = "OuterNDBFrequency.ogg", duration = 1.59 },
RunwayLength = { filename = "RunwayLength.ogg", duration = 0.91 },
VORFrequency = { filename = "VORFrequency.ogg", duration = 1.38 },
TACANChannel = { filename = "TACANChannel.ogg", duration = 0.88 },
PRMGChannel = { filename = "PRMGChannel.ogg", duration = 1.18 },
RSBNChannel = { filename = "RSBNChannel.ogg", duration = 1.14 },
Zulu = { filename = "Zulu.ogg", duration = 0.62 },
InchesOfMercury = { filename = "InchesOfMercury.ogg", duration = 1.26 },
Information = { filename = "Information.ogg", duration = 0.99 },
InnerNDBFrequency = { filename = "InnerNDBFrequency.ogg", duration = 1.69 },
Kilometers = { filename = "Kilometers.ogg", duration = 0.93 },
Knots = { filename = "Knots.ogg", duration = 0.46 },
Left = { filename = "Left.ogg", duration = 0.41 },
MegaHertz = { filename = "MegaHertz.ogg", duration = 0.83 },
Meters = { filename = "Meters.ogg", duration = 0.55 },
MetersPerSecond = { filename = "MetersPerSecond.ogg", duration = 1.03 },
Miles = { filename = "Miles.ogg", duration = 0.44 },
MillimetersOfMercury = { filename = "MillimetersOfMercury.ogg", duration = 1.59 },
Minus = { filename = "Minus.ogg", duration = 0.55 },
N0 = { filename = "N-0.ogg", duration = 0.52 },
N1 = { filename = "N-1.ogg", duration = 0.35 },
N2 = { filename = "N-2.ogg", duration = 0.41 },
N3 = { filename = "N-3.ogg", duration = 0.34 },
N4 = { filename = "N-4.ogg", duration = 0.37 },
N5 = { filename = "N-5.ogg", duration = 0.40 },
N6 = { filename = "N-6.ogg", duration = 0.46 },
N7 = { filename = "N-7.ogg", duration = 0.52 },
N8 = { filename = "N-8.ogg", duration = 0.36 },
N9 = { filename = "N-9.ogg", duration = 0.51 },
NauticalMiles = { filename = "NauticalMiles.ogg", duration = 0.93 },
None = { filename = "None.ogg", duration = 0.33 },
OuterNDBFrequency = { filename = "OuterNDBFrequency.ogg", duration = 1.70 },
PRMGChannel = { filename = "PRMGChannel.ogg", duration = 1.27 },
QFE = { filename = "QFE.ogg", duration = 0.90 },
QNH = { filename = "QNH.ogg", duration = 0.94 },
Rain = { filename = "Rain.ogg", duration = 0.35 },
Right = { filename = "Right.ogg", duration = 0.31 },
RSBNChannel = { filename = "RSBNChannel.ogg", duration = 1.26 },
RunwayLength = { filename = "RunwayLength.ogg", duration = 0.81 },
Snow = { filename = "Snow.ogg", duration = 0.40 },
SnowStorm = { filename = "SnowStorm.ogg", duration = 0.73 },
StatuteMiles = { filename = "StatuteMiles.ogg", duration = 0.90 },
SunriseAt = { filename = "SunriseAt.ogg", duration = 0.82 },
SunsetAt = { filename = "SunsetAt.ogg", duration = 0.87 },
TACANChannel = { filename = "TACANChannel.ogg", duration = 0.81 },
Temperature = { filename = "Temperature.ogg", duration = 0.70 },
Thousand = { filename = "Thousand.ogg", duration = 0.58 },
ThunderStorm = { filename = "ThunderStorm.ogg", duration = 0.79 },
TimeLocal = { filename = "TimeLocal.ogg", duration = 0.83 },
TimeZulu = { filename = "TimeZulu.ogg", duration = 0.83 },
TowerFrequency = { filename = "TowerFrequency.ogg", duration = 1.05 },
Visibilty = { filename = "Visibility.ogg", duration = 1.16 },
VORFrequency = { filename = "VORFrequency.ogg", duration = 1.28 },
WeatherPhenomena = { filename = "WeatherPhenomena.ogg", duration = 1.09 },
WindFrom = { filename = "WindFrom.ogg", duration = 0.63 },
Zulu = { filename = "Zulu.ogg", duration = 0.51 },
}
---
@@ -882,6 +894,66 @@ ATIS.Messages = {
FARP = "Farp",
DELIMITER = "Punto", -- decimal delimiter
},
-- French messages thanks to @Wojtech and Bing
FR = {
HOURS = "Heures",
TIME = "Temps",
NOCLOUDINFO = "Informations sur la couverture nuageuse non disponibles",
OVERCAST = "Ciel couvert",
BROKEN = "Nuages fragmentés",
SCATTERED = "Nuages épars",
FEWCLOUDS = "Nuages rares",
NOCLOUDS = "Clair",
AIRPORT = "Aéroport",
INFORMATION ="Information",
SUNRISEAT = "Levé du soleil à %s heure locale",
SUNSETAT = "Couché du soleil à %s heure locale",
WINDFROMMS = "Vent du %s pour %s mètres par seconde",
WINDFROMKNOTS = "Vent du %s pour %s noeuds",
GUSTING = "Rafale de vent",
VISIKM = "Visibilité %s kilomètres",
VISISM = "Visibilité %s Miles",
RAIN = "Pluie",
TSTORM = "Orage",
SNOW = "Neige",
SSTROM = "Tempête de neige",
FOG = "Brouillard",
DUST = "Poussière",
PHENOMENA = "Phénomène météorologique",
CLOUDBASEM = "Couverture nuageuse de %s à %s mètres",
CLOUDBASEFT = "Couverture nuageuse de %s à %s pieds",
TEMPERATURE = "Température",
DEWPOINT = "Point de rosée",
ALTIMETER = "Altimètre",
ACTIVERUN = "Décollages piste",
ACTIVELANDING = "Atterrissages piste",
LEFT = "Gauche",
RIGHT = "Droite",
RWYLENGTH = "Longueur de piste",
METERS = "Mètre",
FEET = "Pieds",
ELEVATION = "Hauteur",
TOWERFREQ = "Fréquences de la tour",
ILSFREQ = "Fréquences ILS",
OUTERNDB = "Fréquences Outer NDB",
INNERNDB = "Fréquences Inner NDB",
VORFREQ = "Fréquences VOR",
VORFREQTTS = "Fréquences V O R",
TACANCH = "Canal TACAN %d",
RSBNCH = "Canal RSBN",
PRMGCH = "Canal PRMG",
ADVISE = "Informez le contrôle que vous avez copié l'information",
STATUTE = "Statute Miles",
DEGREES = "Degré celcius",
FAHRENHEIT = "Degré Fahrenheit",
INCHHG = "Pouces de mercure",
MMHG = "Millimètres de mercure",
HECTO = "Hectopascals",
METERSPER = "Mètres par seconde",
TACAN = "TAKAN",
FARP = "FARPE",
DELIMITER = "Décimal", -- decimal delimiter
}
}
---
@@ -894,7 +966,7 @@ _ATIS = {}
--- ATIS class version.
-- @field #string version
ATIS.version = "1.0.0"
ATIS.version = "1.0.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@@ -1061,7 +1133,7 @@ end
-- @return #ATIS self
function ATIS:_InitLocalization()
self:T(self.lid.."_InitLocalization")
self.gettext = TEXTANDSOUND:New("AWACS","en") -- Core.TextAndSound#TEXTANDSOUND
self.gettext = TEXTANDSOUND:New("ATIS","en") -- Core.TextAndSound#TEXTANDSOUND
self.locale = "en"
for locale,table in pairs(self.Messages) do
local Locale = string.lower(tostring(locale))
@@ -1975,17 +2047,25 @@ function ATIS:onafterBroadcast( From, Event, To )
local hours = self.gettext:GetEntry("HOURS",self.locale)
local sunrise = coord:GetSunrise()
sunrise = UTILS.Split( sunrise, ":" )
local SUNRISE = string.format( "%s%s", sunrise[1], sunrise[2] )
if self.useSRS then
SUNRISE = string.format( "%s %s %s", sunrise[1], sunrise[2], hours )
--self:I(sunrise)
local SUNRISE = "no time"
if tostring(sunrise) ~= "N/S" and tostring(sunrise) ~= "N/R" then
sunrise = UTILS.Split( sunrise, ":" )
SUNRISE = string.format( "%s%s", sunrise[1], sunrise[2] )
if self.useSRS then
SUNRISE = string.format( "%s %s %s", sunrise[1], sunrise[2], hours )
end
end
local sunset = coord:GetSunset()
sunset = UTILS.Split( sunset, ":" )
local SUNSET = string.format( "%s%s", sunset[1], sunset[2] )
if self.useSRS then
SUNSET = string.format( "%s %s %s", sunset[1], sunset[2], hours )
--self:I(sunset)
local SUNSET = "no time"
if tostring(sunset) ~= "N/S" and tostring(sunset) ~= "N/R" then
sunset = UTILS.Split( sunset, ":" )
SUNSET = string.format( "%s%s", sunset[1], sunset[2] )
if self.useSRS then
SUNSET = string.format( "%s %s %s", sunset[1], sunset[2], hours )
end
end
---------------------------------
@@ -2012,34 +2092,32 @@ function ATIS:onafterBroadcast( From, Event, To )
---------------
-- Get mission weather info. Most of this is static.
local clouds, visibility, turbulence, fog, dust, static = self:GetMissionWeather()
-- Check that fog is actually "thick" enough to reach the airport. If an airport is in the mountains, fog might not affect it as it is measured from sea level.
if fog and fog.thickness < height + 25 then
fog = nil
end
-- Dust only up to 1500 ft = 457 m ASL.
if dust and height + 25 > UTILS.FeetToMeters( 1500 ) then
dust = nil
end
local clouds, visibility, turbulence, dustdens, static = self:GetMissionWeather()
local dust=false
local fog=false
------------------
--- Visibility ---
------------------
-- Get min visibility.
local visibilitymin = visibility
if fog then
if fog.visibility < visibilitymin then
visibilitymin = fog.visibility
if dustdens then
-- Dust only up to 1500 ft = 457 m ASL.
if UTILS.FeetToMeters( 1500 )> height+25 then
dust=true
visibility=math.min(visibility, dustdens)
end
end
if dust then
if dust < visibilitymin then
visibilitymin = dust
else -- As of DCS 2.9.10.3948 (December 2024), fog and dust are mutually exclusive!
-- Get current fog visibility and thickness
local fvis=world.weather.getFogVisibilityDistance()
local fheight=world.weather.getFogThickness()
if fvis>0 and fheight>height+25 then
fog=true
visibility=math.min(visibility, fvis)
end
end
@@ -2047,7 +2125,7 @@ function ATIS:onafterBroadcast( From, Event, To )
if self.metric then
-- Visibility in km.
local reportedviz = UTILS.Round( visibilitymin / 1000 )
local reportedviz = UTILS.Round( visibility / 1000 )
-- max reported visibility 9999 m
if reportedviz > 10 then
reportedviz = 10
@@ -2055,7 +2133,7 @@ function ATIS:onafterBroadcast( From, Event, To )
VISIBILITY = string.format( "%d", reportedviz )
else
-- max reported visibility 10 NM
local reportedviz = UTILS.Round( UTILS.MetersToSM( visibilitymin ) )
local reportedviz = UTILS.Round( UTILS.MetersToSM( visibility ) )
if reportedviz > 10 then
reportedviz = 10
end
@@ -2069,7 +2147,7 @@ function ATIS:onafterBroadcast( From, Event, To )
local cloudbase = clouds.base
local cloudceil = clouds.base + clouds.thickness
local clouddens = clouds.density
-- Cloud preset (DCS 2.7)
local cloudspreset = clouds.preset or "Nothing"
@@ -2100,6 +2178,39 @@ function ATIS:onafterBroadcast( From, Event, To )
else
precepitation = 3 -- snow
end
elseif cloudspreset:find( "RainyPreset4" ) then
-- Overcast + Rain
clouddens = 5
if temperature > 5 then
precepitation = 1 -- rain
else
precepitation = 3 -- snow
end
elseif cloudspreset:find( "RainyPreset5" ) then
-- Overcast + Rain
clouddens = 5
if temperature > 5 then
precepitation = 1 -- rain
else
precepitation = 3 -- snow
end
elseif cloudspreset:find( "RainyPreset6" ) then
-- Overcast + Rain
clouddens = 5
if temperature > 5 then
precepitation = 1 -- rain
else
precepitation = 3 -- snow
end
-- NEWRAINPRESET4
elseif cloudspreset:find( "NEWRAINPRESET4" ) then
-- Overcast + Rain
clouddens = 5
if temperature > 5 then
precepitation = 1 -- rain
else
precepitation = 3 -- snow
end
elseif cloudspreset:find( "RainyPreset" ) then
-- Overcast + Rain
clouddens = 9
@@ -3249,28 +3360,13 @@ function ATIS:GetMissionWeather()
dust = weather.dust_density
end
-- Fog
--[[
["enable_fog"] = false,
["fog"] =
{
["thickness"] = 0,
["visibility"] = 25,
}, -- end of ["fog"]
]]
local fog = nil
if weather.enable_fog == true then
fog = weather.fog
end
self:T( "FF weather:" )
self:T( { clouds = clouds } )
self:T( { visibility = visibility } )
self:T( { turbulence = turbulence } )
self:T( { fog = fog } )
self:T( { dust = dust } )
self:T( { static = static } )
return clouds, visibility, turbulence, fog, dust, static
return clouds, visibility, turbulence, dust, static
end
--- Get thousands of a number.

File diff suppressed because it is too large Load Diff

View File

@@ -3088,8 +3088,7 @@ function AIRBOSS:EnableSRS(PathToSRS,Port,Culture,Gender,Voice,GoogleCreds,Volum
self.SRS:SetVolume(Volume or 1)
--self.SRS:SetModulations(Modulations)
if GoogleCreds then
self.SRS:SetProviderOptionsGoogle(GoogleCreds,GoogleCreds)
self.SRS:SetProvider(MSRS.Provider.GOOGLE)
self.SRS:SetGoogle(GoogleCreds)
end
if Voice then
self.SRS:SetVoice(Voice)
@@ -3615,7 +3614,7 @@ function AIRBOSS:onafterStart( From, Event, To )
-- Handle events.
self:HandleEvent( EVENTS.Birth )
self:HandleEvent( EVENTS.Land )
self:HandleEvent( EVENTS.RunwayTouch )
self:HandleEvent( EVENTS.EngineShutdown )
self:HandleEvent( EVENTS.Takeoff )
self:HandleEvent( EVENTS.Crash )
@@ -3623,7 +3622,6 @@ function AIRBOSS:onafterStart( From, Event, To )
self:HandleEvent( EVENTS.PlayerLeaveUnit, self._PlayerLeft )
self:HandleEvent( EVENTS.MissionEnd )
self:HandleEvent( EVENTS.RemoveUnit )
self:HandleEvent( EVENTS.UnitLost, self.OnEventRemoveUnit )
-- self.StatusScheduler=SCHEDULER:New(self)
-- self.StatusScheduler:Schedule(self, self._Status, {}, 1, 0.5)
@@ -4381,7 +4379,7 @@ function AIRBOSS:onafterStop( From, Event, To )
-- Unhandle events.
self:UnHandleEvent( EVENTS.Birth )
self:UnHandleEvent( EVENTS.Land )
self:UnHandleEvent( EVENTS.RunwayTouch )
self:UnHandleEvent( EVENTS.EngineShutdown )
self:UnHandleEvent( EVENTS.Takeoff )
self:UnHandleEvent( EVENTS.Crash )
@@ -8291,7 +8289,7 @@ end
--- Airboss event handler for event land.
-- @param #AIRBOSS self
-- @param Core.Event#EVENTDATA EventData
function AIRBOSS:OnEventLand( EventData )
function AIRBOSS:OnEventRunwayTouch( EventData )
self:F3( { eventland = EventData } )
-- Nil checks.
@@ -14680,7 +14678,7 @@ function AIRBOSS:_GetPlayerUnitAndName( _unitName )
-- Get DCS unit from its name.
local DCSunit = Unit.getByName( _unitName )
if DCSunit then
if DCSunit and DCSunit.getPlayerName then
-- Get player name if any.
local playername = DCSunit:getPlayerName()
@@ -15651,7 +15649,7 @@ function AIRBOSS:_Number2Sound( playerData, sender, number, delay )
end
-- Split string into characters.
local numbers = _split( number )
local numbers = _split( tostring(number) )
local wait = 0
for i = 1, #numbers do
@@ -15719,7 +15717,7 @@ function AIRBOSS:_Number2Radio( radio, number, delay, interval, pilotcall )
end
-- Split string into characters.
local numbers = _split( number )
local numbers = _split( tostring(number) )
local wait = 0
for i = 1, #numbers do
@@ -18087,7 +18085,7 @@ function AIRBOSS:_MarkCaseZones( _unitName, flare )
self:_GetZoneArcIn( case ):FlareZone( FLARECOLOR.White, 45 )
text = text .. "\n* arc turn in with WHITE flares"
self:_GetZoneArcOut( case ):FlareZone( FLARECOLOR.White, 45 )
text = text .. "\n* arc trun out with WHITE flares"
text = text .. "\n* arc turn out with WHITE flares"
end
end
@@ -18139,7 +18137,7 @@ function AIRBOSS:_MarkCaseZones( _unitName, flare )
self:_GetZoneArcIn( case ):SmokeZone( SMOKECOLOR.Blue, 45 )
text = text .. "\n* arc turn in with BLUE smoke"
self:_GetZoneArcOut( case ):SmokeZone( SMOKECOLOR.Blue, 45 )
text = text .. "\n* arc trun out with BLUE smoke"
text = text .. "\n* arc turn out with BLUE smoke"
end
end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,624 +0,0 @@
--- **Ops** - Brigade Warehouse.
--
-- **Main Features:**
--
-- * Manage platoons
-- * Carry out ARTY and PATROLZONE missions (AUFTRAG)
-- * Define rearming zones
--
-- ===
--
-- ## Example Missions:
--
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Ops/Brigade).
--
-- ===
--
-- ### Author: **funkyfranky**
--
-- ===
-- @module Ops.Brigade
-- @image OPS_Brigade_.png
--- BRIGADE class.
-- @type BRIGADE
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity of output.
-- @field #table rearmingZones Rearming zones. Each element is of type `#BRIGADE.SupplyZone`.
-- @field #table refuellingZones Refuelling zones. Each element is of type `#BRIGADE.SupplyZone`.
-- @field Core.Set#SET_ZONE retreatZones Retreat zone set.
-- @extends Ops.Legion#LEGION
--- *I am not afraid of an Army of lions lead by a sheep; I am afraid of sheep lead by a lion* -- Alexander the Great
--
-- ===
--
-- # The BRIGADE Concept
--
-- A BRIGADE consists of one or multiple PLATOONs. These platoons "live" in a WAREHOUSE that has a phyiscal struction (STATIC or UNIT) and can be captured or destroyed.
--
--
-- @field #BRIGADE
BRIGADE = {
ClassName = "BRIGADE",
verbose = 0,
rearmingZones = {},
refuellingZones = {},
}
--- Supply Zone.
-- @type BRIGADE.SupplyZone
-- @field Core.Zone#ZONE zone The zone.
-- @field Ops.Auftrag#AUFTRAG mission Mission assigned to supply ammo or fuel.
-- @field #boolean markerOn If `true`, marker is on.
-- @field Wrapper.Marker#MARKER marker F10 marker.
--- BRIGADE class version.
-- @field #string version
BRIGADE.version="0.1.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Spawn when hosting warehouse is a ship or oil rig or gas platform.
-- TODO: Rearming zones.
-- TODO: Retreat zones.
-- DONE: Add weapon range.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new BRIGADE class object.
-- @param #BRIGADE self
-- @param #string WarehouseName Name of the warehouse STATIC or UNIT object representing the warehouse.
-- @param #string BrigadeName Name of the brigade.
-- @return #BRIGADE self
function BRIGADE:New(WarehouseName, BrigadeName)
-- Inherit everything from LEGION class.
local self=BASE:Inherit(self, LEGION:New(WarehouseName, BrigadeName)) -- #BRIGADE
-- Nil check.
if not self then
BASE:E(string.format("ERROR: Could not find warehouse %s!", WarehouseName))
return nil
end
-- Set some string id for output to DCS.log file.
self.lid=string.format("BRIGADE %s | ", self.alias)
-- Defaults
self:SetRetreatZones()
-- Turn ship into NAVYGROUP.
if self:IsShip() then
local wh=self.warehouse --Wrapper.Unit#UNIT
local group=wh:GetGroup()
self.warehouseOpsGroup=NAVYGROUP:New(group) --Ops.NavyGroup#NAVYGROUP
self.warehouseOpsElement=self.warehouseOpsGroup:GetElementByName(wh:GetName())
end
-- Add FSM transitions.
-- From State --> Event --> To State
self:AddTransition("*", "ArmyOnMission", "*") -- An ARMYGROUP was send on a Mission (AUFTRAG).
------------------------
--- Pseudo Functions ---
------------------------
--- Triggers the FSM event "Start". Starts the BRIGADE. Initializes parameters and starts event handlers.
-- @function [parent=#BRIGADE] Start
-- @param #BRIGADE self
--- Triggers the FSM event "Start" after a delay. Starts the BRIGADE. Initializes parameters and starts event handlers.
-- @function [parent=#BRIGADE] __Start
-- @param #BRIGADE self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "Stop". Stops the BRIGADE and all its event handlers.
-- @param #BRIGADE self
--- Triggers the FSM event "Stop" after a delay. Stops the BRIGADE and all its event handlers.
-- @function [parent=#BRIGADE] __Stop
-- @param #BRIGADE self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "ArmyOnMission".
-- @function [parent=#BRIGADE] ArmyOnMission
-- @param #BRIGADE self
-- @param Ops.ArmyGroup#ARMYGROUP ArmyGroup The ARMYGROUP on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
--- Triggers the FSM event "ArmyOnMission" after a delay.
-- @function [parent=#BRIGADE] __ArmyOnMission
-- @param #BRIGADE self
-- @param #number delay Delay in seconds.
-- @param Ops.ArmyGroup#ARMYGROUP ArmyGroup The ARMYGROUP on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
--- On after "ArmyOnMission" event.
-- @function [parent=#BRIGADE] OnAfterArmyOnMission
-- @param #BRIGADE self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Ops.ArmyGroup#ARMYGROUP ArmyGroup The ARMYGROUP on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Add a platoon to the brigade.
-- @param #BRIGADE self
-- @param Ops.Platoon#PLATOON Platoon The platoon object.
-- @return #BRIGADE self
function BRIGADE:AddPlatoon(Platoon)
-- Add platoon to brigade.
table.insert(self.cohorts, Platoon)
-- Add assets to platoon.
self:AddAssetToPlatoon(Platoon, Platoon.Ngroups)
-- Set brigade of platoon.
Platoon:SetBrigade(self)
-- Start platoon.
if Platoon:IsStopped() then
Platoon:Start()
end
return self
end
--- Add asset group(s) to platoon.
-- @param #BRIGADE self
-- @param Ops.Platoon#PLATOON Platoon The platoon object.
-- @param #number Nassets Number of asset groups to add.
-- @return #BRIGADE self
function BRIGADE:AddAssetToPlatoon(Platoon, Nassets)
if Platoon then
-- Get the template group of the platoon.
local Group=GROUP:FindByName(Platoon.templatename)
if Group then
-- Debug text.
local text=string.format("Adding asset %s to platoon %s", Group:GetName(), Platoon.name)
self:T(self.lid..text)
-- Add assets to airwing warehouse.
self:AddAsset(Group, Nassets, nil, nil, nil, nil, Platoon.skill, Platoon.livery, Platoon.name)
else
self:E(self.lid.."ERROR: Group does not exist!")
end
else
self:E(self.lid.."ERROR: Platoon does not exit!")
end
return self
end
--- Define a set of retreat zones.
-- @param #BRIGADE self
-- @param Core.Set#SET_ZONE RetreatZoneSet Set of retreat zones.
-- @return #BRIGADE self
function BRIGADE:SetRetreatZones(RetreatZoneSet)
self.retreatZones=RetreatZoneSet or SET_ZONE:New()
return self
end
--- Add a retreat zone.
-- @param #BRIGADE self
-- @param Core.Zone#ZONE RetreatZone Retreat zone.
-- @return #BRIGADE self
function BRIGADE:AddRetreatZone(RetreatZone)
self.retreatZones:AddZone(RetreatZone)
return self
end
--- Get retreat zones.
-- @param #BRIGADE self
-- @return Core.Set#SET_ZONE Set of retreat zones.
function BRIGADE:GetRetreatZones()
return self.retreatZones
end
--- Add a rearming zone.
-- @param #BRIGADE self
-- @param Core.Zone#ZONE RearmingZone Rearming zone.
-- @return #BRIGADE.SupplyZone The rearming zone data.
function BRIGADE:AddRearmingZone(RearmingZone)
local rearmingzone={} --#BRIGADE.SupplyZone
rearmingzone.zone=RearmingZone
rearmingzone.mission=nil
rearmingzone.marker=MARKER:New(rearmingzone.zone:GetCoordinate(), "Rearming Zone"):ToCoalition(self:GetCoalition())
table.insert(self.rearmingZones, rearmingzone)
return rearmingzone
end
--- Add a refuelling zone.
-- @param #BRIGADE self
-- @param Core.Zone#ZONE RefuellingZone Refuelling zone.
-- @return #BRIGADE.SupplyZone The refuelling zone data.
function BRIGADE:AddRefuellingZone(RefuellingZone)
local supplyzone={} --#BRIGADE.SupplyZone
supplyzone.zone=RefuellingZone
supplyzone.mission=nil
supplyzone.marker=MARKER:New(supplyzone.zone:GetCoordinate(), "Refuelling Zone"):ToCoalition(self:GetCoalition())
table.insert(self.refuellingZones, supplyzone)
return supplyzone
end
--- Get platoon by name.
-- @param #BRIGADE self
-- @param #string PlatoonName Name of the platoon.
-- @return Ops.Platoon#PLATOON The Platoon object.
function BRIGADE:GetPlatoon(PlatoonName)
local platoon=self:_GetCohort(PlatoonName)
return platoon
end
--- Get platoon of an asset.
-- @param #BRIGADE self
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The platoon asset.
-- @return Ops.Platoon#PLATOON The platoon object.
function BRIGADE:GetPlatoonOfAsset(Asset)
local platoon=self:GetPlatoon(Asset.squadname)
return platoon
end
--- Remove asset from platoon.
-- @param #BRIGADE self
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The platoon asset.
function BRIGADE:RemoveAssetFromPlatoon(Asset)
local platoon=self:GetPlatoonOfAsset(Asset)
if platoon then
platoon:DelAsset(Asset)
end
end
--- [ GROUND ] Function to load back an asset in the field that has been filed before.
-- @param #BRIGADE self
-- @param #string Templatename e.g."1 PzDv LogRg I\_AID-976" - that's the alias (name) of an platoon spawned as `"platoon - alias"_AID-"asset-ID"`
-- @param Core.Point#COORDINATE Position where to spawn the platoon
-- @return #BRIGADE self
-- @usage
-- Prerequisites:
-- Save the assets spawned by BRIGADE/CHIEF regularly (~every 5 mins) into a file, e.g. like this:
--
-- local Path = FilePath or "C:\\Users\\<yourname>\\Saved Games\\DCS\\Missions\\" -- example path
-- local BlueOpsFilename = BlueFileName or "ExamplePlatoonSave.csv" -- example filename
-- local BlueSaveOps = SET_OPSGROUP:New():FilterCoalitions("blue"):FilterCategoryGround():FilterOnce()
-- UTILS.SaveSetOfOpsGroups(BlueSaveOps,Path,BlueOpsFilename)
--
-- where Path and Filename are strings, as chosen by you.
-- You can then load back the assets at the start of your next mission run. Be aware that it takes a couple of seconds for the
-- platoon data to arrive in brigade, so make this an action after ~20 seconds, e.g. like so:
--
-- function LoadBackAssets()
-- local Path = FilePath or "C:\\Users\\<yourname>\\Saved Games\\DCS\\Missions\\" -- example path
-- local BlueOpsFilename = BlueFileName or "ExamplePlatoonSave.csv" -- example filename
-- if UTILS.CheckFileExists(Path,BlueOpsFilename) then
-- local loadback = UTILS.LoadSetOfOpsGroups(Path,BlueOpsFilename,false)
-- for _,_platoondata in pairs (loadback) do
-- local groupname = _platoondata.groupname -- #string
-- local coordinate = _platoondata.coordinate -- Core.Point#COORDINATE
-- Your_Brigade:LoadBackAssetInPosition(groupname,coordinate)
-- end
-- end
-- end
--
-- local AssetLoader = TIMER:New(LoadBackAssets)
-- AssetLoader:Start(20)
--
-- The assets loaded back into the mission will be considered for AUFTRAG type missions from CHIEF and BRIGADE.
function BRIGADE:LoadBackAssetInPosition(Templatename,Position)
self:T(self.lid .. "LoadBackAssetInPosition: " .. tostring(Templatename))
-- get Platoon alias from Templatename
local nametbl = UTILS.Split(Templatename,"_")
local name = nametbl[1]
self:T(string.format("*** Target Platoon = %s ***",name))
-- find a matching asset table from BRIGADE
local cohorts = self.cohorts or {}
local thisasset = nil --Functional.Warehouse#WAREHOUSE.Assetitem
local found = false
for _,_cohort in pairs(cohorts) do
local asset = _cohort:GetName()
self:T(string.format("*** Looking at Platoon = %s ***",asset))
if asset == name then
self:T("**** Found Platoon ****")
local cohassets = _cohort.assets or {}
for _,_zug in pairs (cohassets) do
local zug = _zug -- Functional.Warehouse#WAREHOUSE.Assetitem
if zug.assignment == name and zug.requested == false then
self:T("**** Found Asset ****")
found = true
thisasset = zug --Functional.Warehouse#WAREHOUSE.Assetitem
break
end
end
end
end
if found then
-- prep asset
thisasset.rid = thisasset.uid
thisasset.requested = false
thisasset.score=100
thisasset.missionTask="CAS"
thisasset.spawned = true
local template = thisasset.templatename
local alias = thisasset.spawngroupname
-- Spawn group
local spawnasset = SPAWN:NewWithAlias(template,alias)
:InitDelayOff()
:SpawnFromCoordinate(Position)
-- build a new self request
local request = {} --Functional.Warehouse#WAREHOUSE.Pendingitem
request.assignment = name
request.warehouse = self
request.assets = {thisasset}
request.ntransporthome = 0
request.ndelivered = 0
request.ntransport = 0
request.cargoattribute = thisasset.attribute
request.category = thisasset.category
request.cargoassets = {thisasset}
request.assetdesc = WAREHOUSE.Descriptor.ASSETLIST
request.cargocategory = thisasset.category
request.toself = true
request.transporttype = WAREHOUSE.TransportType.SELFPROPELLED
request.assetproblem = {}
request.born = true
request.prio = 50
request.uid = thisasset.uid
request.airbase = nil
request.timestamp = timer.getAbsTime()
request.assetdescval = {thisasset}
request.nasset = 1
request.cargogroupset = SET_GROUP:New()
request.cargogroupset:AddGroup(spawnasset)
request.iscargo = true
-- Call Brigade self
self:__AssetSpawned(2, spawnasset, thisasset, request)
end
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- FSM Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Start BRIGADE FSM.
-- @param #BRIGADE self
function BRIGADE:onafterStart(From, Event, To)
-- Start parent Warehouse.
self:GetParent(self, BRIGADE).onafterStart(self, From, Event, To)
-- Info.
self:I(self.lid..string.format("Starting BRIGADE v%s", BRIGADE.version))
end
--- Update status.
-- @param #BRIGADE self
function BRIGADE:onafterStatus(From, Event, To)
-- Status of parent Warehouse.
self:GetParent(self).onafterStatus(self, From, Event, To)
-- FSM state.
local fsmstate=self:GetState()
----------------
-- Transport ---
----------------
self:CheckTransportQueue()
--------------
-- Mission ---
--------------
-- Check if any missions should be cancelled.
self:CheckMissionQueue()
---------------------
-- Rearming Zones ---
---------------------
for _,_rearmingzone in pairs(self.rearmingZones) do
local rearmingzone=_rearmingzone --#BRIGADE.SupplyZone
if (not rearmingzone.mission) or rearmingzone.mission:IsOver() then
rearmingzone.mission=AUFTRAG:NewAMMOSUPPLY(rearmingzone.zone)
self:AddMission(rearmingzone.mission)
end
end
-----------------------
-- Refuelling Zones ---
-----------------------
-- Check refuelling zones.
for _,_supplyzone in pairs(self.refuellingZones) do
local supplyzone=_supplyzone --#BRIGADE.SupplyZone
-- Check if mission is nil or over.
if (not supplyzone.mission) or supplyzone.mission:IsOver() then
supplyzone.mission=AUFTRAG:NewFUELSUPPLY(supplyzone.zone)
self:AddMission(supplyzone.mission)
end
end
-----------
-- Info ---
-----------
-- Display tactival overview.
self:_TacticalOverview()
-- General info:
if self.verbose>=1 then
-- Count missions not over yet.
local Nmissions=self:CountMissionsInQueue()
-- Asset count.
local Npq, Np, Nq=self:CountAssetsOnMission()
-- Asset string.
local assets=string.format("%d [OnMission: Total=%d, Active=%d, Queued=%d]", self:CountAssets(), Npq, Np, Nq)
-- Output.
local text=string.format("%s: Missions=%d, Platoons=%d, Assets=%s", fsmstate, Nmissions, #self.cohorts, assets)
self:I(self.lid..text)
end
------------------
-- Mission Info --
------------------
if self.verbose>=2 then
local text=string.format("Missions Total=%d:", #self.missionqueue)
for i,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
local prio=string.format("%d/%s", mission.prio, tostring(mission.importance)) ; if mission.urgent then prio=prio.." (!)" end
local assets=string.format("%d/%d", mission:CountOpsGroups(), mission.Nassets or 0)
local target=string.format("%d/%d Damage=%.1f", mission:CountMissionTargets(), mission:GetTargetInitialNumber(), mission:GetTargetDamage())
text=text..string.format("\n[%d] %s %s: Status=%s, Prio=%s, Assets=%s, Targets=%s", i, mission.name, mission.type, mission.status, prio, assets, target)
end
self:I(self.lid..text)
end
--------------------
-- Transport Info --
--------------------
if self.verbose>=2 then
local text=string.format("Transports Total=%d:", #self.transportqueue)
for i,_transport in pairs(self.transportqueue) do
local transport=_transport --Ops.OpsTransport#OPSTRANSPORT
local prio=string.format("%d/%s", transport.prio, tostring(transport.importance)) ; if transport.urgent then prio=prio.." (!)" end
local carriers=string.format("Ncargo=%d/%d, Ncarriers=%d", transport.Ncargo, transport.Ndelivered, transport.Ncarrier)
text=text..string.format("\n[%d] UID=%d: Status=%s, Prio=%s, Cargo: %s", i, transport.uid, transport:GetState(), prio, carriers)
end
self:I(self.lid..text)
end
-------------------
-- Platoon Info --
-------------------
if self.verbose>=3 then
local text="Platoons:"
for i,_platoon in pairs(self.cohorts) do
local platoon=_platoon --Ops.Platoon#PLATOON
local callsign=platoon.callsignName and UTILS.GetCallsignName(platoon.callsignName) or "N/A"
local modex=platoon.modex and platoon.modex or -1
local skill=platoon.skill and tostring(platoon.skill) or "N/A"
-- Platoon text.
text=text..string.format("\n* %s %s: %s*%d/%d, Callsign=%s, Modex=%d, Skill=%s", platoon.name, platoon:GetState(), platoon.aircrafttype, platoon:CountAssets(true), #platoon.assets, callsign, modex, skill)
end
self:I(self.lid..text)
end
-------------------
-- Rearming Info --
-------------------
if self.verbose>=4 then
local text="Rearming Zones:"
for i,_rearmingzone in pairs(self.rearmingZones) do
local rearmingzone=_rearmingzone --#BRIGADE.SupplyZone
-- Info text.
text=text..string.format("\n* %s: Mission status=%s, suppliers=%d", rearmingzone.zone:GetName(), rearmingzone.mission:GetState(), rearmingzone.mission:CountOpsGroups())
end
self:I(self.lid..text)
end
---------------------
-- Refuelling Info --
---------------------
if self.verbose>=4 then
local text="Refuelling Zones:"
for i,_refuellingzone in pairs(self.refuellingZones) do
local refuellingzone=_refuellingzone --#BRIGADE.SupplyZone
-- Info text.
text=text..string.format("\n* %s: Mission status=%s, suppliers=%d", refuellingzone.zone:GetName(), refuellingzone.mission:GetState(), refuellingzone.mission:CountOpsGroups())
end
self:I(self.lid..text)
end
----------------
-- Asset Info --
----------------
if self.verbose>=5 then
local text="Assets in stock:"
for i,_asset in pairs(self.stock) do
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
-- Info text.
text=text..string.format("\n* %s: spawned=%s", asset.spawngroupname, tostring(asset.spawned))
end
self:I(self.lid..text)
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- FSM Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- On after "ArmyOnMission".
-- @param #BRIGADE self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Ops.ArmyGroup#ARMYGROUP ArmyGroup Ops army group on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The requested mission.
function BRIGADE:onafterArmyOnMission(From, Event, To, ArmyGroup, Mission)
-- Debug info.
self:T(self.lid..string.format("Group %s on %s mission %s", ArmyGroup:GetName(), Mission:GetType(), Mission:GetName()))
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@@ -31,7 +31,7 @@
-- @image OPS_CSAR.jpg
---
-- Last Update July 2024
-- Last Update Sep 2024
-------------------------------------------------------------------------
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
@@ -41,6 +41,7 @@
-- @field #string lid Class id string for output to DCS log file.
-- @field #number coalition Coalition side number, e.g. `coalition.side.RED`.
-- @field Core.Set#SET_GROUP allheligroupset Set of CSAR heli groups.
-- @field Core.Set#SET_GROUP UserSetGroup Set of CSAR heli groups as designed by the mission designer (if any set).
-- @extends Core.Fsm#FSM
--- *Combat search and rescue (CSAR) are search and rescue operations that are carried out during war that are within or near combat zones.* (Wikipedia)
@@ -116,8 +117,17 @@
-- mycsar.topmenuname = "CSAR" -- set the menu entry name
-- mycsar.ADFRadioPwr = 1000 -- ADF Beacons sending with 1KW as default
-- mycsar.PilotWeight = 80 -- Loaded pilots weigh 80kgs each
-- mycsar.AllowIRStrobe = false -- Allow a menu item to request an IR strobe to find a downed pilot at night (requires NVGs to see it).
-- mycsar.IRStrobeRuntime = 300 -- If an IR Strobe is activated, it runs for 300 seconds (5 mins).
--
-- ## 2.1 Create own SET_GROUP to manage CTLD Pilot groups
--
-- -- Parameter: Set The SET_GROUP object created by the mission designer/user to represent the CSAR pilot groups.
-- -- Needs to be set before starting the CSAR instance.
-- local myset = SET_GROUP:New():FilterPrefixes("Helikopter"):FilterCoalitions("red"):FilterStart()
-- mycsar:SetOwnSetPilotGroups(myset)
--
-- ## 2.1 SRS Features and Other Features
-- ## 2.2 SRS Features and Other Features
--
-- mycsar.useSRS = false -- Set true to use FF\'s SRS integration
-- mycsar.SRSPath = "C:\\Progra~1\\DCS-SimpleRadio-Standalone\\" -- adjust your own path in your SRS installation -- server(!)
@@ -136,6 +146,7 @@
-- mycsar.csarUsePara = false -- If set to true, will use the LandingAfterEjection Event instead of Ejection. Requires mycsar.enableForAI to be set to true. --shagrat
-- mycsar.wetfeettemplate = "man in floating thingy" -- if you use a mod to have a pilot in a rescue float, put the template name in here for wet feet spawns. Note: in conjunction with csarUsePara this might create dual ejected pilots in edge cases.
-- mycsar.allowbronco = false -- set to true to use the Bronco mod as a CSAR plane
-- mycsar.CreateRadioBeacons = true -- set to false to disallow creating ADF radio beacons.
--
-- ## 3. Results
--
@@ -256,6 +267,10 @@ CSAR = {
topmenuname = "CSAR",
ADFRadioPwr = 1000,
PilotWeight = 80,
CreateRadioBeacons = true,
UserSetGroup = nil,
AllowIRStrobe = false,
IRStrobeRuntime = 300,
}
--- Downed pilots info.
@@ -272,6 +287,7 @@ CSAR = {
-- @field #number timestamp Timestamp for approach process.
-- @field #boolean alive Group is alive or dead/rescued.
-- @field #boolean wetfeet Group is spawned over (deep) water.
-- @field #string BeaconName Name of radio beacon - if any.
--- All slot / Limit settings
-- @type CSAR.AircraftType
@@ -292,12 +308,12 @@ CSAR.AircraftType["AH-64D_BLK_II"] = 2
CSAR.AircraftType["Bronco-OV-10A"] = 2
CSAR.AircraftType["MH-60R"] = 10
CSAR.AircraftType["OH-6A"] = 2
CSAR.AircraftType["OH-58D"] = 2
CSAR.AircraftType["OH58D"] = 2
CSAR.AircraftType["CH-47Fbl1"] = 31
--- CSAR class version.
-- @field #string version
CSAR.version="1.0.26"
CSAR.version="1.0.29"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
@@ -456,6 +472,9 @@ function CSAR:New(Coalition, Template, Alias)
-- added 1.0.16
self.PilotWeight = 80
-- Own SET_GROUP if any
self.UserSetGroup = nil
-- WARNING - here\'ll be dragons
-- for this to work you need to de-sanitize your mission environment in <DCS root>\Scripts\MissionScripting.lua
@@ -634,7 +653,7 @@ end
-- @param #string Playername Name of Player (if applicable)
-- @param #boolean Wetfeet Ejected over water
-- @return #CSAR self.
function CSAR:_CreateDownedPilotTrack(Group,Groupname,Side,OriginalUnit,Description,Typename,Frequency,Playername,Wetfeet)
function CSAR:_CreateDownedPilotTrack(Group,Groupname,Side,OriginalUnit,Description,Typename,Frequency,Playername,Wetfeet,BeaconName)
self:T({"_CreateDownedPilotTrack",Groupname,Side,OriginalUnit,Description,Typename,Frequency,Playername})
-- create new entry
@@ -642,7 +661,7 @@ function CSAR:_CreateDownedPilotTrack(Group,Groupname,Side,OriginalUnit,Descript
DownedPilot.desc = Description or ""
DownedPilot.frequency = Frequency or 0
DownedPilot.index = self.downedpilotcounter
DownedPilot.name = Groupname or ""
DownedPilot.name = Groupname or Playername or ""
DownedPilot.originalUnit = OriginalUnit or ""
DownedPilot.player = Playername or ""
DownedPilot.side = Side or 0
@@ -651,6 +670,7 @@ function CSAR:_CreateDownedPilotTrack(Group,Groupname,Side,OriginalUnit,Descript
DownedPilot.timestamp = 0
DownedPilot.alive = true
DownedPilot.wetfeet = Wetfeet or false
DownedPilot.BeaconName = BeaconName
-- Add Pilot
local PilotTable = self.downedPilots
@@ -737,7 +757,6 @@ function CSAR:_SpawnPilotInField(country,point,frequency,wetfeet)
:NewWithAlias(template,alias)
:InitCoalition(coalition)
:InitCountry(country)
--:InitAIOnOff(pilotcacontrol)
:InitDelayOff()
:SpawnFromCoordinate(point)
@@ -819,8 +838,18 @@ function CSAR:_AddCsar(_coalition , _country, _point, _typeName, _unitName, _pla
end
end
local BeaconName
if _playerName then
BeaconName = _playerName..math.random(1,10000)
elseif _unitName then
BeaconName = _unitName..math.random(1,10000)
else
BeaconName = "Ghost-1-1"..math.random(1,10000)
end
if (_freq and _freq ~= 0) then --shagrat only add beacon if _freq is NOT 0
self:_AddBeaconToGroup(_spawnedGroup, _freq)
self:_AddBeaconToGroup(_spawnedGroup, _freq, BeaconName)
end
self:_AddSpecialOptions(_spawnedGroup)
@@ -845,7 +874,7 @@ function CSAR:_AddCsar(_coalition , _country, _point, _typeName, _unitName, _pla
local _GroupName = _spawnedGroup:GetName() or _alias
self:_CreateDownedPilotTrack(_spawnedGroup,_GroupName,_coalition,_unitName,_text,_typeName,_freq,_playerName,wetfeet)
self:_CreateDownedPilotTrack(_spawnedGroup,_GroupName,_coalition,_unitName,_text,_typeName,_freq,_playerName,wetfeet,BeaconName)
self:_InitSARForPilot(_spawnedGroup, _unitName, _freq, noMessage, _playerName) --shagrat use unitName to have the aircraft callsign / descriptive "name" etc.
@@ -963,7 +992,6 @@ end
-- @param Core.Point#COORDINATE Point
-- @param #number Coalition Coalition.
-- @param #string Description (optional) Description.
-- @param #boolean addBeacon (optional) yes or no.
-- @param #boolean Nomessage (optional) If true, don\'t send a message to SAR.
-- @param #string Unitname (optional) Name of the lost unit.
-- @param #string Typename (optional) Type of plane.
@@ -1793,9 +1821,6 @@ function CSAR:_DisplayMessageToSAR(_unit, _text, _time, _clear, _speak, _overrid
end
_text = string.gsub(_text,"km"," kilometer")
_text = string.gsub(_text,"nm"," nautical miles")
--self.msrs:SetVoice(self.SRSVoice)
--self.SRSQueue:NewTransmission(_text,nil,self.msrs,nil,1)
--self:I("Voice = "..self.SRSVoice)
self.SRSQueue:NewTransmission(_text,duration,self.msrs,tstart,2,subgroups,subtitle,subduration,self.SRSchannel,self.SRSModulation,gender,culture,self.SRSVoice,volume,label,coord)
end
return self
@@ -1856,11 +1881,11 @@ function CSAR:_DisplayActiveSAR(_unitName)
else
distancetext = string.format("%.1fkm", _distance/1000.0)
end
if _value.frequency == 0 then--shagrat insert CASEVAC without Frequency
table.insert(_csarList, { dist = _distance, msg = string.format("%s at %s - %s ", _value.desc, _coordinatesText, distancetext) })
else
table.insert(_csarList, { dist = _distance, msg = string.format("%s at %s - %.2f KHz ADF - %s ", _value.desc, _coordinatesText, _value.frequency / 1000, distancetext) })
end
if _value.frequency == 0 or self.CreateRadioBeacons == false then--shagrat insert CASEVAC without Frequency
table.insert(_csarList, { dist = _distance, msg = string.format("%s at %s - %s ", _value.desc, _coordinatesText, distancetext) })
else
table.insert(_csarList, { dist = _distance, msg = string.format("%s at %s - %.2f KHz ADF - %s ", _value.desc, _coordinatesText, _value.frequency / 1000, distancetext) })
end
end
end
@@ -1941,7 +1966,7 @@ function CSAR:_SignalFlare(_unitName)
else
_distance = string.format("%.1fkm",_closest.distance/1000)
end
local _msg = string.format("%s - Popping signal flare at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance)
local _msg = string.format("%s - Firing signal flare at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance)
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
local _coord = _closest.pilot:GetCoordinate()
@@ -1975,7 +2000,7 @@ function CSAR:_DisplayToAllSAR(_message, _side, _messagetime,ToSRS,ToScreen)
if self.msrs:GetProvider() == MSRS.Provider.WINDOWS then
voice = self.CSARVoiceMS or MSRS.Voices.Microsoft.Hedda
end
self:F("Voice = "..voice)
--self:F("Voice = "..voice)
self.SRSQueue:NewTransmission(_message,duration,self.msrs,tstart,2,subgroups,subtitle,subduration,self.SRSchannel,self.SRSModulation,gender,culture,voice,volume,label,self.coordinate)
end
if ToScreen == true or ToScreen == nil then
@@ -1989,6 +2014,41 @@ function CSAR:_DisplayToAllSAR(_message, _side, _messagetime,ToSRS,ToScreen)
return self
end
---(Internal) Request IR Strobe at closest downed pilot.
--@param #CSAR self
--@param #string _unitName Name of the helicopter
function CSAR:_ReqIRStrobe( _unitName )
self:T(self.lid .. " _ReqIRStrobe")
local _heli = self:_GetSARHeli(_unitName)
if _heli == nil then
return
end
local smokedist = 8000
if smokedist < self.approachdist_far then smokedist = self.approachdist_far end
local _closest = self:_GetClosestDownedPilot(_heli)
if _closest ~= nil and _closest.pilot ~= nil and _closest.distance > 0 and _closest.distance < smokedist then
local _clockDir = self:_GetClockDirection(_heli, _closest.pilot)
local _distance = string.format("%.1fkm",_closest.distance/1000)
if _SETTINGS:IsImperial() then
_distance = string.format("%.1fnm",UTILS.MetersToNM(_closest.distance))
else
_distance = string.format("%.1fkm",_closest.distance/1000)
end
local _msg = string.format("%s - IR Strobe active at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance)
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
_closest.pilot:NewIRMarker(true,self.IRStrobeRuntime or 300)
else
local _distance = string.format("%.1fkm",smokedist/1000)
if _SETTINGS:IsImperial() then
_distance = string.format("%.1fnm",UTILS.MetersToNM(smokedist))
else
_distance = string.format("%.1fkm",smokedist/1000)
end
self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",_distance), self.messageTime, false, false, true)
end
return self
end
---(Internal) Request smoke at closest downed pilot.
--@param #CSAR self
--@param #string _unitName Name of the helicopter
@@ -2140,7 +2200,12 @@ function CSAR:_AddMedevacMenuItem()
local _rootMenu1 = MENU_GROUP_COMMAND:New(_group,"List Active CSAR",_rootPath, self._DisplayActiveSAR,self,_unitName)
local _rootMenu2 = MENU_GROUP_COMMAND:New(_group,"Check Onboard",_rootPath, self._CheckOnboard,self,_unitName)
local _rootMenu3 = MENU_GROUP_COMMAND:New(_group,"Request Signal Flare",_rootPath, self._SignalFlare,self,_unitName)
local _rootMenu4 = MENU_GROUP_COMMAND:New(_group,"Request Smoke",_rootPath, self._Reqsmoke,self,_unitName):Refresh()
local _rootMenu4 = MENU_GROUP_COMMAND:New(_group,"Request Smoke",_rootPath, self._Reqsmoke,self,_unitName)
if self.AllowIRStrobe then
local _rootMenu5 = MENU_GROUP_COMMAND:New(_group,"Request IR Strobe",_rootPath, self._ReqIRStrobe,self,_unitName):Refresh()
else
_rootMenu4:Refresh()
end
end
end
end
@@ -2231,9 +2296,13 @@ end
-- @param #CSAR self
-- @param Wrapper.Group#GROUP _group Group #GROUP object.
-- @param #number _freq Frequency to use
function CSAR:_AddBeaconToGroup(_group, _freq)
-- @param #string _name Beacon Name to use
-- @return #CSAR self
function CSAR:_AddBeaconToGroup(_group, _freq, _name)
self:T(self.lid .. " _AddBeaconToGroup")
if self.CreateRadioBeacons == false then return end
local _group = _group
if _group == nil then
--return frequency to pool of available
for _i, _current in ipairs(self.UsedVHFFrequencies) do
@@ -2248,22 +2317,24 @@ function CSAR:_AddBeaconToGroup(_group, _freq)
if _group:IsAlive() then
local _radioUnit = _group:GetUnit(1)
if _radioUnit then
local name = _radioUnit:GetName()
local name = _radioUnit:GetName()
local Frequency = _freq -- Freq in Hertz
local name = _radioUnit:GetName()
local Sound = "l10n/DEFAULT/"..self.radioSound
local vec3 = _radioUnit:GetVec3() or _radioUnit:GetPositionVec3() or {x=0,y=0,z=0}
trigger.action.radioTransmission(Sound, vec3, 0, false, Frequency, self.ADFRadioPwr or 1000,name..math.random(1,10000)) -- Beacon in MP only runs for exactly 30secs straight
trigger.action.radioTransmission(Sound, vec3, 0, false, Frequency, self.ADFRadioPwr or 1000,_name) -- Beacon in MP only runs for exactly 30secs straight
end
end
return self
end
--- (Internal) Helper function to (re-)add beacon to downed pilot.
-- @param #CSAR self
-- @param #table _args Arguments
-- @return #CSAR self
function CSAR:_RefreshRadioBeacons()
self:T(self.lid .. " _RefreshRadioBeacons")
if self.CreateRadioBeacons == false then return end
if self:_CountActiveDownedPilots() > 0 then
local PilotTable = self.downedPilots
for _,_pilot in pairs (PilotTable) do
@@ -2271,8 +2342,10 @@ function CSAR:_RefreshRadioBeacons()
local pilot = _pilot -- #CSAR.DownedPilot
local group = pilot.group
local frequency = pilot.frequency or 0 -- thanks to @Thrud
local bname = pilot.BeaconName or pilot.name..math.random(1,100000)
trigger.action.stopRadioTransmission(bname)
if group and group:IsAlive() and frequency > 0 then
self:_AddBeaconToGroup(group,frequency)
self:_AddBeaconToGroup(group,frequency,bname)
end
end
end
@@ -2309,6 +2382,16 @@ function CSAR:_ReachedPilotLimit()
end
end
--- User - Function to add onw SET_GROUP Set-up for pilot filtering and assignment.
-- Needs to be set before starting the CSAR instance.
-- @param #CSAR self
-- @param Core.Set#SET_GROUP Set The SET_GROUP object created by the mission designer/user to represent the CSAR pilot groups.
-- @return #CSAR self
function CSAR:SetOwnSetPilotGroups(Set)
self.UserSetGroup = Set
return self
end
------------------------------
--- FSM internal Functions ---
------------------------------
@@ -2330,7 +2413,9 @@ function CSAR:onafterStart(From, Event, To)
self:HandleEvent(EVENTS.PlayerEnterUnit, self._EventHandler)
self:HandleEvent(EVENTS.PilotDead, self._EventHandler)
if self.allowbronco then
if self.UserSetGroup then
self.allheligroupset = self.UserSetGroup
elseif self.allowbronco then
local prefixes = self.csarPrefix or {}
self.allheligroupset = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(prefixes):FilterStart()
elseif self.useprefix then
@@ -2339,7 +2424,9 @@ function CSAR:onafterStart(From, Event, To)
else
self.allheligroupset = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterCategoryHelicopter():FilterStart()
end
self.mash = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart() -- currently only GROUP objects, maybe support STATICs also?
if not self.coordinate then
local csarhq = self.mash:GetRandom()
if csarhq then

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,428 +0,0 @@
--- **Ops** - Fleet Warehouse.
--
-- **Main Features:**
--
-- * Manage flotillas
-- * Carry out ARTY and PATROLZONE missions (AUFTRAG)
--
-- ===
--
-- ## Example Missions:
--
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Ops/Fleet).
--
-- ===
--
-- ### Author: **funkyfranky**
--
-- ===
-- @module Ops.Fleet
-- @image OPS_Fleet.png
--- FLEET class.
-- @type FLEET
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity of output.
-- @field Core.Set#SET_ZONE retreatZones Retreat zone set.
-- @field #boolean pathfinding Set pathfinding on for all spawned navy groups.
-- @extends Ops.Legion#LEGION
--- *A fleet of British ships at war are the best negotiators.* -- Horatio Nelson
--
-- ===
--
-- # The FLEET Concept
--
-- A FLEET consists of one or multiple FLOTILLAs. These flotillas "live" in a WAREHOUSE that has a phyiscal struction (STATIC or UNIT) and can be captured or destroyed.
--
-- # Basic Setup
--
-- A new `FLEET` object can be created with the @{#FLEET.New}(`WarehouseName`, `FleetName`) function, where `WarehouseName` is the name of the static or unit object hosting the fleet
-- and `FleetName` is the name you want to give the fleet. This must be *unique*!
--
-- myFleet=FLEET:New("myWarehouseName", "1st Fleet")
-- myFleet:SetPortZone(ZonePort1stFleet)
-- myFleet:Start()
--
-- A fleet needs a *port zone*, which is set via the @{#FLEET.SetPortZone}(`PortZone`) function. This is the zone where the naval assets are spawned and return to.
--
-- Finally, the fleet needs to be started using the @{#FLEET.Start}() function. If the fleet is not started, it will not process any requests.
--
-- ## Adding Flotillas
--
-- Flotillas can be added via the @{#FLEET.AddFlotilla}(`Flotilla`) function. See @{Ops.Flotilla#FLOTILLA} for how to create a flotilla.
--
-- myFleet:AddFlotilla(FlotillaTiconderoga)
-- myFleet:AddFlotilla(FlotillaPerry)
--
--
--
-- @field #FLEET
FLEET = {
ClassName = "FLEET",
verbose = 0,
pathfinding = false,
}
--- Supply Zone.
-- @type FLEET.SupplyZone
-- @field Core.Zone#ZONE zone The zone.
-- @field Ops.Auftrag#AUFTRAG mission Mission assigned to supply ammo or fuel.
-- @field #boolean markerOn If `true`, marker is on.
-- @field Wrapper.Marker#MARKER marker F10 marker.
--- FLEET class version.
-- @field #string version
FLEET.version="0.0.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Add routes?
-- DONE: Add weapon range.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new FLEET class object.
-- @param #FLEET self
-- @param #string WarehouseName Name of the warehouse STATIC or UNIT object representing the warehouse.
-- @param #string FleetName Name of the fleet.
-- @return #FLEET self
function FLEET:New(WarehouseName, FleetName)
-- Inherit everything from LEGION class.
local self=BASE:Inherit(self, LEGION:New(WarehouseName, FleetName)) -- #FLEET
-- Nil check.
if not self then
BASE:E(string.format("ERROR: Could not find warehouse %s!", WarehouseName))
return nil
end
-- Set some string id for output to DCS.log file.
self.lid=string.format("FLEET %s | ", self.alias)
-- Defaults
self:SetRetreatZones()
-- Turn ship into NAVYGROUP.
if self:IsShip() then
local wh=self.warehouse --Wrapper.Unit#UNIT
local group=wh:GetGroup()
self.warehouseOpsGroup=NAVYGROUP:New(group) --Ops.NavyGroup#NAVYGROUP
self.warehouseOpsElement=self.warehouseOpsGroup:GetElementByName(wh:GetName())
end
-- Add FSM transitions.
-- From State --> Event --> To State
self:AddTransition("*", "NavyOnMission", "*") -- An NAVYGROUP was send on a Mission (AUFTRAG).
------------------------
--- Pseudo Functions ---
------------------------
--- Triggers the FSM event "Start". Starts the FLEET. Initializes parameters and starts event handlers.
-- @function [parent=#FLEET] Start
-- @param #FLEET self
--- Triggers the FSM event "Start" after a delay. Starts the FLEET. Initializes parameters and starts event handlers.
-- @function [parent=#FLEET] __Start
-- @param #FLEET self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "Stop". Stops the FLEET and all its event handlers.
-- @param #FLEET self
--- Triggers the FSM event "Stop" after a delay. Stops the FLEET and all its event handlers.
-- @function [parent=#FLEET] __Stop
-- @param #FLEET self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "NavyOnMission".
-- @function [parent=#FLEET] NavyOnMission
-- @param #FLEET self
-- @param Ops.NavyGroup#NAVYGROUP ArmyGroup The NAVYGROUP on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
--- Triggers the FSM event "NavyOnMission" after a delay.
-- @function [parent=#FLEET] __NavyOnMission
-- @param #FLEET self
-- @param #number delay Delay in seconds.
-- @param Ops.NavyGroup#NAVYGROUP ArmyGroup The NAVYGROUP on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
--- On after "NavyOnMission" event.
-- @function [parent=#FLEET] OnAfterNavyOnMission
-- @param #FLEET self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Ops.NavyGroup#NAVYGROUP NavyGroup The NAVYGROUP on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Add a flotilla to the fleet.
-- @param #FLEET self
-- @param Ops.Flotilla#FLOTILLA Flotilla The flotilla object.
-- @return #FLEET self
function FLEET:AddFlotilla(Flotilla)
-- Add flotilla to fleet.
table.insert(self.cohorts, Flotilla)
-- Add assets to flotilla.
self:AddAssetToFlotilla(Flotilla, Flotilla.Ngroups)
-- Set fleet of flotilla.
Flotilla:SetFleet(self)
-- Start flotilla.
if Flotilla:IsStopped() then
Flotilla:Start()
end
return self
end
--- Add asset group(s) to flotilla.
-- @param #FLEET self
-- @param Ops.Flotilla#FLOTILLA Flotilla The flotilla object.
-- @param #number Nassets Number of asset groups to add.
-- @return #FLEET self
function FLEET:AddAssetToFlotilla(Flotilla, Nassets)
if Flotilla then
-- Get the template group of the flotilla.
local Group=GROUP:FindByName(Flotilla.templatename)
if Group then
-- Debug text.
local text=string.format("Adding asset %s to flotilla %s", Group:GetName(), Flotilla.name)
self:T(self.lid..text)
-- Add assets to airwing warehouse.
self:AddAsset(Group, Nassets, nil, nil, nil, nil, Flotilla.skill, Flotilla.livery, Flotilla.name)
else
self:E(self.lid.."ERROR: Group does not exist!")
end
else
self:E(self.lid.."ERROR: Flotilla does not exit!")
end
return self
end
--- Set pathfinding for all spawned naval groups.
-- @param #FLEET self
-- @param #boolean Switch If `true`, pathfinding is used.
-- @return #FLEET self
function FLEET:SetPathfinding(Switch)
self.pathfinding=Switch
return self
end
--- Define a set of retreat zones.
-- @param #FLEET self
-- @param Core.Set#SET_ZONE RetreatZoneSet Set of retreat zones.
-- @return #FLEET self
function FLEET:SetRetreatZones(RetreatZoneSet)
self.retreatZones=RetreatZoneSet or SET_ZONE:New()
return self
end
--- Add a retreat zone.
-- @param #FLEET self
-- @param Core.Zone#ZONE RetreatZone Retreat zone.
-- @return #FLEET self
function FLEET:AddRetreatZone(RetreatZone)
self.retreatZones:AddZone(RetreatZone)
return self
end
--- Get retreat zones.
-- @param #FLEET self
-- @return Core.Set#SET_ZONE Set of retreat zones.
function FLEET:GetRetreatZones()
return self.retreatZones
end
--- Get flotilla by name.
-- @param #FLEET self
-- @param #string FlotillaName Name of the flotilla.
-- @return Ops.Flotilla#FLOTILLA The Flotilla object.
function FLEET:GetFlotilla(FlotillaName)
local flotilla=self:_GetCohort(FlotillaName)
return flotilla
end
--- Get flotilla of an asset.
-- @param #FLEET self
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The flotilla asset.
-- @return Ops.Flotilla#FLOTILLA The flotilla object.
function FLEET:GetFlotillaOfAsset(Asset)
local flotilla=self:GetFlotilla(Asset.squadname)
return flotilla
end
--- Remove asset from flotilla.
-- @param #FLEET self
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The flotilla asset.
function FLEET:RemoveAssetFromFlotilla(Asset)
local flotilla=self:GetFlotillaOfAsset(Asset)
if flotilla then
flotilla:DelAsset(Asset)
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- FSM Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Start FLEET FSM.
-- @param #FLEET self
function FLEET:onafterStart(From, Event, To)
-- Start parent Warehouse.
self:GetParent(self, FLEET).onafterStart(self, From, Event, To)
-- Info.
self:I(self.lid..string.format("Starting FLEET v%s", FLEET.version))
end
--- Update status.
-- @param #FLEET self
function FLEET:onafterStatus(From, Event, To)
-- Status of parent Warehouse.
self:GetParent(self).onafterStatus(self, From, Event, To)
-- FSM state.
local fsmstate=self:GetState()
----------------
-- Transport ---
----------------
self:CheckTransportQueue()
--------------
-- Mission ---
--------------
-- Check if any missions should be cancelled.
self:CheckMissionQueue()
-----------
-- Info ---
-----------
-- Display tactival overview.
self:_TacticalOverview()
-- General info:
if self.verbose>=1 then
-- Count missions not over yet.
local Nmissions=self:CountMissionsInQueue()
-- Asset count.
local Npq, Np, Nq=self:CountAssetsOnMission()
-- Asset string.
local assets=string.format("%d [OnMission: Total=%d, Active=%d, Queued=%d]", self:CountAssets(), Npq, Np, Nq)
-- Output.
local text=string.format("%s: Missions=%d, Flotillas=%d, Assets=%s", fsmstate, Nmissions, #self.cohorts, assets)
self:I(self.lid..text)
end
------------------
-- Mission Info --
------------------
if self.verbose>=2 then
local text=string.format("Missions Total=%d:", #self.missionqueue)
for i,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
local prio=string.format("%d/%s", mission.prio, tostring(mission.importance)) ; if mission.urgent then prio=prio.." (!)" end
local assets=string.format("%d/%d", mission:CountOpsGroups(), mission.Nassets or 0)
local target=string.format("%d/%d Damage=%.1f", mission:CountMissionTargets(), mission:GetTargetInitialNumber(), mission:GetTargetDamage())
text=text..string.format("\n[%d] %s %s: Status=%s, Prio=%s, Assets=%s, Targets=%s", i, mission.name, mission.type, mission.status, prio, assets, target)
end
self:I(self.lid..text)
end
--------------------
-- Transport Info --
--------------------
if self.verbose>=2 then
local text=string.format("Transports Total=%d:", #self.transportqueue)
for i,_transport in pairs(self.transportqueue) do
local transport=_transport --Ops.OpsTransport#OPSTRANSPORT
local prio=string.format("%d/%s", transport.prio, tostring(transport.importance)) ; if transport.urgent then prio=prio.." (!)" end
local carriers=string.format("Ncargo=%d/%d, Ncarriers=%d", transport.Ncargo, transport.Ndelivered, transport.Ncarrier)
text=text..string.format("\n[%d] UID=%d: Status=%s, Prio=%s, Cargo: %s", i, transport.uid, transport:GetState(), prio, carriers)
end
self:I(self.lid..text)
end
-------------------
-- Flotilla Info --
-------------------
if self.verbose>=3 then
local text="Flotillas:"
for i,_flotilla in pairs(self.cohorts) do
local flotilla=_flotilla --Ops.Flotilla#FLOTILLA
local callsign=flotilla.callsignName and UTILS.GetCallsignName(flotilla.callsignName) or "N/A"
local modex=flotilla.modex and flotilla.modex or -1
local skill=flotilla.skill and tostring(flotilla.skill) or "N/A"
-- Flotilla text.
text=text..string.format("\n* %s %s: %s*%d/%d, Callsign=%s, Modex=%d, Skill=%s", flotilla.name, flotilla:GetState(), flotilla.aircrafttype, flotilla:CountAssets(true), #flotilla.assets, callsign, modex, skill)
end
self:I(self.lid..text)
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- FSM Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- On after "NavyOnMission".
-- @param #FLEET self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Ops.ArmyGroup#ARMYGROUP ArmyGroup Ops army group on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The requested mission.
function FLEET:onafterNavyOnMission(From, Event, To, NavyGroup, Mission)
-- Debug info.
self:T(self.lid..string.format("Group %s on %s mission %s", NavyGroup:GetName(), Mission:GetType(), Mission:GetName()))
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,175 +0,0 @@
--- **Ops** - Flotilla is a small naval group belonging to a fleet.
--
-- **Main Features:**
--
-- * Set parameters like livery, skill valid for all flotilla members.
-- * Define mission types, this flotilla can perform (see Ops.Auftrag#AUFTRAG).
-- * Pause/unpause flotilla operations.
--
-- ===
--
-- ### Author: **funkyfranky**
--
-- ===
-- @module Ops.Flotilla
-- @image OPS_Flotilla.png
--- FLOTILLA class.
-- @type FLOTILLA
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity level.
-- @field Ops.OpsGroup#OPSGROUP.WeaponData weaponData Weapon data table with key=BitType.
-- @extends Ops.Cohort#COHORT
--- *No captain can do very wrong if he places his ship alongside that of an enemy.* -- Horation Nelson
--
-- ===
--
-- # The FLOTILLA Concept
--
-- A FLOTILLA is an essential part of a FLEET.
--
--
--
-- @field #FLOTILLA
FLOTILLA = {
ClassName = "FLOTILLA",
verbose = 0,
weaponData = {},
}
--- FLOTILLA class version.
-- @field #string version
FLOTILLA.version="0.1.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: A lot.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new FLOTILLA object and start the FSM.
-- @param #FLOTILLA self
-- @param #string TemplateGroupName Name of the template group.
-- @param #number Ngroups Number of asset groups of this flotilla. Default 3.
-- @param #string FlotillaName Name of the flotilla. Must be **unique**!
-- @return #FLOTILLA self
function FLOTILLA:New(TemplateGroupName, Ngroups, FlotillaName)
-- Inherit everything from COHORT class.
local self=BASE:Inherit(self, COHORT:New(TemplateGroupName, Ngroups, FlotillaName)) -- #FLOTILLA
-- All flotillas get mission type Nothing.
self:AddMissionCapability(AUFTRAG.Type.NOTHING, 50)
-- Is naval.
self.isNaval=true
-- Get initial ammo.
self.ammo=self:_CheckAmmo()
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Flotilla specific user functions.
--- Set fleet of this flotilla.
-- @param #FLOTILLA self
-- @param Ops.Fleet#FLEET Fleet The fleet.
-- @return #FLOTILLA self
function FLOTILLA:SetFleet(Fleet)
self.legion=Fleet
return self
end
--- Get fleet of this flotilla.
-- @param #FLOTILLA self
-- @return Ops.Fleet#FLEET The fleet.
function FLOTILLA:GetFleet()
return self.legion
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Start & Status
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- On after Start event. Starts the FLIGHTGROUP FSM and event handlers.
-- @param #FLOTILLA self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function FLOTILLA:onafterStart(From, Event, To)
-- Short info.
local text=string.format("Starting %s v%s %s", self.ClassName, self.version, self.name)
self:I(self.lid..text)
-- Start the status monitoring.
self:__Status(-1)
end
--- On after "Status" event.
-- @param #FLOTILLA self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function FLOTILLA:onafterStatus(From, Event, To)
if self.verbose>=1 then
-- FSM state.
local fsmstate=self:GetState()
local callsign=self.callsignName and UTILS.GetCallsignName(self.callsignName) or "N/A"
local skill=self.skill and tostring(self.skill) or "N/A"
local NassetsTot=#self.assets
local NassetsInS=self:CountAssets(true)
local NassetsQP=0 ; local NassetsP=0 ; local NassetsQ=0
if self.legion then
NassetsQP, NassetsP, NassetsQ=self.legion:CountAssetsOnMission(nil, self)
end
-- Short info.
local text=string.format("%s [Type=%s, Call=%s, Skill=%s]: Assets Total=%d, Stock=%d, Mission=%d [Active=%d, Queue=%d]",
fsmstate, self.aircrafttype, callsign, skill, NassetsTot, NassetsInS, NassetsQP, NassetsP, NassetsQ)
self:T(self.lid..text)
-- Weapon data info.
if self.verbose>=3 and self.weaponData then
local text="Weapon Data:"
for bit,_weapondata in pairs(self.weaponData) do
local weapondata=_weapondata --Ops.OpsGroup#OPSGROUP.WeaponData
text=text..string.format("\n- Bit=%s: Rmin=%.1f km, Rmax=%.1f km", bit, weapondata.RangeMin/1000, weapondata.RangeMax/1000)
end
self:I(self.lid..text)
end
-- Check if group has detected any units.
self:_CheckAssetStatus()
end
if not self:IsStopped() then
self:__Status(-60)
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Misc Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More