Compare commits

...

98 Commits

Author SHA1 Message Date
Applevangelist 4df1e310a3 CSAR - remove timer check for "open the door" message to make behaviour more realistic 2022-03-14 09:12:24 +01:00
TommyC81 802a77238a Range re-formatting and documentation re-fixing (#1691)
* Update Range.lua

Code formatting.

* RANGE - Documentation fixes.
2022-03-12 09:47:14 +01:00
Applevangelist 85a7e18fae SCORING: Corrected calc error in summary scoring functions 2022-03-11 10:18:59 +01:00
Applevangelist 26b1fd3487 Update CTLD.lua (#1692)
minor nil check
2022-03-09 10:26:16 +01:00
Applevangelist ae7a363012 CTLD - small extra nil check in _GetUnitCargoMass(Unit) 2022-03-03 12:34:43 +01:00
Applevangelist 473362af45 CTLD - small fix for finding crates when using engineers 2022-03-03 11:02:25 +01:00
Applevangelist cde0d09f0a CSAR - remove double class 2022-02-21 19:36:22 +01:00
Applevangelist 94f093826b SEAD - adding workaround for AGM_154 which lost target data 2022-02-21 08:36:37 +01:00
Applevangelist 84f231ea08 CSAR - added wet feet check if also using csarUsePara (no landing event triggered) 2022-02-18 08:22:47 +01:00
Applevangelist 3d9bb14713 CSAR - added "wet feet" option for a 2nd template to be used over water 2022-02-17 17:41:32 +01:00
Applevangelist 6c6cdcf763 CTLD - fix list/build side effect from adding weight limits to helos 2022-02-16 10:06:04 +01:00
Applevangelist 00c8690e61 CTLD - corrected default weight limits when using CTLD:UnitCapabilities() - was setting loadable weight to zero 2022-02-15 18:07:26 +01:00
Applevangelist a0d492cd2d added back GROUP:GetHighestThreat() 2022-02-15 14:41:31 +01:00
Applevangelist ba5ccc1021 CTLD:SetTroopDropZoneRadius(Radius) 2022-02-13 12:08:23 +01:00
Applevangelist a4163017d5 CSAR - CSAR:SpawnCSARAtZone(Zone ...) - Zone can now be a ZONE object as well as a string 2022-02-08 07:49:04 +01:00
Applevangelist 7f4a5c48ec CTLD - add subcategory option, added CTLD:AddCTLDZoneFromAirbase(AirbaseName, Type, Color, Active, HasBeacon) 2022-02-08 07:47:48 +01:00
Applevangelist 9f7588b245 DETECTION - added 3 missing functions 2022-02-04 08:54:02 +01:00
Applevangelist 63cbc0c55b RANGE - added option to save target sheet 2022-02-03 10:01:48 +01:00
Applevangelist 28eb7a678c CTLD - Added Hercules support for crates, troops & vehicles loaded with the help of the ground crew and dropped from the plane. Added weight checks for loaded crates. 2022-02-03 10:00:19 +01:00
Applevangelist a95c49915a SET - correct error in intersection 2022-02-01 08:02:51 +01:00
Applevangelist b7adc6add6 POINT - added function to name/stop fires and smoke 2022-01-30 09:47:11 +01:00
Applevangelist 2aeebf280b AI Dispatchers - add ability to add/remove resources to/from a squad 2022-01-24 09:54:16 +01:00
Applevangelist 8ac06979f0 CTLD added color options for smoke drops, droppable beacons w/ timer 2022-01-23 11:42:16 +01:00
Applevangelist 2d4f90d5eb Added new Callsigns as per 2.7.9 2022-01-23 11:37:07 +01:00
TommyC81 d7a44a639d Update Detection.lua (#1685)
Code formatting. Fix minor typos, errors, and references in documentation.
2022-01-23 11:21:59 +01:00
Applevangelist 7bfa05f47d DETECTION - corrected call for Vec2 in zone 2022-01-19 07:52:59 +01:00
Applevangelist c7bbb09195 Added doors check for UH-60L 2022-01-16 17:07:44 +01:00
Applevangelist 41c9c15ae5 CTLD, CSAR - added support for UH-60L 2022-01-16 11:39:19 +01:00
Applevangelist 964831becf CTLD - make container shape configureable 2022-01-15 11:34:23 +01:00
Applevangelist e847b92cce RAT - Docu corrections 2022-01-11 15:14:40 +01:00
TommyC81 c2ecd86bb4 Minor fixes (#1684)
* Update AI_A2A_Dispatcher.lua

Minor code formatting.

* Update Airbase.lua

Code formatting.
2022-01-10 15:10:30 +01:00
Applevangelist 70d922fad6 SHort name mina AP 2022-01-04 15:10:25 +01:00
Applevangelist 854bee0519 Mark visible as deprecated 2021-12-31 17:52:24 +01:00
Applevangelist d54d991bdd Fix ATC new NTTR AFB names 2021-12-31 17:52:24 +01:00
Applevangelist a4b600b97d Update Airbase.lua (#1680)
Change Nevada AFB names with latest stable patch
2021-12-31 17:44:01 +01:00
TommyC81 d6cfaa5050 Update Scoring.lua (#1674)
Code formatting and minor typo/documentation fixes.
2021-12-28 11:01:44 +01:00
TommyC81 00d1aec210 General fixes (#1673)
* General minor

Code formatting and minor typo/document fixes.

* Update Marker.lua

Code formatting and minor typo/document fixes. Note specifically the correction of "self.tocoaliton" to "self.tocoalition".
2021-12-28 11:01:05 +01:00
Applevangelist f62e3391e1 SCORING - make treason and fratricide switchable 2021-12-28 08:25:31 +01:00
TommyC81 4a406604bd Core modules formatting (#1670)
* Update Fsm.lua

Code formatting and minor typo/documentation fixes.

* Update Goal.lua

Code formatting and minor typo/documentation fixes.

* Update Menu.lua

Code formatting and minor typo/documentation fixes.

* Update Message.lua

Code formatting and minor typo/documentation fixes.

* Update Report.lua

Code formatting and minor typo/documentation fixes.

* Update ScheduleDispatcher.lua

Code formatting and minor typo/documentation fixes.

* Update Scheduler.lua

Code formatting and minor typo/documentation fixes.

* Update Settings.lua

Code formatting and minor typo/documentation fixes.

* Update Spawn.lua

Code formatting and minor typo/documentation fixes.
2021-12-20 12:59:56 +01:00
TommyC81 55cee46a8d Core code formatting and typo fixes. (#1669)
* Update Beacon.lua

Code formatting and minor typo/text fixes.

* Update Database.lua

Code formatting and minor typo/text fixes.

* Update Event.lua

Code formatting and minor typo/text fixes.
2021-12-19 08:47:07 +01:00
TommyC81 607c52c0b7 Update CSAR.lua (#1665)
Code formatting and general typo/documentation fixes.
2021-12-17 09:07:32 +01:00
TommyC81 2694321256 Update CTLD.lua (#1666)
Code formatting. Minor typos and text fixes.
2021-12-17 09:07:24 +01:00
TommyC81 e8e790102a Update Base.lua (#1667)
Code Formatting. General whitespace and spelling.
2021-12-17 09:07:13 +01:00
Applevangelist 9c5561921b Noise reducing measures 2021-12-15 13:46:07 +01:00
Applevangelist 78fab9ab0c CSAR - make beacon length configureable 2021-12-14 09:50:34 +01:00
TommyC81 058c750bc6 Update Set.lua (#1663)
Additional minor code formatting and typo fixes.
2021-12-13 16:52:01 +01:00
Applevangelist f29da39dff CSAR - override suppressmessages for menu driven information 2021-12-12 19:48:36 +01:00
Applevangelist 624a7c70c9 CTLD - corrected landheight of dropped smoke 2021-12-12 19:30:33 +01:00
TommyC81 0447ee2d9e Update Airboss.lua (#1664)
Code formatting. Typo fixing.
2021-12-12 19:15:30 +01:00
TommyC81 456fcd38d0 Code and documentation tweaks. (#1662)
* Update Point.lua

General code formatting.

* Update Set.lua

General code formatting.

* Update Positionable.lua

Code formatting, and documentation fixes.
2021-12-12 13:53:04 +01:00
Applevangelist a3cab7097a SET - Typos 2021-12-11 19:41:02 +01:00
Applevangelist 848e2f1294 SET - Added Zone Filter for STATIC 2021-12-11 14:24:20 +01:00
Applevangelist ef4dc48ea1 CTLD - added option for smoke/flare at position 2021-12-11 14:14:44 +01:00
Applevangelist 2138a33292 CSAR fixed KM message 2021-12-10 12:02:50 +01:00
TommyC81 a59343b987 Code formatting, spelling and documentation fixes. (#1661)
* Update Point.lua

Minor code formatting fix.

* Update Airboss.lua

Minor code formatting and documentation fixes.

* Update Set.lua

Code formatting, spelling and documentation fixes.

* Update ATIS.lua

Code formatting, spelling and documentation fixes.

* Update Task_A2A_Dispatcher.lua

Minor code formatting and documentation fixes. Added TODO re. possible unused variables.
2021-12-09 17:51:38 +01:00
TommyC81 a4ca4bdc99 Code and documentation fixes (#1659)
* Update .lua-format

Adjust for observed coding standards.

* Update ATIS.lua

Correct measurement units and spelling (also changed in Utils.lua).

* Update Utils.lua

Format the file, fix typos, adjust minor text. Rename "celcius" to "celsius". Rename "farenheit" to "fahrenheit".

* Update Warehouse.lua

Adjust measurement unit text.

* Update STTS.lua

Adjust formatting, minor typos, and fix error in documentation (missing blank rows) introduced in previous update.

* Update Range.lua

Adjust minor typos and code formatting. Adjust for celsius/fahrenheit typo correction.

* Update PseudoATC.lua

Adjust for celsius/fahrenheit typo correction in utils.lua.

* Update Point.lua

Code formatting, fix minor typos, adjust for celsius/fahrenheit corrrection in utils.lua.

* Update Range.lua

Minor documentation fix.
2021-12-08 19:52:29 +01:00
TommyC81 a57b9a9081 Update Range.lua (#1658)
Adjust some minor spelling and figure out the quirks of luadocumentor...
2021-12-07 18:13:51 +01:00
Applevangelist 249a6af456 Some false values seem to be in need of being set explicitly 2021-12-06 15:16:01 +01:00
Applevangelist 18685d1a94 Update Utils.lua (#1655)
Small bugfix for UTILS.LoadSetOfGroups
2021-12-06 14:57:49 +01:00
TommyC81 493b090534 LuaFormatter, RANGE formatting, and minor code fixes. (#1653)
* Create .lua-format

* Update Range.lua

Format code.

* Display distance in meters from bombtarget.

All other numbers, including menu lists etc. uses meters. Feet kept in parens.

* Fixed displaying of targetname when bombing.
2021-12-06 14:57:36 +01:00
Applevangelist 389adab9b8 SET - slight change to remove function 2021-12-06 10:26:32 +01:00
TommyC81 6360b8c58f General documentation and code fixes (#1650)
Documentation updates for correctness and clarity.
General code formatting updates.
Ajustment to POSITIONABLE:GetCoord to make use of existing POINT:UpdateFromVec3.
Added comments about clarifying the difference between POSITIONABLE:GetCoordinate() and POSITIONABLE:GetCoord() and to perhaps consider a renaming or merging the functions with an optional flag.
2021-12-04 18:50:05 +01:00
TommyC81 b0818977cf Code formatting. (#1651)
General code formatting and fixes of minor typos.
2021-12-04 18:49:57 +01:00
TommyC81 32deb160ef Formatting and typos (#1652)
* Formatting and typo fixes.

General formatting and typo fixes.

* Update STTS.lua

Keep class table on separate lines.
2021-12-04 18:49:47 +01:00
Applevangelist 2ba5215036 Merge pull request #1649 from TommyC81/RANGE_FIXES
Update Range.lua
2021-12-02 19:25:42 +01:00
Tommy Carlsson 73ea4c7b32 Update Range.lua
Fix documentation - including typos and updates to no longer correct text.
Remove duplicated RANGE.Defaults.goodthitrange value.
DCS seems to use headings 0-359 (i.e. <360), thus also deduct 360 from an exact 360 heading.
2021-12-02 20:49:48 +04:00
Applevangelist 46c37ff06a Merge pull request #1648 from TommyC81/A2G_DISPATCHER_FIXES
Update AI_A2G_Dispatcher.lua
2021-12-01 11:54:56 +01:00
Tommy Carlsson ff4708b624 Update AI_A2G_Dispatcher.lua
General code formatting fixes, and correction of typos/examples.
2021-12-01 13:41:27 +04:00
Applevangelist 82b2c84f13 Merge pull request #1647 from TommyC81/A2G_DISPATCHER_DOCUMENTATION_2
Update AI_A2G_Dispatcher.lua
2021-12-01 09:17:46 +01:00
Tommy Carlsson 48e8b1a9b3 Update AI_A2G_Dispatcher.lua
More updates and fixes.

Update AI_A2G_Dispatcher.lua

General documentation updates.
2021-12-01 11:34:18 +04:00
Applevangelist 1ad7c54ace Merge pull request #1645 from TommyC81/A2G_Dispatcher_documentation
Update AI_A2G_Dispatcher.lua
2021-11-30 17:02:40 +01:00
Tommy Carlsson 9998c86c1f Update AI_A2G_Dispatcher.lua
Fix typos and incorrect references (leftovers) to A2A/CAP etc.
2021-11-30 19:37:26 +04:00
Applevangelist 01a707ae0a Small changes in GROUP 2021-11-29 07:57:07 +01:00
Applevangelist 570e8388fc Bug fixes 2021-11-27 17:30:25 +01:00
Applevangelist 9c5b5d4633 CSAR - added changes by Shagrat for Casevac
CSAR - don't make usePara default. Added coalition check if using the parachute landing event
2021-11-14 13:34:23 +01:00
Applevangelist 822bf13626 Merge pull request #1625 from FlightControl-Master/Applevangelist-unit-1
Wrapper Unit - fix for missile count
2021-11-14 12:59:51 +01:00
Applevangelist c520de0087 Wrapper Unit - fix for missile count
Wrapper Unit - fix for missile count, issue #1624
2021-11-14 12:57:00 +01:00
Applevangelist 0e9076efa3 SEAD - align to dev changes, allow callback on SEAD events 2021-11-11 16:02:13 +01:00
Applevangelist 74cd5e3387 MANTIS - added docu and addition os SEAD events 2021-11-11 16:02:13 +01:00
Applevangelist 65c92be09e Merge pull request #1621 from FlightControl-Master/Applevangelist-casevac
Update CSAR.lua
2021-11-06 15:30:15 +01:00
Applevangelist 8e776cb3ab Update CSAR.lua
Adding CASEVAC option by Shagrat
2021-11-06 15:29:09 +01:00
Applevangelist ab6cd2b751 Fix cleanup exisiting crates 2021-10-31 11:51:31 +01:00
Applevangelist 18c3d990fc Merge pull request #1618 from rollnthndr/master
Enabled SSML when using Google text-to-speech.
2021-10-31 08:15:25 +01:00
Rolln 19d5cb8ecb Added a command line option that will enable
SSML support when using Google text-to-speech.
2021-10-30 23:35:27 -06:00
Applevangelist 2b56a78255 Merge pull request #1617 from Penecruz/master
Airboss V/STOL updates
2021-10-30 22:05:21 +02:00
Penecruz 176d9df476 Merge branch 'FlightControl-Master:master' into master 2021-10-31 06:59:50 +11:00
Penecruz c94275cb8b Airboss V/STOL updates
-Add additional Airboss V/STOL carrier HMAS Canberra L02
-Add Waveoff for AV-8B
-Add Cut Pass if Land without LSO clearance
-Changes to V/STOL groove timings
-Stabilise call when over the V/STOL landing spot
-larger abeam landing spot margin to allow decelerating to stable abeam and still be cleared to land
-Abeam area now extends further aft to allow LSO clearance 45-90 as per NATOPS
-Minor document changes
2021-10-31 06:41:58 +11:00
Applevangelist 45dbce3677 Speedmax returning 0 not nil 2021-10-30 16:33:18 +02:00
Applevangelist 18745158a3 Speedmax returning 0 not nil 2021-10-30 16:33:14 +02:00
Applevangelist 98c6c88391 Completed GetSetComplement 2021-10-29 18:32:13 +02:00
Frank 2e4fd72781 Update Fox.lua
Removed incomplete line `--@field #boolean`
2021-10-28 10:18:43 +02:00
Applevangelist 80ced88ef1 Fix for docs build 2021-10-28 08:31:14 +02:00
Applevangelist 8af3f89c14 Adjustments for Forrestal by Pene 2021-10-24 14:35:55 +02:00
Applevangelist fe3079caad Added Bell-47 2021-10-22 17:04:23 +02:00
Applevangelist 61ac6b4131 Added Bell-47 2021-10-22 17:04:19 +02:00
Frank 36cb189512 Merge pull request #1612 from FlightControl-Master/FF/MasterDevel
AIRBOSS v1.2.0
2021-10-20 19:55:19 +02:00
Frank 15f9843878 AIRBOSS v1.2.0
- Added Forrestal carrier CV-59
2021-10-16 12:11:34 +02:00
Frank 67f847dd16 Update Group.lua
- Fixed SetInvisible and SetImmortal functions to acknowledge parameter false.
2021-10-12 22:16:18 +02:00
70 changed files with 23263 additions and 21571 deletions
+33
View File
@@ -0,0 +1,33 @@
# See https://github.com/Koihik/LuaFormatter
# Use '-- LuaFormatter off' and '-- LuaFormatter on' around code blocks to inhibit formatting
column_limit: 500
indent_width: 2
use_tab: false
continuation_indent_width: 2
keep_simple_control_block_one_line: false
keep_simple_function_one_line: false
align_args: true
break_after_functioncall_lp: false
break_before_functioncall_rp: false
align_parameter: true
chop_down_parameter: true
break_after_functiondef_lp: false
break_before_functiondef_rp: false
align_table_field: true
break_after_table_lb: true
break_before_table_rb: true
chop_down_table: true
chop_down_kv_table: true
column_table_limit: 500
table_sep: ','
extra_sep_at_table_end: true
break_after_operator: true
single_quote_to_double_quote: false
double_quote_to_single_quote: false
spaces_before_call: 1
spaces_inside_functiondef_parens: true
spaces_inside_functioncall_parens: true
spaces_inside_table_braces: true
spaces_around_equals_in_field: true
line_breaks_after_function_body: 1
+3 -3
View File
@@ -40,8 +40,8 @@
-- --
-- ![Process](..\Presentations\AI_CAP\Dia10.JPG) -- ![Process](..\Presentations\AI_CAP\Dia10.JPG)
-- --
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB. -- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. -- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
-- --
-- ![Process](..\Presentations\AI_CAP\Dia13.JPG) -- ![Process](..\Presentations\AI_CAP\Dia13.JPG)
-- --
@@ -71,7 +71,7 @@
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. -- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
-- * **@{#AI_A2A_CAP.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}. -- * **@{#AI_A2A_CAP.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
-- * **@{#AI_A2A_CAP.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task. -- * **@{#AI_A2A_CAP.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. -- * **Status** ( Group ): The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
-- --
-- ## 3. Set the Range of Engagement -- ## 3. Set the Range of Engagement
-- --
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -42,8 +42,8 @@
-- --
-- ![Process](..\Presentations\AI_GCI\Dia10.JPG) -- ![Process](..\Presentations\AI_GCI\Dia10.JPG)
-- --
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB. -- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. -- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
-- --
-- ![Process](..\Presentations\AI_GCI\Dia13.JPG) -- ![Process](..\Presentations\AI_GCI\Dia13.JPG)
-- --
@@ -73,7 +73,7 @@
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. -- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
-- * **@{#AI_A2A_GCI.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}. -- * **@{#AI_A2A_GCI.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
-- * **@{#AI_A2A_GCI.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task. -- * **@{#AI_A2A_GCI.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. -- * **Status** ( Group ): The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
-- --
-- ## 3. Set the Range of Engagement -- ## 3. Set the Range of Engagement
-- --
+6 -6
View File
@@ -39,8 +39,8 @@
-- --
-- ![Process](..\Presentations\AI_PATROL\Dia10.JPG) -- ![Process](..\Presentations\AI_PATROL\Dia10.JPG)
-- --
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB. -- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. -- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
-- --
-- ![Process](..\Presentations\AI_PATROL\Dia11.JPG) -- ![Process](..\Presentations\AI_PATROL\Dia11.JPG)
-- --
@@ -68,7 +68,7 @@
-- * **RTB** ( Group ): Route the AI to the home base. -- * **RTB** ( Group ): Route the AI to the home base.
-- * **Detect** ( Group ): The AI is detecting targets. -- * **Detect** ( Group ): The AI is detecting targets.
-- * **Detected** ( Group ): The AI has detected new targets. -- * **Detected** ( Group ): The AI has detected new targets.
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. -- * **Status** ( Group ): The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
-- --
-- ## 3. Set or Get the AI controllable -- ## 3. Set or Get the AI controllable
-- --
@@ -100,8 +100,8 @@
-- ## 6. Manage the "out of fuel" in the AI_A2A_PATROL -- ## 6. Manage the "out of fuel" in the AI_A2A_PATROL
-- --
-- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base. -- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated. -- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
-- When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit, -- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit,
-- while a new AI is targetted to the AI_A2A_PATROL. -- while a new AI is targetted to the AI_A2A_PATROL.
-- Once the time is finished, the old AI will return to the base. -- Once the time is finished, the old AI will return to the base.
-- Use the method @{#AI_A2A_PATROL.ManageFuel}() to have this proces in place. -- Use the method @{#AI_A2A_PATROL.ManageFuel}() to have this proces in place.
@@ -109,7 +109,7 @@
-- ## 7. Manage "damage" behaviour of the AI in the AI_A2A_PATROL -- ## 7. Manage "damage" behaviour of the AI in the AI_A2A_PATROL
-- --
-- When the AI is damaged, it is required that a new Patrol is started. However, damage cannon be foreseen early on. -- When the AI is damaged, it is required that a new Patrol is started. However, damage cannon be foreseen early on.
-- Therefore, when the damage treshold is reached, the AI will return immediately to the home base (RTB). -- Therefore, when the damage threshold is reached, the AI will return immediately to the home base (RTB).
-- Use the method @{#AI_A2A_PATROL.ManageDamage}() to have this proces in place. -- Use the method @{#AI_A2A_PATROL.ManageDamage}() to have this proces in place.
-- --
-- === -- ===
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -42,8 +42,8 @@
-- --
-- ![Process](..\Presentations\AI_GCI\Dia10.JPG) -- ![Process](..\Presentations\AI_GCI\Dia10.JPG)
-- --
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB. -- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. -- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
-- --
-- ![Process](..\Presentations\AI_GCI\Dia13.JPG) -- ![Process](..\Presentations\AI_GCI\Dia13.JPG)
-- --
+9 -9
View File
@@ -370,11 +370,11 @@ end
--- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base. --- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated. -- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
-- When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_AIR. -- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_AIR.
-- Once the time is finished, the old AI will return to the base. -- Once the time is finished, the old AI will return to the base.
-- @param #AI_AIR self -- @param #AI_AIR self
-- @param #number FuelThresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel. -- @param #number FuelThresholdPercentage The threshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
-- @param #number OutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base. -- @param #number OutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base.
-- @return #AI_AIR self -- @return #AI_AIR self
function AI_AIR:SetFuelThreshold( FuelThresholdPercentage, OutOfFuelOrbitTime ) function AI_AIR:SetFuelThreshold( FuelThresholdPercentage, OutOfFuelOrbitTime )
@@ -387,14 +387,14 @@ function AI_AIR:SetFuelThreshold( FuelThresholdPercentage, OutOfFuelOrbitTime )
return self return self
end end
--- When the AI is damaged beyond a certain treshold, it is required that the AI returns to the home base. --- When the AI is damaged beyond a certain threshold, it is required that the AI returns to the home base.
-- However, damage cannot be foreseen early on. -- However, damage cannot be foreseen early on.
-- Therefore, when the damage treshold is reached, -- Therefore, when the damage threshold is reached,
-- the AI will return immediately to the home base (RTB). -- the AI will return immediately to the home base (RTB).
-- Note that for groups, the average damage of the complete group will be calculated. -- Note that for groups, the average damage of the complete group will be calculated.
-- So, in a group of 4 airplanes, 2 lost and 2 with damage 0.2, the damage treshold will be 0.25. -- So, in a group of 4 airplanes, 2 lost and 2 with damage 0.2, the damage threshold will be 0.25.
-- @param #AI_AIR self -- @param #AI_AIR self
-- @param #number PatrolDamageThreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged. -- @param #number PatrolDamageThreshold The threshold in percentage (between 0 and 1) when the AI is considered to be damaged.
-- @return #AI_AIR self -- @return #AI_AIR self
function AI_AIR:SetDamageThreshold( PatrolDamageThreshold ) function AI_AIR:SetDamageThreshold( PatrolDamageThreshold )
@@ -476,7 +476,7 @@ function AI_AIR:onafterStatus()
local Fuel = self.Controllable:GetFuelMin() local Fuel = self.Controllable:GetFuelMin()
-- If the fuel in the controllable is below the treshold percentage, -- If the fuel in the controllable is below the threshold percentage,
-- then send for refuel in case of a tanker, otherwise RTB. -- then send for refuel in case of a tanker, otherwise RTB.
if Fuel < self.FuelThresholdPercentage then if Fuel < self.FuelThresholdPercentage then
@@ -585,7 +585,7 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
if AIGroup and AIGroup:IsAlive() then if AIGroup and AIGroup:IsAlive() then
self:I( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" ) self:T( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" )
self:ClearTargetDistance() self:ClearTargetDistance()
--AIGroup:ClearTasks() --AIGroup:ClearTasks()
@@ -10,11 +10,11 @@
-- * Setup (CAS) Controlled Air Support squadrons, to attack closeby enemy ground units near friendly installations. -- * Setup (CAS) Controlled Air Support squadrons, to attack closeby enemy ground units near friendly installations.
-- * Setup (BAI) Battleground Air Interdiction squadrons to attack remote enemy ground units and targets. -- * Setup (BAI) Battleground Air Interdiction squadrons to attack remote enemy ground units and targets.
-- * Define and use a detection network controlled by recce. -- * Define and use a detection network controlled by recce.
-- * Define AIR defense squadrons at airbases, farps and carriers. -- * Define AIR defense squadrons at airbases, FARPs and carriers.
-- * Enable airbases for AIR defenses. -- * Enable airbases for AIR defenses.
-- * Add different planes and helicopter templates to squadrons. -- * Add different planes and helicopter templates to squadrons.
-- * Assign squadrons to execute a specific engagement type depending on threat level of the detected ground enemy unit composition. -- * Assign squadrons to execute a specific engagement type depending on threat level of the detected ground enemy unit composition.
-- * Add multiple squadrons to different airbases, farps or carriers. -- * Add multiple squadrons to different airbases, FARPs or carriers.
-- * Define different ranges to engage upon. -- * Define different ranges to engage upon.
-- * Establish an automatic in air refuel process for planes using refuel tankers. -- * Establish an automatic in air refuel process for planes using refuel tankers.
-- * Setup default settings for all squadrons and AIR defenses. -- * Setup default settings for all squadrons and AIR defenses.
@@ -40,7 +40,7 @@
-- --
-- AI_AIR_DISPATCHER is the main AIR defense class that models the AIR defense system. -- AI_AIR_DISPATCHER is the main AIR defense class that models the AIR defense system.
-- --
-- Before you start using the AI_AIR_DISPATCHER, ask youself the following questions. -- Before you start using the AI_AIR_DISPATCHER, ask yourself the following questions.
-- --
-- --
-- ## 1. Which coalition am I modeling an AIR defense system for? blue or red? -- ## 1. Which coalition am I modeling an AIR defense system for? blue or red?
@@ -128,7 +128,7 @@
-- Depending on the defense type, different payloads will be needed. See further points on squadron definition. -- Depending on the defense type, different payloads will be needed. See further points on squadron definition.
-- --
-- --
-- ## 7. Where will the Squadrons be located? On Airbases? On Carrier Ships? On Farps? -- ## 7. Where will the Squadrons be located? On Airbases? On Carrier Ships? On FARPs?
-- --
-- Squadrons are placed at the **home base** on an **airfield**, **carrier** or **farp**. -- Squadrons are placed at the **home base** on an **airfield**, **carrier** or **farp**.
-- Carefully plan where each Squadron will be located as part of the defense system required for mission effective defenses. -- Carefully plan where each Squadron will be located as part of the defense system required for mission effective defenses.
@@ -354,7 +354,7 @@ do -- AI_AIR_DISPATCHER
-- **DetectionSetGroup** is then calling `FilterStart()`, which is starting the dynamic filtering or inclusion of these groups. -- **DetectionSetGroup** is then calling `FilterStart()`, which is starting the dynamic filtering or inclusion of these groups.
-- Note that any destroy or new spawn of a group having a name, starting with the above prefix, will be removed or added to the set. -- Note that any destroy or new spawn of a group having a name, starting with the above prefix, will be removed or added to the set.
-- --
-- Then a new detection object is created from the class `DETECTION_AREAS`. A grouping radius of 1000 meters (1km) is choosen. -- Then a new detection object is created from the class `DETECTION_AREAS`. A grouping radius of 1000 meters (1km) is chosen.
-- --
-- The `Detection` object is then passed to the @{#AI_AIR_DISPATCHER.New}() method to indicate the reconnaissance network -- The `Detection` object is then passed to the @{#AI_AIR_DISPATCHER.New}() method to indicate the reconnaissance network
-- configuration and setup the AIR defense detection mechanism. -- configuration and setup the AIR defense detection mechanism.
@@ -647,7 +647,7 @@ do -- AI_AIR_DISPATCHER
-- * @{#AI_AIR_DISPATCHER.SetSquadronLandingAtRunway}() will despawn the returning aircraft directly after landing at the runway. -- * @{#AI_AIR_DISPATCHER.SetSquadronLandingAtRunway}() will despawn the returning aircraft directly after landing at the runway.
-- * @{#AI_AIR_DISPATCHER.SetSquadronLandingAtEngineShutdown}() will despawn the returning aircraft when the aircraft has returned to its parking spot and has turned off its engines. -- * @{#AI_AIR_DISPATCHER.SetSquadronLandingAtEngineShutdown}() will despawn the returning aircraft when the aircraft has returned to its parking spot and has turned off its engines.
-- --
-- You can use these methods to minimize the airbase coodination overhead and to increase the airbase efficiency. -- You can use these methods to minimize the airbase coordination overhead and to increase the airbase efficiency.
-- When there are lots of aircraft returning for landing, at the same airbase, the takeoff process will be halted, which can cause a complete failure of the -- When there are lots of aircraft returning for landing, at the same airbase, the takeoff process will be halted, which can cause a complete failure of the
-- A2A defense system, as no new CAP or GCI planes can takeoff. -- A2A defense system, as no new CAP or GCI planes can takeoff.
-- Note that the method @{#AI_AIR_DISPATCHER.SetSquadronLandingNearAirbase}() will only work for returning aircraft, not for damaged or out of fuel aircraft. -- Note that the method @{#AI_AIR_DISPATCHER.SetSquadronLandingNearAirbase}() will only work for returning aircraft, not for damaged or out of fuel aircraft.
@@ -724,13 +724,13 @@ do -- AI_AIR_DISPATCHER
-- --
-- Use the method @{#AI_AIR_DISPATCHER.SetSquadronEngageLimit}() to limit the amount of aircraft that will engage with the enemy, per squadron. -- Use the method @{#AI_AIR_DISPATCHER.SetSquadronEngageLimit}() to limit the amount of aircraft that will engage with the enemy, per squadron.
-- --
-- ## 4. Set the **fuel treshold**. -- ## 4. Set the **fuel threshold**.
-- --
-- When aircraft get **out of fuel** to a certain %-tage, which is by default **15% (0.15)**, there are two possible actions that can be taken: -- When aircraft get **out of fuel** to a certain %, which is by default **15% (0.15)**, there are two possible actions that can be taken:
-- - The aircraft will go RTB, and will be replaced with a new aircraft if possible. -- - The aircraft will go RTB, and will be replaced with a new aircraft if possible.
-- - The aircraft will refuel at a tanker, if a tanker has been specified for the squadron. -- - The aircraft will refuel at a tanker, if a tanker has been specified for the squadron.
-- --
-- Use the method @{#AI_AIR_DISPATCHER.SetSquadronFuelThreshold}() to set the **squadron fuel treshold** of the aircraft for all squadrons. -- Use the method @{#AI_AIR_DISPATCHER.SetSquadronFuelThreshold}() to set the **squadron fuel threshold** of the aircraft for all squadrons.
-- --
-- ## 6. Other configuration options -- ## 6. Other configuration options
-- --
@@ -786,17 +786,17 @@ do -- AI_AIR_DISPATCHER
-- --
-- Use the method @{#AI_AIR_DISPATCHER.SetDefaultGrouping}() to set the **default grouping** of spawned airplanes for all squadrons. -- Use the method @{#AI_AIR_DISPATCHER.SetDefaultGrouping}() to set the **default grouping** of spawned airplanes for all squadrons.
-- --
-- ## 10.5. Default RTB fuel treshold. -- ## 10.5. Default RTB fuel threshold.
-- --
-- When an airplane gets **out of fuel** to a certain %-tage, which is **15% (0.15)**, it will go RTB, and will be replaced with a new airplane when applicable. -- When an airplane gets **out of fuel** to a certain %, which is **15% (0.15)**, it will go RTB, and will be replaced with a new airplane when applicable.
-- --
-- Use the method @{#AI_AIR_DISPATCHER.SetDefaultFuelThreshold}() to set the **default fuel treshold** of spawned airplanes for all squadrons. -- Use the method @{#AI_AIR_DISPATCHER.SetDefaultFuelThreshold}() to set the **default fuel threshold** of spawned airplanes for all squadrons.
-- --
-- ## 10.6. Default RTB damage treshold. -- ## 10.6. Default RTB damage threshold.
-- --
-- When an airplane is **damaged** to a certain %-tage, which is **40% (0.40)**, it will go RTB, and will be replaced with a new airplane when applicable. -- When an airplane is **damaged** to a certain %, which is **40% (0.40)**, it will go RTB, and will be replaced with a new airplane when applicable.
-- --
-- Use the method @{#AI_AIR_DISPATCHER.SetDefaultDamageThreshold}() to set the **default damage treshold** of spawned airplanes for all squadrons. -- Use the method @{#AI_AIR_DISPATCHER.SetDefaultDamageThreshold}() to set the **default damage threshold** of spawned airplanes for all squadrons.
-- --
-- ## 10.7. Default settings for **patrol**. -- ## 10.7. Default settings for **patrol**.
-- --
@@ -829,7 +829,7 @@ do -- AI_AIR_DISPATCHER
-- --
-- In the mission editor, setup a group with task Refuelling. A tanker unit of the correct coalition will be automatically selected. -- In the mission editor, setup a group with task Refuelling. A tanker unit of the correct coalition will be automatically selected.
-- Then, use the method @{#AI_AIR_DISPATCHER.SetDefaultTanker}() to set the tanker for the dispatcher. -- Then, use the method @{#AI_AIR_DISPATCHER.SetDefaultTanker}() to set the tanker for the dispatcher.
-- Use the method @{#AI_AIR_DISPATCHER.SetDefaultFuelThreshold}() to set the %-tage left in the defender airplane tanks when a refuel action is needed. -- Use the method @{#AI_AIR_DISPATCHER.SetDefaultFuelThreshold}() to set the % left in the defender airplane tanks when a refuel action is needed.
-- --
-- When the tanker specified is alive and in the air, the tanker will be used for refuelling. -- When the tanker specified is alive and in the air, the tanker will be used for refuelling.
-- --
@@ -843,7 +843,7 @@ do -- AI_AIR_DISPATCHER
-- A2ADispatcher:SetSquadronCapInterval("Sochi", 2, 30, 600, 1 ) -- A2ADispatcher:SetSquadronCapInterval("Sochi", 2, 30, 600, 1 )
-- A2ADispatcher:SetSquadronGci( "Sochi", 900, 1200 ) -- A2ADispatcher:SetSquadronGci( "Sochi", 900, 1200 )
-- --
-- -- Set the default tanker for refuelling to "Tanker", when the default fuel treshold has reached 90% fuel left. -- -- Set the default tanker for refuelling to "Tanker", when the default fuel threshold has reached 90% fuel left.
-- A2ADispatcher:SetDefaultFuelThreshold( 0.9 ) -- A2ADispatcher:SetDefaultFuelThreshold( 0.9 )
-- A2ADispatcher:SetDefaultTanker( "Tanker" ) -- A2ADispatcher:SetDefaultTanker( "Tanker" )
-- --
@@ -883,9 +883,6 @@ do -- AI_AIR_DISPATCHER
-- However, the squadron will still stay alive. Any airplane that is airborne will continue its operations until all airborne airplanes -- However, the squadron will still stay alive. Any airplane that is airborne will continue its operations until all airborne airplanes
-- of the squadron will be destroyed. This to keep consistency of air operations not to confuse the players. -- of the squadron will be destroyed. This to keep consistency of air operations not to confuse the players.
-- --
--
--
--
-- @field #AI_AIR_DISPATCHER -- @field #AI_AIR_DISPATCHER
AI_AIR_DISPATCHER = { AI_AIR_DISPATCHER = {
ClassName = "AI_AIR_DISPATCHER", ClassName = "AI_AIR_DISPATCHER",
@@ -949,7 +946,6 @@ do -- AI_AIR_DISPATCHER
--- @field #AI_AIR_DISPATCHER.DefenseQueue DefenseQueue --- @field #AI_AIR_DISPATCHER.DefenseQueue DefenseQueue
AI_AIR_DISPATCHER.DefenseQueue = {} AI_AIR_DISPATCHER.DefenseQueue = {}
--- Defense approach types --- Defense approach types
-- @type #AI_AIR_DISPATCHER.DefenseApproach -- @type #AI_AIR_DISPATCHER.DefenseApproach
AI_AIR_DISPATCHER.DefenseApproach = { AI_AIR_DISPATCHER.DefenseApproach = {
@@ -958,26 +954,26 @@ do -- AI_AIR_DISPATCHER
} }
--- AI_AIR_DISPATCHER constructor. --- AI_AIR_DISPATCHER constructor.
-- This is defining the AIR DISPATCHER for one coaliton. -- This is defining the AIR DISPATCHER for one coalition.
-- The Dispatcher works with a @{Functional.Detection#DETECTION_BASE} object that is taking of the detection of targets using the EWR units. -- The Dispatcher works with a @{Functional.Detection#DETECTION_BASE} object that is taking of the detection of targets using the EWR units.
-- The Detection object is polymorphic, depending on the type of detection object choosen, the detection will work differently. -- The Detection object is polymorphic, depending on the type of detection object chosen, the detection will work differently.
-- @param #AI_AIR_DISPATCHER self -- @param #AI_AIR_DISPATCHER self
-- @param Functional.Detection#DETECTION_BASE Detection The DETECTION object that will detects targets using the the Early Warning Radar network. -- @param Functional.Detection#DETECTION_BASE Detection The DETECTION object that will detects targets using the the Early Warning Radar network.
-- @return #AI_AIR_DISPATCHER self -- @return #AI_AIR_DISPATCHER self
-- @usage -- @usage
-- --
-- -- Setup the Detection, using DETECTION_AREAS. -- -- Setup the Detection, using DETECTION_AREAS.
-- -- First define the SET of GROUPs that are defining the EWR network. -- -- First define the SET of GROUPs that are defining the EWR network.
-- -- Here with prefixes DF CCCP AWACS, DF CCCP EWR. -- -- Here with prefixes DF CCCP AWACS, DF CCCP EWR.
-- DetectionSetGroup = SET_GROUP:New() -- DetectionSetGroup = SET_GROUP:New()
-- DetectionSetGroup:FilterPrefixes( { "DF CCCP AWACS", "DF CCCP EWR" } ) -- DetectionSetGroup:FilterPrefixes( { "DF CCCP AWACS", "DF CCCP EWR" } )
-- DetectionSetGroup:FilterStart() -- DetectionSetGroup:FilterStart()
-- --
-- -- Define the DETECTION_AREAS, using the DetectionSetGroup, with a 30km grouping radius. -- -- Define the DETECTION_AREAS, using the DetectionSetGroup, with a 30km grouping radius.
-- Detection = DETECTION_AREAS:New( DetectionSetGroup, 30000 ) -- Detection = DETECTION_AREAS:New( DetectionSetGroup, 30000 )
-- --
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object. -- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection ) -- -- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
-- --
function AI_AIR_DISPATCHER:New( Detection ) function AI_AIR_DISPATCHER:New( Detection )
@@ -1435,17 +1431,17 @@ do -- AI_AIR_DISPATCHER
end end
--- Set the default damage treshold when defenders will RTB. --- Set the default damage threshold when defenders will RTB.
-- The default damage treshold is by default set to 40%, which means that when the airplane is 40% damaged, it will go RTB. -- The default damage threshold is by default set to 40%, which means that when the airplane is 40% damaged, it will go RTB.
-- @param #AI_AIR_DISPATCHER self -- @param #AI_AIR_DISPATCHER self
-- @param #number DamageThreshold A decimal number between 0 and 1, that expresses the %-tage of the damage treshold before going RTB. -- @param #number DamageThreshold A decimal number between 0 and 1, that expresses the % of the damage threshold before going RTB.
-- @return #AI_AIR_DISPATCHER -- @return #AI_AIR_DISPATCHER
-- @usage -- @usage
-- --
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object. -- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection ) -- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
-- --
-- -- Now Setup the default damage treshold. -- -- Now Setup the default damage threshold.
-- AIRDispatcher:SetDefaultDamageThreshold( 0.90 ) -- Go RTB when the airplane 90% damaged. -- AIRDispatcher:SetDefaultDamageThreshold( 0.90 ) -- Go RTB when the airplane 90% damaged.
-- --
function AI_AIR_DISPATCHER:SetDefaultDamageThreshold( DamageThreshold ) function AI_AIR_DISPATCHER:SetDefaultDamageThreshold( DamageThreshold )
@@ -1989,7 +1985,7 @@ do -- AI_AIR_DISPATCHER
--- Defines the default amount of extra planes that will take-off as part of the defense system. --- Defines the default amount of extra planes that will take-off as part of the defense system.
-- @param #AI_AIR_DISPATCHER self -- @param #AI_AIR_DISPATCHER self
-- @param #number Overhead The %-tage of Units that dispatching command will allocate to intercept in surplus of detected amount of units. -- @param #number Overhead The % of Units that dispatching command will allocate to intercept in surplus of detected amount of units.
-- The default overhead is 1, so equal balance. The @{#AI_AIR_DISPATCHER.SetOverhead}() method can be used to tweak the defense strength, -- The default overhead is 1, so equal balance. The @{#AI_AIR_DISPATCHER.SetOverhead}() method can be used to tweak the defense strength,
-- taking into account the plane types of the squadron. For example, a MIG-31 with full long-distance AIR missiles payload, may still be less effective than a F-15C with short missiles... -- taking into account the plane types of the squadron. For example, a MIG-31 with full long-distance AIR missiles payload, may still be less effective than a F-15C with short missiles...
-- So in this case, one may want to use the Overhead method to allocate more defending planes as the amount of detected attacking planes. -- So in this case, one may want to use the Overhead method to allocate more defending planes as the amount of detected attacking planes.
@@ -2028,7 +2024,7 @@ do -- AI_AIR_DISPATCHER
--- Defines the amount of extra planes that will take-off as part of the defense system. --- Defines the amount of extra planes that will take-off as part of the defense system.
-- @param #AI_AIR_DISPATCHER self -- @param #AI_AIR_DISPATCHER self
-- @param #string SquadronName The name of the squadron. -- @param #string SquadronName The name of the squadron.
-- @param #number Overhead The %-tage of Units that dispatching command will allocate to intercept in surplus of detected amount of units. -- @param #number Overhead The % of Units that dispatching command will allocate to intercept in surplus of detected amount of units.
-- The default overhead is 1, so equal balance. The @{#AI_AIR_DISPATCHER.SetOverhead}() method can be used to tweak the defense strength, -- The default overhead is 1, so equal balance. The @{#AI_AIR_DISPATCHER.SetOverhead}() method can be used to tweak the defense strength,
-- taking into account the plane types of the squadron. For example, a MIG-31 with full long-distance AIR missiles payload, may still be less effective than a F-15C with short missiles... -- taking into account the plane types of the squadron. For example, a MIG-31 with full long-distance AIR missiles payload, may still be less effective than a F-15C with short missiles...
-- So in this case, one may want to use the Overhead method to allocate more defending planes as the amount of detected attacking planes. -- So in this case, one may want to use the Overhead method to allocate more defending planes as the amount of detected attacking planes.
@@ -2068,7 +2064,7 @@ do -- AI_AIR_DISPATCHER
--- Gets the overhead of planes as part of the defense system, in comparison with the attackers. --- Gets the overhead of planes as part of the defense system, in comparison with the attackers.
-- @param #AI_AIR_DISPATCHER self -- @param #AI_AIR_DISPATCHER self
-- @param #string SquadronName The name of the squadron. -- @param #string SquadronName The name of the squadron.
-- @return #number The %-tage of Units that dispatching command will allocate to intercept in surplus of detected amount of units. -- @return #number The % of Units that dispatching command will allocate to intercept in surplus of detected amount of units.
-- The default overhead is 1, so equal balance. The @{#AI_AIR_DISPATCHER.SetOverhead}() method can be used to tweak the defense strength, -- The default overhead is 1, so equal balance. The @{#AI_AIR_DISPATCHER.SetOverhead}() method can be used to tweak the defense strength,
-- taking into account the plane types of the squadron. For example, a MIG-31 with full long-distance AIR missiles payload, may still be less effective than a F-15C with short missiles... -- taking into account the plane types of the squadron. For example, a MIG-31 with full long-distance AIR missiles payload, may still be less effective than a F-15C with short missiles...
-- So in this case, one may want to use the Overhead method to allocate more defending planes as the amount of detected attacking planes. -- So in this case, one may want to use the Overhead method to allocate more defending planes as the amount of detected attacking planes.
@@ -2674,17 +2670,17 @@ do -- AI_AIR_DISPATCHER
return self return self
end end
--- Set the default fuel treshold when defenders will RTB or Refuel in the air. --- Set the default fuel threshold when defenders will RTB or Refuel in the air.
-- The fuel treshold is by default set to 15%, which means that an airplane will stay in the air until 15% of its fuel has been consumed. -- The fuel threshold is by default set to 15%, which means that an airplane will stay in the air until 15% of its fuel has been consumed.
-- @param #AI_AIR_DISPATCHER self -- @param #AI_AIR_DISPATCHER self
-- @param #number FuelThreshold A decimal number between 0 and 1, that expresses the %-tage of the treshold of fuel remaining in the tank when the plane will go RTB or Refuel. -- @param #number FuelThreshold A decimal number between 0 and 1, that expresses the % of the threshold of fuel remaining in the tank when the plane will go RTB or Refuel.
-- @return #AI_AIR_DISPATCHER -- @return #AI_AIR_DISPATCHER
-- @usage -- @usage
-- --
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object. -- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection ) -- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
-- --
-- -- Now Setup the default fuel treshold. -- -- Now Setup the default fuel threshold.
-- AIRDispatcher:SetDefaultFuelThreshold( 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank. -- AIRDispatcher:SetDefaultFuelThreshold( 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
-- --
function AI_AIR_DISPATCHER:SetDefaultFuelThreshold( FuelThreshold ) function AI_AIR_DISPATCHER:SetDefaultFuelThreshold( FuelThreshold )
@@ -2695,18 +2691,18 @@ do -- AI_AIR_DISPATCHER
end end
--- Set the fuel treshold for the squadron when defenders will RTB or Refuel in the air. --- Set the fuel threshold for the squadron when defenders will RTB or Refuel in the air.
-- The fuel treshold is by default set to 15%, which means that an airplane will stay in the air until 15% of its fuel has been consumed. -- The fuel threshold is by default set to 15%, which means that an airplane will stay in the air until 15% of its fuel has been consumed.
-- @param #AI_AIR_DISPATCHER self -- @param #AI_AIR_DISPATCHER self
-- @param #string SquadronName The name of the squadron. -- @param #string SquadronName The name of the squadron.
-- @param #number FuelThreshold A decimal number between 0 and 1, that expresses the %-tage of the treshold of fuel remaining in the tank when the plane will go RTB or Refuel. -- @param #number FuelThreshold A decimal number between 0 and 1, that expresses the % of the threshold of fuel remaining in the tank when the plane will go RTB or Refuel.
-- @return #AI_AIR_DISPATCHER -- @return #AI_AIR_DISPATCHER
-- @usage -- @usage
-- --
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object. -- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection ) -- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
-- --
-- -- Now Setup the default fuel treshold. -- -- Now Setup the default fuel threshold.
-- AIRDispatcher:SetSquadronRefuelThreshold( "SquadronName", 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank. -- AIRDispatcher:SetSquadronRefuelThreshold( "SquadronName", 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
-- --
function AI_AIR_DISPATCHER:SetSquadronFuelThreshold( SquadronName, FuelThreshold ) function AI_AIR_DISPATCHER:SetSquadronFuelThreshold( SquadronName, FuelThreshold )
@@ -2726,7 +2722,7 @@ do -- AI_AIR_DISPATCHER
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object. -- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection ) -- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
-- --
-- -- Now Setup the default fuel treshold. -- -- Now Setup the default fuel threshold.
-- AIRDispatcher:SetDefaultFuelThreshold( 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank. -- AIRDispatcher:SetDefaultFuelThreshold( 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
-- --
-- -- Now Setup the default tanker. -- -- Now Setup the default tanker.
@@ -2749,7 +2745,7 @@ do -- AI_AIR_DISPATCHER
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object. -- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection ) -- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
-- --
-- -- Now Setup the squadron fuel treshold. -- -- Now Setup the squadron fuel threshold.
-- AIRDispatcher:SetSquadronRefuelThreshold( "SquadronName", 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank. -- AIRDispatcher:SetSquadronRefuelThreshold( "SquadronName", 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
-- --
-- -- Now Setup the squadron tanker. -- -- Now Setup the squadron tanker.
@@ -2847,7 +2843,7 @@ do -- AI_AIR_DISPATCHER
-- @param #AI_AIR_DISPATCHER self -- @param #AI_AIR_DISPATCHER self
function AI_AIR_DISPATCHER:CountDefendersEngaged( AttackerDetection, AttackerCount ) function AI_AIR_DISPATCHER:CountDefendersEngaged( AttackerDetection, AttackerCount )
-- First, count the active AIGroups Units, targetting the DetectedSet -- First, count the active AIGroups Units, targeting the DetectedSet
local DefendersEngaged = 0 local DefendersEngaged = 0
local DefendersTotal = 0 local DefendersTotal = 0
+2 -2
View File
@@ -42,8 +42,8 @@
-- --
-- ![Process](..\Presentations\AI_GCI\Dia10.JPG) -- ![Process](..\Presentations\AI_GCI\Dia10.JPG)
-- --
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB. -- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. -- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
-- --
-- ![Process](..\Presentations\AI_GCI\Dia13.JPG) -- ![Process](..\Presentations\AI_GCI\Dia13.JPG)
-- --
+3 -3
View File
@@ -39,8 +39,8 @@
-- --
-- ![Process](..\Presentations\AI_CAP\Dia10.JPG) -- ![Process](..\Presentations\AI_CAP\Dia10.JPG)
-- --
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB. -- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. -- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
-- --
-- ![Process](..\Presentations\AI_CAP\Dia13.JPG) -- ![Process](..\Presentations\AI_CAP\Dia13.JPG)
-- --
@@ -70,7 +70,7 @@
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. -- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
-- * **@{#AI_AIR_PATROL.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}. -- * **@{#AI_AIR_PATROL.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
-- * **@{#AI_AIR_PATROL.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task. -- * **@{#AI_AIR_PATROL.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. -- * **Status** ( Group ): The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
-- --
-- ## 3. Set the Range of Engagement -- ## 3. Set the Range of Engagement
-- --
+4 -4
View File
@@ -49,7 +49,7 @@
-- Upon started, The AI will **Route** itself towards the random 3D point within a patrol zone, -- Upon started, The AI will **Route** itself towards the random 3D point within a patrol zone,
-- using a random speed within the given altitude and speed limits. -- using a random speed within the given altitude and speed limits.
-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits. -- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits.
-- This cycle will continue until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB. -- This cycle will continue until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
-- --
-- ![Route Event](..\Presentations\AI_BAI\Dia5.JPG) -- ![Route Event](..\Presentations\AI_BAI\Dia5.JPG)
-- --
@@ -87,7 +87,7 @@
-- It will keep patrolling there, until it is notified to RTB or move to another BOMB Zone. -- It will keep patrolling there, until it is notified to RTB or move to another BOMB Zone.
-- It can be notified to go RTB through the **RTB** event. -- It can be notified to go RTB through the **RTB** event.
-- --
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. -- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
-- --
-- ![Engage Event](..\Presentations\AI_BAI\Dia12.JPG) -- ![Engage Event](..\Presentations\AI_BAI\Dia12.JPG)
-- --
@@ -117,7 +117,7 @@
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. -- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
-- * **@{#AI_BAI_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}. -- * **@{#AI_BAI_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}.
-- * **@{#AI_BAI_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the BOMB task. -- * **@{#AI_BAI_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the BOMB task.
-- * **Status**: The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. -- * **Status**: The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
-- --
-- ## 3. Modify the Engage Zone behaviour to pinpoint a **map object** or **scenery object** -- ## 3. Modify the Engage Zone behaviour to pinpoint a **map object** or **scenery object**
-- --
@@ -602,7 +602,7 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
self:SetRefreshTimeInterval( 2 ) self:SetRefreshTimeInterval( 2 )
self:SetDetectionActivated() self:SetDetectionActivated()
self:__Target( -2 ) -- Start Targetting self:__Target( -2 ) -- Start targeting
end end
end end
+4 -4
View File
@@ -4,7 +4,7 @@
-- --
-- * Patrol AI airplanes within a given zone. -- * Patrol AI airplanes within a given zone.
-- * Trigger detected events when enemy airplanes are detected. -- * Trigger detected events when enemy airplanes are detected.
-- * Manage a fuel treshold to RTB on time. -- * Manage a fuel threshold to RTB on time.
-- * Engage the enemy when detected. -- * Engage the enemy when detected.
-- --
-- --
@@ -65,8 +65,8 @@
-- --
-- ![Process](..\Presentations\AI_CAP\Dia10.JPG) -- ![Process](..\Presentations\AI_CAP\Dia10.JPG)
-- --
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB. -- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. -- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
-- --
-- ![Process](..\Presentations\AI_CAP\Dia13.JPG) -- ![Process](..\Presentations\AI_CAP\Dia13.JPG)
-- --
@@ -96,7 +96,7 @@
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. -- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
-- * **@{#AI_CAP_ZONE.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}. -- * **@{#AI_CAP_ZONE.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
-- * **@{#AI_CAP_ZONE.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task. -- * **@{#AI_CAP_ZONE.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. -- * **Status** ( Group ): The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
-- --
-- ## 3. Set the Range of Engagement -- ## 3. Set the Range of Engagement
-- --
+4 -4
View File
@@ -49,7 +49,7 @@
-- Upon started, The AI will **Route** itself towards the random 3D point within a patrol zone, -- Upon started, The AI will **Route** itself towards the random 3D point within a patrol zone,
-- using a random speed within the given altitude and speed limits. -- using a random speed within the given altitude and speed limits.
-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits. -- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits.
-- This cycle will continue until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB. -- This cycle will continue until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
-- --
-- ![Route Event](..\Presentations\AI_CAS\Dia5.JPG) -- ![Route Event](..\Presentations\AI_CAS\Dia5.JPG)
-- --
@@ -87,7 +87,7 @@
-- It will keep patrolling there, until it is notified to RTB or move to another CAS Zone. -- It will keep patrolling there, until it is notified to RTB or move to another CAS Zone.
-- It can be notified to go RTB through the **RTB** event. -- It can be notified to go RTB through the **RTB** event.
-- --
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. -- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
-- --
-- ![Engage Event](..\Presentations\AI_CAS\Dia12.JPG) -- ![Engage Event](..\Presentations\AI_CAS\Dia12.JPG)
-- --
@@ -117,7 +117,7 @@
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. -- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
-- * **@{#AI_CAS_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}. -- * **@{#AI_CAS_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}.
-- * **@{#AI_CAS_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the CAS task. -- * **@{#AI_CAS_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the CAS task.
-- * **Status**: The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. -- * **Status**: The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
-- --
-- === -- ===
-- --
@@ -520,7 +520,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
self:SetRefreshTimeInterval( 2 ) self:SetRefreshTimeInterval( 2 )
self:SetDetectionActivated() self:SetDetectionActivated()
self:__Target( -2 ) -- Start Targetting self:__Target( -2 ) -- Start targeting
end end
end end
+14 -14
View File
@@ -4,7 +4,7 @@
-- --
-- * Patrol AI airplanes within a given zone. -- * Patrol AI airplanes within a given zone.
-- * Trigger detected events when enemy airplanes are detected. -- * Trigger detected events when enemy airplanes are detected.
-- * Manage a fuel treshold to RTB on time. -- * Manage a fuel threshold to RTB on time.
-- --
-- === -- ===
-- --
@@ -72,8 +72,8 @@
-- --
-- ![Process](..\Presentations\AI_PATROL\Dia10.JPG) -- ![Process](..\Presentations\AI_PATROL\Dia10.JPG)
-- --
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB. -- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. -- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
-- --
-- ![Process](..\Presentations\AI_PATROL\Dia11.JPG) -- ![Process](..\Presentations\AI_PATROL\Dia11.JPG)
-- --
@@ -101,7 +101,7 @@
-- * **RTB** ( Group ): Route the AI to the home base. -- * **RTB** ( Group ): Route the AI to the home base.
-- * **Detect** ( Group ): The AI is detecting targets. -- * **Detect** ( Group ): The AI is detecting targets.
-- * **Detected** ( Group ): The AI has detected new targets. -- * **Detected** ( Group ): The AI has detected new targets.
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. -- * **Status** ( Group ): The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
-- --
-- ## 3. Set or Get the AI controllable -- ## 3. Set or Get the AI controllable
-- --
@@ -133,8 +133,8 @@
-- ## 6. Manage the "out of fuel" in the AI_PATROL_ZONE -- ## 6. Manage the "out of fuel" in the AI_PATROL_ZONE
-- --
-- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base. -- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated. -- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
-- When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit, -- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit,
-- while a new AI is targetted to the AI_PATROL_ZONE. -- while a new AI is targetted to the AI_PATROL_ZONE.
-- Once the time is finished, the old AI will return to the base. -- Once the time is finished, the old AI will return to the base.
-- Use the method @{#AI_PATROL_ZONE.ManageFuel}() to have this proces in place. -- Use the method @{#AI_PATROL_ZONE.ManageFuel}() to have this proces in place.
@@ -142,7 +142,7 @@
-- ## 7. Manage "damage" behaviour of the AI in the AI_PATROL_ZONE -- ## 7. Manage "damage" behaviour of the AI in the AI_PATROL_ZONE
-- --
-- When the AI is damaged, it is required that a new AIControllable is started. However, damage cannon be foreseen early on. -- When the AI is damaged, it is required that a new AIControllable is started. However, damage cannon be foreseen early on.
-- Therefore, when the damage treshold is reached, the AI will return immediately to the home base (RTB). -- Therefore, when the damage threshold is reached, the AI will return immediately to the home base (RTB).
-- Use the method @{#AI_PATROL_ZONE.ManageDamage}() to have this proces in place. -- Use the method @{#AI_PATROL_ZONE.ManageDamage}() to have this proces in place.
-- --
-- === -- ===
@@ -581,11 +581,11 @@ function AI_PATROL_ZONE:ClearDetectedUnits()
end end
--- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base. --- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated. -- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
-- When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_PATROL_ZONE. -- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_PATROL_ZONE.
-- Once the time is finished, the old AI will return to the base. -- Once the time is finished, the old AI will return to the base.
-- @param #AI_PATROL_ZONE self -- @param #AI_PATROL_ZONE self
-- @param #number PatrolFuelThresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel. -- @param #number PatrolFuelThresholdPercentage The threshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
-- @param #number PatrolOutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base. -- @param #number PatrolOutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base.
-- @return #AI_PATROL_ZONE self -- @return #AI_PATROL_ZONE self
function AI_PATROL_ZONE:ManageFuel( PatrolFuelThresholdPercentage, PatrolOutOfFuelOrbitTime ) function AI_PATROL_ZONE:ManageFuel( PatrolFuelThresholdPercentage, PatrolOutOfFuelOrbitTime )
@@ -596,14 +596,14 @@ function AI_PATROL_ZONE:ManageFuel( PatrolFuelThresholdPercentage, PatrolOutOfFu
return self return self
end end
--- When the AI is damaged beyond a certain treshold, it is required that the AI returns to the home base. --- When the AI is damaged beyond a certain threshold, it is required that the AI returns to the home base.
-- However, damage cannot be foreseen early on. -- However, damage cannot be foreseen early on.
-- Therefore, when the damage treshold is reached, -- Therefore, when the damage threshold is reached,
-- the AI will return immediately to the home base (RTB). -- the AI will return immediately to the home base (RTB).
-- Note that for groups, the average damage of the complete group will be calculated. -- Note that for groups, the average damage of the complete group will be calculated.
-- So, in a group of 4 airplanes, 2 lost and 2 with damage 0.2, the damage treshold will be 0.25. -- So, in a group of 4 airplanes, 2 lost and 2 with damage 0.2, the damage threshold will be 0.25.
-- @param #AI_PATROL_ZONE self -- @param #AI_PATROL_ZONE self
-- @param #number PatrolDamageThreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged. -- @param #number PatrolDamageThreshold The threshold in percentage (between 0 and 1) when the AI is considered to be damaged.
-- @return #AI_PATROL_ZONE self -- @return #AI_PATROL_ZONE self
function AI_PATROL_ZONE:ManageDamage( PatrolDamageThreshold ) function AI_PATROL_ZONE:ManageDamage( PatrolDamageThreshold )
+2 -2
View File
@@ -194,7 +194,7 @@
-- * is of type `Workmaterials` -- * is of type `Workmaterials`
-- * will report when a carrier is within 500 meters -- * will report when a carrier is within 500 meters
-- * will board to carriers when the carrier is within 500 meters from the cargo object -- * will board to carriers when the carrier is within 500 meters from the cargo object
-- * will dissapear when the cargo is within 25 meters from the carrier during boarding -- * will disappear when the cargo is within 25 meters from the carrier during boarding
-- --
-- So the overall syntax of the #CARGO naming tag and arguments are: -- So the overall syntax of the #CARGO naming tag and arguments are:
-- --
@@ -220,7 +220,7 @@
-- * is of type `Workmaterials` -- * is of type `Workmaterials`
-- * will report when a carrier is within 500 meters -- * will report when a carrier is within 500 meters
-- * will board to carriers when the carrier is within 500 meters from the cargo object -- * will board to carriers when the carrier is within 500 meters from the cargo object
-- * will dissapear when the cargo is within 25 meters from the carrier during boarding -- * will disappear when the cargo is within 25 meters from the carrier during boarding
-- --
-- So the overall syntax of the #CARGO naming tag and arguments are: -- So the overall syntax of the #CARGO naming tag and arguments are:
-- --
+159 -180
View File
@@ -7,7 +7,7 @@
-- * The construction and inheritance of MOOSE classes. -- * The construction and inheritance of MOOSE classes.
-- * The class naming and numbering system. -- * The class naming and numbering system.
-- * The class hierarchy search system. -- * The class hierarchy search system.
-- * The tracing of information or objects during mission execution for debuggin purposes. -- * The tracing of information or objects during mission execution for debugging purposes.
-- * The subscription to DCS events for event handling in MOOSE objects. -- * The subscription to DCS events for event handling in MOOSE objects.
-- * Object inspection. -- * Object inspection.
-- --
@@ -49,7 +49,8 @@ local _ClassID = 0
-- # 2. Trace information for debugging. -- # 2. Trace information for debugging.
-- --
-- The BASE class contains trace methods to trace progress within a mission execution of a certain object. -- The BASE class contains trace methods to trace progress within a mission execution of a certain object.
-- These trace methods are inherited by each MOOSE class interiting BASE, soeach object created from derived class from BASE can use the tracing methods to trace its execution. -- These trace methods are inherited by each MOOSE class inheriting BASE, thus all objects created from
-- a class derived from BASE can use the tracing methods to trace its execution.
-- --
-- Any type of information can be passed to these tracing methods. See the following examples: -- Any type of information can be passed to these tracing methods. See the following examples:
-- --
@@ -111,7 +112,6 @@ local _ClassID = 0
-- --
-- The method @{#BASE.IsTrace}() will validate if tracing is activated or not. -- The method @{#BASE.IsTrace}() will validate if tracing is activated or not.
-- --
--
-- # 3. DCS simulator Event Handling. -- # 3. DCS simulator Event Handling.
-- --
-- The BASE class provides methods to catch DCS Events. These are events that are triggered from within the DCS simulator, -- The BASE class provides methods to catch DCS Events. These are events that are triggered from within the DCS simulator,
@@ -157,8 +157,6 @@ local _ClassID = 0
-- self:SmokeBlue() -- self:SmokeBlue()
-- end -- end
-- --
--
--
-- See the @{Event} module for more information about event handling. -- See the @{Event} module for more information about event handling.
-- --
-- # 4. Class identification methods. -- # 4. Class identification methods.
@@ -203,13 +201,12 @@ BASE = {
Scheduler = nil, Scheduler = nil,
} }
--- @field #BASE.__ --- @field #BASE.__
BASE.__ = {} BASE.__ = {}
--- @field #BASE._ --- @field #BASE._
BASE._ = { BASE._ = {
Schedules = {} --- Contains the Schedulers Active Schedules = {}, --- Contains the Schedulers Active
} }
--- The Formation Class --- The Formation Class
@@ -217,11 +214,9 @@ BASE._ = {
-- @field Cone A cone formation. -- @field Cone A cone formation.
FORMATION = { FORMATION = {
Cone = "Cone", Cone = "Cone",
Vee = "Vee" Vee = "Vee",
} }
--- BASE constructor. --- BASE constructor.
-- --
-- This is an example how to use the BASE:New() constructor in a new class definition when inheriting from BASE. -- This is an example how to use the BASE:New() constructor in a new class definition when inheriting from BASE.
@@ -236,16 +231,16 @@ FORMATION = {
function BASE:New() function BASE:New()
local self = routines.utils.deepCopy( self ) -- Create a new self instance local self = routines.utils.deepCopy( self ) -- Create a new self instance
_ClassID = _ClassID + 1 _ClassID = _ClassID + 1
self.ClassID = _ClassID self.ClassID = _ClassID
-- This is for "private" methods... -- This is for "private" methods...
-- When a __ is passed to a method as "self", the __index will search for the method on the public method list too! -- When a __ is passed to a method as "self", the __index will search for the method on the public method list too!
-- if rawget( self, "__" ) then -- if rawget( self, "__" ) then
--setmetatable( self, { __index = self.__ } ) -- setmetatable( self, { __index = self.__ } )
-- end -- end
return self return self
end end
--- This is the worker method to inherit from a parent class. --- This is the worker method to inherit from a parent class.
@@ -256,26 +251,25 @@ end
function BASE:Inherit( Child, Parent ) function BASE:Inherit( Child, Parent )
-- Create child. -- Create child.
local Child = routines.utils.deepCopy( Child ) local Child = routines.utils.deepCopy( Child )
if Child ~= nil then if Child ~= nil then
-- This is for "private" methods... -- This is for "private" methods...
-- When a __ is passed to a method as "self", the __index will search for the method on the public method list of the same object too! -- When a __ is passed to a method as "self", the __index will search for the method on the public method list of the same object too!
if rawget( Child, "__" ) then if rawget( Child, "__" ) then
setmetatable( Child, { __index = Child.__ } ) setmetatable( Child, { __index = Child.__ } )
setmetatable( Child.__, { __index = Parent } ) setmetatable( Child.__, { __index = Parent } )
else else
setmetatable( Child, { __index = Parent } ) setmetatable( Child, { __index = Parent } )
end end
--Child:_SetDestructor() -- Child:_SetDestructor()
end end
return Child return Child
end end
local function getParent( Child ) local function getParent( Child )
local Parent = nil local Parent = nil
@@ -291,7 +285,6 @@ local function getParent( Child )
return Parent return Parent
end end
--- This is the worker method to retrieve the Parent class. --- This is the worker method to retrieve the Parent class.
-- Note that the Parent class must be passed to call the parent class method. -- Note that the Parent class must be passed to call the parent class method.
-- --
@@ -304,19 +297,18 @@ end
-- @return #BASE -- @return #BASE
function BASE:GetParent( Child, FromClass ) function BASE:GetParent( Child, FromClass )
local Parent local Parent
-- BASE class has no parent -- BASE class has no parent
if Child.ClassName == 'BASE' then if Child.ClassName == 'BASE' then
Parent = nil Parent = nil
else else
--self:E({FromClass = FromClass}) -- self:E({FromClass = FromClass})
--self:E({Child = Child.ClassName}) -- self:E({Child = Child.ClassName})
if FromClass then if FromClass then
while( Child.ClassName ~= "BASE" and Child.ClassName ~= FromClass.ClassName ) do while (Child.ClassName ~= "BASE" and Child.ClassName ~= FromClass.ClassName) do
Child = getParent( Child ) Child = getParent( Child )
--self:E({Child.ClassName}) -- self:E({Child.ClassName})
end end
end end
if Child.ClassName == 'BASE' then if Child.ClassName == 'BASE' then
@@ -325,7 +317,7 @@ function BASE:GetParent( Child, FromClass )
Parent = getParent( Child ) Parent = getParent( Child )
end end
end end
--self:E({Parent.ClassName}) -- self:E({Parent.ClassName})
return Parent return Parent
end end
@@ -354,11 +346,11 @@ function BASE:IsInstanceOf( ClassName )
-- Get the name of the Moose class as a string -- Get the name of the Moose class as a string
ClassName = ClassName.ClassName ClassName = ClassName.ClassName
-- className is neither a string nor a Moose class, throw an error -- className is neither a string nor a Moose class, throw an error
else else
-- I'm not sure if this should take advantage of MOOSE logging function, or throw an error for pcall -- I'm not sure if this should take advantage of MOOSE logging function, or throw an error for pcall
local err_str = 'className parameter should be a string; parameter received: '..type( ClassName ) local err_str = 'className parameter should be a string; parameter received: ' .. type( ClassName )
self:E( err_str ) self:E( err_str )
-- error( err_str ) -- error( err_str )
return false return false
@@ -372,7 +364,7 @@ function BASE:IsInstanceOf( ClassName )
return true return true
end end
local Parent = getParent(self) local Parent = getParent( self )
while Parent do while Parent do
@@ -419,7 +411,6 @@ do -- Event Handling
return _EVENTDISPATCHER return _EVENTDISPATCHER
end end
--- Get the Class @{Event} processing Priority. --- Get the Class @{Event} processing Priority.
-- The Event processing Priority is a number from 1 to 10, -- The Event processing Priority is a number from 1 to 10,
-- reflecting the order of the classes subscribed to the Event to be processed. -- reflecting the order of the classes subscribed to the Event to be processed.
@@ -474,35 +465,35 @@ do -- Event Handling
-- Event handling function prototypes -- Event handling function prototypes
--- Occurs whenever any unit in a mission fires a weapon. But not any machine gun or autocannon based weapon, those are handled by EVENT.ShootingStart. --- Occurs whenever any unit in a mission fires a weapon. But not any machine gun or auto cannon based weapon, those are handled by EVENT.ShootingStart.
-- @function [parent=#BASE] OnEventShot -- @function [parent=#BASE] OnEventShot
-- @param #BASE self -- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs whenever an object is hit by a weapon. --- Occurs whenever an object is hit by a weapon.
-- initiator : The unit object the fired the weapon -- initiator : The unit object the fired the weapon.
-- weapon: Weapon object that hit the target -- weapon: Weapon object that hit the target.
-- target: The Object that was hit. -- target: The Object that was hit.
-- @function [parent=#BASE] OnEventHit -- @function [parent=#BASE] OnEventHit
-- @param #BASE self -- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when an aircraft takes off from an airbase, farp, or ship. --- Occurs when an aircraft takes off from an airbase, farp, or ship.
-- initiator : The unit that tookoff -- initiator : The unit that took off.
-- place: Object from where the AI took-off from. Can be an Airbase Object, FARP, or Ships -- place: Object from where the AI took-off from. Can be an Airbase Object, FARP, or Ships.
-- @function [parent=#BASE] OnEventTakeoff -- @function [parent=#BASE] OnEventTakeoff
-- @param #BASE self -- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when an aircraft lands at an airbase, farp or ship --- Occurs when an aircraft lands at an airbase, farp or ship
-- initiator : The unit that has landed -- initiator : The unit that has landed.
-- place: Object that the unit landed on. Can be an Airbase Object, FARP, or Ships -- place: Object that the unit landed on. Can be an Airbase Object, FARP, or Ships.
-- @function [parent=#BASE] OnEventLand -- @function [parent=#BASE] OnEventLand
-- @param #BASE self -- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when any aircraft crashes into the ground and is completely destroyed. --- Occurs when any aircraft crashes into the ground and is completely destroyed.
-- initiator : The unit that has crashed -- initiator : The unit that has crashed.
-- @function [parent=#BASE] OnEventCrash -- @function [parent=#BASE] OnEventCrash
-- @param #BASE self -- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
@@ -538,18 +529,18 @@ do -- Event Handling
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a ground unit captures either an airbase or a farp. --- Occurs when a ground unit captures either an airbase or a farp.
-- initiator : The unit that captured the base -- initiator : The unit that captured the base.
-- place: The airbase that was captured, can be a FARP or Airbase. When calling place:getCoalition() the faction will already be the new owning faction. -- place: The airbase that was captured, can be a FARP or Airbase. When calling place:getCoalition() the faction will already be the new owning faction.
-- @function [parent=#BASE] OnEventBaseCaptured -- @function [parent=#BASE] OnEventBaseCaptured
-- @param #BASE self -- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a mission starts --- Occurs when a mission starts.
-- @function [parent=#BASE] OnEventMissionStart -- @function [parent=#BASE] OnEventMissionStart
-- @param #BASE self -- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a mission ends --- Occurs when a mission ends.
-- @function [parent=#BASE] OnEventMissionEnd -- @function [parent=#BASE] OnEventMissionEnd
-- @param #BASE self -- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
@@ -561,25 +552,25 @@ do -- Event Handling
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when any object is spawned into the mission. --- Occurs when any object is spawned into the mission.
-- initiator : The unit that was spawned -- initiator : The unit that was spawned.
-- @function [parent=#BASE] OnEventBirth -- @function [parent=#BASE] OnEventBirth
-- @param #BASE self -- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when any system fails on a human controlled aircraft. --- Occurs when any system fails on a human controlled aircraft.
-- initiator : The unit that had the failure -- initiator : The unit that had the failure.
-- @function [parent=#BASE] OnEventHumanFailure -- @function [parent=#BASE] OnEventHumanFailure
-- @param #BASE self -- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when any aircraft starts its engines. --- Occurs when any aircraft starts its engines.
-- initiator : The unit that is starting its engines. -- initiator : The unit that is starting its engines..
-- @function [parent=#BASE] OnEventEngineStartup -- @function [parent=#BASE] OnEventEngineStartup
-- @param #BASE self -- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when any aircraft shuts down its engines. --- Occurs when any aircraft shuts down its engines.
-- initiator : The unit that is stopping its engines. -- initiator : The unit that is stopping its engines..
-- @function [parent=#BASE] OnEventEngineShutdown -- @function [parent=#BASE] OnEventEngineShutdown
-- @param #BASE self -- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
@@ -596,7 +587,7 @@ do -- Event Handling
-- @param #BASE self -- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when any unit begins firing a weapon that has a high rate of fire. Most common with aircraft cannons (GAU-8), autocannons, and machine guns. --- Occurs when any unit begins firing a weapon that has a high rate of fire. Most common with aircraft cannons (GAU-8), auto cannons, and machine guns.
-- initiator : The unit that is doing the shooting. -- initiator : The unit that is doing the shooting.
-- target: The unit that is being targeted. -- target: The unit that is being targeted.
-- @function [parent=#BASE] OnEventShootingStart -- @function [parent=#BASE] OnEventShootingStart
@@ -627,7 +618,6 @@ do -- Event Handling
-- @param #BASE self -- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Unknown precisely what creates this event, likely tied into newer damage model. Will update this page when new information become available. --- Unknown precisely what creates this event, likely tied into newer damage model. Will update this page when new information become available.
-- --
-- * initiator: The unit that had the failure. -- * initiator: The unit that had the failure.
@@ -644,7 +634,7 @@ do -- Event Handling
--- Occurs on the death of a unit. Contains more and different information. Similar to unit_lost it will occur for aircraft before the aircraft crash event occurs. --- Occurs on the death of a unit. Contains more and different information. Similar to unit_lost it will occur for aircraft before the aircraft crash event occurs.
-- --
-- * initiator: The unit that killed the target -- * initiator: The unit that killed the target.
-- * target: Target Object -- * target: Target Object
-- * weapon: Weapon Object -- * weapon: Weapon Object
-- --
@@ -706,7 +696,6 @@ do -- Event Handling
-- @param #BASE self -- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure. -- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a player enters a slot and takes control of an aircraft. --- Occurs when a player enters a slot and takes control of an aircraft.
-- **NOTE**: This is a workaround of a long standing DCS bug with the PLAYER_ENTER_UNIT event. -- **NOTE**: This is a workaround of a long standing DCS bug with the PLAYER_ENTER_UNIT event.
-- initiator : The unit that is being taken control of. -- initiator : The unit that is being taken control of.
@@ -716,7 +705,6 @@ do -- Event Handling
end end
--- Creation of a Birth Event. --- Creation of a Birth Event.
-- @param #BASE self -- @param #BASE self
-- @param DCS#Time EventTime The time stamp of the event. -- @param DCS#Time EventTime The time stamp of the event.
@@ -725,18 +713,18 @@ end
-- @param place -- @param place
-- @param subplace -- @param subplace
function BASE:CreateEventBirth( EventTime, Initiator, IniUnitName, place, subplace ) function BASE:CreateEventBirth( EventTime, Initiator, IniUnitName, place, subplace )
self:F( { EventTime, Initiator, IniUnitName, place, subplace } ) self:F( { EventTime, Initiator, IniUnitName, place, subplace } )
local Event = { local Event = {
id = world.event.S_EVENT_BIRTH, id = world.event.S_EVENT_BIRTH,
time = EventTime, time = EventTime,
initiator = Initiator, initiator = Initiator,
IniUnitName = IniUnitName, IniUnitName = IniUnitName,
place = place, place = place,
subplace = subplace subplace = subplace,
} }
world.onEvent( Event ) world.onEvent( Event )
end end
--- Creation of a Crash Event. --- Creation of a Crash Event.
@@ -744,15 +732,15 @@ end
-- @param DCS#Time EventTime The time stamp of the event. -- @param DCS#Time EventTime The time stamp of the event.
-- @param DCS#Object Initiator The initiating object of the event. -- @param DCS#Object Initiator The initiating object of the event.
function BASE:CreateEventCrash( EventTime, Initiator ) function BASE:CreateEventCrash( EventTime, Initiator )
self:F( { EventTime, Initiator } ) self:F( { EventTime, Initiator } )
local Event = { local Event = {
id = world.event.S_EVENT_CRASH, id = world.event.S_EVENT_CRASH,
time = EventTime, time = EventTime,
initiator = Initiator, initiator = Initiator,
} }
world.onEvent( Event ) world.onEvent( Event )
end end
--- Creation of a Dead Event. --- Creation of a Dead Event.
@@ -766,7 +754,7 @@ function BASE:CreateEventDead( EventTime, Initiator )
id = world.event.S_EVENT_DEAD, id = world.event.S_EVENT_DEAD,
time = EventTime, time = EventTime,
initiator = Initiator, initiator = Initiator,
} }
world.onEvent( Event ) world.onEvent( Event )
end end
@@ -782,7 +770,7 @@ function BASE:CreateEventRemoveUnit( EventTime, Initiator )
id = EVENTS.RemoveUnit, id = EVENTS.RemoveUnit,
time = EventTime, time = EventTime,
initiator = Initiator, initiator = Initiator,
} }
world.onEvent( Event ) world.onEvent( Event )
end end
@@ -798,56 +786,56 @@ function BASE:CreateEventTakeoff( EventTime, Initiator )
id = world.event.S_EVENT_TAKEOFF, id = world.event.S_EVENT_TAKEOFF,
time = EventTime, time = EventTime,
initiator = Initiator, initiator = Initiator,
} }
world.onEvent( Event ) world.onEvent( Event )
end end
--- Creation of a `S_EVENT_PLAYER_ENTER_AIRCRAFT` event. --- Creation of a `S_EVENT_PLAYER_ENTER_AIRCRAFT` event.
-- @param #BASE self -- @param #BASE self
-- @param Wrapper.Unit#UNIT PlayerUnit The aircraft unit the player entered. -- @param Wrapper.Unit#UNIT PlayerUnit The aircraft unit the player entered.
function BASE:CreateEventPlayerEnterAircraft( PlayerUnit ) function BASE:CreateEventPlayerEnterAircraft( PlayerUnit )
self:F( { PlayerUnit } ) self:F( { PlayerUnit } )
local Event = { local Event = {
id = EVENTS.PlayerEnterAircraft, id = EVENTS.PlayerEnterAircraft,
time = timer.getTime(), time = timer.getTime(),
initiator = PlayerUnit:GetDCSObject() initiator = PlayerUnit:GetDCSObject(),
} }
world.onEvent(Event) world.onEvent( Event )
end end
-- TODO: Complete DCS#Event structure. -- TODO: Complete DCS#Event structure.
--- The main event handling function... This function captures all events generated for the class. --- The main event handling function... This function captures all events generated for the class.
-- @param #BASE self -- @param #BASE self
-- @param DCS#Event event -- @param DCS#Event event
function BASE:onEvent(event) function BASE:onEvent( event )
if self then if self then
for EventID, EventObject in pairs(self.Events) do for EventID, EventObject in pairs( self.Events ) do
if EventObject.EventEnabled then if EventObject.EventEnabled then
if event.id == EventObject.Event then if event.id == EventObject.Event then
if self == EventObject.Self then if self == EventObject.Self then
if event.initiator and event.initiator:isExist() then if event.initiator and event.initiator:isExist() then
event.IniUnitName = event.initiator:getName() event.IniUnitName = event.initiator:getName()
end end
if event.target and event.target:isExist() then if event.target and event.target:isExist() then
event.TgtUnitName = event.target:getName() event.TgtUnitName = event.target:getName()
end end
end end
end end
end end
end end
end end
end end
do -- Scheduling do -- Scheduling
@@ -865,23 +853,23 @@ do -- Scheduling
local ObjectName = "-" local ObjectName = "-"
ObjectName = self.ClassName .. self.ClassID ObjectName = self.ClassName .. self.ClassID
self:F3( { "ScheduleOnce: ", ObjectName, Start } ) self:F3( { "ScheduleOnce: ", ObjectName, Start } )
if not self.Scheduler then if not self.Scheduler then
self.Scheduler = SCHEDULER:New( self ) self.Scheduler = SCHEDULER:New( self )
end end
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule( local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
self, self,
SchedulerFunction, SchedulerFunction,
{ ... }, { ... },
Start, Start,
nil, nil,
nil, nil,
nil nil
) )
self._.Schedules[#self._.Schedules+1] = ScheduleID self._.Schedules[#self._.Schedules + 1] = ScheduleID
return self._.Schedules[#self._.Schedules] return self._.Schedules[#self._.Schedules]
end end
@@ -909,17 +897,17 @@ do -- Scheduling
end end
local ScheduleID = self.Scheduler:Schedule( local ScheduleID = self.Scheduler:Schedule(
self, self,
SchedulerFunction, SchedulerFunction,
{ ... }, { ... },
Start, Start,
Repeat, Repeat,
RandomizeFactor, RandomizeFactor,
Stop, Stop,
4 4
) )
self._.Schedules[#self._.Schedules+1] = ScheduleID self._.Schedules[#self._.Schedules + 1] = ScheduleID
return self._.Schedules[#self._.Schedules] return self._.Schedules[#self._.Schedules]
end end
@@ -938,9 +926,8 @@ do -- Scheduling
end end
--- Set a state or property of the Object given a Key and a Value. --- Set a state or property of the Object given a Key and a Value.
-- Note that if the Object is destroyed, nillified or garbage collected, then the Values and Keys will also be gone. -- Note that if the Object is destroyed, set to nil, or garbage collected, then the Values and Keys will also be gone.
-- @param #BASE self -- @param #BASE self
-- @param Object The object that will hold the Value set by the Key. -- @param Object The object that will hold the Value set by the Key.
-- @param Key The key that is used as a reference of the value. Note that the key can be a #string, but it can also be any other type! -- @param Key The key that is used as a reference of the value. Note that the key can be a #string, but it can also be any other type!
@@ -956,9 +943,8 @@ function BASE:SetState( Object, Key, Value )
return self.States[ClassNameAndID][Key] return self.States[ClassNameAndID][Key]
end end
--- Get a Value given a Key from the Object. --- Get a Value given a Key from the Object.
-- Note that if the Object is destroyed, nillified or garbage collected, then the Values and Keys will also be gone. -- Note that if the Object is destroyed, set to nil, or garbage collected, then the Values and Keys will also be gone.
-- @param #BASE self -- @param #BASE self
-- @param Object The object that holds the Value set by the Key. -- @param Object The object that holds the Value set by the Key.
-- @param Key The key that is used to retrieve the value. Note that the key can be a #string, but it can also be any other type! -- @param Key The key that is used to retrieve the value. Note that the key can be a #string, but it can also be any other type!
@@ -1010,8 +996,6 @@ function BASE:TraceOff()
self:TraceOnOff( false ) self:TraceOnOff( false )
end end
--- Set trace on or off --- Set trace on or off
-- Note that when trace is off, no BASE.Debug statement is performed, increasing performance! -- Note that when trace is off, no BASE.Debug statement is performed, increasing performance!
-- When Moose is loaded statically, (as one file), tracing is switched off by default. -- When Moose is loaded statically, (as one file), tracing is switched off by default.
@@ -1020,28 +1004,29 @@ end
-- @param #BASE self -- @param #BASE self
-- @param #boolean TraceOnOff Switch the tracing on or off. -- @param #boolean TraceOnOff Switch the tracing on or off.
-- @usage -- @usage
-- -- Switch the tracing On
-- BASE:TraceOnOff( true )
-- --
-- -- Switch the tracing Off -- -- Switch the tracing On
-- BASE:TraceOnOff( false ) -- BASE:TraceOnOff( true )
--
-- -- Switch the tracing Off
-- BASE:TraceOnOff( false )
--
function BASE:TraceOnOff( TraceOnOff ) function BASE:TraceOnOff( TraceOnOff )
if TraceOnOff==false then if TraceOnOff == false then
self:I( "Tracing in MOOSE is OFF" ) self:I( "Tracing in MOOSE is OFF" )
_TraceOnOff = false _TraceOnOff = false
else else
self:I( "Tracing in MOOSE is ON" ) self:I( "Tracing in MOOSE is ON" )
_TraceOnOff = true _TraceOnOff = true
end end
end end
--- Enquires if tracing is on (for the class). --- Enquires if tracing is on (for the class).
-- @param #BASE self -- @param #BASE self
-- @return #boolean -- @return #boolean
function BASE:IsTrace() function BASE:IsTrace()
if BASE.Debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then if BASE.Debug and (_TraceAll == true) or (_TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName]) then
return true return true
else else
return false return false
@@ -1061,8 +1046,8 @@ end
-- @param #boolean TraceAll true = trace all methods in MOOSE. -- @param #boolean TraceAll true = trace all methods in MOOSE.
function BASE:TraceAll( TraceAll ) function BASE:TraceAll( TraceAll )
if TraceAll==false then if TraceAll == false then
_TraceAll=false _TraceAll = false
else else
_TraceAll = true _TraceAll = true
end end
@@ -1101,7 +1086,7 @@ end
-- @param Arguments A #table or any field. -- @param Arguments A #table or any field.
function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam ) function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
if BASE.Debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then if BASE.Debug and (_TraceAll == true) or (_TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName]) then
local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or BASE.Debug.getinfo( 2, "nl" ) local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or BASE.Debug.getinfo( 3, "l" ) local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or BASE.Debug.getinfo( 3, "l" )
@@ -1120,7 +1105,7 @@ function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
if DebugInfoFrom then if DebugInfoFrom then
LineFrom = DebugInfoFrom.currentline LineFrom = DebugInfoFrom.currentline
end end
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)" , LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
end end
end end
end end
@@ -1140,7 +1125,6 @@ function BASE:F( Arguments )
end end
end end
--- Trace a function call level 2. Must be at the beginning of the function logic. --- Trace a function call level 2. Must be at the beginning of the function logic.
-- @param #BASE self -- @param #BASE self
-- @param Arguments A #table or any field. -- @param Arguments A #table or any field.
@@ -1176,28 +1160,28 @@ end
-- @param Arguments A #table or any field. -- @param Arguments A #table or any field.
function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam ) function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
if BASE.Debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then if BASE.Debug and (_TraceAll == true) or (_TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName]) then
local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or BASE.Debug.getinfo( 2, "nl" ) local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or BASE.Debug.getinfo( 3, "l" ) local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or BASE.Debug.getinfo( 3, "l" )
local Function = "function" local Function = "function"
if DebugInfoCurrent.name then if DebugInfoCurrent.name then
Function = DebugInfoCurrent.name Function = DebugInfoCurrent.name
end end
if _TraceAll == true or _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName].Method[Function] then if _TraceAll == true or _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName].Method[Function] then
local LineCurrent = 0 local LineCurrent = 0
if DebugInfoCurrent.currentline then if DebugInfoCurrent.currentline then
LineCurrent = DebugInfoCurrent.currentline LineCurrent = DebugInfoCurrent.currentline
end end
local LineFrom = 0 local LineFrom = 0
if DebugInfoFrom then if DebugInfoFrom then
LineFrom = DebugInfoFrom.currentline LineFrom = DebugInfoFrom.currentline
end end
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s" , LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) ) env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s", LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
end end
end end
end end
--- Trace a function logic level 1. Can be anywhere within the function logic. --- Trace a function logic level 1. Can be anywhere within the function logic.
@@ -1215,7 +1199,6 @@ function BASE:T( Arguments )
end end
end end
--- Trace a function logic level 2. Can be anywhere within the function logic. --- Trace a function logic level 2. Can be anywhere within the function logic.
-- @param #BASE self -- @param #BASE self
-- @param Arguments A #table or any field. -- @param Arguments A #table or any field.
@@ -1252,28 +1235,27 @@ end
function BASE:E( Arguments ) function BASE:E( Arguments )
if BASE.Debug then if BASE.Debug then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" ) local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" ) local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
local Function = "function" local Function = "function"
if DebugInfoCurrent.name then if DebugInfoCurrent.name then
Function = DebugInfoCurrent.name Function = DebugInfoCurrent.name
end end
local LineCurrent = DebugInfoCurrent.currentline local LineCurrent = DebugInfoCurrent.currentline
local LineFrom = -1 local LineFrom = -1
if DebugInfoFrom then if DebugInfoFrom then
LineFrom = DebugInfoFrom.currentline LineFrom = DebugInfoFrom.currentline
end end
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
else else
env.info( string.format( "%1s:%30s%05d(%s)" , "E", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) ) env.info( string.format( "%1s:%30s%05d(%s)", "E", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
end end
end end
--- Log an information which will be traced always. Can be anywhere within the function logic. --- Log an information which will be traced always. Can be anywhere within the function logic.
-- @param #BASE self -- @param #BASE self
-- @param Arguments A #table or any field. -- @param Arguments A #table or any field.
@@ -1294,26 +1276,23 @@ function BASE:I( Arguments )
LineFrom = DebugInfoFrom.currentline LineFrom = DebugInfoFrom.currentline
end end
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)" , LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
else else
env.info( string.format( "%1s:%30s%05d(%s)" , "I", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) ) env.info( string.format( "%1s:%30s%05d(%s)", "I", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
end end
end end
--- old stuff --- old stuff
--function BASE:_Destructor() -- function BASE:_Destructor()
-- --self:E("_Destructor") -- --self:E("_Destructor")
-- --
-- --self:EventRemoveAll() -- --self:EventRemoveAll()
--end -- end
-- THIS IS WHY WE NEED LUA 5.2 ... -- THIS IS WHY WE NEED LUA 5.2 ...
--function BASE:_SetDestructor() -- function BASE:_SetDestructor()
-- --
-- -- TODO: Okay, this is really technical... -- -- TODO: Okay, this is really technical...
-- -- When you set a proxy to a table to catch __gc, weak tables don't behave like weak... -- -- When you set a proxy to a table to catch __gc, weak tables don't behave like weak...
@@ -1334,4 +1313,4 @@ end
-- -- will be invoked and the destructor called -- -- will be invoked and the destructor called
-- rawset( self, '__proxy', proxy ) -- rawset( self, '__proxy', proxy )
-- --
--end -- end
+83 -84
View File
@@ -36,9 +36,9 @@
-- @field Wrapper.Controllable#CONTROLLABLE Positionable The @{#CONTROLLABLE} that will receive radio capabilities. -- @field Wrapper.Controllable#CONTROLLABLE Positionable The @{#CONTROLLABLE} that will receive radio capabilities.
-- @extends Core.Base#BASE -- @extends Core.Base#BASE
BEACON = { BEACON = {
ClassName = "BEACON", ClassName = "BEACON",
Positionable = nil, Positionable = nil,
name = nil, name = nil,
} }
--- Beacon types supported by DCS. --- Beacon types supported by DCS.
@@ -95,11 +95,11 @@ BEACON.Type={
-- @field #number TACAN TACtical Air Navigation system on ground. -- @field #number TACAN TACtical Air Navigation system on ground.
-- @field #number TACAN_TANKER_X TACtical Air Navigation system for tankers on X band. -- @field #number TACAN_TANKER_X TACtical Air Navigation system for tankers on X band.
-- @field #number TACAN_TANKER_Y TACtical Air Navigation system for tankers on Y band. -- @field #number TACAN_TANKER_Y TACtical Air Navigation system for tankers on Y band.
-- @field #number VOR Very High Frequency Omni-Directional Range -- @field #number VOR Very High Frequency Omnidirectional Range
-- @field #number ILS_LOCALIZER ILS localizer -- @field #number ILS_LOCALIZER ILS localizer
-- @field #number ILS_GLIDESLOPE ILS glideslope. -- @field #number ILS_GLIDESLOPE ILS glide slope.
-- @field #number PRGM_LOCALIZER PRGM localizer. -- @field #number PRGM_LOCALIZER PRGM localizer.
-- @field #number PRGM_GLIDESLOPE PRGM glideslope. -- @field #number PRGM_GLIDESLOPE PRGM glide slope.
-- @field #number BROADCAST_STATION Broadcast station. -- @field #number BROADCAST_STATION Broadcast station.
-- @field #number VORTAC Radio-based navigational aid for aircraft pilots consisting of a co-located VHF omnidirectional range (VOR) beacon and a tactical air navigation system (TACAN) beacon. -- @field #number VORTAC Radio-based navigational aid for aircraft pilots consisting of a co-located VHF omnidirectional range (VOR) beacon and a tactical air navigation system (TACAN) beacon.
-- @field #number TACAN_AA_MODE_X TACtical Air Navigation for aircraft on X band. -- @field #number TACAN_AA_MODE_X TACtical Air Navigation for aircraft on X band.
@@ -131,28 +131,27 @@ BEACON.System={
-- If you want to create a BEACON, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetBeacon}() instead. -- If you want to create a BEACON, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetBeacon}() instead.
-- @param #BEACON self -- @param #BEACON self
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities. -- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities.
-- @return #BEACON Beacon object or #nil if the positionable is invalid. -- @return #BEACON Beacon object or #nil if the POSITIONABLE is invalid.
function BEACON:New(Positionable) function BEACON:New( Positionable )
-- Inherit BASE. -- Inherit BASE.
local self=BASE:Inherit(self, BASE:New()) --#BEACON local self = BASE:Inherit( self, BASE:New() ) -- #BEACON
-- Debug. -- Debug.
self:F(Positionable) self:F( Positionable )
-- Set positionable. -- Set positionable.
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure positionable is valid if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure POSITIONABLE is valid
self.Positionable = Positionable self.Positionable = Positionable
self.name=Positionable:GetName() self.name = Positionable:GetName()
self:I(string.format("New BEACON %s", tostring(self.name))) self:I( string.format( "New BEACON %s", tostring( self.name ) ) )
return self return self
end end
self:E({"The passed positionable is invalid, no BEACON created", Positionable}) self:E( { "The passed POSITIONABLE is invalid, no BEACON created", Positionable } )
return nil return nil
end end
--- Activates a TACAN BEACON. --- Activates a TACAN BEACON.
-- @param #BEACON self -- @param #BEACON self
-- @param #number Channel TACAN channel, i.e. the "10" part in "10Y". -- @param #number Channel TACAN channel, i.e. the "10" part in "10Y".
@@ -162,51 +161,53 @@ end
-- @param #number Duration How long will the beacon last in seconds. Omit for forever. -- @param #number Duration How long will the beacon last in seconds. Omit for forever.
-- @return #BEACON self -- @return #BEACON self
-- @usage -- @usage
--
-- -- Let's create a TACAN Beacon for a tanker -- -- Let's create a TACAN Beacon for a tanker
-- local myUnit = UNIT:FindByName("MyUnit") -- local myUnit = UNIT:FindByName("MyUnit")
-- local myBeacon = myUnit:GetBeacon() -- Creates the beacon -- local myBeacon = myUnit:GetBeacon() -- Creates the beacon
-- --
-- myBeacon:ActivateTACAN(20, "Y", "TEXACO", true) -- Activate the beacon -- myBeacon:ActivateTACAN(20, "Y", "TEXACO", true) -- Activate the beacon
function BEACON:ActivateTACAN(Channel, Mode, Message, Bearing, Duration) --
self:T({channel=Channel, mode=Mode, callsign=Message, bearing=Bearing, duration=Duration}) function BEACON:ActivateTACAN( Channel, Mode, Message, Bearing, Duration )
self:T( { channel = Channel, mode = Mode, callsign = Message, bearing = Bearing, duration = Duration } )
-- Get frequency. -- Get frequency.
local Frequency=UTILS.TACANToFrequency(Channel, Mode) local Frequency = UTILS.TACANToFrequency( Channel, Mode )
-- Check. -- Check.
if not Frequency then if not Frequency then
self:E({"The passed TACAN channel is invalid, the BEACON is not emitting"}) self:E( { "The passed TACAN channel is invalid, the BEACON is not emitting" } )
return self return self
end end
-- Beacon type. -- Beacon type.
local Type=BEACON.Type.TACAN local Type = BEACON.Type.TACAN
-- Beacon system. -- Beacon system.
local System=BEACON.System.TACAN local System = BEACON.System.TACAN
-- Check if unit is an aircraft and set system accordingly. -- Check if unit is an aircraft and set system accordingly.
local AA=self.Positionable:IsAir() local AA = self.Positionable:IsAir()
if AA then if AA then
System=5 --NOTE: 5 is how you cat the correct tanker behaviour! --BEACON.System.TACAN_TANKER System = 5 -- NOTE: 5 is how you cat the correct tanker behaviour! --BEACON.System.TACAN_TANKER
-- Check if "Y" mode is selected for aircraft. -- Check if "Y" mode is selected for aircraft.
if Mode~="Y" then if Mode ~= "Y" then
self:E({"WARNING: The POSITIONABLE you want to attach the AA Tacan Beacon is an aircraft: Mode should Y !The BEACON is not emitting.", self.Positionable}) self:E( { "WARNING: The POSITIONABLE you want to attach the AA TACAN Beacon is an aircraft: Mode should Y! The BEACON is not emitting.", self.Positionable } )
end end
end end
-- Attached unit. -- Attached unit.
local UnitID=self.Positionable:GetID() local UnitID = self.Positionable:GetID()
-- Debug. -- Debug.
self:I({string.format("BEACON Activating TACAN %s: Channel=%d%s, Morse=%s, Bearing=%s, Duration=%s!", tostring(self.name), Channel, Mode, Message, tostring(Bearing), tostring(Duration))}) self:I( { string.format( "BEACON Activating TACAN %s: Channel=%d%s, Morse=%s, Bearing=%s, Duration=%s!", tostring( self.name ), Channel, Mode, Message, tostring( Bearing ), tostring( Duration ) ) } )
-- Start beacon. -- Start beacon.
self.Positionable:CommandActivateBeacon(Type, System, Frequency, UnitID, Channel, Mode, AA, Message, Bearing) self.Positionable:CommandActivateBeacon( Type, System, Frequency, UnitID, Channel, Mode, AA, Message, Bearing )
-- Stop sheduler. -- Stop scheduler.
if Duration then if Duration then
self.Positionable:DeactivateBeacon(Duration) self.Positionable:DeactivateBeacon( Duration )
end end
return self return self
@@ -218,21 +219,21 @@ end
-- @param #string Callsign The Message that is going to be coded in Morse and broadcasted by the beacon. -- @param #string Callsign The Message that is going to be coded in Morse and broadcasted by the beacon.
-- @param #number Duration How long will the beacon last in seconds. Omit for forever. -- @param #number Duration How long will the beacon last in seconds. Omit for forever.
-- @return #BEACON self -- @return #BEACON self
function BEACON:ActivateICLS(Channel, Callsign, Duration) function BEACON:ActivateICLS( Channel, Callsign, Duration )
self:F({Channel=Channel, Callsign=Callsign, Duration=Duration}) self:F( { Channel = Channel, Callsign = Callsign, Duration = Duration } )
-- Attached unit. -- Attached unit.
local UnitID=self.Positionable:GetID() local UnitID = self.Positionable:GetID()
-- Debug -- Debug
self:T2({"ICLS BEACON started!"}) self:T2( { "ICLS BEACON started!" } )
-- Start beacon. -- Start beacon.
self.Positionable:CommandActivateICLS(Channel, UnitID, Callsign) self.Positionable:CommandActivateICLS( Channel, UnitID, Callsign )
-- Stop sheduler -- Stop scheduler
if Duration then -- Schedule the stop of the BEACON if asked by the MD if Duration then -- Schedule the stop of the BEACON if asked by the MD
self.Positionable:DeactivateBeacon(Duration) self.Positionable:DeactivateBeacon( Duration )
end end
return self return self
@@ -246,24 +247,26 @@ end
-- @param #number BeaconDuration How long will the beacon last in seconds. Omit for forever. -- @param #number BeaconDuration How long will the beacon last in seconds. Omit for forever.
-- @return #BEACON self -- @return #BEACON self
-- @usage -- @usage
--
-- -- Let's create a TACAN Beacon for a tanker -- -- Let's create a TACAN Beacon for a tanker
-- local myUnit = UNIT:FindByName("MyUnit") -- local myUnit = UNIT:FindByName("MyUnit")
-- local myBeacon = myUnit:GetBeacon() -- Creates the beacon -- local myBeacon = myUnit:GetBeacon() -- Creates the beacon
-- --
-- myBeacon:AATACAN(20, "TEXACO", true) -- Activate the beacon -- myBeacon:AATACAN(20, "TEXACO", true) -- Activate the beacon
function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration) --
self:F({TACANChannel, Message, Bearing, BeaconDuration}) function BEACON:AATACAN( TACANChannel, Message, Bearing, BeaconDuration )
self:F( { TACANChannel, Message, Bearing, BeaconDuration } )
local IsValid = true local IsValid = true
if not self.Positionable:IsAir() then if not self.Positionable:IsAir() then
self:E({"The POSITIONABLE you want to attach the AA Tacan Beacon is not an aircraft ! The BEACON is not emitting", self.Positionable}) self:E( { "The POSITIONABLE you want to attach the AA TACAN Beacon is not an aircraft! The BEACON is not emitting", self.Positionable } )
IsValid = false IsValid = false
end end
local Frequency = self:_TACANToFrequency(TACANChannel, "Y") local Frequency = self:_TACANToFrequency( TACANChannel, "Y" )
if not Frequency then if not Frequency then
self:E({"The passed TACAN channel is invalid, the BEACON is not emitting"}) self:E( { "The passed TACAN channel is invalid, the BEACON is not emitting" } )
IsValid = false IsValid = false
end end
@@ -277,22 +280,21 @@ function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
end end
if IsValid then -- Starts the BEACON if IsValid then -- Starts the BEACON
self:T2({"AA TACAN BEACON started !"}) self:T2( { "AA TACAN BEACON started !" } )
self.Positionable:SetCommand({ self.Positionable:SetCommand( {
id = "ActivateBeacon", id = "ActivateBeacon",
params = { params = {
type = 4, type = 4,
system = System, system = System,
callsign = Message, callsign = Message,
frequency = Frequency, frequency = Frequency,
} },
}) } )
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
SCHEDULER:New(nil, SCHEDULER:New( nil, function()
function()
self:StopAATACAN() self:StopAATACAN()
end, {}, BeaconDuration) end, {}, BeaconDuration )
end end
end end
@@ -305,18 +307,16 @@ end
function BEACON:StopAATACAN() function BEACON:StopAATACAN()
self:F() self:F()
if not self.Positionable then if not self.Positionable then
self:E({"Start the beacon first before stoping it !"}) self:E( { "Start the beacon first before stopping it!" } )
else else
self.Positionable:SetCommand({ self.Positionable:SetCommand( {
id = 'DeactivateBeacon', id = 'DeactivateBeacon',
params = { params = {},
} } )
})
end end
end end
--- Activates a general purpose Radio Beacon
--- Activates a general pupose Radio Beacon
-- This uses the very generic singleton function "trigger.action.radioTransmission()" provided by DCS to broadcast a sound file on a specific frequency. -- This uses the very generic singleton function "trigger.action.radioTransmission()" provided by DCS to broadcast a sound file on a specific frequency.
-- Although any frequency could be used, only 2 DCS Modules can home on radio beacons at the time of writing : the Huey and the Mi-8. -- Although any frequency could be used, only 2 DCS Modules can home on radio beacons at the time of writing : the Huey and the Mi-8.
-- They can home in on these specific frequencies : -- They can home in on these specific frequencies :
@@ -342,54 +342,53 @@ end
-- --
-- -- Set the beacon and start it -- -- Set the beacon and start it
-- UnitBeacon:RadioBeacon("MySoundFileSOS.ogg", 40, radio.modulation.FM, 20, 5*60) -- UnitBeacon:RadioBeacon("MySoundFileSOS.ogg", 40, radio.modulation.FM, 20, 5*60)
function BEACON:RadioBeacon(FileName, Frequency, Modulation, Power, BeaconDuration) function BEACON:RadioBeacon( FileName, Frequency, Modulation, Power, BeaconDuration )
self:F({FileName, Frequency, Modulation, Power, BeaconDuration}) self:F( { FileName, Frequency, Modulation, Power, BeaconDuration } )
local IsValid = false local IsValid = false
-- Check the filename -- Check the filename
if type(FileName) == "string" then if type( FileName ) == "string" then
if FileName:find(".ogg") or FileName:find(".wav") then if FileName:find( ".ogg" ) or FileName:find( ".wav" ) then
if not FileName:find("l10n/DEFAULT/") then if not FileName:find( "l10n/DEFAULT/" ) then
FileName = "l10n/DEFAULT/" .. FileName FileName = "l10n/DEFAULT/" .. FileName
end end
IsValid = true IsValid = true
end end
end end
if not IsValid then if not IsValid then
self:E({"File name invalid. Maybe something wrong with the extension ? ", FileName}) self:E( { "File name invalid. Maybe something wrong with the extension? ", FileName } )
end end
-- Check the Frequency -- Check the Frequency
if type(Frequency) ~= "number" and IsValid then if type( Frequency ) ~= "number" and IsValid then
self:E({"Frequency invalid. ", Frequency}) self:E( { "Frequency invalid. ", Frequency } )
IsValid = false IsValid = false
end end
Frequency = Frequency * 1000000 -- Conversion to Hz Frequency = Frequency * 1000000 -- Conversion to Hz
-- Check the modulation -- Check the modulation
if Modulation ~= radio.modulation.AM and Modulation ~= radio.modulation.FM and IsValid then --TODO Maybe make this future proof if ED decides to add an other modulation ? if Modulation ~= radio.modulation.AM and Modulation ~= radio.modulation.FM and IsValid then -- TODO: Maybe make this future proof if ED decides to add an other modulation ?
self:E({"Modulation is invalid. Use DCS's enum radio.modulation.", Modulation}) self:E( { "Modulation is invalid. Use DCS's enum radio.modulation.", Modulation } )
IsValid = false IsValid = false
end end
-- Check the Power -- Check the Power
if type(Power) ~= "number" and IsValid then if type( Power ) ~= "number" and IsValid then
self:E({"Power is invalid. ", Power}) self:E( { "Power is invalid. ", Power } )
IsValid = false IsValid = false
end end
Power = math.floor(math.abs(Power)) --TODO Find what is the maximum power allowed by DCS and limit power to that Power = math.floor( math.abs( Power ) ) -- TODO: Find what is the maximum power allowed by DCS and limit power to that
if IsValid then if IsValid then
self:T2({"Activating Beacon on ", Frequency, Modulation}) self:T2( { "Activating Beacon on ", Frequency, Modulation } )
-- Note that this is looped. I have to give this transmission a unique name, I use the class ID -- Note that this is looped. I have to give this transmission a unique name, I use the class ID
trigger.action.radioTransmission(FileName, self.Positionable:GetPositionVec3(), Modulation, true, Frequency, Power, tostring(self.ID)) trigger.action.radioTransmission( FileName, self.Positionable:GetPositionVec3(), Modulation, true, Frequency, Power, tostring( self.ID ) )
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
SCHEDULER:New( nil, SCHEDULER:New( nil, function()
function() self:StopRadioBeacon()
self:StopRadioBeacon() end, {}, BeaconDuration )
end, {}, BeaconDuration) end
end
end end
end end
@@ -399,7 +398,7 @@ end
function BEACON:StopRadioBeacon() function BEACON:StopRadioBeacon()
self:F() self:F()
-- The unique name of the transmission is the class ID -- The unique name of the transmission is the class ID
trigger.action.stopRadioTransmission(tostring(self.ID)) trigger.action.stopRadioTransmission( tostring( self.ID ) )
return self return self
end end
@@ -407,21 +406,21 @@ end
-- @param #BEACON self -- @param #BEACON self
-- @param #number TACANChannel -- @param #number TACANChannel
-- @param #string TACANMode -- @param #string TACANMode
-- @return #number Frequecy -- @return #number Frequency
-- @return #nil if parameters are invalid -- @return #nil if parameters are invalid
function BEACON:_TACANToFrequency(TACANChannel, TACANMode) function BEACON:_TACANToFrequency( TACANChannel, TACANMode )
self:F3({TACANChannel, TACANMode}) self:F3( { TACANChannel, TACANMode } )
if type(TACANChannel) ~= "number" then if type( TACANChannel ) ~= "number" then
if TACANMode ~= "X" and TACANMode ~= "Y" then if TACANMode ~= "X" and TACANMode ~= "Y" then
return nil -- error in arguments return nil -- error in arguments
end end
end end
-- This code is largely based on ED's code, in DCS World\Scripts\World\Radio\BeaconTypes.lua, line 137. -- This code is largely based on ED's code, in DCS World\Scripts\World\Radio\BeaconTypes.lua, line 137.
-- I have no idea what it does but it seems to work -- I have no idea what it does but it seems to work
local A = 1151 -- 'X', channel >= 64 local A = 1151 -- 'X', channel >= 64
local B = 64 -- channel >= 64 local B = 64 -- channel >= 64
if TACANChannel < 64 then if TACANChannel < 64 then
B = 1 B = 1
File diff suppressed because it is too large Load Diff
+90 -108
View File
@@ -14,7 +14,7 @@
-- ![Objects](..\Presentations\EVENT\Dia2.JPG) -- ![Objects](..\Presentations\EVENT\Dia2.JPG)
-- --
-- Within a running mission, various DCS events occur. Units are dynamically created, crash, die, shoot stuff, get hit etc. -- Within a running mission, various DCS events occur. Units are dynamically created, crash, die, shoot stuff, get hit etc.
-- This module provides a mechanism to dispatch those events occuring within your running mission, to the different objects orchestrating your mission. -- This module provides a mechanism to dispatch those events occurring within your running mission, to the different objects orchestrating your mission.
-- --
-- ![Objects](..\Presentations\EVENT\Dia3.JPG) -- ![Objects](..\Presentations\EVENT\Dia3.JPG)
-- --
@@ -32,11 +32,11 @@
-- --
-- ![Objects](..\Presentations\EVENT\Dia5.JPG) -- ![Objects](..\Presentations\EVENT\Dia5.JPG)
-- --
-- There are 5 levels of kind of objects that the _EVENTDISPATCHER services: -- There are 5 types/levels of objects that the _EVENTDISPATCHER services:
-- --
-- * _DATABASE object: The core of the MOOSE objects. Any object that is created, deleted or updated, is done in this database. -- * _DATABASE object: The core of the MOOSE objects. Any object that is created, deleted or updated, is done in this database.
-- * SET_ derived classes: Subsets of the _DATABASE object. These subsets are updated by the _EVENTDISPATCHER as the second priority. -- * SET_ derived classes: These are subsets of the _DATABASE object. These subsets are updated by the _EVENTDISPATCHER as the second priority.
-- * UNIT objects: UNIT objects can subscribe to DCS events. Each DCS event will be directly published to teh subscribed UNIT object. -- * UNIT objects: UNIT objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed UNIT object.
-- * GROUP objects: GROUP objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed GROUP object. -- * GROUP objects: GROUP objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed GROUP object.
-- * Any other object: Various other objects can subscribe to DCS events. Each DCS event triggered will be published to each subscribed object. -- * Any other object: Various other objects can subscribe to DCS events. Each DCS event triggered will be published to each subscribed object.
-- --
@@ -131,6 +131,8 @@
-- * Weapon data: Certain events populate weapon information. -- * Weapon data: Certain events populate weapon information.
-- * Place data: Certain events populate place information. -- * Place data: Certain events populate place information.
-- --
-- Example code snippet:
--
-- --- This function is an Event Handling function that will be called when Tank1 is Dead. -- --- This function is an Event Handling function that will be called when Tank1 is Dead.
-- -- EventData is an EVENTDATA structure. -- -- EventData is an EVENTDATA structure.
-- -- We use the EventData.IniUnit to smoke the tank Green. -- -- We use the EventData.IniUnit to smoke the tank Green.
@@ -141,7 +143,6 @@
-- EventData.IniUnit:SmokeGreen() -- EventData.IniUnit:SmokeGreen()
-- end -- end
-- --
--
-- Find below an overview which events populate which information categories: -- Find below an overview which events populate which information categories:
-- --
-- ![Objects](..\Presentations\EVENT\Dia14.JPG) -- ![Objects](..\Presentations\EVENT\Dia14.JPG)
@@ -151,6 +152,7 @@
-- In case a STATIC object is involved, the documentation indicates which fields will and won't not be populated. -- In case a STATIC object is involved, the documentation indicates which fields will and won't not be populated.
-- The fields **IniObjectCategory** and **TgtObjectCategory** contain the indicator which **kind of object is involved** in the event. -- The fields **IniObjectCategory** and **TgtObjectCategory** contain the indicator which **kind of object is involved** in the event.
-- You can use the enumerator **Object.Category.UNIT** and **Object.Category.STATIC** to check on IniObjectCategory and TgtObjectCategory. -- You can use the enumerator **Object.Category.UNIT** and **Object.Category.STATIC** to check on IniObjectCategory and TgtObjectCategory.
--
-- Example code snippet: -- Example code snippet:
-- --
-- if Event.IniObjectCategory == Object.Category.UNIT then -- if Event.IniObjectCategory == Object.Category.UNIT then
@@ -172,7 +174,6 @@
-- @module Core.Event -- @module Core.Event
-- @image Core_Event.JPG -- @image Core_Event.JPG
--- @type EVENT --- @type EVENT
-- @field #EVENT.Events Events -- @field #EVENT.Events Events
-- @extends Core.Base#BASE -- @extends Core.Base#BASE
@@ -194,7 +195,6 @@ 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_REMOVE_UNIT = world.event.S_EVENT_MAX + 1006
world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT = world.event.S_EVENT_MAX + 1007 world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT = world.event.S_EVENT_MAX + 1007
--- The different types of events supported by MOOSE. --- The different types of events supported by MOOSE.
-- Use this structure to subscribe to events using the @{Core.Base#BASE.HandleEvent}() method. -- Use this structure to subscribe to events using the @{Core.Base#BASE.HandleEvent}() method.
-- @type EVENTS -- @type EVENTS
@@ -227,13 +227,13 @@ EVENTS = {
MarkChange = world.event.S_EVENT_MARK_CHANGE, MarkChange = world.event.S_EVENT_MARK_CHANGE,
MarkRemoved = world.event.S_EVENT_MARK_REMOVED, MarkRemoved = world.event.S_EVENT_MARK_REMOVED,
-- Moose Events -- Moose Events
NewCargo = world.event.S_EVENT_NEW_CARGO, NewCargo = world.event.S_EVENT_NEW_CARGO,
DeleteCargo = world.event.S_EVENT_DELETE_CARGO, DeleteCargo = world.event.S_EVENT_DELETE_CARGO,
NewZone = world.event.S_EVENT_NEW_ZONE, NewZone = world.event.S_EVENT_NEW_ZONE,
DeleteZone = world.event.S_EVENT_DELETE_ZONE, DeleteZone = world.event.S_EVENT_DELETE_ZONE,
NewZoneGoal = world.event.S_EVENT_NEW_ZONE_GOAL, NewZoneGoal = world.event.S_EVENT_NEW_ZONE_GOAL,
DeleteZoneGoal = world.event.S_EVENT_DELETE_ZONE_GOAL, DeleteZoneGoal = world.event.S_EVENT_DELETE_ZONE_GOAL,
RemoveUnit = world.event.S_EVENT_REMOVE_UNIT, RemoveUnit = world.event.S_EVENT_REMOVE_UNIT,
PlayerEnterAircraft = world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT, PlayerEnterAircraft = world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT,
-- Added with DCS 2.5.6 -- Added with DCS 2.5.6
DetailedFailure = world.event.S_EVENT_DETAILED_FAILURE or -1, --We set this to -1 for backward compatibility to DCS 2.5.5 and earlier DetailedFailure = world.event.S_EVENT_DETAILED_FAILURE or -1, --We set this to -1 for backward compatibility to DCS 2.5.5 and earlier
@@ -304,8 +304,6 @@ EVENTS = {
-- @field Core.ZONE#ZONE Zone The zone object. -- @field Core.ZONE#ZONE Zone The zone object.
-- @field #string ZoneName The name of the zone. -- @field #string ZoneName The name of the zone.
local _EVENTMETA = { local _EVENTMETA = {
[world.event.S_EVENT_SHOT] = { [world.event.S_EVENT_SHOT] = {
Order = 1, Order = 1,
@@ -562,7 +560,6 @@ local _EVENTMETA = {
}, },
} }
--- The Events structure --- The Events structure
-- @type EVENT.Events -- @type EVENT.Events
-- @field #number IniUnit -- @field #number IniUnit
@@ -576,12 +573,11 @@ function EVENT:New()
local self = BASE:Inherit( self, BASE:New() ) local self = BASE:Inherit( self, BASE:New() )
-- Add world event handler. -- Add world event handler.
self.EventHandler = world.addEventHandler(self) self.EventHandler = world.addEventHandler( self )
return self return self
end end
--- Initializes the Events structure for the event. --- Initializes the Events structure for the event.
-- @param #EVENT self -- @param #EVENT self
-- @param DCS#world.event EventID Event ID. -- @param DCS#world.event EventID Event ID.
@@ -595,7 +591,7 @@ function EVENT:Init( EventID, EventClass )
self.Events[EventID] = {} self.Events[EventID] = {}
end end
-- Each event has a subtable of EventClasses, ordered by EventPriority. -- Each event has a sub-table of EventClasses, ordered by EventPriority.
local EventPriority = EventClass:GetEventPriority() local EventPriority = EventClass:GetEventPriority()
if not self.Events[EventID][EventPriority] then if not self.Events[EventID][EventPriority] then
@@ -603,7 +599,7 @@ function EVENT:Init( EventID, EventClass )
end end
if not self.Events[EventID][EventPriority][EventClass] then if not self.Events[EventID][EventPriority][EventClass] then
self.Events[EventID][EventPriority][EventClass] = {} self.Events[EventID][EventPriority][EventClass] = {}
end end
return self.Events[EventID][EventPriority][EventClass] return self.Events[EventID][EventPriority][EventClass]
@@ -614,7 +610,7 @@ end
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is. -- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
-- @param DCS#world.event EventID Event ID. -- @param DCS#world.event EventID Event ID.
-- @return #EVENT self -- @return #EVENT self
function EVENT:RemoveEvent( EventClass, EventID ) function EVENT:RemoveEvent( EventClass, EventID )
-- Debug info. -- Debug info.
self:F2( { "Removing subscription for class: ", EventClass:GetClassNameAndID() } ) self:F2( { "Removing subscription for class: ", EventClass:GetClassNameAndID() } )
@@ -638,7 +634,7 @@ end
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is. -- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
-- @param DCS#world.event EventID Event ID. -- @param DCS#world.event EventID Event ID.
-- @return #EVENT.Events -- @return #EVENT.Events
function EVENT:Reset( EventObject ) --R2.1 function EVENT:Reset( EventObject ) -- R2.1
self:F( { "Resetting subscriptions for class: ", EventObject:GetClassNameAndID() } ) self:F( { "Resetting subscriptions for class: ", EventObject:GetClassNameAndID() } )
@@ -657,12 +653,11 @@ function EVENT:Reset( EventObject ) --R2.1
end end
end end
--- Clears all event subscriptions for a @{Core.Base#BASE} derived object. --- Clears all event subscriptions for a @{Core.Base#BASE} derived object.
-- @param #EVENT self -- @param #EVENT self
-- @param Core.Base#BASE EventClass The self class object for which the events are removed. -- @param Core.Base#BASE EventClass The self class object for which the events are removed.
-- @return #EVENT self -- @return #EVENT self
function EVENT:RemoveAll(EventClass) function EVENT:RemoveAll( EventClass )
local EventClassName = EventClass:GetClassNameAndID() local EventClassName = EventClass:GetClassNameAndID()
@@ -676,8 +671,6 @@ function EVENT:RemoveAll(EventClass)
return self return self
end end
--- Create an OnDead event handler for a group --- Create an OnDead event handler for a group
-- @param #EVENT self -- @param #EVENT self
-- @param #table EventTemplate -- @param #table EventTemplate
@@ -709,7 +702,6 @@ function EVENT:OnEventGeneric( EventFunction, EventClass, EventID )
return self return self
end end
--- Set a new listener for an `S_EVENT_X` event for a UNIT. --- Set a new listener for an `S_EVENT_X` event for a UNIT.
-- @param #EVENT self -- @param #EVENT self
-- @param #string UnitName The name of the UNIT. -- @param #string UnitName The name of the UNIT.
@@ -797,7 +789,6 @@ do -- OnDead
end end
do -- OnLand do -- OnLand
--- Create an OnLand event handler for a group --- Create an OnLand event handler for a group
@@ -864,7 +855,7 @@ do -- Event Creation
id = EVENTS.NewCargo, id = EVENTS.NewCargo,
time = timer.getTime(), time = timer.getTime(),
cargo = Cargo, cargo = Cargo,
} }
world.onEvent( Event ) world.onEvent( Event )
end end
@@ -879,7 +870,7 @@ do -- Event Creation
id = EVENTS.DeleteCargo, id = EVENTS.DeleteCargo,
time = timer.getTime(), time = timer.getTime(),
cargo = Cargo, cargo = Cargo,
} }
world.onEvent( Event ) world.onEvent( Event )
end end
@@ -894,7 +885,7 @@ do -- Event Creation
id = EVENTS.NewZone, id = EVENTS.NewZone,
time = timer.getTime(), time = timer.getTime(),
zone = Zone, zone = Zone,
} }
world.onEvent( Event ) world.onEvent( Event )
end end
@@ -909,7 +900,7 @@ do -- Event Creation
id = EVENTS.DeleteZone, id = EVENTS.DeleteZone,
time = timer.getTime(), time = timer.getTime(),
zone = Zone, zone = Zone,
} }
world.onEvent( Event ) world.onEvent( Event )
end end
@@ -924,12 +915,11 @@ do -- Event Creation
id = EVENTS.NewZoneGoal, id = EVENTS.NewZoneGoal,
time = timer.getTime(), time = timer.getTime(),
ZoneGoal = ZoneGoal, ZoneGoal = ZoneGoal,
} }
world.onEvent( Event ) world.onEvent( Event )
end end
--- Creation of a ZoneGoal Deletion Event. --- Creation of a ZoneGoal Deletion Event.
-- @param #EVENT self -- @param #EVENT self
-- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created. -- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created.
@@ -940,12 +930,11 @@ do -- Event Creation
id = EVENTS.DeleteZoneGoal, id = EVENTS.DeleteZoneGoal,
time = timer.getTime(), time = timer.getTime(),
ZoneGoal = ZoneGoal, ZoneGoal = ZoneGoal,
} }
world.onEvent( Event ) world.onEvent( Event )
end end
--- Creation of a S_EVENT_PLAYER_ENTER_UNIT Event. --- Creation of a S_EVENT_PLAYER_ENTER_UNIT Event.
-- @param #EVENT self -- @param #EVENT self
-- @param Wrapper.Unit#UNIT PlayerUnit. -- @param Wrapper.Unit#UNIT PlayerUnit.
@@ -955,8 +944,8 @@ do -- Event Creation
local Event = { local Event = {
id = EVENTS.PlayerEnterUnit, id = EVENTS.PlayerEnterUnit,
time = timer.getTime(), time = timer.getTime(),
initiator = PlayerUnit:GetDCSObject() initiator = PlayerUnit:GetDCSObject(),
} }
world.onEvent( Event ) world.onEvent( Event )
end end
@@ -970,8 +959,8 @@ do -- Event Creation
local Event = { local Event = {
id = EVENTS.PlayerEnterAircraft, id = EVENTS.PlayerEnterAircraft,
time = timer.getTime(), time = timer.getTime(),
initiator = PlayerUnit:GetDCSObject() initiator = PlayerUnit:GetDCSObject(),
} }
world.onEvent( Event ) world.onEvent( Event )
end end
@@ -993,14 +982,13 @@ function EVENT:onEvent( Event )
return errmsg return errmsg
end end
-- Get event meta data. -- Get event meta data.
local EventMeta = _EVENTMETA[Event.id] local EventMeta = _EVENTMETA[Event.id]
-- Check if this is a known event? -- Check if this is a known event?
if EventMeta then if EventMeta then
if self and self.Events and self.Events[Event.id] and self.MissionEnd==false and (Event.initiator~=nil or (Event.initiator==nil and Event.id~=EVENTS.PlayerLeaveUnit)) then if self and self.Events and self.Events[Event.id] and self.MissionEnd == false and (Event.initiator ~= nil or (Event.initiator == nil and Event.id ~= EVENTS.PlayerLeaveUnit)) then
if Event.id and Event.id == EVENTS.MissionEnd then if Event.id and Event.id == EVENTS.MissionEnd then
self.MissionEnd = true self.MissionEnd = true
@@ -1024,9 +1012,9 @@ function EVENT:onEvent( Event )
if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
Event.IniDCSGroupName = Event.IniDCSGroup:getName() Event.IniDCSGroupName = Event.IniDCSGroup:getName()
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName ) Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
--if Event.IniGroup then -- if Event.IniGroup then
Event.IniGroupName = Event.IniDCSGroupName Event.IniGroupName = Event.IniDCSGroupName
--end -- end
end end
Event.IniPlayerName = Event.IniDCSUnit:getPlayerName() Event.IniPlayerName = Event.IniDCSUnit:getPlayerName()
Event.IniCoalition = Event.IniDCSUnit:getCoalition() Event.IniCoalition = Event.IniDCSUnit:getCoalition()
@@ -1036,23 +1024,23 @@ function EVENT:onEvent( Event )
if Event.IniObjectCategory == Object.Category.STATIC then if Event.IniObjectCategory == Object.Category.STATIC then
if Event.id==31 then if Event.id == 31 then
-- Event.initiator is a Static object representing the pilot. But getName() errors due to DCS bug. -- Event.initiator is a Static object representing the pilot. But getName() errors due to DCS bug.
Event.IniDCSUnit = Event.initiator Event.IniDCSUnit = Event.initiator
local ID=Event.initiator.id_ local ID = Event.initiator.id_
Event.IniDCSUnitName = string.format("Ejected Pilot ID %s", tostring(ID)) Event.IniDCSUnitName = string.format( "Ejected Pilot ID %s", tostring( ID ) )
Event.IniUnitName = Event.IniDCSUnitName Event.IniUnitName = Event.IniDCSUnitName
Event.IniCoalition = 0 Event.IniCoalition = 0
Event.IniCategory = 0 Event.IniCategory = 0
Event.IniTypeName = "Ejected Pilot" Event.IniTypeName = "Ejected Pilot"
elseif Event.id == 33 then -- ejection seat discarded elseif Event.id == 33 then -- ejection seat discarded
Event.IniDCSUnit = Event.initiator Event.IniDCSUnit = Event.initiator
local ID=Event.initiator.id_ local ID = Event.initiator.id_
Event.IniDCSUnitName = string.format("Ejection Seat ID %s", tostring(ID)) Event.IniDCSUnitName = string.format( "Ejection Seat ID %s", tostring( ID ) )
Event.IniUnitName = Event.IniDCSUnitName Event.IniUnitName = Event.IniDCSUnitName
Event.IniCoalition = 0 Event.IniCoalition = 0
Event.IniCategory = 0 Event.IniCategory = 0
Event.IniTypeName = "Ejection Seat" Event.IniTypeName = "Ejection Seat"
else else
Event.IniDCSUnit = Event.initiator Event.IniDCSUnit = Event.initiator
@@ -1088,7 +1076,7 @@ function EVENT:onEvent( Event )
Event.IniDCSUnit = Event.initiator Event.IniDCSUnit = Event.initiator
Event.IniDCSUnitName = Event.IniDCSUnit:getName() Event.IniDCSUnitName = Event.IniDCSUnit:getName()
Event.IniUnitName = Event.IniDCSUnitName Event.IniUnitName = Event.IniDCSUnitName
Event.IniUnit = AIRBASE:FindByName(Event.IniDCSUnitName) Event.IniUnit = AIRBASE:FindByName( Event.IniDCSUnitName )
Event.IniCoalition = Event.IniDCSUnit:getCoalition() Event.IniCoalition = Event.IniDCSUnit:getCoalition()
Event.IniCategory = Event.IniDCSUnit:getDesc().category Event.IniCategory = Event.IniDCSUnit:getDesc().category
Event.IniTypeName = Event.IniDCSUnit:getTypeName() Event.IniTypeName = Event.IniDCSUnit:getTypeName()
@@ -1109,9 +1097,9 @@ function EVENT:onEvent( Event )
if Event.TgtDCSGroup and Event.TgtDCSGroup:isExist() then if Event.TgtDCSGroup and Event.TgtDCSGroup:isExist() then
Event.TgtDCSGroupName = Event.TgtDCSGroup:getName() Event.TgtDCSGroupName = Event.TgtDCSGroup:getName()
Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName ) Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName )
--if Event.TgtGroup then -- if Event.TgtGroup then
Event.TgtGroupName = Event.TgtDCSGroupName Event.TgtGroupName = Event.TgtDCSGroupName
--end -- end
end end
Event.TgtPlayerName = Event.TgtDCSUnit:getPlayerName() Event.TgtPlayerName = Event.TgtDCSUnit:getPlayerName()
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition() Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
@@ -1130,18 +1118,18 @@ function EVENT:onEvent( Event )
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName() Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
else else
Event.TgtDCSUnitName = string.format("No target object for Event ID %s", tostring(Event.id)) Event.TgtDCSUnitName = string.format( "No target object for Event ID %s", tostring( Event.id ) )
Event.TgtUnitName = Event.TgtDCSUnitName Event.TgtUnitName = Event.TgtDCSUnitName
Event.TgtUnit = nil Event.TgtUnit = nil
Event.TgtCoalition = 0 Event.TgtCoalition = 0
Event.TgtCategory = 0 Event.TgtCategory = 0
if Event.id == 6 then if Event.id == 6 then
Event.TgtTypeName = "Ejected Pilot" Event.TgtTypeName = "Ejected Pilot"
Event.TgtDCSUnitName = string.format("Ejected Pilot ID %s", tostring(Event.IniDCSUnitName)) Event.TgtDCSUnitName = string.format( "Ejected Pilot ID %s", tostring( Event.IniDCSUnitName ) )
Event.TgtUnitName = Event.TgtDCSUnitName Event.TgtUnitName = Event.TgtDCSUnitName
elseif Event.id == 33 then elseif Event.id == 33 then
Event.TgtTypeName = "Ejection Seat" Event.TgtTypeName = "Ejection Seat"
Event.TgtDCSUnitName = string.format("Ejection Seat ID %s", tostring(Event.IniDCSUnitName)) Event.TgtDCSUnitName = string.format( "Ejection Seat ID %s", tostring( Event.IniDCSUnitName ) )
Event.TgtUnitName = Event.TgtDCSUnitName Event.TgtUnitName = Event.TgtDCSUnitName
else else
Event.TgtTypeName = "Static" Event.TgtTypeName = "Static"
@@ -1167,29 +1155,29 @@ function EVENT:onEvent( Event )
Event.WeaponCoalition = Event.WeaponUNIT and Event.Weapon:getCoalition() Event.WeaponCoalition = Event.WeaponUNIT and Event.Weapon:getCoalition()
Event.WeaponCategory = Event.WeaponUNIT and Event.Weapon:getDesc().category Event.WeaponCategory = Event.WeaponUNIT and Event.Weapon:getDesc().category
Event.WeaponTypeName = Event.WeaponUNIT and Event.Weapon:getTypeName() Event.WeaponTypeName = Event.WeaponUNIT and Event.Weapon:getTypeName()
--Event.WeaponTgtDCSUnit = Event.Weapon:getTarget() -- Event.WeaponTgtDCSUnit = Event.Weapon:getTarget()
end end
-- Place should be given for takeoff and landing events as well as base captured. It should be a DCS airbase. -- Place should be given for takeoff and landing events as well as base captured. It should be a DCS airbase.
if Event.place then if Event.place then
if Event.id==EVENTS.LandingAfterEjection then if Event.id == EVENTS.LandingAfterEjection then
-- Place is here the UNIT of which the pilot ejected. -- Place is here the UNIT of which the pilot ejected.
--local name=Event.place:getName() -- This returns a DCS error "Airbase doesn't exit" :( -- local name=Event.place:getName() -- This returns a DCS error "Airbase doesn't exit" :(
-- However, this is not a big thing, as the aircraft the pilot ejected from is usually long crashed before the ejected pilot touches the ground. -- However, this is not a big thing, as the aircraft the pilot ejected from is usually long crashed before the ejected pilot touches the ground.
--Event.Place=UNIT:Find(Event.place) -- Event.Place=UNIT:Find(Event.place)
else else
Event.Place=AIRBASE:Find(Event.place) Event.Place = AIRBASE:Find( Event.place )
Event.PlaceName=Event.Place:GetName() Event.PlaceName = Event.Place:GetName()
end end
end end
-- Mark points. -- Mark points.
if Event.idx then if Event.idx then
Event.MarkID=Event.idx Event.MarkID = Event.idx
Event.MarkVec3=Event.pos Event.MarkVec3 = Event.pos
Event.MarkCoordinate=COORDINATE:NewFromVec3(Event.pos) Event.MarkCoordinate = COORDINATE:NewFromVec3( Event.pos )
Event.MarkText=Event.text Event.MarkText = Event.text
Event.MarkCoalition=Event.coalition Event.MarkCoalition = Event.coalition
Event.MarkGroupID = Event.groupID Event.MarkGroupID = Event.groupID
end end
@@ -1218,9 +1206,9 @@ function EVENT:onEvent( Event )
-- Okay, we got the event from DCS. Now loop the SORTED self.EventSorted[] table for the received Event.id, and for each EventData registered, check if a function needs to be called. -- Okay, we got the event from DCS. Now loop the SORTED self.EventSorted[] table for the received Event.id, and for each EventData registered, check if a function needs to be called.
for EventClass, EventData in pairs( self.Events[Event.id][EventPriority] ) do for EventClass, EventData in pairs( self.Events[Event.id][EventPriority] ) do
--if Event.IniObjectCategory ~= Object.Category.STATIC then -- if Event.IniObjectCategory ~= Object.Category.STATIC then
-- self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } ) -- self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } )
--end -- end
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName ) Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName ) Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName )
@@ -1237,8 +1225,8 @@ function EVENT:onEvent( Event )
local UnitName = EventClass:GetName() local UnitName = EventClass:GetName()
if ( EventMeta.Side == "I" and UnitName == Event.IniDCSUnitName ) or if (EventMeta.Side == "I" and UnitName == Event.IniDCSUnitName) or
( EventMeta.Side == "T" and UnitName == Event.TgtDCSUnitName ) then (EventMeta.Side == "T" and UnitName == Event.TgtDCSUnitName) then
-- First test if a EventFunction is Set, otherwise search for the default function -- First test if a EventFunction is Set, otherwise search for the default function
if EventData.EventFunction then if EventData.EventFunction then
@@ -1247,15 +1235,14 @@ function EVENT:onEvent( Event )
self:F( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } ) self:F( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
end end
local Result, Value = xpcall( local Result, Value = xpcall( function()
function() return EventData.EventFunction( EventClass, Event )
return EventData.EventFunction( EventClass, Event ) end, ErrorHandler )
end, ErrorHandler )
else else
-- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object. -- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object.
local EventFunction = EventClass[ EventMeta.Event ] local EventFunction = EventClass[EventMeta.Event]
if EventFunction and type( EventFunction ) == "function" then if EventFunction and type( EventFunction ) == "function" then
-- Now call the default event function. -- Now call the default event function.
@@ -1263,10 +1250,9 @@ function EVENT:onEvent( Event )
self:F( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } ) self:F( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
end end
local Result, Value = xpcall( local Result, Value = xpcall( function()
function() return EventFunction( EventClass, Event )
return EventFunction( EventClass, Event ) end, ErrorHandler )
end, ErrorHandler )
end end
end end
end end
@@ -1290,8 +1276,8 @@ function EVENT:onEvent( Event )
-- We can get the name of the EventClass, which is now always a GROUP object. -- We can get the name of the EventClass, which is now always a GROUP object.
local GroupName = EventClass:GetName() local GroupName = EventClass:GetName()
if ( EventMeta.Side == "I" and GroupName == Event.IniDCSGroupName ) or if (EventMeta.Side == "I" and GroupName == Event.IniDCSGroupName) or
( EventMeta.Side == "T" and GroupName == Event.TgtDCSGroupName ) then (EventMeta.Side == "T" and GroupName == Event.TgtDCSGroupName) then
-- First test if a EventFunction is Set, otherwise search for the default function -- First test if a EventFunction is Set, otherwise search for the default function
if EventData.EventFunction then if EventData.EventFunction then
@@ -1300,15 +1286,14 @@ function EVENT:onEvent( Event )
self:F( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } ) self:F( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
end end
local Result, Value = xpcall( local Result, Value = xpcall( function()
function() return EventData.EventFunction( EventClass, Event, unpack( EventData.Params ) )
return EventData.EventFunction( EventClass, Event, unpack( EventData.Params ) ) end, ErrorHandler )
end, ErrorHandler )
else else
-- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object. -- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object.
local EventFunction = EventClass[ EventMeta.Event ] local EventFunction = EventClass[EventMeta.Event]
if EventFunction and type( EventFunction ) == "function" then if EventFunction and type( EventFunction ) == "function" then
-- Now call the default event function. -- Now call the default event function.
@@ -1316,16 +1301,15 @@ function EVENT:onEvent( Event )
self:F( { "Calling " .. EventMeta.Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } ) self:F( { "Calling " .. EventMeta.Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } )
end end
local Result, Value = xpcall( local Result, Value = xpcall( function()
function() return EventFunction( EventClass, Event, unpack( EventData.Params ) )
return EventFunction( EventClass, Event, unpack( EventData.Params ) ) end, ErrorHandler )
end, ErrorHandler )
end end
end end
end end
else else
-- The EventClass is not alive anymore, we remove it from the EventHandlers... -- The EventClass is not alive anymore, we remove it from the EventHandlers...
--self:RemoveEvent( EventClass, Event.id ) -- self:RemoveEvent( EventClass, Event.id )
end end
else else
@@ -1340,14 +1324,13 @@ function EVENT:onEvent( Event )
if Event.IniObjectCategory ~= 3 then if Event.IniObjectCategory ~= 3 then
self:F2( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventPriority } ) self:F2( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventPriority } )
end end
local Result, Value = xpcall( local Result, Value = xpcall( function()
function() return EventData.EventFunction( EventClass, Event )
return EventData.EventFunction( EventClass, Event ) end, ErrorHandler )
end, ErrorHandler )
else else
-- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object. -- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object.
local EventFunction = EventClass[ EventMeta.Event ] local EventFunction = EventClass[EventMeta.Event]
if EventFunction and type( EventFunction ) == "function" then if EventFunction and type( EventFunction ) == "function" then
-- Now call the default event function. -- Now call the default event function.
@@ -1355,11 +1338,10 @@ function EVENT:onEvent( Event )
self:F2( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } ) self:F2( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
end end
local Result, Value = xpcall( local Result, Value = xpcall( function()
function() local Result, Value = EventFunction( EventClass, Event )
local Result, Value = EventFunction( EventClass, Event ) return Result, Value
return Result, Value end, ErrorHandler )
end, ErrorHandler )
end end
end end
@@ -1383,7 +1365,7 @@ function EVENT:onEvent( Event )
self:T( { EventMeta.Text, Event } ) self:T( { EventMeta.Text, Event } )
end end
else else
self:E(string.format("WARNING: Could not get EVENTMETA data for event ID=%d! Is this an unknown/new DCS event?", tostring(Event.id))) self:E( string.format( "WARNING: Could not get EVENTMETA data for event ID=%d! Is this an unknown/new DCS event?", tostring( Event.id ) ) )
end end
Event = nil Event = nil
+108 -117
View File
@@ -21,8 +21,8 @@
-- A FSM can only be in one of a finite number of states. -- A FSM can only be in one of a finite number of states.
-- The machine is in only one state at a time; the state it is in at any given time is called the **current state**. -- The machine is in only one state at a time; the state it is in at any given time is called the **current state**.
-- It can change from one state to another when initiated by an **__internal__ or __external__ triggering event**, which is called a **transition**. -- It can change from one state to another when initiated by an **__internal__ or __external__ triggering event**, which is called a **transition**.
-- An **FSM implementation** is defined by **a list of its states**, **its initial state**, and **the triggering events** for **each possible transition**. -- A **FSM implementation** is defined by **a list of its states**, **its initial state**, and **the triggering events** for **each possible transition**.
-- An FSM implementation is composed out of **two parts**, a set of **state transition rules**, and an implementation set of **state transition handlers**, implementing those transitions. -- A FSM implementation is composed out of **two parts**, a set of **state transition rules**, and an implementation set of **state transition handlers**, implementing those transitions.
-- --
-- The FSM class supports a **hierarchical implementation of a Finite State Machine**, -- The FSM class supports a **hierarchical implementation of a Finite State Machine**,
-- that is, it allows to **embed existing FSM implementations in a master FSM**. -- that is, it allows to **embed existing FSM implementations in a master FSM**.
@@ -34,32 +34,32 @@
-- orders him to destroy x targets and account the results. -- orders him to destroy x targets and account the results.
-- Other examples of ready made FSM could be: -- Other examples of ready made FSM could be:
-- --
-- * route a plane to a zone flown by a human -- * Route a plane to a zone flown by a human.
-- * detect targets by an AI and report to humans -- * Detect targets by an AI and report to humans.
-- * account for destroyed targets by human players -- * Account for destroyed targets by human players.
-- * handle AI infantry to deploy from or embark to a helicopter or airplane or vehicle -- * Handle AI infantry to deploy from or embark to a helicopter or airplane or vehicle.
-- * let an AI patrol a zone -- * Let an AI patrol a zone.
-- --
-- The **MOOSE framework** uses extensively the FSM class and derived FSM\_ classes, -- The **MOOSE framework** extensively uses the FSM class and derived FSM\_ classes,
-- because **the goal of MOOSE is to simplify mission design complexity for mission building**. -- because **the goal of MOOSE is to simplify mission design complexity for mission building**.
-- By efficiently utilizing the FSM class and derived classes, MOOSE allows mission designers to quickly build processes. -- By efficiently utilizing the FSM class and derived classes, MOOSE allows mission designers to quickly build processes.
-- **Ready made FSM-based implementations classes** exist within the MOOSE framework that **can easily be re-used, -- **Ready made FSM-based implementations classes** exist within the MOOSE framework that **can easily be re-used,
-- and tailored** by mission designers through **the implementation of Transition Handlers**. -- and tailored** by mission designers through **the implementation of Transition Handlers**.
-- Each of these FSM implementation classes start either with: -- Each of these FSM implementation classes start either with:
-- --
-- * an acronym **AI\_**, which indicates an FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class. -- * an acronym **AI\_**, which indicates a FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class.
-- * an acronym **TASK\_**, which indicates an FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class. -- * an acronym **TASK\_**, which indicates a FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class.
-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class. -- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class.
-- --
-- Detailed explanations and API specifics are further below clarified and FSM derived class specifics are described in those class documentation sections. -- Detailed explanations and API specifics are further below clarified and FSM derived class specifics are described in those class documentation sections.
-- --
-- ##__Dislaimer:__ -- ##__Disclaimer:__
-- The FSM class development is based on a finite state machine implementation made by Conroy Kyle. -- The FSM class development is based on a finite state machine implementation made by Conroy Kyle.
-- The state machine can be found on [github](https://github.com/kyleconroy/lua-state-machine) -- The state machine can be found on [github](https://github.com/kyleconroy/lua-state-machine)
-- I've reworked this development (taken the concept), and created a **hierarchical state machine** out of it, embedded within the DCS simulator. -- I've reworked this development (taken the concept), and created a **hierarchical state machine** out of it, embedded within the DCS simulator.
-- Additionally, I've added extendability and created an API that allows seamless FSM implementation. -- Additionally, I've added extendability and created an API that allows seamless FSM implementation.
-- --
-- The following derived classes are available in the MOOSE framework, that implement a specialised form of a FSM: -- The following derived classes are available in the MOOSE framework, that implement a specialized form of a FSM:
-- --
-- * @{#FSM_TASK}: Models Finite State Machines for @{Task}s. -- * @{#FSM_TASK}: Models Finite State Machines for @{Task}s.
-- * @{#FSM_PROCESS}: Models Finite State Machines for @{Task} actions, which control @{Client}s. -- * @{#FSM_PROCESS}: Models Finite State Machines for @{Task} actions, which control @{Client}s.
@@ -69,7 +69,6 @@
-- --
-- === -- ===
-- --
--
-- ### Author: **FlightControl** -- ### Author: **FlightControl**
-- ### Contributions: **funkyfranky** -- ### Contributions: **funkyfranky**
-- --
@@ -89,7 +88,6 @@ do -- FSM
-- @field #string current Current state name. -- @field #string current Current state name.
-- @extends Core.Base#BASE -- @extends Core.Base#BASE
--- A Finite State Machine (FSM) models a process flow that transitions between various **States** through triggered **Events**. --- A Finite State Machine (FSM) models a process flow that transitions between various **States** through triggered **Events**.
-- --
-- A FSM can only be in one of a finite number of states. -- A FSM can only be in one of a finite number of states.
@@ -145,12 +143,12 @@ do -- FSM
-- Most of the time, these Event Triggers are used within the Transition Handler methods, so that a workflow is created running through the state machine. -- Most of the time, these Event Triggers are used within the Transition Handler methods, so that a workflow is created running through the state machine.
-- --
-- As explained above, a FSM supports **Linear State Transitions** and **Hierarchical State Transitions**, and both can be mixed to make a comprehensive FSM implementation. -- As explained above, a FSM supports **Linear State Transitions** and **Hierarchical State Transitions**, and both can be mixed to make a comprehensive FSM implementation.
-- The below documentation has a seperate chapter explaining both transition modes, taking into account the **Transition Rules**, **Transition Handlers** and **Event Triggers**. -- The below documentation has a separate chapter explaining both transition modes, taking into account the **Transition Rules**, **Transition Handlers** and **Event Triggers**.
-- --
-- ## FSM Linear Transitions -- ## FSM Linear Transitions
-- --
-- Linear Transitions are Transition Rules allowing an FSM to transition from one or multiple possible **From** state(s) towards a **To** state upon a Triggered **Event**. -- Linear Transitions are Transition Rules allowing an FSM to transition from one or multiple possible **From** state(s) towards a **To** state upon a Triggered **Event**.
-- The Lineair transition rule evaluation will always be done from the **current state** of the FSM. -- The Linear transition rule evaluation will always be done from the **current state** of the FSM.
-- If no valid Transition Rule can be found in the FSM, the FSM will log an error and stop. -- If no valid Transition Rule can be found in the FSM, the FSM will log an error and stop.
-- --
-- ### FSM Transition Rules -- ### FSM Transition Rules
@@ -185,7 +183,7 @@ do -- FSM
-- * The From states can be **a table of strings**, indicating that the transition rule will be valid **if the current state** of the FSM will be **one of the given From states**. -- * The From states can be **a table of strings**, indicating that the transition rule will be valid **if the current state** of the FSM will be **one of the given From states**.
-- * The From state can be a **"*"**, indicating that **the transition rule will always be valid**, regardless of the current state of the FSM. -- * The From state can be a **"*"**, indicating that **the transition rule will always be valid**, regardless of the current state of the FSM.
-- --
-- The below code snippet shows how the two last lines can be rewritten and consensed. -- The below code snippet shows how the two last lines can be rewritten and condensed.
-- --
-- FsmSwitch:AddTransition( { "On", "Middle" }, "SwitchOff", "Off" ) -- FsmSwitch:AddTransition( { "On", "Middle" }, "SwitchOff", "Off" )
-- --
@@ -221,7 +219,7 @@ do -- FSM
-- * The method **FSM:Event()** triggers an Event that will be processed **synchronously** or **immediately**. -- * The method **FSM:Event()** triggers an Event that will be processed **synchronously** or **immediately**.
-- * The method **FSM:__Event( __seconds__ )** triggers an Event that will be processed **asynchronously** over time, waiting __x seconds__. -- * The method **FSM:__Event( __seconds__ )** triggers an Event that will be processed **asynchronously** over time, waiting __x seconds__.
-- --
-- The destinction between these 2 Event Trigger methods are important to understand. An asynchronous call will "log" the Event Trigger to be executed at a later time. -- The distinction between these 2 Event Trigger methods are important to understand. An asynchronous call will "log" the Event Trigger to be executed at a later time.
-- Processing will just continue. Synchronous Event Trigger methods are useful to change states of the FSM immediately, but may have a larger processing impact. -- Processing will just continue. Synchronous Event Trigger methods are useful to change states of the FSM immediately, but may have a larger processing impact.
-- --
-- The following example provides a little demonstration on the difference between synchronous and asynchronous Event Triggering. -- The following example provides a little demonstration on the difference between synchronous and asynchronous Event Triggering.
@@ -345,7 +343,6 @@ do -- FSM
-- === -- ===
-- --
-- @field #FSM -- @field #FSM
--
FSM = { FSM = {
ClassName = "FSM", ClassName = "FSM",
} }
@@ -379,7 +376,6 @@ do -- FSM
return self return self
end end
--- Sets the start state of the FSM. --- Sets the start state of the FSM.
-- @param #FSM self -- @param #FSM self
-- @param #string State A string defining the start state. -- @param #string State A string defining the start state.
@@ -388,7 +384,6 @@ do -- FSM
self.current = State self.current = State
end end
--- Returns the start state of the FSM. --- Returns the start state of the FSM.
-- @param #FSM self -- @param #FSM self
-- @return #string A string containing the start state. -- @return #string A string containing the start state.
@@ -416,7 +411,6 @@ do -- FSM
self:_eventmap( self.Events, Transition ) self:_eventmap( self.Events, Transition )
end end
--- Returns a table of the transition rules defined within the FSM. --- Returns a table of the transition rules defined within the FSM.
-- @param #FSM self -- @param #FSM self
-- @return #table Transitions. -- @return #table Transitions.
@@ -450,7 +444,6 @@ do -- FSM
return Process return Process
end end
--- Returns a table of the SubFSM rules defined within the FSM. --- Returns a table of the SubFSM rules defined within the FSM.
-- @param #FSM self -- @param #FSM self
-- @return #table Sub processes. -- @return #table Sub processes.
@@ -499,7 +492,6 @@ do -- FSM
return self._EndStates or {} return self._EndStates or {}
end end
--- Adds a score for the FSM to be achieved. --- Adds a score for the FSM to be achieved.
-- @param #FSM self -- @param #FSM self
-- @param #string State is the state of the process when the score needs to be given. (See the relevant state descriptions of the process). -- @param #string State is the state of the process when the score needs to be given. (See the relevant state descriptions of the process).
@@ -563,27 +555,27 @@ do -- FSM
end end
--- Event map. --- Event map.
-- @param #FSM self -- @param #FSM self
-- @param #table Events Events. -- @param #table Events Events.
-- @param #table EventStructure Event structure. -- @param #table EventStructure Event structure.
function FSM:_eventmap( Events, EventStructure ) function FSM:_eventmap( Events, EventStructure )
local Event = EventStructure.Event local Event = EventStructure.Event
local __Event = "__" .. EventStructure.Event local __Event = "__" .. EventStructure.Event
self[Event] = self[Event] or self:_create_transition(Event) self[Event] = self[Event] or self:_create_transition( Event )
self[__Event] = self[__Event] or self:_delayed_transition(Event) self[__Event] = self[__Event] or self:_delayed_transition( Event )
-- Debug message. -- Debug message.
self:T2( "Added methods: " .. Event .. ", " .. __Event ) self:T2( "Added methods: " .. Event .. ", " .. __Event )
Events[Event] = self.Events[Event] or { map = {} } Events[Event] = self.Events[Event] or { map = {} }
self:_add_to_map( Events[Event].map, EventStructure ) self:_add_to_map( Events[Event].map, EventStructure )
end end
--- Sub maps. --- Sub maps.
-- @param #FSM self -- @param #FSM self
-- @param #table subs Subs. -- @param #table subs Subs.
-- @param #table sub Sub. -- @param #table sub Sub.
@@ -613,7 +605,7 @@ do -- FSM
-- @param #string EventName Event name. -- @param #string EventName Event name.
-- @return Value. -- @return Value.
function FSM:_call_handler( step, trigger, params, EventName ) function FSM:_call_handler( step, trigger, params, EventName )
--env.info(string.format("FF T=%.3f _call_handler step=%s, trigger=%s, event=%s", timer.getTime(), step, trigger, EventName)) -- env.info(string.format("FF T=%.3f _call_handler step=%s, trigger=%s, event=%s", timer.getTime(), step, trigger, EventName))
local handler = step .. trigger local handler = step .. trigger
@@ -644,10 +636,12 @@ do -- FSM
return errmsg return errmsg
end end
--return self[handler](self, unpack( params )) -- return self[handler](self, unpack( params ))
-- Protected call. -- Protected call.
local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler ) local Result, Value = xpcall( function()
return self[handler]( self, unpack( params ) )
end, ErrorHandler )
return Value return Value
end end
@@ -671,17 +665,16 @@ do -- FSM
local From = self.current local From = self.current
-- Parameters. -- Parameters.
local Params = { From, EventName, To, ... } local Params = { From, EventName, To, ... }
if self["onleave" .. From] or
if self["onleave".. From] or self["OnLeave" .. From] or
self["OnLeave".. From] or self["onbefore" .. EventName] or
self["onbefore".. EventName] or self["OnBefore" .. EventName] or
self["OnBefore".. EventName] or self["onafter" .. EventName] or
self["onafter".. EventName] or self["OnAfter" .. EventName] or
self["OnAfter".. EventName] or self["onenter" .. To] or
self["onenter".. To] or self["OnEnter" .. To] then
self["OnEnter".. To] then
if self:_call_handler( "onbefore", EventName, Params, EventName ) == false then if self:_call_handler( "onbefore", EventName, Params, EventName ) == false then
self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** onbefore" .. EventName ) self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** onbefore" .. EventName )
@@ -716,11 +709,11 @@ do -- FSM
end end
if ClassName == "FSM_CONTROLLABLE" then if ClassName == "FSM_CONTROLLABLE" then
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** TaskUnit: " .. self.Controllable.ControllableName .. " *** " ) self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** TaskUnit: " .. self.Controllable.ControllableName .. " *** " )
end end
if ClassName == "FSM_PROCESS" then if ClassName == "FSM_PROCESS" then
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** Task: " .. self.Task:GetName() .. ", TaskUnit: " .. self.Controllable.ControllableName .. " *** " ) self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** Task: " .. self.Task:GetName() .. ", TaskUnit: " .. self.Controllable.ControllableName .. " *** " )
end end
end end
@@ -733,10 +726,10 @@ do -- FSM
for _, sub in pairs( subtable ) do for _, sub in pairs( subtable ) do
--if sub.nextevent then -- if sub.nextevent then
-- self:F2( "nextevent = " .. sub.nextevent ) -- self:F2( "nextevent = " .. sub.nextevent )
-- self[sub.nextevent]( self ) -- self[sub.nextevent]( self )
--end -- end
self:T( "*** FSM *** Sub *** " .. sub.StartEvent ) self:T( "*** FSM *** Sub *** " .. sub.StartEvent )
@@ -753,11 +746,11 @@ do -- FSM
self:T( "*** FSM *** End *** " .. Event ) self:T( "*** FSM *** End *** " .. Event )
self:_call_handler("onenter", To, Params, EventName ) self:_call_handler( "onenter", To, Params, EventName )
self:_call_handler("OnEnter", To, Params, EventName ) self:_call_handler( "OnEnter", To, Params, EventName )
self:_call_handler("onafter", EventName, Params, EventName ) self:_call_handler( "onafter", EventName, Params, EventName )
self:_call_handler("OnAfter", EventName, Params, EventName ) self:_call_handler( "OnAfter", EventName, Params, EventName )
self:_call_handler("onstate", "change", Params, EventName ) self:_call_handler( "onstate", "change", Params, EventName )
fsmparent[Event]( fsmparent ) fsmparent[Event]( fsmparent )
@@ -766,13 +759,13 @@ do -- FSM
if execute then if execute then
self:_call_handler("onafter", EventName, Params, EventName ) self:_call_handler( "onafter", EventName, Params, EventName )
self:_call_handler("OnAfter", EventName, Params, EventName ) self:_call_handler( "OnAfter", EventName, Params, EventName )
self:_call_handler("onenter", To, Params, EventName ) self:_call_handler( "onenter", To, Params, EventName )
self:_call_handler("OnEnter", To, Params, EventName ) self:_call_handler( "OnEnter", To, Params, EventName )
self:_call_handler("onstate", "change", Params, EventName ) self:_call_handler( "onstate", "change", Params, EventName )
end end
else else
@@ -809,16 +802,16 @@ do -- FSM
self._EventSchedules[EventName] = CallID self._EventSchedules[EventName] = CallID
-- Debug output. -- Debug output.
self:T2(string.format("NEGATIVE Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring(CallID))) self:T2( string.format( "NEGATIVE Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring( CallID ) ) )
else else
self:T2(string.format("NEGATIVE Event %s delayed by %.1f sec CANCELLED as we already have such an event in the queue.", EventName, DelaySeconds)) self:T2( string.format( "NEGATIVE Event %s delayed by %.1f sec CANCELLED as we already have such an event in the queue.", EventName, DelaySeconds ) )
-- reschedule -- reschedule
end end
else else
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true ) CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
self:T2(string.format("Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring(CallID))) self:T2( string.format( "Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring( CallID ) ) )
end end
else else
error( "FSM: An asynchronous event trigger requires a DelaySeconds parameter!!! This can be positive or negative! Sorry, but will not process this." ) error( "FSM: An asynchronous event trigger requires a DelaySeconds parameter!!! This can be positive or negative! Sorry, but will not process this." )
@@ -835,7 +828,9 @@ do -- FSM
-- @param #string EventName Event name. -- @param #string EventName Event name.
-- @return #function Function. -- @return #function Function.
function FSM:_create_transition( EventName ) function FSM:_create_transition( EventName )
return function( self, ... ) return self._handler( self, EventName , ... ) end return function( self, ... )
return self._handler( self, EventName, ... )
end
end end
--- Go sub. --- Go sub.
@@ -862,16 +857,16 @@ do -- FSM
local FSMParent = self.fsmparent local FSMParent = self.fsmparent
if FSMParent and self.endstates[Current] then if FSMParent and self.endstates[Current] then
--self:T( { state = Current, endstates = self.endstates, endstate = self.endstates[Current] } ) -- self:T( { state = Current, endstates = self.endstates, endstate = self.endstates[Current] } )
FSMParent.current = Current FSMParent.current = Current
local ParentFrom = FSMParent.current local ParentFrom = FSMParent.current
--self:T( { ParentFrom, self.ReturnEvents } ) -- self:T( { ParentFrom, self.ReturnEvents } )
local Event = self.ReturnEvents[Current] local Event = self.ReturnEvents[Current]
--self:T( { Event } ) -- self:T( { Event } )
if Event then if Event then
return FSMParent, Event return FSMParent, Event
else else
--self:T( { "Could not find parent event name for state ", ParentFrom } ) -- self:T( { "Could not find parent event name for state ", ParentFrom } )
end end
end end
@@ -883,17 +878,17 @@ do -- FSM
-- @param #table Map Map. -- @param #table Map Map.
-- @param #table Event Event table. -- @param #table Event Event table.
function FSM:_add_to_map( Map, Event ) function FSM:_add_to_map( Map, Event )
self:F3( { Map, Event } ) self:F3( { Map, Event } )
if type(Event.From) == 'string' then if type( Event.From ) == 'string' then
Map[Event.From] = Event.To Map[Event.From] = Event.To
else else
for _, From in ipairs(Event.From) do for _, From in ipairs( Event.From ) do
Map[From] = Event.To Map[From] = Event.To
end end
end end
self:T3( { Map, Event } ) self:T3( { Map, Event } )
end end
--- Get current state. --- Get current state.
@@ -922,7 +917,7 @@ do -- FSM
-- @param #FSM self -- @param #FSM self
-- @param #string State State name. -- @param #string State State name.
-- @param #boolean If true, FSM is in this state. -- @param #boolean If true, FSM is in this state.
function FSM:is(state) function FSM:is( state )
return self.current == state return self.current == state
end end
@@ -931,11 +926,11 @@ do -- FSM
-- @param #string e Event name. -- @param #string e Event name.
-- @return #boolean If true, FSM can do the event. -- @return #boolean If true, FSM can do the event.
-- @return #string To state. -- @return #string To state.
function FSM:can(e) function FSM:can( e )
local Event = self.Events[e] local Event = self.Events[e]
--self:F3( { self.current, Event } ) -- self:F3( { self.current, Event } )
local To = Event and Event.map[self.current] or Event.map['*'] local To = Event and Event.map[self.current] or Event.map['*']
@@ -946,8 +941,8 @@ do -- FSM
-- @param #FSM self -- @param #FSM self
-- @param #string e Event name. -- @param #string e Event name.
-- @return #boolean If true, FSM cannot do the event. -- @return #boolean If true, FSM cannot do the event.
function FSM:cannot(e) function FSM:cannot( e )
return not self:can(e) return not self:can( e )
end end
end end
@@ -1036,7 +1031,7 @@ do -- FSM_CONTROLLABLE
-- @param #string From The From State string. -- @param #string From The From State string.
-- @param #string Event The Event string. -- @param #string Event The Event string.
-- @param #string To The To State string. -- @param #string To The To State string.
function FSM_CONTROLLABLE:OnAfterStop(Controllable,From,Event,To) function FSM_CONTROLLABLE:OnAfterStop( Controllable, From, Event, To )
-- Clear all pending schedules -- Clear all pending schedules
self.CallScheduler:Clear() self.CallScheduler:Clear()
@@ -1047,7 +1042,7 @@ do -- FSM_CONTROLLABLE
-- @param Wrapper.Controllable#CONTROLLABLE FSMControllable -- @param Wrapper.Controllable#CONTROLLABLE FSMControllable
-- @return #FSM_CONTROLLABLE -- @return #FSM_CONTROLLABLE
function FSM_CONTROLLABLE:SetControllable( FSMControllable ) function FSM_CONTROLLABLE:SetControllable( FSMControllable )
--self:F( FSMControllable:GetName() ) -- self:F( FSMControllable:GetName() )
self.Controllable = FSMControllable self.Controllable = FSMControllable
end end
@@ -1075,9 +1070,11 @@ do -- FSM_CONTROLLABLE
if self[handler] then if self[handler] then
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] .. " *** TaskUnit: " .. self.Controllable:GetName() ) self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] .. " *** TaskUnit: " .. self.Controllable:GetName() )
self._EventSchedules[EventName] = nil self._EventSchedules[EventName] = nil
local Result, Value = xpcall( function() return self[handler]( self, self.Controllable, unpack( params ) ) end, ErrorHandler ) local Result, Value = xpcall( function()
return self[handler]( self, self.Controllable, unpack( params ) )
end, ErrorHandler )
return Value return Value
--return self[handler]( self, self.Controllable, unpack( params ) ) -- return self[handler]( self, self.Controllable, unpack( params ) )
end end
end end
@@ -1089,16 +1086,13 @@ do -- FSM_PROCESS
-- @field Tasking.Task#TASK Task -- @field Tasking.Task#TASK Task
-- @extends Core.Fsm#FSM_CONTROLLABLE -- @extends Core.Fsm#FSM_CONTROLLABLE
--- FSM_PROCESS class models Finite State Machines for @{Task} actions, which control @{Client}s. --- FSM_PROCESS class models Finite State Machines for @{Task} actions, which control @{Client}s.
-- --
-- === -- ===
-- --
-- @field #FSM_PROCESS FSM_PROCESS -- @field #FSM_PROCESS FSM_PROCESS
-- --
FSM_PROCESS = { FSM_PROCESS = { ClassName = "FSM_PROCESS" }
ClassName = "FSM_PROCESS",
}
--- Creates a new FSM_PROCESS object. --- Creates a new FSM_PROCESS object.
-- @param #FSM_PROCESS self -- @param #FSM_PROCESS self
@@ -1107,7 +1101,7 @@ do -- FSM_PROCESS
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_PROCESS local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_PROCESS
--self:F( Controllable ) -- self:F( Controllable )
self:Assign( Controllable, Task ) self:Assign( Controllable, Task )
@@ -1139,10 +1133,12 @@ do -- FSM_PROCESS
self._EventSchedules[EventName] = nil self._EventSchedules[EventName] = nil
local Result, Value local Result, Value
if self.Controllable and self.Controllable:IsAlive() == true then if self.Controllable and self.Controllable:IsAlive() == true then
Result, Value = xpcall( function() return self[handler]( self, self.Controllable, self.Task, unpack( params ) ) end, ErrorHandler ) Result, Value = xpcall( function()
return self[handler]( self, self.Controllable, self.Task, unpack( params ) )
end, ErrorHandler )
end end
return Value return Value
--return self[handler]( self, self.Controllable, unpack( params ) ) -- return self[handler]( self, self.Controllable, unpack( params ) )
end end
end end
@@ -1152,7 +1148,6 @@ do -- FSM_PROCESS
function FSM_PROCESS:Copy( Controllable, Task ) function FSM_PROCESS:Copy( Controllable, Task )
self:T( { self:GetClassNameAndID() } ) self:T( { self:GetClassNameAndID() } )
local NewFsm = self:New( Controllable, Task ) -- Core.Fsm#FSM_PROCESS local NewFsm = self:New( Controllable, Task ) -- Core.Fsm#FSM_PROCESS
NewFsm:Assign( Controllable, Task ) NewFsm:Assign( Controllable, Task )
@@ -1170,7 +1165,7 @@ do -- FSM_PROCESS
-- Copy Processes -- Copy Processes
for ProcessID, Process in pairs( self:GetProcesses() ) do for ProcessID, Process in pairs( self:GetProcesses() ) do
--self:E( { Process:GetName() } ) -- self:E( { Process:GetName() } )
local FsmProcess = NewFsm:AddProcess( Process.From, Process.Event, Process.fsm:Copy( Controllable, Task ), Process.ReturnEvents ) local FsmProcess = NewFsm:AddProcess( Process.From, Process.Event, Process.fsm:Copy( Controllable, Task ), Process.ReturnEvents )
end end
@@ -1244,7 +1239,7 @@ do -- FSM_PROCESS
return self:GetTask():GetMission():GetCommandCenter() return self:GetTask():GetMission():GetCommandCenter()
end end
-- TODO: Need to check and fix that an FSM_PROCESS is only for a UNIT. Not for a GROUP. -- TODO: Need to check and fix that an FSM_PROCESS is only for a UNIT. Not for a GROUP.
--- Send a message of the @{Task} to the Group of the Unit. --- Send a message of the @{Task} to the Group of the Unit.
-- @param #FSM_PROCESS self -- @param #FSM_PROCESS self
@@ -1263,32 +1258,29 @@ do -- FSM_PROCESS
CC:MessageToGroup( Message, TaskGroup ) CC:MessageToGroup( Message, TaskGroup )
end end
--- Assign the process to a @{Wrapper.Unit} and activate the process. --- Assign the process to a @{Wrapper.Unit} and activate the process.
-- @param #FSM_PROCESS self -- @param #FSM_PROCESS self
-- @param Task.Tasking#TASK Task -- @param Task.Tasking#TASK Task
-- @param Wrapper.Unit#UNIT ProcessUnit -- @param Wrapper.Unit#UNIT ProcessUnit
-- @return #FSM_PROCESS self -- @return #FSM_PROCESS self
function FSM_PROCESS:Assign( ProcessUnit, Task ) function FSM_PROCESS:Assign( ProcessUnit, Task )
--self:T( { Task:GetName(), ProcessUnit:GetName() } ) -- self:T( { Task:GetName(), ProcessUnit:GetName() } )
self:SetControllable( ProcessUnit ) self:SetControllable( ProcessUnit )
self:SetTask( Task ) self:SetTask( Task )
--self.ProcessGroup = ProcessUnit:GetGroup() -- self.ProcessGroup = ProcessUnit:GetGroup()
return self return self
end end
-- function FSM_PROCESS:onenterAssigned( ProcessUnit, Task, From, Event, To ) -- function FSM_PROCESS:onenterAssigned( ProcessUnit, Task, From, Event, To )
-- --
-- if From( "Planned" ) then -- if From( "Planned" ) then
-- self:T( "*** FSM *** Assign *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To ) -- self:T( "*** FSM *** Assign *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To )
-- self.Task:Assign() -- self.Task:Assign()
-- end -- end
-- end -- end
function FSM_PROCESS:onenterFailed( ProcessUnit, Task, From, Event, To ) function FSM_PROCESS:onenterFailed( ProcessUnit, Task, From, Event, To )
self:T( "*** FSM *** Failed *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To ) self:T( "*** FSM *** Failed *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To )
@@ -1296,7 +1288,6 @@ do -- FSM_PROCESS
self.Task:Fail() self.Task:Fail()
end end
--- StateMachine callback function for a FSM_PROCESS --- StateMachine callback function for a FSM_PROCESS
-- @param #FSM_PROCESS self -- @param #FSM_PROCESS self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
@@ -1309,10 +1300,10 @@ do -- FSM_PROCESS
self:T( "*** FSM *** Change *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To ) self:T( "*** FSM *** Change *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To )
end end
-- if self:IsTrace() then -- if self:IsTrace() then
-- MESSAGE:New( "@ Process " .. self:GetClassNameAndID() .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll() -- MESSAGE:New( "@ Process " .. self:GetClassNameAndID() .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll()
-- self:F2( { Scores = self._Scores, To = To } ) -- self:F2( { Scores = self._Scores, To = To } )
-- end -- end
-- TODO: This needs to be reworked with a callback functions allocated within Task, and set within the mission script from the Task Objects... -- TODO: This needs to be reworked with a callback functions allocated within Task, and set within the mission script from the Task Objects...
if self._Scores[To] then if self._Scores[To] then
@@ -1374,8 +1365,10 @@ do -- FSM_TASK
if self[handler] then if self[handler] then
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] .. " *** Task: " .. self.TaskName ) self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] .. " *** Task: " .. self.TaskName )
self._EventSchedules[EventName] = nil self._EventSchedules[EventName] = nil
--return self[handler]( self, unpack( params ) ) -- return self[handler]( self, unpack( params ) )
local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler ) local Result, Value = xpcall( function()
return self[handler]( self, unpack( params ) )
end, ErrorHandler )
return Value return Value
end end
end end
@@ -1389,14 +1382,12 @@ do -- FSM_SET
-- @field Core.Set#SET_BASE Set -- @field Core.Set#SET_BASE Set
-- @extends Core.Fsm#FSM -- @extends Core.Fsm#FSM
--- FSM_SET class models Finite State Machines for @{Set}s. Note that these FSMs control multiple objects!!! So State concerns here --- FSM_SET class models Finite State Machines for @{Set}s. Note that these FSMs control multiple objects!!! So State concerns here
-- for multiple objects or the position of the state machine in the process. -- for multiple objects or the position of the state machine in the process.
-- --
-- === -- ===
-- --
-- @field #FSM_SET FSM_SET -- @field #FSM_SET FSM_SET
--
FSM_SET = { FSM_SET = {
ClassName = "FSM_SET", ClassName = "FSM_SET",
} }
@@ -1434,8 +1425,8 @@ do -- FSM_SET
return self.Controllable return self.Controllable
end end
function FSM_SET:_call_handler( step, trigger, params, EventName ) function FSM_SET:_call_handler( step, trigger, params, EventName )
local handler = step .. trigger local handler = step .. trigger
if self[handler] then if self[handler] then
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] ) self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] )
self._EventSchedules[EventName] = nil self._EventSchedules[EventName] = nil
+2 -11
View File
@@ -22,13 +22,11 @@
-- @module Core.Goal -- @module Core.Goal
-- @image Core_Goal.JPG -- @image Core_Goal.JPG
do -- Goal do -- Goal
--- @type GOAL --- @type GOAL
-- @extends Core.Fsm#FSM -- @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. --- Models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized.
-- --
-- # 1. GOAL constructor -- # 1. GOAL constructor
@@ -105,9 +103,8 @@ do -- Goal
-- @param #string Event -- @param #string Event
-- @param #string To -- @param #string To
self:SetStartState( "Pending" ) self:SetStartState( "Pending" )
self:AddTransition( "*", "Achieved", "Achieved" ) self:AddTransition( "*", "Achieved", "Achieved" )
--- Achieved Handler OnBefore for GOAL --- Achieved Handler OnBefore for GOAL
-- @function [parent=#GOAL] OnBeforeAchieved -- @function [parent=#GOAL] OnBeforeAchieved
@@ -138,25 +135,22 @@ do -- Goal
return self return self
end end
--- Add a new contribution by a player. --- Add a new contribution by a player.
-- @param #GOAL self -- @param #GOAL self
-- @param #string PlayerName The name of the player. -- @param #string PlayerName The name of the player.
function GOAL:AddPlayerContribution( PlayerName ) function GOAL:AddPlayerContribution( PlayerName )
self:F({PlayerName}) self:F( { PlayerName } )
self.Players[PlayerName] = self.Players[PlayerName] or 0 self.Players[PlayerName] = self.Players[PlayerName] or 0
self.Players[PlayerName] = self.Players[PlayerName] + 1 self.Players[PlayerName] = self.Players[PlayerName] + 1
self.TotalContributions = self.TotalContributions + 1 self.TotalContributions = self.TotalContributions + 1
end end
--- @param #GOAL self --- @param #GOAL self
-- @param #number Player contribution. -- @param #number Player contribution.
function GOAL:GetPlayerContribution( PlayerName ) function GOAL:GetPlayerContribution( PlayerName )
return self.Players[PlayerName] or 0 return self.Players[PlayerName] or 0
end end
--- Get the players who contributed to achieve the goal. --- Get the players who contributed to achieve the goal.
-- The result is a list of players, sorted by the name of the players. -- The result is a list of players, sorted by the name of the players.
-- @param #GOAL self -- @param #GOAL self
@@ -165,7 +159,6 @@ do -- Goal
return self.Players or {} return self.Players or {}
end end
--- Gets the total contributions that happened to achieve the goal. --- Gets the total contributions that happened to achieve the goal.
-- The result is a number. -- The result is a number.
-- @param #GOAL self -- @param #GOAL self
@@ -174,8 +167,6 @@ do -- Goal
return self.TotalContributions or 0 return self.TotalContributions or 0
end end
--- Validates if the goal is achieved. --- Validates if the goal is achieved.
-- @param #GOAL self -- @param #GOAL self
-- @return #boolean true if the goal is achieved. -- @return #boolean true if the goal is achieved.
+54 -92
View File
@@ -14,7 +14,7 @@
-- * Only create or delete menus when required, and keep existing menus persistent. -- * Only create or delete menus when required, and keep existing menus persistent.
-- * Update menu structures. -- * Update menu structures.
-- * Refresh menu structures intelligently, based on a time stamp of updates. -- * Refresh menu structures intelligently, based on a time stamp of updates.
-- - Delete obscolete menus. -- - Delete obsolete menus.
-- - Create new one where required. -- - Create new one where required.
-- - Don't touch the existing ones. -- - Don't touch the existing ones.
-- * Provide a variable amount of parameters to menus. -- * Provide a variable amount of parameters to menus.
@@ -23,7 +23,7 @@
-- * Provide a great tool to manage menus in your code. -- * Provide a great tool to manage menus in your code.
-- --
-- DCS Menus can be managed using the MENU classes. -- DCS Menus can be managed using the MENU classes.
-- The advantage of using MENU classes is that it hides the complexity of dealing with menu management in more advanced scanerios where you need to -- The advantage of using MENU classes is that it hides the complexity of dealing with menu management in more advanced scenarios where you need to
-- set menus and later remove them, and later set them again. You'll find while using use normal DCS scripting functions, that setting and removing -- set menus and later remove them, and later set them again. You'll find while using use normal DCS scripting functions, that setting and removing
-- menus is not a easy feat if you have complex menu hierarchies defined. -- menus is not a easy feat if you have complex menu hierarchies defined.
-- Using the MOOSE menu classes, the removal and refreshing of menus are nicely being handled within these classes, and becomes much more easy. -- Using the MOOSE menu classes, the removal and refreshing of menus are nicely being handled within these classes, and becomes much more easy.
@@ -53,7 +53,6 @@
-- @module Core.Menu -- @module Core.Menu
-- @image Core_Menu.JPG -- @image Core_Menu.JPG
MENU_INDEX = {} MENU_INDEX = {}
MENU_INDEX.MenuMission = {} MENU_INDEX.MenuMission = {}
MENU_INDEX.MenuMission.Menus = {} MENU_INDEX.MenuMission.Menus = {}
@@ -64,8 +63,6 @@ MENU_INDEX.Coalition[coalition.side.RED] = {}
MENU_INDEX.Coalition[coalition.side.RED].Menus = {} MENU_INDEX.Coalition[coalition.side.RED].Menus = {}
MENU_INDEX.Group = {} MENU_INDEX.Group = {}
function MENU_INDEX:ParentPath( ParentMenu, MenuText ) function MENU_INDEX:ParentPath( ParentMenu, MenuText )
local Path = ParentMenu and "@" .. table.concat( ParentMenu.MenuPath or {}, "@" ) or "" local Path = ParentMenu and "@" .. table.concat( ParentMenu.MenuPath or {}, "@" ) or ""
@@ -98,29 +95,25 @@ function MENU_INDEX:ParentPath( ParentMenu, MenuText )
end end
function MENU_INDEX:PrepareMission() function MENU_INDEX:PrepareMission()
self.MenuMission.Menus = self.MenuMission.Menus or {} self.MenuMission.Menus = self.MenuMission.Menus or {}
end end
function MENU_INDEX:PrepareCoalition( CoalitionSide ) function MENU_INDEX:PrepareCoalition( CoalitionSide )
self.Coalition[CoalitionSide] = self.Coalition[CoalitionSide] or {} self.Coalition[CoalitionSide] = self.Coalition[CoalitionSide] or {}
self.Coalition[CoalitionSide].Menus = self.Coalition[CoalitionSide].Menus or {} self.Coalition[CoalitionSide].Menus = self.Coalition[CoalitionSide].Menus or {}
end end
--- ---
-- @param Wrapper.Group#GROUP Group -- @param Wrapper.Group#GROUP Group
function MENU_INDEX:PrepareGroup( Group ) function MENU_INDEX:PrepareGroup( Group )
if Group and Group:IsAlive() ~= nil then -- something was changed here! if Group and Group:IsAlive() ~= nil then -- something was changed here!
local GroupName = Group:GetName() local GroupName = Group:GetName()
self.Group[GroupName] = self.Group[GroupName] or {} self.Group[GroupName] = self.Group[GroupName] or {}
self.Group[GroupName].Menus = self.Group[GroupName].Menus or {} self.Group[GroupName].Menus = self.Group[GroupName].Menus or {}
end end
end end
function MENU_INDEX:HasMissionMenu( Path ) function MENU_INDEX:HasMissionMenu( Path )
return self.MenuMission.Menus[Path] return self.MenuMission.Menus[Path]
@@ -136,8 +129,6 @@ function MENU_INDEX:ClearMissionMenu( Path )
self.MenuMission.Menus[Path] = nil self.MenuMission.Menus[Path] = nil
end end
function MENU_INDEX:HasCoalitionMenu( Coalition, Path ) function MENU_INDEX:HasCoalitionMenu( Coalition, Path )
return self.Coalition[Coalition].Menus[Path] return self.Coalition[Coalition].Menus[Path]
@@ -153,8 +144,6 @@ function MENU_INDEX:ClearCoalitionMenu( Coalition, Path )
self.Coalition[Coalition].Menus[Path] = nil self.Coalition[Coalition].Menus[Path] = nil
end end
function MENU_INDEX:HasGroupMenu( Group, Path ) function MENU_INDEX:HasGroupMenu( Group, Path )
if Group and Group:IsAlive() then if Group and Group:IsAlive() then
local MenuGroupName = Group:GetName() local MenuGroupName = Group:GetName()
@@ -166,7 +155,7 @@ end
function MENU_INDEX:SetGroupMenu( Group, Path, Menu ) function MENU_INDEX:SetGroupMenu( Group, Path, Menu )
local MenuGroupName = Group:GetName() local MenuGroupName = Group:GetName()
Group:F({MenuGroupName=MenuGroupName,Path=Path}) Group:F( { MenuGroupName = MenuGroupName, Path = Path } )
self.Group[MenuGroupName].Menus[Path] = Menu self.Group[MenuGroupName].Menus[Path] = Menu
end end
@@ -178,36 +167,29 @@ end
function MENU_INDEX:Refresh( Group ) function MENU_INDEX:Refresh( Group )
for MenuID, Menu in pairs( self.MenuMission.Menus ) do for MenuID, Menu in pairs( self.MenuMission.Menus ) do
Menu:Refresh() Menu:Refresh()
end end
for MenuID, Menu in pairs( self.Coalition[coalition.side.BLUE].Menus ) do for MenuID, Menu in pairs( self.Coalition[coalition.side.BLUE].Menus ) do
Menu:Refresh() Menu:Refresh()
end end
for MenuID, Menu in pairs( self.Coalition[coalition.side.RED].Menus ) do for MenuID, Menu in pairs( self.Coalition[coalition.side.RED].Menus ) do
Menu:Refresh() Menu:Refresh()
end end
local GroupName = Group:GetName() local GroupName = Group:GetName()
for MenuID, Menu in pairs( self.Group[GroupName].Menus ) do for MenuID, Menu in pairs( self.Group[GroupName].Menus ) do
Menu:Refresh() Menu:Refresh()
end end
end end
do -- MENU_BASE do -- MENU_BASE
--- @type MENU_BASE --- @type MENU_BASE
-- @extends Base#BASE -- @extends Core.Base#BASE
--- Defines the main MENU class where other MENU classes are derived from. --- Defines the main MENU class where other MENU classes are derived from.
-- This is an abstract class, so don't use it. -- This is an abstract class, so don't use it.
@@ -216,10 +198,10 @@ do -- MENU_BASE
ClassName = "MENU_BASE", ClassName = "MENU_BASE",
MenuPath = nil, MenuPath = nil,
MenuText = "", MenuText = "",
MenuParentPath = nil MenuParentPath = nil,
} }
--- Consructor --- Constructor
-- @param #MENU_BASE -- @param #MENU_BASE
-- @return #MENU_BASE -- @return #MENU_BASE
function MENU_BASE:New( MenuText, ParentMenu ) function MENU_BASE:New( MenuText, ParentMenu )
@@ -229,13 +211,13 @@ do -- MENU_BASE
MenuParentPath = ParentMenu.MenuPath MenuParentPath = ParentMenu.MenuPath
end end
local self = BASE:Inherit( self, BASE:New() ) local self = BASE:Inherit( self, BASE:New() )
self.MenuPath = nil self.MenuPath = nil
self.MenuText = MenuText self.MenuText = MenuText
self.ParentMenu = ParentMenu self.ParentMenu = ParentMenu
self.MenuParentPath = MenuParentPath self.MenuParentPath = MenuParentPath
self.Path = ( self.ParentMenu and "@" .. table.concat( self.MenuParentPath or {}, "@" ) or "" ) .. "@" .. self.MenuText self.Path = (self.ParentMenu and "@" .. table.concat( self.MenuParentPath or {}, "@" ) or "") .. "@" .. self.MenuText
self.Menus = {} self.Menus = {}
self.MenuCount = 0 self.MenuCount = 0
self.MenuStamp = timer.getTime() self.MenuStamp = timer.getTime()
@@ -246,7 +228,7 @@ do -- MENU_BASE
self.ParentMenu.Menus[MenuText] = self self.ParentMenu.Menus[MenuText] = self
end end
return self return self
end end
function MENU_BASE:SetParentMenu( MenuText, Menu ) function MENU_BASE:SetParentMenu( MenuText, Menu )
@@ -262,7 +244,7 @@ do -- MENU_BASE
self.ParentMenu.Menus[MenuText] = nil self.ParentMenu.Menus[MenuText] = nil
self.ParentMenu.MenuCount = self.ParentMenu.MenuCount - 1 self.ParentMenu.MenuCount = self.ParentMenu.MenuCount - 1
if self.ParentMenu.MenuCount == 0 then if self.ParentMenu.MenuCount == 0 then
--self.ParentMenu:Remove() -- self.ParentMenu:Remove()
end end
end end
end end
@@ -272,12 +254,11 @@ do -- MENU_BASE
-- @param #boolean RemoveParent If true, the parent menu is automatically removed when this menu is the last child menu of that parent @{Menu}. -- @param #boolean RemoveParent If true, the parent menu is automatically removed when this menu is the last child menu of that parent @{Menu}.
-- @return #MENU_BASE -- @return #MENU_BASE
function MENU_BASE:SetRemoveParent( RemoveParent ) function MENU_BASE:SetRemoveParent( RemoveParent )
--self:F( { RemoveParent } ) -- self:F( { RemoveParent } )
self.MenuRemoveParent = RemoveParent self.MenuRemoveParent = RemoveParent
return self return self
end end
--- Gets a @{Menu} from a parent @{Menu} --- Gets a @{Menu} from a parent @{Menu}
-- @param #MENU_BASE self -- @param #MENU_BASE self
-- @param #string MenuText The text of the child menu. -- @param #string MenuText The text of the child menu.
@@ -295,7 +276,6 @@ do -- MENU_BASE
return self return self
end end
--- Gets a menu stamp for later prevention of menu removal. --- Gets a menu stamp for later prevention of menu removal.
-- @param #MENU_BASE self -- @param #MENU_BASE self
-- @return MenuStamp -- @return MenuStamp
@@ -303,7 +283,6 @@ do -- MENU_BASE
return timer.getTime() return timer.getTime()
end end
--- Sets a time stamp for later prevention of menu removal. --- Sets a time stamp for later prevention of menu removal.
-- @param #MENU_BASE self -- @param #MENU_BASE self
-- @param MenuStamp -- @param MenuStamp
@@ -346,7 +325,7 @@ do -- MENU_COMMAND_BASE
-- @return #MENU_COMMAND_BASE -- @return #MENU_COMMAND_BASE
function MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, CommandMenuArguments ) function MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, CommandMenuArguments )
local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) -- #MENU_COMMAND_BASE local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) -- #MENU_COMMAND_BASE
-- When a menu function goes into error, DCS displays an obscure menu message. -- When a menu function goes into error, DCS displays an obscure menu message.
-- This error handler catches the menu error and displays the full call stack. -- This error handler catches the menu error and displays the full call stack.
@@ -367,7 +346,7 @@ do -- MENU_COMMAND_BASE
local Status, Result = xpcall( MenuFunction, ErrorHandler ) local Status, Result = xpcall( MenuFunction, ErrorHandler )
end end
return self return self
end end
--- This sets the new command function of a menu, --- This sets the new command function of a menu,
@@ -394,7 +373,6 @@ do -- MENU_COMMAND_BASE
end end
do -- MENU_MISSION do -- MENU_MISSION
--- @type MENU_MISSION --- @type MENU_MISSION
@@ -406,13 +384,13 @@ do -- MENU_MISSION
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION.Remove}. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION.Remove}.
-- @field #MENU_MISSION -- @field #MENU_MISSION
MENU_MISSION = { MENU_MISSION = {
ClassName = "MENU_MISSION" ClassName = "MENU_MISSION",
} }
--- MENU_MISSION constructor. Creates a new MENU_MISSION object and creates the menu for a complete mission file. --- MENU_MISSION constructor. Creates a new MENU_MISSION object and creates the menu for a complete mission file.
-- @param #MENU_MISSION self -- @param #MENU_MISSION self
-- @param #string MenuText The text for the menu. -- @param #string MenuText The text for the menu.
-- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the perent menu of DCS world (under F10 other). -- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the parent menu of DCS world (under F10 other).
-- @return #MENU_MISSION -- @return #MENU_MISSION
function MENU_MISSION:New( MenuText, ParentMenu ) function MENU_MISSION:New( MenuText, ParentMenu )
@@ -470,7 +448,7 @@ do -- MENU_MISSION
if MissionMenu == self then if MissionMenu == self then
self:RemoveSubMenus() self:RemoveSubMenus()
if not MenuStamp or self.MenuStamp ~= MenuStamp then if not MenuStamp or self.MenuStamp ~= MenuStamp then
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then
self:F( { Text = self.MenuText, Path = self.MenuPath } ) self:F( { Text = self.MenuText, Path = self.MenuPath } )
if self.MenuPath ~= nil then if self.MenuPath ~= nil then
missionCommands.removeItem( self.MenuPath ) missionCommands.removeItem( self.MenuPath )
@@ -487,8 +465,6 @@ do -- MENU_MISSION
return self return self
end end
end end
do -- MENU_MISSION_COMMAND do -- MENU_MISSION_COMMAND
@@ -503,7 +479,7 @@ do -- MENU_MISSION_COMMAND
-- --
-- @field #MENU_MISSION_COMMAND -- @field #MENU_MISSION_COMMAND
MENU_MISSION_COMMAND = { MENU_MISSION_COMMAND = {
ClassName = "MENU_MISSION_COMMAND" ClassName = "MENU_MISSION_COMMAND",
} }
--- MENU_MISSION constructor. Creates a new radio command item for a complete mission file, which can invoke a function with parameters. --- MENU_MISSION constructor. Creates a new radio command item for a complete mission file, which can invoke a function with parameters.
@@ -556,7 +532,7 @@ do -- MENU_MISSION_COMMAND
if MissionMenu == self then if MissionMenu == self then
if not MenuStamp or self.MenuStamp ~= MenuStamp then if not MenuStamp or self.MenuStamp ~= MenuStamp then
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then
self:F( { Text = self.MenuText, Path = self.MenuPath } ) self:F( { Text = self.MenuText, Path = self.MenuPath } )
if self.MenuPath ~= nil then if self.MenuPath ~= nil then
missionCommands.removeItem( self.MenuPath ) missionCommands.removeItem( self.MenuPath )
@@ -575,8 +551,6 @@ do -- MENU_MISSION_COMMAND
end end
do -- MENU_COALITION do -- MENU_COALITION
--- @type MENU_COALITION --- @type MENU_COALITION
@@ -627,14 +601,14 @@ do -- MENU_COALITION
-- --
-- @field #MENU_COALITION -- @field #MENU_COALITION
MENU_COALITION = { MENU_COALITION = {
ClassName = "MENU_COALITION" ClassName = "MENU_COALITION",
} }
--- MENU_COALITION constructor. Creates a new MENU_COALITION object and creates the menu for a complete coalition. --- MENU_COALITION constructor. Creates a new MENU_COALITION object and creates the menu for a complete coalition.
-- @param #MENU_COALITION self -- @param #MENU_COALITION self
-- @param DCS#coalition.side Coalition The coalition owning the menu. -- @param DCS#coalition.side Coalition The coalition owning the menu.
-- @param #string MenuText The text for the menu. -- @param #string MenuText The text for the menu.
-- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the perent menu of DCS world (under F10 other). -- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the parent menu of DCS world (under F10 other).
-- @return #MENU_COALITION self -- @return #MENU_COALITION self
function MENU_COALITION:New( Coalition, MenuText, ParentMenu ) function MENU_COALITION:New( Coalition, MenuText, ParentMenu )
@@ -693,7 +667,7 @@ do -- MENU_COALITION
if CoalitionMenu == self then if CoalitionMenu == self then
self:RemoveSubMenus() self:RemoveSubMenus()
if not MenuStamp or self.MenuStamp ~= MenuStamp then if not MenuStamp or self.MenuStamp ~= MenuStamp then
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then
self:F( { Coalition = self.Coalition, Text = self.MenuText, Path = self.MenuPath } ) self:F( { Coalition = self.Coalition, Text = self.MenuText, Path = self.MenuPath } )
if self.MenuPath ~= nil then if self.MenuPath ~= nil then
missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath ) missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath )
@@ -712,8 +686,6 @@ do -- MENU_COALITION
end end
do -- MENU_COALITION_COMMAND do -- MENU_COALITION_COMMAND
--- @type MENU_COALITION_COMMAND --- @type MENU_COALITION_COMMAND
@@ -726,7 +698,7 @@ do -- MENU_COALITION_COMMAND
-- --
-- @field #MENU_COALITION_COMMAND -- @field #MENU_COALITION_COMMAND
MENU_COALITION_COMMAND = { MENU_COALITION_COMMAND = {
ClassName = "MENU_COALITION_COMMAND" ClassName = "MENU_COALITION_COMMAND",
} }
--- MENU_COALITION constructor. Creates a new radio command item for a coalition, which can invoke a function with parameters. --- MENU_COALITION constructor. Creates a new radio command item for a coalition, which can invoke a function with parameters.
@@ -760,7 +732,6 @@ do -- MENU_COALITION_COMMAND
end end
--- Refreshes a radio item for a coalition --- Refreshes a radio item for a coalition
-- @param #MENU_COALITION_COMMAND self -- @param #MENU_COALITION_COMMAND self
-- @return #MENU_COALITION_COMMAND -- @return #MENU_COALITION_COMMAND
@@ -784,7 +755,7 @@ do -- MENU_COALITION_COMMAND
if CoalitionMenu == self then if CoalitionMenu == self then
if not MenuStamp or self.MenuStamp ~= MenuStamp then if not MenuStamp or self.MenuStamp ~= MenuStamp then
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then
self:F( { Coalition = self.Coalition, Text = self.MenuText, Path = self.MenuPath } ) self:F( { Coalition = self.Coalition, Text = self.MenuText, Path = self.MenuPath } )
if self.MenuPath ~= nil then if self.MenuPath ~= nil then
missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath ) missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath )
@@ -803,12 +774,11 @@ do -- MENU_COALITION_COMMAND
end end
--- MENU_GROUP --- MENU_GROUP
do do
-- This local variable is used to cache the menus registered under groups. -- This local variable is used to cache the menus registered under groups.
-- Menus don't dissapear when groups for players are destroyed and restarted. -- Menus don't disappear when groups for players are destroyed and restarted.
-- So every menu for a client created must be tracked so that program logic accidentally does not create. -- So every menu for a client created must be tracked so that program logic accidentally does not create.
-- the same menus twice during initialization logic. -- the same menus twice during initialization logic.
-- These menu classes are handling this logic with this variable. -- These menu classes are handling this logic with this variable.
@@ -817,7 +787,6 @@ do
--- @type MENU_GROUP --- @type MENU_GROUP
-- @extends Core.Menu#MENU_BASE -- @extends Core.Menu#MENU_BASE
--- Manages the main menus for @{Wrapper.Group}s. --- Manages the main menus for @{Wrapper.Group}s.
-- --
-- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference. -- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference.
@@ -875,7 +844,7 @@ do
-- --
-- @field #MENU_GROUP -- @field #MENU_GROUP
MENU_GROUP = { MENU_GROUP = {
ClassName = "MENU_GROUP" ClassName = "MENU_GROUP",
} }
--- MENU_GROUP constructor. Creates a new radio menu item for a group. --- MENU_GROUP constructor. Creates a new radio menu item for a group.
@@ -938,7 +907,6 @@ do
end end
--- Removes the main menu and sub menus recursively of this MENU_GROUP. --- Removes the main menu and sub menus recursively of this MENU_GROUP.
-- @param #MENU_GROUP self -- @param #MENU_GROUP self
-- @param MenuStamp -- @param MenuStamp
@@ -953,7 +921,7 @@ do
if GroupMenu == self then if GroupMenu == self then
self:RemoveSubMenus( MenuStamp, MenuTag ) self:RemoveSubMenus( MenuStamp, MenuTag )
if not MenuStamp or self.MenuStamp ~= MenuStamp then if not MenuStamp or self.MenuStamp ~= MenuStamp then
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then
if self.MenuPath ~= nil then if self.MenuPath ~= nil then
self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } )
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath ) missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
@@ -971,7 +939,6 @@ do
return self return self
end end
--- @type MENU_GROUP_COMMAND --- @type MENU_GROUP_COMMAND
-- @extends Core.Menu#MENU_COMMAND_BASE -- @extends Core.Menu#MENU_COMMAND_BASE
@@ -981,7 +948,7 @@ do
-- --
-- @field #MENU_GROUP_COMMAND -- @field #MENU_GROUP_COMMAND
MENU_GROUP_COMMAND = { MENU_GROUP_COMMAND = {
ClassName = "MENU_GROUP_COMMAND" ClassName = "MENU_GROUP_COMMAND",
} }
--- Creates a new radio command item for a group --- Creates a new radio command item for a group
@@ -1043,9 +1010,9 @@ do
if GroupMenu == self then if GroupMenu == self then
if not MenuStamp or self.MenuStamp ~= MenuStamp then if not MenuStamp or self.MenuStamp ~= MenuStamp then
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then
if self.MenuPath ~= nil then if self.MenuPath ~= nil then
self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } )
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath ) missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
end end
MENU_INDEX:ClearGroupMenu( self.Group, Path ) MENU_INDEX:ClearGroupMenu( self.Group, Path )
@@ -1069,7 +1036,6 @@ do
--- @type MENU_GROUP_DELAYED --- @type MENU_GROUP_DELAYED
-- @extends Core.Menu#MENU_BASE -- @extends Core.Menu#MENU_BASE
--- The MENU_GROUP_DELAYED class manages the main menus for groups. --- The MENU_GROUP_DELAYED class manages the main menus for groups.
-- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference. -- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference.
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP.Remove}. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP.Remove}.
@@ -1079,7 +1045,7 @@ do
-- --
-- @field #MENU_GROUP_DELAYED -- @field #MENU_GROUP_DELAYED
MENU_GROUP_DELAYED = { MENU_GROUP_DELAYED = {
ClassName = "MENU_GROUP_DELAYED" ClassName = "MENU_GROUP_DELAYED",
} }
--- MENU_GROUP_DELAYED constructor. Creates a new radio menu item for a group. --- MENU_GROUP_DELAYED constructor. Creates a new radio menu item for a group.
@@ -1116,7 +1082,6 @@ do
end end
--- Refreshes a new radio item for a group and submenus --- Refreshes a new radio item for a group and submenus
-- @param #MENU_GROUP_DELAYED self -- @param #MENU_GROUP_DELAYED self
-- @return #MENU_GROUP_DELAYED -- @return #MENU_GROUP_DELAYED
@@ -1135,7 +1100,6 @@ do
end end
--- Refreshes a new radio item for a group and submenus --- Refreshes a new radio item for a group and submenus
-- @param #MENU_GROUP_DELAYED self -- @param #MENU_GROUP_DELAYED self
-- @return #MENU_GROUP_DELAYED -- @return #MENU_GROUP_DELAYED
@@ -1167,7 +1131,6 @@ do
end end
--- Removes the main menu and sub menus recursively of this MENU_GROUP. --- Removes the main menu and sub menus recursively of this MENU_GROUP.
-- @param #MENU_GROUP_DELAYED self -- @param #MENU_GROUP_DELAYED self
-- @param MenuStamp -- @param MenuStamp
@@ -1182,7 +1145,7 @@ do
if GroupMenu == self then if GroupMenu == self then
self:RemoveSubMenus( MenuStamp, MenuTag ) self:RemoveSubMenus( MenuStamp, MenuTag )
if not MenuStamp or self.MenuStamp ~= MenuStamp then if not MenuStamp or self.MenuStamp ~= MenuStamp then
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then
if self.MenuPath ~= nil then if self.MenuPath ~= nil then
self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } )
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath ) missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
@@ -1200,7 +1163,6 @@ do
return self return self
end end
--- @type MENU_GROUP_COMMAND_DELAYED --- @type MENU_GROUP_COMMAND_DELAYED
-- @extends Core.Menu#MENU_COMMAND_BASE -- @extends Core.Menu#MENU_COMMAND_BASE
@@ -1211,7 +1173,7 @@ do
-- --
-- @field #MENU_GROUP_COMMAND_DELAYED -- @field #MENU_GROUP_COMMAND_DELAYED
MENU_GROUP_COMMAND_DELAYED = { MENU_GROUP_COMMAND_DELAYED = {
ClassName = "MENU_GROUP_COMMAND_DELAYED" ClassName = "MENU_GROUP_COMMAND_DELAYED",
} }
--- Creates a new radio command item for a group --- Creates a new radio command item for a group
@@ -1292,7 +1254,7 @@ do
if GroupMenu == self then if GroupMenu == self then
if not MenuStamp or self.MenuStamp ~= MenuStamp then if not MenuStamp or self.MenuStamp ~= MenuStamp then
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then
if self.MenuPath ~= nil then if self.MenuPath ~= nil then
self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } )
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath ) missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
+116 -110
View File
@@ -56,9 +56,9 @@
-- --
-- @field #MESSAGE -- @field #MESSAGE
MESSAGE = { MESSAGE = {
ClassName = "MESSAGE", ClassName = "MESSAGE",
MessageCategory = 0, MessageCategory = 0,
MessageID = 0, MessageID = 0,
} }
--- Message Types --- Message Types
@@ -68,10 +68,9 @@ MESSAGE.Type = {
Information = "Information", Information = "Information",
Briefing = "Briefing Report", Briefing = "Briefing Report",
Overview = "Overview Report", Overview = "Overview Report",
Detailed = "Detailed Report" Detailed = "Detailed Report",
} }
--- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients. --- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients.
-- @param self -- @param self
-- @param #string MessageText is the text of the Message. -- @param #string MessageText is the text of the Message.
@@ -80,25 +79,26 @@ MESSAGE.Type = {
-- @param #boolean ClearScreen (optional) Clear all previous messages if true. -- @param #boolean ClearScreen (optional) Clear all previous messages if true.
-- @return #MESSAGE -- @return #MESSAGE
-- @usage -- @usage
-- -- Create a series of new Messages. --
-- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score". -- -- Create a series of new Messages.
-- -- MessageRED is meant to be sent to the RED players only, for 10 seconds, and is classified as "End of Mission", with ID "Win". -- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score".
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "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" ) -- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" ) -- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", 25, "End of Mission" )
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" ) -- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" )
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score") -- 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( MessageText, MessageDuration, MessageCategory, ClearScreen )
local self = BASE:Inherit( self, BASE:New() ) local self = BASE:Inherit( self, BASE:New() )
self:F( { MessageText, MessageDuration, MessageCategory } ) self:F( { MessageText, MessageDuration, MessageCategory } )
self.MessageType = nil self.MessageType = nil
-- When no MessageCategory is given, we don't show it as a title... -- When no MessageCategory is given, we don't show it as a title...
if MessageCategory and MessageCategory ~= "" then if MessageCategory and MessageCategory ~= "" then
if MessageCategory:sub(-1) ~= "\n" then if MessageCategory:sub( -1 ) ~= "\n" then
self.MessageCategory = MessageCategory .. ": " self.MessageCategory = MessageCategory .. ": "
else else
self.MessageCategory = MessageCategory:sub( 1, -2 ) .. ":\n" self.MessageCategory = MessageCategory:sub( 1, -2 ) .. ":\n"
@@ -107,23 +107,22 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen
self.MessageCategory = "" self.MessageCategory = ""
end end
self.ClearScreen=false self.ClearScreen = false
if ClearScreen~=nil then if ClearScreen ~= nil then
self.ClearScreen=ClearScreen self.ClearScreen = ClearScreen
end end
self.MessageDuration = MessageDuration or 5 self.MessageDuration = MessageDuration or 5
self.MessageTime = timer.getTime() self.MessageTime = timer.getTime()
self.MessageText = MessageText:gsub("^\n","",1):gsub("\n$","",1) self.MessageText = MessageText:gsub( "^\n", "", 1 ):gsub( "\n$", "", 1 )
self.MessageSent = false self.MessageSent = false
self.MessageGroup = false self.MessageGroup = false
self.MessageCoalition = false self.MessageCoalition = false
return self return self
end end
--- Creates a new MESSAGE object of a certain type. --- Creates a new MESSAGE object of a certain type.
-- Note that these MESSAGE objects are not yet displayed on the display panel. -- Note that these MESSAGE objects are not yet displayed on the display panel.
-- You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients. -- You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients.
@@ -134,10 +133,12 @@ end
-- @param #boolean ClearScreen (optional) Clear all previous messages. -- @param #boolean ClearScreen (optional) Clear all previous messages.
-- @return #MESSAGE -- @return #MESSAGE
-- @usage -- @usage
--
-- MessageAll = MESSAGE:NewType( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", MESSAGE.Type.Information ) -- MessageAll = MESSAGE:NewType( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", MESSAGE.Type.Information )
-- MessageRED = MESSAGE:NewType( "To the RED Players: You receive a penalty because you've killed one of your own units", MESSAGE.Type.Information ) -- MessageRED = MESSAGE:NewType( "To the RED Players: You receive a penalty because you've killed one of your own units", MESSAGE.Type.Information )
-- MessageClient1 = MESSAGE:NewType( "Congratulations, you've just hit a target", MESSAGE.Type.Update ) -- MessageClient1 = MESSAGE:NewType( "Congratulations, you've just hit a target", MESSAGE.Type.Update )
-- MessageClient2 = MESSAGE:NewType( "Congratulations, you've just killed a target", MESSAGE.Type.Update ) -- MessageClient2 = MESSAGE:NewType( "Congratulations, you've just killed a target", MESSAGE.Type.Update )
--
function MESSAGE:NewType( MessageText, MessageType, ClearScreen ) function MESSAGE:NewType( MessageText, MessageType, ClearScreen )
local self = BASE:Inherit( self, BASE:New() ) local self = BASE:Inherit( self, BASE:New() )
@@ -145,69 +146,67 @@ function MESSAGE:NewType( MessageText, MessageType, ClearScreen )
self.MessageType = MessageType self.MessageType = MessageType
self.ClearScreen=false self.ClearScreen = false
if ClearScreen~=nil then if ClearScreen ~= nil then
self.ClearScreen=ClearScreen self.ClearScreen = ClearScreen
end end
self.MessageTime = timer.getTime() self.MessageTime = timer.getTime()
self.MessageText = MessageText:gsub("^\n","",1):gsub("\n$","",1) self.MessageText = MessageText:gsub( "^\n", "", 1 ):gsub( "\n$", "", 1 )
return self return self
end end
--- Clears all previous messages from the screen before the new message is displayed. Not that this must come before all functions starting with ToX(), e.g. ToAll(), ToGroup() etc. --- Clears all previous messages from the screen before the new message is displayed. Not that this must come before all functions starting with ToX(), e.g. ToAll(), ToGroup() etc.
-- @param #MESSAGE self -- @param #MESSAGE self
-- @return #MESSAGE -- @return #MESSAGE
function MESSAGE:Clear() function MESSAGE:Clear()
self:F() self:F()
self.ClearScreen=true self.ClearScreen = true
return self return self
end end
--- Sends a MESSAGE to a Client Group. Note that the Group needs to be defined within the ME with the skillset "Client" or "Player". --- Sends a MESSAGE to a Client Group. Note that the Group needs to be defined within the ME with the skillset "Client" or "Player".
-- @param #MESSAGE self -- @param #MESSAGE self
-- @param Wrapper.Client#CLIENT Client is the Group of the Client. -- @param Wrapper.Client#CLIENT Client is the Group of the Client.
-- @param Core.Settings#SETTINGS Settings Settings used to display the message. -- @param Core.Settings#SETTINGS Settings Settings used to display the message.
-- @return #MESSAGE -- @return #MESSAGE
-- @usage -- @usage
-- -- Send the 2 messages created with the @{New} method to the Client Group.
-- -- Note that the Message of MessageClient2 is overwriting the Message of MessageClient1.
-- ClientGroup = Group.getByName( "ClientGroup" )
-- --
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup ) -- -- Send the 2 messages created with the @{New} method to the Client Group.
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup ) -- -- Note that the Message of MessageClient2 is overwriting the Message of MessageClient1.
-- or -- ClientGroup = Group.getByName( "ClientGroup" )
-- MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup ) --
-- MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup ) -- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
-- or -- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ) -- or
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ) -- MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
-- MessageClient1:ToClient( ClientGroup ) -- MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
-- MessageClient2:ToClient( ClientGroup ) -- or
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" )
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" )
-- MessageClient1:ToClient( ClientGroup )
-- MessageClient2:ToClient( ClientGroup )
--
function MESSAGE:ToClient( Client, Settings ) function MESSAGE:ToClient( Client, Settings )
self:F( Client ) self:F( Client )
if Client and Client:GetClientGroupID() then if Client and Client:GetClientGroupID() then
if self.MessageType then if self.MessageType then
local Settings = Settings or ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS local Settings = Settings or (Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() )) or _SETTINGS -- Core.Settings#SETTINGS
self.MessageDuration = Settings:GetMessageTime( self.MessageType ) self.MessageDuration = Settings:GetMessageTime( self.MessageType )
self.MessageCategory = "" -- self.MessageType .. ": " self.MessageCategory = "" -- self.MessageType .. ": "
end end
if self.MessageDuration ~= 0 then if self.MessageDuration ~= 0 then
local ClientGroupID = Client:GetClientGroupID() local ClientGroupID = Client:GetClientGroupID()
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen) trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
end end
end end
return self return self
end end
--- Sends a MESSAGE to a Group. --- Sends a MESSAGE to a Group.
@@ -220,14 +219,14 @@ function MESSAGE:ToGroup( Group, Settings )
if Group then if Group then
if self.MessageType then if self.MessageType then
local Settings = Settings or ( Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS local Settings = Settings or (Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() )) or _SETTINGS -- Core.Settings#SETTINGS
self.MessageDuration = Settings:GetMessageTime( self.MessageType ) self.MessageDuration = Settings:GetMessageTime( self.MessageType )
self.MessageCategory = "" -- self.MessageType .. ": " self.MessageCategory = "" -- self.MessageType .. ": "
end end
if self.MessageDuration ~= 0 then if self.MessageDuration ~= 0 then
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen ) trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
end end
end end
@@ -237,38 +236,42 @@ end
-- @param #MESSAGE self -- @param #MESSAGE self
-- @return #MESSAGE -- @return #MESSAGE
-- @usage -- @usage
-- -- Send a message created with the @{New} method to the BLUE coalition. --
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue() -- -- Send a message created with the @{New} method to the BLUE coalition.
-- or -- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue()
-- MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue() -- or
-- or -- MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue()
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) -- or
-- MessageBLUE:ToBlue() -- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
-- MessageBLUE:ToBlue()
--
function MESSAGE:ToBlue() function MESSAGE:ToBlue()
self:F() self:F()
self:ToCoalition( coalition.side.BLUE ) self:ToCoalition( coalition.side.BLUE )
return self return self
end end
--- Sends a MESSAGE to the Red Coalition. --- Sends a MESSAGE to the Red Coalition.
-- @param #MESSAGE self -- @param #MESSAGE self
-- @return #MESSAGE -- @return #MESSAGE
-- @usage -- @usage
-- -- Send a message created with the @{New} method to the RED coalition. --
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed() -- -- Send a message created with the @{New} method to the RED coalition.
-- or -- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed()
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed() -- or
-- or -- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed()
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) -- or
-- MessageRED:ToRed() -- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
function MESSAGE:ToRed( ) -- MessageRED:ToRed()
self:F() --
function MESSAGE:ToRed()
self:F()
self:ToCoalition( coalition.side.RED ) self:ToCoalition( coalition.side.RED )
return self return self
end end
--- Sends a MESSAGE to a Coalition. --- Sends a MESSAGE to a Coalition.
@@ -277,15 +280,17 @@ end
-- @param Core.Settings#SETTINGS Settings (Optional) Settings for message display. -- @param Core.Settings#SETTINGS Settings (Optional) Settings for message display.
-- @return #MESSAGE Message object. -- @return #MESSAGE Message object.
-- @usage -- @usage
-- -- Send a message created with the @{New} method to the RED coalition. --
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED ) -- -- Send a message created with the @{New} method to the RED coalition.
-- or -- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED )
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED ) -- or
-- or -- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED )
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) -- or
-- MessageRED:ToCoalition( coalition.side.RED ) -- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
-- MessageRED:ToCoalition( coalition.side.RED )
--
function MESSAGE:ToCoalition( CoalitionSide, Settings ) function MESSAGE:ToCoalition( CoalitionSide, Settings )
self:F( CoalitionSide ) self:F( CoalitionSide )
if self.MessageType then if self.MessageType then
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
@@ -293,14 +298,14 @@ function MESSAGE:ToCoalition( CoalitionSide, Settings )
self.MessageCategory = "" -- self.MessageType .. ": " self.MessageCategory = "" -- self.MessageType .. ": "
end end
if CoalitionSide then if CoalitionSide then
if self.MessageDuration ~= 0 then if self.MessageDuration ~= 0 then
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
trigger.action.outTextForCoalition( CoalitionSide, self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen ) trigger.action.outTextForCoalition( CoalitionSide, self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
end end
end end
return self return self
end end
--- Sends a MESSAGE to a Coalition if the given Condition is true. --- Sends a MESSAGE to a Coalition if the given Condition is true.
@@ -323,14 +328,16 @@ end
-- @param Core.Settings#Settings Settings (Optional) Settings for message display. -- @param Core.Settings#Settings Settings (Optional) Settings for message display.
-- @return #MESSAGE -- @return #MESSAGE
-- @usage -- @usage
-- -- Send a message created to all players. --
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll() -- -- Send a message created to all players.
-- or -- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll()
-- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll() -- or
-- or -- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll()
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ) -- or
-- MessageAll:ToAll() -- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" )
function MESSAGE:ToAll(Settings) -- MessageAll:ToAll()
--
function MESSAGE:ToAll( Settings )
self:F() self:F()
if self.MessageType then if self.MessageType then
@@ -340,14 +347,13 @@ function MESSAGE:ToAll(Settings)
end end
if self.MessageDuration ~= 0 then if self.MessageDuration ~= 0 then
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
trigger.action.outText( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen ) trigger.action.outText( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
end end
return self return self
end end
--- Sends a MESSAGE to all players if the given Condition is true. --- Sends a MESSAGE to all players if the given Condition is true.
-- @param #MESSAGE self -- @param #MESSAGE self
-- @return #MESSAGE -- @return #MESSAGE
@@ -357,5 +363,5 @@ function MESSAGE:ToAllIf( Condition )
self:ToAll() self:ToAll()
end end
return self return self
end end
+207 -76
View File
@@ -26,19 +26,28 @@
-- --
-- ### Authors: -- ### Authors:
-- --
-- * FlightControl : Design & Programming -- * FlightControl (Design & Programming)
-- --
-- ### Contributions: -- ### Contributions:
-- --
-- * funkyfranky
-- * Applevangelist
--
-- ===
--
-- @module Core.Point -- @module Core.Point
-- @image Core_Coordinate.JPG -- @image Core_Coordinate.JPG
do -- COORDINATE do -- COORDINATE
--- @type COORDINATE --- @type COORDINATE
-- @field #string ClassName Name of the class
-- @field #number x Component of the 3D vector.
-- @field #number y Component of the 3D vector.
-- @field #number z Component of the 3D vector.
-- @field #number Heading Heading in degrees. Needs to be set first.
-- @field #number Velocity Velocity in meters per second. Needs to be set first.
-- @extends Core.Base#BASE -- @extends Core.Base#BASE
@@ -201,28 +210,53 @@ do -- COORDINATE
ClassName = "COORDINATE", ClassName = "COORDINATE",
} }
--- @field COORDINATE.WaypointAltType --- Waypoint altitude types.
-- @type COORDINATE.WaypointAltType
-- @field #string BARO Barometric altitude.
-- @field #string RADIO Radio altitude.
COORDINATE.WaypointAltType = { COORDINATE.WaypointAltType = {
BARO = "BARO", BARO = "BARO",
RADIO = "RADIO", RADIO = "RADIO",
} }
--- @field COORDINATE.WaypointAction --- Waypoint actions.
-- @type COORDINATE.WaypointAction
-- @field #string TurningPoint Turning point.
-- @field #string FlyoverPoint Fly over point.
-- @field #string FromParkingArea From parking area.
-- @field #string FromParkingAreaHot From parking area hot.
-- @field #string FromGroundAreaHot From ground area hot.
-- @field #string FromGroundArea From ground area.
-- @field #string FromRunway From runway.
-- @field #string Landing Landing.
-- @field #string LandingReFuAr Landing and refuel and rearm.
COORDINATE.WaypointAction = { COORDINATE.WaypointAction = {
TurningPoint = "Turning Point", TurningPoint = "Turning Point",
FlyoverPoint = "Fly Over Point", FlyoverPoint = "Fly Over Point",
FromParkingArea = "From Parking Area", FromParkingArea = "From Parking Area",
FromParkingAreaHot = "From Parking Area Hot", FromParkingAreaHot = "From Parking Area Hot",
FromGroundAreaHot = "From Ground Area Hot",
FromGroundArea = "From Ground Area",
FromRunway = "From Runway", FromRunway = "From Runway",
Landing = "Landing", Landing = "Landing",
LandingReFuAr = "LandingReFuAr", LandingReFuAr = "LandingReFuAr",
} }
--- @field COORDINATE.WaypointType --- Waypoint types.
-- @type COORDINATE.WaypointType
-- @field #string TakeOffParking Take of parking.
-- @field #string TakeOffParkingHot Take of parking hot.
-- @field #string TakeOff Take off parking hot.
-- @field #string TakeOffGroundHot Take of from ground hot.
-- @field #string TurningPoint Turning point.
-- @field #string Land Landing point.
-- @field #string LandingReFuAr Landing and refuel and rearm.
COORDINATE.WaypointType = { COORDINATE.WaypointType = {
TakeOffParking = "TakeOffParking", TakeOffParking = "TakeOffParking",
TakeOffParkingHot = "TakeOffParkingHot", TakeOffParkingHot = "TakeOffParkingHot",
TakeOff = "TakeOffParkingHot", TakeOff = "TakeOffParkingHot",
TakeOffGroundHot = "TakeOffGroundHot",
TakeOffGround = "TakeOffGround",
TurningPoint = "Turning Point", TurningPoint = "Turning Point",
Land = "Land", Land = "Land",
LandingReFuAr = "LandingReFuAr", LandingReFuAr = "LandingReFuAr",
@@ -232,13 +266,13 @@ do -- COORDINATE
--- COORDINATE constructor. --- COORDINATE constructor.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @param DCS#Distance x The x coordinate of the Vec3 point, pointing to the North. -- @param DCS#Distance x The x coordinate of the Vec3 point, pointing to the North.
-- @param DCS#Distance y The y coordinate of the Vec3 point, pointing to the Right. -- @param DCS#Distance y The y coordinate of the Vec3 point, pointing to up.
-- @param DCS#Distance z The z coordinate of the Vec3 point, pointing to the Right. -- @param DCS#Distance z The z coordinate of the Vec3 point, pointing to the right.
-- @return #COORDINATE -- @return #COORDINATE self
function COORDINATE:New( x, y, z ) function COORDINATE:New( x, y, z )
--env.info("FF COORDINATE New") local self=BASE:Inherit(self, BASE:New()) -- #COORDINATE
local self = BASE:Inherit( self, BASE:New() ) -- #COORDINATE
self.x = x self.x = x
self.y = y self.y = y
self.z = z self.z = z
@@ -249,7 +283,7 @@ do -- COORDINATE
--- COORDINATE constructor. --- COORDINATE constructor.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @param #COORDINATE Coordinate. -- @param #COORDINATE Coordinate.
-- @return #COORDINATE -- @return #COORDINATE self
function COORDINATE:NewFromCoordinate( Coordinate ) function COORDINATE:NewFromCoordinate( Coordinate )
local self = BASE:Inherit( self, BASE:New() ) -- #COORDINATE local self = BASE:Inherit( self, BASE:New() ) -- #COORDINATE
@@ -263,8 +297,8 @@ do -- COORDINATE
--- Create a new COORDINATE object from Vec2 coordinates. --- Create a new COORDINATE object from Vec2 coordinates.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @param DCS#Vec2 Vec2 The Vec2 point. -- @param DCS#Vec2 Vec2 The Vec2 point.
-- @param DCS#Distance LandHeightAdd (optional) The default height if required to be evaluated will be the land height of the x, y coordinate. You can specify an extra height to be added to the land height. -- @param DCS#Distance LandHeightAdd (Optional) The default height if required to be evaluated will be the land height of the x, y coordinate. You can specify an extra height to be added to the land height.
-- @return #COORDINATE -- @return #COORDINATE self
function COORDINATE:NewFromVec2( Vec2, LandHeightAdd ) function COORDINATE:NewFromVec2( Vec2, LandHeightAdd )
local LandHeight = land.getHeight( Vec2 ) local LandHeight = land.getHeight( Vec2 )
@@ -274,8 +308,6 @@ do -- COORDINATE
local self = self:New( Vec2.x, LandHeight, Vec2.y ) -- #COORDINATE local self = self:New( Vec2.x, LandHeight, Vec2.y ) -- #COORDINATE
self:F2( self )
return self return self
end end
@@ -283,7 +315,7 @@ do -- COORDINATE
--- Create a new COORDINATE object from Vec3 coordinates. --- Create a new COORDINATE object from Vec3 coordinates.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @param DCS#Vec3 Vec3 The Vec3 point. -- @param DCS#Vec3 Vec3 The Vec3 point.
-- @return #COORDINATE -- @return #COORDINATE self
function COORDINATE:NewFromVec3( Vec3 ) function COORDINATE:NewFromVec3( Vec3 )
local self = self:New( Vec3.x, Vec3.y, Vec3.z ) -- #COORDINATE local self = self:New( Vec3.x, Vec3.y, Vec3.z ) -- #COORDINATE
@@ -293,6 +325,28 @@ do -- COORDINATE
return self return self
end end
--- Create a new COORDINATE object from a waypoint. This uses the components
--
-- * `waypoint.x`
-- * `waypoint.alt`
-- * `waypoint.y`
--
-- @param #COORDINATE self
-- @param DCS#Waypoint Waypoint The waypoint.
-- @return #COORDINATE self
function COORDINATE:NewFromWaypoint(Waypoint)
local self=self:New(Waypoint.x, Waypoint.alt, Waypoint.y) -- #COORDINATE
return self
end
--- Return the coordinates itself. Sounds stupid but can be useful for compatibility.
-- @param #COORDINATE self
-- @return #COORDINATE self
function COORDINATE:GetCoordinate()
return self
end
--- Return the coordinates of the COORDINATE in Vec3 format. --- Return the coordinates of the COORDINATE in Vec3 format.
-- @param #COORDINATE self -- @param #COORDINATE self
@@ -398,7 +452,7 @@ do -- COORDINATE
-- @return #boolean True if units were found. -- @return #boolean True if units were found.
-- @return #boolean True if statics were found. -- @return #boolean True if statics were found.
-- @return #boolean True if scenery objects were found. -- @return #boolean True if scenery objects were found.
-- @return #table Table of MOOSE @[#Wrapper.Unit#UNIT} objects found. -- @return #table Table of MOOSE @{Wrapper.Unit#UNIT} objects found.
-- @return #table Table of DCS static objects found. -- @return #table Table of DCS static objects found.
-- @return #table Table of DCS scenery objects found. -- @return #table Table of DCS scenery objects found.
function COORDINATE:ScanObjects(radius, scanunits, scanstatics, scanscenery) function COORDINATE:ScanObjects(radius, scanunits, scanstatics, scanscenery)
@@ -486,7 +540,7 @@ do -- COORDINATE
end end
for _,scenery in pairs(Scenery) do for _,scenery in pairs(Scenery) do
self:T(string.format("Scan found scenery %s typename=%s", scenery:getName(), scenery:getTypeName())) self:T(string.format("Scan found scenery %s typename=%s", scenery:getName(), scenery:getTypeName()))
SCENERY:Register(scenery:getName(), scenery) --SCENERY:Register(scenery:getName(), scenery)
end end
return gotunits, gotstatics, gotscenery, Units, Statics, Scenery return gotunits, gotstatics, gotscenery, Units, Statics, Scenery
@@ -532,6 +586,50 @@ do -- COORDINATE
return umin return umin
end end
--- Scan/find SCENERY objects within a certain radius around the coordinate using the world.searchObjects() DCS API function.
-- @param #COORDINATE self
-- @param #number radius (Optional) Scan radius in meters. Default 100 m.
-- @return table Set of scenery objects.
function COORDINATE:ScanScenery(radius)
local _,_,_,_,_,scenerys=self:ScanObjects(radius, false, false, true)
local set={}
for _,_scenery in pairs(scenerys) do
local scenery=_scenery --DCS#Object
local name=scenery:getName()
local s=SCENERY:Register(name, scenery)
table.insert(set, s)
end
return set
end
--- Find the closest scenery to the COORDINATE within a certain radius.
-- @param #COORDINATE self
-- @param #number radius Scan radius in meters. Default 100 m.
-- @return Wrapper.Scenery#SCENERY The closest scenery or #nil if no object is inside the given radius.
function COORDINATE:FindClosestScenery(radius)
local sceneries=self:ScanScenery(radius)
local umin=nil --Wrapper.Scenery#SCENERY
local dmin=math.huge
for _,_scenery in pairs(sceneries) do
local scenery=_scenery --Wrapper.Scenery#SCENERY
local coordinate=scenery:GetCoordinate()
local d=self:Get2DDistance(coordinate)
if d<dmin then
dmin=d
umin=scenery
end
end
return umin
end
--- Calculate the distance from a reference @{#COORDINATE}. --- Calculate the distance from a reference @{#COORDINATE}.
-- @param #COORDINATE self -- @param #COORDINATE self
@@ -597,7 +695,8 @@ do -- COORDINATE
local y=X*math.sin(phi)+Y*math.cos(phi) local y=X*math.sin(phi)+Y*math.cos(phi)
-- Coordinate assignment looks bit strange but is correct. -- Coordinate assignment looks bit strange but is correct.
return COORDINATE:NewFromVec3({x=y, y=self.y, z=x}) local coord=COORDINATE:NewFromVec3({x=y, y=self.y, z=x})
return coord
end end
--- Return a random Vec2 within an Outer Radius and optionally NOT within an Inner Radius of the COORDINATE. --- Return a random Vec2 within an Outer Radius and optionally NOT within an Inner Radius of the COORDINATE.
@@ -640,7 +739,8 @@ do -- COORDINATE
function COORDINATE:GetRandomCoordinateInRadius( OuterRadius, InnerRadius ) function COORDINATE:GetRandomCoordinateInRadius( OuterRadius, InnerRadius )
self:F2( { OuterRadius, InnerRadius } ) self:F2( { OuterRadius, InnerRadius } )
return COORDINATE:NewFromVec2( self:GetRandomVec2InRadius( OuterRadius, InnerRadius ) ) local coord=COORDINATE:NewFromVec2( self:GetRandomVec2InRadius( OuterRadius, InnerRadius ) )
return coord
end end
@@ -698,6 +798,13 @@ do -- COORDINATE
return Velocity or 0 return Velocity or 0
end end
--- Return the "name" of the COORDINATE. Obviously, a coordinate does not have a name like a unit, static or group. So here we take the MGRS coordinates of the position.
-- @param #COORDINATE self
-- @return #string MGRS coordinates.
function COORDINATE:GetName()
local name=self:ToStringMGRS()
return name
end
--- Return velocity text of the COORDINATE. --- Return velocity text of the COORDINATE.
-- @param #COORDINATE self -- @param #COORDINATE self
@@ -783,10 +890,8 @@ do -- COORDINATE
local a={x=TargetCoordinate.x-self.x, y=0, z=TargetCoordinate.z-self.z} local a={x=TargetCoordinate.x-self.x, y=0, z=TargetCoordinate.z-self.z}
local d=UTILS.VecNorm(a) local norm=UTILS.VecNorm(a)
return norm
return d
end end
--- Returns the temperature in Degrees Celsius. --- Returns the temperature in Degrees Celsius.
@@ -807,7 +912,7 @@ do -- COORDINATE
-- The text will reflect the temperature like this: -- The text will reflect the temperature like this:
-- --
-- - For Russian and European aircraft using the metric system - Degrees Celcius (°C) -- - For Russian and European aircraft using the metric system - Degrees Celcius (°C)
-- - For Americain aircraft we link to the imperial system - Degrees Farenheit (°F) -- - For American aircraft we link to the imperial system - Degrees Farenheit (°F)
-- --
-- A text containing a pressure will look like this: -- A text containing a pressure will look like this:
-- --
@@ -853,7 +958,7 @@ do -- COORDINATE
-- The text will contain always the pressure in hPa and: -- The text will contain always the pressure in hPa and:
-- --
-- - For Russian and European aircraft using the metric system - hPa and mmHg -- - For Russian and European aircraft using the metric system - hPa and mmHg
-- - For Americain and European aircraft we link to the imperial system - hPa and inHg -- - For American and European aircraft we link to the imperial system - hPa and inHg
-- --
-- A text containing a pressure will look like this: -- A text containing a pressure will look like this:
-- --
@@ -946,7 +1051,7 @@ do -- COORDINATE
-- The text will reflect the wind like this: -- The text will reflect the wind like this:
-- --
-- - For Russian and European aircraft using the metric system - Wind direction in degrees (°) and wind speed in meters per second (mps). -- - For Russian and European aircraft using the metric system - Wind direction in degrees (°) and wind speed in meters per second (mps).
-- - For Americain aircraft we link to the imperial system - Wind direction in degrees (°) and wind speed in knots per second (kps). -- - For American aircraft we link to the imperial system - Wind direction in degrees (°) and wind speed in knots per second (kps).
-- --
-- A text containing a pressure will look like this: -- A text containing a pressure will look like this:
-- --
@@ -1552,8 +1657,12 @@ do -- COORDINATE
roadtype="railroads" roadtype="railroads"
end end
local x,y = land.getClosestPointOnRoads(roadtype, self.x, self.z) local x,y = land.getClosestPointOnRoads(roadtype, self.x, self.z)
local vec2={ x = x, y = y } local coord=nil
return COORDINATE:NewFromVec2(vec2) if x and y then
local vec2={ x = x, y = y }
coord=COORDINATE:NewFromVec2(vec2)
end
return coord
end end
@@ -1659,7 +1768,7 @@ do -- COORDINATE
return self:GetSurfaceType()==land.SurfaceType.LAND return self:GetSurfaceType()==land.SurfaceType.LAND
end end
--- Checks if the surface type is road. --- Checks if the surface type is land.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @return #boolean If true, the surface type at the coordinate is land. -- @return #boolean If true, the surface type at the coordinate is land.
function COORDINATE:IsSurfaceTypeLand() function COORDINATE:IsSurfaceTypeLand()
@@ -1699,26 +1808,31 @@ do -- COORDINATE
--- Creates an explosion at the point of a certain intensity. --- Creates an explosion at the point of a certain intensity.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @param #number ExplosionIntensity Intensity of the explosion in kg TNT. Default 100 kg. -- @param #number ExplosionIntensity Intensity of the explosion in kg TNT. Default 100 kg.
-- @param #number Delay Delay before explosion in seconds. -- @param #number Delay (Optional) Delay before explosion is triggered in seconds.
-- @return #COORDINATE self -- @return #COORDINATE self
function COORDINATE:Explosion( ExplosionIntensity, Delay ) function COORDINATE:Explosion( ExplosionIntensity, Delay )
self:F2( { ExplosionIntensity } )
ExplosionIntensity=ExplosionIntensity or 100 ExplosionIntensity=ExplosionIntensity or 100
if Delay and Delay>0 then if Delay and Delay>0 then
SCHEDULER:New(nil, self.Explosion, {self,ExplosionIntensity}, Delay) self:ScheduleOnce(Delay, self.Explosion, self, ExplosionIntensity)
else else
trigger.action.explosion( self:GetVec3(), ExplosionIntensity ) trigger.action.explosion(self:GetVec3(), ExplosionIntensity)
end end
return self return self
end end
--- Creates an illumination bomb at the point. --- Creates an illumination bomb at the point.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @param #number power Power of illumination bomb in Candela. -- @param #number Power Power of illumination bomb in Candela. Default 1000 cd.
-- @param #number Delay (Optional) Delay before bomb is ignited in seconds.
-- @return #COORDINATE self -- @return #COORDINATE self
function COORDINATE:IlluminationBomb(power) function COORDINATE:IlluminationBomb(Power, Delay)
self:F2() Power=Power or 1000
trigger.action.illuminationBomb( self:GetVec3(), power ) if Delay and Delay>0 then
self:ScheduleOnce(Delay, self.IlluminationBomb, self, Power)
else
trigger.action.illuminationBomb(self:GetVec3(), Power)
end
return self
end end
@@ -1767,84 +1881,103 @@ do -- COORDINATE
--- Big smoke and fire at the coordinate. --- Big smoke and fire at the coordinate.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @param Utilities.Utils#BIGSMOKEPRESET preset Smoke preset (0=small smoke and fire, 1=medium smoke and fire, 2=large smoke and fire, 3=huge smoke and fire, 4=small smoke, 5=medium smoke, 6=large smoke, 7=huge smoke). -- @param Utilities.Utils#BIGSMOKEPRESET preset Smoke preset (1=small smoke and fire, 2=medium smoke and fire, 3=large smoke and fire, 4=huge smoke and fire, 5=small smoke, 6=medium smoke, 7=large smoke, 8=huge smoke).
-- @param #number density (Optional) Smoke density. Number in [0,...,1]. Default 0.5. -- @param #number density (Optional) Smoke density. Number in [0,...,1]. Default 0.5.
function COORDINATE:BigSmokeAndFire( preset, density ) -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
function COORDINATE:BigSmokeAndFire( preset, density, name )
self:F2( { preset=preset, density=density } ) self:F2( { preset=preset, density=density } )
density=density or 0.5 density=density or 0.5
trigger.action.effectSmokeBig( self:GetVec3(), preset, density ) self.firename = name or "Fire-"..math.random(1,10000)
trigger.action.effectSmokeBig( self:GetVec3(), preset, density, self.firename )
end
--- Stop big smoke and fire at the coordinate.
-- @param #COORDINATE self
-- @param #string name (Optional) Name of the fire to stop it, if not using the same COORDINATE object.
function COORDINATE:StopBigSmokeAndFire( name )
self:F2( { name = name } )
name = name or self.firename
trigger.action.effectSmokeStop( name )
end end
--- Small smoke and fire at the coordinate. --- Small smoke and fire at the coordinate.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
function COORDINATE:BigSmokeAndFireSmall( density ) -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
function COORDINATE:BigSmokeAndFireSmall( density, name )
self:F2( { density=density } ) self:F2( { density=density } )
density=density or 0.5 density=density or 0.5
self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmokeAndFire, density) self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmokeAndFire, density, name)
end end
--- Medium smoke and fire at the coordinate. --- Medium smoke and fire at the coordinate.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
function COORDINATE:BigSmokeAndFireMedium( density ) -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
function COORDINATE:BigSmokeAndFireMedium( density, name )
self:F2( { density=density } ) self:F2( { density=density } )
density=density or 0.5 density=density or 0.5
self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmokeAndFire, density) self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmokeAndFire, density, name)
end end
--- Large smoke and fire at the coordinate. --- Large smoke and fire at the coordinate.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
function COORDINATE:BigSmokeAndFireLarge( density ) -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
function COORDINATE:BigSmokeAndFireLarge( density, name )
self:F2( { density=density } ) self:F2( { density=density } )
density=density or 0.5 density=density or 0.5
self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmokeAndFire, density) self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmokeAndFire, density, name)
end end
--- Huge smoke and fire at the coordinate. --- Huge smoke and fire at the coordinate.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
function COORDINATE:BigSmokeAndFireHuge( density ) -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
function COORDINATE:BigSmokeAndFireHuge( density, name )
self:F2( { density=density } ) self:F2( { density=density } )
density=density or 0.5 density=density or 0.5
self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmokeAndFire, density) self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmokeAndFire, density, name)
end end
--- Small smoke at the coordinate. --- Small smoke at the coordinate.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
function COORDINATE:BigSmokeSmall( density ) -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
function COORDINATE:BigSmokeSmall( density, name )
self:F2( { density=density } ) self:F2( { density=density } )
density=density or 0.5 density=density or 0.5
self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmoke, density) self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmoke, density, name)
end end
--- Medium smoke at the coordinate. --- Medium smoke at the coordinate.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. -- @param number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
function COORDINATE:BigSmokeMedium( density ) -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
function COORDINATE:BigSmokeMedium( density, name )
self:F2( { density=density } ) self:F2( { density=density } )
density=density or 0.5 density=density or 0.5
self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmoke, density) self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmoke, density, name)
end end
--- Large smoke at the coordinate. --- Large smoke at the coordinate.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
function COORDINATE:BigSmokeLarge( density ) -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
function COORDINATE:BigSmokeLarge( density, name )
self:F2( { density=density } ) self:F2( { density=density } )
density=density or 0.5 density=density or 0.5
self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmoke, density) self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmoke, density,name)
end end
--- Huge smoke at the coordinate. --- Huge smoke at the coordinate.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
function COORDINATE:BigSmokeHuge( density ) -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
function COORDINATE:BigSmokeHuge( density, name )
self:F2( { density=density } ) self:F2( { density=density } )
density=density or 0.5 density=density or 0.5
self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmoke, density) self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmoke, density,name)
end end
--- Flares the point in a color. --- Flares the point in a color.
@@ -1991,7 +2124,7 @@ do -- COORDINATE
--- Line to all. --- Line to all.
-- Creates a line on the F10 map from one point to another. -- Creates a line on the F10 map from one point to another.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @param #COORDINATE Endpoint COORDIANTE to where the line is drawn. -- @param #COORDINATE Endpoint COORDINATE to where the line is drawn.
-- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All.
-- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default).
-- @param #number Alpha Transparency [0,1]. Default 1. -- @param #number Alpha Transparency [0,1]. Default 1.
@@ -2016,7 +2149,7 @@ do -- COORDINATE
--- Circle to all. --- Circle to all.
-- Creates a circle on the map with a given radius, color, fill color, and outline. -- Creates a circle on the map with a given radius, color, fill color, and outline.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @param #numberr Radius Radius in meters. Default 1000 m. -- @param #number Radius Radius in meters. Default 1000 m.
-- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All.
-- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default).
-- @param #number Alpha Transparency [0,1]. Default 1. -- @param #number Alpha Transparency [0,1]. Default 1.
@@ -2048,7 +2181,7 @@ do -- COORDINATE
--- Rectangle to all. Creates a rectangle on the map from the COORDINATE in one corner to the end COORDINATE in the opposite corner. --- Rectangle to all. Creates a rectangle on the map from the COORDINATE in one corner to the end COORDINATE in the opposite corner.
-- Creates a line on the F10 map from one point to another. -- Creates a line on the F10 map from one point to another.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @param #COORDINATE Endpoint COORDIANTE in the opposite corner. -- @param #COORDINATE Endpoint COORDINATE in the opposite corner.
-- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All.
-- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default).
-- @param #number Alpha Transparency [0,1]. Default 1. -- @param #number Alpha Transparency [0,1]. Default 1.
@@ -2076,9 +2209,9 @@ do -- COORDINATE
--- Creates a shape defined by 4 points on the F10 map. The first point is the current COORDINATE. The remaining three points need to be specified. --- Creates a shape defined by 4 points on the F10 map. The first point is the current COORDINATE. The remaining three points need to be specified.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @param #COORDINATE Coord2 Second COORDIANTE of the quad shape. -- @param #COORDINATE Coord2 Second COORDINATE of the quad shape.
-- @param #COORDINATE Coord3 Third COORDIANTE of the quad shape. -- @param #COORDINATE Coord3 Third COORDINATE of the quad shape.
-- @param #COORDINATE Coord4 Fourth COORDIANTE of the quad shape. -- @param #COORDINATE Coord4 Fourth COORDINATE of the quad shape.
-- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All.
-- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default). -- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default).
-- @param #number Alpha Transparency [0,1]. Default 1. -- @param #number Alpha Transparency [0,1]. Default 1.
@@ -2152,7 +2285,7 @@ do -- COORDINATE
elseif #vecs==5 then elseif #vecs==5 then
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], Color, FillColor, LineType, ReadOnly, Text or "") trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], Color, FillColor, LineType, ReadOnly, Text or "")
elseif #vecs==6 then elseif #vecs==6 then
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], Color, FillColor, LineType, Text or "") trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], Color, FillColor, LineType, ReadOnly, Text or "")
elseif #vecs==7 then elseif #vecs==7 then
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], Color, FillColor, LineType, ReadOnly, Text or "") trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], Color, FillColor, LineType, ReadOnly, Text or "")
elseif #vecs==8 then elseif #vecs==8 then
@@ -2893,7 +3026,7 @@ do -- POINT_VEC3
-- @type POINT_VEC3 -- @type POINT_VEC3
-- @field #number x The x coordinate in 3D space. -- @field #number x The x coordinate in 3D space.
-- @field #number y The y coordinate in 3D space. -- @field #number y The y coordinate in 3D space.
-- @field #number z The z coordiante in 3D space. -- @field #number z The z COORDINATE in 3D space.
-- @field Utilities.Utils#SMOKECOLOR SmokeColor -- @field Utilities.Utils#SMOKECOLOR SmokeColor
-- @field Utilities.Utils#FLARECOLOR FlareColor -- @field Utilities.Utils#FLARECOLOR FlareColor
-- @field #POINT_VEC3.RoutePointAltType RoutePointAltType -- @field #POINT_VEC3.RoutePointAltType RoutePointAltType
@@ -3325,5 +3458,3 @@ do -- POINT_VEC2
end end
end end
+6 -9
View File
@@ -15,7 +15,6 @@
-- @module Core.Report -- @module Core.Report
-- @image Core_Report.JPG -- @image Core_Report.JPG
--- @type REPORT --- @type REPORT
-- @extends Core.Base#BASE -- @extends Core.Base#BASE
@@ -45,28 +44,26 @@ end
--- Has the REPORT Text? --- Has the REPORT Text?
-- @param #REPORT self -- @param #REPORT self
-- @return #boolean -- @return #boolean
function REPORT:HasText() --R2.1 function REPORT:HasText() -- R2.1
return #self.Report > 0 return #self.Report > 0
end end
--- Set indent of a REPORT. --- Set indent of a REPORT.
-- @param #REPORT self -- @param #REPORT self
-- @param #number Indent -- @param #number Indent
-- @return #REPORT -- @return #REPORT
function REPORT:SetIndent( Indent ) --R2.1 function REPORT:SetIndent( Indent ) -- R2.1
self.Indent = Indent self.Indent = Indent
return self return self
end end
--- Add a new line to a REPORT. --- Add a new line to a REPORT.
-- @param #REPORT self -- @param #REPORT self
-- @param #string Text -- @param #string Text
-- @return #REPORT -- @return #REPORT
function REPORT:Add( Text ) function REPORT:Add( Text )
self.Report[#self.Report+1] = Text self.Report[#self.Report + 1] = Text
return self return self
end end
@@ -76,17 +73,17 @@ end
-- @param #string Separator (optional) The start of each report line can begin with an optional separator character. This can be a "-", or "#", or "*". You're free to choose what you find the best. -- @param #string Separator (optional) The start of each report line can begin with an optional separator character. This can be a "-", or "#", or "*". You're free to choose what you find the best.
-- @return #REPORT -- @return #REPORT
function REPORT:AddIndent( Text, Separator ) function REPORT:AddIndent( Text, Separator )
self.Report[#self.Report+1] = ( ( Separator and Separator .. string.rep( " ", self.Indent - 1 ) ) or string.rep(" ", self.Indent ) ) .. Text:gsub("\n","\n"..string.rep( " ", self.Indent ) ) self.Report[#self.Report + 1] = ((Separator and Separator .. string.rep( " ", self.Indent - 1 )) or string.rep( " ", self.Indent )) .. Text:gsub( "\n", "\n" .. string.rep( " ", self.Indent ) )
return self return self
end end
--- Produces the text of the report, taking into account an optional delimeter, which is \n by default. --- Produces the text of the report, taking into account an optional delimiter, which is \n by default.
-- @param #REPORT self -- @param #REPORT self
-- @param #string Delimiter (optional) A delimiter text. -- @param #string Delimiter (optional) A delimiter text.
-- @return #string The report text. -- @return #string The report text.
function REPORT:Text( Delimiter ) function REPORT:Text( Delimiter )
Delimiter = Delimiter or "\n" Delimiter = Delimiter or "\n"
local ReportText = ( self.Title ~= "" and self.Title .. Delimiter or self.Title ) .. table.concat( self.Report, Delimiter ) or "" local ReportText = (self.Title ~= "" and self.Title .. Delimiter or self.Title) .. table.concat( self.Report, Delimiter ) or ""
return ReportText return ReportText
end end
@@ -17,7 +17,7 @@
-- - When a SCHEDULER object is not attached to another object (that is, it's first :Schedule() parameter is nil), then the SCHEDULER object is _persistent_ within memory. -- - When a SCHEDULER object is not attached to another object (that is, it's first :Schedule() parameter is nil), then the SCHEDULER object is _persistent_ within memory.
-- - When a SCHEDULER object *is* attached to another object, then the SCHEDULER object is _not persistent_ within memory after a garbage collection! -- - When a SCHEDULER object *is* attached to another object, then the SCHEDULER object is _not persistent_ within memory after a garbage collection!
-- --
-- The none persistency of SCHEDULERS attached to objects is required to allow SCHEDULER objects to be garbage collectged, when the parent object is also desroyed or nillified and garbage collected. -- The non-persistency of SCHEDULERS attached to objects is required to allow SCHEDULER objects to be garbage collected when the parent object is destroyed, or set to nil and garbage collected.
-- Even when there are pending timer scheduled functions to be executed for the SCHEDULER object, -- Even when there are pending timer scheduled functions to be executed for the SCHEDULER object,
-- these will not be executed anymore when the SCHEDULER object has been destroyed. -- these will not be executed anymore when the SCHEDULER object has been destroyed.
-- --
@@ -38,7 +38,7 @@
-- @type SCHEDULEDISPATCHER -- @type SCHEDULEDISPATCHER
-- @field #string ClassName Name of the class. -- @field #string ClassName Name of the class.
-- @field #number CallID Call ID counter. -- @field #number CallID Call ID counter.
-- @field #table PersistentSchedulers Persistant schedulers. -- @field #table PersistentSchedulers Persistent schedulers.
-- @field #table ObjectSchedulers Schedulers that only exist as long as the master object exists. -- @field #table ObjectSchedulers Schedulers that only exist as long as the master object exists.
-- @field #table Schedule Meta table setmetatable( {}, { __mode = "k" } ). -- @field #table Schedule Meta table setmetatable( {}, { __mode = "k" } ).
-- @extends Core.Base#BASE -- @extends Core.Base#BASE
@@ -46,11 +46,11 @@
--- The SCHEDULEDISPATCHER structure --- The SCHEDULEDISPATCHER structure
-- @type SCHEDULEDISPATCHER -- @type SCHEDULEDISPATCHER
SCHEDULEDISPATCHER = { SCHEDULEDISPATCHER = {
ClassName = "SCHEDULEDISPATCHER", ClassName = "SCHEDULEDISPATCHER",
CallID = 0, CallID = 0,
PersistentSchedulers = {}, PersistentSchedulers = {},
ObjectSchedulers = {}, ObjectSchedulers = {},
Schedule = nil, Schedule = nil,
} }
--- Player data table holding all important parameters of each player. --- Player data table holding all important parameters of each player.
@@ -58,7 +58,7 @@ SCHEDULEDISPATCHER = {
-- @field #function Function The schedule function to be called. -- @field #function Function The schedule function to be called.
-- @field #table Arguments Schedule function arguments. -- @field #table Arguments Schedule function arguments.
-- @field #number Start Start time in seconds. -- @field #number Start Start time in seconds.
-- @field #number Repeat Repeat time intervall in seconds. -- @field #number Repeat Repeat time interval in seconds.
-- @field #number Randomize Randomization factor [0,1]. -- @field #number Randomize Randomization factor [0,1].
-- @field #number Stop Stop time in seconds. -- @field #number Stop Stop time in seconds.
-- @field #number StartTime Time in seconds when the scheduler is created. -- @field #number StartTime Time in seconds when the scheduler is created.
@@ -77,7 +77,7 @@ end
--- Add a Schedule to the ScheduleDispatcher. --- Add a Schedule to the ScheduleDispatcher.
-- The development of this method was really tidy. -- The development of this method was really tidy.
-- It is constructed as such that a garbage collection is executed on the weak tables, when the Scheduler is nillified. -- It is constructed as such that a garbage collection is executed on the weak tables, when the Scheduler is set to nil.
-- Nothing of this code should be modified without testing it thoroughly. -- Nothing of this code should be modified without testing it thoroughly.
-- @param #SCHEDULEDISPATCHER self -- @param #SCHEDULEDISPATCHER self
-- @param Core.Scheduler#SCHEDULER Scheduler Scheduler object. -- @param Core.Scheduler#SCHEDULER Scheduler Scheduler object.
@@ -85,7 +85,7 @@ end
-- @param #table ScheduleArguments Table of arguments passed to the ScheduleFunction. -- @param #table ScheduleArguments Table of arguments passed to the ScheduleFunction.
-- @param #number Start Start time in seconds. -- @param #number Start Start time in seconds.
-- @param #number Repeat Repeat interval in seconds. -- @param #number Repeat Repeat interval in seconds.
-- @param #number Randomize Radomization factor [0,1]. -- @param #number Randomize Randomization factor [0,1].
-- @param #number Stop Stop time in seconds. -- @param #number Stop Stop time in seconds.
-- @param #number TraceLevel Trace level [0,3]. -- @param #number TraceLevel Trace level [0,3].
-- @param Core.Fsm#FSM Fsm Finite state model. -- @param Core.Fsm#FSM Fsm Finite state model.
@@ -97,9 +97,9 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
self.CallID = self.CallID + 1 self.CallID = self.CallID + 1
-- Create ID. -- Create ID.
local CallID = self.CallID .. "#" .. ( Scheduler.MasterObject and Scheduler.MasterObject.GetClassNameAndID and Scheduler.MasterObject:GetClassNameAndID() or "" ) or "" local CallID = self.CallID .. "#" .. (Scheduler.MasterObject and Scheduler.MasterObject.GetClassNameAndID and Scheduler.MasterObject:GetClassNameAndID() or "") or ""
self:T2(string.format("Adding schedule #%d CallID=%s", self.CallID, CallID)) self:T2( string.format( "Adding schedule #%d CallID=%s", self.CallID, CallID ) )
-- Initialize PersistentSchedulers -- Initialize PersistentSchedulers
self.PersistentSchedulers = self.PersistentSchedulers or {} self.PersistentSchedulers = self.PersistentSchedulers or {}
@@ -110,7 +110,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
if Scheduler.MasterObject then if Scheduler.MasterObject then
self.ObjectSchedulers[CallID] = Scheduler self.ObjectSchedulers[CallID] = Scheduler
self:F3( { CallID = CallID, ObjectScheduler = tostring(self.ObjectSchedulers[CallID]), MasterObject = tostring(Scheduler.MasterObject) } ) self:F3( { CallID = CallID, ObjectScheduler = tostring( self.ObjectSchedulers[CallID] ), MasterObject = tostring( Scheduler.MasterObject ) } )
else else
self.PersistentSchedulers[CallID] = Scheduler self.PersistentSchedulers[CallID] = Scheduler
self:F3( { CallID = CallID, PersistentScheduler = self.PersistentSchedulers[CallID] } ) self:F3( { CallID = CallID, PersistentScheduler = self.PersistentSchedulers[CallID] } )
@@ -118,16 +118,15 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } ) self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } )
self.Schedule[Scheduler] = self.Schedule[Scheduler] or {} self.Schedule[Scheduler] = self.Schedule[Scheduler] or {}
self.Schedule[Scheduler][CallID] = {} --#SCHEDULEDISPATCHER.ScheduleData self.Schedule[Scheduler][CallID] = {} -- #SCHEDULEDISPATCHER.ScheduleData
self.Schedule[Scheduler][CallID].Function = ScheduleFunction self.Schedule[Scheduler][CallID].Function = ScheduleFunction
self.Schedule[Scheduler][CallID].Arguments = ScheduleArguments self.Schedule[Scheduler][CallID].Arguments = ScheduleArguments
self.Schedule[Scheduler][CallID].StartTime = timer.getTime() + ( Start or 0 ) self.Schedule[Scheduler][CallID].StartTime = timer.getTime() + (Start or 0)
self.Schedule[Scheduler][CallID].Start = Start + 0.1 self.Schedule[Scheduler][CallID].Start = Start + 0.1
self.Schedule[Scheduler][CallID].Repeat = Repeat or 0 self.Schedule[Scheduler][CallID].Repeat = Repeat or 0
self.Schedule[Scheduler][CallID].Randomize = Randomize or 0 self.Schedule[Scheduler][CallID].Randomize = Randomize or 0
self.Schedule[Scheduler][CallID].Stop = Stop self.Schedule[Scheduler][CallID].Stop = Stop
-- This section handles the tracing of the scheduled calls. -- This section handles the tracing of the scheduled calls.
-- Because these calls will be executed with a delay, we inspect the place where these scheduled calls are initiated. -- Because these calls will be executed with a delay, we inspect the place where these scheduled calls are initiated.
-- The Info structure contains the output of the debug.getinfo() calls, which inspects the call stack for the function name, line number and source name. -- The Info structure contains the output of the debug.getinfo() calls, which inspects the call stack for the function name, line number and source name.
@@ -149,7 +148,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
-- Therefore, in the call stack, at the TraceLevel these functions are mentioned as "tail calls", and the Info.name field will be nil as a result. -- Therefore, in the call stack, at the TraceLevel these functions are mentioned as "tail calls", and the Info.name field will be nil as a result.
-- To obtain the correct function name for FSM object calls, the function is mentioned in the call stack at a higher stack level. -- To obtain the correct function name for FSM object calls, the function is mentioned in the call stack at a higher stack level.
-- So when function name stored in Info.name is nil, then I inspect the function name within the call stack one level higher. -- So when function name stored in Info.name is nil, then I inspect the function name within the call stack one level higher.
-- So this little piece of code does its magic wonderfully, preformance overhead is neglectible, as scheduled calls don't happen that often. -- So this little piece of code does its magic wonderfully, performance overhead is negligible, as scheduled calls don't happen that often.
local Info = {} local Info = {}
@@ -181,24 +180,24 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
return errmsg return errmsg
end end
-- Get object or persistant scheduler object. -- Get object or persistent scheduler object.
local Scheduler = self.ObjectSchedulers[CallID] --Core.Scheduler#SCHEDULER local Scheduler = self.ObjectSchedulers[CallID] -- Core.Scheduler#SCHEDULER
if not Scheduler then if not Scheduler then
Scheduler = self.PersistentSchedulers[CallID] Scheduler = self.PersistentSchedulers[CallID]
end end
--self:T3( { Scheduler = Scheduler } ) -- self:T3( { Scheduler = Scheduler } )
if Scheduler then if Scheduler then
local MasterObject = tostring(Scheduler.MasterObject) local MasterObject = tostring( Scheduler.MasterObject )
-- Schedule object. -- Schedule object.
local Schedule = self.Schedule[Scheduler][CallID] --#SCHEDULEDISPATCHER.ScheduleData local Schedule = self.Schedule[Scheduler][CallID] -- #SCHEDULEDISPATCHER.ScheduleData
--self:T3( { Schedule = Schedule } ) -- self:T3( { Schedule = Schedule } )
local SchedulerObject = Scheduler.MasterObject --Scheduler.SchedulerObject Now is this the Maste or Scheduler object? local SchedulerObject = Scheduler.MasterObject -- Scheduler.SchedulerObject Now is this the Master or Scheduler object?
local ShowTrace = Scheduler.ShowTrace local ShowTrace = Scheduler.ShowTrace
local ScheduleFunction = Schedule.Function local ScheduleFunction = Schedule.Function
@@ -209,11 +208,10 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
local Stop = Schedule.Stop or 0 local Stop = Schedule.Stop or 0
local ScheduleID = Schedule.ScheduleID local ScheduleID = Schedule.ScheduleID
local Prefix = (Repeat == 0) and "--->" or "+++>"
local Prefix = ( Repeat == 0 ) and "--->" or "+++>"
local Status, Result local Status, Result
--self:E( { SchedulerObject = SchedulerObject } ) -- self:E( { SchedulerObject = SchedulerObject } )
if SchedulerObject then if SchedulerObject then
local function Timer() local function Timer()
if ShowTrace then if ShowTrace then
@@ -236,14 +234,13 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
local StartTime = Schedule.StartTime local StartTime = Schedule.StartTime
-- Debug info. -- Debug info.
self:F3( { CallID=CallID, ScheduleID=ScheduleID, Master = MasterObject, CurrentTime = CurrentTime, StartTime = StartTime, Start = Start, Repeat = Repeat, Randomize = Randomize, Stop = Stop } ) self:F3( { CallID = CallID, ScheduleID = ScheduleID, Master = MasterObject, CurrentTime = CurrentTime, StartTime = StartTime, Start = Start, Repeat = Repeat, Randomize = Randomize, Stop = Stop } )
if Status and ((Result == nil) or (Result and Result ~= false)) then
if Status and (( Result == nil ) or ( Result and Result ~= false ) ) then if Repeat ~= 0 and ((Stop == 0) or (Stop ~= 0 and CurrentTime <= StartTime + Stop)) then
local ScheduleTime = CurrentTime + Repeat + math.random( -(Randomize * Repeat / 2), (Randomize * Repeat / 2) ) + 0.0001 -- Accuracy
if Repeat ~= 0 and ( ( Stop == 0 ) or ( Stop ~= 0 and CurrentTime <= StartTime + Stop ) ) then -- self:T3( { Repeat = CallID, CurrentTime, ScheduleTime, ScheduleArguments } )
local ScheduleTime = CurrentTime + Repeat + math.random(- ( Randomize * Repeat / 2 ), ( Randomize * Repeat / 2 )) + 0.0001 -- Accuracy
--self:T3( { Repeat = CallID, CurrentTime, ScheduleTime, ScheduleArguments } )
return ScheduleTime -- returns the next time the function needs to be called. return ScheduleTime -- returns the next time the function needs to be called.
else else
self:Stop( Scheduler, CallID ) self:Stop( Scheduler, CallID )
@@ -287,21 +284,21 @@ function SCHEDULEDISPATCHER:Start( Scheduler, CallID, Info )
if CallID then if CallID then
local Schedule = self.Schedule[Scheduler][CallID] --#SCHEDULEDISPATCHER.ScheduleData local Schedule = self.Schedule[Scheduler][CallID] -- #SCHEDULEDISPATCHER.ScheduleData
-- Only start when there is no ScheduleID defined! -- Only start when there is no ScheduleID defined!
-- This prevents to "Start" the scheduler twice with the same CallID... -- This prevents to "Start" the scheduler twice with the same CallID...
if not Schedule.ScheduleID then if not Schedule.ScheduleID then
-- Current time in seconds. -- Current time in seconds.
local Tnow=timer.getTime() local Tnow = timer.getTime()
Schedule.StartTime = Tnow -- Set the StartTime field to indicate when the scheduler started. Schedule.StartTime = Tnow -- Set the StartTime field to indicate when the scheduler started.
-- Start DCS schedule function https://wiki.hoggitworld.com/view/DCS_func_scheduleFunction -- Start DCS schedule function https://wiki.hoggitworld.com/view/DCS_func_scheduleFunction
Schedule.ScheduleID = timer.scheduleFunction(Schedule.CallHandler, { CallID = CallID, Info = Info }, Tnow + Schedule.Start) Schedule.ScheduleID = timer.scheduleFunction( Schedule.CallHandler, { CallID = CallID, Info = Info }, Tnow + Schedule.Start )
self:T(string.format("Starting scheduledispatcher Call ID=%s ==> Schedule ID=%s", tostring(CallID), tostring(Schedule.ScheduleID))) self:T( string.format( "Starting SCHEDULEDISPATCHER Call ID=%s ==> Schedule ID=%s", tostring( CallID ), tostring( Schedule.ScheduleID ) ) )
end end
else else
@@ -323,20 +320,20 @@ function SCHEDULEDISPATCHER:Stop( Scheduler, CallID )
if CallID then if CallID then
local Schedule = self.Schedule[Scheduler][CallID] --#SCHEDULEDISPATCHER.ScheduleData local Schedule = self.Schedule[Scheduler][CallID] -- #SCHEDULEDISPATCHER.ScheduleData
-- Only stop when there is a ScheduleID defined for the CallID. So, when the scheduler was stopped before, do nothing. -- Only stop when there is a ScheduleID defined for the CallID. So, when the scheduler was stopped before, do nothing.
if Schedule.ScheduleID then if Schedule.ScheduleID then
self:T(string.format("scheduledispatcher stopping scheduler CallID=%s, ScheduleID=%s", tostring(CallID), tostring(Schedule.ScheduleID))) self:T( string.format( "SCHEDULEDISPATCHER stopping scheduler CallID=%s, ScheduleID=%s", tostring( CallID ), tostring( Schedule.ScheduleID ) ) )
-- Remove schedule function https://wiki.hoggitworld.com/view/DCS_func_removeFunction -- Remove schedule function https://wiki.hoggitworld.com/view/DCS_func_removeFunction
timer.removeFunction(Schedule.ScheduleID) timer.removeFunction( Schedule.ScheduleID )
Schedule.ScheduleID = nil Schedule.ScheduleID = nil
else else
self:T(string.format("Error no ScheduleID for CallID=%s", tostring(CallID))) self:T( string.format( "Error no ScheduleID for CallID=%s", tostring( CallID ) ) )
end end
else else
@@ -359,7 +356,7 @@ function SCHEDULEDISPATCHER:Clear( Scheduler )
end end
end end
--- Shopw tracing info. --- Show tracing info.
-- @param #SCHEDULEDISPATCHER self -- @param #SCHEDULEDISPATCHER self
-- @param Core.Scheduler#SCHEDULER Scheduler Scheduler object. -- @param Core.Scheduler#SCHEDULER Scheduler Scheduler object.
function SCHEDULEDISPATCHER:ShowTrace( Scheduler ) function SCHEDULEDISPATCHER:ShowTrace( Scheduler )
+25 -27
View File
@@ -48,7 +48,6 @@
-- @field #boolean ShowTrace Trace info if true. -- @field #boolean ShowTrace Trace info if true.
-- @extends Core.Base#BASE -- @extends Core.Base#BASE
--- Creates and handles schedules over time, which allow to execute code at specific time intervals with randomization. --- Creates and handles schedules over time, which allow to execute code at specific time intervals with randomization.
-- --
-- A SCHEDULER can manage **multiple** (repeating) schedules. Each planned or executing schedule has a unique **ScheduleID**. -- A SCHEDULER can manage **multiple** (repeating) schedules. Each planned or executing schedule has a unique **ScheduleID**.
@@ -79,7 +78,7 @@
-- --
-- ### Construct a SCHEDULER object without a volatile schedule, but volatile to the Object existence... -- ### Construct a SCHEDULER object without a volatile schedule, but volatile to the Object existence...
-- --
-- * @{#SCHEDULER.New}( Object ): Setup a new SCHEDULER object, which is linked to the Object. When the Object is nillified or destroyed, the SCHEDULER object will also be destroyed and stopped after garbage collection. -- * @{#SCHEDULER.New}( Object ): Setup a new SCHEDULER object, which is linked to the Object. When the Object is set to nil or destroyed, the SCHEDULER object will also be destroyed and stopped after garbage collection.
-- --
-- ZoneObject = ZONE:New( "ZoneName" ) -- ZoneObject = ZONE:New( "ZoneName" )
-- MasterObject = SCHEDULER:New( ZoneObject ) -- MasterObject = SCHEDULER:New( ZoneObject )
@@ -149,13 +148,13 @@
-- ZoneObject = ZONE:New( "ZoneName" ) -- ZoneObject = ZONE:New( "ZoneName" )
-- MasterObject = SCHEDULER:New( ZoneObject ) -- MasterObject = SCHEDULER:New( ZoneObject )
-- --
-- Several parameters can be specified that influence the behaviour of a Schedule. -- Several parameters can be specified that influence the behavior of a Schedule.
-- --
-- ### A single schedule, immediately executed -- ### A single schedule, immediately executed
-- --
-- SchedulerID = MasterObject:Schedule( ZoneObject, ScheduleFunction, {} ) -- SchedulerID = MasterObject:Schedule( ZoneObject, ScheduleFunction, {} )
-- --
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within milleseconds ... -- The above example schedules a new ScheduleFunction call to be executed asynchronously, within milliseconds ...
-- --
-- ### A single schedule, planned over time -- ### A single schedule, planned over time
-- --
@@ -193,10 +192,10 @@
-- --
-- @field #SCHEDULER -- @field #SCHEDULER
SCHEDULER = { SCHEDULER = {
ClassName = "SCHEDULER", ClassName = "SCHEDULER",
Schedules = {}, Schedules = {},
MasterObject = nil, MasterObject = nil,
ShowTrace = nil, ShowTrace = nil,
} }
--- SCHEDULER constructor. --- SCHEDULER constructor.
@@ -235,7 +234,7 @@ end
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called. -- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
-- @param #number Repeat Specifies the time interval in seconds when the scheduler will call the event function. -- @param #number Repeat Specifies the time interval in seconds when the scheduler will call the event function.
-- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat. -- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat.
-- @param #number Stop Time interval in seconds after which the scheduler will be stoppe. -- @param #number Stop Time interval in seconds after which the scheduler will be stopped.
-- @param #number TraceLevel Trace level [0,3]. Default 3. -- @param #number TraceLevel Trace level [0,3]. Default 3.
-- @param Core.Fsm#FSM Fsm Finite state model. -- @param Core.Fsm#FSM Fsm Finite state model.
-- @return #table The ScheduleID of the planned schedule. -- @return #table The ScheduleID of the planned schedule.
@@ -248,25 +247,24 @@ function SCHEDULER:Schedule( MasterObject, SchedulerFunction, SchedulerArguments
if MasterObject and MasterObject.ClassName and MasterObject.ClassID then if MasterObject and MasterObject.ClassName and MasterObject.ClassID then
ObjectName = MasterObject.ClassName .. MasterObject.ClassID ObjectName = MasterObject.ClassName .. MasterObject.ClassID
end end
self:F3( { "Schedule :", ObjectName, tostring( MasterObject ), Start, Repeat, RandomizeFactor, Stop } ) self:F3( { "Schedule :", ObjectName, tostring( MasterObject ), Start, Repeat, RandomizeFactor, Stop } )
-- Set master object. -- Set master object.
self.MasterObject = MasterObject self.MasterObject = MasterObject
-- Add schedule. -- Add schedule.
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule( local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule( self,
self, SchedulerFunction,
SchedulerFunction, SchedulerArguments,
SchedulerArguments, Start,
Start, Repeat,
Repeat, RandomizeFactor,
RandomizeFactor, Stop,
Stop, TraceLevel or 3,
TraceLevel or 3, Fsm
Fsm )
)
self.Schedules[#self.Schedules+1] = ScheduleID self.Schedules[#self.Schedules + 1] = ScheduleID
return ScheduleID return ScheduleID
end end
@@ -276,7 +274,7 @@ end
-- @param #string ScheduleID (Optional) The ScheduleID of the planned (repeating) schedule. -- @param #string ScheduleID (Optional) The ScheduleID of the planned (repeating) schedule.
function SCHEDULER:Start( ScheduleID ) function SCHEDULER:Start( ScheduleID )
self:F3( { ScheduleID } ) self:F3( { ScheduleID } )
self:T(string.format("Starting scheduler ID=%s", tostring(ScheduleID))) self:T( string.format( "Starting scheduler ID=%s", tostring( ScheduleID ) ) )
_SCHEDULEDISPATCHER:Start( self, ScheduleID ) _SCHEDULEDISPATCHER:Start( self, ScheduleID )
end end
@@ -285,7 +283,7 @@ end
-- @param #string ScheduleID (Optional) The ScheduleID of the planned (repeating) schedule. -- @param #string ScheduleID (Optional) The ScheduleID of the planned (repeating) schedule.
function SCHEDULER:Stop( ScheduleID ) function SCHEDULER:Stop( ScheduleID )
self:F3( { ScheduleID } ) self:F3( { ScheduleID } )
self:T(string.format("Stopping scheduler ID=%s", tostring(ScheduleID))) self:T( string.format( "Stopping scheduler ID=%s", tostring( ScheduleID ) ) )
_SCHEDULEDISPATCHER:Stop( self, ScheduleID ) _SCHEDULEDISPATCHER:Stop( self, ScheduleID )
end end
@@ -294,15 +292,15 @@ end
-- @param #string ScheduleID (optional) The ScheduleID of the planned (repeating) schedule. -- @param #string ScheduleID (optional) The ScheduleID of the planned (repeating) schedule.
function SCHEDULER:Remove( ScheduleID ) function SCHEDULER:Remove( ScheduleID )
self:F3( { ScheduleID } ) self:F3( { ScheduleID } )
self:T(string.format("Removing scheduler ID=%s", tostring(ScheduleID))) self:T( string.format( "Removing scheduler ID=%s", tostring( ScheduleID ) ) )
_SCHEDULEDISPATCHER:RemoveSchedule( self, ScheduleID ) _SCHEDULEDISPATCHER:RemoveSchedule( self, ScheduleID )
end end
--- Clears all pending schedules. --- Clears all pending schedules.
-- @param #SCHEDULER self -- @param #SCHEDULER self
function SCHEDULER:Clear() function SCHEDULER:Clear()
self:F3( ) self:F3()
self:T(string.format("Clearing scheduler")) self:T( string.format( "Clearing scheduler" ) )
_SCHEDULEDISPATCHER:Clear( self ) _SCHEDULEDISPATCHER:Clear( self )
end end
File diff suppressed because it is too large Load Diff
+112 -123
View File
@@ -29,15 +29,14 @@
-- @module Core.Settings -- @module Core.Settings
-- @image Core_Settings.JPG -- @image Core_Settings.JPG
--- @type SETTINGS --- @type SETTINGS
-- @extends Core.Base#BASE -- @extends Core.Base#BASE
--- Takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework. --- Takes care of various settings that influence the behavior of certain functionalities and classes within the MOOSE framework.
-- --
-- === -- ===
-- --
-- The SETTINGS class takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework. -- The SETTINGS class takes care of various settings that influence the behavior of certain functionalities and classes within the MOOSE framework.
-- SETTINGS can work on 2 levels: -- SETTINGS can work on 2 levels:
-- --
-- - **Default settings**: A running mission has **Default settings**. -- - **Default settings**: A running mission has **Default settings**.
@@ -59,7 +58,7 @@
-- --
-- A menu is created automatically per Command Center that allows to modify the **Default** settings. -- A menu is created automatically per Command Center that allows to modify the **Default** settings.
-- So, when joining a CC unit, a menu will be available that allows to change the settings parameters **FOR ALL THE PLAYERS**! -- So, when joining a CC unit, a menu will be available that allows to change the settings parameters **FOR ALL THE PLAYERS**!
-- Note that the **Default settings** will only be used when a player has not choosen its own settings. -- Note that the **Default settings** will only be used when a player has not chosen its own settings.
-- --
-- ## 2.2) Player settings menu -- ## 2.2) Player settings menu
-- --
@@ -69,7 +68,7 @@
-- --
-- ## 2.3) Show or Hide the Player Setting menus -- ## 2.3) Show or Hide the Player Setting menus
-- --
-- Of course, it may be requried not to show any setting menus. In this case, a method is available on the **\_SETTINGS object**. -- Of course, it may be required not to show any setting menus. In this case, a method is available on the **\_SETTINGS object**.
-- Use @{#SETTINGS.SetPlayerMenuOff}() to hide the player menus, and use @{#SETTINGS.SetPlayerMenuOn}() show the player menus. -- Use @{#SETTINGS.SetPlayerMenuOff}() to hide the player menus, and use @{#SETTINGS.SetPlayerMenuOn}() show the player menus.
-- Note that when this method is used, any player already in a slot will not have its menus visibility changed. -- Note that when this method is used, any player already in a slot will not have its menus visibility changed.
-- The option will only have effect when a player enters a new slot or changes a slot. -- The option will only have effect when a player enters a new slot or changes a slot.
@@ -94,8 +93,8 @@
-- --
-- - A2G BR: [Bearing Range](https://en.wikipedia.org/wiki/Bearing_(navigation)). -- - A2G BR: [Bearing Range](https://en.wikipedia.org/wiki/Bearing_(navigation)).
-- - A2G MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted. -- - A2G MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted.
-- - A2G LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted. -- - A2G LL DMS: Latitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
-- - A2G LL DDM: Lattitude Longitude [Decimal Degrees Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted. -- - A2G LL DDM: Latitude Longitude [Decimal Degrees Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
-- --
-- ### 3.1.2) A2G coordinates setting **menu** -- ### 3.1.2) A2G coordinates setting **menu**
-- --
@@ -183,7 +182,7 @@
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot. -- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
-- --
-- Each Message Type has specific timings that will be applied when the message is displayed. -- Each Message Type has specific timings that will be applied when the message is displayed.
-- The Settings Menu will provide for each Message Type a selection of proposed durations from which can be choosen. -- The Settings Menu will provide for each Message Type a selection of proposed durations from which can be chosen.
-- So the player can choose its own amount of seconds how long a message should be displayed of a certain type. -- So the player can choose its own amount of seconds how long a message should be displayed of a certain type.
-- Note that **Update** messages can be chosen not to be displayed at all! -- Note that **Update** messages can be chosen not to be displayed at all!
-- --
@@ -196,7 +195,7 @@
-- --
-- ## 3.5) **Era** of the battle -- ## 3.5) **Era** of the battle
-- --
-- The threat level metric is scaled according the era of the battle. A target that is AAA, will pose a much greather threat in WWII than on modern warfare. -- The threat level metric is scaled according the era of the battle. A target that is AAA, will pose a much greater threat in WWII than on modern warfare.
-- Therefore, there are 4 era that are defined within the settings: -- Therefore, there are 4 era that are defined within the settings:
-- --
-- - **WWII** era: Use for warfare with equipment during the world war II time. -- - **WWII** era: Use for warfare with equipment during the world war II time.
@@ -213,8 +212,8 @@
SETTINGS = { SETTINGS = {
ClassName = "SETTINGS", ClassName = "SETTINGS",
ShowPlayerMenu = true, ShowPlayerMenu = true,
MenuShort = false, MenuShort = false,
MenuStatic = false, MenuStatic = false,
} }
SETTINGS.__Enum = {} SETTINGS.__Enum = {}
@@ -231,7 +230,6 @@ SETTINGS.__Enum.Era = {
Modern = 4, Modern = 4,
} }
do -- SETTINGS do -- SETTINGS
--- SETTINGS constructor. --- SETTINGS constructor.
@@ -268,14 +266,14 @@ do -- SETTINGS
-- Short text are better suited for, e.g., VR. -- Short text are better suited for, e.g., VR.
-- @param #SETTINGS self -- @param #SETTINGS self
-- @param #boolean onoff If *true* use short menu texts. If *false* long ones (default). -- @param #boolean onoff If *true* use short menu texts. If *false* long ones (default).
function SETTINGS:SetMenutextShort(onoff) function SETTINGS:SetMenutextShort( onoff )
_SETTINGS.MenuShort = onoff _SETTINGS.MenuShort = onoff
end end
--- Set menu to be static. --- Set menu to be static.
-- @param #SETTINGS self -- @param #SETTINGS self
-- @param #boolean onoff If *true* menu is static. If *false* menu will be updated after changes (default). -- @param #boolean onoff If *true* menu is static. If *false* menu will be updated after changes (default).
function SETTINGS:SetMenuStatic(onoff) function SETTINGS:SetMenuStatic( onoff )
_SETTINGS.MenuStatic = onoff _SETTINGS.MenuStatic = onoff
end end
@@ -289,7 +287,7 @@ do -- SETTINGS
-- @param #SETTINGS self -- @param #SETTINGS self
-- @return #boolean true if metric. -- @return #boolean true if metric.
function SETTINGS:IsMetric() function SETTINGS:IsMetric()
return ( self.Metric ~= nil and self.Metric == true ) or ( self.Metric == nil and _SETTINGS:IsMetric() ) return (self.Metric ~= nil and self.Metric == true) or (self.Metric == nil and _SETTINGS:IsMetric())
end end
--- Sets the SETTINGS imperial. --- Sets the SETTINGS imperial.
@@ -302,7 +300,7 @@ do -- SETTINGS
-- @param #SETTINGS self -- @param #SETTINGS self
-- @return #boolean true if imperial. -- @return #boolean true if imperial.
function SETTINGS:IsImperial() function SETTINGS:IsImperial()
return ( self.Metric ~= nil and self.Metric == false ) or ( self.Metric == nil and _SETTINGS:IsMetric() ) return (self.Metric ~= nil and self.Metric == false) or (self.Metric == nil and _SETTINGS:IsMetric())
end end
--- Sets the SETTINGS LL accuracy. --- Sets the SETTINGS LL accuracy.
@@ -344,13 +342,12 @@ do -- SETTINGS
self.MessageTypeTimings[MessageType] = MessageTime self.MessageTypeTimings[MessageType] = MessageTime
end end
--- Gets the SETTINGS Message Display Timing of a MessageType --- Gets the SETTINGS Message Display Timing of a MessageType
-- @param #SETTINGS self -- @param #SETTINGS self
-- @param Core.Message#MESSAGE MessageType The type of the message. -- @param Core.Message#MESSAGE MessageType The type of the message.
-- @return #number -- @return #number
function SETTINGS:GetMessageTime( MessageType ) function SETTINGS:GetMessageTime( MessageType )
return ( self.MessageTypeTimings and self.MessageTypeTimings[MessageType] ) or _SETTINGS:GetMessageTime( MessageType ) return (self.MessageTypeTimings and self.MessageTypeTimings[MessageType]) or _SETTINGS:GetMessageTime( MessageType )
end end
--- Sets A2G LL DMS --- Sets A2G LL DMS
@@ -371,14 +368,14 @@ do -- SETTINGS
-- @param #SETTINGS self -- @param #SETTINGS self
-- @return #boolean true if LL DMS -- @return #boolean true if LL DMS
function SETTINGS:IsA2G_LL_DMS() function SETTINGS:IsA2G_LL_DMS()
return ( self.A2GSystem and self.A2GSystem == "LL DMS" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_LL_DMS() ) return (self.A2GSystem and self.A2GSystem == "LL DMS") or (not self.A2GSystem and _SETTINGS:IsA2G_LL_DMS())
end end
--- Is LL DDM --- Is LL DDM
-- @param #SETTINGS self -- @param #SETTINGS self
-- @return #boolean true if LL DDM -- @return #boolean true if LL DDM
function SETTINGS:IsA2G_LL_DDM() function SETTINGS:IsA2G_LL_DDM()
return ( self.A2GSystem and self.A2GSystem == "LL DDM" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_LL_DDM() ) return (self.A2GSystem and self.A2GSystem == "LL DDM") or (not self.A2GSystem and _SETTINGS:IsA2G_LL_DDM())
end end
--- Sets A2G MGRS --- Sets A2G MGRS
@@ -392,7 +389,7 @@ do -- SETTINGS
-- @param #SETTINGS self -- @param #SETTINGS self
-- @return #boolean true if MGRS -- @return #boolean true if MGRS
function SETTINGS:IsA2G_MGRS() function SETTINGS:IsA2G_MGRS()
return ( self.A2GSystem and self.A2GSystem == "MGRS" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_MGRS() ) return (self.A2GSystem and self.A2GSystem == "MGRS") or (not self.A2GSystem and _SETTINGS:IsA2G_MGRS())
end end
--- Sets A2G BRA --- Sets A2G BRA
@@ -406,7 +403,7 @@ do -- SETTINGS
-- @param #SETTINGS self -- @param #SETTINGS self
-- @return #boolean true if BRA -- @return #boolean true if BRA
function SETTINGS:IsA2G_BR() function SETTINGS:IsA2G_BR()
return ( self.A2GSystem and self.A2GSystem == "BR" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_BR() ) return (self.A2GSystem and self.A2GSystem == "BR") or (not self.A2GSystem and _SETTINGS:IsA2G_BR())
end end
--- Sets A2A BRA --- Sets A2A BRA
@@ -420,7 +417,7 @@ do -- SETTINGS
-- @param #SETTINGS self -- @param #SETTINGS self
-- @return #boolean true if BRA -- @return #boolean true if BRA
function SETTINGS:IsA2A_BRAA() function SETTINGS:IsA2A_BRAA()
return ( self.A2ASystem and self.A2ASystem == "BRAA" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BRAA() ) return (self.A2ASystem and self.A2ASystem == "BRAA") or (not self.A2ASystem and _SETTINGS:IsA2A_BRAA())
end end
--- Sets A2A BULLS --- Sets A2A BULLS
@@ -434,7 +431,7 @@ do -- SETTINGS
-- @param #SETTINGS self -- @param #SETTINGS self
-- @return #boolean true if BULLS -- @return #boolean true if BULLS
function SETTINGS:IsA2A_BULLS() function SETTINGS:IsA2A_BULLS()
return ( self.A2ASystem and self.A2ASystem == "BULLS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BULLS() ) return (self.A2ASystem and self.A2ASystem == "BULLS") or (not self.A2ASystem and _SETTINGS:IsA2A_BULLS())
end end
--- Sets A2A LL DMS --- Sets A2A LL DMS
@@ -455,14 +452,14 @@ do -- SETTINGS
-- @param #SETTINGS self -- @param #SETTINGS self
-- @return #boolean true if LL DMS -- @return #boolean true if LL DMS
function SETTINGS:IsA2A_LL_DMS() function SETTINGS:IsA2A_LL_DMS()
return ( self.A2ASystem and self.A2ASystem == "LL DMS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_LL_DMS() ) return (self.A2ASystem and self.A2ASystem == "LL DMS") or (not self.A2ASystem and _SETTINGS:IsA2A_LL_DMS())
end end
--- Is LL DDM --- Is LL DDM
-- @param #SETTINGS self -- @param #SETTINGS self
-- @return #boolean true if LL DDM -- @return #boolean true if LL DDM
function SETTINGS:IsA2A_LL_DDM() function SETTINGS:IsA2A_LL_DDM()
return ( self.A2ASystem and self.A2ASystem == "LL DDM" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_LL_DDM() ) return (self.A2ASystem and self.A2ASystem == "LL DDM") or (not self.A2ASystem and _SETTINGS:IsA2A_LL_DDM())
end end
--- Sets A2A MGRS --- Sets A2A MGRS
@@ -476,7 +473,7 @@ do -- SETTINGS
-- @param #SETTINGS self -- @param #SETTINGS self
-- @return #boolean true if MGRS -- @return #boolean true if MGRS
function SETTINGS:IsA2A_MGRS() function SETTINGS:IsA2A_MGRS()
return ( self.A2ASystem and self.A2ASystem == "MGRS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_MGRS() ) return (self.A2ASystem and self.A2ASystem == "MGRS") or (not self.A2ASystem and _SETTINGS:IsA2A_MGRS())
end end
--- @param #SETTINGS self --- @param #SETTINGS self
@@ -495,37 +492,37 @@ do -- SETTINGS
-- A2G Coordinate System -- A2G Coordinate System
------- -------
local text="A2G Coordinate System" local text = "A2G Coordinate System"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="A2G Coordinates" text = "A2G Coordinates"
end end
local A2GCoordinateMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime ) local A2GCoordinateMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
-- Set LL DMS -- Set LL DMS
if not self:IsA2G_LL_DMS() then if not self:IsA2G_LL_DMS() then
local text="Lat/Lon Degree Min Sec (LL DMS)" local text = "Lat/Lon Degree Min Sec (LL DMS)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="LL DMS" text = "LL DMS"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
end end
-- Set LL DDM -- Set LL DDM
if not self:IsA2G_LL_DDM() then if not self:IsA2G_LL_DDM() then
local text="Lat/Lon Degree Dec Min (LL DDM)" local text = "Lat/Lon Degree Dec Min (LL DDM)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="LL DDM" text = "LL DDM"
end end
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
end end
-- Set LL DMS accuracy. -- Set LL DMS accuracy.
if self:IsA2G_LL_DDM() then if self:IsA2G_LL_DDM() then
local text1="LL DDM Accuracy 1" local text1 = "LL DDM Accuracy 1"
local text2="LL DDM Accuracy 2" local text2 = "LL DDM Accuracy 2"
local text3="LL DDM Accuracy 3" local text3 = "LL DDM Accuracy 3"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text1="LL DDM" text1 = "LL DDM"
end end
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
@@ -534,18 +531,18 @@ do -- SETTINGS
-- Set BR. -- Set BR.
if not self:IsA2G_BR() then if not self:IsA2G_BR() then
local text="Bearing, Range (BR)" local text = "Bearing, Range (BR)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="BR" text = "BR"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text , A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "BR" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "BR" ):SetTime( MenuTime )
end end
-- Set MGRS. -- Set MGRS.
if not self:IsA2G_MGRS() then if not self:IsA2G_MGRS() then
local text="Military Grid (MGRS)" local text = "Military Grid (MGRS)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="MGRS" text = "MGRS"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
end end
@@ -563,24 +560,24 @@ do -- SETTINGS
-- A2A Coordinate System -- A2A Coordinate System
------- -------
local text="A2A Coordinate System" local text = "A2A Coordinate System"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="A2A Coordinates" text = "A2A Coordinates"
end end
local A2ACoordinateMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime ) local A2ACoordinateMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
if not self:IsA2A_LL_DMS() then if not self:IsA2A_LL_DMS() then
local text="Lat/Lon Degree Min Sec (LL DMS)" local text = "Lat/Lon Degree Min Sec (LL DMS)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="LL DMS" text = "LL DMS"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
end end
if not self:IsA2A_LL_DDM() then if not self:IsA2A_LL_DDM() then
local text="Lat/Lon Degree Dec Min (LL DDM)" local text = "Lat/Lon Degree Dec Min (LL DDM)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="LL DDM" text = "LL DDM"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
end end
@@ -593,25 +590,25 @@ do -- SETTINGS
end end
if not self:IsA2A_BULLS() then if not self:IsA2A_BULLS() then
local text="Bullseye (BULLS)" local text = "Bullseye (BULLS)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="Bulls" text = "Bulls"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BULLS" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BULLS" ):SetTime( MenuTime )
end end
if not self:IsA2A_BRAA() then if not self:IsA2A_BRAA() then
local text="Bearing Range Altitude Aspect (BRAA)" local text = "Bearing Range Altitude Aspect (BRAA)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="BRAA" text = "BRAA"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BRAA" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BRAA" ):SetTime( MenuTime )
end end
if not self:IsA2A_MGRS() then if not self:IsA2A_MGRS() then
local text="Military Grid (MGRS)" local text = "Military Grid (MGRS)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="MGRS" text = "MGRS"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
end end
@@ -624,31 +621,31 @@ do -- SETTINGS
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 5", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 5", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime )
end end
local text="Measures and Weights System" local text = "Measures and Weights System"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="Unit System" text = "Unit System"
end end
local MetricsMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime ) local MetricsMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
if self:IsMetric() then if self:IsMetric() then
local text="Imperial (Miles,Feet)" local text = "Imperial (Miles,Feet)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="Imperial" text = "Imperial"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, false ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, false ):SetTime( MenuTime )
end end
if self:IsImperial() then if self:IsImperial() then
local text="Metric (Kilometers,Meters)" local text = "Metric (Kilometers,Meters)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="Metric" text = "Metric"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, true ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, true ):SetTime( MenuTime )
end end
local text="Messages and Reports" local text = "Messages and Reports"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="Messages & Reports" text = "Messages & Reports"
end end
local MessagesMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime ) local MessagesMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
@@ -689,7 +686,6 @@ do -- SETTINGS
MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 120 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 120 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "3 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 180 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "3 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 180 ):SetTime( MenuTime )
SettingsMenu:Remove( MenuTime ) SettingsMenu:Remove( MenuTime )
return self return self
@@ -733,11 +729,11 @@ do -- SETTINGS
self.PlayerMenu = PlayerMenu self.PlayerMenu = PlayerMenu
self:I(string.format("Setting menu for player %s", tostring(PlayerName))) self:I( string.format( "Setting menu for player %s", tostring( PlayerName ) ) )
local submenu = MENU_GROUP:New( PlayerGroup, "LL Accuracy", PlayerMenu ) local submenu = MENU_GROUP:New( PlayerGroup, "LL Accuracy", PlayerMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 0 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 0 ) MENU_GROUP_COMMAND:New( PlayerGroup, "LL 0 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 0 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 1 Decimal", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 ) MENU_GROUP_COMMAND:New( PlayerGroup, "LL 1 Decimal", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 2 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 ) MENU_GROUP_COMMAND:New( PlayerGroup, "LL 2 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 3 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 ) MENU_GROUP_COMMAND:New( PlayerGroup, "LL 3 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 4 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 ) MENU_GROUP_COMMAND:New( PlayerGroup, "LL 4 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
@@ -754,40 +750,40 @@ do -- SETTINGS
-- A2G Coordinate System -- A2G Coordinate System
------ ------
local text="A2G Coordinate System" local text = "A2G Coordinate System"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="A2G Coordinates" text = "A2G Coordinates"
end end
local A2GCoordinateMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu ) local A2GCoordinateMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
if not self:IsA2G_LL_DMS() or _SETTINGS.MenuStatic then if not self:IsA2G_LL_DMS() or _SETTINGS.MenuStatic then
local text="Lat/Lon Degree Min Sec (LL DMS)" local text = "Lat/Lon Degree Min Sec (LL DMS)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="A2G LL DMS" text = "A2G LL DMS"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
end end
if not self:IsA2G_LL_DDM() or _SETTINGS.MenuStatic then if not self:IsA2G_LL_DDM() or _SETTINGS.MenuStatic then
local text="Lat/Lon Degree Dec Min (LL DDM)" local text = "Lat/Lon Degree Dec Min (LL DDM)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="A2G LL DDM" text = "A2G LL DDM"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
end end
if not self:IsA2G_BR() or _SETTINGS.MenuStatic then if not self:IsA2G_BR() or _SETTINGS.MenuStatic then
local text="Bearing, Range (BR)" local text = "Bearing, Range (BR)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="A2G BR" text = "A2G BR"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" )
end end
if not self:IsA2G_MGRS() or _SETTINGS.MenuStatic then if not self:IsA2G_MGRS() or _SETTINGS.MenuStatic then
local text="Military Grid (MGRS)" local text = "Military Grid (MGRS)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="A2G MGRS" text = "A2G MGRS"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
end end
@@ -796,49 +792,48 @@ do -- SETTINGS
-- A2A Coordinates Menu -- A2A Coordinates Menu
------ ------
local text="A2A Coordinate System" local text = "A2A Coordinate System"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="A2A Coordinates" text = "A2A Coordinates"
end end
local A2ACoordinateMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu ) local A2ACoordinateMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
if not self:IsA2A_LL_DMS() or _SETTINGS.MenuStatic then if not self:IsA2A_LL_DMS() or _SETTINGS.MenuStatic then
local text="Lat/Lon Degree Min Sec (LL DMS)" local text = "Lat/Lon Degree Min Sec (LL DMS)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="A2A LL DMS" text = "A2A LL DMS"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
end end
if not self:IsA2A_LL_DDM() or _SETTINGS.MenuStatic then if not self:IsA2A_LL_DDM() or _SETTINGS.MenuStatic then
local text="Lat/Lon Degree Dec Min (LL DDM)" local text = "Lat/Lon Degree Dec Min (LL DDM)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="A2A LL DDM" text = "A2A LL DDM"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
end end
if not self:IsA2A_BULLS() or _SETTINGS.MenuStatic then if not self:IsA2A_BULLS() or _SETTINGS.MenuStatic then
local text="Bullseye (BULLS)" local text = "Bullseye (BULLS)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="A2A BULLS" text = "A2A BULLS"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" )
end end
if not self:IsA2A_BRAA() or _SETTINGS.MenuStatic then if not self:IsA2A_BRAA() or _SETTINGS.MenuStatic then
local text="Bearing Range Altitude Aspect (BRAA)" local text = "Bearing Range Altitude Aspect (BRAA)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="A2A BRAA" text = "A2A BRAA"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRAA" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRAA" )
end end
if not self:IsA2A_MGRS() or _SETTINGS.MenuStatic then if not self:IsA2A_MGRS() or _SETTINGS.MenuStatic then
local text="Military Grid (MGRS)" local text = "Military Grid (MGRS)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="A2A MGRS" text = "A2A MGRS"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
end end
@@ -847,24 +842,24 @@ do -- SETTINGS
-- Unit system -- Unit system
--- ---
local text="Measures and Weights System" local text = "Measures and Weights System"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="Unit System" text = "Unit System"
end end
local MetricsMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu ) local MetricsMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
if self:IsMetric() or _SETTINGS.MenuStatic then if self:IsMetric() or _SETTINGS.MenuStatic then
local text="Imperial (Miles,Feet)" local text = "Imperial (Miles,Feet)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="Imperial" text = "Imperial"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, false ) MENU_GROUP_COMMAND:New( PlayerGroup, text, MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, false )
end end
if self:IsImperial() or _SETTINGS.MenuStatic then if self:IsImperial() or _SETTINGS.MenuStatic then
local text="Metric (Kilometers,Meters)" local text = "Metric (Kilometers,Meters)"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="Metric" text = "Metric"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true ) MENU_GROUP_COMMAND:New( PlayerGroup, text, MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true )
end end
@@ -873,9 +868,9 @@ do -- SETTINGS
-- Messages and Reports -- Messages and Reports
--- ---
local text="Messages and Reports" local text = "Messages and Reports"
if _SETTINGS.MenuShort then if _SETTINGS.MenuShort then
text="Messages & Reports" text = "Messages & Reports"
end end
local MessagesMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu ) local MessagesMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
@@ -935,39 +930,38 @@ do -- SETTINGS
return self return self
end end
--- @param #SETTINGS self --- @param #SETTINGS self
function SETTINGS:A2GMenuSystem( MenuGroup, RootMenu, A2GSystem ) function SETTINGS:A2GMenuSystem( MenuGroup, RootMenu, A2GSystem )
self.A2GSystem = A2GSystem self.A2GSystem = A2GSystem
MESSAGE:New( string.format("Settings: Default A2G coordinate system set to %s for all players!", A2GSystem ), 5 ):ToAll() MESSAGE:New( string.format( "Settings: Default A2G coordinate system set to %s for all players!", A2GSystem ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu ) self:SetSystemMenu( MenuGroup, RootMenu )
end end
--- @param #SETTINGS self --- @param #SETTINGS self
function SETTINGS:A2AMenuSystem( MenuGroup, RootMenu, A2ASystem ) function SETTINGS:A2AMenuSystem( MenuGroup, RootMenu, A2ASystem )
self.A2ASystem = A2ASystem self.A2ASystem = A2ASystem
MESSAGE:New( string.format("Settings: Default A2A coordinate system set to %s for all players!", A2ASystem ), 5 ):ToAll() MESSAGE:New( string.format( "Settings: Default A2A coordinate system set to %s for all players!", A2ASystem ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu ) self:SetSystemMenu( MenuGroup, RootMenu )
end end
--- @param #SETTINGS self --- @param #SETTINGS self
function SETTINGS:MenuLL_DDM_Accuracy( MenuGroup, RootMenu, LL_Accuracy ) function SETTINGS:MenuLL_DDM_Accuracy( MenuGroup, RootMenu, LL_Accuracy )
self.LL_Accuracy = LL_Accuracy self.LL_Accuracy = LL_Accuracy
MESSAGE:New( string.format("Settings: Default LL accuracy set to %s for all players!", LL_Accuracy ), 5 ):ToAll() MESSAGE:New( string.format( "Settings: Default LL accuracy set to %s for all players!", LL_Accuracy ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu ) self:SetSystemMenu( MenuGroup, RootMenu )
end end
--- @param #SETTINGS self --- @param #SETTINGS self
function SETTINGS:MenuMGRS_Accuracy( MenuGroup, RootMenu, MGRS_Accuracy ) function SETTINGS:MenuMGRS_Accuracy( MenuGroup, RootMenu, MGRS_Accuracy )
self.MGRS_Accuracy = MGRS_Accuracy self.MGRS_Accuracy = MGRS_Accuracy
MESSAGE:New( string.format("Settings: Default MGRS accuracy set to %s for all players!", MGRS_Accuracy ), 5 ):ToAll() MESSAGE:New( string.format( "Settings: Default MGRS accuracy set to %s for all players!", MGRS_Accuracy ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu ) self:SetSystemMenu( MenuGroup, RootMenu )
end end
--- @param #SETTINGS self --- @param #SETTINGS self
function SETTINGS:MenuMWSystem( MenuGroup, RootMenu, MW ) function SETTINGS:MenuMWSystem( MenuGroup, RootMenu, MW )
self.Metric = MW self.Metric = MW
MESSAGE:New( string.format("Settings: Default measurement format set to %s for all players!", MW and "Metric" or "Imperial" ), 5 ):ToAll() MESSAGE:New( string.format( "Settings: Default measurement format set to %s for all players!", MW and "Metric" or "Imperial" ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu ) self:SetSystemMenu( MenuGroup, RootMenu )
end end
@@ -980,12 +974,12 @@ do -- SETTINGS
do do
--- @param #SETTINGS self --- @param #SETTINGS self
function SETTINGS:MenuGroupA2GSystem( PlayerUnit, PlayerGroup, PlayerName, A2GSystem ) function SETTINGS:MenuGroupA2GSystem( PlayerUnit, PlayerGroup, PlayerName, A2GSystem )
BASE:E( {self, PlayerUnit:GetName(), A2GSystem} ) BASE:E( { self, PlayerUnit:GetName(), A2GSystem } )
self.A2GSystem = A2GSystem self.A2GSystem = A2GSystem
MESSAGE:New( string.format( "Settings: A2G format set to %s for player %s.", A2GSystem, PlayerName ), 5 ):ToGroup( PlayerGroup ) MESSAGE:New( string.format( "Settings: A2G format set to %s for player %s.", A2GSystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
if _SETTINGS.MenuStatic==false then if _SETTINGS.MenuStatic == false then
self:RemovePlayerMenu(PlayerUnit) self:RemovePlayerMenu( PlayerUnit )
self:SetPlayerMenu(PlayerUnit) self:SetPlayerMenu( PlayerUnit )
end end
end end
@@ -993,9 +987,9 @@ do -- SETTINGS
function SETTINGS:MenuGroupA2ASystem( PlayerUnit, PlayerGroup, PlayerName, A2ASystem ) function SETTINGS:MenuGroupA2ASystem( PlayerUnit, PlayerGroup, PlayerName, A2ASystem )
self.A2ASystem = A2ASystem self.A2ASystem = A2ASystem
MESSAGE:New( string.format( "Settings: A2A format set to %s for player %s.", A2ASystem, PlayerName ), 5 ):ToGroup( PlayerGroup ) MESSAGE:New( string.format( "Settings: A2A format set to %s for player %s.", A2ASystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
if _SETTINGS.MenuStatic==false then if _SETTINGS.MenuStatic == false then
self:RemovePlayerMenu(PlayerUnit) self:RemovePlayerMenu( PlayerUnit )
self:SetPlayerMenu(PlayerUnit) self:SetPlayerMenu( PlayerUnit )
end end
end end
@@ -1003,9 +997,9 @@ do -- SETTINGS
function SETTINGS:MenuGroupLL_DDM_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, LL_Accuracy ) function SETTINGS:MenuGroupLL_DDM_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, LL_Accuracy )
self.LL_Accuracy = LL_Accuracy self.LL_Accuracy = LL_Accuracy
MESSAGE:New( string.format( "Settings: LL format accuracy set to %d decimal places for player %s.", LL_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup ) MESSAGE:New( string.format( "Settings: LL format accuracy set to %d decimal places for player %s.", LL_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
if _SETTINGS.MenuStatic==false then if _SETTINGS.MenuStatic == false then
self:RemovePlayerMenu(PlayerUnit) self:RemovePlayerMenu( PlayerUnit )
self:SetPlayerMenu(PlayerUnit) self:SetPlayerMenu( PlayerUnit )
end end
end end
@@ -1013,9 +1007,9 @@ do -- SETTINGS
function SETTINGS:MenuGroupMGRS_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, MGRS_Accuracy ) function SETTINGS:MenuGroupMGRS_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, MGRS_Accuracy )
self.MGRS_Accuracy = MGRS_Accuracy self.MGRS_Accuracy = MGRS_Accuracy
MESSAGE:New( string.format( "Settings: MGRS format accuracy set to %d for player %s.", MGRS_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup ) MESSAGE:New( string.format( "Settings: MGRS format accuracy set to %d for player %s.", MGRS_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
if _SETTINGS.MenuStatic==false then if _SETTINGS.MenuStatic == false then
self:RemovePlayerMenu(PlayerUnit) self:RemovePlayerMenu( PlayerUnit )
self:SetPlayerMenu(PlayerUnit) self:SetPlayerMenu( PlayerUnit )
end end
end end
@@ -1023,9 +1017,9 @@ do -- SETTINGS
function SETTINGS:MenuGroupMWSystem( PlayerUnit, PlayerGroup, PlayerName, MW ) function SETTINGS:MenuGroupMWSystem( PlayerUnit, PlayerGroup, PlayerName, MW )
self.Metric = MW self.Metric = MW
MESSAGE:New( string.format( "Settings: Measurement format set to %s for player %s.", MW and "Metric" or "Imperial", PlayerName ), 5 ):ToGroup( PlayerGroup ) MESSAGE:New( string.format( "Settings: Measurement format set to %s for player %s.", MW and "Metric" or "Imperial", PlayerName ), 5 ):ToGroup( PlayerGroup )
if _SETTINGS.MenuStatic==false then if _SETTINGS.MenuStatic == false then
self:RemovePlayerMenu(PlayerUnit) self:RemovePlayerMenu( PlayerUnit )
self:SetPlayerMenu(PlayerUnit) self:SetPlayerMenu( PlayerUnit )
end end
end end
@@ -1055,7 +1049,6 @@ do -- SETTINGS
end end
--- Configures the era of the mission to be Cold war. --- Configures the era of the mission to be Cold war.
-- @param #SETTINGS self -- @param #SETTINGS self
-- @return #SETTINGS self -- @return #SETTINGS self
@@ -1065,7 +1058,6 @@ do -- SETTINGS
end end
--- Configures the era of the mission to be Modern war. --- Configures the era of the mission to be Modern war.
-- @param #SETTINGS self -- @param #SETTINGS self
-- @return #SETTINGS self -- @return #SETTINGS self
@@ -1075,7 +1067,4 @@ do -- SETTINGS
end end
end end
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1053,7 +1053,7 @@ end
-- * `AIRBASE.Nevada.Lincoln_County` -- * `AIRBASE.Nevada.Lincoln_County`
-- * `AIRBASE.Nevada.McCarran_International_Airport` -- * `AIRBASE.Nevada.McCarran_International_Airport`
-- * `AIRBASE.Nevada.Mesquite` -- * `AIRBASE.Nevada.Mesquite`
-- * `AIRBASE.Nevada.Mina_Airport_3Q0` -- * `AIRBASE.Nevada.Mina_Airport`
-- * `AIRBASE.Nevada.Nellis_AFB` -- * `AIRBASE.Nevada.Nellis_AFB`
-- * `AIRBASE.Nevada.North_Las_Vegas` -- * `AIRBASE.Nevada.North_Las_Vegas`
-- * `AIRBASE.Nevada.Pahute_Mesa_Airstrip` -- * `AIRBASE.Nevada.Pahute_Mesa_Airstrip`
@@ -1288,7 +1288,7 @@ ATC_GROUND_NEVADA = {
}, },
}, },
}, },
[AIRBASE.Nevada.Mina_Airport_3Q0] = { [AIRBASE.Nevada.Mina_Airport] = {
PointsRunways = { PointsRunways = {
[1] = { [1] = {
[1] = {["y"]=-290054.57371429,["x"]=-160930.02228572,}, [1] = {["y"]=-290054.57371429,["x"]=-160930.02228572,},
@@ -73,7 +73,7 @@
-- @field Core.Point#COORDINATE RearmingPlaceCoord Coordinates of the rearming place. If the place is more than 100 m away from the ARTY group, the group will go there. -- @field Core.Point#COORDINATE RearmingPlaceCoord Coordinates of the rearming place. If the place is more than 100 m away from the ARTY group, the group will go there.
-- @field #boolean RearmingArtyOnRoad If true, ARTY group will move to rearming place using mainly roads. Default false. -- @field #boolean RearmingArtyOnRoad If true, ARTY group will move to rearming place using mainly roads. Default false.
-- @field Core.Point#COORDINATE InitialCoord Initial coordinates of the ARTY group. -- @field Core.Point#COORDINATE InitialCoord Initial coordinates of the ARTY group.
-- @field #boolean report Arty group sends messages about their current state or target to its coaliton. -- @field #boolean report Arty group sends messages about their current state or target to its coalition.
-- @field #table ammoshells Table holding names of the shell types which are included when counting the ammo. Default is {"weapons.shells"} which include most shells. -- @field #table ammoshells Table holding names of the shell types which are included when counting the ammo. Default is {"weapons.shells"} which include most shells.
-- @field #table ammorockets Table holding names of the rocket types which are included when counting the ammo. Default is {"weapons.nurs"} which includes most unguided rockets. -- @field #table ammorockets Table holding names of the rocket types which are included when counting the ammo. Default is {"weapons.nurs"} which includes most unguided rockets.
-- @field #table ammomissiles Table holding names of the missile types which are included when counting the ammo. Default is {"weapons.missiles"} which includes some guided missiles. -- @field #table ammomissiles Table holding names of the missile types which are included when counting the ammo. Default is {"weapons.missiles"} which includes some guided missiles.
File diff suppressed because it is too large Load Diff
@@ -23,7 +23,6 @@
-- @module Functional.FOX -- @module Functional.FOX
-- @image Functional_FOX.png -- @image Functional_FOX.png
--- FOX class. --- FOX class.
-- @type FOX -- @type FOX
-- @field #string ClassName Name of the class. -- @field #string ClassName Name of the class.
@@ -48,7 +47,6 @@
-- @field #number dt05 Time step [sec] for missile position updates if distance to target > 5 km and < 10 km. Default 0.5 sec. -- @field #number dt05 Time step [sec] for missile position updates if distance to target > 5 km and < 10 km. Default 0.5 sec.
-- @field #number dt01 Time step [sec] for missile position updates if distance to target > 1 km and < 5 km. Default 0.1 sec. -- @field #number dt01 Time step [sec] for missile position updates if distance to target > 1 km and < 5 km. Default 0.1 sec.
-- @field #number dt00 Time step [sec] for missile position updates if distance to target < 1 km. Default 0.01 sec. -- @field #number dt00 Time step [sec] for missile position updates if distance to target < 1 km. Default 0.01 sec.
-- @field #boolean
-- @extends Core.Fsm#FSM -- @extends Core.Fsm#FSM
--- Fox 3! --- Fox 3!
+159 -53
View File
@@ -19,8 +19,8 @@
-- --
-- @module Functional.Mantis -- @module Functional.Mantis
-- @image Functional.Mantis.jpg -- @image Functional.Mantis.jpg
--
-- Date: July 2021 -- Date: Nov 2021
------------------------------------------------------------------------- -------------------------------------------------------------------------
--- **MANTIS** class, extends Core.Base#BASE --- **MANTIS** class, extends Core.Base#BASE
@@ -101,23 +101,23 @@
-- --
-- # 2. Start up your MANTIS with a basic setting -- # 2. Start up your MANTIS with a basic setting
-- --
-- `myredmantis = MANTIS:New("myredmantis","Red SAM","Red EWR",nil,"red",false)` -- myredmantis = MANTIS:New("myredmantis","Red SAM","Red EWR",nil,"red",false)
-- `myredmantis:Start()` -- myredmantis:Start()
-- --
-- [optional] Use -- [optional] Use
-- --
-- * `MANTIS:SetEWRGrouping(radius)` -- * MANTIS:SetEWRGrouping(radius)
-- * `MANTIS:SetEWRRange(radius)` -- * MANTIS:SetEWRRange(radius)
-- * `MANTIS:SetSAMRadius(radius)` -- * MANTIS:SetSAMRadius(radius)
-- * `MANTIS:SetDetectInterval(interval)` -- * MANTIS:SetDetectInterval(interval)
-- * `MANTIS:SetAutoRelocate(hq, ewr)` -- * MANTIS:SetAutoRelocate(hq, ewr)
-- --
-- before starting #MANTIS to fine-tune your setup. -- before starting #MANTIS to fine-tune your setup.
-- --
-- If you want to use a separate AWACS unit (default detection range: 250km) to support your EWR system, use e.g. the following setup: -- If you want to use a separate AWACS unit (default detection range: 250km) to support your EWR system, use e.g. the following setup:
-- --
-- `mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")` -- mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
-- `mybluemantis:Start()` -- mybluemantis:Start()
-- --
-- # 3. Default settings -- # 3. Default settings
-- --
@@ -138,7 +138,7 @@
-- --
-- Advanced mode will *decrease* reactivity of MANTIS, if HQ and/or EWR network dies. Awacs is counted as one EWR unit. It will set SAMs to RED state if both are dead. Requires usage of an **HQ** object and the **dynamic** option. -- Advanced mode will *decrease* reactivity of MANTIS, if HQ and/or EWR network dies. Awacs is counted as one EWR unit. It will set SAMs to RED state if both are dead. Requires usage of an **HQ** object and the **dynamic** option.
-- --
-- E.g. `mymantis:SetAdvancedMode( true, 90 )` -- E.g. mymantis:SetAdvancedMode( true, 90 )
-- --
-- Use this option if you want to make use of or allow advanced SEAD tactics. -- Use this option if you want to make use of or allow advanced SEAD tactics.
-- --
@@ -147,16 +147,39 @@
-- You can also choose to integrate Mantis with @{Functional.Shorad#SHORAD} for protection against HARMs and AGMs. When SHORAD detects a missile fired at one of MANTIS' SAM sites, it will activate SHORAD systems in -- You can also choose to integrate Mantis with @{Functional.Shorad#SHORAD} for protection against HARMs and AGMs. When SHORAD detects a missile fired at one of MANTIS' SAM sites, it will activate SHORAD systems in
-- the given defense checkradius around that SAM site. Create a SHORAD object first, then integrate with MANTIS like so: -- the given defense checkradius around that SAM site. Create a SHORAD object first, then integrate with MANTIS like so:
-- --
-- `local SamSet = SET_GROUP:New():FilterPrefixes("Blue SAM"):FilterCoalitions("blue"):FilterStart()` -- local SamSet = SET_GROUP:New():FilterPrefixes("Blue SAM"):FilterCoalitions("blue"):FilterStart()
-- `myshorad = SHORAD:New("BlueShorad", "Blue SHORAD", SamSet, 22000, 600, "blue")` -- myshorad = SHORAD:New("BlueShorad", "Blue SHORAD", SamSet, 22000, 600, "blue")
-- `-- now set up MANTIS` -- -- now set up MANTIS
-- `mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")` -- mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
-- `mymantis:AddShorad(myshorad,720)` -- mymantis:AddShorad(myshorad,720)
-- `mymantis:Start()` -- mymantis:Start()
-- --
-- and (optionally) remove the link later on with -- and (optionally) remove the link later on with
-- --
-- `mymantis:RemoveShorad()` -- mymantis:RemoveShorad()
--
-- # 6. Integrated SEAD
--
-- MANTIS is using @{Functional.Sead#SEAD} internally to both detect and evade HARM attacks. No extra efforts needed to set this up!
-- Once a HARM attack is detected, MANTIS (via SEAD) will shut down the radars of the attacked SAM site and take evasive action by moving the SAM
-- vehicles around (*if they are __drivable__*, that is). There's a component of randomness in detection and evasion, which is based on the
-- skill set of the SAM set (the higher the skill, the more likely). When a missile is fired from far away, the SAM will stay active for a
-- period of time to stay defensive, before it takes evasive actions.
--
-- You can link into the SEAD driven events of MANTIS like so:
--
-- function mymantis:OnAfterSeadSuppressionPlanned(From, Event, To, Group, Name, SuppressionStartTime, SuppressionEndTime)
-- -- your code here - SAM site shutdown and evasion planned, but not yet executed
-- -- Time entries relate to timer.getTime() - see https://wiki.hoggitworld.com/view/DCS_func_getTime
-- end
--
-- function mymantis:OnAfterSeadSuppressionStart(From, Event, To, Group, Name)
-- -- your code here - SAM site is emissions off and possibly moving
-- end
--
-- function mymantis:OnAfterSeadSuppressionEnd(From, Event, To, Group, Name)
-- -- your code here - SAM site is back online
-- end
-- --
-- @field #MANTIS -- @field #MANTIS
MANTIS = { MANTIS = {
@@ -198,6 +221,7 @@ MANTIS = {
DLink = false, DLink = false,
DLTimeStamp = 0, DLTimeStamp = 0,
Padding = 10, Padding = 10,
SuppressedGroups = {},
} }
--- Advanced state enumerator --- Advanced state enumerator
@@ -227,23 +251,23 @@ do
--@return #MANTIS self --@return #MANTIS self
--@usage Start up your MANTIS with a basic setting --@usage Start up your MANTIS with a basic setting
-- --
-- `myredmantis = MANTIS:New("myredmantis","Red SAM","Red EWR",nil,"red",false)` -- myredmantis = MANTIS:New("myredmantis","Red SAM","Red EWR",nil,"red",false)
-- `myredmantis:Start()` -- myredmantis:Start()
-- --
-- [optional] Use -- [optional] Use
-- --
-- * `MANTIS:SetEWRGrouping(radius)` -- * MANTIS:SetEWRGrouping(radius)
-- * `MANTIS:SetEWRRange(radius)` -- * MANTIS:SetEWRRange(radius)
-- * `MANTIS:SetSAMRadius(radius)` -- * MANTIS:SetSAMRadius(radius)
-- * `MANTIS:SetDetectInterval(interval)` -- * MANTIS:SetDetectInterval(interval)
-- * `MANTIS:SetAutoRelocate(hq, ewr)` -- * MANTIS:SetAutoRelocate(hq, ewr)
-- --
-- before starting #MANTIS to fine-tune your setup. -- before starting #MANTIS to fine-tune your setup.
-- --
-- If you want to use a separate AWACS unit (default detection range: 250km) to support your EWR system, use e.g. the following setup: -- If you want to use a separate AWACS unit (default detection range: 250km) to support your EWR system, use e.g. the following setup:
-- --
-- `mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")` -- mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
-- `mybluemantis:Start()` -- mybluemantis:Start()
-- --
function MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic,awacs, EmOnOff, Padding) function MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic,awacs, EmOnOff, Padding)
@@ -284,6 +308,7 @@ do
self.SamStateTracker = {} -- table to hold alert states, so we don't trigger state changes twice in adv mode self.SamStateTracker = {} -- table to hold alert states, so we don't trigger state changes twice in adv mode
self.DLink = false self.DLink = false
self.Padding = Padding or 10 self.Padding = Padding or 10
self.SuppressedGroups = {}
if EmOnOff then if EmOnOff then
if EmOnOff == false then if EmOnOff == false then
@@ -331,7 +356,7 @@ do
end end
-- @field #string version -- @field #string version
self.version="0.6.2" self.version="0.7.1"
self:I(string.format("***** Starting MANTIS Version %s *****", self.version)) self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
--- FSM Functions --- --- FSM Functions ---
@@ -340,15 +365,18 @@ do
self:SetStartState("Stopped") self:SetStartState("Stopped")
-- Add FSM transitions. -- Add FSM transitions.
-- From State --> Event --> To State -- From State --> Event --> To State
self:AddTransition("Stopped", "Start", "Running") -- Start FSM. self:AddTransition("Stopped", "Start", "Running") -- Start FSM.
self:AddTransition("*", "Status", "*") -- MANTIS status update. self:AddTransition("*", "Status", "*") -- MANTIS status update.
self:AddTransition("*", "Relocating", "*") -- MANTIS HQ and EWR are relocating. self:AddTransition("*", "Relocating", "*") -- MANTIS HQ and EWR are relocating.
self:AddTransition("*", "GreenState", "*") -- MANTIS A SAM switching to GREEN state. self:AddTransition("*", "GreenState", "*") -- MANTIS A SAM switching to GREEN state.
self:AddTransition("*", "RedState", "*") -- MANTIS A SAM switching to RED state. self:AddTransition("*", "RedState", "*") -- MANTIS A SAM switching to RED state.
self:AddTransition("*", "AdvStateChange", "*") -- MANTIS advanced mode state change. self:AddTransition("*", "AdvStateChange", "*") -- MANTIS advanced mode state change.
self:AddTransition("*", "ShoradActivated", "*") -- MANTIS woke up a connected SHORAD. self:AddTransition("*", "ShoradActivated", "*") -- MANTIS woke up a connected SHORAD.
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM. self:AddTransition("*", "SeadSuppressionStart", "*") -- SEAD has switched off one group.
self:AddTransition("*", "SeadSuppressionEnd", "*") -- SEAD has switched on one group.
self:AddTransition("*", "SeadSuppressionPlanned", "*") -- SEAD has planned a suppression.
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
------------------------ ------------------------
--- Pseudo Functions --- --- Pseudo Functions ---
@@ -427,6 +455,35 @@ do
-- @param #number Radius Radius around the named group to find SHORAD groups -- @param #number Radius Radius around the named group to find SHORAD groups
-- @param #number Ontime Seconds the SHORAD will stay active -- @param #number Ontime Seconds the SHORAD will stay active
--- On After "SeadSuppressionPlanned" event. Mantis has planned to switch off a site to defend SEAD attack.
-- @function [parent=#MANTIS] OnAfterSeadSuppressionPlanned
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @param Wrapper.Group#GROUP Group The suppressed GROUP object
-- @param #string Name Name of the suppressed group
-- @param #number SuppressionStartTime Model start time of the suppression from `timer.getTime()`
-- @param #number SuppressionEndTime Model end time of the suppression from `timer.getTime()`
--- On After "SeadSuppressionStart" event. Mantis has switched off a site to defend a SEAD attack.
-- @function [parent=#MANTIS] OnAfterSeadSuppressionStart
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @param Wrapper.Group#GROUP Group The suppressed GROUP object
-- @param #string Name Name of the suppressed groupe
--- On After "SeadSuppressionEnd" event. Mantis has switched on a site after a SEAD attack.
-- @function [parent=#MANTIS] OnAfterSeadSuppressionEnd
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @param Wrapper.Group#GROUP Group The suppressed GROUP object
-- @param #string Name Name of the suppressed group
return self return self
end end
@@ -625,7 +682,7 @@ do
return self return self
end end
--- Set using an #INTEL_DLINK object instead of #DETECTION. Requires Develop branch of Moose.lua. --- Set using an #INTEL_DLINK object instead of #DETECTION
-- @param #MANTIS self -- @param #MANTIS self
-- @param Ops.Intelligence#INTEL_DLINK DLink The data link object to be used. -- @param Ops.Intelligence#INTEL_DLINK DLink The data link object to be used.
function MANTIS:SetUsingDLink(DLink) function MANTIS:SetUsingDLink(DLink)
@@ -891,6 +948,7 @@ do
local group = _group -- Wrapper.Group#GROUP local group = _group -- Wrapper.Group#GROUP
-- TODO: add emissions on/off -- TODO: add emissions on/off
if self.UseEmOnOff then if self.UseEmOnOff then
group:OptionAlarmStateRed()
group:EnableEmission(false) group:EnableEmission(false)
--group:SetAIOff() --group:SetAIOff()
else else
@@ -909,6 +967,10 @@ do
-- make SAMs evasive -- make SAMs evasive
local mysead = SEAD:New( SEAD_Grps, self.Padding ) -- Functional.Sead#SEAD local mysead = SEAD:New( SEAD_Grps, self.Padding ) -- Functional.Sead#SEAD
mysead:SetEngagementRange(engagerange) mysead:SetEngagementRange(engagerange)
mysead:AddCallBack(self)
if self.UseEmOnOff then
mysead:SwitchEmissions(true)
end
self.mysead = mysead self.mysead = mysead
return self return self
end end
@@ -995,22 +1057,24 @@ do
local name = _data[1] local name = _data[1]
local samgroup = GROUP:FindByName(name) local samgroup = GROUP:FindByName(name)
local IsInZone, Distance = self:CheckObjectInZone(detset, samcoordinate) local IsInZone, Distance = self:CheckObjectInZone(detset, samcoordinate)
if IsInZone then --check any target in zone local suppressed = self.SuppressedGroups[name] or false
if IsInZone then --check any target in zone and not curr managed by SEAD
if samgroup:IsAlive() then if samgroup:IsAlive() then
-- switch on SAM -- switch on SAM
if self.UseEmOnOff then if self.UseEmOnOff and not suppressed then
-- TODO: add emissions on/off -- DONE: add emissions on/off
--samgroup:SetAIOn() --samgroup:SetAIOn()
samgroup:EnableEmission(true) samgroup:EnableEmission(true)
elseif not self.UseEmOnOff and not suppressed then
samgroup:OptionAlarmStateRed()
end end
samgroup:OptionAlarmStateRed() if self.SamStateTracker[name] ~= "RED" and not suppressed then
if self.SamStateTracker[name] ~= "RED" then
self:__RedState(1,samgroup) self:__RedState(1,samgroup)
self.SamStateTracker[name] = "RED" self.SamStateTracker[name] = "RED"
end end
-- link in to SHORAD if available -- link in to SHORAD if available
-- DONE: Test integration fully -- DONE: Test integration fully
if self.ShoradLink and Distance < self.ShoradActDistance then -- don't give SHORAD position away too early if self.ShoradLink and (Distance < self.ShoradActDistance or suppressed) then -- don't give SHORAD position away too early
local Shorad = self.Shorad local Shorad = self.Shorad
local radius = self.checkradius local radius = self.checkradius
local ontime = self.ShoradTime local ontime = self.ShoradTime
@@ -1018,7 +1082,7 @@ do
self:__ShoradActivated(1,name, radius, ontime) self:__ShoradActivated(1,name, radius, ontime)
end end
-- debug output -- debug output
if self.debug or self.verbose then if self.debug or self.verbose and not suppressed then
local text = string.format("SAM %s switched to alarm state RED!", name) local text = string.format("SAM %s switched to 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 if self.verbose then self:I(self.lid..text) end
@@ -1027,15 +1091,16 @@ do
else else
if samgroup:IsAlive() then if samgroup:IsAlive() then
-- switch off SAM -- switch off SAM
if self.UseEmOnOff then if self.UseEmOnOff and not suppressed then
samgroup:EnableEmission(false) samgroup:EnableEmission(false)
end elseif not self.UseEmOnOff and not suppressed then
samgroup:OptionAlarmStateGreen() samgroup:OptionAlarmStateGreen()
if self.SamStateTracker[name] ~= "GREEN" then end
self:__GreenState(1,samgroup) if self.SamStateTracker[name] ~= "GREEN" and not suppressed then
self.SamStateTracker[name] = "GREEN" self:__GreenState(1,samgroup)
end self.SamStateTracker[name] = "GREEN"
if self.debug or self.verbose then end
if self.debug or self.verbose and not suppressed then
local text = string.format("SAM %s switched to alarm state GREEN!", name) local text = string.format("SAM %s switched to 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 if self.verbose then self:I(self.lid..text) end
@@ -1264,6 +1329,47 @@ do
self:T({From, Event, To, Name, Radius, Ontime}) self:T({From, Event, To, Name, Radius, Ontime})
return self return self
end end
--- [Internal] Function triggered by Event SeadSuppressionStart
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @param Wrapper.Group#GROUP Group The suppressed GROUP object
-- @param #string Name Name of the suppressed group
function MANTIS:onafterSeadSuppressionStart(From, Event, To, Group, Name)
self:T({From, Event, To, Name})
self.SuppressedGroups[Name] = true
return self
end
--- [Internal] Function triggered by Event SeadSuppressionEnd
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @param Wrapper.Group#GROUP Group The suppressed GROUP object
-- @param #string Name Name of the suppressed group
function MANTIS:onafterSeadSuppressionEnd(From, Event, To, Group, Name)
self:T({From, Event, To, Name})
self.SuppressedGroups[Name] = false
return self
end
--- [Internal] Function triggered by Event SeadSuppressionPlanned
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @param Wrapper.Group#GROUP Group The suppressed GROUP object
-- @param #string Name Name of the suppressed group
-- @param #number SuppressionStartTime Model start time of the suppression from `timer.getTime()`
-- @param #number SuppressionEndTime Model end time of the suppression from `timer.getTime()`
function MANTIS:onafterSeadSuppressionPlanned(From, Event, To, Group, Name, SuppressionStartTime, SuppressionEndTime)
self:T({From, Event, To, Name})
return self
end
end end
----------------------------------------------------------------------- -----------------------------------------------------------------------
-- MANTIS end -- MANTIS end
@@ -742,7 +742,7 @@ function PSEUDOATC:ReportWeather(GID, UID, position, location)
local T=position:GetTemperature() local T=position:GetTemperature()
-- Correct unit system. -- Correct unit system.
local _T=string.format('%d°F', UTILS.CelciusToFarenheit(T)) local _T=string.format('%d°F', UTILS.CelsiusToFahrenheit(T))
if settings:IsMetric() then if settings:IsMetric() then
_T=string.format('%d°C', T) _T=string.format('%d°C', T)
end end
+5 -5
View File
@@ -69,7 +69,7 @@
-- @field #string category Category of aircarft: "plane" or "heli". -- @field #string category Category of aircarft: "plane" or "heli".
-- @field #number groupsize Number of aircraft in group. -- @field #number groupsize Number of aircraft in group.
-- @field #string friendly Possible departure/destination airport: all=blue+red+neutral, same=spawn+neutral, spawnonly=spawn, blue=blue+neutral, blueonly=blue, red=red+neutral, redonly=red. -- @field #string friendly Possible departure/destination airport: all=blue+red+neutral, same=spawn+neutral, spawnonly=spawn, blue=blue+neutral, blueonly=blue, red=red+neutral, redonly=red.
-- @field #table ctable Table with the valid coalitons from choice self.friendly. -- @field #table ctable Table with the valid coalitions from choice self.friendly.
-- @field #table aircraft Table which holds the basic aircraft properties (speed, range, ...). -- @field #table aircraft Table which holds the basic aircraft properties (speed, range, ...).
-- @field #number Vcruisemax Max cruise speed in m/s (250 m/s = 900 km/h = 486 kt) set by user. -- @field #number Vcruisemax Max cruise speed in m/s (250 m/s = 900 km/h = 486 kt) set by user.
-- @field #number Vclimb Default climb rate in ft/min. -- @field #number Vclimb Default climb rate in ft/min.
@@ -348,7 +348,7 @@ RAT={
category = nil, -- Category of aircarft: "plane" or "heli". category = nil, -- Category of aircarft: "plane" or "heli".
groupsize=nil, -- Number of aircraft in the group. groupsize=nil, -- Number of aircraft in the group.
friendly = "same", -- Possible departure/destination airport: same=spawn+neutral, spawnonly=spawn, blue=blue+neutral, blueonly=blue, red=red+neutral, redonly=red, neutral. friendly = "same", -- Possible departure/destination airport: same=spawn+neutral, spawnonly=spawn, blue=blue+neutral, blueonly=blue, red=red+neutral, redonly=red, neutral.
ctable = {}, -- Table with the valid coalitons from choice self.friendly. ctable = {}, -- Table with the valid coalitions from choice self.friendly.
aircraft = {}, -- Table which holds the basic aircraft properties (speed, range, ...). aircraft = {}, -- Table which holds the basic aircraft properties (speed, range, ...).
Vcruisemax=nil, -- Max cruise speed in set by user. Vcruisemax=nil, -- Max cruise speed in set by user.
Vclimb=1500, -- Default climb rate in ft/min. Vclimb=1500, -- Default climb rate in ft/min.
@@ -657,7 +657,7 @@ end
-- @param #RAT self -- @param #RAT self
-- @param #number naircraft (Optional) Number of aircraft to spawn. Default is one aircraft. -- @param #number naircraft (Optional) Number of aircraft to spawn. Default is one aircraft.
-- @return #boolean True if spawning was successful or nil if nothing was spawned. -- @return #boolean True if spawning was successful or nil if nothing was spawned.
-- @usage yak:Spawn(5) will spawn five aircraft. By default aircraft will spawn at neutral and red airports if the template group is part of the red coaliton. -- @usage yak:Spawn(5) will spawn five aircraft. By default aircraft will spawn at neutral and red airports if the template group is part of the red coalition.
function RAT:Spawn(naircraft) function RAT:Spawn(naircraft)
-- Make sure that this function is only been called once per RAT object. -- Make sure that this function is only been called once per RAT object.
@@ -1289,7 +1289,7 @@ end
--- Include all airports which lie in a zone as possible destinations. --- Include all airports which lie in a zone as possible destinations.
-- @param #RAT self -- @param #RAT self
-- @param Core.Zone#ZONE zone Zone in which the departure airports lie. Has to be a MOOSE zone. -- @param Core.Zone#ZONE zone Zone in which the destination airports lie. Has to be a MOOSE zone.
-- @return #RAT RAT self object. -- @return #RAT RAT self object.
function RAT:SetDestinationsFromZone(zone) function RAT:SetDestinationsFromZone(zone)
self:F2(zone) self:F2(zone)
@@ -1305,7 +1305,7 @@ end
--- Include all airports which lie in a zone as possible destinations. --- Include all airports which lie in a zone as possible destinations.
-- @param #RAT self -- @param #RAT self
-- @param Core.Zone#ZONE zone Zone in which the destination airports lie. Has to be a MOOSE zone. -- @param Core.Zone#ZONE zone Zone in which the departure airports lie. Has to be a MOOSE zone.
-- @return #RAT RAT self object. -- @return #RAT RAT self object.
function RAT:SetDeparturesFromZone(zone) function RAT:SetDeparturesFromZone(zone)
self:F2(zone) self:F2(zone)
File diff suppressed because it is too large Load Diff
+218 -260
View File
@@ -67,7 +67,7 @@
-- --
-- * Upload scoring to a database or a BI tool to publish the scoring results to the player community. -- * Upload scoring to a database or a BI tool to publish the scoring results to the player community.
-- * Upload scoring in an (online) Excel like tool, using pivot tables and pivot charts to show mission results. -- * Upload scoring in an (online) Excel like tool, using pivot tables and pivot charts to show mission results.
-- * Share scoring amoung players after the mission to discuss mission results. -- * Share scoring among players after the mission to discuss mission results.
-- --
-- Scores can be **reported**. **Menu options** are automatically added to **each player group** when a player joins a client slot or a CA unit. -- Scores can be **reported**. **Menu options** are automatically added to **each player group** when a player joins a client slot or a CA unit.
-- Use the radio menu F10 to consult the scores while running the mission. -- Use the radio menu F10 to consult the scores while running the mission.
@@ -88,7 +88,6 @@
-- @module Functional.Scoring -- @module Functional.Scoring
-- @image Scoring.JPG -- @image Scoring.JPG
--- @type SCORING --- @type SCORING
-- @field Players A collection of the current players that have joined the game. -- @field Players A collection of the current players that have joined the game.
-- @extends Core.Base#BASE -- @extends Core.Base#BASE
@@ -99,7 +98,6 @@
-- --
-- local Scoring = SCORING:New( "Scoring File" ) -- local Scoring = SCORING:New( "Scoring File" )
-- --
--
-- # Set the destroy score or penalty scale: -- # Set the destroy score or penalty scale:
-- --
-- Score scales can be set for scores granted when enemies or friendlies are destroyed. -- Score scales can be set for scores granted when enemies or friendlies are destroyed.
@@ -147,11 +145,11 @@
-- --
-- # (Decommissioned) Configure fratricide level. -- # (Decommissioned) Configure fratricide level.
-- --
-- **This functionality is decomissioned until the DCS bug concerning Unit:destroy() not being functional in multi player for player units has been fixed by ED**. -- **This functionality is decommissioned until the DCS bug concerning Unit:destroy() not being functional in multi player for player units has been fixed by ED**.
-- --
-- When a player commits too much damage to friendlies, his penalty score will reach a certain level. -- When a player commits too much damage to friendlies, his penalty score will reach a certain level.
-- Use the method @{#SCORING.SetFratricide}() to define the level when a player gets kicked. -- Use the method @{#SCORING.SetFratricide}() to define the level when a player gets kicked.
-- By default, the fratricide level is the default penalty mutiplier * 2 for the penalty score. -- By default, the fratricide level is the default penalty multiplier * 2 for the penalty score.
-- --
-- # Penalty score when a player changes the coalition. -- # Penalty score when a player changes the coalition.
-- --
@@ -190,8 +188,8 @@
-- --
-- --Sanitize Mission Scripting environment -- --Sanitize Mission Scripting environment
-- --This makes unavailable some unsecure functions. -- --This makes unavailable some unsecure functions.
-- --Mission downloaded from server to client may contain potentialy harmful lua code that may use these functions. -- --Mission downloaded from server to client may contain potentially harmful lua code that may use these functions.
-- --You can remove the code below and make availble these functions at your own risk. -- --You can remove the code below and make available these functions at your own risk.
-- --
-- The MOOSE designer cannot take any responsibility of any damage inflicted as a result of the de-sanitization. -- The MOOSE designer cannot take any responsibility of any damage inflicted as a result of the de-sanitization.
-- That being said, I hope that the SCORING class provides you with a great add-on to score your squad mates achievements. -- That being said, I hope that the SCORING class provides you with a great add-on to score your squad mates achievements.
@@ -229,20 +227,18 @@ SCORING = {
Players = {}, Players = {},
} }
local _SCORINGCoalition = local _SCORINGCoalition = {
{ [1] = "Red",
[1] = "Red", [2] = "Blue",
[2] = "Blue", }
}
local _SCORINGCategory = local _SCORINGCategory = {
{ [Unit.Category.AIRPLANE] = "Plane",
[Unit.Category.AIRPLANE] = "Plane", [Unit.Category.HELICOPTER] = "Helicopter",
[Unit.Category.HELICOPTER] = "Helicopter", [Unit.Category.GROUND_UNIT] = "Vehicle",
[Unit.Category.GROUND_UNIT] = "Vehicle", [Unit.Category.SHIP] = "Ship",
[Unit.Category.SHIP] = "Ship", [Unit.Category.STRUCTURE] = "Structure",
[Unit.Category.STRUCTURE] = "Structure", }
}
--- Creates a new SCORING object to administer the scoring achieved by players. --- Creates a new SCORING object to administer the scoring achieved by players.
-- @param #SCORING self -- @param #SCORING self
@@ -250,8 +246,8 @@ local _SCORINGCategory =
-- @return #SCORING self -- @return #SCORING self
-- @usage -- @usage
-- --
-- -- Define a new scoring object for the mission Gori Valley. -- -- Define a new scoring object for the mission Gori Valley.
-- ScoringObject = SCORING:New( "Gori Valley" ) -- ScoringObject = SCORING:New( "Gori Valley" )
-- --
function SCORING:New( GameName ) function SCORING:New( GameName )
@@ -264,7 +260,6 @@ function SCORING:New( GameName )
error( "A game name must be given to register the scoring results" ) error( "A game name must be given to register the scoring results" )
end end
-- Additional Object scores -- Additional Object scores
self.ScoringObjects = {} self.ScoringObjects = {}
@@ -284,9 +279,11 @@ function SCORING:New( GameName )
-- Default fratricide penalty level (maximum penalty that can be assigned to a player before he gets kicked). -- Default fratricide penalty level (maximum penalty that can be assigned to a player before he gets kicked).
self:SetFratricide( self.ScaleDestroyPenalty * 3 ) self:SetFratricide( self.ScaleDestroyPenalty * 3 )
self.penaltyonfratricide = true
-- Default penalty when a player changes coalition. -- Default penalty when a player changes coalition.
self:SetCoalitionChangePenalty( self.ScaleDestroyPenalty ) self:SetCoalitionChangePenalty( self.ScaleDestroyPenalty )
self.penaltyoncoalitionchange = true
self:SetDisplayMessagePrefix() self:SetDisplayMessagePrefix()
@@ -295,21 +292,18 @@ function SCORING:New( GameName )
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.Hit, self._EventOnHit ) self:HandleEvent( EVENTS.Hit, self._EventOnHit )
self:HandleEvent( EVENTS.Birth ) self:HandleEvent( EVENTS.Birth )
--self:HandleEvent( EVENTS.PlayerEnterUnit ) -- self:HandleEvent( EVENTS.PlayerEnterUnit )
self:HandleEvent( EVENTS.PlayerLeaveUnit ) self:HandleEvent( EVENTS.PlayerLeaveUnit )
-- During mission startup, especially for single player, -- During mission startup, especially for single player,
-- iterate the database for the player that has joined, and add him to the scoring, and set the menu. -- iterate the database for the player that has joined, and add him to the scoring, and set the menu.
-- But this can only be started one second after the mission has started, so i need to schedule this ... -- But this can only be started one second after the mission has started, so i need to schedule this ...
self.ScoringPlayerScan = BASE:ScheduleOnce( 1, self.ScoringPlayerScan = BASE:ScheduleOnce( 1, function()
function() for PlayerName, PlayerUnit in pairs( _DATABASE:GetPlayerUnits() ) do
for PlayerName, PlayerUnit in pairs( _DATABASE:GetPlayerUnits() ) do self:_AddPlayerFromUnit( PlayerUnit )
self:_AddPlayerFromUnit( PlayerUnit ) self:SetScoringMenu( PlayerUnit:GetGroup() )
self:SetScoringMenu( PlayerUnit:GetGroup() )
end
end end
) end )
-- Create the CSV file. -- Create the CSV file.
self:OpenCSV( GameName ) self:OpenCSV( GameName )
@@ -327,7 +321,6 @@ function SCORING:SetDisplayMessagePrefix( DisplayMessagePrefix )
return self return self
end end
--- Set the scale for scoring valid destroys (enemy destroys). --- Set the scale for scoring valid destroys (enemy destroys).
-- A default calculated score is a value between 1 and 10. -- A default calculated score is a value between 1 and 10.
-- The scale magnifies the scores given to the players. -- The scale magnifies the scores given to the players.
@@ -409,7 +402,6 @@ function SCORING:RemoveStaticScore( ScoreStatic )
return self return self
end end
--- Specify a special additional score for a @{Wrapper.Group}. --- Specify a special additional score for a @{Wrapper.Group}.
-- @param #SCORING self -- @param #SCORING self
-- @param Wrapper.Group#GROUP ScoreGroup The @{Wrapper.Group} for which each @{Wrapper.Unit} a Score is given. -- @param Wrapper.Group#GROUP ScoreGroup The @{Wrapper.Group} for which each @{Wrapper.Unit} a Score is given.
@@ -462,7 +454,6 @@ function SCORING:RemoveZoneScore( ScoreZone )
return self return self
end end
--- Configure to send messages after a target has been hit. --- Configure to send messages after a target has been hit.
-- @param #SCORING self -- @param #SCORING self
-- @param #boolean OnOff If true is given, the messages are sent. -- @param #boolean OnOff If true is given, the messages are sent.
@@ -569,10 +560,9 @@ function SCORING:IfMessagesToCoalition()
return self.MessagesAudience == 2 return self.MessagesAudience == 2
end end
--- When a player commits too much damage to friendlies, his penalty score will reach a certain level. --- When a player commits too much damage to friendlies, his penalty score will reach a certain level.
-- Use this method to define the level when a player gets kicked. -- Use this method to define the level when a player gets kicked.
-- By default, the fratricide level is the default penalty mutiplier * 2 for the penalty score. -- By default, the fratricide level is the default penalty multiplier * 2 for the penalty score.
-- @param #SCORING self -- @param #SCORING self
-- @param #number Fratricide The amount of maximum penalty that may be inflicted by a friendly player before he gets kicked. -- @param #number Fratricide The amount of maximum penalty that may be inflicted by a friendly player before he gets kicked.
-- @return #SCORING -- @return #SCORING
@@ -582,6 +572,23 @@ function SCORING:SetFratricide( Fratricide )
return self return self
end end
--- Decide if fratricide is leading to penalties (true) or not (false)
-- @param #SCORING self
-- @param #boolean OnOff Switch for Fratricide
-- @return #SCORING
function SCORING:SwitchFratricide( OnOff )
self.penaltyonfratricide = OnOff
return self
end
--- Decide if a change of coalition is leading to penalties (true) or not (false)
-- @param #SCORING self
-- @param #boolean OnOff Switch for Coalition Changes.
-- @return #SCORING
function SCORING:SwitchTreason( OnOff )
self.penaltyoncoalitionchange = OnOff
return self
end
--- When a player changes the coalition, he can receive a penalty score. --- When a player changes the coalition, he can receive a penalty score.
-- Use the method @{#SCORING.SetCoalitionChangePenalty}() to define the penalty when a player changes coalition. -- Use the method @{#SCORING.SetCoalitionChangePenalty}() to define the penalty when a player changes coalition.
@@ -595,20 +602,18 @@ function SCORING:SetCoalitionChangePenalty( CoalitionChangePenalty )
return self return self
end end
--- Sets the scoring menu. --- Sets the scoring menu.
-- @param #SCORING self -- @param #SCORING self
-- @return #SCORING -- @return #SCORING
function SCORING:SetScoringMenu( ScoringGroup ) function SCORING:SetScoringMenu( ScoringGroup )
local Menu = MENU_GROUP:New( ScoringGroup, 'Scoring and Statistics' ) local Menu = MENU_GROUP:New( ScoringGroup, 'Scoring and Statistics' )
local ReportGroupSummary = MENU_GROUP_COMMAND:New( ScoringGroup, 'Summary report players in group', Menu, SCORING.ReportScoreGroupSummary, self, ScoringGroup ) local ReportGroupSummary = MENU_GROUP_COMMAND:New( ScoringGroup, 'Summary report players in group', Menu, SCORING.ReportScoreGroupSummary, self, ScoringGroup )
local ReportGroupDetailed = MENU_GROUP_COMMAND:New( ScoringGroup, 'Detailed report players in group', Menu, SCORING.ReportScoreGroupDetailed, self, ScoringGroup ) local ReportGroupDetailed = MENU_GROUP_COMMAND:New( ScoringGroup, 'Detailed report players in group', Menu, SCORING.ReportScoreGroupDetailed, self, ScoringGroup )
local ReportToAllSummary = MENU_GROUP_COMMAND:New( ScoringGroup, 'Summary report all players', Menu, SCORING.ReportScoreAllSummary, self, ScoringGroup ) local ReportToAllSummary = MENU_GROUP_COMMAND:New( ScoringGroup, 'Summary report all players', Menu, SCORING.ReportScoreAllSummary, self, ScoringGroup )
self:SetState( ScoringGroup, "ScoringMenu", Menu ) self:SetState( ScoringGroup, "ScoringMenu", Menu )
return self return self
end end
--- Add a new player entering a Unit. --- Add a new player entering a Unit.
-- @param #SCORING self -- @param #SCORING self
-- @param Wrapper.Unit#UNIT UnitData -- @param Wrapper.Unit#UNIT UnitData
@@ -647,15 +652,15 @@ function SCORING:_AddPlayerFromUnit( UnitData )
if not self.Players[PlayerName].UnitCoalition then if not self.Players[PlayerName].UnitCoalition then
self.Players[PlayerName].UnitCoalition = UnitCoalition self.Players[PlayerName].UnitCoalition = UnitCoalition
else else
if self.Players[PlayerName].UnitCoalition ~= UnitCoalition then -- TODO: switch for coalition changes, make penalty alterable
self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + 50 if self.Players[PlayerName].UnitCoalition ~= UnitCoalition and self.penaltyoncoalitionchange then
self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + self.CoalitionChangePenalty or 50
self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1 self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] .. MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] .. "(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). " ..
"(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). 50 Penalty points added.", self.CoalitionChangePenalty .. "Penalty points added.",
MESSAGE.Type.Information MESSAGE.Type.Information )
):ToAll() :ToAll()
self:ScoreCSV( PlayerName, "", "COALITION_PENALTY", 1, -50, self.Players[PlayerName].UnitName, _SCORINGCoalition[self.Players[PlayerName].UnitCoalition], _SCORINGCategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType, self:ScoreCSV( PlayerName, "", "COALITION_PENALTY", 1, -1 * self.CoalitionChangePenalty, self.Players[PlayerName].UnitName, _SCORINGCoalition[self.Players[PlayerName].UnitCoalition], _SCORINGCategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType, UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:GetTypeName() )
UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:GetTypeName() )
end end
end end
@@ -667,29 +672,25 @@ function SCORING:_AddPlayerFromUnit( UnitData )
self.Players[PlayerName].ThreatLevel = UnitThreatLevel self.Players[PlayerName].ThreatLevel = UnitThreatLevel
self.Players[PlayerName].ThreatType = UnitThreatType self.Players[PlayerName].ThreatType = UnitThreatType
-- TODO: DCS bug concerning Units with skill level client don't get destroyed in multi player. This logic is deactivated until this bug gets fixed. -- TODO: make fratricide switchable
--[[ if self.Players[PlayerName].Penalty > self.Fratricide * 0.50 and self.penaltyonfratricide then
if self.Players[PlayerName].Penalty > self.Fratricide * 0.50 then
if self.Players[PlayerName].PenaltyWarning < 1 then if self.Players[PlayerName].PenaltyWarning < 1 then
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than " .. self.Fratricide .. ", you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: " .. self.Players[PlayerName].Penalty, MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than " .. self.Fratricide .. ", you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: " .. self.Players[PlayerName].Penalty,
MESSAGE.Type.Information MESSAGE.Type.Information )
):ToAll() :ToAll()
self.Players[PlayerName].PenaltyWarning = self.Players[PlayerName].PenaltyWarning + 1 self.Players[PlayerName].PenaltyWarning = self.Players[PlayerName].PenaltyWarning + 1
end end
end end
if self.Players[PlayerName].Penalty > self.Fratricide then if self.Players[PlayerName].Penalty > self.Fratricide and self.penaltyonfratricide then
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' committed FRATRICIDE, he will be COURT MARTIALED and is DISMISSED from this mission!", MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' committed FRATRICIDE, he will be COURT MARTIALED and is DISMISSED from this mission!",
MESSAGE.Type.Information MESSAGE.Type.Information )
):ToAll() :ToAll()
UnitData:GetGroup():Destroy() UnitData:GetGroup():Destroy()
end end
--]]
end end
end end
--- Add a goal score for a player. --- Add a goal score for a player.
-- The method takes the Player name for which the Goal score needs to be set. -- The method takes the Player name for which the Goal score needs to be set.
-- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal. -- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal.
@@ -712,14 +713,14 @@ function SCORING:AddGoalScorePlayer( PlayerName, GoalTag, Text, Score )
PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score
PlayerData.Score = PlayerData.Score + Score PlayerData.Score = PlayerData.Score + Score
MESSAGE:NewType( self.DisplayMessagePrefix .. Text, MESSAGE.Type.Information ):ToAll() MESSAGE:NewType( self.DisplayMessagePrefix .. Text,
MESSAGE.Type.Information )
:ToAll()
self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, nil ) self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, nil )
end end
end end
--- Add a goal score for a player. --- Add a goal score for a player.
-- The method takes the PlayerUnit for which the Goal score needs to be set. -- The method takes the PlayerUnit for which the Goal score needs to be set.
-- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal. -- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal.
@@ -744,13 +745,14 @@ function SCORING:AddGoalScore( PlayerUnit, GoalTag, Text, Score )
PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score
PlayerData.Score = PlayerData.Score + Score PlayerData.Score = PlayerData.Score + Score
MESSAGE:NewType( self.DisplayMessagePrefix .. Text, MESSAGE.Type.Information ):ToAll() MESSAGE:NewType( self.DisplayMessagePrefix .. Text,
MESSAGE.Type.Information )
:ToAll()
self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, PlayerUnit:GetName() ) self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, PlayerUnit:GetName() )
end end
end end
--- Registers Scores the players completing a Mission Task. --- Registers Scores the players completing a Mission Task.
-- @param #SCORING self -- @param #SCORING self
-- @param Tasking.Mission#MISSION Mission -- @param Tasking.Mission#MISSION Mission
@@ -780,7 +782,9 @@ function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score )
PlayerData.Score = self.Players[PlayerName].Score + Score PlayerData.Score = self.Players[PlayerName].Score + Score
PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
MESSAGE:NewType( self.DisplayMessagePrefix .. Mission:GetText() .. " : " .. Text .. " Score: " .. Score, MESSAGE.Type.Information ):ToAll() MESSAGE:NewType( self.DisplayMessagePrefix .. Mission:GetText() .. " : " .. Text .. " Score: " .. Score,
MESSAGE.Type.Information )
:ToAll()
self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() ) self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() )
end end
@@ -841,26 +845,24 @@ function SCORING:_AddMissionScore( Mission, Text, Score )
PlayerData.Score = PlayerData.Score + Score PlayerData.Score = PlayerData.Score + Score
PlayerData.Mission[MissionName].ScoreMission = PlayerData.Mission[MissionName].ScoreMission + Score PlayerData.Mission[MissionName].ScoreMission = PlayerData.Mission[MissionName].ScoreMission + Score
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' has " .. Text .. " in " .. Mission:GetText() .. ". " .. MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' has " .. Text .. " in " .. Mission:GetText() .. ". " .. Score .. " mission score!",
Score .. " mission score!", MESSAGE.Type.Information )
MESSAGE.Type.Information ):ToAll() :ToAll()
self:ScoreCSV( PlayerName, "", "MISSION_" .. MissionName:gsub( ' ', '_' ), 1, Score ) self:ScoreCSV( PlayerName, "", "MISSION_" .. MissionName:gsub( ' ', '_' ), 1, Score )
end end
end end
end end
--- Handles the OnPlayerEnterUnit event for the scoring. --- Handles the OnPlayerEnterUnit event for the scoring.
-- @param #SCORING self -- @param #SCORING self
-- @param Core.Event#EVENTDATA Event -- @param Core.Event#EVENTDATA Event
--function SCORING:OnEventPlayerEnterUnit( Event ) -- function SCORING:OnEventPlayerEnterUnit( Event )
-- if Event.IniUnit then -- if Event.IniUnit then
-- self:_AddPlayerFromUnit( Event.IniUnit ) -- self:_AddPlayerFromUnit( Event.IniUnit )
-- self:SetScoringMenu( Event.IniGroup ) -- self:SetScoringMenu( Event.IniGroup )
-- end -- end
--end -- end
--- Handles the OnBirth event for the scoring. --- Handles the OnBirth event for the scoring.
-- @param #SCORING self -- @param #SCORING self
@@ -886,12 +888,11 @@ function SCORING:OnEventPlayerLeaveUnit( Event )
local Menu = self:GetState( Event.IniUnit:GetGroup(), "ScoringMenu" ) -- Core.Menu#MENU_GROUP local Menu = self:GetState( Event.IniUnit:GetGroup(), "ScoringMenu" ) -- Core.Menu#MENU_GROUP
if Menu then if Menu then
-- TODO: Check if this fixes #281. -- TODO: Check if this fixes #281.
--Menu:Remove() -- Menu:Remove()
end end
end end
end end
--- Handles the OnHit event for the scoring. --- Handles the OnHit event for the scoring.
-- @param #SCORING self -- @param #SCORING self
-- @param Core.Event#EVENTDATA Event -- @param Core.Event#EVENTDATA Event
@@ -936,9 +937,9 @@ function SCORING:_EventOnHit( Event )
InitPlayerName = Event.IniPlayerName InitPlayerName = Event.IniPlayerName
InitCoalition = Event.IniCoalition InitCoalition = Event.IniCoalition
--TODO: Workaround Client DCS Bug -- TODO: Workaround Client DCS Bug
--InitCategory = InitUnit:getCategory() -- InitCategory = InitUnit:getCategory()
--InitCategory = InitUnit:getDesc().category -- InitCategory = InitUnit:getDesc().category
InitCategory = Event.IniCategory InitCategory = Event.IniCategory
InitType = Event.IniTypeName InitType = Event.IniTypeName
@@ -946,10 +947,9 @@ function SCORING:_EventOnHit( Event )
InitUnitCategory = _SCORINGCategory[InitCategory] InitUnitCategory = _SCORINGCategory[InitCategory]
InitUnitType = InitType InitUnitType = InitType
self:T( { InitUnitName, InitGroupName, InitPlayerName, InitCoalition, InitCategory, InitType , InitUnitCoalition, InitUnitCategory, InitUnitType } ) self:T( { InitUnitName, InitGroupName, InitPlayerName, InitCoalition, InitCategory, InitType, InitUnitCoalition, InitUnitCategory, InitUnitType } )
end end
if Event.TgtDCSUnit then if Event.TgtDCSUnit then
TargetUnit = Event.TgtDCSUnit TargetUnit = Event.TgtDCSUnit
@@ -960,9 +960,9 @@ function SCORING:_EventOnHit( Event )
TargetPlayerName = Event.TgtPlayerName TargetPlayerName = Event.TgtPlayerName
TargetCoalition = Event.TgtCoalition TargetCoalition = Event.TgtCoalition
--TODO: Workaround Client DCS Bug -- TODO: Workaround Client DCS Bug
--TargetCategory = TargetUnit:getCategory() -- TargetCategory = TargetUnit:getCategory()
--TargetCategory = TargetUnit:getDesc().category -- TargetCategory = TargetUnit:getDesc().category
TargetCategory = Event.TgtCategory TargetCategory = Event.TgtCategory
TargetType = Event.TgtTypeName TargetType = Event.TgtTypeName
@@ -1023,23 +1023,17 @@ function SCORING:_EventOnHit( Event )
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1 PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1
if TargetPlayerName ~= nil then -- It is a player hitting another player ... if TargetPlayerName ~= nil then -- It is a player hitting another player ...
MESSAGE MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " ..
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly player '" .. TargetPlayerName .. "' " .. "Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " .. MESSAGE.Type.Update )
"Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty, :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
MESSAGE.Type.Update :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
)
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
else else
MESSAGE MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " ..
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly target " .. "Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " .. MESSAGE.Type.Update )
"Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty, :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
MESSAGE.Type.Update :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
)
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
end end
self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
else else
@@ -1047,33 +1041,26 @@ function SCORING:_EventOnHit( Event )
PlayerHit.Score = PlayerHit.Score + 1 PlayerHit.Score = PlayerHit.Score + 1
PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1 PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
if TargetPlayerName ~= nil then -- It is a player hitting another player ... if TargetPlayerName ~= nil then -- It is a player hitting another player ...
MESSAGE MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " ..
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy player '" .. TargetPlayerName .. "' " .. "Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " .. MESSAGE.Type.Update )
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty, :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
MESSAGE.Type.Update :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
)
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
else else
MESSAGE MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " ..
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " .. "Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " .. MESSAGE.Type.Update )
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty, :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
MESSAGE.Type.Update :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
)
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
end end
self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
end end
else -- A scenery object was hit. else -- A scenery object was hit.
MESSAGE MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit scenery object.",
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit scenery object.", MESSAGE.Type.Update )
MESSAGE.Type.Update :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
self:ScoreCSV( InitPlayerName, "", "HIT_SCORE", 1, 0, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, "", "Scenery", TargetUnitType ) self:ScoreCSV( InitPlayerName, "", "HIT_SCORE", 1, 0, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, "", "Scenery", TargetUnitType )
end end
end end
@@ -1125,40 +1112,35 @@ function SCORING:_EventOnHit( Event )
if InitCoalition then -- A coalition object was hit, probably a static. if InitCoalition then -- A coalition object was hit, probably a static.
if InitCoalition == TargetCoalition then if InitCoalition == TargetCoalition then
-- TODO: Penalty according scale -- TODO: Penalty according scale
Player.Penalty = Player.Penalty + 10 Player.Penalty = Player.Penalty + 10 -- * self.ScaleDestroyPenalty
PlayerHit.Penalty = PlayerHit.Penalty + 10 PlayerHit.Penalty = PlayerHit.Penalty + 10 -- * self.ScaleDestroyPenalty
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1 PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1 * self.ScaleDestroyPenalty
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
"Penalty: -" .. PlayerHit.Penalty .. " = " .. Player.Score - Player.Penalty,
MESSAGE.Type.Update )
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
MESSAGE
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " ..
TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
"Penalty: -" .. PlayerHit.Penalty .. " = " .. Player.Score - Player.Penalty,
MESSAGE.Type.Update
)
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
else else
Player.Score = Player.Score + 1 Player.Score = Player.Score + 1
PlayerHit.Score = PlayerHit.Score + 1 PlayerHit.Score = PlayerHit.Score + 1
PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1 PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
MESSAGE MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit enemy target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit enemy target " .. "Score: +" .. PlayerHit.Score .. " = " .. Player.Score - Player.Penalty,
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. MESSAGE.Type.Update )
"Score: +" .. PlayerHit.Score .. " = " .. Player.Score - Player.Penalty, :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
MESSAGE.Type.Update :ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
)
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
end end
else -- A scenery object was hit. else -- A scenery object was hit.
MESSAGE MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit scenery object.",
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit scenery object.", MESSAGE.Type.Update )
MESSAGE.Type.Update :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
) :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
self:ScoreCSV( Event.WeaponPlayerName, "", "HIT_SCORE", 1, 0, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, "", "Scenery", TargetUnitType ) self:ScoreCSV( Event.WeaponPlayerName, "", "HIT_SCORE", 1, 0, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, "", "Scenery", TargetUnitType )
end end
end end
@@ -1194,8 +1176,8 @@ function SCORING:_EventOnDeadOrCrash( Event )
TargetPlayerName = Event.IniPlayerName TargetPlayerName = Event.IniPlayerName
TargetCoalition = Event.IniCoalition TargetCoalition = Event.IniCoalition
--TargetCategory = TargetUnit:getCategory() -- TargetCategory = TargetUnit:getCategory()
--TargetCategory = TargetUnit:getDesc().category -- Workaround -- TargetCategory = TargetUnit:getDesc().category -- Workaround
TargetCategory = Event.IniCategory TargetCategory = Event.IniCategory
TargetType = Event.IniTypeName TargetType = Event.IniTypeName
@@ -1236,7 +1218,7 @@ function SCORING:_EventOnDeadOrCrash( Event )
local TargetDestroy = Player.Destroy[TargetCategory][TargetType] local TargetDestroy = Player.Destroy[TargetCategory][TargetType]
TargetDestroy.Score = TargetDestroy.Score or 0 TargetDestroy.Score = TargetDestroy.Score or 0
TargetDestroy.ScoreDestroy = TargetDestroy.ScoreDestroy or 0 TargetDestroy.ScoreDestroy = TargetDestroy.ScoreDestroy or 0
TargetDestroy.Penalty = TargetDestroy.Penalty or 0 TargetDestroy.Penalty = TargetDestroy.Penalty or 0
TargetDestroy.PenaltyDestroy = TargetDestroy.PenaltyDestroy or 0 TargetDestroy.PenaltyDestroy = TargetDestroy.PenaltyDestroy or 0
if TargetCoalition then if TargetCoalition then
@@ -1244,81 +1226,69 @@ function SCORING:_EventOnDeadOrCrash( Event )
local ThreatLevelTarget = TargetThreatLevel local ThreatLevelTarget = TargetThreatLevel
local ThreatTypeTarget = TargetThreatType local ThreatTypeTarget = TargetThreatType
local ThreatLevelPlayer = Player.ThreatLevel / 10 + 1 local ThreatLevelPlayer = Player.ThreatLevel / 10 + 1
local ThreatPenalty = math.ceil( ( ThreatLevelTarget / ThreatLevelPlayer ) * self.ScaleDestroyPenalty / 10 ) local ThreatPenalty = math.ceil( (ThreatLevelTarget / ThreatLevelPlayer) * self.ScaleDestroyPenalty / 10 )
self:F( { ThreatLevel = ThreatPenalty, ThreatLevelTarget = ThreatLevelTarget, ThreatTypeTarget = ThreatTypeTarget, ThreatLevelPlayer = ThreatLevelPlayer } ) self:F( { ThreatLevel = ThreatPenalty, ThreatLevelTarget = ThreatLevelTarget, ThreatTypeTarget = ThreatTypeTarget, ThreatLevelPlayer = ThreatLevelPlayer } )
Player.Penalty = Player.Penalty + ThreatPenalty Player.Penalty = Player.Penalty + ThreatPenalty
TargetDestroy.Penalty = TargetDestroy.Penalty + ThreatPenalty TargetDestroy.Penalty = TargetDestroy.Penalty + ThreatPenalty
TargetDestroy.PenaltyDestroy = TargetDestroy.PenaltyDestroy + 1 TargetDestroy.PenaltyDestroy = TargetDestroy.PenaltyDestroy + 1
if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player
MESSAGE MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " .. "Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty,
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. MESSAGE.Type.Information )
"Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty, :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
MESSAGE.Type.Information :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
)
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
else else
MESSAGE MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " .. "Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty,
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. MESSAGE.Type.Information )
"Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty, :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
MESSAGE.Type.Information :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
)
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
end end
Destroyed = true
self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_PENALTY", 1, ThreatPenalty, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_PENALTY", 1, ThreatPenalty, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
Destroyed = true
else else
local ThreatLevelTarget = TargetThreatLevel local ThreatLevelTarget = TargetThreatLevel
local ThreatTypeTarget = TargetThreatType local ThreatTypeTarget = TargetThreatType
local ThreatLevelPlayer = Player.ThreatLevel / 10 + 1 local ThreatLevelPlayer = Player.ThreatLevel / 10 + 1
local ThreatScore = math.ceil( ( ThreatLevelTarget / ThreatLevelPlayer ) * self.ScaleDestroyScore / 10 ) local ThreatScore = math.ceil( (ThreatLevelTarget / ThreatLevelPlayer) * self.ScaleDestroyScore / 10 )
self:F( { ThreatLevel = ThreatScore, ThreatLevelTarget = ThreatLevelTarget, ThreatTypeTarget = ThreatTypeTarget, ThreatLevelPlayer = ThreatLevelPlayer } ) self:F( { ThreatLevel = ThreatScore, ThreatLevelTarget = ThreatLevelTarget, ThreatTypeTarget = ThreatTypeTarget, ThreatLevelPlayer = ThreatLevelPlayer } )
Player.Score = Player.Score + ThreatScore Player.Score = Player.Score + ThreatScore
TargetDestroy.Score = TargetDestroy.Score + ThreatScore TargetDestroy.Score = TargetDestroy.Score + ThreatScore
TargetDestroy.ScoreDestroy = TargetDestroy.ScoreDestroy + 1 TargetDestroy.ScoreDestroy = TargetDestroy.ScoreDestroy + 1
if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player
MESSAGE MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " .. "Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty,
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. MESSAGE.Type.Information )
"Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty, :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
MESSAGE.Type.Information :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
)
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
else else
MESSAGE MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " .. "Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty,
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. MESSAGE.Type.Information )
"Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty, :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
MESSAGE.Type.Information :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
)
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
end end
Destroyed = true
self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, ThreatScore, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, ThreatScore, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
Destroyed = true
local UnitName = TargetUnit:GetName() local UnitName = TargetUnit:GetName()
local Score = self.ScoringObjects[UnitName] local Score = self.ScoringObjects[UnitName]
if Score then if Score then
Player.Score = Player.Score + Score Player.Score = Player.Score + Score
TargetDestroy.Score = TargetDestroy.Score + Score TargetDestroy.Score = TargetDestroy.Score + Score
MESSAGE MESSAGE:NewType( self.DisplayMessagePrefix .. "Special target '" .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. " destroyed! " ..
:NewType( self.DisplayMessagePrefix .. "Special target '" .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. " destroyed! " .. "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! Total: " .. Player.Score - Player.Penalty,
"Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! Total: " .. Player.Score - Player.Penalty, MESSAGE.Type.Information )
MESSAGE.Type.Information :ToAllIf( self:IfMessagesScore() and self:IfMessagesToAll() )
) :ToCoalitionIf( InitCoalition, self:IfMessagesScore() and self:IfMessagesToCoalition() )
:ToAllIf( self:IfMessagesScore() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesScore() and self:IfMessagesToCoalition() )
self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
Destroyed = true Destroyed = true
end end
@@ -1331,13 +1301,12 @@ function SCORING:_EventOnDeadOrCrash( Event )
if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then
Player.Score = Player.Score + Score Player.Score = Player.Score + Score
TargetDestroy.Score = TargetDestroy.Score + Score TargetDestroy.Score = TargetDestroy.Score + Score
MESSAGE MESSAGE:NewType( self.DisplayMessagePrefix .. "Target destroyed in zone '" .. ScoreZone:GetName() .. "'." ..
:NewType( self.DisplayMessagePrefix .. "Target destroyed in zone '" .. ScoreZone:GetName() .. "'." .. "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. "Total: " .. Player.Score - Player.Penalty,
"Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. MESSAGE.Type.Information )
"Total: " .. Player.Score - Player.Penalty, :ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() )
MESSAGE.Type.Information ) :ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() )
:ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() )
self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
Destroyed = true Destroyed = true
end end
@@ -1347,22 +1316,20 @@ function SCORING:_EventOnDeadOrCrash( Event )
else else
-- Check if there are Zones where the destruction happened. -- Check if there are Zones where the destruction happened.
for ZoneName, ScoreZoneData in pairs( self.ScoringZones ) do for ZoneName, ScoreZoneData in pairs( self.ScoringZones ) do
self:F( { ScoringZone = ScoreZoneData } ) self:F( { ScoringZone = ScoreZoneData } )
local ScoreZone = ScoreZoneData.ScoreZone -- Core.Zone#ZONE_BASE local ScoreZone = ScoreZoneData.ScoreZone -- Core.Zone#ZONE_BASE
local Score = ScoreZoneData.Score local Score = ScoreZoneData.Score
if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then
Player.Score = Player.Score + Score Player.Score = Player.Score + Score
TargetDestroy.Score = TargetDestroy.Score + Score TargetDestroy.Score = TargetDestroy.Score + Score
MESSAGE MESSAGE:NewType( self.DisplayMessagePrefix .. "Scenery destroyed in zone '" .. ScoreZone:GetName() .. "'." ..
:NewType( self.DisplayMessagePrefix .. "Scenery destroyed in zone '" .. ScoreZone:GetName() .. "'." .. "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. "Total: " .. Player.Score - Player.Penalty,
"Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. MESSAGE.Type.Information )
"Total: " .. Player.Score - Player.Penalty, :ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() )
MESSAGE.Type.Information :ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() )
)
:ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() )
Destroyed = true
self:ScoreCSV( PlayerName, "", "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, "", "Scenery", TargetUnitType ) self:ScoreCSV( PlayerName, "", "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, "", "Scenery", TargetUnitType )
Destroyed = true
end end
end end
end end
@@ -1378,7 +1345,6 @@ function SCORING:_EventOnDeadOrCrash( Event )
end end
end end
--- Produce detailed report of player hit scores. --- Produce detailed report of player hit scores.
-- @param #SCORING self -- @param #SCORING self
-- @param #string PlayerName The name of the player. -- @param #string PlayerName The name of the player.
@@ -1420,7 +1386,7 @@ function SCORING:ReportDetailedPlayerHits( PlayerName )
PlayerScore = PlayerScore + Score PlayerScore = PlayerScore + Score
PlayerPenalty = PlayerPenalty + Penalty PlayerPenalty = PlayerPenalty + Penalty
else else
--ScoreMessageHits = ScoreMessageHits .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) -- ScoreMessageHits = ScoreMessageHits .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 )
end end
end end
if ScoreMessageHits ~= "" then if ScoreMessageHits ~= "" then
@@ -1431,7 +1397,6 @@ function SCORING:ReportDetailedPlayerHits( PlayerName )
return ScoreMessage, PlayerScore, PlayerPenalty return ScoreMessage, PlayerScore, PlayerPenalty
end end
--- Produce detailed report of player destroy scores. --- Produce detailed report of player destroy scores.
-- @param #SCORING self -- @param #SCORING self
-- @param #string PlayerName The name of the player. -- @param #string PlayerName The name of the player.
@@ -1478,7 +1443,7 @@ function SCORING:ReportDetailedPlayerDestroys( PlayerName )
PlayerScore = PlayerScore + Score PlayerScore = PlayerScore + Score
PlayerPenalty = PlayerPenalty + Penalty PlayerPenalty = PlayerPenalty + Penalty
else else
--ScoreMessageDestroys = ScoreMessageDestroys .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) -- ScoreMessageDestroys = ScoreMessageDestroys .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 )
end end
end end
if ScoreMessageDestroys ~= "" then if ScoreMessageDestroys ~= "" then
@@ -1597,7 +1562,6 @@ function SCORING:ReportDetailedPlayerMissions( PlayerName )
return ScoreMessage, PlayerScore, PlayerPenalty return ScoreMessage, PlayerScore, PlayerPenalty
end end
--- Report Group Score Summary --- Report Group Score Summary
-- @param #SCORING self -- @param #SCORING self
-- @param Wrapper.Group#GROUP PlayerGroup The player group. -- @param Wrapper.Group#GROUP PlayerGroup The player group.
@@ -1637,13 +1601,12 @@ function SCORING:ReportScoreGroupSummary( PlayerGroup )
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + PenaltyGoals + PenaltyMissions local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + PenaltyGoals + PenaltyMissions
PlayerMessage = PlayerMessage = string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )",
string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )", PlayerName,
PlayerName, PlayerScore - PlayerPenalty,
PlayerScore - PlayerPenalty, PlayerScore,
PlayerScore, PlayerPenalty
PlayerPenalty )
)
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Detailed ):ToGroup( PlayerGroup ) MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Detailed ):ToGroup( PlayerGroup )
end end
end end
@@ -1687,20 +1650,19 @@ function SCORING:ReportScoreGroupDetailed( PlayerGroup )
self:F( { ReportMissions, ScoreMissions, PenaltyMissions } ) self:F( { ReportMissions, ScoreMissions, PenaltyMissions } )
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + PenaltyGoals + PenaltyMissions
PlayerMessage = PlayerMessage = string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )%s%s%s%s%s",
string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )%s%s%s%s%s", PlayerName,
PlayerName, PlayerScore - PlayerPenalty,
PlayerScore - PlayerPenalty, PlayerScore,
PlayerScore, PlayerPenalty,
PlayerPenalty, ReportHits,
ReportHits, ReportDestroys,
ReportDestroys, ReportCoalitionChanges,
ReportCoalitionChanges, ReportGoals,
ReportGoals, ReportMissions
ReportMissions )
)
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Detailed ):ToGroup( PlayerGroup ) MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Detailed ):ToGroup( PlayerGroup )
end end
end end
@@ -1743,32 +1705,30 @@ function SCORING:ReportScoreAllSummary( PlayerGroup )
self:F( { ReportMissions, ScoreMissions, PenaltyMissions } ) self:F( { ReportMissions, ScoreMissions, PenaltyMissions } )
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + PenaltyGoals + PenaltyMissions
PlayerMessage = PlayerMessage = string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )",
string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )", PlayerName,
PlayerName, PlayerScore - PlayerPenalty,
PlayerScore - PlayerPenalty, PlayerScore,
PlayerScore, PlayerPenalty
PlayerPenalty )
)
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Overview ):ToGroup( PlayerGroup ) MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Overview ):ToGroup( PlayerGroup )
end end
end end
end end
function SCORING:SecondsToClock( sSeconds )
function SCORING:SecondsToClock(sSeconds)
local nSeconds = sSeconds local nSeconds = sSeconds
if nSeconds == 0 then if nSeconds == 0 then
--return nil; -- return nil;
return "00:00:00"; return "00:00:00";
else else
nHours = string.format("%02.f", math.floor(nSeconds/3600)); nHours = string.format( "%02.f", math.floor( nSeconds / 3600 ) );
nMins = string.format("%02.f", math.floor(nSeconds/60 - (nHours*60))); nMins = string.format( "%02.f", math.floor( nSeconds / 60 - (nHours * 60) ) );
nSecs = string.format("%02.f", math.floor(nSeconds - nHours*3600 - nMins *60)); nSecs = string.format( "%02.f", math.floor( nSeconds - nHours * 3600 - nMins * 60 ) );
return nHours..":"..nMins..":"..nSecs return nHours .. ":" .. nMins .. ":" .. nSecs
end end
end end
@@ -1793,9 +1753,9 @@ function SCORING:OpenCSV( ScoringCSV )
error( "Error: Cannot open CSV file in " .. lfs.writedir() ) error( "Error: Cannot open CSV file in " .. lfs.writedir() )
end end
self.CSVFile:write( '"GameName","RunTime","Time","PlayerName","TargetPlayerName","ScoreType","PlayerUnitCoaltion","PlayerUnitCategory","PlayerUnitType","PlayerUnitName","TargetUnitCoalition","TargetUnitCategory","TargetUnitType","TargetUnitName","Times","Score"\n' ) self.CSVFile:write( '"GameName","RunTime","Time","PlayerName","TargetPlayerName","ScoreType","PlayerUnitCoalition","PlayerUnitCategory","PlayerUnitType","PlayerUnitName","TargetUnitCoalition","TargetUnitCategory","TargetUnitType","TargetUnitName","Times","Score"\n' )
self.RunTime = os.date("%y-%m-%d_%H-%M-%S") self.RunTime = os.date( "%y-%m-%d_%H-%M-%S" )
else else
error( "A string containing the CSV file name must be given." ) error( "A string containing the CSV file name must be given." )
end end
@@ -1805,7 +1765,6 @@ function SCORING:OpenCSV( ScoringCSV )
return self return self
end end
--- Registers a score for a player. --- Registers a score for a player.
-- @param #SCORING self -- @param #SCORING self
-- @param #string PlayerName The name of the player. -- @param #string PlayerName The name of the player.
@@ -1823,7 +1782,7 @@ end
-- @param #string TargetUnitType The type of the target unit. -- @param #string TargetUnitType The type of the target unit.
-- @return #SCORING self -- @return #SCORING self
function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes, ScoreAmount, PlayerUnitName, PlayerUnitCoalition, PlayerUnitCategory, PlayerUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes, ScoreAmount, PlayerUnitName, PlayerUnitCoalition, PlayerUnitCategory, PlayerUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
--write statistic information to file -- write statistic information to file
local ScoreTime = self:SecondsToClock( timer.getTime() ) local ScoreTime = self:SecondsToClock( timer.getTime() )
PlayerName = PlayerName:gsub( '"', '_' ) PlayerName = PlayerName:gsub( '"', '_' )
@@ -1835,7 +1794,7 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes,
if PlayerUnit then if PlayerUnit then
if not PlayerUnitCategory then if not PlayerUnitCategory then
--PlayerUnitCategory = SCORINGCategory[PlayerUnit:getCategory()] -- PlayerUnitCategory = SCORINGCategory[PlayerUnit:getCategory()]
PlayerUnitCategory = _SCORINGCategory[PlayerUnit:getDesc().category] PlayerUnitCategory = _SCORINGCategory[PlayerUnit:getDesc().category]
end end
@@ -1888,7 +1847,6 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes,
end end
end end
function SCORING:CloseCSV() function SCORING:CloseCSV()
if lfs and io and os then if lfs and io and os then
self.CSVFile:close() self.CSVFile:close()
+320 -128
View File
@@ -6,6 +6,8 @@
-- --
-- * When SAM sites are being fired upon, the SAMs will take evasive action will reposition themselves when possible. -- * When SAM sites are being fired upon, the SAMs will take evasive action will reposition themselves when possible.
-- * When SAM sites are being fired upon, the SAMs will take defensive action by shutting down their radars. -- * When SAM sites are being fired upon, the SAMs will take defensive action by shutting down their radars.
-- * SEAD calculates the time it takes for a HARM to reach the target - and will attempt to minimize the shut-down time.
-- * Detection and evasion of shots has a random component based on the skill level of the SAM groups.
-- --
-- === -- ===
-- --
@@ -17,7 +19,7 @@
-- --
-- ### Authors: **FlightControl**, **applevangelist** -- ### Authors: **FlightControl**, **applevangelist**
-- --
-- Last Update: Aug 2021 -- Last Update: Feb 2022
-- --
-- === -- ===
-- --
@@ -31,6 +33,10 @@
--- Make SAM sites execute evasive and defensive behaviour when being fired upon. --- Make SAM sites execute evasive and defensive behaviour when being fired upon.
-- --
-- This class is very easy to use. Just setup a SEAD object by using @{#SEAD.New}() and SAMs will evade and take defensive action when being fired upon. -- This class is very easy to use. Just setup a SEAD object by using @{#SEAD.New}() and SAMs will evade and take defensive action when being fired upon.
-- Once a HARM attack is detected, SEAD will shut down the radars of the attacked SAM site and take evasive action by moving the SAM
-- vehicles around (*if* they are drivable, that is). There's a component of randomness in detection and evasion, which is based on the
-- skill set of the SAM set (the higher the skill, the more likely). When a missile is fired from far away, the SAM will stay active for a
-- period of time to stay defensive, before it takes evasive actions.
-- --
-- # Constructor: -- # Constructor:
-- --
@@ -51,6 +57,9 @@ SEAD = {
SuppressedGroups = {}, SuppressedGroups = {},
EngagementRange = 75, -- default 75% engagement range Feature Request #1355 EngagementRange = 75, -- default 75% engagement range Feature Request #1355
Padding = 10, Padding = 10,
CallBack = nil,
UseCallBack = false,
debug = false,
} }
--- Missile enumerators --- Missile enumerators
@@ -68,6 +77,8 @@ SEAD = {
["X_25"] = "X_25", ["X_25"] = "X_25",
["X_31"] = "X_31", ["X_31"] = "X_31",
["Kh25"] = "Kh25", ["Kh25"] = "Kh25",
["BGM_109"] = "BGM_109",
["AGM_154"] = "AGM_154",
} }
--- Missile enumerators - from DCS ME and Wikipedia --- Missile enumerators - from DCS ME and Wikipedia
@@ -77,7 +88,7 @@ SEAD = {
["AGM_88"] = { 150, 3}, ["AGM_88"] = { 150, 3},
["AGM_45"] = { 12, 2}, ["AGM_45"] = { 12, 2},
["AGM_122"] = { 16.5, 2.3}, ["AGM_122"] = { 16.5, 2.3},
["AGM_84"] = { 280, 0.85}, ["AGM_84"] = { 280, 0.8},
["ALARM"] = { 45, 2}, ["ALARM"] = { 45, 2},
["LD-10"] = { 60, 4}, ["LD-10"] = { 60, 4},
["X_58"] = { 70, 4}, ["X_58"] = { 70, 4},
@@ -85,6 +96,8 @@ SEAD = {
["X_25"] = { 25, 0.76}, ["X_25"] = { 25, 0.76},
["X_31"] = {150, 3}, ["X_31"] = {150, 3},
["Kh25"] = {25, 0.8}, ["Kh25"] = {25, 0.8},
["BGM_109"] = {460, 0.705}, --in-game ~465kn
["AGM_154"] = {130, 0.61},
} }
--- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles. --- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles.
@@ -93,15 +106,15 @@ SEAD = {
-- @param #SEAD self -- @param #SEAD self
-- @param #table SEADGroupPrefixes Table of #string entries or single #string, which is a table of Prefixes of the SA Groups in the DCS mission editor on which evasive actions need to be taken. -- @param #table SEADGroupPrefixes Table of #string entries or single #string, which is a table of Prefixes of the SA Groups in the DCS mission editor on which evasive actions need to be taken.
-- @param #number Padding (Optional) Extra number of seconds to add to radar switch-back-on time -- @param #number Padding (Optional) Extra number of seconds to add to radar switch-back-on time
-- @return SEAD -- @return #SEAD self
-- @usage -- @usage
-- -- CCCP SEAD Defenses -- -- CCCP SEAD Defenses
-- -- Defends the Russian SA installations from SEAD attacks. -- -- Defends the Russian SA installations from SEAD attacks.
-- SEAD_RU_SAM_Defenses = SEAD:New( { 'RU SA-6 Kub', 'RU SA-6 Defenses', 'RU MI-26 Troops', 'RU Attack Gori' } ) -- SEAD_RU_SAM_Defenses = SEAD:New( { 'RU SA-6 Kub', 'RU SA-6 Defenses', 'RU MI-26 Troops', 'RU Attack Gori' } )
function SEAD:New( SEADGroupPrefixes, Padding ) function SEAD:New( SEADGroupPrefixes, Padding )
local self = BASE:Inherit( self, BASE:New() ) local self = BASE:Inherit( self, FSM:New() )
self:F( SEADGroupPrefixes ) self:T( SEADGroupPrefixes )
if type( SEADGroupPrefixes ) == 'table' then if type( SEADGroupPrefixes ) == 'table' then
for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do
@@ -114,14 +127,25 @@ function SEAD:New( SEADGroupPrefixes, Padding )
local padding = Padding or 10 local padding = Padding or 10
if padding < 10 then padding = 10 end if padding < 10 then padding = 10 end
self.Padding = padding self.Padding = padding
self.UseEmissionsOnOff = true
self.debug = false
self.CallBack = nil
self.UseCallBack = false
self:HandleEvent( EVENTS.Shot, self.HandleEventShot ) self:HandleEvent( EVENTS.Shot, self.HandleEventShot )
self:I("*** SEAD - Started Version 0.3.1") -- Start State.
self:SetStartState("Running")
self:AddTransition("*", "ManageEvasion", "*")
self:AddTransition("*", "CalculateHitZone", "*")
self:I("*** SEAD - Started Version 0.4.3")
return self return self
end end
--- Update the active SEAD Set --- Update the active SEAD Set (while running)
-- @param #SEAD self -- @param #SEAD self
-- @param #table SEADGroupPrefixes The prefixes to add, note: can also be a single #string -- @param #table SEADGroupPrefixes The prefixes to add, note: can also be a single #string
-- @return #SEAD self -- @return #SEAD self
@@ -142,8 +166,8 @@ end
--- Sets the engagement range of the SAMs. Defaults to 75% to make it more deadly. Feature Request #1355 --- Sets the engagement range of the SAMs. Defaults to 75% to make it more deadly. Feature Request #1355
-- @param #SEAD self -- @param #SEAD self
-- @param #number range Set the engagement range in percent, e.g. 50 -- @param #number range Set the engagement range in percent, e.g. 55 (default 75)
-- @return self -- @return #SEAD self
function SEAD:SetEngagementRange(range) function SEAD:SetEngagementRange(range)
self:T( { range } ) self:T( { range } )
range = range or 75 range = range or 75
@@ -157,7 +181,8 @@ end
--- Set the padding in seconds, which extends the radar off time calculated by SEAD --- Set the padding in seconds, which extends the radar off time calculated by SEAD
-- @param #SEAD self -- @param #SEAD self
-- @param #number Padding Extra number of seconds to add for the switch-on -- @param #number Padding Extra number of seconds to add for the switch-on (default 10 seconds)
-- @return #SEAD self
function SEAD:SetPadding(Padding) function SEAD:SetPadding(Padding)
self:T( { Padding } ) self:T( { Padding } )
local padding = Padding or 10 local padding = Padding or 10
@@ -166,59 +191,264 @@ function SEAD:SetPadding(Padding)
return self return self
end end
--- Check if a known HARM was fired --- Set SEAD to use emissions on/off in addition to alarm state.
-- @param #SEAD self -- @param #SEAD self
-- @param #string WeaponName -- @param #boolean Switch True for on, false for off.
-- @return #boolean Returns true for a match -- @return #SEAD self
-- @return #string name Name of hit in table function SEAD:SwitchEmissions(Switch)
function SEAD:_CheckHarms(WeaponName) self:T({Switch})
self:T( { WeaponName } ) self.UseEmissionsOnOff = Switch
local hit = false return self
local name = "" end
for _,_name in pairs (SEAD.Harms) do
if string.find(WeaponName,_name,1) then
hit = true
name = _name
break
end
end
return hit, name
end
--- (Internal) Return distance in meters between two coordinates or -1 on error. --- Add an object to call back when going evasive.
-- @param #SEAD self -- @param #SEAD self
-- @param Core.Point#COORDINATE _point1 Coordinate one -- @param #table Object The object to call. Needs to have object functions as follows:
-- @param Core.Point#COORDINATE _point2 Coordinate two -- `:SeadSuppressionPlanned(Group, Name, SuppressionStartTime, SuppressionEndTime)`
-- @return #number Distance in meters -- `:SeadSuppressionStart(Group, Name)`,
function SEAD:_GetDistance(_point1, _point2) -- `:SeadSuppressionEnd(Group, Name)`,
self:T("_GetDistance") -- @return #SEAD self
if _point1 and _point2 then function SEAD:AddCallBack(Object)
local distance1 = _point1:Get2DDistance(_point2) self:T({Class=Object.ClassName})
local distance2 = _point1:DistanceFromPointVec2(_point2) self.CallBack = Object
--self:T({dist1=distance1, dist2=distance2}) self.UseCallBack = true
if distance1 and type(distance1) == "number" then return self
return distance1 end
elseif distance2 and type(distance2) == "number" then
return distance2 --- (Internal) Check if a known HARM was fired
else -- @param #SEAD self
self:E("*****Cannot calculate distance!") -- @param #string WeaponName
self:E({_point1,_point2}) -- @return #boolean Returns true for a match
return -1 -- @return #string name Name of hit in table
function SEAD:_CheckHarms(WeaponName)
self:T( { WeaponName } )
local hit = false
local name = ""
for _,_name in pairs (SEAD.Harms) do
if string.find(WeaponName,_name,1,true) then
hit = true
name = _name
break
end end
end
return hit, name
end
--- (Internal) Return distance in meters between two coordinates or -1 on error.
-- @param #SEAD self
-- @param Core.Point#COORDINATE _point1 Coordinate one
-- @param Core.Point#COORDINATE _point2 Coordinate two
-- @return #number Distance in meters
function SEAD:_GetDistance(_point1, _point2)
self:T("_GetDistance")
if _point1 and _point2 then
local distance1 = _point1:Get2DDistance(_point2)
local distance2 = _point1:DistanceFromPointVec2(_point2)
--self:T({dist1=distance1, dist2=distance2})
if distance1 and type(distance1) == "number" then
return distance1
elseif distance2 and type(distance2) == "number" then
return distance2
else else
self:E("******Cannot calculate distance!") self:E("*****Cannot calculate distance!")
self:E({_point1,_point2}) self:E({_point1,_point2})
return -1 return -1
end end
else
self:E("******Cannot calculate distance!")
self:E({_point1,_point2})
return -1
end end
end
--- Detects if an SAM site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME. --- (Internal) Calculate hit zone of an AGM-88
-- @see SEAD -- @param #SEAD self
-- @param #SEAD -- @param #table SEADWeapon DCS.Weapon object
-- @param Core.Point#COORDINATE pos0 Position of the plane when it fired
-- @param #number height Height when the missile was fired
-- @param Wrapper.Group#GROUP SEADGroup Attacker group
-- @param #string SEADWeaponName Weapon Name
-- @return #SEAD self
function SEAD:onafterCalculateHitZone(From,Event,To,SEADWeapon,pos0,height,SEADGroup,SEADWeaponName)
self:T("**** Calculating hit zone for " .. (SEADWeaponName or "None"))
if SEADWeapon and SEADWeapon:isExist() then
--local pos = SEADWeapon:getPoint()
-- postion and height
local position = SEADWeapon:getPosition()
local mheight = height
-- heading
local wph = math.atan2(position.x.z, position.x.x)
if wph < 0 then
wph=wph+2*math.pi
end
wph=math.deg(wph)
-- velocity
local wpndata = SEAD.HarmData["AGM_88"]
if string.find(SEADWeaponName,"154",1) then
wpndata = SEAD.HarmData["AGM_154"]
end
local mveloc = math.floor(wpndata[2] * 340.29)
local c1 = (2*mheight*9.81)/(mveloc^2)
local c2 = (mveloc^2) / 9.81
local Ropt = c2 * math.sqrt(c1+1)
if height <= 5000 then
Ropt = Ropt * 0.72
elseif height <= 7500 then
Ropt = Ropt * 0.82
elseif height <= 10000 then
Ropt = Ropt * 0.87
elseif height <= 12500 then
Ropt = Ropt * 0.98
end
-- look at a couple of zones across the trajectory
for n=1,3 do
local dist = Ropt - ((n-1)*20000)
local predpos= pos0:Translate(dist,wph)
if predpos then
local targetzone = ZONE_RADIUS:New("Target Zone",predpos:GetVec2(),20000)
if self.debug then
predpos:MarkToAll(string.format("height=%dm | heading=%d | velocity=%ddeg | Ropt=%dm",mheight,wph,mveloc,Ropt),false)
targetzone:DrawZone(coalition.side.BLUE,{0,0,1},0.2,nil,nil,3,true)
end
local seadset = SET_GROUP:New():FilterPrefixes(self.SEADGroupPrefixes):FilterZones({targetzone}):FilterOnce()
local tgtcoord = targetzone:GetRandomPointVec2()
--if tgtcoord and tgtcoord.ClassName == "COORDINATE" then
--local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord)
local tgtgrp = seadset:GetRandom()
local _targetgroup = nil
local _targetgroupname = "none"
local _targetskill = "Random"
if tgtgrp and tgtgrp:IsAlive() then
_targetgroup = tgtgrp
_targetgroupname = tgtgrp:GetName() -- group name
_targetskill = tgtgrp:GetUnit(1):GetSkill()
self:T("*** Found Target = ".. _targetgroupname)
self:ManageEvasion(_targetskill,_targetgroup,pos0,"AGM_88",SEADGroup, 20)
end
--end
end
end
end
return self
end
--- (Internal) Handle Evasion
-- @param #SEAD self
-- @param #string _targetskill
-- @param Wrapper.Group#GROUP _targetgroup
-- @param Core.Point#COORDINATE SEADPlanePos
-- @param #string SEADWeaponName
-- @param Wrapper.Group#GROUP SEADGroup Attacker Group
-- @param #number timeoffset Offset for tti calc
-- @return #SEAD self
function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,timeoffset)
local timeoffset = timeoffset or 0
if _targetskill == "Random" then -- when skill is random, choose a skill
local Skills = { "Average", "Good", "High", "Excellent" }
_targetskill = Skills[ math.random(1,4) ]
end
--self:T( _targetskill )
if self.TargetSkill[_targetskill] then
local _evade = math.random (1,100) -- random number for chance of evading action
if (_evade > self.TargetSkill[_targetskill].Evade) then
self:T("*** SEAD - Evading")
-- calculate distance of attacker
local _targetpos = _targetgroup:GetCoordinate()
local _distance = self:_GetDistance(SEADPlanePos, _targetpos)
-- weapon speed
local hit, data = self:_CheckHarms(SEADWeaponName)
local wpnspeed = 666 -- ;)
local reach = 10
if hit then
local wpndata = SEAD.HarmData[data]
reach = wpndata[1] * 1,1
local mach = wpndata[2]
wpnspeed = math.floor(mach * 340.29)
end
-- time to impact
local _tti = math.floor(_distance / wpnspeed) - timeoffset -- estimated impact time
if _distance > 0 then
_distance = math.floor(_distance / 1000) -- km
else
_distance = 0
end
self:T( string.format("*** SEAD - target skill %s, distance %dkm, reach %dkm, tti %dsec", _targetskill, _distance,reach,_tti ))
if reach >= _distance then
self:T("*** SEAD - Shot in Reach")
local function SuppressionStart(args)
self:T(string.format("*** SEAD - %s Radar Off & Relocating",args[2]))
local grp = args[1] -- Wrapper.Group#GROUP
local name = args[2] -- #string Group Name
local attacker = args[3] -- Wrapper.Group#GROUP
if self.UseEmissionsOnOff then
grp:EnableEmission(false)
end
grp:OptionAlarmStateGreen() -- needed else we cannot move around
grp:RelocateGroundRandomInRadius(20,300,false,false,"Diamond")
if self.UseCallBack then
local object = self.CallBack
object:SeadSuppressionStart(grp,name,attacker)
end
end
local function SuppressionStop(args)
self:T(string.format("*** SEAD - %s Radar On",args[2]))
local grp = args[1] -- Wrapper.Group#GROUP
local name = args[2] -- #string Group Nam
if self.UseEmissionsOnOff then
grp:EnableEmission(true)
end
grp:OptionAlarmStateRed()
grp:OptionEngageRange(self.EngagementRange)
self.SuppressedGroups[name] = false
if self.UseCallBack then
local object = self.CallBack
object:SeadSuppressionEnd(grp,name)
end
end
-- randomize switch-on time
local delay = math.random(self.TargetSkill[_targetskill].DelayOn[1], self.TargetSkill[_targetskill].DelayOn[2])
if delay > _tti then delay = delay / 2 end -- speed up
if _tti > 600 then delay = _tti - 90 end -- shot from afar, 600 is default shorad ontime
local SuppressionStartTime = timer.getTime() + delay
local SuppressionEndTime = timer.getTime() + _tti + self.Padding
local _targetgroupname = _targetgroup:GetName()
if not self.SuppressedGroups[_targetgroupname] then
self:T(string.format("*** SEAD - %s | Parameters TTI %ds | Switch-Off in %ds",_targetgroupname,_tti,delay))
timer.scheduleFunction(SuppressionStart,{_targetgroup,_targetgroupname, SEADGroup},SuppressionStartTime)
timer.scheduleFunction(SuppressionStop,{_targetgroup,_targetgroupname},SuppressionEndTime)
self.SuppressedGroups[_targetgroupname] = true
if self.UseCallBack then
local object = self.CallBack
object:SeadSuppressionPlanned(_targetgroup,_targetgroupname,SuppressionStartTime,SuppressionEndTime, SEADGroup)
end
end
end
end
end
return self
end
--- (Internal) Detects if an SAM site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME.
-- @param #SEAD self
-- @param Core.Event#EVENTDATA EventData -- @param Core.Event#EVENTDATA EventData
-- @return #SEAD self
function SEAD:HandleEventShot( EventData ) function SEAD:HandleEventShot( EventData )
self:T( { EventData.id } ) self:T( { EventData.id } )
local SEADPlane = EventData.IniUnit -- Wrapper.Unit#UNIT local SEADPlane = EventData.IniUnit -- Wrapper.Unit#UNIT
local SEADGroup = EventData.IniGroup -- Wrapper.Group#GROUP
local SEADPlanePos = SEADPlane:GetCoordinate() -- Core.Point#COORDINATE local SEADPlanePos = SEADPlane:GetCoordinate() -- Core.Point#COORDINATE
local SEADUnit = EventData.IniDCSUnit local SEADUnit = EventData.IniDCSUnit
local SEADUnitName = EventData.IniDCSUnitName local SEADUnitName = EventData.IniDCSUnitName
@@ -233,94 +463,56 @@ function SEAD:HandleEventShot( EventData )
local _targetskill = "Random" local _targetskill = "Random"
local _targetgroupname = "none" local _targetgroupname = "none"
local _target = EventData.Weapon:getTarget() -- Identify target local _target = EventData.Weapon:getTarget() -- Identify target
local _targetUnit = UNIT:Find(_target) -- Wrapper.Unit#UNIT if not _target or self.debug then -- AGM-88 or 154 w/o target data
self:E("***** SEAD - No target data for " .. (SEADWeaponName or "None"))
if string.find(SEADWeaponName,"AGM_88",1,true) or string.find(SEADWeaponName,"AGM_154",1,true) then
self:I("**** Tracking AGM-88/154 with no target data.")
local pos0 = SEADPlane:GetCoordinate()
local fheight = SEADPlane:GetHeight()
self:__CalculateHitZone(20,SEADWeapon,pos0,fheight,SEADGroup,SEADWeaponName)
end
return self
end
local targetcat = _target:getCategory() -- Identify category
local _targetUnit = nil -- Wrapper.Unit#UNIT
local _targetgroup = nil -- Wrapper.Group#GROUP local _targetgroup = nil -- Wrapper.Group#GROUP
if _targetUnit and _targetUnit:IsAlive() then self:T(string.format("*** Targetcat = %d",targetcat))
_targetgroup = _targetUnit:GetGroup() if targetcat == Object.Category.UNIT then -- UNIT
_targetgroupname = _targetgroup:GetName() -- group name self:T("*** Target Category UNIT")
local _targetUnitName = _targetUnit:GetName() _targetUnit = UNIT:Find(_target) -- Wrapper.Unit#UNIT
_targetUnit:GetSkill() if _targetUnit and _targetUnit:IsAlive() then
_targetskill = _targetUnit:GetSkill() _targetgroup = _targetUnit:GetGroup()
_targetgroupname = _targetgroup:GetName() -- group name
local _targetUnitName = _targetUnit:GetName()
_targetUnit:GetSkill()
_targetskill = _targetUnit:GetSkill()
end
elseif targetcat == Object.Category.STATIC then
self:T("*** Target Category STATIC")
local seadset = SET_GROUP:New():FilterPrefixes(self.SEADGroupPrefixes):FilterOnce()
local targetpoint = _target:getPoint() or {x=0,y=0,z=0}
local tgtcoord = COORDINATE:NewFromVec3(targetpoint)
local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord)
if tgtgrp and tgtgrp:IsAlive() then
_targetgroup = tgtgrp
_targetgroupname = tgtgrp:GetName() -- group name
_targetskill = tgtgrp:GetUnit(1):GetSkill()
self:T("*** Found Target = ".. _targetgroupname)
end
end end
-- see if we are shot at -- see if we are shot at
local SEADGroupFound = false local SEADGroupFound = false
for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do
self:T( SEADGroupPrefix ) self:T("Target = ".. _targetgroupname .. " | Prefix = " .. SEADGroupPrefix )
if string.find( _targetgroupname, SEADGroupPrefix, 1, true ) then if string.find( _targetgroupname, SEADGroupPrefix,1,true ) then
SEADGroupFound = true SEADGroupFound = true
self:T( '*** SEAD - Group Match Found' ) self:T( '*** SEAD - Group Match Found' )
break break
end end
end end
if SEADGroupFound == true then -- yes we are being attacked if SEADGroupFound == true then -- yes we are being attacked
if _targetskill == "Random" then -- when skill is random, choose a skill self:ManageEvasion(_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup)
local Skills = { "Average", "Good", "High", "Excellent" }
_targetskill = Skills[ math.random(1,4) ]
end
--self:T( _targetskill )
if self.TargetSkill[_targetskill] then
local _evade = math.random (1,100) -- random number for chance of evading action
if (_evade > self.TargetSkill[_targetskill].Evade) then
self:T("*** SEAD - Evading")
-- calculate distance of attacker
local _targetpos = _targetgroup:GetCoordinate()
local _distance = self:_GetDistance(SEADPlanePos, _targetpos)
-- weapon speed
local hit, data = self:_CheckHarms(SEADWeaponName)
local wpnspeed = 666 -- ;)
local reach = 10
if hit then
local wpndata = SEAD.HarmData[data]
reach = wpndata[1] * 1,1
local mach = wpndata[2]
wpnspeed = math.floor(mach * 340.29)
end
-- time to impact
local _tti = math.floor(_distance / wpnspeed) -- estimated impact time
if _distance > 0 then
_distance = math.floor(_distance / 1000) -- km
else
_distance = 0
end
self:T( string.format("*** SEAD - target skill %s, distance %dkm, reach %dkm, tti %dsec", _targetskill, _distance,reach,_tti ))
if reach >= _distance then
self:T("*** SEAD - Shot in Reach")
local function SuppressionStart(args)
self:T(string.format("*** SEAD - %s Radar Off & Relocating",args[2]))
local grp = args[1] -- Wrapper.Group#GROUP
grp:OptionAlarmStateGreen()
grp:RelocateGroundRandomInRadius(20,300,false,false,"Diamond")
end
local function SuppressionStop(args)
self:T(string.format("*** SEAD - %s Radar On",args[2]))
local grp = args[1] -- Wrapper.Group#GROUP
grp:OptionAlarmStateRed()
grp:OptionEngageRange(self.EngagementRange)
self.SuppressedGroups[args[2]] = false
end
-- randomize switch-on time
local delay = math.random(self.TargetSkill[_targetskill].DelayOn[1], self.TargetSkill[_targetskill].DelayOn[2])
if delay > _tti then delay = delay / 2 end -- speed up
if _tti > (3*delay) then delay = (_tti / 2) * 0.9 end -- shot from afar
local SuppressionStartTime = timer.getTime() + delay
local SuppressionEndTime = timer.getTime() + _tti + self.Padding
if not self.SuppressedGroups[_targetgroupname] then
self:T(string.format("*** SEAD - %s | Parameters TTI %ds | Switch-Off in %ds",_targetgroupname,_tti,delay))
timer.scheduleFunction(SuppressionStart,{_targetgroup,_targetgroupname},SuppressionStartTime)
timer.scheduleFunction(SuppressionStop,{_targetgroup,_targetgroupname},SuppressionEndTime)
self.SuppressedGroups[_targetgroupname] = true
end
end
end
end
end end
end end
return self
end end
@@ -50,7 +50,7 @@
-- @field #boolean Report If true, send status messages to coalition. -- @field #boolean Report If true, send status messages to coalition.
-- @field Wrapper.Static#STATIC warehouse The phyical warehouse structure. -- @field Wrapper.Static#STATIC warehouse The phyical warehouse structure.
-- @field #string alias Alias of the warehouse. Name its called when sending messages. -- @field #string alias Alias of the warehouse. Name its called when sending messages.
-- @field Core.Zone#ZONE zone Zone around the warehouse. If this zone is captured, the warehouse and all its assets goes to the capturing coaliton. -- @field Core.Zone#ZONE zone Zone around the warehouse. If this zone is captured, the warehouse and all its assets goes to the capturing coalition.
-- @field Wrapper.Airbase#AIRBASE airbase Airbase the warehouse belongs to. -- @field Wrapper.Airbase#AIRBASE airbase Airbase the warehouse belongs to.
-- @field #string airbasename Name of the airbase associated to the warehouse. -- @field #string airbasename Name of the airbase associated to the warehouse.
-- @field Core.Point#COORDINATE road Closest point to warehouse on road. -- @field Core.Point#COORDINATE road Closest point to warehouse on road.
@@ -764,7 +764,7 @@
-- warehouseBatumi:Load("D:\\My Warehouse Data\\") -- warehouseBatumi:Load("D:\\My Warehouse Data\\")
-- warehouseBatumi:Start() -- warehouseBatumi:Start()
-- --
-- This sequence loads all assets from file. If a warehouse was captured in the last mission, it also respawns the static warehouse structure with the right coaliton. -- This sequence loads all assets from file. If a warehouse was captured in the last mission, it also respawns the static warehouse structure with the right coalition.
-- However, it due to DCS limitations it is not possible to set the airbase coalition. This has to be done manually in the mission editor. Or alternatively, one could -- However, it due to DCS limitations it is not possible to set the airbase coalition. This has to be done manually in the mission editor. Or alternatively, one could
-- spawn some ground units via a self request and let them capture the airbase. -- spawn some ground units via a self request and let them capture the airbase.
-- --
@@ -1601,7 +1601,7 @@ WAREHOUSE = {
-- @field #number range Range of the unit in meters. -- @field #number range Range of the unit in meters.
-- @field #number speedmax Maximum speed in km/h the group can do. -- @field #number speedmax Maximum speed in km/h the group can do.
-- @field #number size Maximum size in length and with of the asset in meters. -- @field #number size Maximum size in length and with of the asset in meters.
-- @field #number weight The weight of the whole asset group in kilo gramms. -- @field #number weight The weight of the whole asset group in kilograms.
-- @field DCS#Object.Desc DCSdesc All DCS descriptors. -- @field DCS#Object.Desc DCSdesc All DCS descriptors.
-- @field #WAREHOUSE.Attribute attribute Generalized attribute of the group. -- @field #WAREHOUSE.Attribute attribute Generalized attribute of the group.
-- @field #table cargobay Array of cargo bays of all units in an asset group. -- @field #table cargobay Array of cargo bays of all units in an asset group.
@@ -1811,7 +1811,7 @@ WAREHOUSE.version="1.0.2"
-- DONE: Add shipping lanes between warehouses. -- DONE: Add shipping lanes between warehouses.
-- DONE: Handle cases with immobile units <== should be handled by dispatcher classes. -- DONE: Handle cases with immobile units <== should be handled by dispatcher classes.
-- DONE: Handle cases for aircraft carriers and other ships. Place warehouse on carrier possible? On others probably not - exclude them? -- DONE: Handle cases for aircraft carriers and other ships. Place warehouse on carrier possible? On others probably not - exclude them?
-- DONE: Add general message function for sending to coaliton or debug. -- DONE: Add general message function for sending to coalition or debug.
-- DONE: Fine tune event handlers. -- DONE: Fine tune event handlers.
-- DONE: Improve generalized attributes. -- DONE: Improve generalized attributes.
-- DONE: If warehouse is destroyed, all asssets are gone. -- DONE: If warehouse is destroyed, all asssets are gone.
@@ -3155,7 +3155,7 @@ end
-- @param MinAssets (Optional) Minimum number of assets the warehouse should have. Default 0. -- @param MinAssets (Optional) Minimum number of assets the warehouse should have. Default 0.
-- @param #string Descriptor (Optional) Descriptor describing the selected assets which should be in stock. See @{#WAREHOUSE.Descriptor} for possible values. -- @param #string Descriptor (Optional) Descriptor describing the selected assets which should be in stock. See @{#WAREHOUSE.Descriptor} for possible values.
-- @param DescriptorValue (Optional) Descriptor value selecting the type of assets which should be in stock. -- @param DescriptorValue (Optional) Descriptor value selecting the type of assets which should be in stock.
-- @param DCS#Coalition.side Coalition (Optional) Coalition side of the warehouse. Default is the same coaliton as the present warehouse. Set to false for any coalition. -- @param DCS#Coalition.side Coalition (Optional) Coalition side of the warehouse. Default is the same coalition as the present warehouse. Set to false for any coalition.
-- @param Core.Point#COORDINATE RefCoordinate (Optional) Coordinate to which the closest warehouse is searched. Default is the warehouse calling this function. -- @param Core.Point#COORDINATE RefCoordinate (Optional) Coordinate to which the closest warehouse is searched. Default is the warehouse calling this function.
-- @return #WAREHOUSE The the nearest warehouse object. Or nil if no warehouse is found. -- @return #WAREHOUSE The the nearest warehouse object. Or nil if no warehouse is found.
-- @return #number The distance to the nearest warehouse in meters. Or nil if no warehouse is found. -- @return #number The distance to the nearest warehouse in meters. Or nil if no warehouse is found.
@@ -3267,7 +3267,7 @@ function WAREHOUSE:onafterStart(From, Event, To)
-- Short info. -- Short info.
local text=string.format("Starting warehouse %s alias %s:\n",self.warehouse:GetName(), self.alias) local text=string.format("Starting warehouse %s alias %s:\n",self.warehouse:GetName(), self.alias)
text=text..string.format("Coaliton = %s\n", self:GetCoalitionName()) text=text..string.format("Coalition = %s\n", self:GetCoalitionName())
text=text..string.format("Country = %s\n", self:GetCountryName()) text=text..string.format("Country = %s\n", self:GetCountryName())
text=text..string.format("Airbase = %s (category=%d)\n", self:GetAirbaseName(), self:GetAirbaseCategory()) text=text..string.format("Airbase = %s (category=%d)\n", self:GetAirbaseName(), self:GetAirbaseCategory())
env.info(text) env.info(text)
@@ -8460,7 +8460,7 @@ function WAREHOUSE:_GetStockAssetsText(messagetoall)
end end
--- Create or update mark text at warehouse, which is displayed in F10 map showing how many assets of each type are in stock. --- Create or update mark text at warehouse, which is displayed in F10 map showing how many assets of each type are in stock.
-- Only the coaliton of the warehouse owner is able to see it. -- Only the coalition of the warehouse owner is able to see it.
-- @param #WAREHOUSE self -- @param #WAREHOUSE self
-- @return #string Text about warehouse stock -- @return #string Text about warehouse stock
function WAREHOUSE:_UpdateWarehouseMarkText() function WAREHOUSE:_UpdateWarehouseMarkText()
@@ -804,7 +804,7 @@ do -- ZONE_CAPTURE_COALITION
return IsEmpty return IsEmpty
end end
--- Check if zone is "Guarded", i.e. only one (the defending) coaliton is present inside the zone. --- Check if zone is "Guarded", i.e. only one (the defending) coalition is present inside the zone.
-- @param #ZONE_CAPTURE_COALITION self -- @param #ZONE_CAPTURE_COALITION self
-- @return #boolean self:IsAllInZoneOfCoalition( self.Coalition ) -- @return #boolean self:IsAllInZoneOfCoalition( self.Coalition )
function ZONE_CAPTURE_COALITION:IsGuarded() function ZONE_CAPTURE_COALITION:IsGuarded()
@@ -826,7 +826,7 @@ do -- ZONE_CAPTURE_COALITION
return IsCaptured return IsCaptured
end end
--- Check if zone is "Attacked", i.e. another coaliton entered the zone. --- Check if zone is "Attacked", i.e. another coalition entered the zone.
-- @param #ZONE_CAPTURE_COALITION self -- @param #ZONE_CAPTURE_COALITION self
-- @return #boolean self:IsSomeInZoneOfCoalition( self.Coalition ) -- @return #boolean self:IsSomeInZoneOfCoalition( self.Coalition )
function ZONE_CAPTURE_COALITION:IsAttacked() function ZONE_CAPTURE_COALITION:IsAttacked()
@@ -906,7 +906,6 @@ do -- ZONE_CAPTURE_COALITION
-- Misc Functions -- Misc Functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Update Mark on F10 map. --- Update Mark on F10 map.
-- @param #ZONE_CAPTURE_COALITION self -- @param #ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:Mark() function ZONE_CAPTURE_COALITION:Mark()
@@ -925,7 +924,7 @@ do -- ZONE_CAPTURE_COALITION
Coord:RemoveMark(self.MarkBlue) Coord:RemoveMark(self.MarkBlue)
end end
-- Create new marks for each coaliton. -- Create new marks for each coalition.
if self.Coalition == coalition.side.BLUE then if self.Coalition == coalition.side.BLUE then
self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Blue\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State ) self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Blue\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State )
self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Blue\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State ) self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Blue\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State )
@@ -24,7 +24,6 @@ do -- ZoneGoal
-- @field #table ObjectCategories Table of object categories that are able to hold a zone. Default is UNITS and STATICS. -- @field #table ObjectCategories Table of object categories that are able to hold a zone. Default is UNITS and STATICS.
-- @extends Functional.ZoneGoal#ZONE_GOAL -- @extends Functional.ZoneGoal#ZONE_GOAL
--- ZONE_GOAL_COALITION models processes that have a Goal with a defined achievement involving a Zone for a Coalition. --- ZONE_GOAL_COALITION models processes that have a Goal with a defined achievement involving a Zone for a Coalition.
-- Derived classes implement the ways how the achievements can be realized. -- Derived classes implement the ways how the achievements can be realized.
-- --
@@ -42,10 +41,10 @@ do -- ZoneGoal
-- --
-- @field #ZONE_GOAL_COALITION -- @field #ZONE_GOAL_COALITION
ZONE_GOAL_COALITION = { ZONE_GOAL_COALITION = {
ClassName = "ZONE_GOAL_COALITION", ClassName = "ZONE_GOAL_COALITION",
Coalition = nil, Coalition = nil,
PreviousCoaliton = nil, PreviousCoalition = nil,
UnitCategories = nil, UnitCategories = nil,
ObjectCategories = nil, ObjectCategories = nil,
} }
@@ -61,31 +60,30 @@ do -- ZoneGoal
function ZONE_GOAL_COALITION:New( Zone, Coalition, UnitCategories ) function ZONE_GOAL_COALITION:New( Zone, Coalition, UnitCategories )
if not Zone then if not Zone then
BASE:E("ERROR: No Zone specified in ZONE_GOAL_COALITON!") BASE:E( "ERROR: No Zone specified in ZONE_GOAL_COALITION!" )
return nil return nil
end end
-- Inherit ZONE_GOAL. -- Inherit ZONE_GOAL.
local self = BASE:Inherit( self, ZONE_GOAL:New( Zone ) ) -- #ZONE_GOAL_COALITION local self = BASE:Inherit( self, ZONE_GOAL:New( Zone ) ) -- #ZONE_GOAL_COALITION
self:F( { Zone = Zone, Coalition = Coalition } ) self:F( { Zone = Zone, Coalition = Coalition } )
-- Set initial owner. -- Set initial owner.
self:SetCoalition( Coalition or coalition.side.NEUTRAL) self:SetCoalition( Coalition or coalition.side.NEUTRAL )
-- Set default unit and object categories for the zone scan. -- Set default unit and object categories for the zone scan.
self:SetUnitCategories(UnitCategories) self:SetUnitCategories( UnitCategories )
self:SetObjectCategories() self:SetObjectCategories()
return self return self
end end
--- Set the owning coalition of the zone. --- Set the owning coalition of the zone.
-- @param #ZONE_GOAL_COALITION self -- @param #ZONE_GOAL_COALITION self
-- @param DCSCoalition.DCSCoalition#coalition Coalition The coalition ID, e.g. *coalition.side.RED*. -- @param DCSCoalition.DCSCoalition#coalition Coalition The coalition ID, e.g. *coalition.side.RED*.
-- @return #ZONE_GOAL_COALITION -- @return #ZONE_GOAL_COALITION
function ZONE_GOAL_COALITION:SetCoalition( Coalition ) function ZONE_GOAL_COALITION:SetCoalition( Coalition )
self.PreviousCoalition=self.Coalition or Coalition self.PreviousCoalition = self.Coalition or Coalition
self.Coalition = Coalition self.Coalition = Coalition
return self return self
end end
@@ -96,11 +94,11 @@ do -- ZoneGoal
-- @return #ZONE_GOAL_COALITION -- @return #ZONE_GOAL_COALITION
function ZONE_GOAL_COALITION:SetUnitCategories( UnitCategories ) function ZONE_GOAL_COALITION:SetUnitCategories( UnitCategories )
if UnitCategories and type(UnitCategories)~="table" then if UnitCategories and type( UnitCategories ) ~= "table" then
UnitCategories={UnitCategories} UnitCategories = { UnitCategories }
end end
self.UnitCategories=UnitCategories or {Unit.Category.GROUND_UNIT} self.UnitCategories = UnitCategories or { Unit.Category.GROUND_UNIT }
return self return self
end end
@@ -111,11 +109,11 @@ do -- ZoneGoal
-- @return #ZONE_GOAL_COALITION -- @return #ZONE_GOAL_COALITION
function ZONE_GOAL_COALITION:SetObjectCategories( ObjectCategories ) function ZONE_GOAL_COALITION:SetObjectCategories( ObjectCategories )
if ObjectCategories and type(ObjectCategories)~="table" then if ObjectCategories and type( ObjectCategories ) ~= "table" then
ObjectCategories={ObjectCategories} ObjectCategories = { ObjectCategories }
end end
self.ObjectCategories=ObjectCategories or {Object.Category.UNIT, Object.Category.STATIC} self.ObjectCategories = ObjectCategories or { Object.Category.UNIT, Object.Category.STATIC }
return self return self
end end
@@ -127,22 +125,20 @@ do -- ZoneGoal
return self.Coalition return self.Coalition
end end
--- Get the previous coaliton, i.e. the one owning the zone before the current one. --- Get the previous coalition, i.e. the one owning the zone before the current one.
-- @param #ZONE_GOAL_COALITION self -- @param #ZONE_GOAL_COALITION self
-- @return DCSCoalition.DCSCoalition#coalition Coalition. -- @return DCSCoalition.DCSCoalition#coalition Coalition.
function ZONE_GOAL_COALITION:GetPreviousCoalition() function ZONE_GOAL_COALITION:GetPreviousCoalition()
return self.PreviousCoalition return self.PreviousCoalition
end end
--- Get the owning coalition name of the zone. --- Get the owning coalition name of the zone.
-- @param #ZONE_GOAL_COALITION self -- @param #ZONE_GOAL_COALITION self
-- @return #string Coalition name. -- @return #string Coalition name.
function ZONE_GOAL_COALITION:GetCoalitionName() function ZONE_GOAL_COALITION:GetCoalitionName()
return UTILS.GetCoalitionName(self.Coalition) return UTILS.GetCoalitionName( self.Coalition )
end end
--- Check status Coalition ownership. --- Check status Coalition ownership.
-- @param #ZONE_GOAL_COALITION self -- @param #ZONE_GOAL_COALITION self
-- @return #ZONE_GOAL_COALITION -- @return #ZONE_GOAL_COALITION
@@ -152,8 +148,8 @@ do -- ZoneGoal
local State = self:GetState() local State = self:GetState()
-- Debug text. -- Debug text.
local text=string.format("Zone state=%s, Owner=%s, Scanning...", State, self:GetCoalitionName()) local text = string.format( "Zone state=%s, Owner=%s, Scanning...", State, self:GetCoalitionName() )
self:F(text) self:F( text )
-- Scan zone. -- Scan zone.
self:Scan( self.ObjectCategories, self.UnitCategories ) self:Scan( self.ObjectCategories, self.UnitCategories )
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+210 -48
View File
@@ -6,6 +6,14 @@
-- --
-- === -- ===
-- --
-- ## Missions:--- **Ops** -- Combat Search and Rescue.
--
-- ===
--
-- **CSAR** - MOOSE based Helicopter CSAR Operations.
--
-- ===
--
-- ## Missions: -- ## Missions:
-- --
-- ### [CSAR - Combat Search & Rescue](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20CSAR) -- ### [CSAR - Combat Search & Rescue](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20CSAR)
@@ -22,7 +30,7 @@
-- @module Ops.CSAR -- @module Ops.CSAR
-- @image OPS_CSAR.jpg -- @image OPS_CSAR.jpg
-- Date: Oct 2021 -- Date: Feb 2022
------------------------------------------------------------------------- -------------------------------------------------------------------------
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM --- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
@@ -45,6 +53,7 @@
-- * Object oriented refactoring of Ciribob\'s fantastic CSAR script. -- * Object oriented refactoring of Ciribob\'s fantastic CSAR script.
-- * No need for extra MIST loading. -- * No need for extra MIST loading.
-- * Additional events to tailor your mission. -- * Additional events to tailor your mission.
-- * Optional SpawnCASEVAC to create casualties without beacon (e.g. handling dead ground vehicles and create CASVAC requests).
-- --
-- ## 0. Prerequisites -- ## 0. Prerequisites
-- --
@@ -115,6 +124,9 @@
-- self.SRSPath = "E:\\Progra~1\\DCS-SimpleRadio-Standalone\\" -- adjust your own path in your SRS installation -- server(!) -- self.SRSPath = "E:\\Progra~1\\DCS-SimpleRadio-Standalone\\" -- adjust your own path in your SRS installation -- server(!)
-- self.SRSchannel = 300 -- radio channel -- self.SRSchannel = 300 -- radio channel
-- self.SRSModulation = radio.modulation.AM -- modulation -- self.SRSModulation = radio.modulation.AM -- modulation
-- --
-- self.csarUsePara = false -- If set to true, will use the LandingAfterEjection Event instead of Ejection --shagrat
-- self.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.
-- --
-- ## 3. Results -- ## 3. Results
-- --
@@ -175,6 +187,8 @@
-- -- Create downed "Pilot Wagner" in #ZONE "CSAR_Start_1" at a random point for the blue coalition -- -- Create downed "Pilot Wagner" in #ZONE "CSAR_Start_1" at a random point for the blue coalition
-- my_csar:SpawnCSARAtZone( "CSAR_Start_1", coalition.side.BLUE, "Pilot Wagner", true ) -- my_csar:SpawnCSARAtZone( "CSAR_Start_1", coalition.side.BLUE, "Pilot Wagner", true )
-- --
-- --Create a casualty and CASEVAC request from a "Point" (VEC2) for the blue coalition --shagrat
-- my_csar:SpawnCASEVAC(Point, coalition.side.BLUE)
-- --
-- @field #CSAR -- @field #CSAR
CSAR = { CSAR = {
@@ -222,8 +236,9 @@ CSAR = {
-- @field #number frequency Frequency of the NDB. -- @field #number frequency Frequency of the NDB.
-- @field #string player Player name if applicable. -- @field #string player Player name if applicable.
-- @field Wrapper.Group#GROUP group Spawned group object. -- @field Wrapper.Group#GROUP group Spawned group object.
-- @field #number timestamp Timestamp for approach process -- @field #number timestamp Timestamp for approach process.
-- @field #boolean alive Group is alive or dead/rescued -- @field #boolean alive Group is alive or dead/rescued.
-- @field #boolean wetfeet Group is spawned over (deep) water.
--- All slot / Limit settings --- All slot / Limit settings
-- @type CSAR.AircraftType -- @type CSAR.AircraftType
@@ -238,10 +253,12 @@ CSAR.AircraftType["Mi-8MTV2"] = 12
CSAR.AircraftType["Mi-8MT"] = 12 CSAR.AircraftType["Mi-8MT"] = 12
CSAR.AircraftType["Mi-24P"] = 8 CSAR.AircraftType["Mi-24P"] = 8
CSAR.AircraftType["Mi-24V"] = 8 CSAR.AircraftType["Mi-24V"] = 8
CSAR.AircraftType["Bell-47"] = 2
CSAR.AircraftType["UH-60L"] = 10
--- CSAR class version. --- CSAR class version.
-- @field #string version -- @field #string version
CSAR.version="0.1.11r1" CSAR.version="1.0.4c"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list -- ToDo list
@@ -249,7 +266,7 @@ CSAR.version="0.1.11r1"
-- DONE: SRS Integration (to be tested) -- DONE: SRS Integration (to be tested)
-- TODO: Maybe - add option to smoke/flare closest MASH -- TODO: Maybe - add option to smoke/flare closest MASH
-- TODO: shagrat Add cargoWeight to helicopter when pilot boarded
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor -- Constructor
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -350,6 +367,7 @@ function CSAR:New(Coalition, Template, Alias)
self.extractDistance = 500 -- Distance the Downed pilot will run to the rescue helicopter self.extractDistance = 500 -- Distance the Downed pilot will run to the rescue helicopter
self.loadtimemax = 135 -- seconds self.loadtimemax = 135 -- seconds
self.radioSound = "beacon.ogg" -- the name of the sound file to use for the Pilot radio beacons. If this isnt added to the mission BEACONS WONT WORK! self.radioSound = "beacon.ogg" -- the name of the sound file to use for the Pilot radio beacons. If this isnt added to the mission BEACONS WONT WORK!
self.beaconRefresher = 29 -- seconds
self.allowFARPRescue = true --allows pilot to be rescued by landing at a FARP or Airbase self.allowFARPRescue = true --allows pilot to be rescued by landing at a FARP or Airbase
self.FARPRescueDistance = 1000 -- you need to be this close to a FARP or Airport for the pilot to be rescued. self.FARPRescueDistance = 1000 -- you need to be this close to a FARP or Airport for the pilot to be rescued.
self.max_units = 6 --max number of pilots that can be carried self.max_units = 6 --max number of pilots that can be carried
@@ -380,6 +398,13 @@ function CSAR:New(Coalition, Template, Alias)
self.countryred = country.id.RUSSIA self.countryred = country.id.RUSSIA
self.countryneutral = country.id.UN_PEACEKEEPERS self.countryneutral = country.id.UN_PEACEKEEPERS
-- added 0.1.3
self.csarUsePara = false -- shagrat set to true, will use the LandingAfterEjection Event instead of Ejection
-- added 0.1.4
self.wetfeettemplate = nil
self.usewetfeet = false
-- WARNING - here\'ll be dragons -- WARNING - here\'ll be dragons
-- for this to work you need to de-sanitize your mission environment in <DCS root>\Scripts\MissionScripting.lua -- for this to work you need to de-sanitize your mission environment in <DCS root>\Scripts\MissionScripting.lua
-- needs SRS => 1.9.6 to work (works on the *server* side) -- needs SRS => 1.9.6 to work (works on the *server* side)
@@ -491,8 +516,9 @@ end
-- @param #string Typename Typename of unit. -- @param #string Typename Typename of unit.
-- @param #number Frequency Frequency of the NDB in Hz -- @param #number Frequency Frequency of the NDB in Hz
-- @param #string Playername Name of Player (if applicable) -- @param #string Playername Name of Player (if applicable)
-- @param #boolean Wetfeet Ejected over water
-- @return #CSAR self. -- @return #CSAR self.
function CSAR:_CreateDownedPilotTrack(Group,Groupname,Side,OriginalUnit,Description,Typename,Frequency,Playername) function CSAR:_CreateDownedPilotTrack(Group,Groupname,Side,OriginalUnit,Description,Typename,Frequency,Playername,Wetfeet)
self:T({"_CreateDownedPilotTrack",Groupname,Side,OriginalUnit,Description,Typename,Frequency,Playername}) self:T({"_CreateDownedPilotTrack",Groupname,Side,OriginalUnit,Description,Typename,Frequency,Playername})
-- create new entry -- create new entry
@@ -508,6 +534,7 @@ function CSAR:_CreateDownedPilotTrack(Group,Groupname,Side,OriginalUnit,Descript
DownedPilot.group = Group DownedPilot.group = Group
DownedPilot.timestamp = 0 DownedPilot.timestamp = 0
DownedPilot.alive = true DownedPilot.alive = true
DownedPilot.wetfeet = Wetfeet or false
-- Add Pilot -- Add Pilot
local PilotTable = self.downedPilots local PilotTable = self.downedPilots
@@ -557,17 +584,23 @@ end
-- @param #number country Country for template. -- @param #number country Country for template.
-- @param Core.Point#COORDINATE point Coordinate to spawn at. -- @param Core.Point#COORDINATE point Coordinate to spawn at.
-- @param #number frequency Frequency of the pilot's beacon -- @param #number frequency Frequency of the pilot's beacon
-- @param #boolean wetfeet Spawn is over water
-- @return Wrapper.Group#GROUP group The #GROUP object. -- @return Wrapper.Group#GROUP group The #GROUP object.
-- @return #string alias The alias name. -- @return #string alias The alias name.
function CSAR:_SpawnPilotInField(country,point,frequency) function CSAR:_SpawnPilotInField(country,point,frequency,wetfeet)
self:T({country,point,frequency}) self:T({country,point,frequency,tostring(wetfeet)})
local freq = frequency or 1000 local freq = frequency or 1000
local freq = freq / 1000 -- kHz local freq = freq / 1000 -- kHz
for i=1,10 do for i=1,10 do
math.random(i,10000) math.random(i,10000)
end end
if point:IsSurfaceTypeWater() then point.y = 0 end if point:IsSurfaceTypeWater() or wetfeet then
point.y = 0
end
local template = self.template local template = self.template
if self.usewetfeet and wetfeet then
template = self.wetfeettemplate
end
local alias = string.format("Pilot %.2fkHz-%d", freq, math.random(1,99)) local alias = string.format("Pilot %.2fkHz-%d", freq, math.random(1,99))
local coalition = self.coalition local coalition = self.coalition
local pilotcacontrol = self.allowDownedPilotCAcontrol -- Switch AI on/oof - is this really correct for CA? local pilotcacontrol = self.allowDownedPilotCAcontrol -- Switch AI on/oof - is this really correct for CA?
@@ -633,21 +666,31 @@ function CSAR:_AddCsar(_coalition , _country, _point, _typeName, _unitName, _pla
self:T({_coalition , _country, _point, _typeName, _unitName, _playerName, _freq, noMessage, _description}) self:T({_coalition , _country, _point, _typeName, _unitName, _playerName, _freq, noMessage, _description})
local template = self.template local template = self.template
local wetfeet = false
local surface = _point:GetSurfaceType()
if surface == land.SurfaceType.WATER then
wetfeet = true
end
if not _freq then if not _freq then
_freq = self:_GenerateADFFrequency() _freq = self:_GenerateADFFrequency()
if not _freq then _freq = 333000 end --noob catch if not _freq then _freq = 333000 end --noob catch
end end
local _spawnedGroup, _alias = self:_SpawnPilotInField(_country,_point,_freq) local _spawnedGroup, _alias = self:_SpawnPilotInField(_country,_point,_freq,wetfeet)
local _typeName = _typeName or "Pilot" local _typeName = _typeName or "Pilot"
if not noMessage then if not noMessage then
if _freq ~= 0 then --shagrat different CASEVAC msg
self:_DisplayToAllSAR("MAYDAY MAYDAY! " .. _typeName .. " is down. ", self.coalition, self.messageTime) self:_DisplayToAllSAR("MAYDAY MAYDAY! " .. _typeName .. " is down. ", self.coalition, self.messageTime)
else
self:_DisplayToAllSAR("Troops In Contact. " .. _typeName .. " requests CASEVAC. ", self.coalition, self.messageTime)
end
end end
if _freq then if (_freq and _freq ~= 0) then --shagrat only add beacon if _freq is NOT 0
self:_AddBeaconToGroup(_spawnedGroup, _freq) self:_AddBeaconToGroup(_spawnedGroup, _freq)
end end
@@ -656,25 +699,33 @@ function CSAR:_AddCsar(_coalition , _country, _point, _typeName, _unitName, _pla
local _text = _description local _text = _description
if not forcedesc then if not forcedesc then
if _playerName ~= nil then if _playerName ~= nil then
_text = "Pilot " .. _playerName if _freq ~= 0 then --shagrat
elseif _unitName ~= nil then _text = "Pilot " .. _playerName
_text = "AI Pilot of " .. _unitName else
_text = "TIC - " .. _playerName
end end
elseif _unitName ~= nil then
if _freq ~= 0 then --shagrat
_text = "AI Pilot of " .. _unitName
else
_text = "TIC - " .. _unitName
end
end
end end
self:T({_spawnedGroup, _alias}) self:T({_spawnedGroup, _alias})
local _GroupName = _spawnedGroup:GetName() or _alias local _GroupName = _spawnedGroup:GetName() or _alias
self:_CreateDownedPilotTrack(_spawnedGroup,_GroupName,_coalition,_unitName,_text,_typeName,_freq,_playerName) self:_CreateDownedPilotTrack(_spawnedGroup,_GroupName,_coalition,_unitName,_text,_typeName,_freq,_playerName,wetfeet)
self:_InitSARForPilot(_spawnedGroup, _GroupName, _freq, noMessage) self:_InitSARForPilot(_spawnedGroup, _unitName, _freq, noMessage) --shagrat use unitName to have the aircraft callsign / descriptive "name" etc.
return self return self
end end
--- (Internal) Function to add a CSAR object into the scene at a zone coordinate. For mission designers wanting to add e.g. PoWs to the scene. --- (Internal) Function to add a CSAR object into the scene at a zone coordinate. For mission designers wanting to add e.g. PoWs to the scene.
-- @param #CSAR self -- @param #CSAR self
-- @param #string _zone Name of the zone. -- @param #string _zone Name of the zone. Can also be passed as a (normal, round) ZONE object.
-- @param #number _coalition Coalition. -- @param #number _coalition Coalition.
-- @param #string _description (optional) Description. -- @param #string _description (optional) Description.
-- @param #boolean _randomPoint (optional) Random yes or no. -- @param #boolean _randomPoint (optional) Random yes or no.
@@ -685,7 +736,16 @@ end
function CSAR:_SpawnCsarAtZone( _zone, _coalition, _description, _randomPoint, _nomessage, unitname, typename, forcedesc) function CSAR:_SpawnCsarAtZone( _zone, _coalition, _description, _randomPoint, _nomessage, unitname, typename, forcedesc)
self:T(self.lid .. " _SpawnCsarAtZone") self:T(self.lid .. " _SpawnCsarAtZone")
local freq = self:_GenerateADFFrequency() local freq = self:_GenerateADFFrequency()
local _triggerZone = ZONE:New(_zone) -- trigger to use as reference position
local _triggerZone = nil
if type(_zone) == "string" then
_triggerZone = ZONE:New(_zone) -- trigger to use as reference position
elseif type(_zone) == "table" and _zone.ClassName then
if string.find(_zone.ClassName, "ZONE",1) then
_triggerZone = _zone -- is already a zone
end
end
if _triggerZone == nil then if _triggerZone == nil then
self:E(self.lid.."ERROR: Can\'t find zone called " .. _zone, 10) self:E(self.lid.."ERROR: Can\'t find zone called " .. _zone, 10)
return return
@@ -719,7 +779,7 @@ end
--- Function to add a CSAR object into the scene at a zone coordinate. For mission designers wanting to add e.g. PoWs to the scene. --- Function to add a CSAR object into the scene at a zone coordinate. For mission designers wanting to add e.g. PoWs to the scene.
-- @param #CSAR self -- @param #CSAR self
-- @param #string Zone Name of the zone. -- @param #string Zone Name of the zone. Can also be passed as a (normal, round) ZONE object.
-- @param #number Coalition Coalition. -- @param #number Coalition Coalition.
-- @param #string Description (optional) Description. -- @param #string Description (optional) Description.
-- @param #boolean RandomPoint (optional) Random yes or no. -- @param #boolean RandomPoint (optional) Random yes or no.
@@ -736,6 +796,58 @@ function CSAR:SpawnCSARAtZone(Zone, Coalition, Description, RandomPoint, Nomessa
return self return self
end end
--- (Internal) Function to add a CSAR object into the scene at a Point coordinate (VEC_2). For mission designers wanting to add e.g. casualties to the scene, that don't use beacons.
-- @param #CSAR self
-- @param #string _Point a POINT_VEC2.
-- @param #number _coalition Coalition.
-- @param #string _description (optional) Description.
-- @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.
-- @param #boolean forcedesc (optional) Force to use the description passed only for the pilot track entry. Use to have fully custom names.
function CSAR:_SpawnCASEVAC( _Point, _coalition, _description, _nomessage, unitname, typename, forcedesc) --shagrat added internal Function _SpawnCASEVAC
self:T(self.lid .. " _SpawnCASEVAC")
local _description = _description or "CASEVAC"
local unitname = unitname or "CASEVAC"
local typename = typename or "Ground Commander"
local pos = {}
pos = _Point
local _country = 0
if _coalition == coalition.side.BLUE then
_country = self.countryblue
elseif _coalition == coalition.side.RED then
_country = self.countryred
else
_country = self.countryneutral
end
--shagrat set frequency to 0 as "flag" for no beacon
self:_AddCsar(_coalition, _country, pos, typename, unitname, _description, 0, _nomessage, _description, forcedesc)
return self
end
--- Function to add a CSAR object into the scene at a zone coordinate. For mission designers wanting to add e.g. PoWs to the scene.
-- @param #CSAR self
-- @param #string Point a POINT_VEC2.
-- @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.
-- @param #boolean Forcedesc (optional) Force to use the **description passed only** for the pilot track entry. Use to have fully custom names.
-- @usage If missions designers want to spawn downed pilots into the field, e.g. at mission begin, to give the helicopter guys work, they can do this like so:
--
-- -- Create casualty "CASEVAC" at Point #POINT_VEC2 for the blue coalition.
-- my_csar:SpawnCASEVAC( POINT_VEC2, coalition.side.BLUE )
function CSAR:SpawnCASEVAC(Point, Coalition, Description, Nomessage, Unitname, Typename, Forcedesc)
self:_SpawnCASEVAC(Point, Coalition, Description, Nomessage, Unitname, Typename, Forcedesc)
return self
end --shagrat end added CASEVAC
--- (Internal) Event handler. --- (Internal) Event handler.
-- @param #CSAR self -- @param #CSAR self
function CSAR:_EventHandler(EventData) function CSAR:_EventHandler(EventData)
@@ -744,6 +856,11 @@ function CSAR:_EventHandler(EventData)
local _event = EventData -- Core.Event#EVENTDATA local _event = EventData -- Core.Event#EVENTDATA
-- no Player
if self.enableForAI == false and _event.IniPlayerName == nil then
return
end
-- no event -- no event
if _event == nil or _event.initiator == nil then if _event == nil or _event.initiator == nil then
return false return false
@@ -828,15 +945,11 @@ function CSAR:_EventHandler(EventData)
return -- error! return -- error!
end end
local _coalition = _unit:GetCoalition() local _coalition = _unit:GetCoalition()
if _coalition ~= self.coalition then if _coalition ~= self.coalition then
return --ignore! return --ignore!
end end
if self.enableForAI == false and _event.IniPlayerName == nil then
return
end
if not self.takenOff[_event.IniUnitName] and not _group:IsAirborne() then if not self.takenOff[_event.IniUnitName] and not _group:IsAirborne() then
self:T(self.lid .. " Pilot has not taken off, ignore") self:T(self.lid .. " Pilot has not taken off, ignore")
return -- give up, pilot hasnt taken off return -- give up, pilot hasnt taken off
@@ -851,11 +964,39 @@ function CSAR:_EventHandler(EventData)
return return
end end
-- all checks passed, get going.
local _freq = self:_GenerateADFFrequency()
self:_AddCsar(_coalition, _unit:GetCountry(), _unit:GetCoordinate() , _unit:GetTypeName(), _unit:GetName(), _event.IniPlayerName, _freq, false, "none")
return true -- TODO: Over water check --- EVENTS.LandingAfterEjection NOT triggered by DCS, so handle csarUsePara = true case
-- might create dual pilots in edge cases
local wetfeet = false
local surface = _unit:GetCoordinate():GetSurfaceType()
if surface == land.SurfaceType.WATER then
wetfeet = true
end
-- all checks passed, get going.
if self.csarUsePara == false or (self.csarUsePara and wetfeet ) then --shagrat check parameter LandingAfterEjection, if true don't spawn a Pilot from EJECTION event, wait for the Chute to land
local _freq = self:_GenerateADFFrequency()
self:_AddCsar(_coalition, _unit:GetCountry(), _unit:GetCoordinate() , _unit:GetTypeName(), _unit:GetName(), _event.IniPlayerName, _freq, false, "none")
return true
end
---- shagrat on event LANDING_AFTER_EJECTION spawn pilot at parachute location
elseif (_event.id == EVENTS.LandingAfterEjection and self.csarUsePara == true) then
self:I({EVENT=_event})
local _LandingPos = COORDINATE:NewFromVec3(_event.initiator:getPosition().p)
local _unitname = "Aircraft" --_event.initiator:getName() or "Aircraft" --shagrat Optional use of Object name which is unfortunately 'f15_Pilot_Parachute'
local _typename = "Ejected Pilot" --_event.Initiator.getTypeName() or "Ejected Pilot"
local _country = _event.initiator:getCountry()
local _coalition = coalition.getCountryCoalition( _country )
if _coalition == self.coalition then
local _freq = self:_GenerateADFFrequency()
self:I({coalition=_coalition,country= _country, coord=_LandingPos, name=_unitname, player=_event.IniPlayerName, freq=_freq})
self:_AddCsar(_coalition, _country, _LandingPos, nil, _unitname, _event.IniPlayerName, _freq, false, "none")--shagrat add CSAR at Parachute location.
Unit.destroy(_event.initiator) -- shagrat remove static Pilot model
end
return true
elseif _event.id == EVENTS.Land then elseif _event.id == EVENTS.Land then
self:T(self.lid .. " Landing") self:T(self.lid .. " Landing")
@@ -920,8 +1061,13 @@ function CSAR:_InitSARForPilot(_downedGroup, _GroupName, _freq, _nomessage)
local _leadername = _leader:GetName() local _leadername = _leader:GetName()
if not _nomessage then if not _nomessage then
local _text = string.format("%s requests SAR at %s, beacon at %.2f KHz", _leadername, _coordinatesText, _freqk) if _freq ~= 0 then --shagrat
local _text = string.format("%s requests SAR at %s, beacon at %.2f KHz", _groupName, _coordinatesText, _freqk)--shagrat _groupName to prevent 'f15_Pilot_Parachute'
self:_DisplayToAllSAR(_text,self.coalition,self.messageTime) self:_DisplayToAllSAR(_text,self.coalition,self.messageTime)
else --shagrat CASEVAC msg
local _text = string.format("Pickup Zone at %s.", _coordinatesText )
self:_DisplayToAllSAR(_text,self.coalition,self.messageTime)
end
end end
for _,_heliName in pairs(self.csarUnits) do for _,_heliName in pairs(self.csarUnits) do
@@ -1025,9 +1171,9 @@ function CSAR:_CheckWoundedGroupStatus(heliname,woundedgroupname)
local dist = UTILS.MetersToNM(self.autosmokedistance) local dist = UTILS.MetersToNM(self.autosmokedistance)
disttext = string.format("%.0fnm",dist) disttext = string.format("%.0fnm",dist)
end end
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Damn, that thing is loud!\nI'll pop a smoke when you are %s away.\nLand or hover by the smoke.", _heliName, _pilotName, disttext), self.messageTime,false,true) self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nI'll pop a smoke when you are %s away.\nLand or hover by the smoke.", _heliName, _pilotName, disttext), self.messageTime,false,true)
else else
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Damn, that thing is loud!\nRequest a flare or smoke if you need.", _heliName, _pilotName), self.messageTime,false,true) self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nRequest a flare or smoke if you need.", _heliName, _pilotName), self.messageTime,false,true)
end end
--mark as shown for THIS heli and THIS group --mark as shown for THIS heli and THIS group
self.heliVisibleMessage[_lookupKeyHeli] = true self.heliVisibleMessage[_lookupKeyHeli] = true
@@ -1059,7 +1205,7 @@ function CSAR:_PopSmokeForGroup(_woundedGroupName, _woundedLeader)
if _lastSmoke == nil or timer.getTime() > _lastSmoke then if _lastSmoke == nil or timer.getTime() > _lastSmoke then
local _smokecolor = self.smokecolor local _smokecolor = self.smokecolor
local _smokecoord = _woundedLeader:GetCoordinate() local _smokecoord = _woundedLeader:GetCoordinate():Translate( 6, math.random( 1, 360) ) --shagrat place smoke at a random 6 m distance, so smoke does not obscure the pilot
_smokecoord:Smoke(_smokecolor) _smokecoord:Smoke(_smokecolor)
self.smokeMarkers[_woundedGroupName] = timer.getTime() + 300 -- next smoke time self.smokeMarkers[_woundedGroupName] = timer.getTime() + 300 -- next smoke time
end end
@@ -1186,7 +1332,8 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
_time = self.landedStatus[_lookupKeyHeli] - 10 _time = self.landedStatus[_lookupKeyHeli] - 10
self.landedStatus[_lookupKeyHeli] = _time self.landedStatus[_lookupKeyHeli] = _time
end end
if _time <= 0 or _distance < self.loadDistance then --if _time <= 0 or _distance < self.loadDistance then
if _distance < self.loadDistance + 5 or _distance <= 13 then
if self.pilotmustopendoors and not self:_IsLoadingDoorOpen(_heliName) then if self.pilotmustopendoors and not self:_IsLoadingDoorOpen(_heliName) then
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true) self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true)
return true return true
@@ -1359,12 +1506,13 @@ end
-- @param #number _time Message show duration. -- @param #number _time Message show duration.
-- @param #boolean _clear (optional) Clear screen. -- @param #boolean _clear (optional) Clear screen.
-- @param #boolean _speak (optional) Speak message via SRS. -- @param #boolean _speak (optional) Speak message via SRS.
function CSAR:_DisplayMessageToSAR(_unit, _text, _time, _clear, _speak) -- @param #boolean _override (optional) Override message suppression
function CSAR:_DisplayMessageToSAR(_unit, _text, _time, _clear, _speak, _override)
self:T(self.lid .. " _DisplayMessageToSAR") self:T(self.lid .. " _DisplayMessageToSAR")
local group = _unit:GetGroup() local group = _unit:GetGroup()
local _clear = _clear or nil local _clear = _clear or nil
local _time = _time or self.messageTime local _time = _time or self.messageTime
if not self.suppressmessages then if _override or not self.suppressmessages then
local m = MESSAGE:New(_text,_time,"Info",_clear):ToGroup(group) local m = MESSAGE:New(_text,_time,"Info",_clear):ToGroup(group)
end end
-- integrate SRS -- integrate SRS
@@ -1434,7 +1582,11 @@ function CSAR:_DisplayActiveSAR(_unitName)
else else
distancetext = string.format("%.1fkm", _distance/1000.0) distancetext = string.format("%.1fkm", _distance/1000.0)
end end
table.insert(_csarList, { dist = _distance, msg = string.format("%s at %s - %.2f KHz ADF - %s ", _value.desc, _coordinatesText, _value.frequency / 1000, distancetext) }) 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
end end
end end
@@ -1448,7 +1600,7 @@ function CSAR:_DisplayActiveSAR(_unitName)
_msg = _msg .. "\n" .. _line.msg _msg = _msg .. "\n" .. _line.msg
end end
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime*2) self:_DisplayMessageToSAR(_heli, _msg, self.messageTime*2, false, false, true)
return self return self
end end
@@ -1506,7 +1658,7 @@ function CSAR:_SignalFlare(_unitName)
local _closest = self:_GetClosestDownedPilot(_heli) local _closest = self:_GetClosestDownedPilot(_heli)
local smokedist = 8000 local smokedist = 8000
if self.approachdist_far > smokedist then smokedist = self.approachdist_far end if self.approachdist_far > smokedist then smokedist = self.approachdist_far end
if _closest ~= nil and _closest.pilot ~= nil and _closest.distance < smokedist then if _closest ~= nil and _closest.pilot ~= nil and _closest.distance > 0 and _closest.distance < smokedist then
local _clockDir = self:_GetClockDirection(_heli, _closest.pilot) local _clockDir = self:_GetClockDirection(_heli, _closest.pilot)
local _distance = 0 local _distance = 0
@@ -1516,7 +1668,7 @@ function CSAR:_SignalFlare(_unitName)
_distance = string.format("%.1fkm",_closest.distance) _distance = string.format("%.1fkm",_closest.distance)
end end
local _msg = string.format("%s - Popping signal flare at your %s o\'clock. Distance %s", _unitName, _clockDir, _distance) local _msg = string.format("%s - Popping signal flare at your %s o\'clock. Distance %s", _unitName, _clockDir, _distance)
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true) self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
local _coord = _closest.pilot:GetCoordinate() local _coord = _closest.pilot:GetCoordinate()
_coord:FlareRed(_clockDir) _coord:FlareRed(_clockDir)
@@ -1527,7 +1679,7 @@ function CSAR:_SignalFlare(_unitName)
else else
_distance = string.format("%.1fkm",smokedist/1000) _distance = string.format("%.1fkm",smokedist/1000)
end end
self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",_distance), self.messageTime) self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",_distance), self.messageTime, false, false, true)
end end
return self return self
end end
@@ -1561,16 +1713,16 @@ function CSAR:_Reqsmoke( _unitName )
local smokedist = 8000 local smokedist = 8000
if smokedist < self.approachdist_far then smokedist = self.approachdist_far end if smokedist < self.approachdist_far then smokedist = self.approachdist_far end
local _closest = self:_GetClosestDownedPilot(_heli) local _closest = self:_GetClosestDownedPilot(_heli)
if _closest ~= nil and _closest.pilot ~= nil and _closest.distance < smokedist then if _closest ~= nil and _closest.pilot ~= nil and _closest.distance > 0 and _closest.distance < smokedist then
local _clockDir = self:_GetClockDirection(_heli, _closest.pilot) local _clockDir = self:_GetClockDirection(_heli, _closest.pilot)
local _distance = 0 local _distance = 0
if _SETTINGS:IsImperial() then if _SETTINGS:IsImperial() then
_distance = string.format("%.1fnm",UTILS.MetersToNM(_closest.distance)) _distance = string.format("%.1fnm",UTILS.MetersToNM(_closest.distance))
else else
_distance = string.format("%.1fkm",_closest.distance) _distance = string.format("%.1fkm",_closest.distance/1000)
end end
local _msg = string.format("%s - Popping signal smoke at your %s o\'clock. Distance %s", _unitName, _clockDir, _distance) local _msg = string.format("%s - Popping smoke at your %s o\'clock. Distance %s", _unitName, _clockDir, _distance)
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true) self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
local _coord = _closest.pilot:GetCoordinate() local _coord = _closest.pilot:GetCoordinate()
local color = self.smokecolor local color = self.smokecolor
_coord:Smoke(color) _coord:Smoke(color)
@@ -1581,7 +1733,7 @@ function CSAR:_Reqsmoke( _unitName )
else else
_distance = string.format("%.1fkm",smokedist/1000) _distance = string.format("%.1fkm",smokedist/1000)
end end
self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",_distance), self.messageTime) self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",_distance), self.messageTime, false, false, true)
end end
return self return self
end end
@@ -1653,13 +1805,13 @@ function CSAR:_CheckOnboard(_unitName)
--list onboard pilots --list onboard pilots
local _inTransit = self.inTransitGroups[_unitName] local _inTransit = self.inTransitGroups[_unitName]
if _inTransit == nil then if _inTransit == nil then
self:_DisplayMessageToSAR(_unit, "No Rescued Pilots onboard", self.messageTime) self:_DisplayMessageToSAR(_unit, "No Rescued Pilots onboard", self.messageTime, false, false, true)
else else
local _text = "Onboard - RTB to FARP/Airfield or MASH: " local _text = "Onboard - RTB to FARP/Airfield or MASH: "
for _, _onboard in pairs(self.inTransitGroups[_unitName]) do for _, _onboard in pairs(self.inTransitGroups[_unitName]) do
_text = _text .. "\n" .. _onboard.desc _text = _text .. "\n" .. _onboard.desc
end end
self:_DisplayMessageToSAR(_unit, _text, self.messageTime*2) self:_DisplayMessageToSAR(_unit, _text, self.messageTime*2, false, false, true)
end end
return self return self
end end
@@ -1875,6 +2027,7 @@ function CSAR:onafterStart(From, Event, To)
self:HandleEvent(EVENTS.Takeoff, self._EventHandler) self:HandleEvent(EVENTS.Takeoff, self._EventHandler)
self:HandleEvent(EVENTS.Land, self._EventHandler) self:HandleEvent(EVENTS.Land, self._EventHandler)
self:HandleEvent(EVENTS.Ejection, self._EventHandler) self:HandleEvent(EVENTS.Ejection, self._EventHandler)
self:HandleEvent(EVENTS.LandingAfterEjection, self._EventHandler) --shagrat
self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler) self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler)
self:HandleEvent(EVENTS.PlayerEnterUnit, self._EventHandler) self:HandleEvent(EVENTS.PlayerEnterUnit, self._EventHandler)
self:HandleEvent(EVENTS.PilotDead, self._EventHandler) self:HandleEvent(EVENTS.PilotDead, self._EventHandler)
@@ -1885,6 +2038,9 @@ function CSAR:onafterStart(From, Event, To)
self.allheligroupset = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterCategoryHelicopter():FilterStart() self.allheligroupset = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterCategoryHelicopter():FilterStart()
end end
self.mash = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart() -- currently only GROUP objects, maybe support STATICs also? self.mash = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart() -- currently only GROUP objects, maybe support STATICs also?
if self.wetfeettemplate then
self.usewetfeet = true
end
self:__Status(-10) self:__Status(-10)
return self return self
end end
@@ -1918,7 +2074,12 @@ function CSAR:onbeforeStatus(From, Event, To)
self:T({From, Event, To}) self:T({From, Event, To})
-- housekeeping -- housekeeping
self:_AddMedevacMenuItem() self:_AddMedevacMenuItem()
self:_RefreshRadioBeacons()
if not self.BeaconTimer or (self.BeaconTimer and not self.BeaconTimer:IsRunning()) then
self.BeaconTimer = TIMER:New(self._RefreshRadioBeacons,self)
self.BeaconTimer:Start(2,self.beaconRefresher)
end
self:_CheckDownedPilotTable() self:_CheckDownedPilotTable()
for _,_sar in pairs (self.csarUnits) do for _,_sar in pairs (self.csarUnits) do
local PilotTable = self.downedPilots local PilotTable = self.downedPilots
@@ -1985,6 +2146,7 @@ function CSAR:onafterStop(From, Event, To)
self:UnHandleEvent(EVENTS.Takeoff) self:UnHandleEvent(EVENTS.Takeoff)
self:UnHandleEvent(EVENTS.Land) self:UnHandleEvent(EVENTS.Land)
self:UnHandleEvent(EVENTS.Ejection) self:UnHandleEvent(EVENTS.Ejection)
self:UnHandleEvent(EVENTS.LandingAfterEjection) -- shagrat
self:UnHandleEvent(EVENTS.PlayerEnterUnit) self:UnHandleEvent(EVENTS.PlayerEnterUnit)
self:UnHandleEvent(EVENTS.PlayerEnterAircraft) self:UnHandleEvent(EVENTS.PlayerEnterAircraft)
self:UnHandleEvent(EVENTS.PilotDead) self:UnHandleEvent(EVENTS.PilotDead)
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -802,7 +802,7 @@ function RESCUEHELO:_OnEventCrashOrEject(EventData)
-- Debug. -- Debug.
local text=string.format("Unit %s crashed or ejected.", unitname) local text=string.format("Unit %s crashed or ejected.", unitname)
MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug) MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug)
self:I(self.lid..text) self:T(self.lid..text)
-- Get coordinate of unit. -- Get coordinate of unit.
local coord=unit:GetCoordinate() local coord=unit:GetCoordinate()
+10 -1
View File
@@ -88,10 +88,19 @@
-- --
-- Use a specific "culture" with the @{#MSRS.SetCulture} function, e.g. `:SetCulture("en-US")` or `:SetCulture("de-DE")`. -- Use a specific "culture" with the @{#MSRS.SetCulture} function, e.g. `:SetCulture("en-US")` or `:SetCulture("de-DE")`.
-- --
-- ## Set Google
--
-- Use Google's text-to-speech engine with the @{#MSRS.SetGoogle} function, e.g. ':SetGoogle()'.
-- By enabling this it also allows you to utilize SSML in your text for added flexibilty.
-- For more information on setting up a cloud account, visit: https://cloud.google.com/text-to-speech
-- Google's supported SSML reference: https://cloud.google.com/text-to-speech/docs/ssml
--
-- ## Set Voice -- ## Set Voice
-- --
-- Use a specifc voice with the @{#MSRS.SetVoice} function, e.g, `:SetVoice("Microsoft Hedda Desktop")`. -- Use a specifc voice with the @{#MSRS.SetVoice} function, e.g, `:SetVoice("Microsoft Hedda Desktop")`.
-- Note that this must be installed on your windows system. -- Note that this must be installed on your windows system.
-- If enabling SetGoogle(), you can use voices provided by Google
-- Google's supported voices: https://cloud.google.com/text-to-speech/docs/voices
-- --
-- ## Set Coordinate -- ## Set Coordinate
-- --
@@ -678,7 +687,7 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
-- Set google. -- Set google.
if self.google then if self.google then
command=command..string.format(' -G "%s"', self.google) command=command..string.format(' --ssml -G "%s"', self.google)
end end
-- Debug output. -- Debug output.
+1 -1
View File
@@ -132,7 +132,7 @@ MISSION = {
-- @param #string MissionName Name of the mission. This name will be used to reference the status of each mission by the players. -- @param #string MissionName Name of the mission. This name will be used to reference the status of each mission by the players.
-- @param #string MissionPriority String indicating the "priority" of the Mission. e.g. "Primary", "Secondary". It is free format and up to the Mission designer to choose. There are no rules behind this field. -- @param #string MissionPriority String indicating the "priority" of the Mission. e.g. "Primary", "Secondary". It is free format and up to the Mission designer to choose. There are no rules behind this field.
-- @param #string MissionBriefing String indicating the mission briefing to be shown when a player joins a @{CLIENT}. -- @param #string MissionBriefing String indicating the mission briefing to be shown when a player joins a @{CLIENT}.
-- @param DCS#coaliton.side MissionCoalition Side of the coalition, i.e. and enumerator @{#DCS.coalition.side} corresponding to RED, BLUE or NEUTRAL. -- @param DCS#coalition.side MissionCoalition Side of the coalition, i.e. and enumerator @{#DCS.coalition.side} corresponding to RED, BLUE or NEUTRAL.
-- @return #MISSION self -- @return #MISSION self
function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefing, MissionCoalition ) function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefing, MissionCoalition )
+1 -1
View File
@@ -82,7 +82,7 @@
-- --
-- ![Mission](../Tasking/Report_Statistics_Progress.JPG) -- ![Mission](../Tasking/Report_Statistics_Progress.JPG)
-- --
-- A statistic report on the progress of the mission. Each task achievement will increase the %-tage to 100% as a goal to complete the task. -- A statistic report on the progress of the mission. Each task achievement will increase the % to 100% as a goal to complete the task.
-- --
-- ## 1.3) Join a Task. -- ## 1.3) Join a Task.
-- --
+20 -50
View File
@@ -38,7 +38,7 @@ do -- TASK_A2A
-- --
-- @field #TASK_A2A -- @field #TASK_A2A
TASK_A2A = { TASK_A2A = {
ClassName = "TASK_A2A", ClassName = "TASK_A2A"
} }
--- Instantiates a new TASK_A2A. --- Instantiates a new TASK_A2A.
@@ -60,29 +60,27 @@ do -- TASK_A2A
local Fsm = self:GetUnitProcess() local Fsm = self:GetUnitProcess()
Fsm:AddTransition( "Assigned", "RouteToRendezVous", "RoutingToRendezVous" ) Fsm:AddTransition( "Assigned", "RouteToRendezVous", "RoutingToRendezVous" )
Fsm:AddProcess ( "RoutingToRendezVous", "RouteToRendezVousPoint", ACT_ROUTE_POINT:New(), { Arrived = "ArriveAtRendezVous" } ) Fsm:AddProcess( "RoutingToRendezVous", "RouteToRendezVousPoint", ACT_ROUTE_POINT:New(), { Arrived = "ArriveAtRendezVous" } )
Fsm:AddProcess ( "RoutingToRendezVous", "RouteToRendezVousZone", ACT_ROUTE_ZONE:New(), { Arrived = "ArriveAtRendezVous" } ) Fsm:AddProcess( "RoutingToRendezVous", "RouteToRendezVousZone", ACT_ROUTE_ZONE:New(), { Arrived = "ArriveAtRendezVous" } )
Fsm:AddTransition( { "Arrived", "RoutingToRendezVous" }, "ArriveAtRendezVous", "ArrivedAtRendezVous" ) Fsm:AddTransition( { "Arrived", "RoutingToRendezVous" }, "ArriveAtRendezVous", "ArrivedAtRendezVous" )
Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "Engage", "Engaging" ) Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "Engage", "Engaging" )
Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "HoldAtRendezVous", "HoldingAtRendezVous" ) Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "HoldAtRendezVous", "HoldingAtRendezVous" )
Fsm:AddProcess ( "Engaging", "Account", ACT_ACCOUNT_DEADS:New(), {} ) Fsm:AddProcess( "Engaging", "Account", ACT_ACCOUNT_DEADS:New(), {} )
Fsm:AddTransition( "Engaging", "RouteToTarget", "Engaging" ) Fsm:AddTransition( "Engaging", "RouteToTarget", "Engaging" )
Fsm:AddProcess( "Engaging", "RouteToTargetZone", ACT_ROUTE_ZONE:New(), {} ) Fsm:AddProcess( "Engaging", "RouteToTargetZone", ACT_ROUTE_ZONE:New(), {} )
Fsm:AddProcess( "Engaging", "RouteToTargetPoint", ACT_ROUTE_POINT:New(), {} ) Fsm:AddProcess( "Engaging", "RouteToTargetPoint", ACT_ROUTE_POINT:New(), {} )
Fsm:AddTransition( "Engaging", "RouteToTargets", "Engaging" ) Fsm:AddTransition( "Engaging", "RouteToTargets", "Engaging" )
-- Fsm:AddTransition( "Accounted", "DestroyedAll", "Accounted" ) -- Fsm:AddTransition( "Accounted", "DestroyedAll", "Accounted" )
-- Fsm:AddTransition( "Accounted", "Success", "Success" ) -- Fsm:AddTransition( "Accounted", "Success", "Success" )
Fsm:AddTransition( "Rejected", "Reject", "Aborted" ) Fsm:AddTransition( "Rejected", "Reject", "Aborted" )
Fsm:AddTransition( "Failed", "Fail", "Failed" ) Fsm:AddTransition( "Failed", "Fail", "Failed" )
-- @param #FSM_PROCESS self
---- @param #FSM_PROCESS self
-- @param Wrapper.Unit#UNIT TaskUnit -- @param Wrapper.Unit#UNIT TaskUnit
-- @param #TASK_CARGO Task -- @param #TASK_CARGO Task
function Fsm:OnLeaveAssigned( TaskUnit, Task ) function Fsm:OnLeaveAssigned( TaskUnit, Task )
@@ -128,7 +126,7 @@ do -- TASK_A2A
function Fsm:onafterEngage( TaskUnit, Task ) function Fsm:onafterEngage( TaskUnit, Task )
self:F( { self } ) self:F( { self } )
self:__Account( 0.1 ) self:__Account( 0.1 )
self:__RouteToTarget(0.1 ) self:__RouteToTarget( 0.1 )
self:__RouteToTargets( -10 ) self:__RouteToTargets( -10 )
end end
@@ -177,8 +175,6 @@ do -- TASK_A2A
self.TargetSetUnit = TargetSetUnit self.TargetSetUnit = TargetSetUnit
end end
--- @param #TASK_A2A self --- @param #TASK_A2A self
function TASK_A2A:GetPlannedMenuText() function TASK_A2A:GetPlannedMenuText()
return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )" return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )"
@@ -188,7 +184,7 @@ do -- TASK_A2A
-- @param Core.Point#COORDINATE RendezVousCoordinate The Coordinate object referencing to the 2D point where the RendezVous point is located on the map. -- @param Core.Point#COORDINATE RendezVousCoordinate The Coordinate object referencing to the 2D point where the RendezVous point is located on the map.
-- @param #number RendezVousRange The RendezVousRange that defines when the player is considered to have arrived at the RendezVous point. -- @param #number RendezVousRange The RendezVousRange that defines when the player is considered to have arrived at the RendezVous point.
-- @param Wrapper.Unit#UNIT TaskUnit -- @param Wrapper.Unit#UNIT TaskUnit
function TASK_A2A:SetRendezVousCoordinate( RendezVousCoordinate, RendezVousRange, TaskUnit ) function TASK_A2A:SetRendezVousCoordinate( RendezVousCoordinate, RendezVousRange, TaskUnit )
local ProcessUnit = self:GetUnitProcess( TaskUnit ) local ProcessUnit = self:GetUnitProcess( TaskUnit )
@@ -209,8 +205,6 @@ do -- TASK_A2A
return ActRouteRendezVous:GetCoordinate(), ActRouteRendezVous:GetRange() return ActRouteRendezVous:GetCoordinate(), ActRouteRendezVous:GetRange()
end end
--- @param #TASK_A2A self --- @param #TASK_A2A self
-- @param Core.Zone#ZONE_BASE RendezVousZone The Zone object where the RendezVous is located on the map. -- @param Core.Zone#ZONE_BASE RendezVousZone The Zone object where the RendezVous is located on the map.
-- @param Wrapper.Unit#UNIT TaskUnit -- @param Wrapper.Unit#UNIT TaskUnit
@@ -244,7 +238,6 @@ do -- TASK_A2A
ActRouteTarget:SetCoordinate( TargetCoordinate ) ActRouteTarget:SetCoordinate( TargetCoordinate )
end end
--- @param #TASK_A2A self --- @param #TASK_A2A self
-- @param Wrapper.Unit#UNIT TaskUnit -- @param Wrapper.Unit#UNIT TaskUnit
-- @return Core.Point#COORDINATE The Coordinate object where the Target is located on the map. -- @return Core.Point#COORDINATE The Coordinate object where the Target is located on the map.
@@ -256,7 +249,6 @@ do -- TASK_A2A
return ActRouteTarget:GetCoordinate() return ActRouteTarget:GetCoordinate()
end end
--- @param #TASK_A2A self --- @param #TASK_A2A self
-- @param Core.Zone#ZONE_BASE TargetZone The Zone object where the Target is located on the map. -- @param Core.Zone#ZONE_BASE TargetZone The Zone object where the Target is located on the map.
-- @param Wrapper.Unit#UNIT TaskUnit -- @param Wrapper.Unit#UNIT TaskUnit
@@ -268,7 +260,6 @@ do -- TASK_A2A
ActRouteTarget:SetZone( TargetZone, Altitude, Heading ) ActRouteTarget:SetZone( TargetZone, Altitude, Heading )
end end
--- @param #TASK_A2A self --- @param #TASK_A2A self
-- @param Wrapper.Unit#UNIT TaskUnit -- @param Wrapper.Unit#UNIT TaskUnit
-- @return Core.Zone#ZONE_BASE The Zone object where the Target is located on the map. -- @return Core.Zone#ZONE_BASE The Zone object where the Target is located on the map.
@@ -293,7 +284,7 @@ do -- TASK_A2A
--- Return the relative distance to the target vicinity from the player, in order to sort the targets in the reports per distance from the threats. --- Return the relative distance to the target vicinity from the player, in order to sort the targets in the reports per distance from the threats.
-- @param #TASK_A2A self -- @param #TASK_A2A self
function TASK_A2A:ReportOrder( ReportGroup ) function TASK_A2A:ReportOrder( ReportGroup )
self:UpdateTaskInfo( self.DetectedItem ) self:UpdateTaskInfo( self.DetectedItem )
local Coordinate = self.TaskInfo:GetData( "Coordinate" ) local Coordinate = self.TaskInfo:GetData( "Coordinate" )
local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate ) local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate )
@@ -301,7 +292,6 @@ do -- TASK_A2A
return Distance return Distance
end end
--- This method checks every 10 seconds if the goal has been reached of the task. --- This method checks every 10 seconds if the goal has been reached of the task.
-- @param #TASK_A2A self -- @param #TASK_A2A self
function TASK_A2A:onafterGoal( TaskUnit, From, Event, To ) function TASK_A2A:onafterGoal( TaskUnit, From, Event, To )
@@ -314,7 +304,6 @@ do -- TASK_A2A
self:__Goal( -10 ) self:__Goal( -10 )
end end
--- @param #TASK_A2A self --- @param #TASK_A2A self
function TASK_A2A:UpdateTaskInfo( DetectedItem ) function TASK_A2A:UpdateTaskInfo( DetectedItem )
@@ -360,7 +349,7 @@ do -- TASK_A2A
-- @param Wrapper.Group#GROUP TaskGroup The player group. -- @param Wrapper.Group#GROUP TaskGroup The player group.
function TASK_A2A:GetAutoAssignPriority( AutoAssignMethod, CommandCenter, TaskGroup ) function TASK_A2A:GetAutoAssignPriority( AutoAssignMethod, CommandCenter, TaskGroup )
if AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Random then if AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Random then
return math.random( 1, 9 ) return math.random( 1, 9 )
elseif AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Distance then elseif AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Distance then
local Coordinate = self.TaskInfo:GetData( "Coordinate" ) local Coordinate = self.TaskInfo:GetData( "Coordinate" )
@@ -375,7 +364,6 @@ do -- TASK_A2A
end end
do -- TASK_A2A_INTERCEPT do -- TASK_A2A_INTERCEPT
--- The TASK_A2A_INTERCEPT class --- The TASK_A2A_INTERCEPT class
@@ -384,7 +372,7 @@ do -- TASK_A2A_INTERCEPT
-- @extends Tasking.Task#TASK -- @extends Tasking.Task#TASK
--- Defines an intercept task for a human player to be executed. --- Defines an intercept task for a human player to be executed.
-- When enemy planes need to be intercepted by human players, use this task type to urgen the players to get out there! -- When enemy planes need to be intercepted by human players, use this task type to urge the players to get out there!
-- --
-- The TASK_A2A_INTERCEPT is used by the @{Tasking.Task_A2A_Dispatcher#TASK_A2A_DISPATCHER} to automatically create intercept tasks -- The TASK_A2A_INTERCEPT is used by the @{Tasking.Task_A2A_Dispatcher#TASK_A2A_DISPATCHER} to automatically create intercept tasks
-- based on detected airborne enemy targets intruding friendly airspace. -- based on detected airborne enemy targets intruding friendly airspace.
@@ -394,11 +382,9 @@ do -- TASK_A2A_INTERCEPT
-- --
-- @field #TASK_A2A_INTERCEPT -- @field #TASK_A2A_INTERCEPT
TASK_A2A_INTERCEPT = { TASK_A2A_INTERCEPT = {
ClassName = "TASK_A2A_INTERCEPT", ClassName = "TASK_A2A_INTERCEPT"
} }
--- Instantiates a new TASK_A2A_INTERCEPT. --- Instantiates a new TASK_A2A_INTERCEPT.
-- @param #TASK_A2A_INTERCEPT self -- @param #TASK_A2A_INTERCEPT self
-- @param Tasking.Mission#MISSION Mission -- @param Tasking.Mission#MISSION Mission
@@ -413,15 +399,12 @@ do -- TASK_A2A_INTERCEPT
Mission:AddTask( self ) Mission:AddTask( self )
self:SetBriefing( self:SetBriefing( TaskBriefing or "Intercept incoming intruders.\n" )
TaskBriefing or
"Intercept incoming intruders.\n"
)
return self return self
end end
--- Set a score when a target in scope of the A2A attack, has been destroyed . --- Set a score when a target in scope of the A2A attack, has been destroyed.
-- @param #TASK_A2A_INTERCEPT self -- @param #TASK_A2A_INTERCEPT self
-- @param #string PlayerName The name of the player. -- @param #string PlayerName The name of the player.
-- @param #number Score The score in points to be granted when task process has been achieved. -- @param #number Score The score in points to be granted when task process has been achieved.
@@ -469,10 +452,8 @@ do -- TASK_A2A_INTERCEPT
return self return self
end end
end end
do -- TASK_A2A_SWEEP do -- TASK_A2A_SWEEP
--- The TASK_A2A_SWEEP class --- The TASK_A2A_SWEEP class
@@ -493,11 +474,9 @@ do -- TASK_A2A_SWEEP
-- --
-- @field #TASK_A2A_SWEEP -- @field #TASK_A2A_SWEEP
TASK_A2A_SWEEP = { TASK_A2A_SWEEP = {
ClassName = "TASK_A2A_SWEEP", ClassName = "TASK_A2A_SWEEP"
} }
--- Instantiates a new TASK_A2A_SWEEP. --- Instantiates a new TASK_A2A_SWEEP.
-- @param #TASK_A2A_SWEEP self -- @param #TASK_A2A_SWEEP self
-- @param Tasking.Mission#MISSION Mission -- @param Tasking.Mission#MISSION Mission
@@ -512,10 +491,7 @@ do -- TASK_A2A_SWEEP
Mission:AddTask( self ) Mission:AddTask( self )
self:SetBriefing( self:SetBriefing( TaskBriefing or "Perform a fighter sweep. Incoming intruders were detected and could be hiding at the location.\n" )
TaskBriefing or
"Perform a fighter sweep. Incoming intruders were detected and could be hiding at the location.\n"
)
return self return self
end end
@@ -531,7 +507,7 @@ do -- TASK_A2A_SWEEP
self:__Goal( -10 ) self:__Goal( -10 )
end end
--- Set a score when a target in scope of the A2A attack, has been destroyed . --- Set a score when a target in scope of the A2A attack, has been destroyed.
-- @param #TASK_A2A_SWEEP self -- @param #TASK_A2A_SWEEP self
-- @param #string PlayerName The name of the player. -- @param #string PlayerName The name of the player.
-- @param #number Score The score in points to be granted when task process has been achieved. -- @param #number Score The score in points to be granted when task process has been achieved.
@@ -581,7 +557,6 @@ do -- TASK_A2A_SWEEP
end end
do -- TASK_A2A_ENGAGE do -- TASK_A2A_ENGAGE
--- The TASK_A2A_ENGAGE class --- The TASK_A2A_ENGAGE class
@@ -600,11 +575,9 @@ do -- TASK_A2A_ENGAGE
-- --
-- @field #TASK_A2A_ENGAGE -- @field #TASK_A2A_ENGAGE
TASK_A2A_ENGAGE = { TASK_A2A_ENGAGE = {
ClassName = "TASK_A2A_ENGAGE", ClassName = "TASK_A2A_ENGAGE"
} }
--- Instantiates a new TASK_A2A_ENGAGE. --- Instantiates a new TASK_A2A_ENGAGE.
-- @param #TASK_A2A_ENGAGE self -- @param #TASK_A2A_ENGAGE self
-- @param Tasking.Mission#MISSION Mission -- @param Tasking.Mission#MISSION Mission
@@ -619,10 +592,7 @@ do -- TASK_A2A_ENGAGE
Mission:AddTask( self ) Mission:AddTask( self )
self:SetBriefing( self:SetBriefing( TaskBriefing or "Bogeys are nearby! Players close by are ordered to ENGAGE the intruders!\n" )
TaskBriefing or
"Bogeys are nearby! Players close by are ordered to ENGAGE the intruders!\n"
)
return self return self
end end
@@ -108,7 +108,7 @@ do -- TASK_A2A_DISPATCHER
-- The above example creates a SET_GROUP instance, and stores this in the variable (object) **EWRSet**. -- The above example creates a SET_GROUP instance, and stores this in the variable (object) **EWRSet**.
-- **EWRSet** is then being configured to filter all active groups with a group name starting with **EWR** to be included in the Set. -- **EWRSet** is then being configured to filter all active groups with a group name starting with **EWR** to be included in the Set.
-- **EWRSet** is then being ordered to start the dynamic filtering. Note that any destroy or new spawn of a group with the above names will be removed or added to the Set. -- **EWRSet** is then being ordered to start the dynamic filtering. Note that any destroy or new spawn of a group with the above names will be removed or added to the Set.
-- Then a new **EWRDetection** object is created from the class DETECTION_AREAS. A grouping radius of 6000 is choosen, which is 6km. -- Then a new **EWRDetection** object is created from the class DETECTION_AREAS. A grouping radius of 6000 is chosen, which is 6 km.
-- The **EWRDetection** object is then passed to the @{#TASK_A2A_DISPATCHER.New}() method to indicate the EWR network configuration and setup the A2A tasking and detection mechanism. -- The **EWRDetection** object is then passed to the @{#TASK_A2A_DISPATCHER.New}() method to indicate the EWR network configuration and setup the A2A tasking and detection mechanism.
-- --
-- ### 2. Define the detected **target grouping radius**: -- ### 2. Define the detected **target grouping radius**:
@@ -185,7 +185,6 @@ do -- TASK_A2A_DISPATCHER
SweepZones = {}, SweepZones = {},
} }
--- TASK_A2A_DISPATCHER constructor. --- TASK_A2A_DISPATCHER constructor.
-- @param #TASK_A2A_DISPATCHER self -- @param #TASK_A2A_DISPATCHER self
-- @param Tasking.Mission#MISSION Mission The mission for which the task dispatching is done. -- @param Tasking.Mission#MISSION Mission The mission for which the task dispatching is done.
@@ -208,7 +207,6 @@ do -- TASK_A2A_DISPATCHER
self:AddTransition( "Started", "Assign", "Started" ) self:AddTransition( "Started", "Assign", "Started" )
--- OnAfter Transition Handler for Event Assign. --- OnAfter Transition Handler for Event Assign.
-- @function [parent=#TASK_A2A_DISPATCHER] OnAfterAssign -- @function [parent=#TASK_A2A_DISPATCHER] OnAfterAssign
-- @param #TASK_A2A_DISPATCHER self -- @param #TASK_A2A_DISPATCHER self
@@ -224,7 +222,6 @@ do -- TASK_A2A_DISPATCHER
return self return self
end end
--- Define the radius to when an ENGAGE task will be generated for any nearby by airborne friendlies, which are executing cap or returning from an intercept mission. --- Define the radius to when an ENGAGE task will be generated for any nearby by airborne friendlies, which are executing cap or returning from an intercept mission.
-- So, if there is a target area detected and reported, -- So, if there is a target area detected and reported,
-- then any friendlies that are airborne near this target area, -- then any friendlies that are airborne near this target area,
@@ -257,7 +254,7 @@ do -- TASK_A2A_DISPATCHER
-- @param #TASK_A2A_DISPATCHER self -- @param #TASK_A2A_DISPATCHER self
-- @param #boolean onoff Set messages on (true) or off (false) -- @param #boolean onoff Set messages on (true) or off (false)
function TASK_A2A_DISPATCHER:SetSendMessages( onoff ) function TASK_A2A_DISPATCHER:SetSendMessages( onoff )
self.FlashNewTask = onoff self.FlashNewTask = onoff
end end
--- Creates an INTERCEPT task when there are targets for it. --- Creates an INTERCEPT task when there are targets for it.
@@ -286,7 +283,6 @@ do -- TASK_A2A_DISPATCHER
return nil return nil
end end
--- Creates an SWEEP task when there are targets for it. --- Creates an SWEEP task when there are targets for it.
-- @param #TASK_A2A_DISPATCHER self -- @param #TASK_A2A_DISPATCHER self
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
@@ -296,8 +292,7 @@ do -- TASK_A2A_DISPATCHER
self:F( { DetectedItem.ItemID } ) self:F( { DetectedItem.ItemID } )
local DetectedSet = DetectedItem.Set local DetectedSet = DetectedItem.Set
local DetectedZone = DetectedItem.Zone local DetectedZone = DetectedItem.Zone -- TODO: This seems unused, remove?
if DetectedItem.IsDetected == false then if DetectedItem.IsDetected == false then
@@ -312,7 +307,6 @@ do -- TASK_A2A_DISPATCHER
return nil return nil
end end
--- Creates an ENGAGE task when there are human friendlies airborne near the targets. --- Creates an ENGAGE task when there are human friendlies airborne near the targets.
-- @param #TASK_A2A_DISPATCHER self -- @param #TASK_A2A_DISPATCHER self
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
@@ -322,11 +316,10 @@ do -- TASK_A2A_DISPATCHER
self:F( { DetectedItem.ItemID } ) self:F( { DetectedItem.ItemID } )
local DetectedSet = DetectedItem.Set local DetectedSet = DetectedItem.Set
local DetectedZone = DetectedItem.Zone local DetectedZone = DetectedItem.Zone -- TODO: This seems unused, remove?
local PlayersCount, PlayersReport = self:GetPlayerFriendliesNearBy( DetectedItem ) local PlayersCount, PlayersReport = self:GetPlayerFriendliesNearBy( DetectedItem )
-- Only allow ENGAGE when there are Players near the zone, and when the Area has detected items since the last run in a 60 seconds time zone. -- Only allow ENGAGE when there are Players near the zone, and when the Area has detected items since the last run in a 60 seconds time zone.
if PlayersCount > 0 and DetectedItem.IsDetected == true then if PlayersCount > 0 and DetectedItem.IsDetected == true then
@@ -341,9 +334,6 @@ do -- TASK_A2A_DISPATCHER
return nil return nil
end end
--- Evaluates the removal of the Task from the Mission. --- Evaluates the removal of the Task from the Mission.
-- Can only occur when the DetectedItem is Changed AND the state of the Task is "Planned". -- Can only occur when the DetectedItem is Changed AND the state of the Task is "Planned".
-- @param #TASK_A2A_DISPATCHER self -- @param #TASK_A2A_DISPATCHER self
@@ -388,8 +378,8 @@ do -- TASK_A2A_DISPATCHER
end end
local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT
--DetectedSet:Flush( self ) -- DetectedSet:Flush( self )
--self:F( { DetectedSetCount = DetectedSet:Count() } ) -- self:F( { DetectedSetCount = DetectedSet:Count() } )
if DetectedSet:Count() == 0 then if DetectedSet:Count() == 0 then
Remove = true Remove = true
end end
@@ -423,7 +413,7 @@ do -- TASK_A2A_DISPATCHER
local FriendlyUnitThreatLevel = FriendlyUnit:GetThreatLevel() local FriendlyUnitThreatLevel = FriendlyUnit:GetThreatLevel()
FriendliesCount = FriendliesCount + 1 FriendliesCount = FriendliesCount + 1
local FriendlyType = FriendlyUnit:GetTypeName() local FriendlyType = FriendlyUnit:GetTypeName()
FriendlyTypes[FriendlyType] = FriendlyTypes[FriendlyType] and ( FriendlyTypes[FriendlyType] + 1 ) or 1 FriendlyTypes[FriendlyType] = FriendlyTypes[FriendlyType] and (FriendlyTypes[FriendlyType] + 1) or 1
if DetectedTreatLevel < FriendlyUnitThreatLevel + 2 then if DetectedTreatLevel < FriendlyUnitThreatLevel + 2 then
end end
end end
@@ -431,19 +421,18 @@ do -- TASK_A2A_DISPATCHER
end end
--self:F( { FriendliesCount = FriendliesCount } ) -- self:F( { FriendliesCount = FriendliesCount } )
local FriendlyTypesReport = REPORT:New() local FriendlyTypesReport = REPORT:New()
if FriendliesCount > 0 then if FriendliesCount > 0 then
for FriendlyType, FriendlyTypeCount in pairs( FriendlyTypes ) do for FriendlyType, FriendlyTypeCount in pairs( FriendlyTypes ) do
FriendlyTypesReport:Add( string.format("%d of %s", FriendlyTypeCount, FriendlyType ) ) FriendlyTypesReport:Add( string.format( "%d of %s", FriendlyTypeCount, FriendlyType ) )
end end
else else
FriendlyTypesReport:Add( "-" ) FriendlyTypesReport:Add( "-" )
end end
return FriendliesCount, FriendlyTypesReport return FriendliesCount, FriendlyTypesReport
end end
@@ -464,7 +453,7 @@ do -- TASK_A2A_DISPATCHER
for PlayerUnitName, PlayerUnitData in pairs( PlayersNearBy ) do for PlayerUnitName, PlayerUnitData in pairs( PlayersNearBy ) do
local PlayerUnit = PlayerUnitData -- Wrapper.Unit#UNIT local PlayerUnit = PlayerUnitData -- Wrapper.Unit#UNIT
local PlayerName = PlayerUnit:GetPlayerName() local PlayerName = PlayerUnit:GetPlayerName()
--self:F( { PlayerName = PlayerName, PlayerUnit = PlayerUnit } ) -- self:F( { PlayerName = PlayerName, PlayerUnit = PlayerUnit } )
if PlayerUnit:IsAirPlane() and PlayerName ~= nil then if PlayerUnit:IsAirPlane() and PlayerName ~= nil then
local FriendlyUnitThreatLevel = PlayerUnit:GetThreatLevel() local FriendlyUnitThreatLevel = PlayerUnit:GetThreatLevel()
PlayersCount = PlayersCount + 1 PlayersCount = PlayersCount + 1
@@ -481,13 +470,12 @@ do -- TASK_A2A_DISPATCHER
if PlayersCount > 0 then if PlayersCount > 0 then
for PlayerName, PlayerType in pairs( PlayerTypes ) do for PlayerName, PlayerType in pairs( PlayerTypes ) do
PlayerTypesReport:Add( string.format('"%s" in %s', PlayerName, PlayerType ) ) PlayerTypesReport:Add( string.format( '"%s" in %s', PlayerName, PlayerType ) )
end end
else else
PlayerTypesReport:Add( "-" ) PlayerTypesReport:Add( "-" )
end end
return PlayersCount, PlayerTypesReport return PlayersCount, PlayerTypesReport
end end
@@ -496,7 +484,6 @@ do -- TASK_A2A_DISPATCHER
self.Tasks[TaskIndex] = nil self.Tasks[TaskIndex] = nil
end end
--- Assigns tasks in relation to the detected items to the @{Core.Set#SET_GROUP}. --- Assigns tasks in relation to the detected items to the @{Core.Set#SET_GROUP}.
-- @param #TASK_A2A_DISPATCHER self -- @param #TASK_A2A_DISPATCHER self
-- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Functional.Detection#DETECTION_BASE} derived object. -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Functional.Detection#DETECTION_BASE} derived object.
@@ -536,8 +523,8 @@ do -- TASK_A2A_DISPATCHER
local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT
local DetectedCount = DetectedSet:Count() local DetectedCount = DetectedSet:Count()
local DetectedZone = DetectedItem.Zone local DetectedZone = DetectedItem.Zone
--self:F( { "Targets in DetectedItem", DetectedItem.ItemID, DetectedSet:Count(), tostring( DetectedItem ) } ) -- self:F( { "Targets in DetectedItem", DetectedItem.ItemID, DetectedSet:Count(), tostring( DetectedItem ) } )
--DetectedSet:Flush( self ) -- DetectedSet:Flush( self )
local DetectedID = DetectedItem.ID local DetectedID = DetectedItem.ID
local TaskIndex = DetectedItem.Index local TaskIndex = DetectedItem.Index
@@ -593,7 +580,7 @@ do -- TASK_A2A_DISPATCHER
TaskReport:Add( Task:GetName() ) TaskReport:Add( Task:GetName() )
else else
self:F("This should not happen") self:F( "This should not happen" )
end end
end end
@@ -612,10 +599,10 @@ do -- TASK_A2A_DISPATCHER
-- TODO set menus using the HQ coordinator -- TODO set menus using the HQ coordinator
Mission:GetCommandCenter():SetMenu() Mission:GetCommandCenter():SetMenu()
local TaskText = TaskReport:Text(", ") local TaskText = TaskReport:Text( ", " )
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" and (self.FlashNewTask) then if (not Mission:IsGroupAssigned( TaskGroup )) and TaskText ~= "" and (self.FlashNewTask) then
Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup ) Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup )
end end
end end
+18 -50
View File
@@ -38,7 +38,7 @@ do -- TASK_A2G
-- --
-- @field #TASK_A2G -- @field #TASK_A2G
TASK_A2G = { TASK_A2G = {
ClassName = "TASK_A2G", ClassName = "TASK_A2G"
} }
--- Instantiates a new TASK_A2G. --- Instantiates a new TASK_A2G.
@@ -61,27 +61,25 @@ do -- TASK_A2G
local Fsm = self:GetUnitProcess() local Fsm = self:GetUnitProcess()
Fsm:AddTransition( "Assigned", "RouteToRendezVous", "RoutingToRendezVous" ) Fsm:AddTransition( "Assigned", "RouteToRendezVous", "RoutingToRendezVous" )
Fsm:AddProcess ( "RoutingToRendezVous", "RouteToRendezVousPoint", ACT_ROUTE_POINT:New(), { Arrived = "ArriveAtRendezVous" } ) Fsm:AddProcess( "RoutingToRendezVous", "RouteToRendezVousPoint", ACT_ROUTE_POINT:New(), { Arrived = "ArriveAtRendezVous" } )
Fsm:AddProcess ( "RoutingToRendezVous", "RouteToRendezVousZone", ACT_ROUTE_ZONE:New(), { Arrived = "ArriveAtRendezVous" } ) Fsm:AddProcess( "RoutingToRendezVous", "RouteToRendezVousZone", ACT_ROUTE_ZONE:New(), { Arrived = "ArriveAtRendezVous" } )
Fsm:AddTransition( { "Arrived", "RoutingToRendezVous" }, "ArriveAtRendezVous", "ArrivedAtRendezVous" ) Fsm:AddTransition( { "Arrived", "RoutingToRendezVous" }, "ArriveAtRendezVous", "ArrivedAtRendezVous" )
Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "Engage", "Engaging" ) Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "Engage", "Engaging" )
Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "HoldAtRendezVous", "HoldingAtRendezVous" ) Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "HoldAtRendezVous", "HoldingAtRendezVous" )
Fsm:AddProcess ( "Engaging", "Account", ACT_ACCOUNT_DEADS:New(), {} ) Fsm:AddProcess( "Engaging", "Account", ACT_ACCOUNT_DEADS:New(), {} )
Fsm:AddTransition( "Engaging", "RouteToTarget", "Engaging" ) Fsm:AddTransition( "Engaging", "RouteToTarget", "Engaging" )
Fsm:AddProcess( "Engaging", "RouteToTargetZone", ACT_ROUTE_ZONE:New(), {} ) Fsm:AddProcess( "Engaging", "RouteToTargetZone", ACT_ROUTE_ZONE:New(), {} )
Fsm:AddProcess( "Engaging", "RouteToTargetPoint", ACT_ROUTE_POINT:New(), {} ) Fsm:AddProcess( "Engaging", "RouteToTargetPoint", ACT_ROUTE_POINT:New(), {} )
Fsm:AddTransition( "Engaging", "RouteToTargets", "Engaging" ) Fsm:AddTransition( "Engaging", "RouteToTargets", "Engaging" )
--Fsm:AddTransition( "Accounted", "DestroyedAll", "Accounted" ) -- Fsm:AddTransition( "Accounted", "DestroyedAll", "Accounted" )
--Fsm:AddTransition( "Accounted", "Success", "Success" ) -- Fsm:AddTransition( "Accounted", "Success", "Success" )
Fsm:AddTransition( "Rejected", "Reject", "Aborted" ) Fsm:AddTransition( "Rejected", "Reject", "Aborted" )
Fsm:AddTransition( "Failed", "Fail", "Failed" ) Fsm:AddTransition( "Failed", "Fail", "Failed" )
--- Test --- Test
-- @param #FSM_PROCESS self -- @param #FSM_PROCESS self
-- @param Wrapper.Unit#UNIT TaskUnit -- @param Wrapper.Unit#UNIT TaskUnit
@@ -130,7 +128,7 @@ do -- TASK_A2G
function Fsm:onafterEngage( TaskUnit, Task ) function Fsm:onafterEngage( TaskUnit, Task )
self:F( { self } ) self:F( { self } )
self:__Account( 0.1 ) self:__Account( 0.1 )
self:__RouteToTarget(0.1 ) self:__RouteToTarget( 0.1 )
self:__RouteToTargets( -10 ) self:__RouteToTargets( -10 )
end end
@@ -179,8 +177,6 @@ do -- TASK_A2G
self.TargetSetUnit = TargetSetUnit self.TargetSetUnit = TargetSetUnit
end end
--- @param #TASK_A2G self --- @param #TASK_A2G self
function TASK_A2G:GetPlannedMenuText() function TASK_A2G:GetPlannedMenuText()
return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )" return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )"
@@ -190,7 +186,7 @@ do -- TASK_A2G
-- @param Core.Point#COORDINATE RendezVousCoordinate The Coordinate object referencing to the 2D point where the RendezVous point is located on the map. -- @param Core.Point#COORDINATE RendezVousCoordinate The Coordinate object referencing to the 2D point where the RendezVous point is located on the map.
-- @param #number RendezVousRange The RendezVousRange that defines when the player is considered to have arrived at the RendezVous point. -- @param #number RendezVousRange The RendezVousRange that defines when the player is considered to have arrived at the RendezVous point.
-- @param Wrapper.Unit#UNIT TaskUnit -- @param Wrapper.Unit#UNIT TaskUnit
function TASK_A2G:SetRendezVousCoordinate( RendezVousCoordinate, RendezVousRange, TaskUnit ) function TASK_A2G:SetRendezVousCoordinate( RendezVousCoordinate, RendezVousRange, TaskUnit )
local ProcessUnit = self:GetUnitProcess( TaskUnit ) local ProcessUnit = self:GetUnitProcess( TaskUnit )
@@ -211,8 +207,6 @@ do -- TASK_A2G
return ActRouteRendezVous:GetCoordinate(), ActRouteRendezVous:GetRange() return ActRouteRendezVous:GetCoordinate(), ActRouteRendezVous:GetRange()
end end
--- @param #TASK_A2G self --- @param #TASK_A2G self
-- @param Core.Zone#ZONE_BASE RendezVousZone The Zone object where the RendezVous is located on the map. -- @param Core.Zone#ZONE_BASE RendezVousZone The Zone object where the RendezVous is located on the map.
-- @param Wrapper.Unit#UNIT TaskUnit -- @param Wrapper.Unit#UNIT TaskUnit
@@ -246,7 +240,6 @@ do -- TASK_A2G
ActRouteTarget:SetCoordinate( TargetCoordinate ) ActRouteTarget:SetCoordinate( TargetCoordinate )
end end
--- @param #TASK_A2G self --- @param #TASK_A2G self
-- @param Wrapper.Unit#UNIT TaskUnit -- @param Wrapper.Unit#UNIT TaskUnit
-- @return Core.Point#COORDINATE The Coordinate object where the Target is located on the map. -- @return Core.Point#COORDINATE The Coordinate object where the Target is located on the map.
@@ -258,7 +251,6 @@ do -- TASK_A2G
return ActRouteTarget:GetCoordinate() return ActRouteTarget:GetCoordinate()
end end
--- @param #TASK_A2G self --- @param #TASK_A2G self
-- @param Core.Zone#ZONE_BASE TargetZone The Zone object where the Target is located on the map. -- @param Core.Zone#ZONE_BASE TargetZone The Zone object where the Target is located on the map.
-- @param Wrapper.Unit#UNIT TaskUnit -- @param Wrapper.Unit#UNIT TaskUnit
@@ -270,7 +262,6 @@ do -- TASK_A2G
ActRouteTarget:SetZone( TargetZone ) ActRouteTarget:SetZone( TargetZone )
end end
--- @param #TASK_A2G self --- @param #TASK_A2G self
-- @param Wrapper.Unit#UNIT TaskUnit -- @param Wrapper.Unit#UNIT TaskUnit
-- @return Core.Zone#ZONE_BASE The Zone object where the Target is located on the map. -- @return Core.Zone#ZONE_BASE The Zone object where the Target is located on the map.
@@ -295,7 +286,7 @@ do -- TASK_A2G
--- Return the relative distance to the target vicinity from the player, in order to sort the targets in the reports per distance from the threats. --- Return the relative distance to the target vicinity from the player, in order to sort the targets in the reports per distance from the threats.
-- @param #TASK_A2G self -- @param #TASK_A2G self
function TASK_A2G:ReportOrder( ReportGroup ) function TASK_A2G:ReportOrder( ReportGroup )
self:UpdateTaskInfo( self.DetectedItem ) self:UpdateTaskInfo( self.DetectedItem )
local Coordinate = self.TaskInfo:GetData( "Coordinate" ) local Coordinate = self.TaskInfo:GetData( "Coordinate" )
local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate ) local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate )
@@ -303,7 +294,6 @@ do -- TASK_A2G
return Distance return Distance
end end
--- This method checks every 10 seconds if the goal has been reached of the task. --- This method checks every 10 seconds if the goal has been reached of the task.
-- @param #TASK_A2G self -- @param #TASK_A2G self
function TASK_A2G:onafterGoal( TaskUnit, From, Event, To ) function TASK_A2G:onafterGoal( TaskUnit, From, Event, To )
@@ -365,12 +355,12 @@ do -- TASK_A2G
-- @param Wrapper.Group#GROUP TaskGroup The player group. -- @param Wrapper.Group#GROUP TaskGroup The player group.
function TASK_A2G:GetAutoAssignPriority( AutoAssignMethod, CommandCenter, TaskGroup ) function TASK_A2G:GetAutoAssignPriority( AutoAssignMethod, CommandCenter, TaskGroup )
if AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Random then if AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Random then
return math.random( 1, 9 ) return math.random( 1, 9 )
elseif AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Distance then elseif AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Distance then
local Coordinate = self.TaskInfo:GetData( "Coordinate" ) local Coordinate = self.TaskInfo:GetData( "Coordinate" )
local Distance = Coordinate:Get2DDistance( CommandCenter:GetPositionable():GetCoordinate() ) local Distance = Coordinate:Get2DDistance( CommandCenter:GetPositionable():GetCoordinate() )
self:F({Distance=Distance}) self:F( { Distance = Distance } )
return math.floor( Distance ) return math.floor( Distance )
elseif AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Priority then elseif AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Priority then
return 1 return 1
@@ -381,7 +371,6 @@ do -- TASK_A2G
end end
do -- TASK_A2G_SEAD do -- TASK_A2G_SEAD
--- The TASK_A2G_SEAD class --- The TASK_A2G_SEAD class
@@ -397,7 +386,7 @@ do -- TASK_A2G_SEAD
-- --
-- @field #TASK_A2G_SEAD -- @field #TASK_A2G_SEAD
TASK_A2G_SEAD = { TASK_A2G_SEAD = {
ClassName = "TASK_A2G_SEAD", ClassName = "TASK_A2G_SEAD"
} }
--- Instantiates a new TASK_A2G_SEAD. --- Instantiates a new TASK_A2G_SEAD.
@@ -408,16 +397,13 @@ do -- TASK_A2G_SEAD
-- @param Core.Set#SET_UNIT TargetSetUnit -- @param Core.Set#SET_UNIT TargetSetUnit
-- @param #string TaskBriefing The briefing of the task. -- @param #string TaskBriefing The briefing of the task.
-- @return #TASK_A2G_SEAD self -- @return #TASK_A2G_SEAD self
function TASK_A2G_SEAD:New( Mission, SetGroup, TaskName, TargetSetUnit, TaskBriefing) function TASK_A2G_SEAD:New( Mission, SetGroup, TaskName, TargetSetUnit, TaskBriefing )
local self = BASE:Inherit( self, TASK_A2G:New( Mission, SetGroup, TaskName, TargetSetUnit, "SEAD", TaskBriefing ) ) -- #TASK_A2G_SEAD local self = BASE:Inherit( self, TASK_A2G:New( Mission, SetGroup, TaskName, TargetSetUnit, "SEAD", TaskBriefing ) ) -- #TASK_A2G_SEAD
self:F() self:F()
Mission:AddTask( self ) Mission:AddTask( self )
self:SetBriefing( self:SetBriefing( TaskBriefing or "Execute a Suppression of Enemy Air Defenses." )
TaskBriefing or
"Execute a Suppression of Enemy Air Defenses."
)
return self return self
end end
@@ -470,7 +456,6 @@ do -- TASK_A2G_SEAD
return self return self
end end
end end
do -- TASK_A2G_BAI do -- TASK_A2G_BAI
@@ -488,9 +473,7 @@ do -- TASK_A2G_BAI
-- based on detected enemy ground targets. -- based on detected enemy ground targets.
-- --
-- @field #TASK_A2G_BAI -- @field #TASK_A2G_BAI
TASK_A2G_BAI = { TASK_A2G_BAI = { ClassName = "TASK_A2G_BAI" }
ClassName = "TASK_A2G_BAI",
}
--- Instantiates a new TASK_A2G_BAI. --- Instantiates a new TASK_A2G_BAI.
-- @param #TASK_A2G_BAI self -- @param #TASK_A2G_BAI self
@@ -506,10 +489,7 @@ do -- TASK_A2G_BAI
Mission:AddTask( self ) Mission:AddTask( self )
self:SetBriefing( self:SetBriefing( TaskBriefing or "Execute a Battlefield Air Interdiction of a group of enemy targets." )
TaskBriefing or
"Execute a Battlefield Air Interdiction of a group of enemy targets."
)
return self return self
end end
@@ -564,9 +544,6 @@ do -- TASK_A2G_BAI
end end
do -- TASK_A2G_CAS do -- TASK_A2G_CAS
--- The TASK_A2G_CAS class --- The TASK_A2G_CAS class
@@ -581,9 +558,7 @@ do -- TASK_A2G_CAS
-- based on detected enemy ground targets. -- based on detected enemy ground targets.
-- --
-- @field #TASK_A2G_CAS -- @field #TASK_A2G_CAS
TASK_A2G_CAS = { TASK_A2G_CAS = { ClassName = "TASK_A2G_CAS" }
ClassName = "TASK_A2G_CAS",
}
--- Instantiates a new TASK_A2G_CAS. --- Instantiates a new TASK_A2G_CAS.
-- @param #TASK_A2G_CAS self -- @param #TASK_A2G_CAS self
@@ -599,17 +574,11 @@ do -- TASK_A2G_CAS
Mission:AddTask( self ) Mission:AddTask( self )
self:SetBriefing( self:SetBriefing( TaskBriefing or ( "Execute a Close Air Support for a group of enemy targets. " .. "Beware of friendlies at the vicinity! " ) )
TaskBriefing or
"Execute a Close Air Support for a group of enemy targets. " ..
"Beware of friendlies at the vicinity! "
)
return self return self
end end
--- Set a score when a target in scope of the A2G attack, has been destroyed . --- Set a score when a target in scope of the A2G attack, has been destroyed .
-- @param #TASK_A2G_CAS self -- @param #TASK_A2G_CAS self
-- @param #string PlayerName The name of the player. -- @param #string PlayerName The name of the player.
@@ -658,5 +627,4 @@ do -- TASK_A2G_CAS
return self return self
end end
end end
@@ -6,11 +6,12 @@
-- * Dynamically change the tasks as the tactical situation evolves during the mission. -- * Dynamically change the tasks as the tactical situation evolves during the mission.
-- * Dynamically assign (CAS) Close Air Support tasks for human players. -- * Dynamically assign (CAS) Close Air Support tasks for human players.
-- * Dynamically assign (BAI) Battlefield Air Interdiction tasks for human players. -- * Dynamically assign (BAI) Battlefield Air Interdiction tasks for human players.
-- * Dynamically assign (SEAD) Supression of Enemy Air Defense tasks for human players to eliminate G2A missile threats. -- * Dynamically assign (SEAD) Suppression of Enemy Air Defense tasks for human players to eliminate G2A missile threats.
-- * Define and use an EWR (Early Warning Radar) network. -- * Define and use an EWR (Early Warning Radar) network.
-- * Define different ranges to engage upon intruders. -- * Define different ranges to engage upon intruders.
-- * Keep task achievements. -- * Keep task achievements.
-- * Score task achievements.-- -- * Score task achievements.
--
-- === -- ===
-- --
-- ### Author: **FlightControl** -- ### Author: **FlightControl**
@@ -122,7 +123,7 @@ do -- TASK_A2G_DISPATCHER
-- F1. Command Center [Lima] -- F1. Command Center [Lima]
-- F1. Mission "Overlord (High)" -- F1. Mission "Overlord (High)"
-- --
-- Command Center [Gori] is controlling Mission "Alpha", "Beta", "Gamma". Alpha is the Primary mission, Beta the Secondary and there is a Tacical mission Gamma. -- Command Center [Gori] is controlling Mission "Alpha", "Beta", "Gamma". Alpha is the Primary mission, Beta the Secondary and there is a Tactical mission Gamma.
-- Command Center [Lima] is controlling Missions "Overlord", which needs to be executed with High priority. -- Command Center [Lima] is controlling Missions "Overlord", which needs to be executed with High priority.
-- --
-- ## 1.1. Mission Menu (Under the Command Center Menu) -- ## 1.1. Mission Menu (Under the Command Center Menu)
@@ -196,7 +197,7 @@ do -- TASK_A2G_DISPATCHER
-- --
-- The Mission Reports Menu is a sub menu, that provides options to retrieve further information on the current Mission: -- The Mission Reports Menu is a sub menu, that provides options to retrieve further information on the current Mission:
-- --
-- - **Report Mission Progress**: Shows the progress of the current Mission. Each Task has a %-tage of completion. -- - **Report Mission Progress**: Shows the progress of the current Mission. Each Task has a % of completion.
-- - **Report Players per Task**: Show which players are engaged on which Task within the Mission. -- - **Report Players per Task**: Show which players are engaged on which Task within the Mission.
-- --
-- For CC |Gori|, Mission "Alpha", the Mission Reports menu structure could look like this: -- For CC |Gori|, Mission "Alpha", the Mission Reports menu structure could look like this:
@@ -264,7 +265,6 @@ do -- TASK_A2G_DISPATCHER
-- --
-- **The F5. Assigned Task __TaskName__ allows the player to control the current Assigned Task and take further actions.** -- **The F5. Assigned Task __TaskName__ allows the player to control the current Assigned Task and take further actions.**
-- --
--
-- ## 1.3. Join Planned Task Menu -- ## 1.3. Join Planned Task Menu
-- --
-- The Join Planned Task Menu contains the different Planned A2G Tasks **in a structured Menu Hierarchy**. -- The Join Planned Task Menu contains the different Planned A2G Tasks **in a structured Menu Hierarchy**.
@@ -388,7 +388,7 @@ do -- TASK_A2G_DISPATCHER
-- - A @{Mission} object. Each task belongs to a Mission. -- - A @{Mission} object. Each task belongs to a Mission.
-- - A @{Detection} object. There are several detection grouping methods to choose from. -- - A @{Detection} object. There are several detection grouping methods to choose from.
-- - A @{Task_A2G_Dispatcher} object. The master A2G task dispatcher. -- - A @{Task_A2G_Dispatcher} object. The master A2G task dispatcher.
-- - A @{Set} of @{Wrapper.Group} objects that will detect the emeny, the RecceSet. This is attached to the @{Detection} object. -- - A @{Set} of @{Wrapper.Group} objects that will detect the enemy, the RecceSet. This is attached to the @{Detection} object.
-- - A @{Set} ob @{Wrapper.Group} objects that will attack the enemy, the AttackSet. This is attached to the @{Task_A2G_Dispatcher} object. -- - A @{Set} ob @{Wrapper.Group} objects that will attack the enemy, the AttackSet. This is attached to the @{Task_A2G_Dispatcher} object.
-- --
-- Below an example mission declaration that is defines a Task A2G Dispatcher object. -- Below an example mission declaration that is defines a Task A2G Dispatcher object.
@@ -425,7 +425,7 @@ do -- TASK_A2G_DISPATCHER
-- --
-- -- Now we have everything to setup the main A2G TaskDispatcher. -- -- Now we have everything to setup the main A2G TaskDispatcher.
-- TaskDispatcher = TASK_A2G_DISPATCHER -- TaskDispatcher = TASK_A2G_DISPATCHER
-- :New( Mission, AttackSet, DetectionAreas ) -- We assign the TaskDispatcher under Mission. The AttackSet will engage the enemy and will recieve the dispatched Tasks. The DetectionAreas will report any detected enemies to the TaskDispatcher. -- :New( Mission, AttackSet, DetectionAreas ) -- We assign the TaskDispatcher under Mission. The AttackSet will engage the enemy and will receive the dispatched Tasks. The DetectionAreas will report any detected enemies to the TaskDispatcher.
-- --
-- --
-- --
@@ -434,10 +434,9 @@ do -- TASK_A2G_DISPATCHER
ClassName = "TASK_A2G_DISPATCHER", ClassName = "TASK_A2G_DISPATCHER",
Mission = nil, Mission = nil,
Detection = nil, Detection = nil,
Tasks = {}, Tasks = {}
} }
--- TASK_A2G_DISPATCHER constructor. --- TASK_A2G_DISPATCHER constructor.
-- @param #TASK_A2G_DISPATCHER self -- @param #TASK_A2G_DISPATCHER self
-- @param Tasking.Mission#MISSION Mission The mission for which the task dispatching is done. -- @param Tasking.Mission#MISSION Mission The mission for which the task dispatching is done.
@@ -451,7 +450,7 @@ do -- TASK_A2G_DISPATCHER
self.Detection = Detection self.Detection = Detection
self.Mission = Mission self.Mission = Mission
self.FlashNewTask = true --set to false to suppress flash messages self.FlashNewTask = true -- set to false to suppress flash messages
self.Detection:FilterCategories( { Unit.Category.GROUND_UNIT } ) self.Detection:FilterCategories( { Unit.Category.GROUND_UNIT } )
@@ -472,11 +471,11 @@ do -- TASK_A2G_DISPATCHER
return self return self
end end
--- Set flashing player messages on or off --- Set flashing player messages on or off
-- @param #TASK_A2G_DISPATCHER self -- @param #TASK_A2G_DISPATCHER self
-- @param #boolean onoff Set messages on (true) or off (false) -- @param #boolean onoff Set messages on (true) or off (false)
function TASK_A2G_DISPATCHER:SetSendMessages( onoff ) function TASK_A2G_DISPATCHER:SetSendMessages( onoff )
self.FlashNewTask = onoff self.FlashNewTask = onoff
end end
--- Creates a SEAD task when there are targets for it. --- Creates a SEAD task when there are targets for it.
@@ -518,7 +517,6 @@ do -- TASK_A2G_DISPATCHER
local DetectedSet = DetectedItem.Set local DetectedSet = DetectedItem.Set
local DetectedZone = DetectedItem.Zone local DetectedZone = DetectedItem.Zone
-- Determine if the set has ground units. -- Determine if the set has ground units.
-- There should be ground unit friendlies nearby. Airborne units are valid friendlies types. -- There should be ground unit friendlies nearby. Airborne units are valid friendlies types.
-- And there shouldn't be any radar. -- And there shouldn't be any radar.
@@ -550,7 +548,6 @@ do -- TASK_A2G_DISPATCHER
local DetectedSet = DetectedItem.Set local DetectedSet = DetectedItem.Set
local DetectedZone = DetectedItem.Zone local DetectedZone = DetectedItem.Zone
-- Determine if the set has ground units. -- Determine if the set has ground units.
-- There shouldn't be any ground unit friendlies nearby. -- There shouldn't be any ground unit friendlies nearby.
-- And there shouldn't be any radar. -- And there shouldn't be any radar.
@@ -571,7 +568,6 @@ do -- TASK_A2G_DISPATCHER
return nil return nil
end end
function TASK_A2G_DISPATCHER:RemoveTask( TaskIndex ) function TASK_A2G_DISPATCHER:RemoveTask( TaskIndex )
self.Mission:RemoveTask( self.Tasks[TaskIndex] ) self.Mission:RemoveTask( self.Tasks[TaskIndex] )
self.Tasks[TaskIndex] = nil self.Tasks[TaskIndex] = nil
@@ -588,8 +584,8 @@ do -- TASK_A2G_DISPATCHER
function TASK_A2G_DISPATCHER:EvaluateRemoveTask( Mission, Task, TaskIndex, DetectedItemChanged ) function TASK_A2G_DISPATCHER:EvaluateRemoveTask( Mission, Task, TaskIndex, DetectedItemChanged )
if Task then if Task then
if ( Task:IsStatePlanned() and DetectedItemChanged == true ) or Task:IsStateCancelled() then if (Task:IsStatePlanned() and DetectedItemChanged == true) or Task:IsStateCancelled() then
--self:F( "Removing Tasking: " .. Task:GetTaskName() ) -- self:F( "Removing Tasking: " .. Task:GetTaskName() )
self:RemoveTask( TaskIndex ) self:RemoveTask( TaskIndex )
end end
end end
@@ -597,7 +593,6 @@ do -- TASK_A2G_DISPATCHER
return Task return Task
end end
--- Assigns tasks in relation to the detected items to the @{Core.Set#SET_GROUP}. --- Assigns tasks in relation to the detected items to the @{Core.Set#SET_GROUP}.
-- @param #TASK_A2G_DISPATCHER self -- @param #TASK_A2G_DISPATCHER self
-- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Functional.Detection#DETECTION_BASE} derived object. -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Functional.Detection#DETECTION_BASE} derived object.
@@ -638,8 +633,8 @@ do -- TASK_A2G_DISPATCHER
local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem
local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT
local DetectedZone = DetectedItem.Zone local DetectedZone = DetectedItem.Zone
--self:F( { "Targets in DetectedItem", DetectedItem.ItemID, DetectedSet:Count(), tostring( DetectedItem ) } ) -- self:F( { "Targets in DetectedItem", DetectedItem.ItemID, DetectedSet:Count(), tostring( DetectedItem ) } )
--DetectedSet:Flush( self ) -- DetectedSet:Flush( self )
local DetectedItemID = DetectedItem.ID local DetectedItemID = DetectedItem.ID
local TaskIndex = DetectedItem.Index local TaskIndex = DetectedItem.Index
@@ -660,7 +655,7 @@ do -- TASK_A2G_DISPATCHER
Task:SetTargetSetUnit( TargetSetUnit ) Task:SetTargetSetUnit( TargetSetUnit )
Task:SetDetection( Detection, DetectedItem ) Task:SetDetection( Detection, DetectedItem )
Task:UpdateTaskInfo( DetectedItem ) Task:UpdateTaskInfo( DetectedItem )
TargetsReport:Add( Detection:GetChangeText( DetectedItem ) ) TargetsReport:Add( Detection:GetChangeText( DetectedItem ) )
else else
Task:Cancel() Task:Cancel()
end end
@@ -694,8 +689,8 @@ do -- TASK_A2G_DISPATCHER
-- Now we send to each group the changes, if any. -- Now we send to each group the changes, if any.
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
local TargetsText = TargetsReport:Text(", ") local TargetsText = TargetsReport:Text( ", " )
if ( Mission:IsGroupAssigned(TaskGroup) ) and TargetsText ~= "" and self.FlashNewTask then if (Mission:IsGroupAssigned( TaskGroup )) and TargetsText ~= "" and self.FlashNewTask then
Mission:GetCommandCenter():MessageToGroup( string.format( "Task %s has change of targets:\n %s", Task:GetName(), TargetsText ), TaskGroup ) Mission:GetCommandCenter():MessageToGroup( string.format( "Task %s has change of targets:\n %s", Task:GetName(), TargetsText ), TaskGroup )
end end
end end
@@ -753,7 +748,7 @@ do -- TASK_A2G_DISPATCHER
local TargetSetUnit = self:EvaluateSEAD( DetectedItem ) -- Returns a SetUnit if there are targets to be SEADed... local TargetSetUnit = self:EvaluateSEAD( DetectedItem ) -- Returns a SetUnit if there are targets to be SEADed...
if TargetSetUnit then if TargetSetUnit then
Task = TASK_A2G_SEAD:New( Mission, self.SetGroup, string.format( "SEAD.%03d", DetectedItemID ), TargetSetUnit ) Task = TASK_A2G_SEAD:New( Mission, self.SetGroup, string.format( "SEAD.%03d", DetectedItemID ), TargetSetUnit )
DetectedItem.DesignateMenuName = string.format( "SEAD.%03d", DetectedItemID ) --inject a name for DESIGNATE, if using same DETECTION object DetectedItem.DesignateMenuName = string.format( "SEAD.%03d", DetectedItemID ) -- inject a name for DESIGNATE, if using same DETECTION object
Task:SetDetection( Detection, DetectedItem ) Task:SetDetection( Detection, DetectedItem )
end end
@@ -762,7 +757,7 @@ do -- TASK_A2G_DISPATCHER
local TargetSetUnit = self:EvaluateCAS( DetectedItem ) -- Returns a SetUnit if there are targets to be CASed... local TargetSetUnit = self:EvaluateCAS( DetectedItem ) -- Returns a SetUnit if there are targets to be CASed...
if TargetSetUnit then if TargetSetUnit then
Task = TASK_A2G_CAS:New( Mission, self.SetGroup, string.format( "CAS.%03d", DetectedItemID ), TargetSetUnit ) Task = TASK_A2G_CAS:New( Mission, self.SetGroup, string.format( "CAS.%03d", DetectedItemID ), TargetSetUnit )
DetectedItem.DesignateMenuName = string.format( "CAS.%03d", DetectedItemID ) --inject a name for DESIGNATE, if using same DETECTION object DetectedItem.DesignateMenuName = string.format( "CAS.%03d", DetectedItemID ) -- inject a name for DESIGNATE, if using same DETECTION object
Task:SetDetection( Detection, DetectedItem ) Task:SetDetection( Detection, DetectedItem )
end end
@@ -771,7 +766,7 @@ do -- TASK_A2G_DISPATCHER
local TargetSetUnit = self:EvaluateBAI( DetectedItem, self.Mission:GetCommandCenter():GetPositionable():GetCoalition() ) -- Returns a SetUnit if there are targets to be BAIed... local TargetSetUnit = self:EvaluateBAI( DetectedItem, self.Mission:GetCommandCenter():GetPositionable():GetCoalition() ) -- Returns a SetUnit if there are targets to be BAIed...
if TargetSetUnit then if TargetSetUnit then
Task = TASK_A2G_BAI:New( Mission, self.SetGroup, string.format( "BAI.%03d", DetectedItemID ), TargetSetUnit ) Task = TASK_A2G_BAI:New( Mission, self.SetGroup, string.format( "BAI.%03d", DetectedItemID ), TargetSetUnit )
DetectedItem.DesignateMenuName = string.format( "BAI.%03d", DetectedItemID ) --inject a name for DESIGNATE, if using same DETECTION object DetectedItem.DesignateMenuName = string.format( "BAI.%03d", DetectedItemID ) -- inject a name for DESIGNATE, if using same DETECTION object
Task:SetDetection( Detection, DetectedItem ) Task:SetDetection( Detection, DetectedItem )
end end
end end
@@ -800,14 +795,12 @@ do -- TASK_A2G_DISPATCHER
self:Aborted( Task ) self:Aborted( Task )
end end
TaskReport:Add( Task:GetName() ) TaskReport:Add( Task:GetName() )
else else
self:F("This should not happen") self:F( "This should not happen" )
end end
end end
-- OK, so the tasking has been done, now delete the changes reported for the area. -- OK, so the tasking has been done, now delete the changes reported for the area.
Detection:AcceptChanges( DetectedItem ) Detection:AcceptChanges( DetectedItem )
end end
@@ -815,9 +808,9 @@ do -- TASK_A2G_DISPATCHER
-- TODO set menus using the HQ coordinator -- TODO set menus using the HQ coordinator
Mission:GetCommandCenter():SetMenu() Mission:GetCommandCenter():SetMenu()
local TaskText = TaskReport:Text(", ") local TaskText = TaskReport:Text( ", " )
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" and self.FlashNewTask then if (not Mission:IsGroupAssigned( TaskGroup )) and TaskText ~= "" and self.FlashNewTask then
Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup ) Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup )
end end
end end
+46 -46
View File
@@ -11,7 +11,7 @@
-- --
-- DCS itself provides a lot of enumerators for various things. See [Enumerators](https://wiki.hoggitworld.com/view/Category:Enumerators) on Hoggit. -- DCS itself provides a lot of enumerators for various things. See [Enumerators](https://wiki.hoggitworld.com/view/Category:Enumerators) on Hoggit.
-- --
-- Other Moose classe also have enumerators. For example, the AIRBASE class has enumerators for airbase names. -- Other Moose classes also have enumerators. For example, the AIRBASE class has enumerators for airbase names.
-- --
-- @module ENUMS -- @module ENUMS
-- @image MOOSE.JPG -- @image MOOSE.JPG
@@ -30,16 +30,16 @@ ENUMS = {}
-- @type ENUMS.ROE -- @type ENUMS.ROE
-- @field #number WeaponFree AI will engage any enemy group it detects. Target prioritization is based based on the threat of the target. -- @field #number WeaponFree AI will engage any enemy group it detects. Target prioritization is based based on the threat of the target.
-- @field #number OpenFireWeaponFree AI will engage any enemy group it detects, but will prioritize targets specified in the groups tasking. -- @field #number OpenFireWeaponFree AI will engage any enemy group it detects, but will prioritize targets specified in the groups tasking.
-- @field #number OpenFire AI will engage only targets specified in its taskings. -- @field #number OpenFire AI will engage only targets specified in its tasking.
-- @field #number ReturnFire AI will only engage threats that shoot first. -- @field #number ReturnFire AI will only engage threats that shoot first.
-- @field #number WeaponHold AI will hold fire under all circumstances. -- @field #number WeaponHold AI will hold fire under all circumstances.
ENUMS.ROE = { ENUMS.ROE = {
WeaponFree=0, WeaponFree = 0,
OpenFireWeaponFree=1, OpenFireWeaponFree = 1,
OpenFire=2, OpenFire = 2,
ReturnFire=3, ReturnFire = 3,
WeaponHold=4, WeaponHold = 4,
} }
--- Reaction On Threat. --- Reaction On Threat.
-- @type ENUMS.ROT -- @type ENUMS.ROT
@@ -49,11 +49,11 @@ ENUMS.ROE = {
-- @field #number BypassAndEscape AI will attempt to avoid enemy threat zones all together. This includes attempting to fly above or around threats. -- @field #number BypassAndEscape AI will attempt to avoid enemy threat zones all together. This includes attempting to fly above or around threats.
-- @field #number AllowAbortMission If a threat is deemed severe enough the AI will abort its mission and return to base. -- @field #number AllowAbortMission If a threat is deemed severe enough the AI will abort its mission and return to base.
ENUMS.ROT = { ENUMS.ROT = {
NoReaction=0, NoReaction = 0,
PassiveDefense=1, PassiveDefense = 1,
EvadeFire=2, EvadeFire = 2,
BypassAndEscape=3, BypassAndEscape = 3,
AllowAbortMission=4, AllowAbortMission = 4,
} }
--- Alarm state. --- Alarm state.
@@ -62,12 +62,12 @@ ENUMS.ROT = {
-- @field #number Green Group is not combat ready. Sensors are stowed if possible. -- @field #number Green Group is not combat ready. Sensors are stowed if possible.
-- @field #number Red Group is combat ready and actively searching for targets. Some groups like infantry will not move in this state. -- @field #number Red Group is combat ready and actively searching for targets. Some groups like infantry will not move in this state.
ENUMS.AlarmState = { ENUMS.AlarmState = {
Auto=0, Auto = 0,
Green=1, Green = 1,
Red=2, Red = 2,
} }
--- Weapon types. See the [Weapon Flag](https://wiki.hoggitworld.com/view/DCS_enum_weapon_flag) enumerotor on hoggit wiki. --- Weapon types. See the [Weapon Flag](https://wiki.hoggitworld.com/view/DCS_enum_weapon_flag) enumerator on Hoggit wiki.
-- @type ENUMS.WeaponFlag -- @type ENUMS.WeaponFlag
ENUMS.WeaponFlag={ ENUMS.WeaponFlag={
-- Bombs -- Bombs
@@ -111,7 +111,7 @@ ENUMS.WeaponFlag={
-- --
-- Bombs -- Bombs
GuidedBomb = 14, -- (LGB + TvGB + SNSGB) GuidedBomb = 14, -- (LGB + TvGB + SNSGB)
AnyUnguidedBomb = 2147485680, -- (HeBomb + Penetrator + NapalmBomb + FAEBomb + ClusterBomb + Dispencer + CandleBomb + ParachuteBomb) AnyUnguidedBomb = 2147485680, -- (HeBomb + Penetrator + NapalmBomb + FAEBomb + ClusterBomb + Dispenser + CandleBomb + ParachuteBomb)
AnyBomb = 2147485694, -- (GuidedBomb + AnyUnguidedBomb) AnyBomb = 2147485694, -- (GuidedBomb + AnyUnguidedBomb)
--- Rockets --- Rockets
AnyRocket = 30720, -- LightRocket + MarkerRocket + CandleRocket + HeavyRocket AnyRocket = 30720, -- LightRocket + MarkerRocket + CandleRocket + HeavyRocket
@@ -173,7 +173,7 @@ ENUMS.MissionTask={
TRANSPORT="Transport", TRANSPORT="Transport",
} }
--- Formations (new). See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on hoggit wiki. --- Formations (new). See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on Hoggit wiki.
-- @type ENUMS.Formation -- @type ENUMS.Formation
ENUMS.Formation={} ENUMS.Formation={}
ENUMS.Formation.FixedWing={} ENUMS.Formation.FixedWing={}
@@ -216,23 +216,23 @@ ENUMS.Formation.FixedWing.FighterVic.Close = 917505
ENUMS.Formation.FixedWing.FighterVic.Open = 917506 ENUMS.Formation.FixedWing.FighterVic.Open = 917506
ENUMS.Formation.RotaryWing={} ENUMS.Formation.RotaryWing={}
ENUMS.Formation.RotaryWing.Column={} ENUMS.Formation.RotaryWing.Column={}
ENUMS.Formation.RotaryWing.Column.D70=720896 ENUMS.Formation.RotaryWing.Column.D70 = 720896
ENUMS.Formation.RotaryWing.Wedge={} ENUMS.Formation.RotaryWing.Wedge={}
ENUMS.Formation.RotaryWing.Wedge.D70=8 ENUMS.Formation.RotaryWing.Wedge.D70 = 8
ENUMS.Formation.RotaryWing.FrontRight={} ENUMS.Formation.RotaryWing.FrontRight={}
ENUMS.Formation.RotaryWing.FrontRight.D300=655361 ENUMS.Formation.RotaryWing.FrontRight.D300 = 655361
ENUMS.Formation.RotaryWing.FrontRight.D600=655362 ENUMS.Formation.RotaryWing.FrontRight.D600 = 655362
ENUMS.Formation.RotaryWing.FrontLeft={} ENUMS.Formation.RotaryWing.FrontLeft={}
ENUMS.Formation.RotaryWing.FrontLeft.D300=655617 ENUMS.Formation.RotaryWing.FrontLeft.D300 = 655617
ENUMS.Formation.RotaryWing.FrontLeft.D600=655618 ENUMS.Formation.RotaryWing.FrontLeft.D600 = 655618
ENUMS.Formation.RotaryWing.EchelonRight={} ENUMS.Formation.RotaryWing.EchelonRight={}
ENUMS.Formation.RotaryWing.EchelonRight.D70 =589825 ENUMS.Formation.RotaryWing.EchelonRight.D70 = 589825
ENUMS.Formation.RotaryWing.EchelonRight.D300=589826 ENUMS.Formation.RotaryWing.EchelonRight.D300 = 589826
ENUMS.Formation.RotaryWing.EchelonRight.D600=589827 ENUMS.Formation.RotaryWing.EchelonRight.D600 = 589827
ENUMS.Formation.RotaryWing.EchelonLeft={} ENUMS.Formation.RotaryWing.EchelonLeft={}
ENUMS.Formation.RotaryWing.EchelonLeft.D70 =590081 ENUMS.Formation.RotaryWing.EchelonLeft.D70 = 590081
ENUMS.Formation.RotaryWing.EchelonLeft.D300=590082 ENUMS.Formation.RotaryWing.EchelonLeft.D300 = 590082
ENUMS.Formation.RotaryWing.EchelonLeft.D600=590083 ENUMS.Formation.RotaryWing.EchelonLeft.D600 = 590083
ENUMS.Formation.Vehicle={} ENUMS.Formation.Vehicle={}
ENUMS.Formation.Vehicle.Vee="Vee" ENUMS.Formation.Vehicle.Vee="Vee"
ENUMS.Formation.Vehicle.EchelonRight="EchelonR" ENUMS.Formation.Vehicle.EchelonRight="EchelonR"
@@ -244,25 +244,25 @@ ENUMS.Formation.Vehicle.Cone="Cone"
ENUMS.Formation.Vehicle.Diamond="Diamond" ENUMS.Formation.Vehicle.Diamond="Diamond"
--- Formations (old). The old format is a simplified version of the new formation enums, which allow more sophisticated settings. --- Formations (old). The old format is a simplified version of the new formation enums, which allow more sophisticated settings.
-- See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on hoggit wiki. -- See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on Hoggit wiki.
-- @type ENUMS.FormationOld -- @type ENUMS.FormationOld
ENUMS.FormationOld={} ENUMS.FormationOld={}
ENUMS.FormationOld.FixedWing={} ENUMS.FormationOld.FixedWing={}
ENUMS.FormationOld.FixedWing.LineAbreast=1 ENUMS.FormationOld.FixedWing.LineAbreast = 1
ENUMS.FormationOld.FixedWing.Trail=2 ENUMS.FormationOld.FixedWing.Trail = 2
ENUMS.FormationOld.FixedWing.Wedge=3 ENUMS.FormationOld.FixedWing.Wedge = 3
ENUMS.FormationOld.FixedWing.EchelonRight=4 ENUMS.FormationOld.FixedWing.EchelonRight = 4
ENUMS.FormationOld.FixedWing.EchelonLeft=5 ENUMS.FormationOld.FixedWing.EchelonLeft = 5
ENUMS.FormationOld.FixedWing.FingerFour=6 ENUMS.FormationOld.FixedWing.FingerFour = 6
ENUMS.FormationOld.FixedWing.SpreadFour=7 ENUMS.FormationOld.FixedWing.SpreadFour = 7
ENUMS.FormationOld.FixedWing.BomberElement=12 ENUMS.FormationOld.FixedWing.BomberElement = 12
ENUMS.FormationOld.FixedWing.BomberElementHeight=13 ENUMS.FormationOld.FixedWing.BomberElementHeight = 13
ENUMS.FormationOld.FixedWing.FighterVic=14 ENUMS.FormationOld.FixedWing.FighterVic = 14
ENUMS.FormationOld.RotaryWing={} ENUMS.FormationOld.RotaryWing={}
ENUMS.FormationOld.RotaryWing.Wedge=8 ENUMS.FormationOld.RotaryWing.Wedge = 8
ENUMS.FormationOld.RotaryWing.Echelon=9 ENUMS.FormationOld.RotaryWing.Echelon = 9
ENUMS.FormationOld.RotaryWing.Front=10 ENUMS.FormationOld.RotaryWing.Front = 10
ENUMS.FormationOld.RotaryWing.Column=11 ENUMS.FormationOld.RotaryWing.Column = 11
--- Morse Code. See the [Wikipedia](https://en.wikipedia.org/wiki/Morse_code). --- Morse Code. See the [Wikipedia](https://en.wikipedia.org/wiki/Morse_code).
+187 -193
View File
@@ -9,7 +9,6 @@
-- @module Utilities.PROFILER -- @module Utilities.PROFILER
-- @image MOOSE.JPG -- @image MOOSE.JPG
--- PROFILER class. --- PROFILER class.
-- @type PROFILER -- @type PROFILER
-- @field #string ClassName Name of the class. -- @field #string ClassName Name of the class.
@@ -25,7 +24,6 @@
-- @field #number ThreshTtot Total time threshold. Only write output if total function CPU time is more than this value. -- @field #number ThreshTtot Total time threshold. Only write output if total function CPU time is more than this value.
-- @field #string fileNamePrefix Output file name prefix, e.g. "MooseProfiler". -- @field #string fileNamePrefix Output file name prefix, e.g. "MooseProfiler".
-- @field #string fileNameSuffix Output file name prefix, e.g. "txt" -- @field #string fileNameSuffix Output file name prefix, e.g. "txt"
--- *The emperor counsels simplicity. First principles. Of each particular thing, ask: What is it in itself, in its own constitution? What is its causal nature? * --- *The emperor counsels simplicity. First principles. Of each particular thing, ask: What is it in itself, in its own constitution? What is its causal nature? *
-- --
-- === -- ===
@@ -35,12 +33,11 @@
-- # The PROFILER Concept -- # The PROFILER Concept
-- --
-- Profile your lua code. This tells you, which functions are called very often and which consume most real time. -- Profile your lua code. This tells you, which functions are called very often and which consume most real time.
-- With this information you can optimize the perfomance of your code. -- With this information you can optimize the performance of your code.
-- --
-- # Prerequisites -- # Prerequisites
-- --
-- The modules **os** and **lfs** need to be desanizied. -- The modules **os** and **lfs** need to be de-sanitized.
--
-- --
-- # Start -- # Start
-- --
@@ -117,61 +114,60 @@ PROFILER = {
--- Start profiler. --- Start profiler.
-- @param #number Delay Delay in seconds before profiler is stated. Default is immediately. -- @param #number Delay Delay in seconds before profiler is stated. Default is immediately.
-- @param #number Duration Duration in (game) seconds before the profiler is stopped. Default is when mission ends. -- @param #number Duration Duration in (game) seconds before the profiler is stopped. Default is when mission ends.
function PROFILER.Start(Delay, Duration) function PROFILER.Start( Delay, Duration )
-- Check if os, io and lfs are available. -- Check if os, io and lfs are available.
local go=true local go = true
if not os then if not os then
env.error("ERROR: Profiler needs os to be desanitized!") env.error( "ERROR: Profiler needs os to be de-sanitized!" )
go=false go = false
end end
if not io then if not io then
env.error("ERROR: Profiler needs io to be desanitized!") env.error( "ERROR: Profiler needs io to be de-sanitized!" )
go=false go = false
end end
if not lfs then if not lfs then
env.error("ERROR: Profiler needs lfs to be desanitized!") env.error( "ERROR: Profiler needs lfs to be de-sanitized!" )
go=false go = false
end end
if not go then if not go then
return return
end end
if Delay and Delay>0 then if Delay and Delay > 0 then
BASE:ScheduleOnce(Delay, PROFILER.Start, 0, Duration) BASE:ScheduleOnce( Delay, PROFILER.Start, 0, Duration )
else else
-- Set start time. -- Set start time.
PROFILER.TstartGame=timer.getTime() PROFILER.TstartGame = timer.getTime()
PROFILER.TstartOS=os.clock() PROFILER.TstartOS = os.clock()
-- Add event handler. -- Add event handler.
world.addEventHandler(PROFILER.eventHandler) world.addEventHandler( PROFILER.eventHandler )
-- Info in log. -- Info in log.
env.info('############################ Profiler Started ############################') env.info( '############################ Profiler Started ############################' )
if Duration then if Duration then
env.info(string.format("- Will be running for %d seconds", Duration)) env.info( string.format( "- Will be running for %d seconds", Duration ) )
else else
env.info(string.format("- Will be stopped when mission ends")) env.info( string.format( "- Will be stopped when mission ends" ) )
end end
env.info(string.format("- Calls per second threshold %.3f/sec", PROFILER.ThreshCPS)) env.info( string.format( "- Calls per second threshold %.3f/sec", PROFILER.ThreshCPS ) )
env.info(string.format("- Total function time threshold %.3f sec", PROFILER.ThreshTtot)) env.info( string.format( "- Total function time threshold %.3f sec", PROFILER.ThreshTtot ) )
env.info(string.format("- Output file \"%s\" in your DCS log file folder", PROFILER.getfilename(PROFILER.fileNameSuffix))) env.info( string.format( "- Output file \"%s\" in your DCS log file folder", PROFILER.getfilename( PROFILER.fileNameSuffix ) ) )
env.info(string.format("- Output file \"%s\" in CSV format", PROFILER.getfilename("csv"))) env.info( string.format( "- Output file \"%s\" in CSV format", PROFILER.getfilename( "csv" ) ) )
env.info('###############################################################################') env.info( '###############################################################################' )
-- Message on screen -- Message on screen
local duration=Duration or 600 local duration = Duration or 600
trigger.action.outText("### Profiler running ###", duration) trigger.action.outText( "### Profiler running ###", duration )
-- Set hook. -- Set hook.
debug.sethook(PROFILER.hook, "cr") debug.sethook( PROFILER.hook, "cr" )
-- Auto stop profiler. -- Auto stop profiler.
if Duration then if Duration then
PROFILER.Stop(Duration) PROFILER.Stop( Duration )
end end
end end
@@ -180,34 +176,33 @@ end
--- Stop profiler. --- Stop profiler.
-- @param #number Delay Delay before stop in seconds. -- @param #number Delay Delay before stop in seconds.
function PROFILER.Stop(Delay) function PROFILER.Stop( Delay )
if Delay and Delay>0 then if Delay and Delay > 0 then
BASE:ScheduleOnce(Delay, PROFILER.Stop) BASE:ScheduleOnce( Delay, PROFILER.Stop )
else else
-- Remove hook. -- Remove hook.
debug.sethook() debug.sethook()
-- Run time game. -- Run time game.
local runTimeGame=timer.getTime()-PROFILER.TstartGame local runTimeGame = timer.getTime() - PROFILER.TstartGame
-- Run time real OS. -- Run time real OS.
local runTimeOS=os.clock()-PROFILER.TstartOS local runTimeOS = os.clock() - PROFILER.TstartOS
-- Show info. -- Show info.
PROFILER.showInfo(runTimeGame, runTimeOS) PROFILER.showInfo( runTimeGame, runTimeOS )
end end
end end
--- Event handler. --- Event handler.
function PROFILER.eventHandler:onEvent(event) function PROFILER.eventHandler:onEvent( event )
if event.id==world.event.S_EVENT_MISSION_END then if event.id == world.event.S_EVENT_MISSION_END then
PROFILER.Stop() PROFILER.Stop()
end end
end end
@@ -218,34 +213,34 @@ end
--- Debug hook. --- Debug hook.
-- @param #table event Event. -- @param #table event Event.
function PROFILER.hook(event) function PROFILER.hook( event )
local f=debug.getinfo(2, "f").func local f = debug.getinfo( 2, "f" ).func
if event=='call' then if event == 'call' then
if PROFILER.Counters[f]==nil then if PROFILER.Counters[f] == nil then
PROFILER.Counters[f]=1 PROFILER.Counters[f] = 1
PROFILER.dInfo[f]=debug.getinfo(2,"Sn") PROFILER.dInfo[f] = debug.getinfo( 2, "Sn" )
if PROFILER.fTimeTotal[f]==nil then if PROFILER.fTimeTotal[f] == nil then
PROFILER.fTimeTotal[f]=0 PROFILER.fTimeTotal[f] = 0
end end
else else
PROFILER.Counters[f]=PROFILER.Counters[f]+1 PROFILER.Counters[f] = PROFILER.Counters[f] + 1
end end
if PROFILER.fTime[f]==nil then if PROFILER.fTime[f] == nil then
PROFILER.fTime[f]=os.clock() PROFILER.fTime[f] = os.clock()
end end
elseif (event=='return') then elseif (event == 'return') then
if PROFILER.fTime[f]~=nil then if PROFILER.fTime[f] ~= nil then
PROFILER.fTimeTotal[f]=PROFILER.fTimeTotal[f]+(os.clock()-PROFILER.fTime[f]) PROFILER.fTimeTotal[f] = PROFILER.fTimeTotal[f] + (os.clock() - PROFILER.fTime[f])
PROFILER.fTime[f]=nil PROFILER.fTime[f] = nil
end end
end end
@@ -262,11 +257,11 @@ end
-- @return #string Source file name. -- @return #string Source file name.
-- @return #string Line number. -- @return #string Line number.
-- @return #number Function time in seconds. -- @return #number Function time in seconds.
function PROFILER.getData(func) function PROFILER.getData( func )
local n=PROFILER.dInfo[func] local n = PROFILER.dInfo[func]
if n.what=="C" then if n.what == "C" then
return n.name, "?", "?", PROFILER.fTimeTotal[func] return n.name, "?", "?", PROFILER.fTimeTotal[func]
end end
@@ -276,31 +271,31 @@ end
--- Write text to log file. --- Write text to log file.
-- @param #function f The file. -- @param #function f The file.
-- @param #string txt The text. -- @param #string txt The text.
function PROFILER._flog(f, txt) function PROFILER._flog( f, txt )
f:write(txt.."\r\n") f:write( txt .. "\r\n" )
end end
--- Show table. --- Show table.
-- @param #table data Data table. -- @param #table data Data table.
-- @param #function f The file. -- @param #function f The file.
-- @param #number runTimeGame Game run time in seconds. -- @param #number runTimeGame Game run time in seconds.
function PROFILER.showTable(data, f, runTimeGame) function PROFILER.showTable( data, f, runTimeGame )
-- Loop over data. -- Loop over data.
for i=1, #data do for i = 1, #data do
local t=data[i] --#PROFILER.Data local t = data[i] -- #PROFILER.Data
-- Calls per second. -- Calls per second.
local cps=t.count/runTimeGame local cps = t.count / runTimeGame
local threshCPS=cps>=PROFILER.ThreshCPS local threshCPS = cps >= PROFILER.ThreshCPS
local threshTot=t.tm>=PROFILER.ThreshTtot local threshTot = t.tm >= PROFILER.ThreshTtot
if threshCPS and threshTot then if threshCPS and threshTot then
-- Output -- Output
local text=string.format("%30s: %8d calls %8.1f/sec - Time Total %8.3f sec (%.3f %%) %5.3f sec/call %s line %s", t.func, t.count, cps, t.tm, t.tm/runTimeGame*100, t.tm/t.count, tostring(t.src), tostring(t.line)) local text = string.format( "%30s: %8d calls %8.1f/sec - Time Total %8.3f sec (%.3f %%) %5.3f sec/call %s line %s", t.func, t.count, cps, t.tm, t.tm / runTimeGame * 100, t.tm / t.count, tostring( t.src ), tostring( t.line ) )
PROFILER._flog(f, text) PROFILER._flog( f, text )
end end
end end
@@ -310,26 +305,26 @@ end
--- Print csv file. --- Print csv file.
-- @param #table data Data table. -- @param #table data Data table.
-- @param #number runTimeGame Game run time in seconds. -- @param #number runTimeGame Game run time in seconds.
function PROFILER.printCSV(data, runTimeGame) function PROFILER.printCSV( data, runTimeGame )
-- Output file. -- Output file.
local file=PROFILER.getfilename("csv") local file = PROFILER.getfilename( "csv" )
local g=io.open(file, 'w') local g = io.open( file, 'w' )
-- Header. -- Header.
local text="Function,Total Calls,Calls per Sec,Total Time,Total in %,Sec per Call,Source File;Line Number," local text = "Function,Total Calls,Calls per Sec,Total Time,Total in %,Sec per Call,Source File;Line Number,"
g:write(text.."\r\n") g:write( text .. "\r\n" )
-- Loop over data. -- Loop over data.
for i=1, #data do for i = 1, #data do
local t=data[i] --#PROFILER.Data local t = data[i] -- #PROFILER.Data
-- Calls per second. -- Calls per second.
local cps=t.count/runTimeGame local cps = t.count / runTimeGame
-- Output -- Output
local txt=string.format("%s,%d,%.1f,%.3f,%.3f,%.3f,%s,%s,", t.func, t.count, cps, t.tm, t.tm/runTimeGame*100, t.tm/t.count, tostring(t.src), tostring(t.line)) local txt = string.format( "%s,%d,%.1f,%.3f,%.3f,%.3f,%s,%s,", t.func, t.count, cps, t.tm, t.tm / runTimeGame * 100, t.tm / t.count, tostring( t.src ), tostring( t.line ) )
g:write(txt.."\r\n") g:write( txt .. "\r\n" )
end end
@@ -337,27 +332,26 @@ function PROFILER.printCSV(data, runTimeGame)
g:close() g:close()
end end
--- Write info to output file. --- Write info to output file.
-- @param #string ext Extension. -- @param #string ext Extension.
-- @return #string File name. -- @return #string File name.
function PROFILER.getfilename(ext) function PROFILER.getfilename( ext )
local dir=lfs.writedir()..[[Logs\]] local dir = lfs.writedir() .. [[Logs\]]
ext=ext or PROFILER.fileNameSuffix ext = ext or PROFILER.fileNameSuffix
local file=dir..PROFILER.fileNamePrefix.."."..ext local file = dir .. PROFILER.fileNamePrefix .. "." .. ext
if not UTILS.FileExists(file) then if not UTILS.FileExists( file ) then
return file return file
end end
for i=1,999 do for i = 1, 999 do
local file=string.format("%s%s-%03d.%s", dir,PROFILER.fileNamePrefix, i, ext) local file = string.format( "%s%s-%03d.%s", dir, PROFILER.fileNamePrefix, i, ext )
if not UTILS.FileExists(file) then if not UTILS.FileExists( file ) then
return file return file
end end
@@ -368,81 +362,76 @@ end
--- Write info to output file. --- Write info to output file.
-- @param #number runTimeGame Game time in seconds. -- @param #number runTimeGame Game time in seconds.
-- @param #number runTimeOS OS time in seconds. -- @param #number runTimeOS OS time in seconds.
function PROFILER.showInfo(runTimeGame, runTimeOS) function PROFILER.showInfo( runTimeGame, runTimeOS )
-- Output file. -- Output file.
local file=PROFILER.getfilename(PROFILER.fileNameSuffix) local file = PROFILER.getfilename( PROFILER.fileNameSuffix )
local f=io.open(file, 'w') local f = io.open( file, 'w' )
-- Gather data. -- Gather data.
local Ttot=0 local Ttot = 0
local Calls=0 local Calls = 0
local t={} local t = {}
local tcopy=nil --#PROFILER.Data local tcopy = nil -- #PROFILER.Data
local tserialize=nil --#PROFILER.Data local tserialize = nil -- #PROFILER.Data
local tforgen=nil --#PROFILER.Data local tforgen = nil -- #PROFILER.Data
local tpairs=nil --#PROFILER.Data local tpairs = nil -- #PROFILER.Data
for func, count in pairs( PROFILER.Counters ) do
for func, count in pairs(PROFILER.Counters) do local s, src, line, tm = PROFILER.getData( func )
local s,src,line,tm=PROFILER.getData(func) if PROFILER.logUnknown == true then
if s == nil then
if PROFILER.logUnknown==true then s = "<Unknown>"
if s==nil then s="<Unknown>" end end
end end
if s~=nil then if s ~= nil then
-- Profile data. -- Profile data.
local T= local T = { func = s, src = src, line = line, count = count, tm = tm } -- #PROFILER.Data
{ func=s,
src=src,
line=line,
count=count,
tm=tm,
} --#PROFILER.Data
-- Collect special cases. Somehow, e.g. "_copy" appears multiple times so we try to gather all data. -- Collect special cases. Somehow, e.g. "_copy" appears multiple times so we try to gather all data.
if s=="_copy" then if s == "_copy" then
if tcopy==nil then if tcopy == nil then
tcopy=T tcopy = T
else else
tcopy.count=tcopy.count+T.count tcopy.count = tcopy.count + T.count
tcopy.tm=tcopy.tm+T.tm tcopy.tm = tcopy.tm + T.tm
end end
elseif s=="_Serialize" then elseif s == "_Serialize" then
if tserialize==nil then if tserialize == nil then
tserialize=T tserialize = T
else else
tserialize.count=tserialize.count+T.count tserialize.count = tserialize.count + T.count
tserialize.tm=tserialize.tm+T.tm tserialize.tm = tserialize.tm + T.tm
end end
elseif s=="(for generator)" then elseif s == "(for generator)" then
if tforgen==nil then if tforgen == nil then
tforgen=T tforgen = T
else else
tforgen.count=tforgen.count+T.count tforgen.count = tforgen.count + T.count
tforgen.tm=tforgen.tm+T.tm tforgen.tm = tforgen.tm + T.tm
end end
elseif s=="pairs" then elseif s == "pairs" then
if tpairs==nil then if tpairs == nil then
tpairs=T tpairs = T
else else
tpairs.count=tpairs.count+T.count tpairs.count = tpairs.count + T.count
tpairs.tm=tpairs.tm+T.tm tpairs.tm = tpairs.tm + T.tm
end end
else else
table.insert(t, T) table.insert( t, T )
end end
-- Total function time. -- Total function time.
Ttot=Ttot+tm Ttot = Ttot + tm
-- Total number of calls. -- Total number of calls.
Calls=Calls+count Calls = Calls + count
end end
@@ -450,90 +439,95 @@ function PROFILER.showInfo(runTimeGame, runTimeOS)
-- Add special cases. -- Add special cases.
if tcopy then if tcopy then
table.insert(t, tcopy) table.insert( t, tcopy )
end end
if tserialize then if tserialize then
table.insert(t, tserialize) table.insert( t, tserialize )
end end
if tforgen then if tforgen then
table.insert(t, tforgen) table.insert( t, tforgen )
end end
if tpairs then if tpairs then
table.insert(t, tpairs) table.insert( t, tpairs )
end end
env.info('############################ Profiler Stopped ############################') env.info( '############################ Profiler Stopped ############################' )
env.info(string.format("* Runtime Game : %s = %d sec", UTILS.SecondsToClock(runTimeGame, true), runTimeGame)) env.info( string.format( "* Runtime Game : %s = %d sec", UTILS.SecondsToClock( runTimeGame, true ), runTimeGame ) )
env.info(string.format("* Runtime Real : %s = %d sec", UTILS.SecondsToClock(runTimeOS, true), runTimeOS)) env.info( string.format( "* Runtime Real : %s = %d sec", UTILS.SecondsToClock( runTimeOS, true ), runTimeOS ) )
env.info(string.format("* Function time : %s = %.1f sec (%.1f percent of runtime game)", UTILS.SecondsToClock(Ttot, true), Ttot, Ttot/runTimeGame*100)) env.info( string.format( "* Function time : %s = %.1f sec (%.1f percent of runtime game)", UTILS.SecondsToClock( Ttot, true ), Ttot, Ttot / runTimeGame * 100 ) )
env.info(string.format("* Total functions : %d", #t)) env.info( string.format( "* Total functions : %d", #t ) )
env.info(string.format("* Total func calls : %d", Calls)) env.info( string.format( "* Total func calls : %d", Calls ) )
env.info(string.format("* Writing to file : \"%s\"", file)) env.info( string.format( "* Writing to file : \"%s\"", file ) )
env.info(string.format("* Writing to file : \"%s\"", PROFILER.getfilename("csv"))) env.info( string.format( "* Writing to file : \"%s\"", PROFILER.getfilename( "csv" ) ) )
env.info("##############################################################################") env.info( "##############################################################################" )
-- Sort by total time. -- Sort by total time.
table.sort(t, function(a,b) return a.tm>b.tm end) table.sort( t, function( a, b )
return a.tm > b.tm
end )
-- Write data. -- Write data.
PROFILER._flog(f,"") PROFILER._flog( f, "" )
PROFILER._flog(f,"************************************************************************************************************************") PROFILER._flog( f, "************************************************************************************************************************" )
PROFILER._flog(f,"************************************************************************************************************************") PROFILER._flog( f, "************************************************************************************************************************" )
PROFILER._flog(f,"************************************************************************************************************************") PROFILER._flog( f, "************************************************************************************************************************" )
PROFILER._flog(f,"") PROFILER._flog( f, "" )
PROFILER._flog(f,"-------------------------") PROFILER._flog( f, "-------------------------" )
PROFILER._flog(f,"---- Profiler Report ----") PROFILER._flog( f, "---- Profiler Report ----" )
PROFILER._flog(f,"-------------------------") PROFILER._flog( f, "-------------------------" )
PROFILER._flog(f,"") PROFILER._flog( f, "" )
PROFILER._flog(f,string.format("* Runtime Game : %s = %.1f sec", UTILS.SecondsToClock(runTimeGame, true), runTimeGame)) PROFILER._flog( f, string.format( "* Runtime Game : %s = %.1f sec", UTILS.SecondsToClock( runTimeGame, true ), runTimeGame ) )
PROFILER._flog(f,string.format("* Runtime Real : %s = %.1f sec", UTILS.SecondsToClock(runTimeOS, true), runTimeOS)) PROFILER._flog( f, string.format( "* Runtime Real : %s = %.1f sec", UTILS.SecondsToClock( runTimeOS, true ), runTimeOS ) )
PROFILER._flog(f,string.format("* Function time : %s = %.1f sec (%.1f %% of runtime game)", UTILS.SecondsToClock(Ttot, true), Ttot, Ttot/runTimeGame*100)) PROFILER._flog( f, string.format( "* Function time : %s = %.1f sec (%.1f %% of runtime game)", UTILS.SecondsToClock( Ttot, true ), Ttot, Ttot / runTimeGame * 100 ) )
PROFILER._flog(f,"") PROFILER._flog( f, "" )
PROFILER._flog(f,string.format("* Total functions = %d", #t)) PROFILER._flog( f, string.format( "* Total functions = %d", #t ) )
PROFILER._flog(f,string.format("* Total func calls = %d", Calls)) PROFILER._flog( f, string.format( "* Total func calls = %d", Calls ) )
PROFILER._flog(f,"") PROFILER._flog( f, "" )
PROFILER._flog(f,string.format("* Calls per second threshold = %.3f/sec", PROFILER.ThreshCPS)) PROFILER._flog( f, string.format( "* Calls per second threshold = %.3f/sec", PROFILER.ThreshCPS ) )
PROFILER._flog(f,string.format("* Total func time threshold = %.3f sec", PROFILER.ThreshTtot)) PROFILER._flog( f, string.format( "* Total func time threshold = %.3f sec", PROFILER.ThreshTtot ) )
PROFILER._flog(f,"") PROFILER._flog( f, "" )
PROFILER._flog(f,"************************************************************************************************************************") PROFILER._flog( f, "************************************************************************************************************************" )
PROFILER._flog(f,"") PROFILER._flog( f, "" )
PROFILER.showTable(t, f, runTimeGame) PROFILER.showTable( t, f, runTimeGame )
-- Sort by number of calls. -- Sort by number of calls.
table.sort(t, function(a,b) return a.tm/a.count>b.tm/b.count end) table.sort( t, function( a, b )
return a.tm / a.count > b.tm / b.count
end )
-- Detailed data. -- Detailed data.
PROFILER._flog(f,"") PROFILER._flog( f, "" )
PROFILER._flog(f,"************************************************************************************************************************") PROFILER._flog( f, "************************************************************************************************************************" )
PROFILER._flog(f,"") PROFILER._flog( f, "" )
PROFILER._flog(f,"--------------------------------------") PROFILER._flog( f, "--------------------------------------" )
PROFILER._flog(f,"---- Data Sorted by Time per Call ----") PROFILER._flog( f, "---- Data Sorted by Time per Call ----" )
PROFILER._flog(f,"--------------------------------------") PROFILER._flog( f, "--------------------------------------" )
PROFILER._flog(f,"") PROFILER._flog( f, "" )
PROFILER.showTable(t, f, runTimeGame) PROFILER.showTable( t, f, runTimeGame )
-- Sort by number of calls. -- Sort by number of calls.
table.sort(t, function(a,b) return a.count>b.count end) table.sort( t, function( a, b )
return a.count > b.count
end )
-- Detailed data. -- Detailed data.
PROFILER._flog(f,"") PROFILER._flog( f, "" )
PROFILER._flog(f,"************************************************************************************************************************") PROFILER._flog( f, "************************************************************************************************************************" )
PROFILER._flog(f,"") PROFILER._flog( f, "" )
PROFILER._flog(f,"------------------------------------") PROFILER._flog( f, "------------------------------------" )
PROFILER._flog(f,"---- Data Sorted by Total Calls ----") PROFILER._flog( f, "---- Data Sorted by Total Calls ----" )
PROFILER._flog(f,"------------------------------------") PROFILER._flog( f, "------------------------------------" )
PROFILER._flog(f,"") PROFILER._flog( f, "" )
PROFILER.showTable(t, f, runTimeGame) PROFILER.showTable( t, f, runTimeGame )
-- Closing. -- Closing.
PROFILER._flog(f,"") PROFILER._flog( f, "" )
PROFILER._flog(f,"************************************************************************************************************************") PROFILER._flog( f, "************************************************************************************************************************" )
PROFILER._flog(f,"************************************************************************************************************************") PROFILER._flog( f, "************************************************************************************************************************" )
PROFILER._flog(f,"************************************************************************************************************************") PROFILER._flog( f, "************************************************************************************************************************" )
-- Close file. -- Close file.
f:close() f:close()
-- Print csv file. -- Print csv file.
PROFILER.printCSV(t, runTimeGame) PROFILER.printCSV( t, runTimeGame )
end end
File diff suppressed because it is too large Load Diff
+93 -93
View File
@@ -1,7 +1,6 @@
--- **Utilities** DCS Simple Text-To-Speech (STTS). --- **Utilities** DCS Simple Text-To-Speech (STTS).
-- --
-- --
--
-- @module Utils.STTS -- @module Utils.STTS
-- @image MOOSE.JPG -- @image MOOSE.JPG
@@ -15,7 +14,7 @@
-- --
-- # DCS Modification Required -- # DCS Modification Required
-- --
-- You will need to edit MissionScripting.lua in DCS World/Scripts/MissionScripting.lua and remove the sanitisation. -- You will need to edit MissionScripting.lua in DCS World/Scripts/MissionScripting.lua and remove the sanitization.
-- To do this remove all the code below the comment - the line starts "local function sanitizeModule(name)" -- To do this remove all the code below the comment - the line starts "local function sanitizeModule(name)"
-- Do this without DCS running to allow mission scripts to use os functions. -- Do this without DCS running to allow mission scripts to use os functions.
-- --
@@ -23,7 +22,7 @@
-- --
-- # USAGE: -- # USAGE:
-- --
-- Add this script into the mission as a DO SCRIPT or DO SCRIPT FROM FILE to initialise it -- Add this script into the mission as a DO SCRIPT or DO SCRIPT FROM FILE to initialize it
-- Make sure to edit the STTS.SRS_PORT and STTS.DIRECTORY to the correct values before adding to the mission. -- Make sure to edit the STTS.SRS_PORT and STTS.DIRECTORY to the correct values before adding to the mission.
-- Then its as simple as calling the correct function in LUA as a DO SCRIPT or in your own scripts. -- Then its as simple as calling the correct function in LUA as a DO SCRIPT or in your own scripts.
-- --
@@ -43,7 +42,7 @@
-- * OPTIONAL - Speed -10 to +10 -- * OPTIONAL - Speed -10 to +10
-- * OPTIONAL - Gender male, female or neuter -- * OPTIONAL - Gender male, female or neuter
-- * OPTIONAL - Culture - en-US, en-GB etc -- * OPTIONAL - Culture - en-US, en-GB etc
-- * OPTIONAL - Voice - a specfic voice by name. Run DCS-SR-ExternalAudio.exe with --help to get the ones you can use on the command line -- * OPTIONAL - Voice - a specific voice by name. Run DCS-SR-ExternalAudio.exe with --help to get the ones you can use on the command line
-- * OPTIONAL - Google TTS - Switch to Google Text To Speech - Requires STTS.GOOGLE_CREDENTIALS path and Google project setup correctly -- * OPTIONAL - Google TTS - Switch to Google Text To Speech - Requires STTS.GOOGLE_CREDENTIALS path and Google project setup correctly
-- --
-- --
@@ -55,7 +54,7 @@
-- --
-- ## Example -- ## Example
-- --
--This example will say the words "Hello DCS WORLD" on 251 MHz AM at maximum volume with a client called SRS and to the Blue coalition only centered on the position of the Unit called "A UNIT" -- This example will say the words "Hello DCS WORLD" on 251 MHz AM at maximum volume with a client called SRS and to the Blue coalition only centered on the position of the Unit called "A UNIT"
-- --
-- STTS.TextToSpeech("Hello DCS WORLD","251","AM","1.0","SRS",2,Unit.getByName("A UNIT"):getPoint(),-5,"male","en-GB") -- STTS.TextToSpeech("Hello DCS WORLD","251","AM","1.0","SRS",2,Unit.getByName("A UNIT"):getPoint(),-5,"male","en-GB")
-- --
@@ -75,12 +74,12 @@
-- STTS.PlayMP3("C:\\Users\\Ciaran\\Downloads\\PR-Music.mp3","255,31","AM,FM","0.5","Multiple",0) -- STTS.PlayMP3("C:\\Users\\Ciaran\\Downloads\\PR-Music.mp3","255,31","AM,FM","0.5","Multiple",0)
-- --
-- @field #STTS -- @field #STTS
STTS={ STTS = {
ClassName="STTS", ClassName = "STTS",
DIRECTORY="", DIRECTORY = "",
SRS_PORT=5002, SRS_PORT = 5002,
GOOGLE_CREDENTIALS="C:\\Users\\Ciaran\\Downloads\\googletts.json", GOOGLE_CREDENTIALS = "C:\\Users\\Ciaran\\Downloads\\googletts.json",
EXECUTABLE="DCS-SR-ExternalAudio.exe", EXECUTABLE = "DCS-SR-ExternalAudio.exe"
} }
--- FULL Path to the FOLDER containing DCS-SR-ExternalAudio.exe - EDIT TO CORRECT FOLDER --- FULL Path to the FOLDER containing DCS-SR-ExternalAudio.exe - EDIT TO CORRECT FOLDER
@@ -92,40 +91,43 @@ STTS.SRS_PORT = 5002
--- Google credentials file --- Google credentials file
STTS.GOOGLE_CREDENTIALS = "C:\\Users\\Ciaran\\Downloads\\googletts.json" STTS.GOOGLE_CREDENTIALS = "C:\\Users\\Ciaran\\Downloads\\googletts.json"
--- DONT CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING --- DON'T CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING
STTS.EXECUTABLE = "DCS-SR-ExternalAudio.exe" STTS.EXECUTABLE = "DCS-SR-ExternalAudio.exe"
--- Function for UUID. --- Function for UUID.
function STTS.uuid() function STTS.uuid()
local random = math.random local random = math.random
local template ='yxxx-xxxxxxxxxxxx' local template = 'yxxx-xxxxxxxxxxxx'
return string.gsub(template, '[xy]', function (c) return string.gsub( template, '[xy]', function( c )
local v = (c == 'x') and random(0, 0xf) or random(8, 0xb) local v = (c == 'x') and random( 0, 0xf ) or random( 8, 0xb )
return string.format('%x', v) return string.format( '%x', v )
end) end )
end end
--- Round a number. --- Round a number.
-- @param #number x Number. -- @param #number x Number.
-- @param #number n Precision. -- @param #number n Precision.
function STTS.round(x, n) function STTS.round( x, n )
n = math.pow(10, n or 0) n = math.pow( 10, n or 0 )
x = x * n x = x * n
if x >= 0 then x = math.floor(x + 0.5) else x = math.ceil(x - 0.5) end if x >= 0 then
x = math.floor( x + 0.5 )
else
x = math.ceil( x - 0.5 )
end
return x / n return x / n
end end
--- Function returns estimated speech time in seconds. --- Function returns estimated speech time in seconds.
-- Assumptions for time calc: 100 Words per min, avarage of 5 letters for english word so -- Assumptions for time calc: 100 Words per min, average of 5 letters for english word so
-- --
-- * 5 chars * 100wpm = 500 characters per min = 8.3 chars per second -- * 5 chars * 100wpm = 500 characters per min = 8.3 chars per second
-- --
-- So lengh of msg / 8.3 = number of seconds needed to read it. rounded down to 8 chars per sec map function: -- So length of msg / 8.3 = number of seconds needed to read it. rounded down to 8 chars per sec map function:
-- --
-- * (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min -- * (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
-- --
function STTS.getSpeechTime(length,speed,isGoogle) function STTS.getSpeechTime( length, speed, isGoogle )
local maxRateRatio = 3 local maxRateRatio = 3
@@ -134,100 +136,99 @@ function STTS.getSpeechTime(length,speed,isGoogle)
local speedFactor = 1.0 local speedFactor = 1.0
if isGoogle then if isGoogle then
speedFactor = speed speedFactor = speed
else else
if speed ~= 0 then if speed ~= 0 then
speedFactor = math.abs(speed) * (maxRateRatio - 1) / 10 + 1 speedFactor = math.abs( speed ) * (maxRateRatio - 1) / 10 + 1
end end
if speed < 0 then if speed < 0 then
speedFactor = 1/speedFactor speedFactor = 1 / speedFactor
end end
end end
local wpm = math.ceil(100 * speedFactor) local wpm = math.ceil( 100 * speedFactor )
local cps = math.floor((wpm * 5)/60) local cps = math.floor( (wpm * 5) / 60 )
if type(length) == "string" then if type( length ) == "string" then
length = string.len(length) length = string.len( length )
end end
return math.ceil(length/cps) return math.ceil( length / cps )
end end
--- Text to speech function. --- Text to speech function.
function STTS.TextToSpeech(message, freqs, modulations, volume, name, coalition, point, speed, gender, culture, voice, googleTTS) function STTS.TextToSpeech( message, freqs, modulations, volume, name, coalition, point, speed, gender, culture, voice, googleTTS )
if os == nil or io == nil then if os == nil or io == nil then
env.info("[DCS-STTS] LUA modules os or io are sanitized. skipping. ") env.info( "[DCS-STTS] LUA modules os or io are sanitized. skipping. " )
return return
end end
speed = speed or 1 speed = speed or 1
gender = gender or "female" gender = gender or "female"
culture = culture or "" culture = culture or ""
voice = voice or "" voice = voice or ""
coalition=coalition or "0" coalition = coalition or "0"
name=name or "ROBOT" name = name or "ROBOT"
volume=1 volume = 1
speed=1 speed = 1
message = message:gsub( "\"", "\\\"" )
message = message:gsub("\"","\\\"") local cmd = string.format( "start /min \"\" /d \"%s\" /b \"%s\" -f %s -m %s -c %s -p %s -n \"%s\" -h", STTS.DIRECTORY, STTS.EXECUTABLE, freqs or "305", modulations or "AM", coalition, STTS.SRS_PORT, name )
local cmd = string.format("start /min \"\" /d \"%s\" /b \"%s\" -f %s -m %s -c %s -p %s -n \"%s\" -h", STTS.DIRECTORY, STTS.EXECUTABLE, freqs or "305", modulations or "AM", coalition, STTS.SRS_PORT, name)
if voice ~= "" then if voice ~= "" then
cmd = cmd .. string.format(" -V \"%s\"",voice) cmd = cmd .. string.format( " -V \"%s\"", voice )
else else
if culture ~= "" then if culture ~= "" then
cmd = cmd .. string.format(" -l %s",culture) cmd = cmd .. string.format( " -l %s", culture )
end end
if gender ~= "" then if gender ~= "" then
cmd = cmd .. string.format(" -g %s",gender) cmd = cmd .. string.format( " -g %s", gender )
end end
end end
if googleTTS == true then if googleTTS == true then
cmd = cmd .. string.format(" -G \"%s\"",STTS.GOOGLE_CREDENTIALS) cmd = cmd .. string.format( " -G \"%s\"", STTS.GOOGLE_CREDENTIALS )
end end
if speed ~= 1 then if speed ~= 1 then
cmd = cmd .. string.format(" -s %s",speed) cmd = cmd .. string.format( " -s %s", speed )
end end
if volume ~= 1.0 then if volume ~= 1.0 then
cmd = cmd .. string.format(" -v %s",volume) cmd = cmd .. string.format( " -v %s", volume )
end end
if point and type(point) == "table" and point.x then if point and type( point ) == "table" and point.x then
local lat, lon, alt = coord.LOtoLL(point) local lat, lon, alt = coord.LOtoLL( point )
lat = STTS.round(lat,4) lat = STTS.round( lat, 4 )
lon = STTS.round(lon,4) lon = STTS.round( lon, 4 )
alt = math.floor(alt) alt = math.floor( alt )
cmd = cmd .. string.format(" -L %s -O %s -A %s",lat,lon,alt) cmd = cmd .. string.format( " -L %s -O %s -A %s", lat, lon, alt )
end end
cmd = cmd ..string.format(" -t \"%s\"",message) cmd = cmd .. string.format( " -t \"%s\"", message )
if string.len(cmd) > 255 then if string.len( cmd ) > 255 then
local filename = os.getenv('TMP') .. "\\DCS_STTS-" .. STTS.uuid() .. ".bat" local filename = os.getenv( 'TMP' ) .. "\\DCS_STTS-" .. STTS.uuid() .. ".bat"
local script = io.open(filename,"w+") local script = io.open( filename, "w+" )
script:write(cmd .. " && exit" ) script:write( cmd .. " && exit" )
script:close() script:close()
cmd = string.format("\"%s\"",filename) cmd = string.format( "\"%s\"", filename )
timer.scheduleFunction(os.remove, filename, timer.getTime() + 1) timer.scheduleFunction( os.remove, filename, timer.getTime() + 1 )
end end
if string.len(cmd) > 255 then if string.len( cmd ) > 255 then
env.info("[DCS-STTS] - cmd string too long") env.info( "[DCS-STTS] - cmd string too long" )
env.info("[DCS-STTS] TextToSpeech Command :\n" .. cmd.."\n") env.info( "[DCS-STTS] TextToSpeech Command :\n" .. cmd .. "\n" )
end end
os.execute(cmd) os.execute( cmd )
return STTS.getSpeechTime(message,speed,googleTTS) return STTS.getSpeechTime( message, speed, googleTTS )
end end
--- Play mp3 function. --- Play mp3 function.
@@ -235,22 +236,21 @@ end
-- @param #string freqs Frequencies, e.g. "305, 256". -- @param #string freqs Frequencies, e.g. "305, 256".
-- @param #string modulations Modulations, e.g. "AM, FM". -- @param #string modulations Modulations, e.g. "AM, FM".
-- @param #string volume Volume, e.g. "0.5". -- @param #string volume Volume, e.g. "0.5".
function STTS.PlayMP3(pathToMP3, freqs, modulations, volume, name, coalition, point) function STTS.PlayMP3( pathToMP3, freqs, modulations, volume, name, coalition, point )
local cmd = string.format("start \"\" /d \"%s\" /b /min \"%s\" -i \"%s\" -f %s -m %s -c %s -p %s -n \"%s\" -v %s -h", local cmd = string.format( "start \"\" /d \"%s\" /b /min \"%s\" -i \"%s\" -f %s -m %s -c %s -p %s -n \"%s\" -v %s -h", STTS.DIRECTORY, STTS.EXECUTABLE, pathToMP3, freqs or "305", modulations or "AM", coalition or "0", STTS.SRS_PORT, name or "ROBOT", volume or "1" )
STTS.DIRECTORY, STTS.EXECUTABLE, pathToMP3, freqs or "305", modulations or "AM", coalition or "0", STTS.SRS_PORT, name or "ROBOT", volume or "1")
if point and type(point) == "table" and point.x then if point and type( point ) == "table" and point.x then
local lat, lon, alt = coord.LOtoLL(point) local lat, lon, alt = coord.LOtoLL( point )
lat = STTS.round(lat,4) lat = STTS.round( lat, 4 )
lon = STTS.round(lon,4) lon = STTS.round( lon, 4 )
alt = math.floor(alt) alt = math.floor( alt )
cmd = cmd .. string.format(" -L %s -O %s -A %s",lat,lon,alt) cmd = cmd .. string.format( " -L %s -O %s -A %s", lat, lon, alt )
end end
env.info("[DCS-STTS] MP3/OGG Command :\n" .. cmd.."\n") env.info( "[DCS-STTS] MP3/OGG Command :\n" .. cmd .. "\n" )
os.execute(cmd) os.execute( cmd )
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
+69 -33
View File
@@ -310,8 +310,7 @@ end
--- Returns the @{DCS#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission. --- Returns the @{DCS#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission.
-- @param Wrapper.Positionable#POSITIONABLE self -- @param Wrapper.Positionable#POSITIONABLE self
-- @return DCS#Position The 3D position vectors of the POSITIONABLE. -- @return DCS#Position The 3D position vectors of the POSITIONABLE or #nil if the groups not existing or alive.
-- @return #nil The POSITIONABLE is not existing or alive.
function GROUP:GetPositionVec3() -- Overridden from POSITIONABLE:GetPositionVec3() function GROUP:GetPositionVec3() -- Overridden from POSITIONABLE:GetPositionVec3()
self:F2( self.PositionableName ) self:F2( self.PositionableName )
@@ -339,9 +338,7 @@ end
-- If the first @{Wrapper.Unit} of the group is inactive, it will return false. -- If the first @{Wrapper.Unit} of the group is inactive, it will return false.
-- --
-- @param #GROUP self -- @param #GROUP self
-- @return #boolean true if the group is alive and active. -- @return #boolean `true` if the group is alive *and* active, `false` if the group is alive but inactive or `#nil` if the group does not exist anymore.
-- @return #boolean false if the group is alive but inactive.
-- @return #nil if the group does not exist anymore.
function GROUP:IsAlive() function GROUP:IsAlive()
self:F2( self.GroupName ) self:F2( self.GroupName )
@@ -363,8 +360,7 @@ end
--- Returns if the group is activated. --- Returns if the group is activated.
-- @param #GROUP self -- @param #GROUP self
-- @return #boolean true if group is activated. -- @return #boolean `true` if group is activated or `#nil` The group is not existing or alive.
-- @return #nil The group is not existing or alive.
function GROUP:IsActive() function GROUP:IsActive()
self:F2( self.GroupName ) self:F2( self.GroupName )
@@ -412,7 +408,6 @@ function GROUP:Destroy( GenerateEvent, delay )
self:F2( self.GroupName ) self:F2( self.GroupName )
if delay and delay>0 then if delay and delay>0 then
--SCHEDULER:New(nil, GROUP.Destroy, {self, GenerateEvent}, delay)
self:ScheduleOnce(delay, GROUP.Destroy, self, GenerateEvent) self:ScheduleOnce(delay, GROUP.Destroy, self, GenerateEvent)
else else
@@ -568,12 +563,12 @@ function GROUP:GetSpeedMax()
local Units=self:GetUnits() local Units=self:GetUnits()
local speedmax=nil local speedmax=0
for _,unit in pairs(Units) do for _,unit in pairs(Units) do
local unit=unit --Wrapper.Unit#UNIT local unit=unit --Wrapper.Unit#UNIT
local speed=unit:GetSpeedMax() local speed=unit:GetSpeedMax()
if speedmax==nil then if speedmax==0 then
speedmax=speed speedmax=speed
elseif speed<speedmax then elseif speed<speedmax then
speedmax=speed speedmax=speed
@@ -2326,41 +2321,44 @@ function GROUP:GetAttribute()
local unarmedship=self:HasAttribute("Unarmed ships") local unarmedship=self:HasAttribute("Unarmed ships")
-- Define attribute. Order is important. -- Define attribute. Order of attack is important.
if transportplane then if fighter then
attribute=GROUP.Attribute.AIR_TRANSPORTPLANE
elseif awacs then
attribute=GROUP.Attribute.AIR_AWACS
elseif fighter then
attribute=GROUP.Attribute.AIR_FIGHTER attribute=GROUP.Attribute.AIR_FIGHTER
elseif bomber then elseif bomber then
attribute=GROUP.Attribute.AIR_BOMBER attribute=GROUP.Attribute.AIR_BOMBER
elseif awacs then
attribute=GROUP.Attribute.AIR_AWACS
elseif transportplane then
attribute=GROUP.Attribute.AIR_TRANSPORTPLANE
elseif tanker then elseif tanker then
attribute=GROUP.Attribute.AIR_TANKER attribute=GROUP.Attribute.AIR_TANKER
elseif transporthelo then -- helos
attribute=GROUP.Attribute.AIR_TRANSPORTHELO
elseif attackhelicopter then elseif attackhelicopter then
attribute=GROUP.Attribute.AIR_ATTACKHELO attribute=GROUP.Attribute.AIR_ATTACKHELO
elseif transporthelo then
attribute=GROUP.Attribute.AIR_TRANSPORTHELO
elseif uav then elseif uav then
attribute=GROUP.Attribute.AIR_UAV attribute=GROUP.Attribute.AIR_UAV
elseif apc then -- ground - order of attack
attribute=GROUP.Attribute.GROUND_APC
elseif infantry then
attribute=GROUP.Attribute.GROUND_INFANTRY
elseif artillery then
attribute=GROUP.Attribute.GROUND_ARTILLERY
elseif tank then
attribute=GROUP.Attribute.GROUND_TANK
elseif aaa then
attribute=GROUP.Attribute.GROUND_AAA
elseif ewr then elseif ewr then
attribute=GROUP.Attribute.GROUND_EWR attribute=GROUP.Attribute.GROUND_EWR
elseif sam then elseif sam then
attribute=GROUP.Attribute.GROUND_SAM attribute=GROUP.Attribute.GROUND_SAM
elseif aaa then
attribute=GROUP.Attribute.GROUND_AAA
elseif artillery then
attribute=GROUP.Attribute.GROUND_ARTILLERY
elseif tank then
attribute=GROUP.Attribute.GROUND_TANK
elseif apc then
attribute=GROUP.Attribute.GROUND_APC
elseif infantry then
attribute=GROUP.Attribute.GROUND_INFANTRY
elseif truck then elseif truck then
attribute=GROUP.Attribute.GROUND_TRUCK attribute=GROUP.Attribute.GROUND_TRUCK
elseif train then elseif train then
attribute=GROUP.Attribute.GROUND_TRAIN attribute=GROUP.Attribute.GROUND_TRAIN
-- ships
elseif aircraftcarrier then elseif aircraftcarrier then
attribute=GROUP.Attribute.NAVAL_AIRCRAFTCARRIER attribute=GROUP.Attribute.NAVAL_AIRCRAFTCARRIER
elseif warship then elseif warship then
@@ -2578,8 +2576,10 @@ end
-- @return #GROUP self -- @return #GROUP self
function GROUP:SetCommandInvisible(switch) function GROUP:SetCommandInvisible(switch)
self:F2( self.GroupName ) self:F2( self.GroupName )
local switch = switch or false if switch==nil then
local SetInvisible = {id = 'SetInvisible', params = {value = true}} switch=false
end
local SetInvisible = {id = 'SetInvisible', params = {value = switch}}
self:SetCommand(SetInvisible) self:SetCommand(SetInvisible)
return self return self
end end
@@ -2590,9 +2590,11 @@ end
-- @return #GROUP self -- @return #GROUP self
function GROUP:SetCommandImmortal(switch) function GROUP:SetCommandImmortal(switch)
self:F2( self.GroupName ) self:F2( self.GroupName )
local switch = switch or false if switch==nil then
local SetInvisible = {id = 'SetImmortal', params = {value = true}} switch=false
self:SetCommand(SetInvisible) end
local SetImmortal = {id = 'SetImmortal', params = {value = switch}}
self:SetCommand(SetImmortal)
return self return self
end end
@@ -2607,6 +2609,40 @@ function GROUP:GetSkill()
return skill return skill
end end
--- Get the unit in the group with the highest threat level, which is still alive.
-- @param #GROUP self
-- @return Wrapper.Unit#UNIT The most dangerous unit in the group.
-- @return #number Threat level of the unit.
function GROUP:GetHighestThreat()
-- Get units of the group.
local units=self:GetUnits()
if units then
local threat=nil ; local maxtl=0
for _,_unit in pairs(units or {}) do
local unit=_unit --Wrapper.Unit#UNIT
if unit and unit:IsAlive() then
-- Threat level of group.
local tl=unit:GetThreatLevel()
-- Check if greater the current threat.
if tl>maxtl then
maxtl=tl
threat=unit
end
end
end
return threat, maxtl
end
return nil, nil
end
--do -- Smoke --do -- Smoke
-- --
----- Signal a flare at the position of the GROUP. ----- Signal a flare at the position of the GROUP.
@@ -176,7 +176,7 @@ function IDENTIFIABLE:GetCoalitionName()
if DCSIdentifiable then if DCSIdentifiable then
-- Get coaliton ID. -- Get coalition ID.
local IdentifiableCoalition = DCSIdentifiable:getCoalition() local IdentifiableCoalition = DCSIdentifiable:getCoalition()
self:T3( IdentifiableCoalition ) self:T3( IdentifiableCoalition )
+170 -183
View File
@@ -15,7 +15,6 @@
-- @module Wrapper.Marker -- @module Wrapper.Marker
-- @image Wrapper_Marker.png -- @image Wrapper_Marker.png
--- Marker class. --- Marker class.
-- @type MARKER -- @type MARKER
-- @field #string ClassName Name of the class. -- @field #string ClassName Name of the class.
@@ -24,7 +23,7 @@
-- @field #number mid Marker ID. -- @field #number mid Marker ID.
-- @field Core.Point#COORDINATE coordinate Coordinate of the mark. -- @field Core.Point#COORDINATE coordinate Coordinate of the mark.
-- @field #string text Text displayed in the mark panel. -- @field #string text Text displayed in the mark panel.
-- @field #string message Message dispayed when the mark is added. -- @field #string message Message displayed when the mark is added.
-- @field #boolean readonly Marker is read-only. -- @field #boolean readonly Marker is read-only.
-- @field #number coalition Coalition to which the marker is displayed. -- @field #number coalition Coalition to which the marker is displayed.
-- @extends Core.Fsm#FSM -- @extends Core.Fsm#FSM
@@ -42,29 +41,29 @@
-- # Create a Marker -- # Create a Marker
-- --
-- -- Create a MARKER object at Batumi with a trivial text. -- -- Create a MARKER object at Batumi with a trivial text.
-- local Coordinate=AIRBASE:FindByName("Batumi"):GetCoordinate() -- local Coordinate = AIRBASE:FindByName( "Batumi" ):GetCoordinate()
-- mymarker=MARKER:New(Coordinate, "I am Batumi Airfield") -- mymarker = MARKER:New( Coordinate, "I am Batumi Airfield" )
-- --
-- Now this does **not** show the marker yet. We still need to specifiy to whom it is shown. There are several options, i.e. -- Now this does **not** show the marker yet. We still need to specify to whom it is shown. There are several options, i.e.
-- show the marker to everyone, to a speficic coaliton only, or only to a specific group. -- show the marker to everyone, to a specific coalition only, or only to a specific group.
-- --
-- ## For Everyone -- ## For Everyone
-- --
-- If the marker should be visible to everyone, you can use the :ToAll() function. -- If the marker should be visible to everyone, you can use the :ToAll() function.
-- --
-- mymarker=MARKER:New(Coordinate, "I am Batumi Airfield"):ToAll() -- mymarker = MARKER:New( Coordinate, "I am Batumi Airfield" ):ToAll()
-- --
-- ## For a Coaliton -- ## For a Coalition
-- --
-- If the maker should be visible to a specific coalition, you can use the :ToCoalition() function. -- If the maker should be visible to a specific coalition, you can use the :ToCoalition() function.
-- --
-- mymarker=MARKER:New(Coordinate, "I am Batumi Airfield"):ToCoaliton(coaliton.side.BLUE) -- mymarker = MARKER:New( Coordinate , "I am Batumi Airfield" ):ToCoalition( coalition.side.BLUE )
-- --
-- ### To Blue Coaliton -- ### To Blue Coalition
-- --
-- ### To Red Coalition -- ### To Red Coalition
-- --
-- This would show the marker only to the Blue coaliton. -- This would show the marker only to the Blue coalition.
-- --
-- ## For a Group -- ## For a Group
-- --
@@ -76,28 +75,28 @@
-- --
-- The marker text and coordinate can be updated easily as shown below. -- The marker text and coordinate can be updated easily as shown below.
-- --
-- However, note that **updateing involves to remove and recreate the marker if either text or its coordinate is changed**. -- However, note that **updating involves to remove and recreate the marker if either text or its coordinate is changed**.
-- *This is a DCS scripting engine limitation.* -- *This is a DCS scripting engine limitation.*
-- --
-- ## Update Text -- ## Update Text
-- --
-- If you created a marker "mymarker" as shown above, you can update the dispayed test by -- If you created a marker "mymarker" as shown above, you can update the displayed test by
-- --
-- mymarker:UpdateText("I am the new text at Batumi") -- mymarker:UpdateText( "I am the new text at Batumi" )
-- --
-- The update can also be delayed by, e.g. 90 seconds, using -- The update can also be delayed by, e.g. 90 seconds, using
-- --
-- mymarker:UpdateText("I am the new text at Batumi", 90) -- mymarker:UpdateText( "I am the new text at Batumi", 90 )
-- --
-- ## Update Coordinate -- ## Update Coordinate
-- --
-- If you created a marker "mymarker" as shown above, you can update its coordinate on the F10 map by -- If you created a marker "mymarker" as shown above, you can update its coordinate on the F10 map by
-- --
-- mymarker:UpdateCoordinate(NewCoordinate) -- mymarker:UpdateCoordinate( NewCoordinate )
-- --
-- The update can also be delayed by, e.g. 60 seconds, using -- The update can also be delayed by, e.g. 60 seconds, using
-- --
-- mymarker:UpdateCoordinate(NewCoordinate, 60) -- mymarker:UpdateCoordinate( NewCoordinate , 60 )
-- --
-- # Retrieve Data -- # Retrieve Data
-- --
@@ -105,18 +104,18 @@
-- --
-- ## Text -- ## Text
-- --
-- local text=mymarker:GetText() -- local text =mymarker:GetText()
-- env.info("Marker Text = " .. text) -- env.info( "Marker Text = " .. text )
-- --
-- ## Coordinate -- ## Coordinate
-- --
-- local Coordinate=mymarker:GetCoordinate() -- local Coordinate = mymarker:GetCoordinate()
-- env.info("Marker Coordinate LL DSM = " .. Coordinate:ToStringLLDMS()) -- env.info( "Marker Coordinate LL DSM = " .. Coordinate:ToStringLLDMS() )
-- --
-- --
-- # FSM Events -- # FSM Events
-- --
-- Moose creates addditonal events, so called FSM event, when markers are added, changed, removed, and text or the coordianteis updated. -- Moose creates additional events, so called FSM event, when markers are added, changed, removed, and text or the coordinate is updated.
-- --
-- These events can be captured and used for processing via OnAfter functions as shown below. -- These events can be captured and used for processing via OnAfter functions as shown below.
-- --
@@ -133,26 +132,25 @@
-- --
-- # Examples -- # Examples
-- --
--
-- @field #MARKER -- @field #MARKER
MARKER = { MARKER = {
ClassName = "MARKER", ClassName = "MARKER",
Debug = false, Debug = false,
lid = nil, lid = nil,
mid = nil, mid = nil,
coordinate = nil, coordinate = nil,
text = nil, text = nil,
message = nil, message = nil,
readonly = nil, readonly = nil,
coalition = nil, coalition = nil,
} }
--- Marker ID. Running number. --- Marker ID. Running number.
_MARKERID=0 _MARKERID = 0
--- Marker class version. --- Marker class version.
-- @field #string version -- @field #string version
MARKER.version="0.1.0" MARKER.version = "0.1.0"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@@ -172,38 +170,38 @@ MARKER.version="0.1.0"
-- @param Core.Point#COORDINATE Coordinate Coordinate where to place the marker. -- @param Core.Point#COORDINATE Coordinate Coordinate where to place the marker.
-- @param #string Text Text displayed on the mark panel. -- @param #string Text Text displayed on the mark panel.
-- @return #MARKER self -- @return #MARKER self
function MARKER:New(Coordinate, Text) function MARKER:New( Coordinate, Text )
-- Inherit everything from FSM class. -- Inherit everything from FSM class.
local self=BASE:Inherit(self, FSM:New()) -- #MARKER local self = BASE:Inherit( self, FSM:New() ) -- #MARKER
self.coordinate=Coordinate self.coordinate = Coordinate
self.text=Text self.text = Text
-- Defaults -- Defaults
self.readonly=false self.readonly = false
self.message="" self.message = ""
-- New marker ID. This is not the one of the actual marker. -- New marker ID. This is not the one of the actual marker.
_MARKERID=_MARKERID+1 _MARKERID = _MARKERID + 1
self.myid=_MARKERID self.myid = _MARKERID
-- Log ID. -- Log ID.
self.lid=string.format("Marker #%d | ", self.myid) self.lid = string.format( "Marker #%d | ", self.myid )
-- Start State. -- Start State.
self:SetStartState("Invisible") self:SetStartState( "Invisible" )
-- Add FSM transitions. -- Add FSM transitions.
-- From State --> Event --> To State -- From State --> Event --> To State
self:AddTransition("Invisible", "Added", "Visible") -- Marker was added. self:AddTransition( "Invisible", "Added", "Visible" ) -- Marker was added.
self:AddTransition("Visible", "Removed", "Invisible") -- Marker was removed. self:AddTransition( "Visible", "Removed", "Invisible" ) -- Marker was removed.
self:AddTransition("*", "Changed", "*") -- Marker was changed. self:AddTransition( "*", "Changed", "*" ) -- Marker was changed.
self:AddTransition("*", "TextUpdate", "*") -- Text updated. self:AddTransition( "*", "TextUpdate", "*" ) -- Text updated.
self:AddTransition("*", "CoordUpdate", "*") -- Coordinates updated. self:AddTransition( "*", "CoordUpdate", "*" ) -- Coordinates updated.
--- Triggers the FSM event "Added". --- Triggers the FSM event "Added".
-- @function [parent=#MARKER] Added -- @function [parent=#MARKER] Added
@@ -223,7 +221,6 @@ function MARKER:New(Coordinate, Text)
-- @param #string To To state. -- @param #string To To state.
-- @param Core.Event#EVENTDATA EventData Event data table. -- @param Core.Event#EVENTDATA EventData Event data table.
--- Triggers the FSM event "Removed". --- Triggers the FSM event "Removed".
-- @function [parent=#MARKER] Removed -- @function [parent=#MARKER] Removed
-- @param #MARKER self -- @param #MARKER self
@@ -242,7 +239,6 @@ function MARKER:New(Coordinate, Text)
-- @param #string To To state. -- @param #string To To state.
-- @param Core.Event#EVENTDATA EventData Event data table. -- @param Core.Event#EVENTDATA EventData Event data table.
--- Triggers the FSM event "Changed". --- Triggers the FSM event "Changed".
-- @function [parent=#MARKER] Changed -- @function [parent=#MARKER] Changed
-- @param #MARKER self -- @param #MARKER self
@@ -261,7 +257,6 @@ function MARKER:New(Coordinate, Text)
-- @param #string To To state. -- @param #string To To state.
-- @param Core.Event#EVENTDATA EventData Event data table. -- @param Core.Event#EVENTDATA EventData Event data table.
--- Triggers the FSM event "TextUpdate". --- Triggers the FSM event "TextUpdate".
-- @function [parent=#MARKER] TextUpdate -- @function [parent=#MARKER] TextUpdate
-- @param #MARKER self -- @param #MARKER self
@@ -280,7 +275,6 @@ function MARKER:New(Coordinate, Text)
-- @param #string To To state. -- @param #string To To state.
-- @param #string Text The new text. -- @param #string Text The new text.
--- Triggers the FSM event "CoordUpdate". --- Triggers the FSM event "CoordUpdate".
-- @function [parent=#MARKER] CoordUpdate -- @function [parent=#MARKER] CoordUpdate
-- @param #MARKER self -- @param #MARKER self
@@ -299,11 +293,10 @@ function MARKER:New(Coordinate, Text)
-- @param #string To To state. -- @param #string To To state.
-- @param Core.Point#COORDINATE Coordinate The updated Coordinate. -- @param Core.Point#COORDINATE Coordinate The updated Coordinate.
-- Handle events. -- Handle events.
self:HandleEvent(EVENTS.MarkAdded) self:HandleEvent( EVENTS.MarkAdded )
self:HandleEvent(EVENTS.MarkRemoved) self:HandleEvent( EVENTS.MarkRemoved )
self:HandleEvent(EVENTS.MarkChange) self:HandleEvent( EVENTS.MarkChange )
return self return self
end end
@@ -317,7 +310,7 @@ end
-- @return #MARKER self -- @return #MARKER self
function MARKER:ReadOnly() function MARKER:ReadOnly()
self.readonly=true self.readonly = true
return self return self
end end
@@ -326,9 +319,9 @@ end
-- @param #MARKER self -- @param #MARKER self
-- @param #string Text Message displayed when the marker is added. -- @param #string Text Message displayed when the marker is added.
-- @return #MARKER self -- @return #MARKER self
function MARKER:Message(Text) function MARKER:Message( Text )
self.message=Text or "" self.message = Text or ""
return self return self
end end
@@ -337,28 +330,28 @@ end
-- @param #MARKER self -- @param #MARKER self
-- @param #number Delay (Optional) Delay in seconds, before the marker is created. -- @param #number Delay (Optional) Delay in seconds, before the marker is created.
-- @return #MARKER self -- @return #MARKER self
function MARKER:ToAll(Delay) function MARKER:ToAll( Delay )
if Delay and Delay>0 then if Delay and Delay > 0 then
self:ScheduleOnce(Delay, MARKER.ToAll, self) self:ScheduleOnce( Delay, MARKER.ToAll, self )
else else
self.toall=true self.toall = true
self.tocoaliton=nil self.tocoalition = nil
self.coalition=nil self.coalition = nil
self.togroup=nil self.togroup = nil
self.groupname=nil self.groupname = nil
self.groupid=nil self.groupid = nil
-- First remove an existing mark. -- First remove an existing mark.
if self.shown then if self.shown then
self:Remove() self:Remove()
end end
self.mid=UTILS.GetMarkID() self.mid = UTILS.GetMarkID()
-- Call DCS function. -- Call DCS function.
trigger.action.markToAll(self.mid, self.text, self.coordinate:GetVec3(), self.readonly, self.message) trigger.action.markToAll( self.mid, self.text, self.coordinate:GetVec3(), self.readonly, self.message )
end end
@@ -367,32 +360,32 @@ end
--- Place marker visible for a specific coalition only. --- Place marker visible for a specific coalition only.
-- @param #MARKER self -- @param #MARKER self
-- @param #number Coalition Coalition 1=Red, 2=Blue, 0=Neutral. See `coaliton.side.RED`. -- @param #number Coalition Coalition 1=Red, 2=Blue, 0=Neutral. See `coalition.side.RED`.
-- @param #number Delay (Optional) Delay in seconds, before the marker is created. -- @param #number Delay (Optional) Delay in seconds, before the marker is created.
-- @return #MARKER self -- @return #MARKER self
function MARKER:ToCoalition(Coalition, Delay) function MARKER:ToCoalition( Coalition, Delay )
if Delay and Delay>0 then if Delay and Delay > 0 then
self:ScheduleOnce(Delay, MARKER.ToCoalition, self, Coalition) self:ScheduleOnce( Delay, MARKER.ToCoalition, self, Coalition )
else else
self.coalition=Coalition self.coalition = Coalition
self.tocoaliton=true self.tocoalition = true
self.toall=false self.toall = false
self.togroup=false self.togroup = false
self.groupname=nil self.groupname = nil
self.groupid=nil self.groupid = nil
-- First remove an existing mark. -- First remove an existing mark.
if self.shown then if self.shown then
self:Remove() self:Remove()
end end
self.mid=UTILS.GetMarkID() self.mid = UTILS.GetMarkID()
-- Call DCS function. -- Call DCS function.
trigger.action.markToCoalition(self.mid, self.text, self.coordinate:GetVec3(), self.coalition, self.readonly, self.message) trigger.action.markToCoalition( self.mid, self.text, self.coordinate:GetVec3(), self.coalition, self.readonly, self.message )
end end
@@ -403,8 +396,8 @@ end
-- @param #MARKER self -- @param #MARKER self
-- @param #number Delay (Optional) Delay in seconds, before the marker is created. -- @param #number Delay (Optional) Delay in seconds, before the marker is created.
-- @return #MARKER self -- @return #MARKER self
function MARKER:ToBlue(Delay) function MARKER:ToBlue( Delay )
self:ToCoalition(coalition.side.BLUE, Delay) self:ToCoalition( coalition.side.BLUE, Delay )
return self return self
end end
@@ -412,8 +405,8 @@ end
-- @param #MARKER self -- @param #MARKER self
-- @param #number Delay (Optional) Delay in seconds, before the marker is created. -- @param #number Delay (Optional) Delay in seconds, before the marker is created.
-- @return #MARKER self -- @return #MARKER self
function MARKER:ToRed(Delay) function MARKER:ToRed( Delay )
self:ToCoalition(coalition.side.RED, Delay) self:ToCoalition( coalition.side.RED, Delay )
return self return self
end end
@@ -421,51 +414,50 @@ end
-- @param #MARKER self -- @param #MARKER self
-- @param #number Delay (Optional) Delay in seconds, before the marker is created. -- @param #number Delay (Optional) Delay in seconds, before the marker is created.
-- @return #MARKER self -- @return #MARKER self
function MARKER:ToNeutral(Delay) function MARKER:ToNeutral( Delay )
self:ToCoalition(coalition.side.NEUTRAL, Delay) self:ToCoalition( coalition.side.NEUTRAL, Delay )
return self return self
end end
--- Place marker visible for a specific group only. --- Place marker visible for a specific group only.
-- @param #MARKER self -- @param #MARKER self
-- @param Wrapper.Group#GROUP Group The group to which the marker is displayed. -- @param Wrapper.Group#GROUP Group The group to which the marker is displayed.
-- @param #number Delay (Optional) Delay in seconds, before the marker is created. -- @param #number Delay (Optional) Delay in seconds, before the marker is created.
-- @return #MARKER self -- @return #MARKER self
function MARKER:ToGroup(Group, Delay) function MARKER:ToGroup( Group, Delay )
if Delay and Delay>0 then if Delay and Delay > 0 then
self:ScheduleOnce(Delay, MARKER.ToGroup, self, Group) self:ScheduleOnce( Delay, MARKER.ToGroup, self, Group )
else else
-- Check if group exists. -- Check if group exists.
if Group and Group:IsAlive()~=nil then if Group and Group:IsAlive() ~= nil then
self.groupid=Group:GetID() self.groupid = Group:GetID()
if self.groupid then if self.groupid then
self.groupname=Group:GetName() self.groupname = Group:GetName()
self.togroup=true self.togroup = true
self.tocoaliton=nil self.tocoalition = nil
self.coalition=nil self.coalition = nil
self.toall=nil self.toall = nil
-- First remove an existing mark. -- First remove an existing mark.
if self.shown then if self.shown then
self:Remove() self:Remove()
end end
self.mid=UTILS.GetMarkID() self.mid = UTILS.GetMarkID()
-- Call DCS function. -- Call DCS function.
trigger.action.markToGroup(self.mid, self.text, self.coordinate:GetVec3(), self.groupid, self.readonly, self.message) trigger.action.markToGroup( self.mid, self.text, self.coordinate:GetVec3(), self.groupid, self.readonly, self.message )
end end
else else
--TODO: Warning! -- TODO: Warning!
end end
end end
@@ -478,17 +470,17 @@ end
-- @param #string Text Updated text. -- @param #string Text Updated text.
-- @param #number Delay (Optional) Delay in seconds, before the marker is created. -- @param #number Delay (Optional) Delay in seconds, before the marker is created.
-- @return #MARKER self -- @return #MARKER self
function MARKER:UpdateText(Text, Delay) function MARKER:UpdateText( Text, Delay )
if Delay and Delay>0 then if Delay and Delay > 0 then
self:ScheduleOnce(Delay, MARKER.UpdateText, self, Text) self:ScheduleOnce( Delay, MARKER.UpdateText, self, Text )
else else
self.text=tostring(Text) self.text = tostring( Text )
self:Refresh() self:Refresh()
self:TextUpdate(tostring(Text)) self:TextUpdate( tostring( Text ) )
end end
@@ -500,17 +492,17 @@ end
-- @param Core.Point#COORDINATE Coordinate The new coordinate. -- @param Core.Point#COORDINATE Coordinate The new coordinate.
-- @param #number Delay (Optional) Delay in seconds, before the marker is created. -- @param #number Delay (Optional) Delay in seconds, before the marker is created.
-- @return #MARKER self -- @return #MARKER self
function MARKER:UpdateCoordinate(Coordinate, Delay) function MARKER:UpdateCoordinate( Coordinate, Delay )
if Delay and Delay>0 then if Delay and Delay > 0 then
self:ScheduleOnce(Delay, MARKER.UpdateCoordinate, self, Coordinate) self:ScheduleOnce( Delay, MARKER.UpdateCoordinate, self, Coordinate )
else else
self.coordinate=Coordinate self.coordinate = Coordinate
self:Refresh() self:Refresh()
self:CoordUpdate(Coordinate) self:CoordUpdate( Coordinate )
end end
@@ -521,28 +513,28 @@ end
-- @param #MARKER self -- @param #MARKER self
-- @param #number Delay (Optional) Delay in seconds, before the marker is created. -- @param #number Delay (Optional) Delay in seconds, before the marker is created.
-- @return #MARKER self -- @return #MARKER self
function MARKER:Refresh(Delay) function MARKER:Refresh( Delay )
if Delay and Delay>0 then if Delay and Delay > 0 then
self:ScheduleOnce(Delay, MARKER.Refresh, self) self:ScheduleOnce( Delay, MARKER.Refresh, self )
else else
if self.toall then if self.toall then
self:ToAll() self:ToAll()
elseif self.tocoaliton then elseif self.tocoalition then
self:ToCoalition(self.coalition) self:ToCoalition( self.coalition )
elseif self.togroup then elseif self.togroup then
local group=GROUP:FindByName(self.groupname) local group = GROUP:FindByName( self.groupname )
self:ToGroup(group) self:ToGroup( group )
else else
self:E(self.lid.."ERROR: unknown To in :Refresh()!") self:E( self.lid .. "ERROR: unknown To in :Refresh()!" )
end end
end end
@@ -554,16 +546,16 @@ end
-- @param #MARKER self -- @param #MARKER self
-- @param #number Delay (Optional) Delay in seconds, before the marker is removed. -- @param #number Delay (Optional) Delay in seconds, before the marker is removed.
-- @return #MARKER self -- @return #MARKER self
function MARKER:Remove(Delay) function MARKER:Remove( Delay )
if Delay and Delay>0 then if Delay and Delay > 0 then
self:ScheduleOnce(Delay, MARKER.Remove, self) self:ScheduleOnce( Delay, MARKER.Remove, self )
else else
if self.shown then if self.shown then
-- Call DCS function. -- Call DCS function.
trigger.action.removeMark(self.mid) trigger.action.removeMark( self.mid )
end end
@@ -590,24 +582,23 @@ end
-- @param #MARKER self -- @param #MARKER self
-- @param #string Text Marker text. Default is an empty sting "". -- @param #string Text Marker text. Default is an empty sting "".
-- @return #MARKER self -- @return #MARKER self
function MARKER:SetText(Text) function MARKER:SetText( Text )
self.text=Text and tostring(Text) or "" self.text = Text and tostring( Text ) or ""
return self return self
end end
--- Check if marker is currently visible on the F10 map. --- Check if marker is currently visible on the F10 map.
-- @param #MARKER self -- @param #MARKER self
-- @return #boolean True if the marker is currently visible. -- @return #boolean True if the marker is currently visible.
function MARKER:IsVisible() function MARKER:IsVisible()
return self:Is("Visible") return self:Is( "Visible" )
end end
--- Check if marker is currently invisible on the F10 map. --- Check if marker is currently invisible on the F10 map.
-- @param #MARKER self -- @param #MARKER self
-- @return -- @return
function MARKER:IsInvisible() function MARKER:IsInvisible()
return self:Is("Invisible") return self:Is( "Invisible" )
end end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -617,19 +608,19 @@ end
--- Event function when a MARKER is added. --- Event function when a MARKER is added.
-- @param #MARKER self -- @param #MARKER self
-- @param Core.Event#EVENTDATA EventData -- @param Core.Event#EVENTDATA EventData
function MARKER:OnEventMarkAdded(EventData) function MARKER:OnEventMarkAdded( EventData )
if EventData and EventData.MarkID then if EventData and EventData.MarkID then
local MarkID=EventData.MarkID local MarkID = EventData.MarkID
self:T3(self.lid..string.format("Captured event MarkAdded for Mark ID=%s", tostring(MarkID))) self:T3( self.lid .. string.format( "Captured event MarkAdded for Mark ID=%s", tostring( MarkID ) ) )
if MarkID==self.mid then if MarkID == self.mid then
self.shown=true self.shown = true
self:Added(EventData) self:Added( EventData )
end end
@@ -640,19 +631,19 @@ end
--- Event function when a MARKER is removed. --- Event function when a MARKER is removed.
-- @param #MARKER self -- @param #MARKER self
-- @param Core.Event#EVENTDATA EventData -- @param Core.Event#EVENTDATA EventData
function MARKER:OnEventMarkRemoved(EventData) function MARKER:OnEventMarkRemoved( EventData )
if EventData and EventData.MarkID then if EventData and EventData.MarkID then
local MarkID=EventData.MarkID local MarkID = EventData.MarkID
self:T3(self.lid..string.format("Captured event MarkAdded for Mark ID=%s", tostring(MarkID))) self:T3( self.lid .. string.format( "Captured event MarkAdded for Mark ID=%s", tostring( MarkID ) ) )
if MarkID==self.mid then if MarkID == self.mid then
self.shown=false self.shown = false
self:Removed(EventData) self:Removed( EventData )
end end
@@ -663,19 +654,19 @@ end
--- Event function when a MARKER changed. --- Event function when a MARKER changed.
-- @param #MARKER self -- @param #MARKER self
-- @param Core.Event#EVENTDATA EventData -- @param Core.Event#EVENTDATA EventData
function MARKER:OnEventMarkChange(EventData) function MARKER:OnEventMarkChange( EventData )
if EventData and EventData.MarkID then if EventData and EventData.MarkID then
local MarkID=EventData.MarkID local MarkID = EventData.MarkID
self:T3(self.lid..string.format("Captured event MarkChange for Mark ID=%s", tostring(MarkID))) self:T3( self.lid .. string.format( "Captured event MarkChange for Mark ID=%s", tostring( MarkID ) ) )
if MarkID==self.mid then if MarkID == self.mid then
self:Changed(EventData) self:Changed( EventData )
self:TextChanged(tostring(EventData.MarkText)) self:TextChanged( tostring( EventData.MarkText ) )
end end
@@ -693,17 +684,17 @@ end
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
-- @param Core.Event#EVENTDATA EventData Event data table. -- @param Core.Event#EVENTDATA EventData Event data table.
function MARKER:onafterAdded(From, Event, To, EventData) function MARKER:onafterAdded( From, Event, To, EventData )
-- Debug info. -- Debug info.
local text=string.format("Captured event MarkAdded for myself:\n") local text = string.format( "Captured event MarkAdded for myself:\n" )
text=text..string.format("Marker ID = %s\n", tostring(EventData.MarkID)) text = text .. string.format( "Marker ID = %s\n", tostring( EventData.MarkID ) )
text=text..string.format("Coalition = %s\n", tostring(EventData.MarkCoalition)) text = text .. string.format( "Coalition = %s\n", tostring( EventData.MarkCoalition ) )
text=text..string.format("Group ID = %s\n", tostring(EventData.MarkGroupID)) text = text .. string.format( "Group ID = %s\n", tostring( EventData.MarkGroupID ) )
text=text..string.format("Initiator = %s\n", EventData.IniUnit and EventData.IniUnit:GetName() or "Nobody") text = text .. string.format( "Initiator = %s\n", EventData.IniUnit and EventData.IniUnit:GetName() or "Nobody" )
text=text..string.format("Coordinate = %s\n", EventData.MarkCoordinate and EventData.MarkCoordinate:ToStringLLDMS() or "Nowhere") text = text .. string.format( "Coordinate = %s\n", EventData.MarkCoordinate and EventData.MarkCoordinate:ToStringLLDMS() or "Nowhere" )
text=text..string.format("Text: \n%s", tostring(EventData.MarkText)) text = text .. string.format( "Text: \n%s", tostring( EventData.MarkText ) )
self:T2(self.lid..text) self:T2( self.lid .. text )
end end
@@ -713,17 +704,17 @@ end
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
-- @param Core.Event#EVENTDATA EventData Event data table. -- @param Core.Event#EVENTDATA EventData Event data table.
function MARKER:onafterRemoved(From, Event, To, EventData) function MARKER:onafterRemoved( From, Event, To, EventData )
-- Debug info. -- Debug info.
local text=string.format("Captured event MarkRemoved for myself:\n") local text = string.format( "Captured event MarkRemoved for myself:\n" )
text=text..string.format("Marker ID = %s\n", tostring(EventData.MarkID)) text = text .. string.format( "Marker ID = %s\n", tostring( EventData.MarkID ) )
text=text..string.format("Coalition = %s\n", tostring(EventData.MarkCoalition)) text = text .. string.format( "Coalition = %s\n", tostring( EventData.MarkCoalition ) )
text=text..string.format("Group ID = %s\n", tostring(EventData.MarkGroupID)) text = text .. string.format( "Group ID = %s\n", tostring( EventData.MarkGroupID ) )
text=text..string.format("Initiator = %s\n", EventData.IniUnit and EventData.IniUnit:GetName() or "Nobody") text = text .. string.format( "Initiator = %s\n", EventData.IniUnit and EventData.IniUnit:GetName() or "Nobody" )
text=text..string.format("Coordinate = %s\n", EventData.MarkCoordinate and EventData.MarkCoordinate:ToStringLLDMS() or "Nowhere") text = text .. string.format( "Coordinate = %s\n", EventData.MarkCoordinate and EventData.MarkCoordinate:ToStringLLDMS() or "Nowhere" )
text=text..string.format("Text: \n%s", tostring(EventData.MarkText)) text = text .. string.format( "Text: \n%s", tostring( EventData.MarkText ) )
self:T2(self.lid..text) self:T2( self.lid .. text )
end end
@@ -733,17 +724,17 @@ end
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
-- @param Core.Event#EVENTDATA EventData Event data table. -- @param Core.Event#EVENTDATA EventData Event data table.
function MARKER:onafterChanged(From, Event, To, EventData) function MARKER:onafterChanged( From, Event, To, EventData )
-- Debug info. -- Debug info.
local text=string.format("Captured event MarkChange for myself:\n") local text = string.format( "Captured event MarkChange for myself:\n" )
text=text..string.format("Marker ID = %s\n", tostring(EventData.MarkID)) text = text .. string.format( "Marker ID = %s\n", tostring( EventData.MarkID ) )
text=text..string.format("Coalition = %s\n", tostring(EventData.MarkCoalition)) text = text .. string.format( "Coalition = %s\n", tostring( EventData.MarkCoalition ) )
text=text..string.format("Group ID = %s\n", tostring(EventData.MarkGroupID)) text = text .. string.format( "Group ID = %s\n", tostring( EventData.MarkGroupID ) )
text=text..string.format("Initiator = %s\n", EventData.IniUnit and EventData.IniUnit:GetName() or "Nobody") text = text .. string.format( "Initiator = %s\n", EventData.IniUnit and EventData.IniUnit:GetName() or "Nobody" )
text=text..string.format("Coordinate = %s\n", EventData.MarkCoordinate and EventData.MarkCoordinate:ToStringLLDMS() or "Nowhere") text = text .. string.format( "Coordinate = %s\n", EventData.MarkCoordinate and EventData.MarkCoordinate:ToStringLLDMS() or "Nowhere" )
text=text..string.format("Text: \n%s", tostring(EventData.MarkText)) text = text .. string.format( "Text: \n%s", tostring( EventData.MarkText ) )
self:T2(self.lid..text) self:T2( self.lid .. text )
end end
@@ -753,9 +744,9 @@ end
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
-- @param #string Text The updated text, displayed in the mark panel. -- @param #string Text The updated text, displayed in the mark panel.
function MARKER:onafterTextUpdate(From, Event, To, Text) function MARKER:onafterTextUpdate( From, Event, To, Text )
self:T(self.lid..string.format("New Marker Text:\n%s", Text)) self:T( self.lid .. string.format( "New Marker Text:\n%s", Text ) )
end end
@@ -765,12 +756,8 @@ end
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
-- @param Core.Point#COORDINATE Coordinate The updated coordinates. -- @param Core.Point#COORDINATE Coordinate The updated coordinates.
function MARKER:onafterCoordUpdate(From, Event, To, Coordinate) function MARKER:onafterCoordUpdate( From, Event, To, Coordinate )
self:T(self.lid..string.format("New Marker Coordinate in LL DMS: %s", Coordinate:ToStringLLDMS())) self:T( self.lid .. string.format( "New Marker Coordinate in LL DMS: %s", Coordinate:ToStringLLDMS() ) )
end end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
File diff suppressed because it is too large Load Diff
+25 -37
View File
@@ -10,11 +10,8 @@
-- --
-- @module Wrapper.Static -- @module Wrapper.Static
-- @image Wrapper_Static.JPG -- @image Wrapper_Static.JPG
--- @type STATIC --- @type STATIC
-- @extends Wrapper.Positionable#POSITIONABLE -- @extends Wrapper.Positionable#POSITIONABLE
--- Wrapper class to handle Static objects. --- Wrapper class to handle Static objects.
-- --
-- Note that Statics are almost the same as Units, but they don't have a controller. -- Note that Statics are almost the same as Units, but they don't have a controller.
@@ -40,13 +37,10 @@
-- --
-- * @{#STATIC.FindByName}(): Find a STATIC instance from the _DATABASE object using a DCS Static name. -- * @{#STATIC.FindByName}(): Find a STATIC instance from the _DATABASE object using a DCS Static name.
-- --
-- IMPORTANT: ONE SHOULD NEVER SANATIZE these STATIC OBJECT REFERENCES! (make the STATIC object references nil). -- IMPORTANT: ONE SHOULD NEVER SANITIZE these STATIC OBJECT REFERENCES! (make the STATIC object references nil).
-- --
-- @field #STATIC -- @field #STATIC
STATIC = { STATIC = { ClassName = "STATIC" }
ClassName = "STATIC",
}
--- Register a static object. --- Register a static object.
-- @param #STATIC self -- @param #STATIC self
@@ -58,7 +52,6 @@ function STATIC:Register( StaticName )
return self return self
end end
--- Finds a STATIC from the _DATABASE using a DCSStatic object. --- Finds a STATIC from the _DATABASE using a DCSStatic object.
-- @param #STATIC self -- @param #STATIC self
-- @param DCS#StaticObject DCSStatic An existing DCS Static object reference. -- @param DCS#StaticObject DCSStatic An existing DCS Static object reference.
@@ -85,7 +78,7 @@ function STATIC:FindByName( StaticName, RaiseError )
self.StaticName = StaticName self.StaticName = StaticName
if StaticFound then if StaticFound then
return StaticFound return StaticFound
end end
if RaiseError == nil or RaiseError == true then if RaiseError == nil or RaiseError == true then
@@ -97,8 +90,9 @@ end
--- Destroys the STATIC. --- Destroys the STATIC.
-- @param #STATIC self -- @param #STATIC self
-- @param #boolean GenerateEvent (Optional) true if you want to generate a crash or dead event for the static. -- @param #boolean GenerateEvent (Optional) true to generate a crash or dead event, false to not generate any event. `nil` (default) creates a remove event.
-- @return #nil The DCS StaticObject is not existing or alive. -- @return #nil The DCS StaticObject is not existing or alive.
--
-- @usage -- @usage
-- -- Air static example: destroy the static Helicopter and generate a S_EVENT_CRASH. -- -- Air static example: destroy the static Helicopter and generate a S_EVENT_CRASH.
-- Helicopter = STATIC:FindByName( "Helicopter" ) -- Helicopter = STATIC:FindByName( "Helicopter" )
@@ -117,7 +111,7 @@ end
-- @usage -- @usage
-- -- Destroy without event generation example. -- -- Destroy without event generation example.
-- Ship = STATIC:FindByName( "Boat" ) -- Ship = STATIC:FindByName( "Boat" )
-- Ship:Destroy( false ) -- Don't generate an event upon destruction. -- Ship:Destroy( false ) -- Don't generate any event upon destruction.
-- --
function STATIC:Destroy( GenerateEvent ) function STATIC:Destroy( GenerateEvent )
self:F2( self.ObjectName ) self:F2( self.ObjectName )
@@ -148,7 +142,6 @@ function STATIC:Destroy( GenerateEvent )
return nil return nil
end end
--- Get DCS object of static of static. --- Get DCS object of static of static.
-- @param #STATIC self -- @param #STATIC self
-- @return DCS static object -- @return DCS static object
@@ -180,7 +173,6 @@ function STATIC:GetUnits()
return nil return nil
end end
--- Get threat level of static. --- Get threat level of static.
-- @param #STATIC self -- @param #STATIC self
-- @return #number Threat level 1. -- @return #number Threat level 1.
@@ -194,15 +186,15 @@ end
-- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static. -- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static.
-- @param #number Heading The heading of the static respawn in degrees. Default is 0 deg. -- @param #number Heading The heading of the static respawn in degrees. Default is 0 deg.
-- @param #number Delay Delay in seconds before the static is spawned. -- @param #number Delay Delay in seconds before the static is spawned.
function STATIC:SpawnAt(Coordinate, Heading, Delay) function STATIC:SpawnAt( Coordinate, Heading, Delay )
Heading=Heading or 0 Heading = Heading or 0
if Delay and Delay>0 then if Delay and Delay > 0 then
SCHEDULER:New(nil, self.SpawnAt, {self, Coordinate, Heading}, Delay) SCHEDULER:New( nil, self.SpawnAt, { self, Coordinate, Heading }, Delay )
else else
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName) local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName )
SpawnStatic:SpawnFromPointVec2( Coordinate, Heading, self.StaticName ) SpawnStatic:SpawnFromPointVec2( Coordinate, Heading, self.StaticName )
@@ -211,47 +203,43 @@ function STATIC:SpawnAt(Coordinate, Heading, Delay)
return self return self
end end
--- Respawn the @{Wrapper.Unit} at the same location with the same properties. --- Respawn the @{Wrapper.Unit} at the same location with the same properties.
-- This is useful to respawn a cargo after it has been destroyed. -- This is useful to respawn a cargo after it has been destroyed.
-- @param #STATIC self -- @param #STATIC self
-- @param DCS#country.id CountryID (Optional) The country ID used for spawning the new static. Default is same as currently. -- @param DCS#country.id CountryID (Optional) The country ID used for spawning the new static. Default is same as currently.
-- @param #number Delay (Optional) Delay in seconds before static is respawned. Default now. -- @param #number Delay (Optional) Delay in seconds before static is respawned. Default now.
function STATIC:ReSpawn(CountryID, Delay) function STATIC:ReSpawn( CountryID, Delay )
if Delay and Delay>0 then if Delay and Delay > 0 then
SCHEDULER:New(nil, self.ReSpawn, {self, CountryID}, Delay) SCHEDULER:New( nil, self.ReSpawn, { self, CountryID }, Delay )
else else
CountryID=CountryID or self:GetCountry() CountryID = CountryID or self:GetCountry()
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, CountryID) local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName, CountryID )
SpawnStatic:Spawn(nil, self.StaticName) SpawnStatic:Spawn( nil, self.StaticName )
end end
return self return self
end end
--- Respawn the @{Wrapper.Unit} at a defined Coordinate with an optional heading. --- Respawn the @{Wrapper.Unit} at a defined Coordinate with an optional heading.
-- @param #STATIC self -- @param #STATIC self
-- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static. -- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static.
-- @param #number Heading (Optional) The heading of the static respawn in degrees. Default the current heading. -- @param #number Heading (Optional) The heading of the static respawn in degrees. Default is the current heading.
-- @param #number Delay (Optional) Delay in seconds before static is respawned. Default now. -- @param #number Delay (Optional) Delay in seconds before static is respawned. Default is now.
function STATIC:ReSpawnAt(Coordinate, Heading, Delay) function STATIC:ReSpawnAt( Coordinate, Heading, Delay )
--Heading=Heading or 0 -- Heading=Heading or 0
if Delay and Delay>0 then if Delay and Delay > 0 then
SCHEDULER:New(nil, self.ReSpawnAt, {self, Coordinate, Heading}, Delay) SCHEDULER:New( nil, self.ReSpawnAt, { self, Coordinate, Heading }, Delay )
else else
local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName, self:GetCountry() )
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, self:GetCountry()) SpawnStatic:SpawnFromCoordinate( Coordinate, Heading, self.StaticName )
SpawnStatic:SpawnFromCoordinate(Coordinate, Heading, self.StaticName)
end end
return self return self
+9 -20
View File
@@ -168,9 +168,6 @@ function UNIT:GetDCSObject()
return nil return nil
end end
--- Respawn the @{Wrapper.Unit} using a (tweaked) template of the parent Group. --- Respawn the @{Wrapper.Unit} using a (tweaked) template of the parent Group.
-- --
-- This function will: -- This function will:
@@ -263,8 +260,6 @@ function UNIT:ReSpawnAt( Coordinate, Heading )
_DATABASE:Spawn( SpawnGroupTemplate ) _DATABASE:Spawn( SpawnGroupTemplate )
end end
--- Returns if the unit is activated. --- Returns if the unit is activated.
-- @param #UNIT self -- @param #UNIT self
-- @return #boolean `true` if Unit is activated. `nil` The DCS Unit is not existing or alive. -- @return #boolean `true` if Unit is activated. `nil` The DCS Unit is not existing or alive.
@@ -301,8 +296,6 @@ function UNIT:IsAlive()
return nil return nil
end end
--- Returns the Unit's callsign - the localized string. --- Returns the Unit's callsign - the localized string.
-- @param #UNIT self -- @param #UNIT self
-- @return #string The Callsign of the Unit. -- @return #string The Callsign of the Unit.
@@ -442,7 +435,7 @@ function UNIT:GetSpeedMax()
return SpeedMax*3.6 return SpeedMax*3.6
end end
return nil return 0
end end
--- Returns the unit's max range in meters derived from the DCS descriptors. --- Returns the unit's max range in meters derived from the DCS descriptors.
@@ -626,8 +619,8 @@ function UNIT:GetAmmunition()
-- Type name of current weapon. -- Type name of current weapon.
local Tammo=ammotable[w]["desc"]["typeName"] local Tammo=ammotable[w]["desc"]["typeName"]
local _weaponString = UTILS.Split(Tammo,"%.") --local _weaponString = UTILS.Split(Tammo,"%.")
local _weaponName = _weaponString[#_weaponString] --local _weaponName = _weaponString[#_weaponString]
-- Get the weapon category: shell=0, missile=1, rocket=2, bomb=3 -- Get the weapon category: shell=0, missile=1, rocket=2, bomb=3
local Category=ammotable[w].desc.category local Category=ammotable[w].desc.category
@@ -656,7 +649,8 @@ function UNIT:GetAmmunition()
elseif Category==Weapon.Category.MISSILE then elseif Category==Weapon.Category.MISSILE then
-- Add up all cruise missiles (category 5)
-- Add up all missiles (category 5)
if MissileCategory==Weapon.MissileCategory.AAM then if MissileCategory==Weapon.MissileCategory.AAM then
nmissiles=nmissiles+Nammo nmissiles=nmissiles+Nammo
elseif MissileCategory==Weapon.MissileCategory.ANTI_SHIP then elseif MissileCategory==Weapon.MissileCategory.ANTI_SHIP then
@@ -665,6 +659,10 @@ function UNIT:GetAmmunition()
nmissiles=nmissiles+Nammo nmissiles=nmissiles+Nammo
elseif MissileCategory==Weapon.MissileCategory.OTHER then elseif MissileCategory==Weapon.MissileCategory.OTHER then
nmissiles=nmissiles+Nammo nmissiles=nmissiles+Nammo
elseif MissileCategory==Weapon.MissileCategory.SAM then
nmissiles=nmissiles+Nammo
elseif MissileCategory==Weapon.MissileCategory.CRUISE then
nmissiles=nmissiles+Nammo
end end
end end
@@ -956,7 +954,6 @@ end
-- @return #string Some text. -- @return #string Some text.
function UNIT:GetThreatLevel() function UNIT:GetThreatLevel()
local ThreatLevel = 0 local ThreatLevel = 0
local ThreatText = "" local ThreatText = ""
@@ -982,7 +979,6 @@ function UNIT:GetThreatLevel()
"LR SAMs" "LR SAMs"
} }
if Attributes["LR SAM"] then ThreatLevel = 10 if Attributes["LR SAM"] then ThreatLevel = 10
elseif Attributes["MR SAM"] then ThreatLevel = 9 elseif Attributes["MR SAM"] then ThreatLevel = 9
elseif Attributes["SR SAM"] and elseif Attributes["SR SAM"] and
@@ -1018,7 +1014,6 @@ function UNIT:GetThreatLevel()
"Fighter" "Fighter"
} }
if Attributes["Fighters"] then ThreatLevel = 10 if Attributes["Fighters"] then ThreatLevel = 10
elseif Attributes["Multirole fighters"] then ThreatLevel = 9 elseif Attributes["Multirole fighters"] then ThreatLevel = 9
elseif Attributes["Battleplanes"] then ThreatLevel = 8 elseif Attributes["Battleplanes"] then ThreatLevel = 8
@@ -1136,12 +1131,6 @@ function UNIT:OtherUnitInRadius( AwaitUnit, Radius )
return nil return nil
end end
--- Returns if the unit is a friendly unit. --- Returns if the unit is a friendly unit.
-- @param #UNIT self -- @param #UNIT self
-- @return #boolean IsFriendly evaluation result. -- @return #boolean IsFriendly evaluation result.