Compare commits

...

1013 Commits
2.1.4 ... 2.4.a

Author SHA1 Message Date
FlightControl_Master
0e0ab3507c Okay, fixed the problem with the crashing at the deploy zone.
Also added methods to set and/or randomize the pickup speed, pickup radius, deploy speed, deploy radius.
2018-05-13 15:57:28 +02:00
Frank
92a70d07d9 Merge pull request #899 from FlightControl-Master/FF/Develop
ARTY v0.9.1
2018-05-12 15:44:58 +02:00
funkyfranky
8db5351ad7 ARTY v0.9.1
Added option to not engage an already assigned target.
Fixed bug in _checkname function.
2018-05-12 15:42:15 +02:00
FlightControl_Master
25a6cbcf6d Helicopter AI_CARGO_DISPATCHER working (almost).
Queueing at deploy locations working.
2018-05-12 08:37:27 +02:00
Frank
ac7ae68ee8 Merge pull request #898 from FlightControl-Master/FF/Develop
Added Big Smoke Effect
2018-05-11 21:56:01 +02:00
funkyfranky
230a803045 Corrected description. 2018-05-11 12:30:33 +02:00
funkyfranky
d61840d834 Added Big Smoke Effect
Added big smoke effects to COORDINATE API.
2018-05-11 12:27:55 +02:00
funkyfranky
f74520afd3 Merge branch 'develop' into FF/Develop 2018-05-11 12:26:25 +02:00
FlightControl_Master
74668bb7db Fixes 2018-05-10 23:42:14 +02:00
FlightControl_Master
bca964aca8 Helicopter version of AI_CARGO_DISPATCHER_HELICOPTER 2018-05-10 23:17:06 +02:00
funkyfranky
ad9e97f192 Merge branch 'develop' into FF/Develop 2018-05-10 22:48:29 +02:00
funkyfranky
aac5efbf61 ARTY added shots to report output 2018-05-10 22:48:14 +02:00
FlightControl_Master
6b31ad9645 Moose file changes 2018-05-10 20:00:50 +02:00
Frank
0097316333 Merge pull request #896 from FlightControl-Master/FF/Develop
New classes.
2018-05-10 17:57:21 +02:00
funkyfranky
a0adca43f1 Merge branch 'develop' into FF/Develop 2018-05-10 17:05:45 +02:00
funkyfranky
6f0507ea7f Minor fixes.
Positionalble: Added isExist because of problems with getting coords from scenery objects.
Suppresson: Fixes. Added new transitions.
PseudoATC: Removed eject.
Artillery: Optimized debug output.
2018-05-10 15:40:10 +02:00
FlightControl_Master
1159d11a12 New AI_CARGO_DISPATCHER_APC 2018-05-10 14:39:22 +02:00
FlightControl_Master
9ee21f80ac comments 2018-05-10 08:07:28 +02:00
funkyfranky
f9d7eea721 ARTY, PseudoATC, RANGE, RAT, SUPPRESSION
ARTY v0.9.0: Added anti-ship missiles.  Various fixes.
PSEUDOATC v0.9.0: Added docu.  Cleaned up code.  Bug fixes.
RANGE v1.1.1: Changed menu.
RAT v2.2.2:  Changed default setting to menu = off. Added user function to enable/disable menus.
SUPPRESSION v0.9.0: Improvements.
2018-05-09 23:56:55 +02:00
funkyfranky
191fcb25be PseudoATC v0.7.0
Pseudo ATC improvements.
Minor changes in RAT and Suppression.
2018-05-09 00:11:53 +02:00
FlightControl_Master
a1eb0ff4d9 Fixes 2018-05-08 20:26:46 +02:00
FlightControl_Master
0600c96282 Finish Cargo/AI_Cargo_APC 2018-05-08 06:43:15 +02:00
funkyfranky
95d7b8250d Minor Changes. 2018-05-07 23:32:57 +02:00
funkyfranky
fc852e0386 Merge branch 'develop' into FF/Develop 2018-05-07 17:52:33 +02:00
funkyfranky
9429ec66ca RAT fixed typo 2018-05-07 17:44:53 +02:00
funkyfranky
92c3b530cc ARTY v0.8.9
Improved documentation.
2018-05-07 17:33:48 +02:00
FlightControl_Master
dd636939bb Documentation and performance fix. 2018-05-07 06:11:58 +02:00
funkyfranky
6554fa55d1 ARTY v0.8.8
Minor Changes.
2018-05-07 00:20:19 +02:00
funkyfranky
3157a63b7e ARTY v0.8.8
Added working implementation for moves.
Other minor adjustments.
2018-05-06 20:40:14 +02:00
funkyfranky
d9222c23cb ARTY v0.8.7
Added first version of move implementation. Moves are not executed yet.
2018-05-06 17:03:31 +02:00
funkyfranky
16d4a65569 ARTY v0.8.6
Added user function for rearming properties.
Minor bug fixes.
2018-05-06 15:13:36 +02:00
funkyfranky
a2c12dc05e ARTY v0.8.5
Improved GetAmmo function. Display of ammo table.
Removed all schedulers.
2018-05-06 12:51:51 +02:00
funkyfranky
c36579f88a ARTY v0.8.4
Several improvments and fixes.
2018-05-06 12:05:23 +02:00
FlightControl_Master
19b3dcec21 # Conflicts:
#	Moose Development/Moose/AI/AI_Cargo_APC.lua
#	Moose Development/Moose/Wrapper/Controllable.lua
2018-05-06 07:36:58 +02:00
funkyfranky
ba944444da ARTY v0.8.3
Various improvements. Still WIP.
2018-05-05 23:59:02 +02:00
funkyfranky
f33856cddd ARTY v0.8.2
Fixes. Stil WIP
2018-05-05 22:51:43 +02:00
funkyfranky
57c5ab1ecd ARTY v0.8.1
Improvements in FSM states.
Still not quite functional.
2018-05-05 21:45:07 +02:00
funkyfranky
0cf4b8845e ARTY v0.8.0
WIP version. Not functional.
2018-05-05 08:44:16 +02:00
funkyfranky
4fccfa38d4 ARTY v0.7
Added "NewTarget" event.
Improved task function for waypoints
Removed TargetQueue scheduler.
2018-05-03 23:42:03 +02:00
funkyfranky
531c1d7e90 ARTY v0.6 (WIP)
Added documentation
Added user FSM functions.
Adjusted FSM (untested)
Added task route function.
2018-05-03 00:24:23 +02:00
FlightControl_Master
810d900d7e Working with Transporting mode on or off. 2018-05-02 22:18:07 +02:00
funkyfranky
274b44459e ARTY v0.5
- Adjusted schedulers.
- Improved transitions.
- Make rearming unit go back to its original position.
- Added user functions.
- Using only coodinates for target assignments.
- Added dead event handling.
2018-05-02 00:14:05 +02:00
funkyfranky
394b5f5b89 ARTY v0.4.0
Improved assigned time for engagement. Next day should be possible now.
Added check whether a group started firing within a certain time.
2018-04-30 22:53:57 +02:00
funkyfranky
e5268a29cf ARTY v0.3
First working version. But still WIP.
2018-04-30 12:05:51 +02:00
funkyfranky
b14a672b0e ARTY improvements. 2018-04-26 23:08:16 +02:00
funkyfranky
0ec3192fb7 Arty improvements 2018-04-25 22:49:36 +02:00
funkyfranky
33271edf78 Added ARTY class
First draft...
2018-04-24 23:38:41 +02:00
funkyfranky
441fba0830 PseudoATC
Fixed waypoints BR
2018-04-24 21:12:35 +02:00
funkyfranky
7dbc9436ed PseudoATC
restructured menu
2018-04-24 00:29:09 +02:00
FlightControl_Master
c999389cda Handler for unloading too. 2018-04-23 06:51:49 +02:00
funkyfranky
462564cd01 PseudoATC and RANGE
Range: corrected heading
PseudoATC: lots of changes
2018-04-22 23:55:21 +02:00
funkyfranky
c2a968d2ef Merge branch 'develop' into FF/Develop 2018-04-20 00:13:49 +02:00
funkyfranky
2297646873 Range v1.1.1
Added strafe pit/bombing targets info
2018-04-20 00:13:30 +02:00
FlightControl_Master
af050629aa Made it. Now cargo can be defined in the Mission Editor as #CARGO 2018-04-17 06:25:40 +02:00
FlightControl_Master
3757eb06d9 Fixes for AI_CARGO_AIRPLANE 2018-04-15 04:41:52 +02:00
funkyfranky
06b555a50a Merge branch 'develop' into FF/Develop 2018-04-14 19:35:09 +02:00
FlightControl_Master
b9eab34d6a WIP on AI_Cargo_Airplane 2018-04-14 13:45:00 +02:00
FlightControl_Master
1444a613c5 New AI_Cargo_Airplane file 2018-04-14 12:02:48 +02:00
FlightControl_Master
ecf3434c3d Merge branch 'master' into develop 2018-04-14 08:08:01 +02:00
FlightControl_Master
5988ceec05 A new AI Cargo Helicopter class. 2018-04-13 22:31:19 +02:00
FlightControl_Master
f01b2c9149 Finish Cargo/AI_Cargo_APC 2018-04-13 20:35:38 +02:00
FlightControl_Master
b33dd94fa0 Fixed a bug in Spawn regarding spawning with templates. 2018-04-13 13:57:47 +02:00
FlightControl_Master
47dd73a377 Fixes 2018-04-13 12:22:39 +02:00
FlightControl_Master
25ae0c3d15 Finish this feature. 2018-04-13 09:56:00 +02:00
FlightControl_Master
3389c908d7 Finish Task_Assignment 2018-04-12 20:04:19 +02:00
FlightControl_Master
3e6017c0d5 Task Assignment 2018-04-12 20:03:44 +02:00
FlightControl_Master
fea2f55fbb Lots of optimizations 2018-04-12 13:59:55 +02:00
FlightControl_Master
dcc42b8e62 Fixes 2018-04-11 23:24:13 +02:00
FlightControl_Master
9cea486fdc Progress 2018-04-11 17:09:59 +02:00
FlightControl_Master
faa934ffce Fixed stuff for multi player 2018-04-11 17:00:11 +02:00
FlightControl_Master
1ae1b9abd7 Ready for another test session. 2018-04-11 09:14:12 +02:00
FlightControl_Master
ffe4d9a143 Finish Cargo/FC/Transport 2018-04-10 20:02:40 +02:00
funkyfranky
d5d0703502 Merge branch 'develop' into FF/Develop 2018-04-09 13:57:40 +02:00
funkyfranky
fe3e91d1a0 Merge branch 'master' into FF/Develop 2018-04-09 13:57:17 +02:00
FlightControl_Master
1beb34231e Getting rid of an old annoyance. 2018-04-09 13:38:32 +02:00
FlightControl_Master
a6889be676 # Conflicts:
#	Moose Development/Moose/Tasking/Task_CARGO.lua
2018-04-09 13:30:33 +02:00
FlightControl_Master
4eb596f5bf Finish Cargo/FC/Transport 2018-04-09 12:56:11 +02:00
funkyfranky
01de126a8f Merge branch 'develop' into FF/Develop 2018-04-09 08:16:10 +02:00
FlightControl_Master
86cc1f81b6 Finish Cargo/FC/Transport 2018-04-08 22:38:45 +02:00
FlightControl_Master
a95afe9956 # Conflicts:
#	Moose Development/Moose/Tasking/Task_CARGO.lua
2018-04-08 22:36:58 +02:00
FlightControl_Master
8b8fcaaacd # Conflicts:
#	Moose Development/Moose/Tasking/Task_CARGO.lua
2018-04-08 18:59:42 +02:00
FlightControl_Master
31f0bb9fef Adding events for Deployed and PickedUp. 2018-04-08 13:33:18 +02:00
FlightControl_Master
af23aa3b79 -- Lots of fixes done. Especially on the
- Messaging
- Menu system
- Crashing DCS
- Routing
2018-04-08 11:01:46 +02:00
funkyfranky
e606ab1b8a Merge branch 'develop' into FF/Develop 2018-04-07 23:58:40 +02:00
Frank
d792061df8 Merge pull request #861 from FlightControl-Master/FF-Servant
RANGE v1.1.0
2018-04-07 23:44:57 +02:00
funkyfranky
689f9fd8e9 RANGE v1.1.0
- Missiles are now tracked.
- Statics can now be used for strafe pits.
- Statics are automatically recognized.
- More user functions to add bomb or strafe targets.
- Bomb targets are allowed to move.
- Bomb targets can automatically move randomly inside the range zone.
- Improved trace output.
- Documentation updated.
2018-04-07 23:37:07 +02:00
funkyfranky
303f5cb571 RANGE v1.1.0
- Missiles are now tracked.
- Statics can now be used for strafe pits.
- Statics are automatically recognized.
- More user functions to add bomb or strafe targets.
- Bomb targets are allowed to move.
- Bomb targets can automatically move randomly inside the range zone.
- Improved trace output.
- Documentation updated.
2018-04-07 23:36:09 +02:00
FlightControl_Master
b1ecdc727c Faster menu and fix for Disembark loaded engineers in other helicopter. 2018-04-07 19:00:18 +02:00
FlightControl_Master
7735120f25 Progress on AI_CARGO_TROOPS 2018-04-07 14:21:34 +02:00
FlightControl_Master
a247f56c7e Progress on AI_CARGO_TROOPS 2018-04-07 10:18:52 +02:00
FlightControl_Master
718138abd6 Fixed slingload deploy problem.
Fixed messaging. Now a message is shown when cargo reports itself when in LoadRange and when near, it will allow for loading of cargo.
Fixed the perception that cargo can be boarded when loaded in an other carrier, which is totally wrong.
2018-04-06 21:33:54 +02:00
FlightControl_Master
269b52fd0e Fixed slingload deploy problem.
Fixed messaging. Now a message is shown when cargo reports itself when in LoadRange and when near, it will allow for loading of cargo.
Fixed the perception that cargo can be boarded when loaded in an other carrier, which is totally wrong.
2018-04-06 21:28:43 +02:00
funkyfranky
fd34bab65a Merge branch 'develop' into FF/Develop 2018-04-05 22:47:38 +02:00
funkyfranky
e2df7f9732 Merge branch 'master' into FF/Develop 2018-04-05 22:44:41 +02:00
funkyfranky
ed0c5b2264 Added Range 1.0.3
Just copied from other branch.
2018-04-05 22:44:33 +02:00
FlightControl_Master
2ebd25d677 Finish Cargo/FC/Csar 2018-04-05 19:54:24 +02:00
FlightControl_Master
376eeb63c5 Added CARGO_SLINGLOAD and fixed some bugs. 2018-04-05 19:44:04 +02:00
FlightControl_Master
5971f6de09 Added CARGO_SLINGLOAD 2018-04-05 19:43:24 +02:00
FlightControl_Master
a586d81f68 Cargo Crate transportation working :-) 2018-04-05 15:06:59 +02:00
FlightControl_Master
c60dda2545 Cargo Crate transportation working :-) 2018-04-05 15:06:36 +02:00
FlightControl_Master
45d1cb48bb Added Transport tasking to the dispatcher
# Conflicts:
#	Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua
2018-04-04 14:44:15 +02:00
FlightControl_Master
0d995d1832 Progress 2018-04-04 14:38:49 +02:00
funkyfranky
e094c8133a Added PseudoATC and Suppression 2018-04-03 16:49:34 +02:00
FlightControl_Master
1f578d4ab5 Working CSAR ... huray 2018-04-03 07:45:26 +02:00
FlightControl_Master
ec973fcc76 Working CSAR ... huray 2018-04-03 07:43:55 +02:00
FlightControl_Master
25831db057 Progress
-- Still need to fix an issue with some strang objects appearing and a crash.
2018-04-02 19:33:44 +02:00
FlightControl_Master
d0925ddfc1 Progress 2018-04-02 09:29:51 +02:00
FlightControl_Master
a4d3089fdb Updates Csar 2018-03-31 09:10:11 +02:00
FlightControl_Master
a94e744028 -- New modules for CSAR tasking. 2018-03-31 07:35:18 +02:00
Frank
b415039947 Merge pull request #850 from FlightControl-Master/FF-Servant
RANGE 1.0.3
2018-03-30 19:56:36 +02:00
funkyfranky
9de6993a4c RANGE 1.0.3
Improved ammo counting.
2018-03-30 19:54:53 +02:00
Frank
b3facc6e88 Merge pull request #849 from FlightControl-Master/FF-Servant
RANGE 1.0.2
2018-03-30 11:35:06 +02:00
funkyfranky
10ebc0b1e7 RANGE 1.0.2
Added hit percentage for strafing runs.
2018-03-30 11:30:10 +02:00
FlightControl_Master
1401bb29aa New cargo files 2018-03-29 17:56:38 +02:00
FlightControl_Master
9688c606f0 New Cargo files 2018-03-29 17:55:58 +02:00
FlightControl_Master
c4ba2c0235 -- Fixing respawning of CargoGroups after dead event. 2018-03-29 12:48:47 +02:00
FlightControl_Master
35f18d0d1f -- Fixing respawning of CargoGroups after dead event. 2018-03-29 12:48:24 +02:00
FlightControl_Master
93640b1d8e -- Further fixes for TASK_CARGO_TRANSPORT 2018-03-29 12:02:07 +02:00
FlightControl_Master
75d179176d -- A lot of fixes to the new Cargo handling model. Now also TASK_CARGO_TRANSPORT is working. 2018-03-29 12:00:46 +02:00
FlightControl_Master
c37560275e -- A lot of fixes to the new Cargo handling model. Now also TASK_CARGO_TRANSPORT is working. 2018-03-29 12:00:11 +02:00
FlightControl_Master
812902b009 -- First prototype of AI_CARGO_TROOPS 2018-03-28 18:01:07 +02:00
FlightControl_Master
b29ce9b45e Boarding of troops 2018-03-28 18:00:17 +02:00
FlightControl_Master
31a7a4e993 Default of near radius is 25 meters. 2018-03-28 16:48:03 +02:00
FlightControl_Master
7a8881974c Optimizations of cargo deployment. 2018-03-28 16:42:37 +02:00
FlightControl_Master
ea069455d3 Merge branch 'AI_Cargo_Troops_old' into feature/AI_Cargo_Troops_Handling 2018-03-28 16:16:21 +02:00
Frank
f03807207d Merge pull request #847 from FlightControl-Master/FF-Servant
RAT v2.2.1
2018-03-28 15:26:00 +02:00
FlightControl_Master
59bf7fdc96 Merged 'develop'.
# Conflicts:
#	Moose Development/Moose/Core/Cargo.lua
2018-03-28 13:49:57 +02:00
funkyfranky
6c26f2cd69 RAT v2.2.1
Added parking spot DB.
Added spawning on top of other unit check.
Added user functions.
Added trance functions.
2018-03-28 00:03:29 +02:00
FlightControl_Master
2caada0119 -- Fixed a lot of issues with cargo when the cargo representative is destroyed. 2018-03-27 21:03:30 +02:00
FlightControl_Master
7a579a0ab5 -- Fixed a lot of issues with cargo when the cargo representative is destroyed. 2018-03-27 20:59:37 +02:00
FlightControl_Master
cf6b7365af Finish SET_AIRBASE_does_not_update_#817 2018-03-27 15:10:54 +02:00
FlightControl_Master
272308cf98 Finish SET_AIRBASE_does_not_update_#817 2018-03-27 15:10:54 +02:00
FlightControl_Master
747777b297 -- Fix issue SET_AIRBASE does not update #817. 2018-03-27 15:10:14 +02:00
FlightControl_Master
20594ad294 Finish SET_AIRBASE_does_not_update_#817 2018-03-27 15:03:47 +02:00
FlightControl_Master
b4b2034792 Finish SET_AIRBASE_does_not_update_#817 2018-03-27 15:03:47 +02:00
FlightControl_Master
e22e7f2c58 -- Fix issue SET_AIRBASE does not update #817. 2018-03-27 15:03:07 +02:00
FlightControl_Master
12fcb99218 -- The infantry must only be 5 meters near. 2018-03-27 14:16:25 +02:00
FlightControl_Master
b1a1c6c552 -- The infantry must only be 5 meters near. 2018-03-27 14:16:04 +02:00
FlightControl_Master
61e2e8ca6b Added lua file 2018-03-27 13:57:09 +02:00
FlightControl_Master
21a7bac4e0 added file 2018-03-27 13:56:53 +02:00
FlightControl_Master
12c4e142e9 comment 2018-03-27 13:47:25 +02:00
FlightControl_Master
9759640d52 comment 2018-03-27 13:46:55 +02:00
FlightControl_Master
395923eb07 First prototype of AI_CARGO_TROOPS 2018-03-27 12:13:08 +02:00
FlightControl_Master
727d64927b First working prototype of AI_CARGO_TROOPS. 2018-03-27 12:07:16 +02:00
FlightControl_Master
b6fc46fdd0 Cargo Troops 2018-03-26 17:53:23 +02:00
FlightControl_Master
e7518d69e6 Cargo Troops 2018-03-26 07:39:55 +02:00
FlightControl_Master
cce90b1f46 New AI_CARGO_TROOPS class 2018-03-26 06:52:24 +02:00
FlightControl_Master
a15ef93e7c Merged 'develop'. 2018-03-26 06:10:11 +02:00
FlightControl_Master
08cc4e3530 Finish Detection_error_with_units_and_types 2018-03-26 05:34:20 +02:00
FlightControl_Master
7d1d165a5a Finish Detection_error_with_units_and_types 2018-03-26 05:34:20 +02:00
FlightControl_Master
fa92615f5d -- Fixed Designate menus for UNITS and TYPES.
-- Fixed error in Detection Units and Types, when the last unit is destroyed in teh collection, it would crash the logic.
-- In the event processing, no error to be generated if the target static is not found.
2018-03-26 05:33:17 +02:00
FlightControl_Master
c4f2446b92 fix 2018-03-25 08:17:33 +02:00
FlightControl_Master
7088c4c426 updated branched creation of include repo 2018-03-25 08:15:13 +02:00
FlightControl_Master
7963f04bdc progress 2018-03-24 08:01:49 +01:00
FlightControl_Master
ca32c57c52 Progress on the new cargo group movements 2018-03-24 07:32:04 +01:00
FlightControl_Master
bd4ad42fcf Merge branch 'release/2.3' 2018-03-24 05:33:08 +01:00
FlightControl_Master
c4ff6d7bfd Merge branch 'develop' into release/2.3 2018-03-24 05:32:16 +01:00
FlightControl_Master
25659647a6 Finish Feature-Designate_option_to_disable_flashing_messages 2018-03-24 05:28:15 +01:00
FlightControl_Master
e2ffbba04d -- Fixing documentation 2018-03-24 05:27:58 +01:00
FlightControl_Master
4bc1cd1b51 -- New option to disable the flashing of detection messages. 2018-03-24 05:12:27 +01:00
Frank
95eb88e67e Merge pull request #841 from FlightControl-Master/FF-Servant
Range Radio Menu Hotfix
2018-03-22 19:54:49 +01:00
funkyfranky
089306b36d Range Radio Menu Hotfix
Root radio menu bug fixed when multiple ranges are defined.
Fixed crash in OnEventHit when player died.
2018-03-22 19:43:17 +01:00
FlightControl_Master
c59ed155e6 Fixing double command center menus. 2018-03-22 06:37:31 +01:00
FlightControl_Master
0d8f3d25e9 Removing test on detection visible 2018-03-22 06:17:39 +01:00
FlightControl_Master
cbb800de02 Fixed issue in TASK_A2A_DISPATCHER with taskupdates. 2018-03-22 06:10:06 +01:00
FlightControl_Master
52d783a0b7 Fixing errors due to core changes in the model. 2018-03-22 05:01:14 +01:00
Frank
7a4a3217df Merge pull request #840 from FlightControl-Master/FF-Servant
RANGE 1.0.1
2018-03-22 00:31:08 +01:00
funkyfranky
af2299d392 RANGE 1.0.1
Change _OnBirth() to OnEventBirth().
Messages about bomb impact only within Range radius.
Fixed DCSunit not known when player leaves.
Fixed TgtGroup in DCS onEvent() event handler.
Added YT demo vid.
Added 476th range object reference.
2018-03-22 00:21:41 +01:00
FlightControl_Master
24a3298f2e Merge branch 'FC/Hotfix-DETECTION__Detection_is_detecting_invisible_units._#779' 2018-03-20 15:52:19 +01:00
FlightControl_Master
5188c40701 Fixed the detection of invisible units. 2018-03-20 15:52:06 +01:00
FlightControl_Master
e01a4fa18c Fix bad link ZONE_CAPTURE_COALITION 2018-03-20 12:11:56 +01:00
FlightControl_Master
de5a283e50 - Hotfix-Ground units should not be given a default speed of 999 km/h in COORDINATE:WaypointGround() #831 2018-03-20 11:58:26 +01:00
FlightControl_Master
89e6672db1 - fixed error where the players collection was iterated from the DATABASE, but the wrong collection :-)
- now the player database is correctly interpreted, and the unit is interpreted, not the player name :-)
2018-03-20 11:49:59 +01:00
FlightControl_Master
fa15d170f7 - fixed error where the players collection was iterated from the DATABASE, but the wrong collection :-)
- now the player database is correctly interpreted, and the unit is interpreted, not the player name :-)
2018-03-20 11:49:26 +01:00
FlightControl_Master
2baa42e2bc - New TASK number (ID) allocation method per MISSION object.
- Added a :I() info trace method, that will put the difference between info and exceptions.
- SET_BASE:Flush() now contains the reference object of the elements that are flushed.
2018-03-20 11:28:34 +01:00
FlightControl_Master
44160dfa29 Merge branch 'master' into FC/DETECTION_UNITS_class_broken___#773 2018-03-20 11:26:19 +01:00
FlightControl_Master
a283290c06 Merge branch 'FC/Documentation-Release_2.3' 2018-03-20 10:35:18 +01:00
FlightControl_Master
706aea01ca Cleanup of documentation of AI 2018-03-20 10:34:53 +01:00
FlightControl_Master
fc7e15521d Merge branch 'FC/Documentation-Release_2.3' 2018-03-20 05:14:50 +01:00
FlightControl_Master
7a5c8d54e7 Added Start and Stop methods. 2018-03-20 05:14:16 +01:00
FlightControl_Master
136a7c2a5b Merge branch 'master' into FC/Documentation-Release_2.3 2018-03-20 04:31:44 +01:00
FlightControl_Master
eebd247fdd Merge branch 'FC/Documentation-Release_2.3' 2018-03-18 23:04:17 +01:00
FlightControl_Master
284a1853ff Documentation 2018-03-18 23:01:15 +01:00
FlightControl_Master
2b89a4b5b1 Merge branch 'FC/Documentation-Release_2.3' 2018-03-18 11:56:45 +01:00
FlightControl_Master
8c6482632b A2G Dispatcher Documentation 2018-03-18 11:56:31 +01:00
FlightControl_Master
51c233956c Merge branch 'master' into FC/Documentation-Release_2.3 2018-03-18 11:35:49 +01:00
FlightControl_Master
c2e575ef20 - Remove unnecessary comments from trace.
- Reworked the messaging. The name of the sender is now better modelled.
  - When a name is given, the name is used, unmodified.
  - When no name is given, the callign is inspected and used if set.
  - When no name and callsign, the group name is used.
- Reworked the Detection logic.
  - 2 collections, one for the internal grouping and one for the external indexes.
  - Reworked the methods.
- Reworked the naming of Command Centers.
  - A name function
  - A text function, showing Command Center [X]
  - A short text function, showing CC [X]
- Reworked the naming of Missions.
  - A name function
  - a text function, showing Mission "X (prio)"
  - a short text function, showing Mission "X"
- Embedded the new namings within the code (where I found them).
- There may be some leftovers. Please raise, and I'll fix it immediately.
- I've tested where i could.
2018-03-18 11:23:35 +01:00
FlightControl_Master
7c2c6daf3e Tracify comments 2018-03-18 11:17:37 +01:00
FlightControl_Master
9d100e9bc1 Merge branch 'FC/Documentation-Release_2.3' into FC/DETECTION_UNITS_class_broken___#773 2018-03-18 09:38:40 +01:00
FlightControl_Master
7b5136eabf Documentation 2018-03-18 08:16:02 +01:00
FlightControl_Master
af7a87e5a0 Merge branch 'master' into FC/Documentation-Release_2.3 2018-03-18 07:39:41 +01:00
Frank
a18d432141 Merge pull request #830 from FlightControl-Master/FF-Servant
RANGE class
2018-03-17 09:25:11 +01:00
FlightControl_Master
011a5b94fd Progress A2A detection fixed (i think). 2018-03-17 08:38:26 +01:00
FlightControl_Master
d672983c11 Progress 2018-03-17 08:02:25 +01:00
FlightControl_Master
9be9277a08 Clean up the detection code. It is complicated 2018-03-17 05:23:44 +01:00
funkyfranky
5976b92281 Added RANGE class 2018-03-16 18:18:10 +01:00
FlightControl_Master
0f18b29144 Merge branch 'master' into FC/DETECTION_UNITS_class_broken___#773 2018-03-16 06:41:26 +01:00
FlightControl_Master
533689826e First version of fix.
I need to make a second internal index in Detection to sort out the alternative groupings per unit name or type name.
2018-03-16 06:40:50 +01:00
FlightControl_Master
62eb36c456 Default designation range limit 8000 km. 2018-03-15 21:41:59 +01:00
FlightControl_Master
34265720cc Updated documentation A2G Dispatcher 2018-03-15 21:36:52 +01:00
FlightControl_Master
38d267b2bc Merge branch 'FC/Documentation-Release_2.3' 2018-03-15 12:47:52 +01:00
FlightControl_Master
251302839e Minor changes 2018-03-15 12:47:35 +01:00
FlightControl_Master
285c05b6ba Merge branch 'FC/Documentation-Release_2.3' 2018-03-15 12:42:32 +01:00
FlightControl_Master
bdc66058ab A2G Dispatcher, WIP 2018-03-15 12:42:23 +01:00
FlightControl_Master
df6bc598a4 Merge branch 'FC/Documentation-Release_2.3' 2018-03-15 11:42:22 +01:00
FlightControl_Master
c5c437fa50 New code 2018-03-15 11:41:52 +01:00
Sven Van de Velde
650f16084b Documented Task A2G Dispatcher
WIP
2018-03-15 09:27:35 +01:00
FlightControl_Master
949178d698 Merge branch 'FC/DETECTION_UNITS_class_broken___#773' 2018-03-14 06:58:02 +01:00
FlightControl_Master
e57d05fc91 Fixes DETECTION_UNITS and DETECTION_TYPES again. 2018-03-14 06:57:47 +01:00
FlightControl_Master
92d4bad63f Fixes some documentation issues reported by Shadowze 2018-03-13 21:00:32 +01:00
FlightControl_Master
58b2802f3a Fixing limit of cargo to 10 2018-03-13 14:43:05 +01:00
FlightControl_Master
e16eb38764 Merge branch 'FC/HotFix_TASK_A2A__Task_A2A_Dispatcher_throws_error_#804' 2018-03-13 12:17:12 +01:00
FlightControl_Master
f5a2183808 - Fixes A2A dispatching
- Fixes problem with target marking.
2018-03-13 12:16:59 +01:00
FlightControl_Master
2bc7a8c126 Merge branch 'FC/HotFix-Task_changes_BAI_-_CAS_-_BAI_when_Client_aircraft_go_in_and_out_of_range._#772' 2018-03-12 20:07:28 +01:00
FlightControl_Master
03ba031153 To ensure that A2G tasking does not get confused between BAI and CAS and back to BAI 2018-03-12 19:58:59 +01:00
FlightControl_Master
7fe333cc35 Fixing issue with dynamic loader (program path). 2018-03-12 16:44:47 +01:00
FlightControl_Master
6f1e483fd7 Merge branch 'FC/HotFix-Cargo-Transport_(Issue_#821)' 2018-03-12 14:21:36 +01:00
FlightControl_Master
01c18278fc Fixed for transport cargo 2018-03-12 14:21:20 +01:00
FlightControl_Master
5120088b66 Merge branch 'master' into FC/HotFix-Cargo-Transport_(Issue_#821) 2018-03-12 11:18:13 +01:00
FlightControl_Master
f82a0c092a Fix of picture in docs. 2018-03-12 10:57:18 +01:00
FlightControl_Master
296d1dbc2b Rework of missions 2018-03-12 10:48:38 +01:00
FlightControl_Master
825f4f2fac Merge branch 'FC/Hotfix-Designate_Menu_Rework_(Issue_813)' 2018-03-12 10:46:56 +01:00
FlightControl_Master
53980423a9 Rework documentation of DESIGNATE 2018-03-12 10:43:25 +01:00
Frank
fe01c03037 Merge pull request #827 from FlightControl-Master/FF-Servant
RATMANAGER documentation
2018-03-11 19:16:30 +01:00
funkyfranky
96ca3eeb44 RATMANAGER documentation
Fixes/added brief documentation for RATMANAGER class.
2018-03-11 19:12:07 +01:00
Frank
309ba285b1 Merge pull request #826 from FlightControl-Master/FF-Servant
RAT v2.2
2018-03-11 13:29:05 +01:00
funkyfranky
f2cb750aa2 RAT v2.2
RAT:
- Added possibility to activate uncontrolled aircraft.
- Added immortal option (untested).
- Added invisible option (untested).
- Added check that when aircraft are spawned on the runway, that they get despawned immediately.
- Added RATMANAGER class.

ZONE: Fix/workaround for isExist() always returning false for scenery objects.
2018-03-10 23:57:49 +01:00
FlightControl_Master
3544f07169 If one or more units of a group defined as CARGO_GROUP died, the CARGO_GROUP:Board() command does not trigger the CARGO_GRUOP:OnEnterLoaded() function. 2018-03-10 08:44:33 +01:00
FlightControl_Master
75f5cf9ac5 Merge branch 'FC/HotFix-Cargo-Transport_(Issue_#821)' 2018-03-10 08:12:03 +01:00
FlightControl_Master
a780f6635f Cargo Transport 2018-03-10 08:11:08 +01:00
FlightControl_Master
ae2e99a560 Updating loader so that it allows to load complete mission scripts for mission designers from other paths. 2018-03-10 07:00:09 +01:00
FlightControl_Master
34592a53be Preliminary 2018-03-10 06:58:12 +01:00
FlightControl_Master
370278e643 Fixed tasks not being aborted when a player leaves the slot or disconnects. 2018-03-09 14:35:34 +01:00
FlightControl_Master
778ab58eee Could not test all, but already committing. It works in SP and fixes the completed task issue. 2018-03-09 12:36:53 +01:00
FlightControl_Master
bf9d6cbd75 Merge branch 'FC/Hotfix-Length_LL_(Issue_819)' 2018-03-06 15:47:47 +01:00
FlightControl_Master
6bcbffb37f Fixed length of lat and lon 2018-03-06 15:47:39 +01:00
FlightControl_Master
68c701afc6 Merge branch 'FC/Feature-QFE_(Issue_814)' 2018-03-06 15:17:05 +01:00
FlightControl_Master
d11de24866 Fixing wrong conversion for mmHg and inHg + accurancy of numbers set to recommendations. 2018-03-06 15:16:43 +01:00
FlightControl_Master
5c7caadab7 Merge branch 'FC/Hotfix-Designate_Menu_Rework_(Issue_813)' 2018-03-06 12:38:28 +01:00
FlightControl_Master
8bbff46efd Reworked the DESIGNATE functionality and menu mechanisms. 2018-03-06 12:38:22 +01:00
FlightControl_Master
0865390284 I messed the non decection part. 2018-03-05 21:05:34 +01:00
FlightControl_Master
6dfba37fe9 Merge branch 'FC/HotFix_No_CommandCenter_Menu' 2018-03-05 11:56:02 +01:00
FlightControl_Master
0147c3a17c Revised the Command Center menu generation for MP and in SP when coming back from spectators or when changing the slot. 2018-03-05 11:49:05 +01:00
FlightControl_Master
03c38356ce Fixed the issue that No commandcenter menu was generated in case of birth of a join of a player. 2018-03-05 11:36:01 +01:00
FlightControl_Master
5e5dab99eb Merge branch 'FC/Feature-QFE_(Issue_814)' 2018-03-04 13:16:08 +01:00
FlightControl_Master
9f17382145 Reworked heavily the generation of reports and text on map coordinates. 2018-03-04 13:15:20 +01:00
FlightControl_Master
43336ae431 Merge branch 'FC/Hotfix-BULLS_(Issue_807)' 2018-03-03 06:58:29 +01:00
FlightControl_Master
fed937c7b7 Fixed issue #807 2018-03-03 06:58:04 +01:00
FlightControl_Master
734f624a9e Merge branch 'FC/Feature-QFE_(Issue_814)' 2018-03-03 05:51:16 +01:00
FlightControl_Master
a518af1200 Issue #814 solved by adding it to the task reports of the A2G task. 2018-03-03 05:50:31 +01:00
FlightControl_Master
d3fc84fe8c New version 2018-03-01 21:17:05 +01:00
FlightControl_Master
a5e2309409 Merge branch 'FC/Group_Respawning' 2018-03-01 20:42:21 +01:00
FlightControl_Master
760bdd2016 Merge branch 'master' into FC/Group_Respawning 2018-03-01 20:41:59 +01:00
FlightControl_Master
733b4940f8 Updated function names 2018-03-01 20:41:26 +01:00
FlightControl_Master
2620927146 Group Updates 2018-03-01 17:42:50 +01:00
FlightControl_Master
96216494bb Added Respawning to GROUP, first draft version. 2018-03-01 11:48:24 +01:00
Sven Van de Velde
67b5d0ca1c Settings 2018-02-27 17:42:21 +01:00
Sven Van de Velde
296b06e0b0 Updated documentation of Settings. 2018-02-27 14:46:20 +01:00
Sven Van de Velde
4e28ed3ee6 Disable Settings Menu for each individual player. Settings menus are by default on, but can be disabled by calling _SETTINGS:SetPlayerMenuOff(). 2018-02-26 21:15:04 +01:00
Sven Van de Velde
08ad1a0bce readme 2018-02-26 14:03:02 +01:00
Sven Van de Velde
d935cbaea2 readme 2018-02-26 13:46:45 +01:00
Sven Van de Velde
f7a5fc7d92 site 2018-02-26 13:40:36 +01:00
Sven Van de Velde
6329ac9262 redme 2018-02-26 13:37:47 +01:00
Sven Van de Velde
4649e2f823 readme 2018-02-26 13:34:52 +01:00
Sven Van de Velde
06df068d6b new readme 2018-02-26 13:29:25 +01:00
Sven Van de Velde
0dd4676879 readme 2018-02-26 13:23:34 +01:00
Sven Van de Velde
17fc554beb readme 2018-02-26 13:22:57 +01:00
Sven Van de Velde
510cef1d59 readme 2018-02-26 13:17:36 +01:00
Sven Van de Velde
dc8d9ddfdd readme 2018-02-26 13:15:13 +01:00
Sven Van de Velde
ed0f84da61 Readme 2018-02-26 13:14:46 +01:00
Sven Van de Velde
e0aa16dbd5 Readme 2018-02-26 13:13:47 +01:00
Sven Van de Velde
7ff664b05d New readme 2018-02-26 13:12:29 +01:00
Sven Van de Velde
930768e2e3 New readme 2018-02-26 13:11:03 +01:00
Sven Van de Velde
c1278993aa Complete 2018-02-26 11:58:27 +01:00
Sven Van de Velde
7145fef233 Complete3 2018-02-26 11:52:28 +01:00
Sven Van de Velde
0a118cf264 Complete2 2018-02-26 11:48:47 +01:00
Sven Van de Velde
344871d727 Complete 2018-02-26 11:46:24 +01:00
Sven Van de Velde
43b2f8c3ff Add DCS stuff 2018-02-26 10:04:01 +01:00
Sven Van de Velde
85f0fe758b Remove submodule 2018-02-26 10:02:48 +01:00
Sven Van de Velde
bb2a1a82a8 Test 2018-02-26 09:32:35 +01:00
Sven Van de Velde
b2a7c994bc Remove Test 2018-02-26 09:32:01 +01:00
Sven Van de Velde
83044af064 Account test 2018-02-24 18:22:57 +01:00
Sven Van de Velde
abcbbdfb79 Publish Moose.lua and Moose_.lua to MOOSE_INCLUDE 2018-02-18 12:33:35 +01:00
Sven Van de Velde
dc75002723 Fixed read me 2018-02-18 11:44:11 +01:00
Sven Van de Velde
3ce5d71fc9 Fixing issue #799 2018-02-18 11:44:01 +01:00
Sven Van de Velde
0764affd49 Donate ... 2018-02-18 09:10:47 +01:00
Sven Van de Velde
8507a85915 Donation 2018-02-18 09:02:24 +01:00
Sven Van de Velde
0dcd414c24 Updated documentation page for the MOOSE repository on GITHUB. 2018-02-17 21:53:56 +01:00
Sven Van de Velde
5ab050b237 Moved release notes 2018-02-17 21:40:08 +01:00
Sven Van de Velde
7eedd7cbf1 Fixed Moose.files 2018-02-17 21:33:29 +01:00
Sven Van de Velde
0e0b1f470b Moved to branch 2018-02-17 21:32:32 +01:00
Sven Van de Velde
beba6ee751 Create artefacts when generating from master. 2018-02-17 21:18:55 +01:00
Sven Van de Velde
2d1409dedb Cleanup of the MOOSE repository. Only the essential is remained. 2018-02-17 21:17:55 +01:00
Sven Van de Velde
85cb0b40f8 Added appveyor 2018-02-17 21:10:37 +01:00
Sven Van de Velde
eb9fc7589f Update to latest changes 2018-02-17 17:02:19 +01:00
Sven Van de Velde
a334511601 reset 2018-02-17 16:52:38 +01:00
Sven Van de Velde
646958cc1a Redirect 2018-02-17 16:49:20 +01:00
Sven Van de Velde
cd414a8129 Redirect 2018-02-17 16:47:19 +01:00
Sven Van de Velde
857ebfab44 Merge pull request #778 from Mongrelf/master
AI_A2A_Dispatcher CountCapAirborne and Detection Change for AcceptZones
2018-02-13 19:19:25 +01:00
Sven Van de Velde
039491a3e1 Merge pull request #808 from FlightControl-Master/servant
Servant
2018-02-13 19:18:34 +01:00
Sven Van de Velde
051733ac97 Update README.md 2018-02-13 16:56:19 +01:00
funkyfranky
f2774dbf71 Added DCS atmosphere API functions.
COORDINATE:GetTemperature(height) returns the temperature (optionally as a function of height ASL).
COORDINATE:GetPressure(height) returns the pressure (optionally as a function of height ASL).
COORDINATE:GetWind(height) returns the wind direction and strength (optionally as a function of height ASL).
UTILS.BeaufortScale(speed) returns the Beaufort number and wind description as a function of wind speed.
2018-02-12 22:50:23 +01:00
funkyfranky
6f6db6d26f Added last waypoint to RouteGroundOnRoad function if that is not on road. 2018-02-11 17:17:13 +01:00
funkyfranky
f69f666deb Added new ways to find routes using roads.
COORDINATE class: added two new functions to find the nearest road and coordinates to a destination using roads.

CONTROLLABLE class: added new function to route a controllable using roads.
2018-02-11 16:40:03 +01:00
funkyfranky
5134de9f28 Markers and RAT v2.1
Added additional arguments for markers as introduced in DCS 2.5.
RAT improvements:
- Added onboard num via input.
- Added description of WPs.
- Fixed markers.
2018-02-08 20:26:04 +01:00
Frank
b3267c00e9 Merge pull request #787 from FlightControl-Master/funkyfranky
RAT fixes
2017-12-31 18:56:34 +01:00
funkyfranky
282bf8bd07 RAT fix
Fix crash in _WaypointFunction due to self:T
Increased version number to 2.0.3
2017-12-30 15:03:37 +01:00
funkyfranky
b52b5b78c9 RAT fixes
Changed self:T to BASE:T
2017-12-30 11:13:45 +01:00
FlightControl_Master
9bca76ddcf * Moved CommandCenter menu to Group Level. It is only generated when a Mission Menu is generated.
* Optimized the menu generation of A2G tasks and DESIGNATE.
  * Removed S_EVENT_PAYER_ENTER_UNIT because it isn't working anyway.
2017-12-22 12:46:07 +01:00
FlightControl_Master
77cddfaeb4 Optimized menu version 2017-12-22 12:44:16 +01:00
FlightControl_Master
ee6a553b6b Re-added player menus 2017-12-22 12:05:14 +01:00
FlightControl_Master
2e195e6dca small optimization of commandcentermenu 2017-12-22 12:01:03 +01:00
FlightControl_Master
f615d2c50a Moved command center menu to GROUP level, also Mission menu. 2017-12-22 11:38:01 +01:00
FlightControl_Master
e54fad6c53 Commented out SetPlayerMenu and S_EVENT_PLAYER_ENTER_UNIT commented out too! 2017-12-22 11:11:25 +01:00
Mongrelf
7b0c0a0c8b Changing Condition Check Starting to Started
Had Starting as the additional condition check but should be 'Started'
2017-12-21 15:34:02 -07:00
FlightControl_Master
4efe03b07b Menu optimizaton changes, did some great stuff here i think. 2017-12-21 22:52:37 +01:00
Mongrelf
030bd92148 AcceptZones Change
Added higher level variable to hold detection state across multiple AcceptZones.
2017-12-21 14:33:09 -07:00
Mongrelf
0f4b3e0d88 AI_A2A_Dispatcher:CountCAPAirborne
Added additional condition check for state = "Starting"
2017-12-21 14:18:33 -07:00
FlightControl_Master
abf0de49d1 Maybe this already helps 2017-12-21 06:26:05 +01:00
FlightControl_Master
e7d48f335c * Added marking of task on map when also assigned.
* A BAI task won't be converted to a CAS task when a friendly airplane is nearby.
2017-12-20 11:51:23 +01:00
FlightControl_Master
ee4f7e843d * Added marking of task on map when also assigned.
* A BAI task won't be converted to a CAS task when a friendly airplane is nearby.
2017-12-20 11:51:00 +01:00
FlightControl_Master
4157ede997 Fixing mistake with the sorting of the menus 2017-12-20 10:07:37 +01:00
FlightControl_Master
54450c9933 limiting task menus to 5 pieces .... 2017-12-19 22:13:05 +01:00
FlightControl_Master
f545d5d31f Fixed the issue in AI_BALANCER.... 2017-12-18 11:50:47 +01:00
FlightControl_Master
8332ba5112 Fixed the issue in AI_BALANCER 2017-12-18 11:50:15 +01:00
FlightControl_Master
f35d78c11c Fixed the issue in designate. 2017-12-17 17:39:13 +01:00
FlightControl_Master
93f03a1e8b Remove trace event 2017-12-16 07:59:01 +01:00
FlightControl_Master
c018a6e13f Stress test menus made me realize about the Path ... 2017-12-15 19:58:25 +01:00
FlightControl_Master
b8c1135b3b When S_EVENT_PLAYER_ENTER_UNIT is called, then the unit is not alive yet. 2017-12-15 13:33:24 +01:00
FlightControl_Master
abbb59efb9 Trying to refresh the menus 2017-12-13 23:20:04 +01:00
FlightControl_Master
ce61e8d859 Fixed typo 2017-12-13 14:28:45 +01:00
Sven Van de Velde
ee698722a6 Merge pull request #765 from FlightControl-Master/ET-rat_remove_menu
Possible fix for removal of menus in RAT
2017-12-13 14:25:40 +01:00
132nd-etcher
be0856c9e1 Possible fix for removal of menus in RAT 2017-12-13 14:10:16 +01:00
FlightControl_Master
e04b434fcb Fixing menus 2017-12-12 20:50:52 +01:00
FlightControl_Master
95112e8818 Solving the SCORING menu not anymore accessible due to S_EVENT_PLAYER_ENTER_UNIT bug in DCS (not fired anymore in MP when a player joins a slot). 2017-12-12 16:08:23 +01:00
FlightControl_Master
09d02e18cf S_EVENT_PLAYER_ENTER_UNIT not called in MP 2017-12-12 15:26:55 +01:00
FlightControl_Master
2ce1057d71 Trying to find the errors. 2017-12-12 14:09:59 +01:00
FlightControl_Master
e048ea995e Maybe the removal of the Settings when a player exits kills DCS ? 2017-12-12 13:59:52 +01:00
FlightControl_Master
d66b7b8c20 Capture Zone documentation. 2017-12-11 22:33:38 +01:00
FlightControl_Master
37dc49c14f Tasking trace optimizations 2017-12-11 13:32:42 +01:00
FlightControl_Master
ef1290015e AliveSet fix 2017-12-11 11:31:47 +01:00
FlightControl_Master
02c671bd63 Ensuring that only alive groups are handled, trying to solve the menu issues.
Optimizing the threatlevel boxes.
2017-12-11 11:08:15 +01:00
FlightControl_Master
18a15332fe Trying to fix the disappearing menus... 2017-12-10 22:05:08 +01:00
FlightControl_Master
d733221317 Fixed issue with CaptureZones, scheduler implementation was wrong. 2017-12-10 20:19:21 +01:00
FlightControl_Master
e036ec0adf Fixing error with SET_BASE:GetSet(). It was the wrong approach to solve the Menu issues. Setting back to the original. 2017-12-10 19:02:20 +01:00
FlightControl_Master
f18b18187b Optimizing Scoring and Controllable 2017-12-10 14:28:58 +01:00
FlightControl_Master
3135639557 Fixed problem with SchedulerObject in BASE. This caused conflicts in SPAWN and SCHEDULER. 2017-12-09 13:28:08 +01:00
FlightControl_Master
5eeafd2fba Validate if this fixes the error 2017-12-08 19:16:53 +01:00
FlightControl_Master
0577e7ee70 Reverse change on SPAWN. Wrong change. 2017-12-08 18:49:08 +01:00
FlightControl_Master
d9a4c63011 Fixes OnSpawnGroup back to scheduler mode, because that worked. 2017-12-08 16:18:31 +01:00
FlightControl_Master
7fd2500db4 Fixed issue with SpawnInAir 2017-12-08 14:58:22 +01:00
Sven Van de Velde
822920e77e Merge pull request #755 from FlightControl-Master/ET-debug_error
fix a small issues in EVENT with debug condition
2017-12-07 18:50:36 +01:00
Sven Van de Velde
85e2811c79 Merge pull request #758 from FlightControl-Master/ET-rat_fixes
fix a few mismatched calls to RAT and rat methods and functions
2017-12-07 18:47:48 +01:00
132nd-etcher
757b2cb6a2 fix a few mismatched calls to RAT and rat methods and functions 2017-12-07 16:20:08 +01:00
132nd-etcher
15c09d9880 fix a small issues in EVENT with debug condition 2017-12-07 10:57:28 +01:00
FlightControl_Master
64b6f52a2d Target marking of all tasks in a mission.
Fixed bug with SetAcceptRange.
2017-12-05 14:31:02 +01:00
FlightControl_Master
27159c4234 Optimized detection.
A CAS task becomes now a BAI task, and vise versa, when the friendlies situation changes!
2017-12-05 10:40:26 +01:00
FlightControl_Master
d38c2540c2 Fixed errors with SET_GROUP 2017-12-04 14:01:59 +01:00
FlightControl_Master
901f460907 Fixed DesignateReport being generated for a group that does not exist. 2017-12-03 08:24:26 +01:00
FlightControl_Master
a2fa2c4fa2 Fixes for A2G tasking, reduce trace, and put in key trace lines to follow the tasking. 2017-12-03 08:06:35 +01:00
FlightControl_Master
76ea635b63 * Fixed AI_A2A_DISPATCHER going crazy
* Fixed SET to avoid when a new element is added, that the index is also incremented.
2017-11-30 16:04:58 +01:00
FlightControl_Master
d2a7cc77cc bracket mistake 2017-11-30 14:00:20 +01:00
Sven Van de Velde
c81e9e5a5e Merge pull request #744 from 132nd-etcher/RAT_trace
RAT Trace
2017-11-30 12:29:15 +01:00
Sven Van de Velde
92c4507a55 Merge branch 'master' into RAT_trace 2017-11-30 12:26:04 +01:00
Sven Van de Velde
967d608b94 Merge branch 'master' into RAT_trace 2017-11-30 12:19:10 +01:00
FlightControl_Master
14c075abfc * Fixed issue with Scoring menu not shown in single player.
* Fixed issue with Scoring players table not being populated correctly, resulting in the scoring report for all players not being shown. Fixed.
2017-11-30 12:01:44 +01:00
FlightControl_Master
ce449c37b1 Reworked the sanitization of debug
Fixed an issue in Designate for the messages.
2017-11-30 10:30:42 +01:00
Sven Van de Velde
09f5421612 Merge pull request #748 from FlightControl-Master/funkyfranky
Fixed "debug" problem
2017-11-29 05:55:44 +01:00
funkyfranky
3c8244b2aa Fixed "debug" problem
Changed RAT.debug to RAT.Debug
Added switch for ATC messages
2017-11-24 22:34:09 +01:00
FlightControl_Master
057e528947 Changes 2017-11-23 21:00:38 +01:00
132nd-etcher
e9fe11e9b3 RAT Trace
Use BASE tracing methods in RAT
2017-11-22 09:07:18 +01:00
FlightControl_Master
b7183023c9 Documentation 2017-11-22 06:23:58 +01:00
FlightControl_Master
dd58838983 * Rewritten the complete menu mechanism.
* SetRemoveParent method on menus removed, made obsolete, to avoid menus being deleted that should not.
  * A2G reports now work again, and improved the reporting for successful or failed tasks.
  * Removed MENU_CLIENT and MENU_CLIENT_COMMAND
  * Improved the detection of new spawned groups within the TASK_A2G_DISPATCHER.
  * Improved how new detections and new target sets are reported and followed-up within the TASK_A2G mechanism.

Pending: Improve the TASK_A2A_DISPATCHER and TASK_A2A mechanisms.
2017-11-22 06:22:36 +01:00
FlightControl_Master
ef5d69032a Commented the tracing from the debugger client. If needed it can be reactivated. 2017-11-14 08:59:15 +01:00
FlightControl_Master
6dcbbec087 improvements 2017-11-12 22:49:47 +01:00
FlightControl_Master
6c98cf3a09 Fix error in SpawnAtAirbase 2017-11-12 21:02:49 +01:00
FlightControl_Master
5f6981d309 Takeoff in Air fixed.
NewFromGroupName Fixed
2017-11-12 07:12:50 +01:00
FlightControl_Master
49d3e4e7da Updates upon advice from wingthor 2017-11-10 14:37:13 +01:00
FlightControl_Master
060a1b219f updates 2017-11-10 12:28:13 +01:00
FlightControl_Master
4db18a4846 Tag test 2017-11-10 12:19:03 +01:00
FlightControl_Master
42a9e4c60d Test 2017-11-10 12:04:10 +01:00
FlightControl_Master
f3bd097e6f Updates 2017-11-10 11:12:48 +01:00
FlightControl_Master
1848e117aa Merge branch 'LDT-Debug' 2017-11-10 11:01:29 +01:00
FlightControl_Master
131db74630 Release test 2017-11-10 10:58:05 +01:00
FlightControl_Master
46e76a3833 updated connect 2017-11-10 06:53:04 +01:00
FlightControl_Master
7ff06b5ef8 New way of loading the debugger. 2017-11-09 22:57:18 +01:00
FlightControl_Master
f65238efe6 Got something working finally. 2017-11-09 21:36:11 +01:00
FlightControl_Master
0a819f254a Progress 2 2017-11-08 09:41:18 +01:00
FlightControl_Master
7c7722efe6 Add luasocket place 2017-11-07 19:01:11 +01:00
FlightControl_Master
e229e2e381 Documentation 2017-11-07 18:06:18 +01:00
FlightControl_Master
ac0d2fa92c "Working assets in prototype version" 2017-11-07 17:56:59 +01:00
FlightControl_Master
e9837acda3 Update init 2017-11-05 06:35:34 +01:00
FlightControl_Master
2e049ccfd4 updates 2017-11-05 06:30:29 +01:00
FlightControl_Master
73a1c56532 New dynamic loader 2017-11-05 06:15:06 +01:00
FlightControl_Master
5686f97565 Added the debugger 2017-11-05 06:12:04 +01:00
FlightControl_Master
c1910646e2 Merge branch 'master' into LDT-Debug
# Conflicts:
#	Moose Development/Moose/Moose.lua
#	Moose Mission Setup/Moose.lua
2017-11-05 06:09:41 +01:00
FlightControl_Master
dab20a3b88 Destroyed units weren't accounted anymore. Fixed this. 2017-11-03 08:33:35 +01:00
FlightControl_Master
f82d07ebc0 Extended the Waypoint functions of COORDINATE with new methods for Air operations:
* function COORDINATE:WaypointAirTurningPoint( AltType, Speed )
  * function COORDINATE:WaypointAirFlyOverPoint( AltType, Speed )
  * function COORDINATE:WaypointAirTakeOffParkingHot( AltType, Speed )
  * function COORDINATE:WaypointAirTakeOffParking( AltType, Speed )
  * function COORDINATE:WaypointAirTakeOffRunway( AltType, Speed )
  * function COORDINATE:WaypointAirLanding( Speed )
2017-11-02 08:19:46 +01:00
FlightControl_Master
e625aaf28c Documentation 2017-11-01 17:50:04 +01:00
FlightControl_Master
7bc0f103d9 Fixed and documentation of ZONE_CAPTURE_COALITION 2017-11-01 17:22:22 +01:00
Sven Van de Velde
6a0294e22b Merge pull request #726 from FlightControl-Master/funkyfranky
@Funkyfranky done the merge on master.
2017-10-31 10:58:10 +01:00
funkyfranky
82fa9ae8b3 Merge branch 'master' into funkyfranky 2017-10-31 08:47:17 +01:00
FlightControl_Master
0c70a34561 Improved ATC_GROUND
* Added speed limits.
  * Speed limits can now be set per airbase.
  * Maximum speed to prevent takeoff can be set.
  * Maximum speed can be set per airbase.
  * Improved documentation.
2017-10-31 08:32:47 +01:00
funkyfranky
4618e81039 RAT bug fix
Holding and final waypoint fixed when aircraft chang the flightplan.
2017-10-30 12:37:13 +01:00
funkyfranky
84fee06196 RAT bug fixes.
When SetDeparture() is not used, SetDestination() does not count the possible destinations correctly.
When Commute() is used with RAT.wp.coldorhot, next spawning will happen in air.
2017-10-30 09:52:50 +01:00
FlightControl_Master
f6f2695808 Documentation Patch 2.2.5. 2017-10-30 08:22:23 +01:00
Frank
cbf0112bd7 Merge pull request #724 from FlightControl-Master/funkyfranky
Funkyfranky
2017-10-30 07:27:19 +01:00
funkyfranky
97be67bae9 RAT v2 2017-10-29 19:27:39 +01:00
funkyfranky
58a6c43c41 RAT fixes and adjustments
Fixed maxdistance. Was 500 not 5000 km.
2017-10-29 15:09:17 +01:00
funkyfranky
d564b0161c Merge branch 'master' into funkyfranky 2017-10-28 15:10:43 +02:00
FlightControl_Master
6e47fd0c46 Merge branch 'FC/ATC_Ground' 2017-10-28 08:13:18 +02:00
FlightControl_Master
9a90225d40 A lot of documentation improvements and fixing a bug report. 2017-10-28 08:12:13 +02:00
funkyfranky
43b5926b74 Moose.lua 2017-10-27 22:08:16 +02:00
funkyfranky
86c7e64018 Merge branch 'master' into funkyfranky 2017-10-27 22:02:09 +02:00
funkyfranky
c66117464a RAT enhancements
Added possibility to add all friendly airports as departure/destination when SetDeparture() is used.
Improved consistency check.
Added SetAISkill() function.
2017-10-27 22:00:47 +02:00
FlightControl_Master
6f0a254929 Documentation 2017-10-27 18:30:03 +02:00
FlightControl_Master
c495d0e5e9 Airbases updates 2017-10-27 07:03:27 +02:00
FlightControl_Master
bdf5c1e960 Documentation 2017-10-27 07:00:40 +02:00
FlightControl_Master
86ad985e0b updates docs 2017-10-26 21:19:41 +02:00
FlightControl_Master
abf84e121f Documentation 2017-10-26 19:22:18 +02:00
FlightControl_Master
212c674443 Merge branch 'Release-2.2.0'
# Conflicts:
#	Moose Development/Moose/Core/Spawn.lua
#	Moose Mission Setup/Moose.lua
#	Moose Mission Setup/Moose_.lua
2017-10-26 19:06:22 +02:00
FlightControl_Master
9965d8284e * Modified :SpawnInZone(), :SpawnFromVec2(), :SpawnFromStatic(), :SpawnFromUnit() specifying an optional MinHeight and MaxHeight as a parameter, so that the mission designer can choose if he wanna use the group height set in the mission editor for spawn or a random height specified by the parameters. 2017-10-26 18:59:24 +02:00
funkyfranky
3ac649d6e8 RAT small fixes
Radio Modulation function named wrong.
Markers bug fixed.
2017-10-26 17:27:12 +02:00
FlightControl_Master
0e4a5c02d5 Working version, fiew! 2017-10-26 14:54:59 +02:00
FlightControl_Master
8a4a37ac11 extended the airbase range 2017-10-26 12:04:39 +02:00
FlightControl_Master
74951f4237 Documentation 2017-10-26 11:17:11 +02:00
FlightControl_Master
8aa14428dc Merge branch 'FC/AirbasePolice'
# Conflicts:
#	Moose Development/Moose/Functional/ATC_Ground.lua
#	docs/Documentation/AirbasePolice.html
2017-10-26 11:16:04 +02:00
FlightControl_Master
8002febf09 * Renamed AIRBASE POLICE to ATC GROUND
* Fixed issues with landing and departing.
2017-10-26 11:13:11 +02:00
funkyfranky
7da932e048 RAT final touches 2017-10-26 00:05:40 +02:00
funkyfranky
6923cfe143 moose.lua 2017-10-24 23:16:04 +02:00
funkyfranky
06283ad9e3 moose 2017-10-24 23:06:01 +02:00
funkyfranky
f4a0b83619 RAT 2017-10-24 23:03:57 +02:00
funkyfranky
70e5ce30bb Merge branch 'master' into funkyfranky 2017-10-23 23:31:02 +02:00
funkyfranky
3b3017aa1d RAT improvements. 2017-10-23 23:30:38 +02:00
FlightControl_Master
6c5dcb068b Documentation 2017-10-23 15:35:14 +02:00
FlightControl_Master
ea7d4e4ab8 Merge branch 'FC/AirbasePolice'
# Conflicts:
#	Moose Development/Moose/Functional/AirbasePolice.lua
2017-10-23 15:33:45 +02:00
FlightControl_Master
a8c5ccd4ad * Final version
* Monitor off taxi way
  * Monitor maximum speed
  * Monitor kick speed
2017-10-23 15:30:40 +02:00
funkyfranky
e41b038730 Merge branch 'master' into funkyfranky 2017-10-22 22:55:07 +02:00
funkyfranky
172e51307c RAT 2017-10-22 22:54:50 +02:00
FlightControl_Master
ccb4d7f7b5 Merge branch 'FC/AirbasePolice' 2017-10-22 22:40:00 +02:00
FlightControl_Master
140f81b695 * Added all airbases of Nevada.
* Added all airbases of Normandy.
2017-10-22 22:39:29 +02:00
FlightControl_Master
81d724d881 Merge branch 'FC/AirbasePolice'
# Conflicts:
#	docs/Documentation/Task_Cargo.html
2017-10-21 17:18:39 +02:00
FlightControl_Master
b7528dad2e Improved airbase police 2017-10-21 12:04:05 +02:00
FlightControl_Master
63ba44dca2 * Create GROUP Templates out of the fly, so even when not in the mission.
* Added smoke Altitude and AngleOffset to ZONE_RADIUS for Smoke
2017-10-21 07:42:19 +02:00
funkyfranky
8ea8702140 Removed Suppressive Fire 2017-10-20 22:39:13 +02:00
funkyfranky
b923159298 Changed Suppression Fire to Suppressive Fire 2017-10-20 22:32:45 +02:00
funkyfranky
79afc5a856 Merge branch 'master' into funkyfranky 2017-10-20 22:30:10 +02:00
FlightControl_Master
4d8179ec70 Documentation 2017-10-20 14:10:59 +02:00
FlightControl_Master
224f0694d8 Merge branch 'FC/AirbasePolice' 2017-10-20 14:06:05 +02:00
FlightControl_Master
57b4838a5a doc 2017-10-20 13:57:18 +02:00
FlightControl_Master
a204dd2f4b Banner 2017-10-20 13:56:29 +02:00
FlightControl_Master
7cab0ca22a Documentation improvements. 2017-10-20 13:54:37 +02:00
funkyfranky
3e16e5fa51 RAT 2017-10-19 23:36:28 +02:00
funkyfranky
210ad2154c Merge branch 'master' into funkyfranky 2017-10-19 23:34:22 +02:00
funkyfranky
bce2e3b922 RAT waypoints 2017-10-19 23:34:14 +02:00
FlightControl_Master
a8e77bddd4 Merge branch 'FC/Kick_Players' 2017-10-19 10:23:56 +02:00
FlightControl_Master
d8eb7ce097 New airbase police version 2017-10-19 10:20:10 +02:00
funkyfranky
d0107d5cee RAT added radio 2017-10-19 00:39:40 +02:00
funkyfranky
a82be92577 Merge branch 'master' into funkyfranky 2017-10-18 16:54:18 +02:00
funkyfranky
730cd92d51 RAT ATC 2017-10-18 15:51:01 +02:00
FlightControl_Master
d3b5c77e5c * Fixes for AI_A2A_GCICAP, tracing the setup information.
* Fixed Spawning in air bug, Takeoff event generation parameters mismatch solved.
2017-10-18 09:03:13 +02:00
funkyfranky
f1b7ae7643 RAT
fixes
2017-10-18 00:47:44 +02:00
funkyfranky
f952cd4bb5 Merge branch 'master' into funkyfranky 2017-10-17 18:23:52 +02:00
funkyfranky
32e61da588 RAT 2017-10-17 17:13:34 +02:00
FlightControl_Master
c27197500c Removed bugs 2017-10-17 11:47:03 +02:00
FlightControl_Master
b5fbe6d55e Set the flag 2017-10-17 11:08:49 +02:00
FlightControl_Master
291df87beb Stupid me, did not set the flag!!! 2017-10-17 10:34:35 +02:00
funkyfranky
a661c6e711 RAT Improved Flightplan Logic 2017-10-17 00:33:08 +02:00
funkyfranky
e1d12cbd8e Suppression + RAT 2017-10-16 00:14:41 +02:00
funkyfranky
1e2a84608f Merge branch 'master' into funkyfranky 2017-10-14 09:29:24 +02:00
funkyfranky
88260ae4f3 Suppression Fire 2017-10-12 14:55:50 +02:00
Sven Van de Velde
3a8c1f97f1 Merge pull request #717 from FlightControl-Master/FC-Zone-Transport-Cargo
Fc zone transport cargo
2017-10-12 11:04:39 +02:00
FlightControl_Master
0cc36b5ee2 Added CARGO_CRATE
Added a new object called CARGO_CRATE
2017-10-12 11:02:56 +02:00
FlightControl_Master
d5c7d0028b Merge branch 'master' into FC-Zone-Transport-Cargo 2017-10-12 08:24:23 +02:00
funkyfranky
3a0f60adc9 Suppression Fire and Alarm State 2017-10-12 00:36:21 +02:00
funkyfranky
a575dfea7d Suppression Fire 2017-10-11 17:27:25 +02:00
FlightControl_Master
515cf70295 fixed text 2017-10-11 11:23:10 +02:00
FlightControl_Master
fbabc54e03 Created a logic using flags to kick layers using the extended slot blocker from Ciribob 2017-10-11 11:22:17 +02:00
FlightControl_Master
059754fc28 added API descriptions 2017-10-11 09:38:49 +02:00
funkyfranky
cbc0579c79 Suppression Fire 2017-10-10 23:30:22 +02:00
FlightControl_Master
da0bf650fa Fix dependency error 2017-10-10 21:56:23 +02:00
FlightControl_Master
4de8bc742f Update Spawn to correct place 2017-10-10 21:41:59 +02:00
Sven Van de Velde
93ba003e5b Merge pull request #716 from FlightControl-Master/FC-Spawn-Optimization
Fc spawn optimization
2017-10-10 21:33:34 +02:00
FlightControl_Master
da476b29a6 Optimizations
* Added ZONE_POLYGON:NewFromGroupName() to ease the syntax.
* Renamed Functional.Spawn#SPAWN to Core.Spawn#SPAWN
2017-10-10 21:32:59 +02:00
FlightControl_Master
5ee9633dc6 Added method SPAWN:InitRandomizeTemplatePrefixes 2017-10-10 20:28:33 +02:00
FlightControl_Master
6d2e8d34fb Added Templating from a SET_GROUP object 2017-10-10 18:36:19 +02:00
FlightControl_Master
a35e95a7dc Hotfix 2.2.3 2017-10-10 11:53:54 +02:00
FlightControl_Master
126810a273 Merge remote-tracking branch 'refs/remotes/origin/Release-2.2.0' 2017-10-10 11:53:03 +02:00
FlightControl_Master
58e3e5293e Hotfix 2.2.3
* Fixed a problem in AI_A2A_DISPATCHER, patrols didn't work anymore due
to a stupid mistake in a variable rename (sorry). Fixed now.
2017-10-10 11:52:30 +02:00
FlightControl_Master
8eff6493ec Hotfix 2.2.3
* Fixed AI_A2A_DISPATCHER; a stupid syntax error due to a variable
rename sneaked into the logic.
2017-10-10 11:50:48 +02:00
Sven Van de Velde
0227549207 Merge pull request #715 from FlightControl-Master/FC-Capture-Zones
Fc capture zones
2017-10-10 11:08:20 +02:00
FlightControl_Master
ddf45d8485 Documentation and new moose.lua for dynamic loading. 2017-10-10 11:07:43 +02:00
FlightControl_Master
6f151a6c5d Progress
* Added USERFLAG class to manage user flags
* Added USERSOUND class to manage sounds
* Added SET_BASE:GetSetNames() to return an array of the object names of
a Set. (Created dynamic lists based on mission editor groups defined).
* Added SET_BASE:GetSetObjects()
* Revised the Messages
* Optimized the code for GetScannedCoalition
* Markings text optimized for ZONE_CAPTURE_COALITION. Now the owning
coalition is also shown.
* Removed the stupid naming of messages to coalitions.
2017-10-10 11:06:05 +02:00
FlightControl_Master
9bfca83804 Merge remote-tracking branch 'refs/remotes/origin/master' into FC-Capture-Zones 2017-10-09 14:47:22 +02:00
FlightControl_Master
4b74d1b724 Update 2017-10-09 14:47:06 +02:00
FlightControl_Master
1067f16ce4 Changes 2017-10-09 14:46:13 +02:00
FlightControl_Master
5896ebe9ca Merge remote-tracking branch 'refs/remotes/origin/Release-2.2.0'
# Conflicts:
#	Moose Mission Setup/Moose.lua
#	Moose Mission Setup/Moose_.lua
2017-10-09 13:32:53 +02:00
FlightControl_Master
305cb3092e Patch 2.2.2: Updated Scoring
* Disabled the logic of Fratricide until a DCS bug gets fixed by ED.
There is no workaround possible. Units containing a player cannot be
destroyed using Unit:destroy() API in multi player when the player is
seated in a Unit from a Client connected PC to the Server.
* By default, hit messages are disabled. They can be enabled by using
SCORING:SetMessagesHit().
2017-10-09 13:10:42 +02:00
Frank
04c2a545f2 Merge pull request #713 from FlightControl-Master/funkyfranky
Fixes in Cargo
2017-10-08 23:13:36 +02:00
funkyfranky
09fd43a3c9 Trace value changed 2017-10-08 22:58:39 +02:00
funkyfranky
d0c6a9756c Fixes in cargo 2017-10-08 22:56:22 +02:00
Frank
b72f649b91 Merge pull request #712 from FlightControl-Master/funkyfranky
Added option to use MOOSE zones for airport selection.
2017-10-08 19:39:58 +02:00
funkyfranky
a78275814d Merge branch 'master' into funkyfranky 2017-10-08 19:00:34 +02:00
funkyfranky
c4fbdb32c4 Moose.lua 2017-10-08 19:00:06 +02:00
Sven Van de Velde
4be4482957 Merge pull request #711 from FlightControl-Master/Scenery-Search
Scenery Search methods
2017-10-08 14:11:10 +02:00
FlightControl_Master
8542823692 Scenery Search methods 2017-10-08 14:10:38 +02:00
Sven Van de Velde
712b77b590 Merge pull request #710 from FlightControl-Master/FC-Protect-Class
Fc protect class
2017-10-07 22:14:59 +02:00
FlightControl_Master
57cb31c86b Moved capture related methods to ZONE_CAPTURE_COALITION 2017-10-07 22:14:05 +02:00
FlightControl_Master
7f04c98d61 Merge remote-tracking branch 'refs/remotes/origin/master' into FC-Protect-Class 2017-10-07 21:37:23 +02:00
FlightControl_Master
15ea0bc63a ZONE GOAL CARGO stuff 2017-10-06 19:56:31 +02:00
FlightControl_Master
50aaeb1465 Merge remote-tracking branch 'refs/remotes/origin/master' into FC-Zone-Transport-Cargo 2017-10-06 18:28:35 +02:00
funkyfranky
a515385ae0 Merge branch 'master' into funkyfranky 2017-10-06 18:28:34 +02:00
Sven Van de Velde
399021502f Merge pull request #709 from FlightControl-Master/FC-Protect-Class
Capture Zone
2017-10-06 18:26:02 +02:00
FlightControl_Master
020f097584 Introduction of Zone goal classes 2017-10-06 14:44:28 +02:00
FlightControl_Master
5c56e75a60 Moved ZoneGoal and ZoneGoalCoalition from Core to Functional 2017-10-06 13:08:47 +02:00
FlightControl_Master
f2afd524ef Merge remote-tracking branch 'refs/remotes/origin/master' into FC-Protect-Class
# Conflicts:
#	Moose Mission Setup/Moose.lua
#	Moose Mission Setup/Moose_.lua
2017-10-06 13:04:46 +02:00
FlightControl_Master
ea8ba2f9aa Incorporate Hotfix 2.2.1 2017-10-06 13:00:43 +02:00
FlightControl_Master
421541e88e Merge remote-tracking branch 'refs/remotes/origin/Release-2.2.0' 2017-10-06 12:59:58 +02:00
FlightControl_Master
7c26e88345 Hotfix 2.2.1
- Changed ROTPassiveDefenses of AI_A2A to ROTEvadeFire
2017-10-06 12:41:31 +02:00
FlightControl_Master
84ddb3e380 Progress 2017-10-05 19:08:33 +02:00
FlightControl_Master
ffc1c5d6ad Progress 2017-10-05 18:31:39 +02:00
funkyfranky
0a325efeaf Minor fixes. 2017-10-05 15:42:57 +02:00
FlightControl_Master
cd83a0b488 Update 2017-10-05 12:13:31 +02:00
FlightControl_Master
fe47783bfa Progress 2017-10-05 11:09:10 +02:00
funkyfranky
6061883194 Added airport selection by zone. 2017-10-05 00:08:48 +02:00
funkyfranky
2d6b74ee9e Merge branch 'master' into funkyfranky 2017-10-04 18:14:23 +02:00
FlightControl_Master
feef4c148e Progress 2017-10-04 17:12:05 +02:00
funkyfranky
6952401238 Added airports from zone (untested) 2017-10-04 16:45:27 +02:00
FlightControl_Master
454c0e5543 Progress 2017-10-04 14:34:24 +02:00
FlightControl_Master
1f5030fcbc Progress 2017-10-03 19:19:09 +02:00
FlightControl_Master
78f4f532f7 New dynamic lua 2017-10-03 14:01:40 +02:00
FlightControl_Master
18de424352 Merge remote-tracking branch 'refs/remotes/origin/master' into FC-Protect-Class
# Conflicts:
#	Moose Mission Setup/Moose.lua
2017-10-03 13:55:41 +02:00
FlightControl_Master
36a9295197 Static versions 2017-10-03 13:52:26 +02:00
FlightControl_Master
ca77e2d029 Merge remote-tracking branch 'refs/remotes/origin/master' into Release-2.2.0
# Conflicts:
#	Moose Mission Setup/Moose.lua
2017-10-03 13:51:42 +02:00
FlightControl_Master
93d5327811 Support 2 moose.lua versions, one stripped and one with comments. 2017-10-03 13:49:56 +02:00
FlightControl_Master
2224cc7593 Merge remote-tracking branch 'refs/remotes/origin/master' into FC-Protect-Class 2017-10-03 13:17:19 +02:00
FlightControl_Master
d5e9c47bad Updated pictures 2017-10-03 11:40:43 +02:00
FlightControl_Master
e62523786c Static Moose.lua 2017-10-03 11:07:47 +02:00
FlightControl_Master
e10913edaf Pictures 2017-10-03 11:01:09 +02:00
FlightControl_Master
4dc1fbaf52 Release Notes 2017-10-03 10:36:00 +02:00
FlightControl_Master
5aad27edfc Progress 2017-10-02 13:49:21 +02:00
FlightControl_Master
0b5d97bf3f Progress 2017-09-30 14:35:18 +02:00
FlightControl_Master
e1aef42df8 Progress 2017-09-30 13:54:53 +02:00
FlightControl_Master
f115630546 Progress 2017-09-30 07:40:01 +02:00
FlightControl_Master
c6e86c494d Progress 2017-09-29 17:34:20 +02:00
FlightControl_Master
cafcbfde90 Progress 2017-09-29 13:19:24 +02:00
FlightControl_Master
632ce65bf5 Progress 2017-09-29 12:11:25 +02:00
FlightControl_Master
b84d08f052 Progress 2017-09-29 07:03:50 +02:00
FlightControl_Master
57eeefcf06 Progress 2017-09-28 19:54:44 +02:00
FlightControl_Master
9227bbdfca Protect first version 2017-09-28 13:25:12 +02:00
FlightControl_Master
5641d65f71 Added new Scheduler events to BASE. 2017-09-28 11:04:45 +02:00
FlightControl_Master
5558c26db7 Reduction of moose.lua sizing working now! 2017-09-26 18:47:33 +02:00
FlightControl_Master
11067d4bfd Fixed DefenderSquadron.Resources nil problem for DefendersNeeded 2017-09-26 09:37:05 +02:00
FlightControl_Master
e1f4bdc24b Improvements on Patrol 2017-09-25 12:55:12 +02:00
Frank
bc072d10df Merge pull request #704 from FlightControl-Master/funkyfranky
ATC queue and fixes.
2017-09-25 10:10:22 +02:00
funkyfranky
ec6961fada ATC queue minor changes 2017-09-24 21:53:24 +02:00
funkyfranky
374aae3e7e Merge branch 'master' into funkyfranky 2017-09-24 15:30:10 +02:00
funkyfranky
c41b30adc2 Improved get destination/departuire behaviour. 2017-09-24 15:29:51 +02:00
FlightControl_Master
27e8226330 Added Patrol methods
* CONTROLLABLE has received the following new methods:
* :PatrolRoute()
* :PatrolRouteRandom( Speed, Formation )
* :PatrolZones( ZoneList, Speed, Formation )
2017-09-24 08:17:28 +02:00
funkyfranky
0c55d4d20e Merge branch 'master' into funkyfranky 2017-09-22 19:03:04 +02:00
funkyfranky
43a62ebf87 ATC and Documentation 2017-09-22 16:53:55 +02:00
FlightControl_Master
0df4b5fd37 Fixed DISPATCHER issues with TakeoffFromRunway 2017-09-22 11:08:35 +02:00
funkyfranky
2fa18ae6c7 Added trigger events for ATC landing. 2017-09-22 00:36:18 +02:00
FlightControl_Master
d77cbff3f8 Adding controlapi to the documentation set 2017-09-21 17:18:57 +02:00
funkyfranky
c1f884d024 atc2 2017-09-21 01:11:52 +02:00
FlightControl_Master
a909e1ee5d Modified message types 2017-09-20 09:53:23 +02:00
FlightControl_Master
fa14f4655e Changed message display methods 2017-09-20 06:54:17 +02:00
funkyfranky
43cbc93a96 atc 2017-09-19 16:34:37 +02:00
FlightControl_Master
ec7cc9e547 Fixed issues with CAS and CAP
* AI_CAP_ZONE: Fixed CAP engaging.
* AI_CAS_ZONE: Fixed CAS engaging.
2017-09-18 14:50:56 +02:00
FlightControl_Master
9226ab9fa9 Updated timestamp of dynamic version 2017-09-18 06:15:06 +02:00
FlightControl_Master
4edc8363e1 Urgent fixes
* DESIGNATE: Messages not appearing correctly and crashing the logic is
fixed. (due to a stupid typo).
* TASK_A2G: Tasking is fixed. Status menus are now displayed properly.
Also when the task is planned.
* MENU_COMMAND: I found now why DCS is displayer "error in error
handler" sometimes when a menu was selected. The error handler is DCS is
bugged, so made my own one.
2017-09-18 06:10:45 +02:00
funkyfranky
0f764424e8 Added some more output. 2017-09-17 23:39:19 +02:00
funkyfranky
8c5eb5fb0d Bug fixes
Fixed bug in airport ID.
Fixed bug in equation of waypoint distance calculation.
2017-09-16 10:57:32 +02:00
FlightControl_Master
56813a800c Fixed the impossible bearing calculation problem
* Bearing is only known of a SET_UNIT, if all units of the set are
heading +/- 5 degrees in the same direction.
2017-09-15 19:38:19 +02:00
FlightControl_Master
df7ffc2a3f Fixed detailed report following settings of player
* Detailed task report now follows coordinate format settings of player.
2017-09-15 17:01:15 +02:00
FlightControl_Master
6799cd776e RAT documentation update 2017-09-15 16:17:08 +02:00
funkyfranky
6fc9baee07 Improved Gauss, added spawn for FARPS/ships (untested) 2017-09-15 16:03:48 +02:00
Sven Van de Velde
a9679f831d Merge pull request #699 from FlightControl-Master/funkyfranky
Funkyfranky
2017-09-15 14:38:08 +02:00
funkyfranky
a8e14b5e20 .gitignore 2017-09-15 14:31:23 +02:00
funkyfranky
c1c148eab4 deleted AI_Bai.html 2017-09-15 14:24:25 +02:00
funkyfranky
5ae7ee8e1b Docu fixes 2017-09-15 14:20:39 +02:00
funkyfranky
5f8bc4f3bd merge master 2017-09-15 14:09:31 +02:00
FlightControl_Master
bae6219b7a Fix crash with markings
* Fixed a crash with markings
* Optimized the detailed report of a task
2017-09-15 13:42:08 +02:00
FlightControl_Master
6a725475c9 Documentation 2017-09-15 10:54:09 +02:00
FlightControl_Master
efd2f7938e Optimized code for SpawnAtAirbase 2017-09-15 10:39:50 +02:00
funkyfranky
09f61610c1 Added metric functions for cruisealt.
Fixed bugs regarding coalitions.
Adjusted gaussian distribution for cruise alt.
2017-09-15 00:02:29 +02:00
funkyfranky
0a2f7c031d Merge branch 'master' into funkyfranky 2017-09-14 23:10:54 +02:00
FlightControl_Master
1ee6b3501f Spawn on Ship is fixed (i hope now) 2017-09-14 12:25:17 +02:00
FlightControl_Master
0ede10b1a2 Fixed takeoff problem in 2.1 2017-09-14 11:30:45 +02:00
funkyfranky
e0158a9a66 Merge branch 'master' into funkyfranky 2017-09-14 08:28:37 +02:00
funkyfranky
27e32486fd remove RAT.html 2017-09-14 00:45:36 +02:00
funkyfranky
6b08f6aaac Bloody html 2017-09-14 00:44:09 +02:00
funkyfranky
ae2be627e3 Added function to spawn without template (no working yet). 2017-09-14 00:37:26 +02:00
FlightControl_Master
887faacdb1 New documentation version 2017-09-13 21:41:46 +02:00
FlightControl_Master
f47ac8baaf delete old rat file 2017-09-13 21:37:21 +02:00
funkyfranky
8d600ca8a4 Merge branch 'master' into funkyfranky 2017-09-13 17:52:06 +02:00
funkyfranky
d29d959e47 Added livery and skill options (untested) 2017-09-13 16:48:00 +02:00
funkyfranky
c62cd53e5f Removed AI_RAT.html 2017-09-13 13:31:08 +02:00
Frank
0cc3249738 Merge pull request #687 from FlightControl-Master/funkyfranky
Funkyfranky
2017-09-13 08:32:06 +02:00
Sven Van de Velde
902dec5233 Merge pull request #689 from FlightControl-Master/Additions
Additions
2017-09-13 07:07:31 +02:00
FlightControl_Master
adb4befcdf Updates 2017-09-13 07:07:07 +02:00
FlightControl_Master
5d62125245 Merge remote-tracking branch 'refs/remotes/origin/master' into Additions 2017-09-13 04:19:06 +02:00
funkyfranky
ca39a158d7 Added TODO item 2017-09-12 23:03:25 +02:00
funkyfranky
597a62c8ab Merge branch 'master' into funkyfranky 2017-09-12 17:49:33 +02:00
funkyfranky
a91be7df58 Added Gaussian Distribution to randomize FL. 2017-09-12 16:47:02 +02:00
Sven Van de Velde
00463f401e Merge pull request #686 from FlightControl-Master/Additions
Implemented Message Types
2017-09-12 12:22:45 +02:00
FlightControl_Master
e177c7e804 Merge remote-tracking branch 'refs/remotes/origin/master' into Additions 2017-09-12 12:20:44 +02:00
FlightControl_Master
e545af51f3 Implemented type messages to Coalition 2017-09-12 12:20:41 +02:00
FlightControl_Master
6d1385a031 Implemented Message Types
* Added Message Type Methods
* SETTINGS menu has been added with Message Type display times
* Modifed the FSM action classes to use the new Message Type methods.
2017-09-12 11:41:52 +02:00
funkyfranky
fa8a9b52fe Merge branch 'master' into funkyfranky 2017-09-11 23:27:04 +02:00
funkyfranky
217ded3492 Added possibility to use same template group multiple times.
Changed SPAWN:New() to SPAWN:NewWithAlias().
Cleaned up debug messages etc.
Other fixes and improvements.
2017-09-11 23:23:15 +02:00
Sven Van de Velde
eac57ae0a3 Merge pull request #685 from FlightControl-Master/Additions
Additions
2017-09-11 15:02:39 +02:00
FlightControl_Master
8a8c496c64 Merge remote-tracking branch 'refs/remotes/origin/master' into Additions 2017-09-11 15:02:08 +02:00
FlightControl_Master
f2db40db6e To gruop 2017-09-11 14:59:07 +02:00
Sven Van de Velde
c70b587936 Merge pull request #684 from FlightControl-Master/Additions
Markers
2017-09-11 14:55:47 +02:00
FlightControl_Master
560f551ed7 Progress 2017-09-11 14:54:08 +02:00
FlightControl_Master
bdfd03a0b8 Merge remote-tracking branch 'refs/remotes/origin/master' into Additions 2017-09-11 06:54:56 +02:00
Sven Van de Velde
e1e2d082be Merge pull request #683 from FlightControl-Master/Markings
Added methods to COORDINATE to place marks on the map
2017-09-11 06:51:44 +02:00
FlightControl_Master
51e50bee71 Added methods to COORDINATE to place marks on the map
* Added new methods to COORDINATE allowing to place marks for players on
the map. Now marks can be placed on the map using :AddToAll(),
:MarkToCoalition(), :MarkToCoalitionRed(), :MarkToCoalitionBlue(),
:MarkToGroup() and marks can be removed using :RemoveMark()
2017-09-11 06:51:14 +02:00
funkyfranky
1baeba251e Added RAT documentation.
Caught some user errors for unknown airports etc.
Improved despawn on inactive planes.
2017-09-11 00:11:50 +02:00
funkyfranky
5e0e8f3f73 Merge branch 'master' into funkyfranky 2017-09-09 21:58:53 +02:00
Sven Van de Velde
ae4affbf2f Merge pull request #680 from FlightControl-Master/Additions
Additions
2017-09-09 19:07:11 +02:00
FlightControl_Master
6a13febf7b Updates 2017-09-09 19:02:37 +02:00
funkyfranky
7a23115cf9 Merge branch 'master' into funkyfranky 2017-09-09 18:26:22 +02:00
funkyfranky
5d627d91d8 Moved RAT to functional. 2017-09-09 18:23:57 +02:00
funkyfranky
e205af75ca Fixed bugs introduced in last update.
Added delete markers to F10 menu.
2017-09-08 23:22:33 +02:00
FlightControl_Master
4dc468e902 In progress
* Markers
* BR menu on designate always in A2G
2017-09-08 20:12:15 +02:00
funkyfranky
5992c852da Improved menu, added enumerators for ROE/ROT, added random takeoff (untested) 2017-09-08 16:27:51 +02:00
Sven Van de Velde
bae0e4c35b Merge pull request #679 from FlightControl-Master/FC-Fix-Overhead
Fixed overhead problems
2017-09-08 14:08:08 +02:00
FlightControl_Master
1fee3eb7a8 Fixed overhead problems 2017-09-08 14:04:33 +02:00
Sven Van de Velde
8b26f7d975 Merge pull request #678 from FlightControl-Master/Fixes-for-AI_A2A_DISPATCHER
Fixes for ai a2a dispatcher
2017-09-08 10:35:57 +02:00
FlightControl_Master
fcce06c3f1 Error handling 2017-09-08 10:30:52 +02:00
FlightControl_Master
f628e720a9 Check if RecceGroup is alive before iterating... 2017-09-08 10:27:31 +02:00
FlightControl_Master
6959f50777 First fixes 2017-09-08 10:19:48 +02:00
funkyfranky
e4e1990657 Added option to respawn after landing.
Changed default to respawn after engine shut-down.
2017-09-08 00:33:31 +02:00
funkyfranky
f79143095e Added min/max fligh level. 2017-09-07 08:02:08 +02:00
funkyfranky
8c97861e8e Merge branch 'master' into funkyfranky 2017-09-06 17:51:08 +02:00
funkyfranky
07878d4b6e Added enumerators (untested version) 2017-09-06 16:59:11 +02:00
funkyfranky
1d1f8d8a01 Enhancement and minor fixes.
Added possibility to create markers from F10 menu.
Minor bug fixes.
Cleaned up messages.
2017-09-06 00:15:55 +02:00
FlightControl_Master
9dc68fb665 Fix problem with CAP #677
A stupid typo was the root cause in DETECTION_BASE. The friendlies
prefixes were overwritten for the sequent squadron.
2017-09-05 21:47:23 +02:00
funkyfranky
c84df9bf5a Added enumerators (untested) 2017-09-05 16:56:06 +02:00
funkyfranky
9fc00dd9c3 Some fixes and improvements.
Added some menu stuff.
Fixed things in journey case.
2017-09-05 00:23:06 +02:00
funkyfranky
b490412f63 F10 menu update (untested) 2017-09-04 16:43:51 +02:00
funkyfranky
27c51f8fe3 First alpha version.
Added commute and continuejourney.
Improved status reports.
Added basic status menu.
Many other fixes.
2017-09-04 00:37:13 +02:00
funkyfranky
84b4651cd9 Merge branch 'master' into funkyfranky 2017-09-03 09:48:16 +02:00
funkyfranky
d5a21ff604 Improved flight plan calculation.
Included phi in flight plan.
Many other fixes and changes.
2017-09-03 09:47:14 +02:00
funkyfranky
758f500857 Merge branch 'master' into funkyfranky 2017-09-03 09:44:54 +02:00
FlightControl_Master
2830bcb867 Respect Gci radius
* Corrected the calculation to the distance to the airbase, when the
intercept calculation is used. Now the intercept point is not anymore
interfering with the gci radius validation and gci radius is now
correctly respected and validated.
2017-09-02 10:24:28 +02:00
FlightControl_Master
e6c765c441 Solve calculation problems with player has disconnected or changed plane
* Player disconnecting will not result in coordinate calculation
problems in AI_A2A_CAP and AI_A2A_GCI while engaged with the player
machine. The engagement will stop.
2017-09-02 09:22:23 +02:00
FlightControl_Master
c2965e0736 Single lase commands 2017-09-01 19:24:50 +02:00
funkyfranky
1f893fe544 Minor changes 2017-09-01 16:56:32 +02:00
FlightControl_Master
e6dd040a43 Fixed problem with EWR not present and CAP not detecting. 2017-09-01 12:59:57 +02:00
FlightControl_Master
0eb0a3a3e7 Detection time 2017-09-01 12:22:31 +02:00
funkyfranky
023a7a17c5 Improvements in following the fligh plan.
Adjusted some speed in route. Still much to do.
2017-09-01 00:14:38 +02:00
FlightControl_Master
62d1da8487 Select the closest airplanes first 2017-08-31 23:55:30 +02:00
funkyfranky
1c6b760b36 Aircraft climb rapidly :( 2017-08-31 21:56:24 +02:00
funkyfranky
e5fdd50cc6 Merge branch 'master' into funkyfranky 2017-08-31 16:40:10 +02:00
funkyfranky
6e27b93e45 Added user functions. 2017-08-31 15:57:25 +02:00
Sven Van de Velde
dfd4e3562b Merge pull request #674 from FlightControl-Master/Fix-EWR
Fix CAP not engaging.
2017-08-31 09:22:14 +02:00
FlightControl_Master
261faebe31 Fixed CAP not enaging problem 2017-08-31 09:19:08 +02:00
FlightControl_Master
199ecb87bc Updates 2017-08-31 08:47:06 +02:00
FlightControl_Master
14c7916c55 Updates 2017-08-31 08:46:59 +02:00
funkyfranky
6ff2dfe444 Improved takeoff types for zones and airports.
Cleand up function position in code.
2017-08-31 01:01:55 +02:00
FlightControl_Master
bfd0c19109 Fixed nil value problem in friendlies search 2017-08-30 20:11:31 +02:00
funkyfranky
b4c27c270a Merge branch 'master' into funkyfranky 2017-08-30 18:29:22 +02:00
funkyfranky
f4e8f15090 Improvements of departure selection (unfinished). 2017-08-30 17:04:54 +02:00
FlightControl_Master
05d9faedee Fixed friendlies nearby calculation
* Added DETECTION_BASE:FilterFriendliesCategory() method, which allows
to filter friendlies based on the category of the units found. This
method was required to be added to avoid counting airborne units as
friendlies in A2G missions.
2017-08-30 09:28:04 +02:00
funkyfranky
8bcb47a8ee Merge branch 'master' into funkyfranky 2017-08-30 08:51:53 +02:00
FlightControl_Master
ea96a5e0a3 Planes remaining at airfield fixed
* AI_A2A_DISPATCHER: Planes remaining on the airfield is now fixed. The
issue was with planes out of fuel doing CAP, which would return to a
different airbase because they were out of control. At the landing,
these weren't despawned.
2017-08-30 07:30:03 +02:00
funkyfranky
9568f7f87f Improvements of air start.
Improved air start parameters.
Added markers.
Other fixes.
2017-08-30 00:41:34 +02:00
Sven Van de Velde
e1a730bbe3 Merge pull request #672 from FlightControl-Master/Deferred-detection-coordinates-and-other-fixes
Deferred detection coordinates and other fixes
2017-08-29 22:42:25 +02:00
FlightControl_Master
d26a938ba4 Fixed detection reports
* Detection reports of DETECTION classes now are returned as a REPORT
object. So they can be streamed with various delimiters \n or , or
other...
* If a coordinate needs to be represented by BR or BRAA, then a "source"
controllable is required, which is usually the player aircraft. If not
given, the coordinate will be returned in MGRS mode!!!
2017-08-29 22:20:38 +02:00
FlightControl_Master
62ab859215 DESIGNATE can now lase for specific codes
* DESIGNATE can now lase targets with specific laser codes upon request
by players. Methods :AddMenuLaserCode() and :RemoveMenuLaserCode()
added, which allow to set or delete specific additional menu options in
the lase menu for players to lase with specific codes. This comes in
handy for the SU-25T and the A-10A and other planes.
2017-08-29 21:48:11 +02:00
funkyfranky
eac89f784d Improvments for air spawn behaviour. 2017-08-29 16:46:56 +02:00
FlightControl_Master
9784b694ba Fixed detection problem with ESCORT 2017-08-29 09:00:43 +02:00
funkyfranky
5a29b272dc First implementation of "air" start.
Added possibility to spawn in zones.
Other improvements and fixes.
2017-08-28 23:51:54 +02:00
funkyfranky
61884c07c7 Restored oritinal Spawn and AI_Balancer.lua files 2017-08-28 15:35:09 +02:00
FlightControl_Master
8bb3d5a760 Fixed CAP not counting correctly
* CAP now counts correctly per squadron. The specified amount of CAP
will work now.
* CAP now schedules at different start times, and have different repeat
times. More random.
2017-08-28 11:33:37 +02:00
funkyfranky
6a2739da5e Fixed Spawn & AI_Balancer mistake. 2017-08-28 00:16:55 +02:00
funkyfranky
9289e0dac1 First version of RAT
Not even alpha status.
2017-08-28 00:05:30 +02:00
FlightControl_Master
5be01775f7 Merge remote-tracking branch 'refs/remotes/origin/master' into Deferred-detection-coordinates-and-other-fixes 2017-08-27 17:54:41 +02:00
Sven Van de Velde
5da44baff2 Merge pull request #668 from FlightControl-Master/Settings-LL
Revised settings system based on feedback from @thebgpikester and @Ramsay58
2017-08-27 17:53:21 +02:00
FlightControl_Master
02ff2e8efa Revised settings system based on feedback from @thebgpikester and @Ramsay58
Now the LL menu is replaced by 2 menus:

- Lon/Lat Degree Min Sec (LL DMS)
- Lon/Lat Degree Dec Min (LL DDM)

LL Accuracy menu options are only available when LL DDM. As agreed, for
DMS there won't be any accuracy. Optimized the menu settings logic.

Default menu setting is BR for A2G and BRAA for A2A.
2017-08-27 17:51:28 +02:00
FlightControl_Master
608293f1cb Updates 2017-08-15 20:39:32 +02:00
FlightControl_Master
9dcda37703 Updates 2017-08-15 20:23:26 +02:00
FlightControl_Master
1cf2383dfd First version 2017-08-15 17:44:09 +02:00
FlightControl_Master
d558c5be21 Updates 2017-08-13 17:04:04 +02:00
FlightControl_Master
4f2afa29fa Fixes with waypoints in NTTR 2.1.1
behaves different than 1.5.7!!!
2017-08-12 17:07:10 +02:00
FlightControl_Master
3742f2937c Fix in scheduler 2017-08-12 16:12:07 +02:00
FlightControl_Master
a9ac185034 Fixes
* Added a maximum markings per designated target group. So not all FACs
are occupied.
* Optimized the designation report. Move the horizontal line.
* Ensured in DESIGNATE that when targets are ordered to be smoke or
designated, that this also will happen. Was issue with the scheduler,
which got garbage collected before actually being executed, resulting in
an obsolete schedule.
* Fixed the tasking, coordinates are now updated when enquiring a task
report.
2017-08-12 08:27:58 +02:00
FlightControl_Master
b1e7951a47 Nearest distance for Designate is 12.000 meters 2017-08-11 16:44:58 +02:00
Sven Van de Velde
0aa92372bf Merge pull request #652 from FlightControl-Master/Designate
Designate
2017-08-11 14:50:02 +02:00
FlightControl_Master
d7a5f469af Optimized the menu when the parameters are changed. 2017-08-11 14:48:49 +02:00
FlightControl_Master
27f77c5df0 Updates 2017-08-11 14:14:35 +02:00
FlightControl_Master
49bf6010f8 Designate optimization 2017-08-11 05:22:46 +02:00
FlightControl_Master
e16e5d9a81 Fixes 2017-08-08 21:37:12 +02:00
FlightControl_Master
3dde62a550 Fixed key problem in TaskFunction() 2017-08-08 18:08:40 +02:00
FlightControl_Master
8a334b6671 Documentation 2017-08-08 16:11:31 +02:00
FlightControl_Master
6dec92168e Documentation 2017-08-08 15:56:17 +02:00
FlightControl_Master
386777930e Updates of tasking 2017-08-08 15:54:44 +02:00
FlightControl_Master
2aecf45316 Many Fixes 2017-08-08 09:42:42 +02:00
FlightControl_Master
63866e4aa9 Updates of tracing 2017-08-06 17:37:36 +02:00
FlightControl_Master
2dcc1aaf0a Report formatting 2017-08-06 12:19:05 +02:00
FlightControl_Master
82c7121125 Fixes for tasking reporting 2017-08-06 11:02:48 +02:00
FlightControl_Master
b2e522aac1 Documentation 2017-08-06 08:14:01 +02:00
FlightControl_Master
5a8d1da54e Documentation 2017-08-06 07:51:53 +02:00
FlightControl_Master
464fb1aeca Documentation 2017-08-06 07:50:37 +02:00
FlightControl_Master
1883e84918 Documentation 2017-08-06 07:45:36 +02:00
FlightControl_Master
d349ed12a9 Engage Range test 2017-08-06 07:40:55 +02:00
FlightControl_Master
094db73176 Documentation 2017-08-06 07:19:01 +02:00
FlightControl_Master
a86a346378 Update the documentation and how default values were set in AI_A2A_DISPATCHER 2017-08-06 07:08:54 +02:00
FlightControl_Master
3d2dbea1d7 Fixing unlimited resources and problems with landing planes. 2017-08-05 18:06:51 +02:00
Sven Van de Velde
d383c42131 Merge pull request #648 from FlightControl-Master/641-gcicap-infinite-resources
Added infinite resources implementation.
2017-08-05 16:29:47 +02:00
FlightControl_Master
cc1b34937c Added infinite resources implementation. 2017-08-05 16:26:32 +02:00
Sven Van de Velde
2ccfe27401 Merge pull request #646 from FlightControl-Master/643-Spawn-Altitude
643 spawn altitude
2017-08-05 15:15:44 +02:00
FlightControl_Master
53845448b0 Documentation 2017-08-05 15:14:11 +02:00
FlightControl_Master
b88c84fc3b Fixed 643 2017-08-05 13:52:59 +02:00
FlightControl_Master
446ecc5b4d Set the new spawn altitude 2017-08-05 13:33:02 +02:00
Frank
a928a1c750 Merge pull request #640 from FlightControl-Master/funkyfranky
Fixes for Group in Zone functions
2017-08-05 12:26:19 +02:00
FlightControl_Master
544b68c51f Update 2017-08-03 12:26:56 +02:00
FlightControl_Master
2815e841e0 Refresh pictures 2017-08-03 12:25:47 +02:00
FlightControl_Master
dbe1d7aaa3 New Refuelling process 2017-08-03 12:21:56 +02:00
funkyfranky
36ea613f68 Merge branch 'master' into funkyfranky 2017-08-02 21:28:46 +02:00
FlightControl_Master
2611ba0fe8 Fix the schedule dispatcher
-- Implemented a working Stop time.
2017-08-02 21:18:16 +02:00
FlightControl_Master
2cf1801f1d Fixed endless loop when out of resources upon receiving a GCI request. 2017-08-02 20:54:26 +02:00
funkyfranky
5233c633a9 Fixes for Group in Zone functions
If a group is not alive, group in zone functions crash. Added checks if group is still alive. If not return before the error occurs.
2017-08-02 17:56:07 +02:00
FlightControl_Master
2501db53b8 Removed traces 2017-08-02 12:46:13 +02:00
FlightControl_Master
4b60f776ce Apply randomization at start for schedules.
Apply randomization at start for schedules.
2017-08-02 12:41:35 +02:00
FlightControl_Master
d8d06a18ce Updates and bug fixes 2017-08-02 09:43:08 +02:00
FlightControl_Master
9054a493f9 Updated defects in dispatcher 2017-08-01 17:35:53 +02:00
FlightControl_Master
9ec29f607f Fixed an issue with the overhead parameter
Now the GCI will spawn the actual overhead needed, independent of the
grouping parameter. For example, when grouping was 1 and overhead 1.5,
only one plane was spawned. Now two planes are spawned of 2 groups of 1
unit.
2017-08-01 07:19:29 +02:00
Sven Van de Velde
616e035e9a Merge pull request #638 from FlightControl-Master/637-Limit-Engage-Distance
637 limit engage distance
2017-07-31 17:06:05 +02:00
FlightControl_Master
411636a7f4 Intercept ready 2017-07-31 17:04:20 +02:00
FlightControl_Master
27b18780f8 Optimizations 2017-07-31 12:35:37 +02:00
FlightControl_Master
85bd3a1c33 First working version 2017-07-31 12:04:27 +02:00
FlightControl_Master
87634969b3 Added default CAP methods
* Added method :SetDefaultCapTimeInterval( CapMinSeconds, CapMaxSeconds
) for AI_A2A_DISPATCHER and AI_A2A_GCICAP.
* Added method :SetDefaultCapLimit( CapLimit ) for AI_A2A_DISPATCHER and
AI_A2A_GCICAP.

Added documentation in chapter 10.7 and chapter 1.8.
Changed Treshold to Threshold
2017-07-30 20:54:24 +02:00
FlightControl_Master
5107366e57 Added fuel treshold and damage treshold as default parameter setting methods
* Added method :SetDefaultFuelTreshold( FuelTreshold )
* Added method :SetDefaultDamageTreshold( DamageTreshold )
2017-07-30 10:39:10 +02:00
FlightControl_Master
82a3dd32c0 Removed trace 2017-07-30 07:37:45 +02:00
FlightControl_Master
fdcad2dd93 Fixed the landing bug
When using A2A GCICAP, the planes would land, but not dissapear.
2017-07-30 07:31:23 +02:00
FlightControl_Master
3ec783b0e4 Fixed issue in 2.1.1, targets not engaged when flying from parking spot. 2017-07-29 19:08:10 +02:00
FlightControl_Master
ea8af14df5 Updates 2017-07-28 22:44:22 +02:00
FlightControl_Master
906c49792e Further documentation on AI_A2A_DISPATCHER with examples 2017-07-27 12:37:46 +02:00
FlightControl_Master
61fe3cf457 Following up on the requirement #636 a new default management system has been built...
A lot of new methods have been added to set the default behaviour for:

*  function AI_A2A_DISPATCHER:SetDefaultTakeoff( Takeoff )
*  function AI_A2A_DISPATCHER:SetDefaultTakeoffFromParkingCold()
*  function AI_A2A_DISPATCHER:SetDefaultTakeoffFromParkingHot()
*  function AI_A2A_DISPATCHER:SetDefaultTakeoffFromRunway()
*  function AI_A2A_DISPATCHER:SetDefaultTakeoffInAir()
*  function AI_A2A_DISPATCHER:SetDefaultLanding( Landing )
*  function AI_A2A_DISPATCHER:SetDefaultLandingAtEngineShutdown()
*  function AI_A2A_DISPATCHER:SetDefaultLandingAtRunway()
*  function AI_A2A_DISPATCHER:SetDefaultLandingNearAirbase()
*  function AI_A2A_DISPATCHER:SetDefaultGrouping( Grouping )
*  function AI_A2A_DISPATCHER:SetDefaultOverhead( Overhead )
2017-07-27 11:56:03 +02:00
FlightControl_Master
600166fd80 Fixed error in Escort, Reports were not shown
-- Fixed reports to be shown in ESCORT class. SETTINGS now also are
working in ESCORT reports. MGRS, LL, BR, metric, imperial are now
supported.
2017-07-27 07:52:38 +02:00
FlightControl_Master
a6830237f4 Fixed bug in MENU_GROUP_COMMAND 2017-07-26 22:17:15 +02:00
FlightControl_Master
dddcb42e32 Documentation 2017-07-26 15:14:44 +02:00
FlightControl_Master
9c9ed494d9 Progress 2017-07-26 15:08:56 +02:00
FlightControl_Master
b004929223 Docs 2017-07-26 13:18:13 +02:00
FlightControl_Master
495786b4eb Heavily improved the documentation of AI_A2A_DISPATCHER 2017-07-26 13:17:55 +02:00
FlightControl_Master
940f872b40 Documentation improvements. 2017-07-26 10:06:42 +02:00
FlightControl_Master
227752399b Updated designation menu settings 2017-07-26 08:15:18 +02:00
Sven Van de Velde
a19b41537e Merge pull request #634 from FlightControl-Master/629-Update-Assigned-Tasks-To-Players
629 update assigned tasks to players
2017-07-25 16:35:20 +02:00
FlightControl_Master
713e741299 Fixed issue with menu system Planned Tasks
There was a problem that when multiiple groups were part of the attack
set, then the menus for planned tasks were not correctly generated.
2017-07-25 16:29:57 +02:00
FlightControl_Master
c3ee9306f3 Progress 2017-07-25 12:54:15 +02:00
FlightControl_Master
3924d2d8fc Fixes 2017-07-25 09:11:57 +02:00
FlightControl_Master
ec6e182db8 Lowered the refresh frequency of the spots 2017-07-25 08:31:03 +02:00
FlightControl_Master
652ed8b178 Fix for #627 2017-07-25 08:20:38 +02:00
FlightControl_Master
a2630670c0 Docs 2017-07-24 17:42:00 +02:00
FlightControl_Master
b386c2b5eb Documentation 2017-07-24 05:59:34 +02:00
FlightControl_Master
fce1007fb9 Main doc 2017-07-24 05:42:50 +02:00
FlightControl_Master
b769ad143d Fixed some glitches in Detection (when set is empty) + documentation 2017-07-22 08:20:23 +02:00
FlightControl_Master
4d33abb0eb Documentation 2017-07-20 13:19:39 +02:00
FlightControl_Master
a61c6b4fe2 Documentation updates 2017-07-19 19:05:59 +02:00
FlightControl_Master
1206935886 Added DESIGNATE:SetMission() method.
-- Allows to place the designate menu under the menu of the mission.
2017-07-19 18:45:48 +02:00
FlightControl_Master
2c16992b5c Changed airbase template search radius 2017-07-19 09:57:03 +02:00
FlightControl_Master
eb73c24367 Added trace 2017-07-19 09:26:18 +02:00
FlightControl_Master
295b482ce6 Updated documentation 2017-07-15 09:07:31 +02:00
FlightControl_Master
b21cd0c0ae AI_A2A_DISPATCHER and AI_A2A_GCICAP optimizations
-- Optimized takeoff height when airplanes spawn in the air.
-- Optimized helicopters to be included in detections.
-- Updated documentation.
2017-07-15 09:07:16 +02:00
FlightControl
beb87f82bf Also adapted Task menus to know the task type. 2017-07-13 22:13:08 +02:00
FlightControl
4252f9baac Fixed problem with crash in Detection.lua.
When DetectionObject is nil (this can be), or is destroyed in between
detections, then nil must be returned and IsDetectedObjectIdentified is
not required to be checked.
2017-07-13 21:41:58 +02:00
FlightControl
6f581cadf1 Fixes issue where A2G cannot be selected for A2G tasks with an airplane.
Added the IsInstanceOf check in COORDINATE:ToString method. If Task is
given, (the Task), then it is checked which parent task it was from. If
A2A, the mode will be A2A, if A2G or CARGO, the mode will be A2G. If
Task was not given, then the unit type will decide upon the A2A or A2G
mode.
2017-07-13 21:35:48 +02:00
FlightControl
f8cca7d510 Added for A2A in SETTINGS LL and MGRS! 2017-07-12 22:34:52 +02:00
FlightControl
c1bee3a9b0 Fixed #614 - Implemented an implementation with or without {}....
See documentation of SetBorderZone.
2017-07-12 20:42:06 +02:00
132nd-etcher
60681d7e23 Merge pull request #622 from FlightControl-Master/620-IsInstance
620: IsInstance

Closes #620
2017-07-12 16:09:15 +02:00
132nd-etcher
9fe51587a1 Add function BASE:IsInstanceOf( className )
This method checks if a Moose object is an instance of a given className.
2017-07-12 14:55:25 +02:00
132nd-etcher
82fd08521f Add UTILS.IsInstanceOf = function( object, className )
This function takes any object and check if it is an instance of className.
The object can be either a MOOSE class or a basic lua type.
2017-07-12 14:55:15 +02:00
132nd-etcher
2f416ea98e Update BASE:GetParent( Child ) so that it returns nil when called on BASE class
We need to know if that the BASE class has no parent.
2017-07-12 14:55:01 +02:00
FlightControl
33916c2631 Merge remote-tracking branch 'refs/remotes/origin/master-release'
# Conflicts:
#	Moose Mission Setup/Moose.lua
#	Release 2.1.md
2017-07-11 16:56:17 +02:00
FlightControl
a0befeb34f Fixed a bug in the removal of GROUP objects in SET_GROUP
Upon a DEAD or CRASH event processing in a SET_GROUP, the GROUP object
would be removed regardless of how many UNITs are still in the GROUP
object.
The fix is that upon a DEAD or CRASH event in a SET_GROUP, it will be
checked if there is only one UNIT left in the GROUP, and only then the
GROUP will be removed from the SET_GROUP.
2017-07-11 16:20:15 +02:00
Rob Graham
0501959ab9 Merge pull request #619 from FlightControl-Master/RobGraham
Added Knots to Kmph
2017-07-11 17:08:00 +10:00
robgrahamau
764beb7c22 Added Knots to Kmph 2017-07-11 16:46:14 +10:00
FlightControl
1d939311c3 Removed trace 2017-07-08 14:17:43 +02:00
FlightControl
47f1b8ae66 Event Handling 2017-07-08 14:10:33 +02:00
FlightControl
cff8522922 Size 2017-07-08 13:04:37 +02:00
FlightControl
d78547aa33 Added picture 2017-07-08 13:02:51 +02:00
FlightControl
ab33d6b272 CLEANUP_AIRBASE documentation 2017-07-08 13:00:18 +02:00
FlightControl
388103afea Fixes
-- when carrier containing cargo goes to spectators, it was not handled
correctly. now it is
-- removed "unassigned" message when task is cancelled from group. It is
useless.
2017-07-08 12:40:56 +02:00
FlightControl
85975c01a4 Optimizations 2017-07-08 09:20:42 +02:00
FlightControl
3fe573926b Fixed scoring format 2017-07-08 06:35:06 +02:00
FlightControl
8e2aef17e7 Fixes to resolve exceptions in multi player situations 2017-07-08 05:54:33 +02:00
FlightControl
367c4d74af Fixes imperial / metric menu option setting 2017-07-08 05:00:47 +02:00
FlightControl
06e063d594 Fixes cargo 2017-07-07 18:45:32 +02:00
FlightControl
7ebf7a2bee Fixed #611 2017-07-07 18:20:58 +02:00
FlightControl
b5c53baf67 Fixed #592 2017-07-07 18:19:37 +02:00
132nd-etcher
536934390c Reduce AI CAP logging noise (#609)
Replace calls to E by calls to F in order to reduce the amount of log spam during an ongoing AI CAP patrol.
2017-07-07 12:07:27 +02:00
FlightControl
1e6035b282 Optimized CARGO
- Smoke position upon arrival at pickup zone
- Solved problem with deploy, deploy function was not called.
- Added Smoke to CARGO
- Moved Smoke to POSITIONABLE
2017-07-07 11:46:08 +02:00
FlightControl
5bbe5fca60 Fix to get correct parent class 2017-07-07 10:41:16 +02:00
Sven Van de Velde
4c5aad51b3 Merge pull request #608 from FlightControl-Master/Performance
Fixed performance issue
2017-07-07 08:23:52 +02:00
FlightControl
688875dca5 Fixed performance issue
Problem was in BASE. I added a field "ParentClass", which was a
mistake...
at every deepcopy it started to copy ParentClass contents too! My god!
No wonder it suddenly went all slow.
2017-07-07 08:23:22 +02:00
Sven Van de Velde
b4c8fbf75a Merge pull request #607 from FlightControl-Master/601-Respawn-Cargo
601 respawn cargo
2017-07-06 21:49:09 +02:00
FlightControl
edb53013b2 Progress 2017-07-06 21:47:02 +02:00
FlightControl
70f48a3d53 Progress 2017-07-06 19:13:15 +02:00
FlightControl
532a311db6 Cargo is now respawning correctly when:
The cargo is destroyed
The carrier crashes with cargo on board
The player exits the carrier with cargo on board.
2017-07-06 17:00:53 +02:00
FlightControl
71da9933d7 Cargo auto respawn first part is working
When all CARGO UNITS of a CARGO_GROUP are destroyed, then when
RespawnOnDestroyed( true ) is used, the CARGO will respawn
automatically.
2017-07-06 11:23:04 +02:00
FlightControl
9f5b9ab04c Progress 2017-07-06 08:51:08 +02:00
Sven Van de Velde
f76ac1e03a Merge pull request #606 from FlightControl-Master/596-CARGO-TRANSPORT-Limits
Implemented Cargo limits
2017-07-06 07:33:15 +02:00
FlightControl
b84541f232 Implemented Cargo limits
Cargo is only allowed to be boarded or a route can only be done if the
limit of the cargo has not been reached! A few additional methods have
been added like IsDeployed. CARGO_GROUP gets the deployed status if it
is transported.
2017-07-06 07:32:44 +02:00
Sven Van de Velde
6115e12309 Merge pull request #604 from FlightControl-Master/603-AI-A2A-GCICAP
Created AI_A2A_GCICAP
2017-07-05 12:54:56 +02:00
FlightControl
c22bc1c57f Created AI_A2A_GCICAP 2017-07-05 10:11:34 +02:00
FlightControl
84055e9798 Updates fixing cargo stuff 2017-07-04 16:34:00 +02:00
FlightControl
ccfcca8f9a Tweaks for the settings system
- Player settings are located at the group level. Only the first player
that joins the group will be able to configure the settings.
- Default system settings are located at the group of the commend
center. Thus, the COMMANDCENTER class will contain the default system
settings menu. You need to join the command center unit (ALT-J) as a
game master to be able to configure these settings.
2017-07-04 10:55:45 +02:00
FlightControl
c043eef5eb Added method CLEANUP:CleanMissilesOn() 2017-07-04 07:05:33 +02:00
FlightControl
2db0265ae6 Fixed first line of task report 2017-07-03 12:11:06 +02:00
FlightControl
3cd787fb1e Fix issue with deployment 2017-07-03 08:46:17 +02:00
FlightControl
8825b26b36 New version 2017-07-02 23:16:35 +02:00
FlightControl
300ee0a16a Fix trace amount and performance 2017-07-02 17:59:56 +02:00
FlightControl
1283caf80b OK. fixed 2017-07-02 12:55:29 +02:00
FlightControl
af230d9874 Fixed goal problem in TASK_CARGO_TRANSPORT more or less, needs further investigation 2017-07-02 12:44:27 +02:00
FlightControl
f221047eba Updated various functions for tasking. 2017-07-02 12:14:41 +02:00
FlightControl
e7b3aa82f9 SWEEP tasks should fall under the SWEEP menu, not INTERCEPT menu 2017-07-02 01:08:00 +02:00
FlightControl
33c6290864 Fixed error with __
Had to test for the presence in raw format, not using __Index
2017-07-02 00:29:17 +02:00
FlightControl
9006e17c25 Fixed problem with BASE:GetParent method 2017-07-01 19:00:44 +02:00
FlightControl
22b02cd3ee Made __ methods invisible 2017-07-01 13:12:52 +02:00
FlightControl
507e4ef25a Made CleanUpScheduler private 2017-07-01 13:02:49 +02:00
FlightControl
8b1583df30 Made Airbases private 2017-07-01 13:00:12 +02:00
FlightControl
083568d3fd Updates 2017-07-01 12:55:51 +02:00
FlightControl
8e5af4ada4 New implementations
of inheritance
of private - public methods ....

This is a big improvement for many!
2017-07-01 12:32:44 +02:00
FlightControl
5d2eb2ea15 Dynamic Moose.lua 2017-06-30 10:36:14 +02:00
FlightControl
76ec5aa009 Documentation 2017-06-30 10:33:21 +02:00
FlightControl
35681c6f96 Resize 2017-06-30 10:31:27 +02:00
FlightControl
d719c437ec Fixes 2017-06-30 10:30:46 +02:00
FlightControl
133910ac3b New revised CLEANUP class 2017-06-30 10:27:44 +02:00
FlightControl
862f2ab3ac new version 2017-06-29 16:58:12 +02:00
FlightControl
2f4361c97a Fixed dispatching S_EVENT_PLAYER_LEAVE_UNIT fired when no player in unit
S_EVENT_PLAYER_LEAVE_UNIT should not be handled when there is no player
in the unit!
but
S_EVENT_MISSION_END should be handled, and also has no initiator!
2017-06-29 14:58:10 +02:00
FlightControl
4b7b042bb1 Removed trace 2017-06-29 13:23:03 +02:00
FlightControl
18a76fa355 Updated trace to minimize trace overhead. 2017-06-29 13:18:01 +02:00
FlightControl
bccc4abf26 Fixes bug that would loop over every unit in the group.
Only the players in a group should be unassigned, not all units.
2017-06-29 10:17:55 +02:00
FlightControl
a021967295 Trying stuff out... Nothing more. 2017-06-29 04:52:45 +02:00
FlightControl
975566eb3c Fixed message bug in scoring 2017-06-26 20:51:01 +02:00
FlightControl
55164c38bf Finetuning of the messages and menus 2017-06-26 20:33:26 +02:00
FlightControl
1aeb7b3ff6 Fixed issue #566 and #567 2017-06-26 19:37:31 +02:00
Sven Van de Velde
fa77ba3f48 Merge pull request #588 from FlightControl-Master/585-TASK-A2A-DISPATCHER
585 task a2a dispatcher
2017-06-25 07:41:07 +02:00
FlightControl
1aecd47d5a Show all tasks in Mission Task Progress report 2017-06-25 07:39:36 +02:00
FlightControl
6b920ea3f4 Mission Progress Report added
This reports lists for the tasks in the mission which players have made
progress for that task.
2017-06-25 07:28:55 +02:00
FlightControl
6a2869138e Merge remote-tracking branch 'refs/remotes/origin/master' into 585-TASK-A2A-DISPATCHER 2017-06-25 06:07:32 +02:00
FlightControl
1b36cee3b6 Documentation 2017-06-24 16:21:43 +02:00
Sven Van de Velde
70f2c0051a Merge pull request #587 from FlightControl-Master/585-TASK-A2A-DISPATCHER
585 task a2a dispatcher
2017-06-24 15:24:05 +02:00
FlightControl
d396ca1684 Target progress accounting for players 2017-06-24 15:21:59 +02:00
FlightControl
aed71ca9e2 Task Progress Accounting
Record achievement history for players executing a task. Only show
progress when there is progress to report. Only score progress when
there is progress for a player, not for other groups.
2017-06-24 15:05:33 +02:00
FlightControl
50094fde6c Additional scores definitions 2017-06-24 11:35:20 +02:00
FlightControl
d5b66fd08c Merge remote-tracking branch 'refs/remotes/origin/master' into 585-TASK-A2A-DISPATCHER 2017-06-24 10:29:29 +02:00
Sven Van de Velde
34d2b12acc Merge pull request #586 from FlightControl-Master/585-TASK-A2A-DISPATCHER
Improved Task Goal monitoring
2017-06-23 21:55:53 +02:00
FlightControl
f0c20be967 Improved Task Goal monitoring 2017-06-23 21:54:59 +02:00
FlightControl
6126ec9450 Fixes bug in SET_GROUP
Was unable to filter on category "ground". Fixed now.
2017-06-23 08:14:02 +02:00
FlightControl
df7c45d7ef Documentation 2017-06-23 07:51:43 +02:00
FlightControl
f52d8a3ad4 Resize pictures 2017-06-23 07:42:31 +02:00
FlightControl
ab27a1bd2b Documentation 2017-06-23 07:40:38 +02:00
FlightControl
e341287c56 Documentation 2017-06-23 07:38:36 +02:00
FlightControl
ca5247ce1b TASK_A2A_DISPATCHER 2017-06-23 07:36:35 +02:00
FlightControl
81a8056233 Fix problems with pictures 2017-06-23 07:28:49 +02:00
Sven Van de Velde
a92174f32e Merge pull request #584 from FlightControl-Master/562-AI-A2A-Dispatcher
562 ai a2a dispatcher
2017-06-22 22:17:00 +02:00
FlightControl
79ec86f369 TASK_A2A_DISPATCHER documentation 2017-06-22 22:15:17 +02:00
FlightControl
a31abef3cf TASK_A2A_DISPATCHER documentation 2017-06-22 22:13:31 +02:00
Sven Van de Velde
f89964d8ba Merge pull request #583 from FlightControl-Master/562-AI-A2A-Dispatcher
562 ai a2a dispatcher
2017-06-22 10:13:34 +02:00
FlightControl
706a0949ee Docu 2017-06-22 09:58:46 +02:00
FlightControl
bdfd169d39 Added GCI engage range. 2017-06-22 09:58:05 +02:00
FlightControl
44f60169cb Merge remote-tracking branch 'refs/remotes/origin/master' into 562-AI-A2A-Dispatcher 2017-06-22 06:30:55 +02:00
FlightControl
caad080c6c Fixed but with distance when player was nearby.
Detection used PlayerUnitName, instead of Distance. Added new
FriendliesDistance field.
This is a better solution.
2017-06-22 06:30:36 +02:00
Sven Van de Velde
c4a2c9edc9 Merge pull request #582 from FlightControl-Master/562-AI-A2A-Dispatcher
562 ai a2a dispatcher
2017-06-21 11:49:40 +02:00
FlightControl
ee30fa6ac2 Merge remote-tracking branch 'refs/remotes/origin/master' into 562-AI-A2A-Dispatcher 2017-06-21 11:48:24 +02:00
FlightControl
d23cf6028b Updates 2017-06-21 11:48:19 +02:00
FlightControl
6a58290833 Updates 2017-06-21 10:55:35 +02:00
Sven Van de Velde
3b9fdbd5cd Merge pull request #580 from FlightControl-Master/FilterPrefixFix
Fix for '-' characters in the prefix string when using FilterPrefix o…
2017-06-21 06:22:42 +02:00
Sven Van de Velde
d88c3106d0 Merge pull request #581 from FlightControl-Master/562-AI-A2A-Dispatcher
562 ai a2a dispatcher
2017-06-21 06:22:16 +02:00
FlightControl
34bf013b9b TASK_A2A 2017-06-21 06:17:07 +02:00
FlightControl
2e8efe8f4a Merge remote-tracking branch 'refs/remotes/origin/master' into 562-AI-A2A-Dispatcher 2017-06-21 06:00:59 +02:00
FlightControl
54c8a6f9dd Updates 2017-06-21 06:00:24 +02:00
Fridge
18ddbdac84 Fix for '-' characters in the prefix string when using FilterPrefix on groups with '-' in the name
This should replace '-' characters in the search pattern with %- (the escaped version). Thedouble %% is necessary to get the escape sequence through.
2017-06-20 20:51:08 -03:00
Sven Van de Velde
7c4ee9bebd Merge pull request #579 from FlightControl-Master/562-AI-A2A-Dispatcher
562 ai a2a dispatcher
2017-06-20 12:15:00 +02:00
FlightControl
ce397d0a4e Merge remote-tracking branch 'refs/remotes/origin/master' into 562-AI-A2A-Dispatcher 2017-06-20 12:13:39 +02:00
FlightControl
06c8c00dc9 Airbases of Nevada and Normandy 2017-06-20 12:12:52 +02:00
FlightControl
220e5b17aa Merge remote-tracking branch 'refs/remotes/origin/master-release-2.1' into master-release 2017-06-19 20:11:18 +02:00
FlightControl
ef217c0b19 Fix for CTD in DCS 2.1.
Destroyed scenery object cannot be inspected with all the methods.
SceneryObject:getTypeName() goes into CTD with the scenery has been
destroyed.
The problem was in the event handler (Event.lua).
This is fixed by checking if the SceneryObject exists before getting the
type name.
If it does not exist, the type name is filled with "SCENERY".
2017-06-18 09:00:48 +02:00
FlightControl
c72e6ff9b4 Fixed DCS CTD in 2.1 for destroyed scenery objects.
The problem was in the event handler.
getTypeName() for a destroyed scenery object brings DCS into CTD.
2017-06-18 08:31:27 +02:00
FlightControl
305584344e Updated gitignore 2017-06-15 19:52:31 +02:00
FlightControl
a42b5fcea7 Fixes 2017-06-15 19:46:46 +02:00
FlightControl
18591c434f Documentation 2017-06-15 07:02:20 +02:00
FlightControl
439ebf1676 Documentation 2017-06-14 15:17:41 +02:00
FlightControl
05d69457f2 Documentation 2017-06-14 15:08:49 +02:00
FlightControl
a646dd900d Altitude was wrongly set in patrol 2017-06-14 14:34:55 +02:00
FlightControl
fb54b2f280 Trace 2017-06-14 11:50:35 +02:00
FlightControl
2f8b881186 Documentation 2017-06-14 11:17:20 +02:00
FlightControl
385dba63d9 Documentation 2017-06-14 11:13:14 +02:00
Sven Van de Velde
95ce44f2d8 Merge pull request #577 from FlightControl-Master/562-AI-A2A-Dispatcher
562 ai a2a dispatcher
2017-06-14 11:09:25 +02:00
FlightControl
915c65176e Documentation 2017-06-14 11:06:44 +02:00
FlightControl
4f472253de Documentation 2017-06-14 11:02:43 +02:00
FlightControl
c53f8a7033 Documentation 2017-06-14 10:25:19 +02:00
FlightControl
15cf215d49 Documentation 2017-06-14 10:24:59 +02:00
FlightControl
208f214e96 Merge remote-tracking branch 'refs/remotes/origin/master' into 562-AI-A2A-Dispatcher 2017-06-14 10:13:06 +02:00
Sven Van de Velde
e7f83669c4 Merge pull request #576 from FlightControl-Master/562-AI-A2A-Dispatcher
562 ai a2a dispatcher
2017-06-13 13:42:28 +02:00
FlightControl
2b6fecbe4d Documentation 2017-06-13 13:38:52 +02:00
Sven Van de Velde
3e5542e592 Merge pull request #575 from FlightControl-Master/562-AI-A2A-Dispatcher
562 ai a2a dispatcher
2017-06-13 13:35:44 +02:00
FlightControl
1369a28aca Updates 2017-06-13 13:34:49 +02:00
Sven Van de Velde
00933b2905 Merge pull request #574 from FlightControl-Master/562-AI-A2A-Dispatcher
Updates
2017-06-13 13:30:41 +02:00
FlightControl
dd39ff4e94 Updates 2017-06-13 13:29:48 +02:00
Sven Van de Velde
922b61b9fe Merge pull request #573 from FlightControl-Master/562-AI-A2A-Dispatcher
562 ai a2a dispatcher
2017-06-13 13:18:30 +02:00
FlightControl
5a7551d312 Progress 2017-06-13 13:17:17 +02:00
FlightControl
94c208cbc9 Progress 2017-06-13 07:00:44 +02:00
FlightControl
1ea916ec73 Progress 2017-06-12 16:25:05 +02:00
FlightControl
f56b2229a7 Progress 2017-06-12 06:44:01 +02:00
FlightControl
4f91ba6081 Progress 2017-06-10 10:59:41 +02:00
FlightControl
9f22e2cc71 Progress 2017-06-09 20:35:46 +02:00
FlightControl
e17de754a3 Progress 2017-06-08 15:44:35 +02:00
FlightControl
18885f0450 Merge remote-tracking branch 'refs/remotes/origin/master' into 562-AI-A2A-Dispatcher 2017-06-08 11:53:56 +02:00
FlightControl
0f9f615313 Progress 2017-06-08 11:53:53 +02:00
FlightControl
d84f3fcd24 Undo bugfix, the thing worked perfectly :-( 2017-06-08 08:46:03 +02:00
FlightControl
fa6d53634b Bugfix in SpawnInZone where SpawnIndex was not incremented correctly. 2017-06-08 00:49:52 +02:00
FlightControl
ce24d2b4a6 Progress 2017-06-08 00:47:56 +02:00
FlightControl
f151e1e5f4 Progress 2017-06-08 00:35:18 +02:00
FlightControl
59ab62685c Progress 2017-06-08 00:20:53 +02:00
FlightControl
e68b715321 Documentation 2017-06-07 15:18:22 +02:00
FlightControl
ef95cfb1f5 Progress 2017-06-07 12:56:43 +02:00
FlightControl
d120875fa9 Merge remote-tracking branch 'refs/remotes/origin/master' into 562-AI-A2A-Dispatcher 2017-06-07 09:06:53 +02:00
FlightControl
9dfff9ae5e Added TaskRouteToVec2 method 2017-06-06 22:11:25 +02:00
FlightControl
86d8eb023d Progress 2017-06-06 21:46:51 +02:00
FlightControl
b48c467d57 Progress 2017-06-06 21:36:32 +02:00
FlightControl
cf4c269f77 Progress 2017-06-06 18:33:24 +02:00
FlightControl
2fb83c89af Progress 2017-06-06 14:43:40 +02:00
FlightControl
37a176e3ae Progress 2017-06-03 10:28:50 +02:00
FlightControl
09776a60c9 ooofff! waypoint functions and route setting is now working how i wanted it to work 2017-06-02 11:21:53 +02:00
FlightControl
17838d7099 Progress 2017-06-01 13:18:50 +02:00
FlightControl
531f8a9106 Progress 2017-05-31 22:41:29 +02:00
FlightControl
a3289205e6 Progress 2017-05-31 18:58:34 +02:00
FlightControl
0af5e1428b Progress 2017-05-30 19:38:56 +02:00
FlightControl
7ec9a93231 Resize the images 2017-05-29 18:07:45 +02:00
FlightControl
9984055f7d Documentation 2017-05-29 18:02:57 +02:00
FlightControl
4e29565382 Documentation 2017-05-29 14:09:07 +02:00
FlightControl
bc734f1190 Removed disturbing reports when joining a client slot (forgot to delete). 2017-05-29 10:32:54 +02:00
Sven Van de Velde
7d8add6d4c Merge pull request #561 from FlightControl-Master/553-player-reports
553 player reports
2017-05-29 07:13:33 +02:00
FlightControl
ec8a399ca6 Players per Task report added 2017-05-29 07:12:42 +02:00
FlightControl
1935bd235e Merge remote-tracking branch 'refs/remotes/origin/master' into 553-player-reports 2017-05-29 07:02:40 +02:00
Sven Van de Velde
c6631356ea Merge pull request #560 from FlightControl-Master/419-A2A-Tasking
A2A SWEEP Tasking
2017-05-29 05:30:33 +02:00
FlightControl
f2e966735c A2A SWEEP Tasking 2017-05-29 05:29:41 +02:00
Delta-99
35c2cb45bb Merge pull request #558 from FlightControl-Master/OnSpawnGroup-fix-delay
OnSpawnGroup happening before BIRTH sometimes
2017-05-28 13:33:02 -04:00
Delta-99
33fcb86383 Merge pull request #559 from FlightControl-Master/555-EnrouteTaskEngage-fix
EnRouteTaskEngageTargets defined twice
2017-05-28 13:32:51 -04:00
Delta-99
8096c170d5 EnRouteTaskEngageTargets defined twice
EnRouteTaskEngageTargets was defined twice. The 2nd instance looks like
it should have been named EnRouteTaskEngageTargetsInZone. Fixed and
added documentation at the top.
2017-05-28 13:09:50 -04:00
Delta-99
333eba2cb8 OnSpawnGroup happening before BIRTH sometimes
Add a little bit of a delay in calling the OnSpawnGroup function as it
sometimes happens before the actual BIRTH event of the group.
2017-05-28 12:51:50 -04:00
Sven Van de Velde
3cb6bd3a99 Merge pull request #557 from FlightControl-Master/419-A2A-Tasking
419 a2a tasking
2017-05-28 18:25:44 +02:00
FlightControl
f8ab65ce0e Reference points implemented 2017-05-28 18:24:44 +02:00
FlightControl
707a5a778a Merge remote-tracking branch 'refs/remotes/origin/master' into 419-A2A-Tasking 2017-05-28 09:13:03 +02:00
FlightControl
6f183bad74 Update 2017-05-28 09:13:00 +02:00
Sven Van de Velde
28a38d04fd Merge pull request #554 from FlightControl-Master/553-player-reports
Player reports
2017-05-27 10:11:17 +02:00
FlightControl
051cc4955f CARGO 2017-05-27 10:09:44 +02:00
FlightControl
e06b2c5e4f Documentation 2017-05-27 10:04:43 +02:00
FlightControl
8157d7a8d0 Player reports 2017-05-27 09:57:38 +02:00
Sven Van de Velde
a522568a60 Merge pull request #552 from FlightControl-Master/419-A2A-Tasking
Mission goals
2017-05-26 09:44:16 +02:00
FlightControl
b6ecd52444 Mission goals 2017-05-26 09:43:49 +02:00
Sven Van de Velde
3105ef7cb6 Merge pull request #551 from FlightControl-Master/419-A2A-Tasking
419 a2a tasking
2017-05-26 08:44:23 +02:00
FlightControl
356f4a041f Cleaned up the reporting side of A2G tasking 2017-05-26 08:43:30 +02:00
FlightControl
6d43ab371e Merge remote-tracking branch 'refs/remotes/origin/master' into 419-A2A-Tasking 2017-05-26 08:37:04 +02:00
FlightControl
a1a8f90cc5 Removed some old code 2017-05-26 08:35:49 +02:00
FlightControl
c10b4fb129 Fix problem with an end statement that is too much in Task_CARGO.lua 2017-05-26 07:53:40 +02:00
Wingthor
e025b6b407 Merge pull request #537 from FlightControl-Master/baluballa
Added posibilty to SetSmokeColor on Cargo
2017-05-25 11:14:22 +02:00
Wingthor
10f12e4ead Changed algo for starting smoke process 2017-05-25 10:28:04 +02:00
Wingthor
3c71af48ee Added A space to test syncing 2017-05-25 10:02:53 +02:00
Sven Van de Velde
daa68cb110 Merge pull request #542 from FlightControl-Master/541-fix-radio-loop
set default value for Loop
2017-05-25 08:52:53 +02:00
Sven Van de Velde
10b49b4a15 Merge pull request #547 from FlightControl-Master/546-Fix-Coordinates
Fixed error as reported in #546
2017-05-25 07:56:21 +02:00
FlightControl
bcae1bbd89 Fixed some stuff 2017-05-25 07:44:27 +02:00
FlightControl
624a4aa70a Planned task removal for A2G areas that have no targets anymore. 2017-05-24 12:58:14 +02:00
FlightControl
0702057f47 Only remove planned tasks 2017-05-24 12:07:49 +02:00
FlightControl
89371378b7 Fixed non removal of Planned Tasks 2017-05-24 11:49:03 +02:00
FlightControl
f3b49ecc0a Fixed the removal of obscolete planned tasks 2017-05-24 07:14:40 +02:00
FlightControl
fb1e9972a5 Documentation 2017-05-23 22:20:29 +02:00
FlightControl
f6a26e3723 trace 2017-05-23 22:17:38 +02:00
Sven Van de Velde
26027245f0 Merge pull request #545 from FlightControl-Master/419-A2A-Tasking
419 a2a tasking
2017-05-23 20:04:05 +02:00
FlightControl
a66529d482 ENGAGE task is working now
-- Also the switching between INTERCEPT and ENGAGE (players move in and
out of proximity), is working now !!!
2017-05-23 20:02:58 +02:00
FlightControl
bbb086ae6b Merge remote-tracking branch 'refs/remotes/origin/master' into 419-A2A-Tasking 2017-05-23 14:01:50 +02:00
Sven Van de Velde
4ed387cc6b Merge pull request #544 from FlightControl-Master/419-A2A-Tasking
ENGAGE A2A Task Type
2017-05-23 13:53:34 +02:00
FlightControl
b88c6b5f6c Merge remote-tracking branch 'refs/remotes/origin/master' into 419-A2A-Tasking 2017-05-23 13:52:40 +02:00
FlightControl
30ae32e539 Got ENGAGE A2A task type working. 2017-05-23 13:51:47 +02:00
Sven Van de Velde
e42ea47ea8 Merge pull request #543 from FlightControl-Master/419-A2A-Tasking
419 a2a tasking
2017-05-23 11:51:18 +02:00
FlightControl
96f7a79f3a Working INTERCEPT! 2017-05-23 11:50:28 +02:00
Wingthor
6378cbc0ee Changed the structure
Change the structure, took away the nil value error when calling the
setter. How ever color is not set proper, or turns out false
2017-05-23 01:24:39 +02:00
Delta-99
f3a5b735d6 set default value for Loop
Set the default value for loop. If not set Broadcast generates an error.
2017-05-22 15:38:24 -04:00
Wingthor
473735dcd7 Changed the code to support Moose Color Enumeration 2017-05-22 14:37:21 +02:00
FlightControl
220edef653 Merge remote-tracking branch 'refs/remotes/origin/master' into 419-A2A-Tasking 2017-05-22 12:22:34 +02:00
Sven Van de Velde
2619fe814a Merge pull request #540 from FlightControl-Master/419-A2A-Tasking
419 a2a tasking
2017-05-22 12:18:22 +02:00
FlightControl
599f31dfae Final tests done, publishing 2017-05-22 12:17:18 +02:00
FlightControl
8ab12e5e9a Progress 2017-05-22 10:59:19 +02:00
FlightControl
314032ba3d Progress 2017-05-22 09:54:07 +02:00
FlightControl
961658ee9a Small Fix 2017-05-20 22:07:36 +02:00
FlightControl
2b0fcd3426 Progress 2017-05-20 22:04:44 +02:00
Wingthor
824431ae94 Found a few error in my code, still does not work 2017-05-20 17:09:14 +02:00
FlightControl
923ea597ec Updates 2017-05-20 16:41:45 +02:00
Wingthor
9112d6cc6e Added posibilty to SetSmokeColor on Cargo
Someting is wrong with the setter, when calling it, it seems to be nil.
Need som advice
2017-05-20 16:36:12 +02:00
FlightControl
ece08e5e37 Got something working with these coordinates 2017-05-20 16:32:56 +02:00
FlightControl
96fdf72400 Progress implementing teh SETTINGS class and coordinates per Controllable of the player 2017-05-20 13:32:21 +02:00
FlightControl
5fd4f96fc8 Merge remote-tracking branch 'refs/remotes/origin/master' into 419-A2A-Tasking 2017-05-20 10:38:29 +02:00
FlightControl
13449cc9ee Progress designing system settings 2017-05-20 08:48:57 +02:00
Sven Van de Velde
eab81a2bf9 Merge pull request #534 from FlightControl-Master/419-A2A-Tasking
419 a2a tasking
2017-05-18 21:19:48 +02:00
FlightControl
264cf69a6f A2A_Dispatcher is ready, i think 2017-05-18 21:18:40 +02:00
FlightControl
0e9caf2d3f Merge remote-tracking branch 'refs/remotes/origin/master-release-prep' 2017-05-18 21:09:44 +02:00
FlightControl
45429c8f2a Dynamic 2017-05-18 21:08:53 +02:00
FlightControl
312007b51c Progress 2017-05-18 20:53:15 +02:00
FlightControl
3106f62709 Progress 2017-05-18 16:26:31 +02:00
FlightControl
48595e1282 Merge remote-tracking branch 'refs/remotes/origin/master' into 419-A2A-Tasking
# Conflicts:
#	Moose Mission Setup/Moose.lua
2017-05-18 14:20:23 +02:00
FlightControl
ee20d91a5e Merge remote-tracking branch 'refs/remotes/origin/master-release-prep' 2017-05-18 14:17:07 +02:00
FlightControl
9abc4f9725 INTERCEPT logic working 2017-05-18 13:26:25 +02:00
FlightControl
cc064c95b1 Merge remote-tracking branch 'refs/remotes/origin/master' into 419-A2A-Tasking
# Conflicts:
#	Moose Mission Setup/Moose.lua
2017-05-18 12:22:09 +02:00
FlightControl
1f2e3d6514 Removed moose.lua 2017-05-18 10:07:28 +02:00
FlightControl
71566e3a53 Merge remote-tracking branch 'refs/remotes/origin/master-release-prep' 2017-05-18 10:04:34 +02:00
FlightControl
4b62fbd497 First A2A class 2017-05-17 19:12:39 +02:00
FlightControl
b96628eba8 Release notes 2017-05-17 10:27:38 +02:00
822 changed files with 53507 additions and 291672 deletions

85
.appveyor/appveyor.yml Normal file
View File

@@ -0,0 +1,85 @@
version: 3.9.1.{build}
shallow_clone: true
skip_branch_with_pr: false
skip_commits:
message: /!nobuild/
skip_tags: false
environment:
access_token_documentation:
secure: JVBVVL8uJUcLXN+48eRdELEeCGOGCCaMzCqutsUqNuaZ/KblG5ZTt7+LV4UKv/0f
LUAROCKS_VER: 2.4.1
LUA_VER: 5.1.5
LUA: lua5.3
matrix:
- LUA_VER: 5.1.5
platform:
- x64
init:
- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
throw "There are newer queued builds for this pull request, failing early." }
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
install:
# Outcomment if lua environment invalidates and needs to be reinstalled, otherwise all will run from the cache.
# - call choco install 7zip.commandline
# - call choco install lua51
# - call choco install luarocks
# - call refreshenv
# - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
# - cmd: PATH = %PATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\bin
# - cmd: set LUA_PATH = %LUA_PATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\share\lua\5.1\?.lua;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\share\lua\5.1\?\init.lua
# - cmd: set LUA_CPATH = %LUA_CPATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\lib\lua\5.1\?.dll
# - call luarocks install luasrcdiet
# - call luarocks install checks
# - call luarocks install luadocumentor
# - call luarocks install luacheck
#cache:
# - C:\ProgramData\chocolatey\lib
# - C:\ProgramData\chocolatey\bin
build_script:
- ps: |
if( $env:appveyor_repo_branch -eq 'master' -or $env:appveyor_repo_branch -eq 'develop' )
{
$apiUrl = 'https://ci.appveyor.com/api'
$token = 'qts80b5kpq0ooj4x6vvw'
$headers = @{
"Authorization" = "Bearer $token"
"Content-type" = "application/json"
}
$RequestBody = @{ accountName = 'FlightControl-Master'; projectSlug = 'moose-include'; branch = "$env:appveyor_repo_branch"; environmentVariables = @{} } | ConvertTo-Json
# Generate the new version ...
$project = Invoke-RestMethod -method Post -Uri "$apiUrl/builds" -Headers $headers -Body $RequestBody
}
- ps: |
if( $env:appveyor_repo_branch -eq 'master' )
{
$apiUrl = 'https://ci.appveyor.com/api'
$token = 'qts80b5kpq0ooj4x6vvw'
$headers = @{
"Authorization" = "Bearer $token"
"Content-type" = "application/json"
}
$RequestBody = @{ accountName = 'FlightControl-Master'; projectSlug = 'moose-docs'; branch = 'master'; environmentVariables = @{} } | ConvertTo-Json
# get project with last build details
$project = Invoke-RestMethod -method Post -Uri "$apiUrl/builds" -Headers $headers -Body $RequestBody
}
test: off
# test_script:
# - cmd: luacheck "Moose Development\Moose\moose.lua" "Moose Mission Setup\moose.lua"
on_finish:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))

4
.gitmodules vendored
View File

@@ -1,4 +0,0 @@
[submodule "Moose Development/Moose/Dcs"]
path = Moose Development/Moose/Dcs
url = https://github.com/FlightControl-Master/DCS-API.git
branch = master

View File

@@ -0,0 +1,37 @@
--Initialization script for the Mission lua Environment (SSE)
dofile('Scripts/ScriptingSystem.lua')
-- Add LuaSocket to the LUAPATH, so that it can be found.
package.path = package.path..";.\\LuaSocket\\?.lua;"
-- Connect to the debugger, first require it.
local initconnection = require("debugger")
-- Now make the connection..
-- "127.0.0.1" is the localhost.
-- 10000 is the port. If you wanna use another port in LDT, change this number too!
-- "dcsserver" is the name of the server. If you wanna use another name, change the name here too!
-- nil (is for transport protocol, but not using this)
-- "win" don't touch. But is important to indicate that we are in a windows environment to the debugger script.
initconnection( "127.0.0.1", 10000, "dcsserver", nil, "win", "" )
--Sanitize Mission Scripting environment
--This makes unavailable some unsecure functions.
--Mission downloaded from server to client may contain potentialy harmful lua code that may use these functions.
--You can remove the code below and make availble these functions at your own risk.
local function sanitizeModule(name)
_G[name] = nil
package.loaded[name] = nil
end
do
sanitizeModule('os')
--sanitizeModule('io')
sanitizeModule('lfs')
require = nil
loadlib = nil
end

View File

@@ -0,0 +1,56 @@
-- If you want to use the debugger, add 3 lines of extra code into MissionScripting.lua of DCS world.
-- De-sanitize the io module. The debugger needs it.
---------------------------------------------------------------------------------------------------------------------------
-- MissionScripting.lua modifications
---------------------------------------------------------------------------------------------------------------------------
-- --Initialization script for the Mission lua Environment (SSE)
--
-- dofile('Scripts/ScriptingSystem.lua')
--
-- package.path = package.path..";.\\LuaSocket\\?.lua;"
-- local initconnection = require("debugger")
-- initconnection( "127.0.0.1", 10000, "dcsserver", nil, "win", "" )
--
-- --Sanitize Mission Scripting environment
-- --This makes unavailable some unsecure functions.
-- --Mission downloaded from server to client may contain potentialy harmful lua code that may use these functions.
-- --You can remove the code below and make availble these functions at your own risk.
--
-- local function sanitizeModule(name)
-- _G[name] = nil
-- package.loaded[name] = nil
-- end
--
-- do
-- sanitizeModule('os')
-- --sanitizeModule('io')
-- sanitizeModule('lfs')
-- require = nil
-- loadlib = nil
-- end
---------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------
-- So for clarity, these are the three lines of code that matter!
-- Add LuaSocket to the LUAPATH, so that it can be found.
package.path = package.path..";.\\LuaSocket\\?.lua;"
-- Connect to the debugger, first require it.
local initconnection = require("debugger")
-- Now make the connection..
-- "127.0.0.1" is the localhost.
-- 10000 is the port. If you wanna use another port in LDT, change this number too!
-- "dcsserver" is the name of the server. Ensure the same name is used at the Debug Configuration panel!
-- nil (is for transport protocol, but not using this)
-- "win" don't touch. But is important to indicate that we are in a windows environment to the debugger script.
initconnection( "127.0.0.1", 10000, "dcsserver", nil, "win", "" )

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
</listAttribute>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/Utils/GenerateDocumentations.bat}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Framework/Utils}"/>
</launchConfiguration>

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
</listAttribute>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/Utils/luarocks/lua5.1.exe}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="&quot;Moose_Create.lua&quot; &#13;&#10;&quot;D&quot;&#13;&#10;&quot;${current_date}&quot; &#13;&#10;&quot;${workspace_loc:/Moose_Framework//Moose Development/Moose}&quot; &#13;&#10;&quot;${workspace_loc:/Moose_Framework/Moose Mission Setup}&quot;"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Framework/Moose Mission Setup}"/>
</launchConfiguration>

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
</listAttribute>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/Utils/luarocks/lua5.1.exe}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="&quot;Moose_Create.lua&quot; &#13;&#10;&quot;S&quot;&#13;&#10;&quot;${current_date}&quot; &#13;&#10;&quot;${workspace_loc:/Moose_Framework//Moose Development/Moose}&quot; &#13;&#10;&quot;${workspace_loc:/Moose_Framework/Moose Mission Setup}&quot;"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Framework/Moose Mission Setup}"/>
</launchConfiguration>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
</listAttribute>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/Moose Mission Setup/Moose Mission Update/Moose_Update_Missions.bat}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Missions}"/>
</launchConfiguration>

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
</listAttribute>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/Moose Mission Setup/Moose Mission Update/Moose_Update_Missions.bat}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="&quot;${selected_resource_loc}&quot;"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Framework/Moose Mission Setup/Moose Mission Update}"/>
</launchConfiguration>

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,737 @@
--- **AI** -- (R2.2) - Models the process of air operations for airplanes.
--
-- This is a class used in the @{AI_A2A_Dispatcher}.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI_A2A
--BASE:TraceClass("AI_A2A")
--- @type AI_A2A
-- @extends Core.Fsm#FSM_CONTROLLABLE
--- # AI_A2A class, extends @{Fsm#FSM_CONTROLLABLE}
--
-- The AI_A2A class implements the core functions to operate an AI @{Group} A2A tasking.
--
--
-- ## AI_A2A constructor
--
-- * @{#AI_A2A.New}(): Creates a new AI_A2A object.
--
-- ## 2. AI_A2A is a FSM
--
-- ![Process](..\Presentations\AI_PATROL\Dia2.JPG)
--
-- ### 2.1. AI_A2A States
--
-- * **None** ( Group ): The process is not started yet.
-- * **Patrolling** ( Group ): The AI is patrolling the Patrol Zone.
-- * **Returning** ( Group ): The AI is returning to Base.
-- * **Stopped** ( Group ): The process is stopped.
-- * **Crashed** ( Group ): The AI has crashed or is dead.
--
-- ### 2.2. AI_A2A Events
--
-- * **Start** ( Group ): Start the process.
-- * **Stop** ( Group ): Stop the process.
-- * **Route** ( Group ): Route the AI to a new random 3D point within the Patrol Zone.
-- * **RTB** ( Group ): Route the AI to the home base.
-- * **Detect** ( Group ): The AI is detecting 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.
--
-- ## 3. Set or Get the AI controllable
--
-- * @{#AI_A2A.SetControllable}(): Set the AIControllable.
-- * @{#AI_A2A.GetControllable}(): Get the AIControllable.
--
-- @field #AI_A2A
AI_A2A = {
ClassName = "AI_A2A",
}
--- Creates a new AI_A2A object
-- @param #AI_A2A self
-- @param Wrapper.Group#GROUP AIGroup The GROUP object to receive the A2A Process.
-- @return #AI_A2A
function AI_A2A:New( AIGroup )
-- Inherits from BASE
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_A2A
self:SetControllable( AIGroup )
self:SetFuelThreshold( .2, 60 )
self:SetDamageThreshold( 0.4 )
self:SetDisengageRadius( 70000 )
self:SetStartState( "Stopped" )
self:AddTransition( "*", "Start", "Started" )
--- Start Handler OnBefore for AI_A2A
-- @function [parent=#AI_A2A] OnBeforeStart
-- @param #AI_A2A self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Start Handler OnAfter for AI_A2A
-- @function [parent=#AI_A2A] OnAfterStart
-- @param #AI_A2A self
-- @param #string From
-- @param #string Event
-- @param #string To
--- Start Trigger for AI_A2A
-- @function [parent=#AI_A2A] Start
-- @param #AI_A2A self
--- Start Asynchronous Trigger for AI_A2A
-- @function [parent=#AI_A2A] __Start
-- @param #AI_A2A self
-- @param #number Delay
self:AddTransition( "*", "Stop", "Stopped" )
--- OnLeave Transition Handler for State Stopped.
-- @function [parent=#AI_A2A] OnLeaveStopped
-- @param #AI_A2A self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnEnter Transition Handler for State Stopped.
-- @function [parent=#AI_A2A] OnEnterStopped
-- @param #AI_A2A self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
--- OnBefore Transition Handler for Event Stop.
-- @function [parent=#AI_A2A] OnBeforeStop
-- @param #AI_A2A self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnAfter Transition Handler for Event Stop.
-- @function [parent=#AI_A2A] OnAfterStop
-- @param #AI_A2A self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
--- Synchronous Event Trigger for Event Stop.
-- @function [parent=#AI_A2A] Stop
-- @param #AI_A2A self
--- Asynchronous Event Trigger for Event Stop.
-- @function [parent=#AI_A2A] __Stop
-- @param #AI_A2A self
-- @param #number Delay The delay in seconds.
self:AddTransition( "*", "Status", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A.
--- OnBefore Transition Handler for Event Status.
-- @function [parent=#AI_A2A] OnBeforeStatus
-- @param #AI_A2A self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnAfter Transition Handler for Event Status.
-- @function [parent=#AI_A2A] OnAfterStatus
-- @param #AI_A2A self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
--- Synchronous Event Trigger for Event Status.
-- @function [parent=#AI_A2A] Status
-- @param #AI_A2A self
--- Asynchronous Event Trigger for Event Status.
-- @function [parent=#AI_A2A] __Status
-- @param #AI_A2A self
-- @param #number Delay The delay in seconds.
self:AddTransition( "*", "RTB", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A.
--- OnBefore Transition Handler for Event RTB.
-- @function [parent=#AI_A2A] OnBeforeRTB
-- @param #AI_A2A self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnAfter Transition Handler for Event RTB.
-- @function [parent=#AI_A2A] OnAfterRTB
-- @param #AI_A2A self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
--- Synchronous Event Trigger for Event RTB.
-- @function [parent=#AI_A2A] RTB
-- @param #AI_A2A self
--- Asynchronous Event Trigger for Event RTB.
-- @function [parent=#AI_A2A] __RTB
-- @param #AI_A2A self
-- @param #number Delay The delay in seconds.
--- OnLeave Transition Handler for State Returning.
-- @function [parent=#AI_A2A] OnLeaveReturning
-- @param #AI_A2A self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnEnter Transition Handler for State Returning.
-- @function [parent=#AI_A2A] OnEnterReturning
-- @param #AI_A2A self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
self:AddTransition( "Patrolling", "Refuel", "Refuelling" )
--- Refuel Handler OnBefore for AI_A2A
-- @function [parent=#AI_A2A] OnBeforeRefuel
-- @param #AI_A2A self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Refuel Handler OnAfter for AI_A2A
-- @function [parent=#AI_A2A] OnAfterRefuel
-- @param #AI_A2A self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From
-- @param #string Event
-- @param #string To
--- Refuel Trigger for AI_A2A
-- @function [parent=#AI_A2A] Refuel
-- @param #AI_A2A self
--- Refuel Asynchronous Trigger for AI_A2A
-- @function [parent=#AI_A2A] __Refuel
-- @param #AI_A2A self
-- @param #number Delay
self:AddTransition( "*", "Takeoff", "Airborne" )
self:AddTransition( "*", "Return", "Returning" )
self:AddTransition( "*", "Hold", "Holding" )
self:AddTransition( "*", "Home", "Home" )
self:AddTransition( "*", "LostControl", "LostControl" )
self:AddTransition( "*", "Fuel", "Fuel" )
self:AddTransition( "*", "Damaged", "Damaged" )
self:AddTransition( "*", "Eject", "*" )
self:AddTransition( "*", "Crash", "Crashed" )
self:AddTransition( "*", "PilotDead", "*" )
self.IdleCount = 0
return self
end
--- @param Wrapper.Group#GROUP self
-- @param Core.Event#EVENTDATA EventData
function GROUP:OnEventTakeoff( EventData, Fsm )
Fsm:Takeoff()
self:UnHandleEvent( EVENTS.Takeoff )
end
function AI_A2A:SetDispatcher( Dispatcher )
self.Dispatcher = Dispatcher
end
function AI_A2A:GetDispatcher()
return self.Dispatcher
end
function AI_A2A:SetTargetDistance( Coordinate )
local CurrentCoord = self.Controllable:GetCoordinate()
self.TargetDistance = CurrentCoord:Get2DDistance( Coordinate )
self.ClosestTargetDistance = ( not self.ClosestTargetDistance or self.ClosestTargetDistance > self.TargetDistance ) and self.TargetDistance or self.ClosestTargetDistance
end
function AI_A2A:ClearTargetDistance()
self.TargetDistance = nil
self.ClosestTargetDistance = nil
end
--- Sets (modifies) the minimum and maximum speed of the patrol.
-- @param #AI_A2A self
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @return #AI_A2A self
function AI_A2A:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
self.PatrolMinSpeed = PatrolMinSpeed
self.PatrolMaxSpeed = PatrolMaxSpeed
end
--- Sets the floor and ceiling altitude of the patrol.
-- @param #AI_A2A self
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @return #AI_A2A self
function AI_A2A:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } )
self.PatrolFloorAltitude = PatrolFloorAltitude
self.PatrolCeilingAltitude = PatrolCeilingAltitude
end
--- Sets the home airbase.
-- @param #AI_A2A self
-- @param Wrapper.Airbase#AIRBASE HomeAirbase
-- @return #AI_A2A self
function AI_A2A:SetHomeAirbase( HomeAirbase )
self:F2( { HomeAirbase } )
self.HomeAirbase = HomeAirbase
end
--- Sets to refuel at the given tanker.
-- @param #AI_A2A self
-- @param Wrapper.Group#GROUP TankerName The group name of the tanker as defined within the Mission Editor or spawned.
-- @return #AI_A2A self
function AI_A2A:SetTanker( TankerName )
self:F2( { TankerName } )
self.TankerName = TankerName
end
--- Sets the disengage range, that when engaging a target beyond the specified range, the engagement will be cancelled and the plane will RTB.
-- @param #AI_A2A self
-- @param #number DisengageRadius The disengage range.
-- @return #AI_A2A self
function AI_A2A:SetDisengageRadius( DisengageRadius )
self:F2( { DisengageRadius } )
self.DisengageRadius = DisengageRadius
end
--- Set the status checking off.
-- @param #AI_A2A self
-- @return #AI_A2A self
function AI_A2A:SetStatusOff()
self:F2()
self.CheckStatus = false
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.
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold 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_A2A.
-- Once the time is finished, the old AI will return to the base.
-- @param #AI_A2A self
-- @param #number PatrolFuelThresholdPercentage The treshold 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.
-- @return #AI_A2A self
function AI_A2A:SetFuelThreshold( PatrolFuelThresholdPercentage, PatrolOutOfFuelOrbitTime )
self.PatrolManageFuel = true
self.PatrolFuelThresholdPercentage = PatrolFuelThresholdPercentage
self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime
self.Controllable:OptionRTBBingoFuel( false )
return self
end
--- When the AI is damaged beyond a certain treshold, it is required that the AI returns to the home base.
-- However, damage cannot be foreseen early on.
-- Therefore, when the damage treshold is reached,
-- the AI will return immediately to the home base (RTB).
-- 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.
-- @param #AI_A2A self
-- @param #number PatrolDamageThreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged.
-- @return #AI_A2A self
function AI_A2A:SetDamageThreshold( PatrolDamageThreshold )
self.PatrolManageDamage = true
self.PatrolDamageThreshold = PatrolDamageThreshold
return self
end
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
-- @param #AI_A2A self
-- @return #AI_A2A self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A:onafterStart( Controllable, From, Event, To )
self:F2()
self:__Status( 10 ) -- Check status status every 30 seconds.
self:HandleEvent( EVENTS.PilotDead, self.OnPilotDead )
self:HandleEvent( EVENTS.Crash, self.OnCrash )
self:HandleEvent( EVENTS.Ejection, self.OnEjection )
Controllable:OptionROEHoldFire()
Controllable:OptionROTVertical()
end
--- @param #AI_A2A self
function AI_A2A:onbeforeStatus()
return self.CheckStatus
end
--- @param #AI_A2A self
function AI_A2A:onafterStatus()
self:F( " Checking Status" )
if self.Controllable and self.Controllable:IsAlive() then
local RTB = false
local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() )
if not self:Is( "Holding" ) and not self:Is( "Returning" ) then
local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() )
self:F({DistanceFromHomeBase=DistanceFromHomeBase})
if DistanceFromHomeBase > self.DisengageRadius then
self:E( self.Controllable:GetName() .. " is too far from home base, RTB!" )
self:Hold( 300 )
RTB = false
end
end
if self:Is( "Fuel" ) or self:Is( "Damaged" ) or self:Is( "LostControl" ) then
if DistanceFromHomeBase < 5000 then
self:E( self.Controllable:GetName() .. " is too far from home base, RTB!" )
self:Home( "Destroy" )
end
end
if not self:Is( "Fuel" ) and not self:Is( "Home" ) then
local Fuel = self.Controllable:GetFuel()
self:F({Fuel=Fuel})
if Fuel < self.PatrolFuelThresholdPercentage then
if self.TankerName then
self:E( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" )
self:Refuel()
else
self:E( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" )
local OldAIControllable = self.Controllable
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
local TimedOrbitTask = OldAIControllable:TaskControlled( OrbitTask, OldAIControllable:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil ) )
OldAIControllable:SetTask( TimedOrbitTask, 10 )
self:Fuel()
RTB = true
end
else
end
end
-- TODO: Check GROUP damage function.
local Damage = self.Controllable:GetLife()
local InitialLife = self.Controllable:GetLife0()
self:F( { Damage = Damage, InitialLife = InitialLife, DamageThreshold = self.PatrolDamageThreshold } )
if ( Damage / InitialLife ) < self.PatrolDamageThreshold then
self:E( self.Controllable:GetName() .. " is damaged: " .. Damage .. " ... RTB!" )
self:Damaged()
RTB = true
self:SetStatusOff()
end
-- Check if planes went RTB and are out of control.
if self.Controllable:HasTask() == false then
if not self:Is( "Started" ) and
not self:Is( "Stopped" ) and
not self:Is( "Home" ) then
if self.IdleCount >= 2 then
if Damage ~= InitialLife then
self:Damaged()
else
self:E( self.Controllable:GetName() .. " control lost! " )
self:LostControl()
end
else
self.IdleCount = self.IdleCount + 1
end
end
else
self.IdleCount = 0
end
if RTB == true then
self:__RTB( 0.5 )
end
self:__Status( 10 )
end
end
--- @param Wrapper.Group#GROUP AIGroup
function AI_A2A.RTBRoute( AIGroup, Fsm )
AIGroup:F( { "AI_A2A.RTBRoute:", AIGroup:GetName() } )
if AIGroup:IsAlive() then
Fsm:__RTB( 0.5 )
end
end
--- @param Wrapper.Group#GROUP AIGroup
function AI_A2A.RTBHold( AIGroup, Fsm )
AIGroup:F( { "AI_A2A.RTBHold:", AIGroup:GetName() } )
if AIGroup:IsAlive() then
Fsm:__RTB( 0.5 )
Fsm:Return()
local Task = AIGroup:TaskOrbitCircle( 4000, 400 )
AIGroup:SetTask( Task )
end
end
--- @param #AI_A2A self
-- @param Wrapper.Group#GROUP AIGroup
function AI_A2A:onafterRTB( AIGroup, From, Event, To )
self:F( { AIGroup, From, Event, To } )
if AIGroup and AIGroup:IsAlive() then
self:E( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" )
self:ClearTargetDistance()
AIGroup:ClearTasks()
local EngageRoute = {}
--- Calculate the target route point.
local CurrentCoord = AIGroup:GetCoordinate()
local ToTargetCoord = self.HomeAirbase:GetCoordinate()
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
local ToAirbaseAngle = CurrentCoord:GetAngleDegrees( CurrentCoord:GetDirectionVec3( ToTargetCoord ) )
local Distance = CurrentCoord:Get2DDistance( ToTargetCoord )
local ToAirbaseCoord = CurrentCoord:Translate( 5000, ToAirbaseAngle )
if Distance < 5000 then
self:E( "RTB and near the airbase!" )
self:Home()
return
end
--- Create a route point of type air.
local ToRTBRoutePoint = ToAirbaseCoord:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToTargetSpeed,
true
)
self:F( { Angle = ToAirbaseAngle, ToTargetSpeed = ToTargetSpeed } )
self:T2( { self.MinSpeed, self.MaxSpeed, ToTargetSpeed } )
EngageRoute[#EngageRoute+1] = ToRTBRoutePoint
EngageRoute[#EngageRoute+1] = ToRTBRoutePoint
AIGroup:OptionROEHoldFire()
AIGroup:OptionROTEvadeFire()
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
AIGroup:WayPointInitialize( EngageRoute )
local Tasks = {}
Tasks[#Tasks+1] = AIGroup:TaskFunction( "AI_A2A.RTBRoute", self )
EngageRoute[#EngageRoute].task = AIGroup:TaskCombo( Tasks )
--- NOW ROUTE THE GROUP!
AIGroup:Route( EngageRoute, 0.5 )
end
end
--- @param #AI_A2A self
-- @param Wrapper.Group#GROUP AIGroup
function AI_A2A:onafterHome( AIGroup, From, Event, To )
self:F( { AIGroup, From, Event, To } )
self:E( "Group " .. self.Controllable:GetName() .. " ... Home! ( " .. self:GetState() .. " )" )
if AIGroup and AIGroup:IsAlive() then
end
end
--- @param #AI_A2A self
-- @param Wrapper.Group#GROUP AIGroup
function AI_A2A:onafterHold( AIGroup, From, Event, To, HoldTime )
self:F( { AIGroup, From, Event, To } )
self:E( "Group " .. self.Controllable:GetName() .. " ... Holding! ( " .. self:GetState() .. " )" )
if AIGroup and AIGroup:IsAlive() then
local OrbitTask = AIGroup:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
local TimedOrbitTask = AIGroup:TaskControlled( OrbitTask, AIGroup:TaskCondition( nil, nil, nil, nil, HoldTime , nil ) )
local RTBTask = AIGroup:TaskFunction( "AI_A2A.RTBHold", self )
local OrbitHoldTask = AIGroup:TaskOrbitCircle( 4000, self.PatrolMinSpeed )
--AIGroup:SetState( AIGroup, "AI_A2A", self )
AIGroup:SetTask( AIGroup:TaskCombo( { TimedOrbitTask, RTBTask, OrbitHoldTask } ), 1 )
end
end
--- @param Wrapper.Group#GROUP AIGroup
function AI_A2A.Resume( AIGroup, Fsm )
AIGroup:F( { "AI_A2A.Resume:", AIGroup:GetName() } )
if AIGroup:IsAlive() then
Fsm:__RTB( 0.5 )
end
end
--- @param #AI_A2A self
-- @param Wrapper.Group#GROUP AIGroup
function AI_A2A:onafterRefuel( AIGroup, From, Event, To )
self:F( { AIGroup, From, Event, To } )
self:E( "Group " .. self.Controllable:GetName() .. " ... Refuelling! ( " .. self:GetState() .. " )" )
if AIGroup and AIGroup:IsAlive() then
local Tanker = GROUP:FindByName( self.TankerName )
if Tanker:IsAlive() and Tanker:IsAirPlane() then
local RefuelRoute = {}
--- Calculate the target route point.
local CurrentCoord = AIGroup:GetCoordinate()
local ToRefuelCoord = Tanker:GetCoordinate()
local ToRefuelSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
--- Create a route point of type air.
local ToRefuelRoutePoint = ToRefuelCoord:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToRefuelSpeed,
true
)
self:F( { ToRefuelSpeed = ToRefuelSpeed } )
RefuelRoute[#RefuelRoute+1] = ToRefuelRoutePoint
RefuelRoute[#RefuelRoute+1] = ToRefuelRoutePoint
AIGroup:OptionROEHoldFire()
AIGroup:OptionROTEvadeFire()
local Tasks = {}
Tasks[#Tasks+1] = AIGroup:TaskRefueling()
Tasks[#Tasks+1] = AIGroup:TaskFunction( self:GetClassName() .. ".Resume", self )
RefuelRoute[#RefuelRoute].task = AIGroup:TaskCombo( Tasks )
AIGroup:Route( RefuelRoute, 0.5 )
else
self:RTB()
end
end
end
--- @param #AI_A2A self
function AI_A2A:onafterDead()
self:SetStatusOff()
end
--- @param #AI_A2A self
-- @param Core.Event#EVENTDATA EventData
function AI_A2A:OnCrash( EventData )
if self.Controllable:IsAlive() and EventData.IniDCSGroupName == self.Controllable:GetName() then
self:E( self.Controllable:GetUnits() )
if #self.Controllable:GetUnits() == 1 then
self:__Crash( 1, EventData )
end
end
end
--- @param #AI_A2A self
-- @param Core.Event#EVENTDATA EventData
function AI_A2A:OnEjection( EventData )
if self.Controllable:IsAlive() and EventData.IniDCSGroupName == self.Controllable:GetName() then
self:__Eject( 1, EventData )
end
end
--- @param #AI_A2A self
-- @param Core.Event#EVENTDATA EventData
function AI_A2A:OnPilotDead( EventData )
if self.Controllable:IsAlive() and EventData.IniDCSGroupName == self.Controllable:GetName() then
self:__PilotDead( 1, EventData )
end
end

View File

@@ -0,0 +1,492 @@
--- **AI** -- (R2.2) - Models the process of Combat Air Patrol (CAP) for airplanes.
--
-- This is a class used in the @{AI_A2A_Dispatcher}.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI_A2A_Cap
--BASE:TraceClass("AI_A2A_CAP")
--- @type AI_A2A_CAP
-- @extends AI.AI_A2A_Patrol#AI_A2A_PATROL
--- # AI_A2A_CAP class, extends @{AI_CAP#AI_PATROL_ZONE}
--
-- The AI_A2A_CAP class implements the core functions to patrol a @{Zone} by an AI @{Group} or @{Group}
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
--
-- ![Process](..\Presentations\AI_CAP\Dia3.JPG)
--
-- The AI_A2A_CAP is assigned a @{Group} and this must be done before the AI_A2A_CAP process can be started using the **Start** event.
--
-- ![Process](..\Presentations\AI_CAP\Dia4.JPG)
--
-- The AI will fly towards the random 3D point within the patrol zone, 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.
--
-- ![Process](..\Presentations\AI_CAP\Dia5.JPG)
--
-- This cycle will continue.
--
-- ![Process](..\Presentations\AI_CAP\Dia6.JPG)
--
-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event.
--
-- ![Process](..\Presentations\AI_CAP\Dia9.JPG)
--
-- When enemies are detected, the AI will automatically engage the enemy.
--
-- ![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.
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
--
-- ![Process](..\Presentations\AI_CAP\Dia13.JPG)
--
-- ## 1. AI_A2A_CAP constructor
--
-- * @{#AI_A2A_CAP.New}(): Creates a new AI_A2A_CAP object.
--
-- ## 2. AI_A2A_CAP is a FSM
--
-- ![Process](..\Presentations\AI_CAP\Dia2.JPG)
--
-- ### 2.1 AI_A2A_CAP States
--
-- * **None** ( Group ): The process is not started yet.
-- * **Patrolling** ( Group ): The AI is patrolling the Patrol Zone.
-- * **Engaging** ( Group ): The AI is engaging the bogeys.
-- * **Returning** ( Group ): The AI is returning to Base..
--
-- ### 2.2 AI_A2A_CAP Events
--
-- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
-- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone.
-- * **@{#AI_A2A_CAP.Engage}**: Let the AI engage the bogeys.
-- * **@{#AI_A2A_CAP.Abort}**: Aborts the engagement and return patrolling in the patrol zone.
-- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
-- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
-- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
-- * **@{#AI_A2A_CAP.Destroy}**: The AI has destroyed a bogey @{Unit}.
-- * **@{#AI_A2A_CAP.Destroyed}**: The AI has destroyed all bogeys @{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.
--
-- ## 3. Set the Range of Engagement
--
-- ![Range](..\Presentations\AI_CAP\Dia11.JPG)
--
-- An optional range can be set in meters,
-- that will define when the AI will engage with the detected airborne enemy targets.
-- The range can be beyond or smaller than the range of the Patrol Zone.
-- The range is applied at the position of the AI.
-- Use the method @{AI_CAP#AI_A2A_CAP.SetEngageRange}() to define that range.
--
-- ## 4. Set the Zone of Engagement
--
-- ![Zone](..\Presentations\AI_CAP\Dia12.JPG)
--
-- An optional @{Zone} can be set,
-- that will define when the AI will engage with the detected airborne enemy targets.
-- Use the method @{AI_Cap#AI_A2A_CAP.SetEngageZone}() to define that Zone.
--
-- ===
--
-- @field #AI_A2A_CAP
AI_A2A_CAP = {
ClassName = "AI_A2A_CAP",
}
--- Creates a new AI_A2A_CAP object
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
-- @param Dcs.DCSTypes#Speed EngageMinSpeed The minimum speed of the @{Group} in km/h when engaging a target.
-- @param Dcs.DCSTypes#Speed EngageMaxSpeed The maximum speed of the @{Group} in km/h when engaging a target.
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @return #AI_A2A_CAP
function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType )
-- Inherits from BASE
local self = BASE:Inherit( self, AI_A2A_PATROL:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_A2A_CAP
self.Accomplished = false
self.Engaging = false
self.EngageMinSpeed = EngageMinSpeed
self.EngageMaxSpeed = EngageMaxSpeed
self:AddTransition( { "Patrolling", "Engaging", "Returning", "Airborne" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP.
--- OnBefore Transition Handler for Event Engage.
-- @function [parent=#AI_A2A_CAP] OnBeforeEngage
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnAfter Transition Handler for Event Engage.
-- @function [parent=#AI_A2A_CAP] OnAfterEngage
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
--- Synchronous Event Trigger for Event Engage.
-- @function [parent=#AI_A2A_CAP] Engage
-- @param #AI_A2A_CAP self
--- Asynchronous Event Trigger for Event Engage.
-- @function [parent=#AI_A2A_CAP] __Engage
-- @param #AI_A2A_CAP self
-- @param #number Delay The delay in seconds.
--- OnLeave Transition Handler for State Engaging.
-- @function [parent=#AI_A2A_CAP] OnLeaveEngaging
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnEnter Transition Handler for State Engaging.
-- @function [parent=#AI_A2A_CAP] OnEnterEngaging
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP.
--- OnBefore Transition Handler for Event Fired.
-- @function [parent=#AI_A2A_CAP] OnBeforeFired
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnAfter Transition Handler for Event Fired.
-- @function [parent=#AI_A2A_CAP] OnAfterFired
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
--- Synchronous Event Trigger for Event Fired.
-- @function [parent=#AI_A2A_CAP] Fired
-- @param #AI_A2A_CAP self
--- Asynchronous Event Trigger for Event Fired.
-- @function [parent=#AI_A2A_CAP] __Fired
-- @param #AI_A2A_CAP self
-- @param #number Delay The delay in seconds.
self:AddTransition( "*", "Destroy", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP.
--- OnBefore Transition Handler for Event Destroy.
-- @function [parent=#AI_A2A_CAP] OnBeforeDestroy
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnAfter Transition Handler for Event Destroy.
-- @function [parent=#AI_A2A_CAP] OnAfterDestroy
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
--- Synchronous Event Trigger for Event Destroy.
-- @function [parent=#AI_A2A_CAP] Destroy
-- @param #AI_A2A_CAP self
--- Asynchronous Event Trigger for Event Destroy.
-- @function [parent=#AI_A2A_CAP] __Destroy
-- @param #AI_A2A_CAP self
-- @param #number Delay The delay in seconds.
self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP.
--- OnBefore Transition Handler for Event Abort.
-- @function [parent=#AI_A2A_CAP] OnBeforeAbort
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnAfter Transition Handler for Event Abort.
-- @function [parent=#AI_A2A_CAP] OnAfterAbort
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
--- Synchronous Event Trigger for Event Abort.
-- @function [parent=#AI_A2A_CAP] Abort
-- @param #AI_A2A_CAP self
--- Asynchronous Event Trigger for Event Abort.
-- @function [parent=#AI_A2A_CAP] __Abort
-- @param #AI_A2A_CAP self
-- @param #number Delay The delay in seconds.
self:AddTransition( "Engaging", "Accomplish", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP.
--- OnBefore Transition Handler for Event Accomplish.
-- @function [parent=#AI_A2A_CAP] OnBeforeAccomplish
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnAfter Transition Handler for Event Accomplish.
-- @function [parent=#AI_A2A_CAP] OnAfterAccomplish
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
--- Synchronous Event Trigger for Event Accomplish.
-- @function [parent=#AI_A2A_CAP] Accomplish
-- @param #AI_A2A_CAP self
--- Asynchronous Event Trigger for Event Accomplish.
-- @function [parent=#AI_A2A_CAP] __Accomplish
-- @param #AI_A2A_CAP self
-- @param #number Delay The delay in seconds.
return self
end
--- onafter State Transition for Event Patrol.
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AICap The AI Group managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_CAP:onafterStart( AICap, From, Event, To )
AICap:HandleEvent( EVENTS.Takeoff, nil, self )
end
--- Set the Engage Zone which defines where the AI will engage bogies.
-- @param #AI_A2A_CAP self
-- @param Core.Zone#ZONE EngageZone The zone where the AI is performing CAP.
-- @return #AI_A2A_CAP self
function AI_A2A_CAP:SetEngageZone( EngageZone )
self:F2()
if EngageZone then
self.EngageZone = EngageZone
else
self.EngageZone = nil
end
end
--- Set the Engage Range when the AI will engage with airborne enemies.
-- @param #AI_A2A_CAP self
-- @param #number EngageRange The Engage Range.
-- @return #AI_A2A_CAP self
function AI_A2A_CAP:SetEngageRange( EngageRange )
self:F2()
if EngageRange then
self.EngageRange = EngageRange
else
self.EngageRange = nil
end
end
--- onafter State Transition for Event Patrol.
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The AI Group managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_CAP:onafterPatrol( AICap, From, Event, To )
-- Call the parent Start event handler
self:GetParent(self).onafterPatrol( self, AICap, From, Event, To )
self:HandleEvent( EVENTS.Dead )
end
-- todo: need to fix this global function
--- @param Wrapper.Group#GROUP AICap
function AI_A2A_CAP.AttackRoute( AICap, Fsm )
AICap:F( { "AI_A2A_CAP.AttackRoute:", AICap:GetName() } )
if AICap:IsAlive() then
Fsm:__Engage( 0.5 )
end
end
--- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_CAP:onbeforeEngage( AICap, From, Event, To )
if self.Accomplished == true then
return false
end
end
--- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The AI Group managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_CAP:onafterAbort( AICap, From, Event, To )
AICap:ClearTasks()
self:__Route( 0.5 )
end
--- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The AICap Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_CAP:onafterEngage( AICap, From, Event, To, AttackSetUnit )
self:F( { AICap, From, Event, To, AttackSetUnit} )
self.AttackSetUnit = AttackSetUnit or self.AttackSetUnit -- Core.Set#SET_UNIT
local FirstAttackUnit = self.AttackSetUnit:GetFirst() -- Wrapper.Unit#UNIT
if FirstAttackUnit and FirstAttackUnit:IsAlive() then -- If there is no attacker anymore, stop the engagement.
if AICap:IsAlive() then
local EngageRoute = {}
--- Calculate the target route point.
local CurrentCoord = AICap:GetCoordinate()
local ToTargetCoord = self.AttackSetUnit:GetFirst():GetCoordinate()
local ToTargetSpeed = math.random( self.EngageMinSpeed, self.EngageMaxSpeed )
local ToInterceptAngle = CurrentCoord:GetAngleDegrees( CurrentCoord:GetDirectionVec3( ToTargetCoord ) )
--- Create a route point of type air.
local ToPatrolRoutePoint = CurrentCoord:Translate( 5000, ToInterceptAngle ):WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToTargetSpeed,
true
)
self:F( { Angle = ToInterceptAngle, ToTargetSpeed = ToTargetSpeed } )
self:T2( { self.MinSpeed, self.MaxSpeed, ToTargetSpeed } )
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
local AttackTasks = {}
for AttackUnitID, AttackUnit in pairs( self.AttackSetUnit:GetSet() ) do
local AttackUnit = AttackUnit -- Wrapper.Unit#UNIT
self:T( { "Attacking Unit:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsAir() } )
if AttackUnit:IsAlive() and AttackUnit:IsAir() then
AttackTasks[#AttackTasks+1] = AICap:TaskAttackUnit( AttackUnit )
end
end
if #AttackTasks == 0 then
self:E("No targets found -> Going back to Patrolling")
self:__Abort( 0.5 )
else
AICap:OptionROEOpenFire()
AICap:OptionROTEvadeFire()
AttackTasks[#AttackTasks+1] = AICap:TaskFunction( "AI_A2A_CAP.AttackRoute", self )
EngageRoute[#EngageRoute].task = AICap:TaskCombo( AttackTasks )
end
AICap:Route( EngageRoute, 0.5 )
end
else
self:E("No targets found -> Going back to Patrolling")
self:__Abort( 0.5 )
end
end
--- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_CAP:onafterAccomplish( AICap, From, Event, To )
self.Accomplished = true
self:SetDetectionOff()
end
--- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @param Core.Event#EVENTDATA EventData
function AI_A2A_CAP:onafterDestroy( AICap, From, Event, To, EventData )
if EventData.IniUnit then
self.AttackUnits[EventData.IniUnit] = nil
end
end
--- @param #AI_A2A_CAP self
-- @param Core.Event#EVENTDATA EventData
function AI_A2A_CAP:OnEventDead( EventData )
self:F( { "EventDead", EventData } )
if EventData.IniDCSUnit then
if self.AttackUnits and self.AttackUnits[EventData.IniUnit] then
self:__Destroy( 1, EventData )
end
end
end
--- @param Wrapper.Group#GROUP AICap
function AI_A2A_CAP.Resume( AICap )
AICap:F( { "AI_A2A_CAP.Resume:", AICap:GetName() } )
if AICap:IsAlive() then
local _AI_A2A = AICap:GetState( AICap, "AI_A2A" ) -- #AI_A2A
_AI_A2A:__Reset( 1 )
_AI_A2A:__Route( 5 )
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,462 @@
--- **AI** -- (R2.2) - Models the process of Ground Controlled Interception (GCI) for airplanes.
--
-- This is a class used in the @{AI_A2A_Dispatcher}.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI_A2A_GCI
--- @type AI_A2A_GCI
-- @extends AI.AI_A2A#AI_A2A
--- # AI_A2A_GCI class, extends @{AI_A2A#AI_A2A}
--
-- The AI_A2A_GCI class implements the core functions to intercept intruders. The Engage function will intercept intruders.
--
-- ![Process](..\Presentations\AI_GCI\Dia3.JPG)
--
-- The AI_A2A_GCI is assigned a @{Group} and this must be done before the AI_A2A_GCI process can be started using the **Start** event.
--
-- ![Process](..\Presentations\AI_GCI\Dia4.JPG)
--
-- The AI will fly towards the random 3D point within the patrol zone, 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.
--
-- ![Process](..\Presentations\AI_GCI\Dia5.JPG)
--
-- This cycle will continue.
--
-- ![Process](..\Presentations\AI_GCI\Dia6.JPG)
--
-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event.
--
-- ![Process](..\Presentations\AI_GCI\Dia9.JPG)
--
-- When enemies are detected, the AI will automatically engage the enemy.
--
-- ![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.
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
--
-- ![Process](..\Presentations\AI_GCI\Dia13.JPG)
--
-- ## 1. AI_A2A_GCI constructor
--
-- * @{#AI_A2A_GCI.New}(): Creates a new AI_A2A_GCI object.
--
-- ## 2. AI_A2A_GCI is a FSM
--
-- ![Process](..\Presentations\AI_GCI\Dia2.JPG)
--
-- ### 2.1 AI_A2A_GCI States
--
-- * **None** ( Group ): The process is not started yet.
-- * **Patrolling** ( Group ): The AI is patrolling the Patrol Zone.
-- * **Engaging** ( Group ): The AI is engaging the bogeys.
-- * **Returning** ( Group ): The AI is returning to Base..
--
-- ### 2.2 AI_A2A_GCI Events
--
-- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
-- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone.
-- * **@{#AI_A2A_GCI.Engage}**: Let the AI engage the bogeys.
-- * **@{#AI_A2A_GCI.Abort}**: Aborts the engagement and return patrolling in the patrol zone.
-- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
-- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
-- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
-- * **@{#AI_A2A_GCI.Destroy}**: The AI has destroyed a bogey @{Unit}.
-- * **@{#AI_A2A_GCI.Destroyed}**: The AI has destroyed all bogeys @{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.
--
-- ## 3. Set the Range of Engagement
--
-- ![Range](..\Presentations\AI_GCI\Dia11.JPG)
--
-- An optional range can be set in meters,
-- that will define when the AI will engage with the detected airborne enemy targets.
-- The range can be beyond or smaller than the range of the Patrol Zone.
-- The range is applied at the position of the AI.
-- Use the method @{AI_GCI#AI_A2A_GCI.SetEngageRange}() to define that range.
--
-- ## 4. Set the Zone of Engagement
--
-- ![Zone](..\Presentations\AI_GCI\Dia12.JPG)
--
-- An optional @{Zone} can be set,
-- that will define when the AI will engage with the detected airborne enemy targets.
-- Use the method @{AI_Cap#AI_A2A_GCI.SetEngageZone}() to define that Zone.
--
-- ===
--
-- @field #AI_A2A_GCI
AI_A2A_GCI = {
ClassName = "AI_A2A_GCI",
}
--- Creates a new AI_A2A_GCI object
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept
-- @return #AI_A2A_GCI
function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
-- Inherits from BASE
local self = BASE:Inherit( self, AI_A2A:New( AIIntercept ) ) -- #AI_A2A_GCI
self.Accomplished = false
self.Engaging = false
self.EngageMinSpeed = EngageMinSpeed
self.EngageMaxSpeed = EngageMaxSpeed
self.PatrolMinSpeed = EngageMinSpeed
self.PatrolMaxSpeed = EngageMaxSpeed
self.PatrolAltType = "RADIO"
self:AddTransition( { "Started", "Engaging", "Returning", "Airborne" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_GCI.
--- OnBefore Transition Handler for Event Engage.
-- @function [parent=#AI_A2A_GCI] OnBeforeEngage
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnAfter Transition Handler for Event Engage.
-- @function [parent=#AI_A2A_GCI] OnAfterEngage
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
--- Synchronous Event Trigger for Event Engage.
-- @function [parent=#AI_A2A_GCI] Engage
-- @param #AI_A2A_GCI self
--- Asynchronous Event Trigger for Event Engage.
-- @function [parent=#AI_A2A_GCI] __Engage
-- @param #AI_A2A_GCI self
-- @param #number Delay The delay in seconds.
--- OnLeave Transition Handler for State Engaging.
-- @function [parent=#AI_A2A_GCI] OnLeaveEngaging
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnEnter Transition Handler for State Engaging.
-- @function [parent=#AI_A2A_GCI] OnEnterEngaging
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_GCI.
--- OnBefore Transition Handler for Event Fired.
-- @function [parent=#AI_A2A_GCI] OnBeforeFired
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnAfter Transition Handler for Event Fired.
-- @function [parent=#AI_A2A_GCI] OnAfterFired
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
--- Synchronous Event Trigger for Event Fired.
-- @function [parent=#AI_A2A_GCI] Fired
-- @param #AI_A2A_GCI self
--- Asynchronous Event Trigger for Event Fired.
-- @function [parent=#AI_A2A_GCI] __Fired
-- @param #AI_A2A_GCI self
-- @param #number Delay The delay in seconds.
self:AddTransition( "*", "Destroy", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_GCI.
--- OnBefore Transition Handler for Event Destroy.
-- @function [parent=#AI_A2A_GCI] OnBeforeDestroy
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnAfter Transition Handler for Event Destroy.
-- @function [parent=#AI_A2A_GCI] OnAfterDestroy
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
--- Synchronous Event Trigger for Event Destroy.
-- @function [parent=#AI_A2A_GCI] Destroy
-- @param #AI_A2A_GCI self
--- Asynchronous Event Trigger for Event Destroy.
-- @function [parent=#AI_A2A_GCI] __Destroy
-- @param #AI_A2A_GCI self
-- @param #number Delay The delay in seconds.
self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_GCI.
--- OnBefore Transition Handler for Event Abort.
-- @function [parent=#AI_A2A_GCI] OnBeforeAbort
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnAfter Transition Handler for Event Abort.
-- @function [parent=#AI_A2A_GCI] OnAfterAbort
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
--- Synchronous Event Trigger for Event Abort.
-- @function [parent=#AI_A2A_GCI] Abort
-- @param #AI_A2A_GCI self
--- Asynchronous Event Trigger for Event Abort.
-- @function [parent=#AI_A2A_GCI] __Abort
-- @param #AI_A2A_GCI self
-- @param #number Delay The delay in seconds.
self:AddTransition( "Engaging", "Accomplish", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_GCI.
--- OnBefore Transition Handler for Event Accomplish.
-- @function [parent=#AI_A2A_GCI] OnBeforeAccomplish
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnAfter Transition Handler for Event Accomplish.
-- @function [parent=#AI_A2A_GCI] OnAfterAccomplish
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
--- Synchronous Event Trigger for Event Accomplish.
-- @function [parent=#AI_A2A_GCI] Accomplish
-- @param #AI_A2A_GCI self
--- Asynchronous Event Trigger for Event Accomplish.
-- @function [parent=#AI_A2A_GCI] __Accomplish
-- @param #AI_A2A_GCI self
-- @param #number Delay The delay in seconds.
return self
end
--- onafter State Transition for Event Patrol.
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The AI Group managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_GCI:onafterStart( AIIntercept, From, Event, To )
AIIntercept:HandleEvent( EVENTS.Takeoff, nil, self )
end
--- onafter State Transition for Event Patrol.
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The AI Group managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_GCI:onafterEngage( AIIntercept, From, Event, To )
self:HandleEvent( EVENTS.Dead )
end
-- todo: need to fix this global function
--- @param Wrapper.Group#GROUP AIControllable
function AI_A2A_GCI.InterceptRoute( AIIntercept, Fsm )
AIIntercept:F( { "AI_A2A_GCI.InterceptRoute:", AIIntercept:GetName() } )
if AIIntercept:IsAlive() then
Fsm:__Engage( 0.5 )
--local Task = AIIntercept:TaskOrbitCircle( 4000, 400 )
--AIIntercept:SetTask( Task )
end
end
--- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_GCI:onbeforeEngage( AIIntercept, From, Event, To )
if self.Accomplished == true then
return false
end
end
--- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The AI Group managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_GCI:onafterAbort( AIIntercept, From, Event, To )
AIIntercept:ClearTasks()
self:Return()
self:__RTB( 0.5 )
end
--- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The GroupGroup managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_GCI:onafterEngage( AIIntercept, From, Event, To, AttackSetUnit )
self:F( { AIIntercept, From, Event, To, AttackSetUnit} )
self.AttackSetUnit = AttackSetUnit or self.AttackSetUnit -- Core.Set#SET_UNIT
local FirstAttackUnit = self.AttackSetUnit:GetFirst()
if FirstAttackUnit and FirstAttackUnit:IsAlive() then
if AIIntercept:IsAlive() then
local EngageRoute = {}
local CurrentCoord = AIIntercept:GetCoordinate()
--- Calculate the target route point.
local CurrentCoord = AIIntercept:GetCoordinate()
local ToTargetCoord = self.AttackSetUnit:GetFirst():GetCoordinate()
self:SetTargetDistance( ToTargetCoord ) -- For RTB status check
local ToTargetSpeed = math.random( self.EngageMinSpeed, self.EngageMaxSpeed )
local ToInterceptAngle = CurrentCoord:GetAngleDegrees( CurrentCoord:GetDirectionVec3( ToTargetCoord ) )
--- Create a route point of type air.
local ToPatrolRoutePoint = CurrentCoord:Translate( 15000, ToInterceptAngle ):WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToTargetSpeed,
true
)
self:F( { Angle = ToInterceptAngle, ToTargetSpeed = ToTargetSpeed } )
self:F( { self.EngageMinSpeed, self.EngageMaxSpeed, ToTargetSpeed } )
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
local AttackTasks = {}
for AttackUnitID, AttackUnit in pairs( self.AttackSetUnit:GetSet() ) do
local AttackUnit = AttackUnit -- Wrapper.Unit#UNIT
if AttackUnit:IsAlive() and AttackUnit:IsAir() then
self:T( { "Intercepting Unit:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsAir() } )
AttackTasks[#AttackTasks+1] = AIIntercept:TaskAttackUnit( AttackUnit )
end
end
if #AttackTasks == 0 then
self:E("No targets found -> Going RTB")
self:Return()
self:__RTB( 0.5 )
else
AIIntercept:OptionROEOpenFire()
AIIntercept:OptionROTEvadeFire()
AttackTasks[#AttackTasks+1] = AIIntercept:TaskFunction( "AI_A2A_GCI.InterceptRoute", self )
EngageRoute[#EngageRoute].task = AIIntercept:TaskCombo( AttackTasks )
end
AIIntercept:Route( EngageRoute, 0.5 )
end
else
self:E("No targets found -> Going RTB")
self:Return()
self:__RTB( 0.5 )
end
end
--- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_GCI:onafterAccomplish( AIIntercept, From, Event, To )
self.Accomplished = true
self:SetDetectionOff()
end
--- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @param Core.Event#EVENTDATA EventData
function AI_A2A_GCI:onafterDestroy( AIIntercept, From, Event, To, EventData )
if EventData.IniUnit then
self.AttackUnits[EventData.IniUnit] = nil
end
end
--- @param #AI_A2A_GCI self
-- @param Core.Event#EVENTDATA EventData
function AI_A2A_GCI:OnEventDead( EventData )
self:F( { "EventDead", EventData } )
if EventData.IniDCSUnit then
if self.AttackUnits and self.AttackUnits[EventData.IniUnit] then
self:__Destroy( 1, EventData )
end
end
end

View File

@@ -0,0 +1,366 @@
--- **AI** -- (R2.2) - Models the process of air patrol of airplanes.
--
-- This is a class used in the @{AI_A2A_Dispatcher}.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI_A2A_Patrol
--- @type AI_A2A_PATROL
-- @extends AI.AI_A2A#AI_A2A
--- # AI_A2A_PATROL class, extends @{Fsm#FSM_CONTROLLABLE}
--
-- The AI_A2A_PATROL class implements the core functions to patrol a @{Zone} by an AI @{Group} or @{Group}.
--
-- ![Process](..\Presentations\AI_PATROL\Dia3.JPG)
--
-- The AI_A2A_PATROL is assigned a @{Group} and this must be done before the AI_A2A_PATROL process can be started using the **Start** event.
--
-- ![Process](..\Presentations\AI_PATROL\Dia4.JPG)
--
-- The AI will fly towards the random 3D point within the patrol zone, 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.
--
-- ![Process](..\Presentations\AI_PATROL\Dia5.JPG)
--
-- This cycle will continue.
--
-- ![Process](..\Presentations\AI_PATROL\Dia6.JPG)
--
-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event.
--
-- ![Process](..\Presentations\AI_PATROL\Dia9.JPG)
--
---- Note that the enemy is not engaged! To model enemy engagement, either tailor the **Detected** event, or
-- use derived AI_ classes to model AI offensive or defensive behaviour.
--
-- ![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.
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
--
-- ![Process](..\Presentations\AI_PATROL\Dia11.JPG)
--
-- ## 1. AI_A2A_PATROL constructor
--
-- * @{#AI_A2A_PATROL.New}(): Creates a new AI_A2A_PATROL object.
--
-- ## 2. AI_A2A_PATROL is a FSM
--
-- ![Process](..\Presentations\AI_PATROL\Dia2.JPG)
--
-- ### 2.1. AI_A2A_PATROL States
--
-- * **None** ( Group ): The process is not started yet.
-- * **Patrolling** ( Group ): The AI is patrolling the Patrol Zone.
-- * **Returning** ( Group ): The AI is returning to Base.
-- * **Stopped** ( Group ): The process is stopped.
-- * **Crashed** ( Group ): The AI has crashed or is dead.
--
-- ### 2.2. AI_A2A_PATROL Events
--
-- * **Start** ( Group ): Start the process.
-- * **Stop** ( Group ): Stop the process.
-- * **Route** ( Group ): Route the AI to a new random 3D point within the Patrol Zone.
-- * **RTB** ( Group ): Route the AI to the home base.
-- * **Detect** ( Group ): The AI is detecting 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.
--
-- ## 3. Set or Get the AI controllable
--
-- * @{#AI_A2A_PATROL.SetControllable}(): Set the AIControllable.
-- * @{#AI_A2A_PATROL.GetControllable}(): Get the AIControllable.
--
-- ## 4. Set the Speed and Altitude boundaries of the AI controllable
--
-- * @{#AI_A2A_PATROL.SetSpeed}(): Set the patrol speed boundaries of the AI, for the next patrol.
-- * @{#AI_A2A_PATROL.SetAltitude}(): Set altitude boundaries of the AI, for the next patrol.
--
-- ## 5. Manage the detection process of the AI controllable
--
-- The detection process of the AI controllable can be manipulated.
-- Detection requires an amount of CPU power, which has an impact on your mission performance.
-- Only put detection on when absolutely necessary, and the frequency of the detection can also be set.
--
-- * @{#AI_A2A_PATROL.SetDetectionOn}(): Set the detection on. The AI will detect for targets.
-- * @{#AI_A2A_PATROL.SetDetectionOff}(): Set the detection off, the AI will not detect for targets. The existing target list will NOT be erased.
--
-- The detection frequency can be set with @{#AI_A2A_PATROL.SetRefreshTimeInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection.
-- Use the method @{#AI_A2A_PATROL.GetDetectedUnits}() to obtain a list of the @{Unit}s detected by the AI.
--
-- The detection can be filtered to potential targets in a specific zone.
-- Use the method @{#AI_A2A_PATROL.SetDetectionZone}() to set the zone where targets need to be detected.
-- Note that when the zone is too far away, or the AI is not heading towards the zone, or the AI is too high, no targets may be detected
-- according the weather conditions.
--
-- ## 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.
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated.
-- When the fuel treshold 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.
-- 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.
--
-- ## 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.
-- Therefore, when the damage treshold 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.
--
-- ===
--
-- @field #AI_A2A_PATROL
AI_A2A_PATROL = {
ClassName = "AI_A2A_PATROL",
}
--- Creates a new AI_A2A_PATROL object
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @return #AI_A2A_PATROL self
-- @usage
-- -- Define a new AI_A2A_PATROL Object. This PatrolArea will patrol a Group within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h.
-- PatrolZone = ZONE:New( 'PatrolZone' )
-- PatrolSpawn = SPAWN:New( 'Patrol Group' )
-- PatrolArea = AI_A2A_PATROL:New( PatrolZone, 3000, 6000, 600, 900 )
function AI_A2A_PATROL:New( AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
-- Inherits from BASE
local self = BASE:Inherit( self, AI_A2A:New( AIPatrol ) ) -- #AI_A2A_PATROL
self.PatrolZone = PatrolZone
self.PatrolFloorAltitude = PatrolFloorAltitude
self.PatrolCeilingAltitude = PatrolCeilingAltitude
self.PatrolMinSpeed = PatrolMinSpeed
self.PatrolMaxSpeed = PatrolMaxSpeed
-- defafult PatrolAltType to "RADIO" if not specified
self.PatrolAltType = PatrolAltType or "RADIO"
self:AddTransition( { "Started", "Airborne", "Refuelling" }, "Patrol", "Patrolling" )
--- OnBefore Transition Handler for Event Patrol.
-- @function [parent=#AI_A2A_PATROL] OnBeforePatrol
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnAfter Transition Handler for Event Patrol.
-- @function [parent=#AI_A2A_PATROL] OnAfterPatrol
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
--- Synchronous Event Trigger for Event Patrol.
-- @function [parent=#AI_A2A_PATROL] Patrol
-- @param #AI_A2A_PATROL self
--- Asynchronous Event Trigger for Event Patrol.
-- @function [parent=#AI_A2A_PATROL] __Patrol
-- @param #AI_A2A_PATROL self
-- @param #number Delay The delay in seconds.
--- OnLeave Transition Handler for State Patrolling.
-- @function [parent=#AI_A2A_PATROL] OnLeavePatrolling
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnEnter Transition Handler for State Patrolling.
-- @function [parent=#AI_A2A_PATROL] OnEnterPatrolling
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
self:AddTransition( "Patrolling", "Route", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_PATROL.
--- OnBefore Transition Handler for Event Route.
-- @function [parent=#AI_A2A_PATROL] OnBeforeRoute
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #boolean Return false to cancel Transition.
--- OnAfter Transition Handler for Event Route.
-- @function [parent=#AI_A2A_PATROL] OnAfterRoute
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
--- Synchronous Event Trigger for Event Route.
-- @function [parent=#AI_A2A_PATROL] Route
-- @param #AI_A2A_PATROL self
--- Asynchronous Event Trigger for Event Route.
-- @function [parent=#AI_A2A_PATROL] __Route
-- @param #AI_A2A_PATROL self
-- @param #number Delay The delay in seconds.
self:AddTransition( "*", "Reset", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_PATROL.
return self
end
--- Sets (modifies) the minimum and maximum speed of the patrol.
-- @param #AI_A2A_PATROL self
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
-- @return #AI_A2A_PATROL self
function AI_A2A_PATROL:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
self.PatrolMinSpeed = PatrolMinSpeed
self.PatrolMaxSpeed = PatrolMaxSpeed
end
--- Sets the floor and ceiling altitude of the patrol.
-- @param #AI_A2A_PATROL self
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @return #AI_A2A_PATROL self
function AI_A2A_PATROL:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } )
self.PatrolFloorAltitude = PatrolFloorAltitude
self.PatrolCeilingAltitude = PatrolCeilingAltitude
end
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
-- @param #AI_A2A_PATROL self
-- @return #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_PATROL:onafterPatrol( AIPatrol, From, Event, To )
self:F2()
self:ClearTargetDistance()
self:__Route( 1 )
AIPatrol:OnReSpawn(
function( PatrolGroup )
self:__Reset( 1 )
self:__Route( 5 )
end
)
end
--- @param Wrapper.Group#GROUP AIPatrol
-- This statis method is called from the route path within the last task at the last waaypoint of the AIPatrol.
-- Note that this method is required, as triggers the next route when patrolling for the AIPatrol.
function AI_A2A_PATROL.PatrolRoute( AIPatrol, Fsm )
AIPatrol:F( { "AI_A2A_PATROL.PatrolRoute:", AIPatrol:GetName() } )
if AIPatrol:IsAlive() then
Fsm:Route()
end
end
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The Group managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_PATROL:onafterRoute( AIPatrol, From, Event, To )
self:F2()
-- When RTB, don't allow anymore the routing.
if From == "RTB" then
return
end
if AIPatrol:IsAlive() then
local PatrolRoute = {}
--- Calculate the target route point.
local CurrentCoord = AIPatrol:GetCoordinate()
local ToTargetCoord = self.PatrolZone:GetRandomPointVec2()
ToTargetCoord:SetAlt( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ) )
self:SetTargetDistance( ToTargetCoord ) -- For RTB status check
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
--- Create a route point of type air.
local ToPatrolRoutePoint = ToTargetCoord:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToTargetSpeed,
true
)
PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint
PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint
local Tasks = {}
Tasks[#Tasks+1] = AIPatrol:TaskFunction( "AI_A2A_PATROL.PatrolRoute", self )
PatrolRoute[#PatrolRoute].task = AIPatrol:TaskCombo( Tasks )
AIPatrol:OptionROEReturnFire()
AIPatrol:OptionROTEvadeFire()
AIPatrol:Route( PatrolRoute, 0.5 )
end
end
--- @param Wrapper.Group#GROUP AIPatrol
function AI_A2A_PATROL.Resume( AIPatrol )
AIPatrol:F( { "AI_A2A_PATROL.Resume:", AIPatrol:GetName() } )
if AIPatrol:IsAlive() then
local _AI_A2A = AIPatrol:GetState( AIPatrol, "AI_A2A" ) -- #AI_A2A
_AI_A2A:__Reset( 1 )
_AI_A2A:__Route( 5 )
end
end

View File

@@ -1,55 +1,25 @@
--- **AI** -- **Provide Battlefield Air Interdiction (bombing).**
--- **AI** -- (R2.1) - Manages the independent process of Battlefield Air Interdiction (bombing) for airplanes.
--
-- ===
--
-- ![Banner Image](..\Presentations\AI_BAI\Dia1.JPG)
--
-- ===
--
-- AI_BAI classes makes AI Controllables execute bombing tasks.
--
-- There are the following types of BAI classes defined:
--
-- * @{#AI_BAI_ZONE}: Perform a BAI in a zone.
--
-- ====
--
-- # Demo Missions
--
-- ### [AI_BAI Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/BOMB%20-%20Close%20Air%20Support)
--
-- ### [AI_BAI Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/BOMB%20-%20Close%20Air%20Support)
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
--
-- # YouTube Channel
--
-- ### [AI_BAI YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl3JBO1WDqqpyYRRmIkR2ir2)
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/BAI%20-%20Battlefield%20Air%20Interdiction)
--
-- ===
--
-- # **API CHANGE HISTORY**
--
-- The underlying change log documents the API changes. Please read this carefully. The following notation is used:
--
-- * **Added** parts are expressed in bold type face.
-- * _Removed_ parts are expressed in italic type face.
--
-- Hereby the change log:
--
-- 2017-01-15: Initial class and API.
--
--
-- ### [YouTube Playlist]()
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Contributions:
--
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision.
--
-- ### Authors:
--
-- * **FlightControl**: Concept, Design & Programming.
--
-- ===
--
-- @module AI_Bai
@@ -546,7 +516,7 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToEngageZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -603,7 +573,7 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, self.EngageAltitude, ToTargetVec2.y )
--- Create a route point of type air.
local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir(
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -627,7 +597,7 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
--- NOW ROUTE THE GROUP!
Controllable:WayPointExecute( 1 )
self:SetDetectionInterval( 2 )
self:SetRefreshTimeInterval( 2 )
self:SetDetectionActivated()
self:__Target( -2 ) -- Start Targetting
end

View File

@@ -1,58 +1,31 @@
--- Single-Player:**No** / Multi-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**All** -- **AI Balancing will replace in multi player missions
-- non-occupied human slots with AI groups, in order to provide an engaging simulation environment,
-- even when there are hardly any players in the mission.**
--- **AI** -- (2.1) - Balance player slots with AI to create an engaging simulation environment, independent of the amount of players.
--
-- ===
--
-- ![Banner Image](..\Presentations\AI_Balancer\Dia1.JPG)
--
-- ====
--
-- # Demo Missions
--
-- ### [AI_BALANCER Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/AIB%20-%20AI%20Balancing)
--
-- ### [AI_BALANCER Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AIB%20-%20AI%20Balancing)
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
--
-- # YouTube Channel
--
-- ### [AI_BALANCER YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl2CJVIrL1TdAumuVS8n64B7)
--
-- ===
--
-- # **API CHANGE HISTORY**
--
-- The underlying change log documents the API changes. Please read this carefully. The following notation is used:
--
-- * **Added** parts are expressed in bold type face.
-- * _Removed_ parts are expressed in italic type face.
--
-- Hereby the change log:
--
-- 2017-01-17: There is still a problem with AI being destroyed, but not respawned. Need to check further upon that.
--
-- 2017-01-08: AI_BALANCER:**InitSpawnInterval( Earliest, Latest )** added.
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/AIB%20-%20AI%20Balancing)
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl2CJVIrL1TdAumuVS8n64B7)
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)
-- * **SNAFU**: Had a couple of mails with the guys to validate, if the same concept in the GCI/CAP script could be reworked within MOOSE. None of the script code has been used however within the new AI_BALANCER moose class.
--
-- ### Authors:
--
-- * FlightControl: Framework Design & Programming and Documentation.
-- ===
--
-- @module AI_Balancer
--- @type AI_BALANCER
-- @field Core.Set#SET_CLIENT SetClient
-- @field Functional.Spawn#SPAWN SpawnAI
-- @field Core.Spawn#SPAWN SpawnAI
-- @field Wrapper.Group#GROUP Test
-- @extends Core.Fsm#FSM_SET
@@ -125,7 +98,7 @@ AI_BALANCER = {
--- Creates a new AI_BALANCER object
-- @param #AI_BALANCER self
-- @param Core.Set#SET_CLIENT SetClient A SET\_CLIENT object that will contain the CLIENT objects to be monitored if they are alive or not (joined by a player).
-- @param Functional.Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed.
-- @param Core.Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed.
-- @return #AI_BALANCER
function AI_BALANCER:New( SetClient, SpawnAI )
@@ -170,22 +143,22 @@ end
--- Returns the AI to the nearest friendly @{Airbase#AIRBASE}.
-- @param #AI_BALANCER self
-- @param Dcs.DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}.
-- @param Dcs.DCSTypes#Distance ReturnThresholdRange If there is an enemy @{Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}.
-- @param Core.Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Set#SET_AIRBASE}s to evaluate where to return to.
function AI_BALANCER:ReturnToNearestAirbases( ReturnTresholdRange, ReturnAirbaseSet )
function AI_BALANCER:ReturnToNearestAirbases( ReturnThresholdRange, ReturnAirbaseSet )
self.ToNearestAirbase = true
self.ReturnTresholdRange = ReturnTresholdRange
self.ReturnThresholdRange = ReturnThresholdRange
self.ReturnAirbaseSet = ReturnAirbaseSet
end
--- Returns the AI to the home @{Airbase#AIRBASE}.
-- @param #AI_BALANCER self
-- @param Dcs.DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}.
function AI_BALANCER:ReturnToHomeAirbase( ReturnTresholdRange )
-- @param Dcs.DCSTypes#Distance ReturnThresholdRange If there is an enemy @{Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}.
function AI_BALANCER:ReturnToHomeAirbase( ReturnThresholdRange )
self.ToHomeAirbase = true
self.ReturnTresholdRange = ReturnTresholdRange
self.ReturnThresholdRange = ReturnThresholdRange
end
--- @param #AI_BALANCER self
@@ -197,9 +170,10 @@ function AI_BALANCER:onenterSpawning( SetGroup, From, Event, To, ClientName )
-- OK, Spawn a new group from the default SpawnAI object provided.
local AIGroup = self.SpawnAI:Spawn() -- Wrapper.Group#GROUP
if AIGroup then
AIGroup:E( "Spawning new AIGroup" )
AIGroup:T( { "Spawning new AIGroup", ClientName = ClientName } )
--TODO: need to rework UnitName thing ...
SetGroup:Remove( ClientName ) -- Ensure that the previously allocated AIGroup to ClientName is removed in the Set.
SetGroup:Add( ClientName, AIGroup )
self.SpawnQueue[ClientName] = nil
@@ -215,9 +189,9 @@ end
function AI_BALANCER:onenterDestroying( SetGroup, From, Event, To, ClientName, AIGroup )
AIGroup:Destroy()
SetGroup:Flush()
SetGroup:Flush( self )
SetGroup:Remove( ClientName )
SetGroup:Flush()
SetGroup:Flush( self )
end
--- @param #AI_BALANCER self
@@ -258,23 +232,24 @@ function AI_BALANCER:onenterMonitoring( SetGroup )
self:T3(Client.ClientName)
local AIGroup = self.Set:Get( Client.UnitName ) -- Wrapper.Group#GROUP
if Client:IsAlive() then
if AIGroup then self:T( { AIGroup = AIGroup:GetName(), IsAlive = AIGroup:IsAlive() } ) end
if Client:IsAlive() == true then
if AIGroup and AIGroup:IsAlive() == true then
if self.ToNearestAirbase == false and self.ToHomeAirbase == false then
self:Destroy( Client.UnitName, AIGroup )
else
-- We test if there is no other CLIENT within the self.ReturnTresholdRange of the first unit of the AI group.
-- We test if there is no other CLIENT within the self.ReturnThresholdRange of the first unit of the AI group.
-- If there is a CLIENT, the AI stays engaged and will not return.
-- If there is no CLIENT within the self.ReturnTresholdRange, then the unit will return to the Airbase return method selected.
-- If there is no CLIENT within the self.ReturnThresholdRange, then the unit will return to the Airbase return method selected.
local PlayerInRange = { Value = false }
local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetVec2(), self.ReturnTresholdRange )
local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetVec2(), self.ReturnThresholdRange )
self:T2( RangeZone )
_DATABASE:ForEachPlayer(
_DATABASE:ForEachPlayerUnit(
--- @param Wrapper.Unit#UNIT RangeTestUnit
function( RangeTestUnit, RangeZone, AIGroup, PlayerInRange )
self:T2( { PlayerInRange, RangeTestUnit.UnitName, RangeZone.ZoneName } )
@@ -303,11 +278,12 @@ function AI_BALANCER:onenterMonitoring( SetGroup )
else
if not AIGroup or not AIGroup:IsAlive() == true then
self:T( "Client " .. Client.UnitName .. " not alive." )
self:T( { Queue = self.SpawnQueue[Client.UnitName] } )
if not self.SpawnQueue[Client.UnitName] then
-- Spawn a new AI taking into account the spawn interval Earliest, Latest
self:__Spawn( math.random( self.Earliest, self.Latest ), Client.UnitName )
self.SpawnQueue[Client.UnitName] = true
self:E( "New AI Spawned for Client " .. Client.UnitName )
self:T( "New AI Spawned for Client " .. Client.UnitName )
end
end
end

View File

@@ -1,59 +1,29 @@
--- **AI** - **Execute Combat Air Patrol (CAP).**
--- **AI** -- (R2.1) - Manages the independent process of Combat Air Patrol (CAP) for airplanes.
--
-- ===
--
-- ![Banner Image](..\Presentations\AI_CAP\Dia1.JPG)
--
-- ===
--
-- AI CAP classes makes AI Controllables execute a Combat Air Patrol.
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAP%20-%20Combat%20Air%20Patrol)
--
-- There are the following types of CAP classes defined:
--
-- * @{#AI_CAP_ZONE}: Perform a CAP in a zone.
--
-- ====
--
-- # Demo Missions
--
-- ### [AI_CAP Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAP%20-%20Combat%20Air%20Patrol)
--
-- ### [AI_CAP Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAP%20-%20Combat%20Air%20Patrol)
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
--
-- # YouTube Channel
--
-- ### [AI_CAP YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1YCyPxJgoZn-CfhwyeW65L)
--
-- ====
--
-- # **API CHANGE HISTORY**
--
-- The underlying change log documents the API changes. Please read this carefully. The following notation is used:
--
-- * **Added** parts are expressed in bold type face.
-- * _Removed_ parts are expressed in italic type face.
--
-- Hereby the change log:
--
-- 2017-01-15: Initial class and API.
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Contributions:
--
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1YCyPxJgoZn-CfhwyeW65L)
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing.
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Concept, Advice & Testing.
-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision.
-- * **[Whisper](http://forums.eagle.ru/member.php?u=3829): Testing.
-- * **[Delta99](https://forums.eagle.ru/member.php?u=125166): Testing.
--
-- ### Authors:
--
-- * **FlightControl**: Concept, Design & Programming.
--
-- ===
--
-- @module AI_Cap
@@ -373,16 +343,20 @@ function AI_CAP_ZONE:onafterStart( Controllable, From, Event, To )
end
-- todo: need to fix this global function
--- @param Wrapper.Controllable#CONTROLLABLE AIControllable
function _NewEngageCapRoute( AIControllable )
--- @param AI.AI_CAP#AI_CAP_ZONE
-- @param Wrapper.Group#GROUP EngageGroup
function AI_CAP_ZONE.EngageRoute( EngageGroup, Fsm )
AIControllable:T( "NewEngageRoute" )
local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cap#AI_CAP_ZONE
EngageZone:__Engage( 1 )
EngageGroup:F( { "AI_CAP_ZONE.EngageRoute:", EngageGroup:GetName() } )
if EngageGroup:IsAlive() then
Fsm:__Engage( 1 )
end
end
--- @param #AI_CAP_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
@@ -417,7 +391,7 @@ function AI_CAP_ZONE:onafterDetected( Controllable, From, Event, To )
end
if Engage == true then
self:E( 'Detected -> Engaging' )
self:F( 'Detected -> Engaging' )
self:__Engage( 1 )
end
end
@@ -455,7 +429,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToEngageZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -479,7 +453,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
--- Create a route point of type air.
local ToPatrolRoutePoint = ToTargetPointVec3:RoutePointAir(
local ToPatrolRoutePoint = ToTargetPointVec3:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -490,7 +464,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
Controllable:OptionROEOpenFire()
Controllable:OptionROTPassiveDefense()
Controllable:OptionROTEvadeFire()
local AttackTasks = {}
@@ -500,13 +474,13 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
if DetectedUnit:IsAlive() and DetectedUnit:IsAir() then
if self.EngageZone then
if DetectedUnit:IsInZone( self.EngageZone ) then
self:E( {"Within Zone and Engaging ", DetectedUnit } )
self:F( {"Within Zone and Engaging ", DetectedUnit } )
AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit )
end
else
if self.EngageRange then
if DetectedUnit:GetPointVec3():Get2DDistance(Controllable:GetPointVec3() ) <= self.EngageRange then
self:E( {"Within Range and Engaging", DetectedUnit } )
self:F( {"Within Range and Engaging", DetectedUnit } )
AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit )
end
else
@@ -518,28 +492,20 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
end
end
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
self.Controllable:WayPointInitialize( EngageRoute )
if #AttackTasks == 0 then
self:E("No targets found -> Going back to Patrolling")
self:F("No targets found -> Going back to Patrolling")
self:__Abort( 1 )
self:__Route( 1 )
self:SetDetectionActivated()
else
AttackTasks[#AttackTasks+1] = Controllable:TaskFunction( "AI_CAP_ZONE.EngageRoute", self )
EngageRoute[1].task = Controllable:TaskCombo( AttackTasks )
--- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ...
self.Controllable:SetState( self.Controllable, "EngageZone", self )
self.Controllable:WayPointFunction( #EngageRoute, 1, "_NewEngageCapRoute" )
self:SetDetectionDeactivated()
end
--- NOW ROUTE THE GROUP!
self.Controllable:WayPointExecute( 1, 2 )
Controllable:Route( EngageRoute, 0.5 )
end
end

View File

@@ -1,44 +1,27 @@
--- **AI** -- **Provide Close Air Support to friendly ground troops.**
--- **AI** -- (R2.1) - Manages the independent process of Close Air Support for airplanes.
--
-- ===
--
-- ![Banner Image](..\Presentations\AI_CAS\Dia1.JPG)
--
-- ===
--
-- AI CAS classes makes AI Controllables execute a Close Air Support.
--
-- There are the following types of CAS classes defined:
--
-- * @{#AI_CAS_ZONE}: Perform a CAS in a zone.
--
-- ====
--
-- # Demo Missions
--
-- ### [AI_CAS Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAS%20-%20Close%20Air%20Support)
--
-- ### [AI_CAS Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAS%20-%20Close%20Air%20Support)
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
--
-- # YouTube Channel
--
-- ### [AI_CAS YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl3JBO1WDqqpyYRRmIkR2ir2)
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAS%20-%20Close%20Air%20Support)
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Contributions:
--
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl3JBO1WDqqpyYRRmIkR2ir2)
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing.
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Concept, Advice & Testing.
-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision.
--
-- ### Authors:
--
-- * **FlightControl**: Concept, Design & Programming.
-- ===
--
-- @module AI_Cas
@@ -107,11 +90,11 @@
--
-- ![Engage Event](..\Presentations\AI_CAS\Dia12.JPG)
--
-- # 1. AI_CAS_ZONE constructor
-- ## AI_CAS_ZONE constructor
--
-- * @{#AI_CAS_ZONE.New}(): Creates a new AI_CAS_ZONE object.
--
-- ## 2. AI_CAS_ZONE is a FSM
-- ## AI_CAS_ZONE is a FSM
--
-- ![Process](..\Presentations\AI_CAS\Dia2.JPG)
--
@@ -374,12 +357,15 @@ function AI_CAS_ZONE:onafterStart( Controllable, From, Event, To )
self:SetDetectionDeactivated() -- When not engaging, set the detection off.
end
--- @param Wrapper.Controllable#CONTROLLABLE AIControllable
function _NewEngageRoute( AIControllable )
--- @param AI.AI_CAS#AI_CAS_ZONE
-- @param Wrapper.Group#GROUP EngageGroup
function AI_CAS_ZONE.EngageRoute( EngageGroup, Fsm )
AIControllable:T( "NewEngageRoute" )
local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cas#AI_CAS_ZONE
EngageZone:__Engage( 1, EngageZone.EngageSpeed, EngageZone.EngageAltitude, EngageZone.EngageWeaponExpend, EngageZone.EngageAttackQty, EngageZone.EngageDirection )
EngageGroup:F( { "AI_CAS_ZONE.EngageRoute:", EngageGroup:GetName() } )
if EngageGroup:IsAlive() then
Fsm:__Engage( 1, Fsm.EngageSpeed, Fsm.EngageAltitude, Fsm.EngageWeaponExpend, Fsm.EngageAttackQty, Fsm.EngageDirection )
end
end
@@ -401,7 +387,6 @@ end
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_CAS_ZONE:onafterTarget( Controllable, From, Event, To )
self:E("onafterTarget")
if Controllable:IsAlive() then
@@ -412,7 +397,7 @@ function AI_CAS_ZONE:onafterTarget( Controllable, From, Event, To )
if DetectedUnit:IsAlive() then
if DetectedUnit:IsInZone( self.EngageZone ) then
if Detected == true then
self:E( {"Target: ", DetectedUnit } )
self:F( {"Target: ", DetectedUnit } )
self.DetectedUnits[DetectedUnit] = false
local AttackTask = Controllable:TaskAttackUnit( DetectedUnit, false, self.EngageWeaponExpend, self.EngageAttackQty, self.EngageDirection, self.EngageAltitude, nil )
self.Controllable:PushTask( AttackTask, 1 )
@@ -465,6 +450,9 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
if Controllable:IsAlive() then
Controllable:OptionROEOpenFire()
Controllable:OptionROTVertical()
local EngageRoute = {}
--- Calculate the current route point.
@@ -474,7 +462,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToEngageZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -486,12 +474,12 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
local AttackTasks = {}
for DetectedUnitID, DetectedUnit in pairs( self.DetectedUnits ) do
for DetectedUnit, Detected in pairs( self.DetectedUnits ) do
local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT
self:T( DetectedUnit )
if DetectedUnit:IsAlive() then
if DetectedUnit:IsInZone( self.EngageZone ) then
self:E( {"Engaging ", DetectedUnit } )
self:F( {"Engaging ", DetectedUnit } )
AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit,
true,
EngageWeaponExpend,
@@ -504,7 +492,8 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
end
end
EngageRoute[1].task = Controllable:TaskCombo( AttackTasks )
AttackTasks[#AttackTasks+1] = Controllable:TaskFunction( "AI_CAS_ZONE.EngageRoute", self )
EngageRoute[#EngageRoute].task = Controllable:TaskCombo( AttackTasks )
--- Define a random point in the @{Zone}. The AI will fly to that point within the zone.
@@ -516,7 +505,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, self.EngageAltitude, ToTargetVec2.y )
--- Create a route point of type air.
local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir(
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -525,22 +514,10 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
)
EngageRoute[#EngageRoute+1] = ToTargetRoutePoint
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
Controllable:WayPointInitialize( EngageRoute )
Controllable:Route( EngageRoute, 0.5 )
--- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ...
Controllable:SetState( Controllable, "EngageZone", self )
Controllable:WayPointFunction( #EngageRoute, 1, "_NewEngageRoute" )
--- NOW ROUTE THE GROUP!
Controllable:WayPointExecute( 1 )
Controllable:OptionROEOpenFire()
Controllable:OptionROTVertical()
self:SetDetectionInterval( 2 )
self:SetRefreshTimeInterval( 2 )
self:SetDetectionActivated()
self:__Target( -2 ) -- Start Targetting
end

View File

@@ -0,0 +1,680 @@
--- **AI** -- (R2.3) - Models the intelligent transportation of infantry and other cargo.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI_Cargo_APC
--- @type AI_CARGO_APC
-- @extends Core.Fsm#FSM_CONTROLLABLE
--- # AI\_CARGO\_APC class, extends @{Core.Base#BASE}
--
-- ===
--
-- AI\_CARGO\APC brings a dynamic cargo handling capability for AI groups.
--
-- Armoured Personnel Carriers (APC), Trucks, Jeeps and other ground based carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
-- The AI\_CARGO\APC module uses the @{Cargo} capabilities within the MOOSE framework.
-- CARGO derived objects must be declared within the mission to make the AI\_CARGO\APC object recognize the cargo.
-- Please consult the @{Cargo} module for more information.
--
-- ## Cargo loading.
--
-- The module will load automatically cargo when the APCs are within boarding or loading range.
-- The boarding or loading range is specified when the cargo is created in the simulation, and therefore, this range depends on the type of cargo
-- and the specified boarding range.
--
-- ## Enemies nearby.
--
-- When the APCs are approaching enemy units, something special is happening.
-- The APCs will stop moving, and the loaded infantry will unboard and follow the APCs and will help to defend the group.
-- The carrier will hold the route once the unboarded infantry is further than 50 meters from the APCs,
-- to ensure that the APCs are not too far away from the following running infantry.
-- Once all enemies are cleared, the infantry will board again automatically into the APCs. Once boarded, the APCs will follow its pre-defined route.
--
-- A combat range needs to be specified in meters at the @{#AI_CARGO_APC.New}() method.
-- This combat range will trigger the unboarding of troops when enemies are within the combat range around the APCs.
-- During my tests, I've noticed that there is a balance between ensuring that the infantry is within sufficient hit range (effectiveness) versus
-- vulnerability of the infantry. It all depends on the kind of enemies that are expected to be encountered.
-- A combat range of 350 meters to 500 meters has been proven to be the most effective and efficient.
--
-- ## Infantry health.
--
-- When infantry is unboarded from the APCs, the infantry is actually respawned into the battlefield.
-- As a result, the unboarding infantry is very _healthy_ every time it unboards.
-- This is due to the limitation of the DCS simulator, which is not able to specify the health of new spawned units as a parameter.
-- However, infantry that was destroyed when unboarded and following the APCs, won't be respawned again. Destroyed is destroyed.
-- As a result, there is some additional strength that is gained when an unboarding action happens, but in terms of simulation balance this has
-- marginal impact on the overall battlefield simulation. Fortunately, the firing strength of infantry is limited, and thus, respacing healthy infantry every
-- time is not so much of an issue ...
--
-- ## Control the APCs on the map.
--
-- It is possible also as a human ground commander to influence the path of the APCs, by pointing a new path using the DCS user interface on the map.
-- In this case, the APCs will change the direction towards its new indicated route. However, there is a catch!
-- Once the APCs are near the enemy, and infantry is unboarded, the APCs won't be able to hold the route until the infantry could catch up.
-- The APCs will simply drive on and won't stop! This is a limitation in ED that prevents user actions being controlled by the scripting engine.
-- No workaround is possible on this.
--
-- ## Cargo deployment.
--
-- Using the @{#AI_CARGO_APC.Deploy}() method, you are able to direct the APCs towards a point on the battlefield to unboard/unload the cargo at the specific coordinate.
-- The APCs will follow nearby roads as much as possible, to ensure fast and clean cargo transportation between the objects and villages in the simulation environment.
--
-- ## Cargo pickup.
--
-- Using the @{#AI_CARGO_APC.Pickup}() method, you are able to direct the APCs towards a point on the battlefield to board/load the cargo at the specific coordinate.
-- The APCs will follow nearby roads as much as possible, to ensure fast and clean cargo transportation between the objects and villages in the simulation environment.
--
--
--
-- @field #AI_CARGO_APC
AI_CARGO_APC = {
ClassName = "AI_CARGO_APC",
Coordinate = nil, -- Core.Point#COORDINATE,
APC_Cargo = {},
}
--- Creates a new AI_CARGO_APC object.
-- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP CargoCarrier
-- @param Core.Set#SET_CARGO CargoSet
-- @param #number CombatRadius
-- @return #AI_CARGO_APC
function AI_CARGO_APC:New( CargoCarrier, CargoSet, CombatRadius )
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_CARGO_APC
self.CargoSet = CargoSet -- Core.Set#SET_CARGO
self.CombatRadius = CombatRadius
self:SetStartState( "Unloaded" )
self:AddTransition( "Unloaded", "Pickup", "*" )
self:AddTransition( "Loaded", "Deploy", "*" )
self:AddTransition( "*", "Load", "Boarding" )
self:AddTransition( "Boarding", "Board", "Boarding" )
self:AddTransition( "Boarding", "Loaded", "Loaded" )
self:AddTransition( "Loaded", "Unload", "Unboarding" )
self:AddTransition( "Unboarding", "Unboard", "Unboarding" )
self:AddTransition( { "Unboarding", "Unloaded" }, "Unloaded", "Unloaded" )
self:AddTransition( "*", "Monitor", "*" )
self:AddTransition( "*", "Follow", "Following" )
self:AddTransition( "*", "Guard", "Unloaded" )
self:AddTransition( "*", "Home", "*" )
self:AddTransition( "*", "Destroyed", "Destroyed" )
--- Pickup Handler OnBefore for AI_CARGO_APC
-- @function [parent=#AI_CARGO_APC] OnBeforePickup
-- @param #AI_CARGO_APC self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Point#COORDINATE Coordinate
-- @return #boolean
--- Pickup Handler OnAfter for AI_CARGO_APC
-- @function [parent=#AI_CARGO_APC] OnAfterPickup
-- @param #AI_CARGO_APC self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Point#COORDINATE Coordinate
--- Pickup Trigger for AI_CARGO_APC
-- @function [parent=#AI_CARGO_APC] Pickup
-- @param #AI_CARGO_APC self
-- @param Core.Point#COORDINATE Coordinate
--- Pickup Asynchronous Trigger for AI_CARGO_APC
-- @function [parent=#AI_CARGO_APC] __Pickup
-- @param #AI_CARGO_APC self
-- @param #number Delay
-- @param Core.Point#COORDINATE Coordinate
--- Deploy Handler OnBefore for AI_CARGO_APC
-- @function [parent=#AI_CARGO_APC] OnBeforeDeploy
-- @param #AI_CARGO_APC self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Point#COORDINATE Coordinate
-- @return #boolean
--- Deploy Handler OnAfter for AI_CARGO_APC
-- @function [parent=#AI_CARGO_APC] OnAfterDeploy
-- @param #AI_CARGO_APC self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Point#COORDINATE Coordinate
--- Deploy Trigger for AI_CARGO_APC
-- @function [parent=#AI_CARGO_APC] Deploy
-- @param #AI_CARGO_APC self
-- @param Core.Point#COORDINATE Coordinate
--- Deploy Asynchronous Trigger for AI_CARGO_APC
-- @function [parent=#AI_CARGO_APC] __Deploy
-- @param #AI_CARGO_APC self
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Delay
--- Loaded Handler OnAfter for AI_CARGO_APC
-- @function [parent=#AI_CARGO_APC] OnAfterLoaded
-- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
-- @param #string From
-- @param #string Event
-- @param #string To
--- Unloaded Handler OnAfter for AI_CARGO_APC
-- @function [parent=#AI_CARGO_APC] OnAfterUnloaded
-- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
-- @param #string From
-- @param #string Event
-- @param #string To
self:__Monitor( 1 )
self:SetCarrier( CargoCarrier )
self.Transporting = false
self.Relocating = false
return self
end
--- Set the Carrier.
-- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP CargoCarrier
-- @return #AI_CARGO_APC
function AI_CARGO_APC:SetCarrier( CargoCarrier )
self.CargoCarrier = CargoCarrier -- Wrapper.Group#GROUP
self.CargoCarrier:SetState( self.CargoCarrier, "AI_CARGO_APC", self )
CargoCarrier:HandleEvent( EVENTS.Dead )
CargoCarrier:HandleEvent( EVENTS.Hit )
function CargoCarrier:OnEventDead( EventData )
self:F({"dead"})
local AICargoTroops = self:GetState( self, "AI_CARGO_APC" )
self:F({AICargoTroops=AICargoTroops})
if AICargoTroops then
self:F({})
if not AICargoTroops:Is( "Loaded" ) then
-- There are enemies within combat range. Unload the CargoCarrier.
AICargoTroops:Destroyed()
end
end
end
function CargoCarrier:OnEventHit( EventData )
self:F({"hit"})
local AICargoTroops = self:GetState( self, "AI_CARGO_APC" )
if AICargoTroops then
self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } )
if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then
-- There are enemies within combat range. Unload the CargoCarrier.
AICargoTroops:Unload( false )
end
end
end
self.Zone = ZONE_UNIT:New( self.CargoCarrier:GetName() .. "-Zone", self.CargoCarrier, self.CombatRadius )
self.Coalition = self.CargoCarrier:GetCoalition()
self:SetControllable( CargoCarrier )
self:Guard()
return self
end
function AI_CARGO_APC:IsTransporting()
return self.Transporting == true
end
function AI_CARGO_APC:IsRelocating()
return self.Relocating == true
end
--- Find a free Carrier within a range.
-- @param #AI_CARGO_APC self
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Radius
-- @return Wrapper.Group#GROUP NewCarrier
function AI_CARGO_APC:FindCarrier( Coordinate, Radius )
local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius )
CoordinateZone:Scan( { Object.Category.UNIT } )
for _, DCSUnit in pairs( CoordinateZone:GetScannedUnits() ) do
local NearUnit = UNIT:Find( DCSUnit )
self:F({NearUnit=NearUnit})
if not NearUnit:GetState( NearUnit, "AI_CARGO_APC" ) then
local Attributes = NearUnit:GetDesc()
self:F({Desc=Attributes})
if NearUnit:HasAttribute( "Trucks" ) then
return NearUnit:GetGroup()
end
end
end
return nil
end
--- Follow Infantry to the Carrier.
-- @param #AI_CARGO_APC self
-- @param #AI_CARGO_APC Me
-- @param Wrapper.Unit#UNIT APCUnit
-- @param Cargo.CargoGroup#CARGO_GROUP Cargo
-- @return #AI_CARGO_APC
function AI_CARGO_APC:FollowToCarrier( Me, APCUnit, CargoGroup )
local InfantryGroup = CargoGroup:GetGroup()
self:F( { self = self:GetClassNameAndID(), InfantryGroup = InfantryGroup:GetName() } )
--if self:Is( "Following" ) then
if APCUnit:IsAlive() then
-- We check if the Cargo is near to the CargoCarrier.
if InfantryGroup:IsPartlyInZone( ZONE_UNIT:New( "Radius", APCUnit, 25 ) ) then
-- The Cargo does not need to follow the Carrier.
Me:Guard()
else
self:F( { InfantryGroup = InfantryGroup:GetName() } )
if InfantryGroup:IsAlive() then
self:F( { InfantryGroup = InfantryGroup:GetName() } )
local Waypoints = {}
-- Calculate the new Route.
local FromCoord = InfantryGroup:GetCoordinate()
local FromGround = FromCoord:WaypointGround( 10, "Diamond" )
self:F({FromGround=FromGround})
table.insert( Waypoints, FromGround )
local ToCoord = APCUnit:GetCoordinate():GetRandomCoordinateInRadius( 10, 5 )
local ToGround = ToCoord:WaypointGround( 10, "Diamond" )
self:F({ToGround=ToGround})
table.insert( Waypoints, ToGround )
local TaskRoute = InfantryGroup:TaskFunction( "AI_CARGO_APC.FollowToCarrier", Me, APCUnit, CargoGroup )
self:F({Waypoints = Waypoints})
local Waypoint = Waypoints[#Waypoints]
InfantryGroup:SetTaskWaypoint( Waypoint, TaskRoute ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
InfantryGroup:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details.
end
end
end
end
--- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
function AI_CARGO_APC:onafterMonitor( APC, From, Event, To )
self:F( { APC, From, Event, To } )
if APC and APC:IsAlive() then
if self.CarrierCoordinate then
if self:IsRelocating() == true then
local Coordinate = APC:GetCoordinate()
self.Zone:Scan( { Object.Category.UNIT } )
if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
if self:Is( "Unloaded" ) or self:Is( "Following" ) then
-- There are no enemies within combat range. Load the CargoCarrier.
self:Load()
end
else
if self:Is( "Loaded" ) then
-- There are enemies within combat range. Unload the CargoCarrier.
self:__Unload( 1, false )
else
if self:Is( "Unloaded" ) then
self:Follow()
end
if self:Is( "Following" ) then
for APCUnit, Cargo in pairs( self.APC_Cargo ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
if Cargo:IsAlive() then
if not Cargo:IsNear( APCUnit, 40 ) then
APCUnit:RouteStop()
self.CarrierStopped = true
else
if self.CarrierStopped then
if Cargo:IsNear( APCUnit, 25 ) then
APCUnit:RouteResume()
self.CarrierStopped = nil
end
end
end
end
end
end
end
end
end
end
self.CarrierCoordinate = APC:GetCoordinate()
end
self:__Monitor( -5 )
end
--- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
function AI_CARGO_APC:onbeforeLoad( APC, From, Event, To )
self:F( { APC, From, Event, To } )
local Boarding = false
self.BoardingCount = 0
if APC and APC:IsAlive() then
self.APC_Cargo = {}
for _, APCUnit in pairs( APC:GetUnits() ) do
local APCUnit = APCUnit -- Wrapper.Unit#UNIT
for _, Cargo in pairs( self.CargoSet:GetSet() ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
self:F( { IsUnLoaded = Cargo:IsUnLoaded(), IsDeployed = Cargo:IsDeployed(), Cargo:GetName(), APC:GetName() } )
if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then
if Cargo:IsInLoadRadius( APCUnit:GetCoordinate() ) then
self:F( { "In radius", APCUnit:GetName() } )
APC:RouteStop()
--Cargo:Ungroup()
Cargo:Board( APCUnit, 25 )
self:__Board( 1, Cargo )
Boarding = true
-- So now this APCUnit has Cargo that is being loaded.
-- This will be used further in the logic to follow and to check cargo status.
self.APC_Cargo[APCUnit] = Cargo
break
end
end
end
end
end
return Boarding
end
--- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
function AI_CARGO_APC:onafterBoard( APC, From, Event, To, Cargo )
self:F( { APC, From, Event, To, Cargo } )
if APC and APC:IsAlive() then
self:F({ IsLoaded = Cargo:IsLoaded(), Cargo:GetName(), APC:GetName() } )
if not Cargo:IsLoaded() then
self:__Board( 10, Cargo )
else
self:__Loaded( 1 )
end
end
end
--- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
function AI_CARGO_APC:onbeforeLoaded( APC, From, Event, To )
self:F( { APC, From, Event, To } )
local Loaded = true
if APC and APC:IsAlive() then
for APCUnit, Cargo in pairs( self.APC_Cargo ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed(), Cargo:GetName(), APC:GetName() } )
if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then
Loaded = false
end
end
end
if Loaded == true then
APC:RouteResume()
end
return Loaded
end
--- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
function AI_CARGO_APC:onafterUnload( APC, From, Event, To, Deployed )
self:F( { APC, From, Event, To, Deployed } )
if APC and APC:IsAlive() then
for _, APCUnit in pairs( APC:GetUnits() ) do
local APCUnit = APCUnit -- Wrapper.Unit#UNIT
APC:RouteStop()
for _, Cargo in pairs( APCUnit:GetCargo() ) do
Cargo:UnBoard()
self:__Unboard( 10, Cargo, Deployed )
end
end
end
end
--- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
function AI_CARGO_APC:onafterUnboard( APC, From, Event, To, Cargo, Deployed )
self:F( { APC, From, Event, To, Cargo:GetName() } )
if APC and APC:IsAlive() then
if not Cargo:IsUnLoaded() then
self:__Unboard( 10, Cargo, Deployed )
else
self:__Unloaded( 1, Cargo, Deployed )
end
end
end
--- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
function AI_CARGO_APC:onbeforeUnloaded( APC, From, Event, To, Cargo, Deployed )
self:F( { APC, From, Event, To, Cargo:GetName(), Deployed = Deployed } )
local AllUnloaded = true
--Cargo:Regroup()
if APC and APC:IsAlive() then
for _, APCUnit in pairs( APC:GetUnits() ) do
local APCUnit = APCUnit -- Wrapper.Unit#UNIT
local CargoCheck = self.APC_Cargo[APCUnit]
if CargoCheck then
self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } )
if CargoCheck:IsUnLoaded() == false then
AllUnloaded = false
break
end
end
end
if AllUnloaded == true then
if Deployed == true then
for APCUnit, Cargo in pairs( self.APC_Cargo ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
Cargo:SetDeployed( true )
end
self.APC_Cargo = {}
end
self:Guard()
self.CargoCarrier = APC
end
end
self:F( { AllUnloaded = AllUnloaded } )
return AllUnloaded
end
--- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
function AI_CARGO_APC:onafterFollow( APC, From, Event, To )
self:F( { APC, From, Event, To } )
self:F( "Follow" )
if APC and APC:IsAlive() then
for APCUnit, Cargo in pairs( self.APC_Cargo ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
if Cargo:IsUnLoaded() then
self:FollowToCarrier( self, APCUnit, Cargo )
APCUnit:RouteResume()
end
end
end
end
--- @param #AI_CARGO_APC
-- @param Wrapper.Group#GROUP APC
function AI_CARGO_APC._Pickup( APC, self )
APC:F( { "AI_CARGO_APC._Pickup:", APC:GetName() } )
if APC:IsAlive() then
self:Load()
self.Relocating = true
end
end
--- @param #AI_CARGO_APC
-- @param Wrapper.Group#GROUP APC
function AI_CARGO_APC._Deploy( APC, self )
APC:F( { "AI_CARGO_APC._Deploy:", APC } )
if APC:IsAlive() then
self:Unload( true )
self.Transporting = false
self.Relocating = false
end
end
--- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed
-- @param #string EndPointFormation The formation at the end point of the action.
function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate )
if APC and APC:IsAlive() then
if Coordinate then
self.RoutePickup = true
local Waypoints = APC:TaskGroundOnRoad( Coordinate, 150, "Line abreast" )
local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Pickup", self )
self:F({Waypoints = Waypoints})
local Waypoint = Waypoints[#Waypoints]
APC:SetTaskWaypoint( Waypoint, TaskFunction ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
APC:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details.
else
AI_CARGO_APC._Pickup( APC, self )
end
self.Transporting = true
end
end
--- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed
-- @param #string EndPointFormation The formation at the end point of the action.
function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate )
if APC and APC:IsAlive() then
self.RouteDeploy = true
local Waypoints = APC:TaskGroundOnRoad( Coordinate, 150, "Line abreast" )
local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Deploy", self )
self:F({Waypoints = Waypoints})
local Waypoint = Waypoints[#Waypoints]
APC:SetTaskWaypoint( Waypoint, TaskFunction ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
APC:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details.
end
end
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP APC
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed
function AI_CARGO_APC:onafterHome( APC, From, Event, To, Coordinate )
if APC and APC:IsAlive() ~= nil then
self.RouteHome = true
local Waypoints = APC:TaskGroundOnRoad( Coordinate, 120, "Line abreast" )
self:F({Waypoints = Waypoints})
local Waypoint = Waypoints[#Waypoints]
APC:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details.
end
end

View File

@@ -0,0 +1,448 @@
--- **AI** -- (R2.3) - Models the intelligent transportation of infantry (cargo).
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI_Cargo_Airplane
--- @type AI_CARGO_AIRPLANE
-- @extends Core.Fsm#FSM_CONTROLLABLE
--- # AI\_CARGO\_AIRPLANE class, extends @{Core.Base@BASE}
--
-- ===
--
-- @field #AI_CARGO_AIRPLANE
AI_CARGO_AIRPLANE = {
ClassName = "AI_CARGO_AIRPLANE",
Coordinate = nil -- Core.Point#COORDINATE,
}
--- Creates a new AI_CARGO_AIRPLANE object.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
-- @param Core.Set#SET_CARGO CargoSet
-- @param #number CombatRadius
-- @return #AI_CARGO_AIRPLANE
function AI_CARGO_AIRPLANE:New( Airplane, CargoSet )
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_CARGO_AIRPLANE
self.CargoSet = CargoSet -- Cargo.CargoGroup#CARGO_GROUP
self:SetStartState( "Unloaded" )
self:AddTransition( "Unloaded", "Pickup", "*" )
self:AddTransition( "Loaded", "Deploy", "*" )
self:AddTransition( "Unloaded", "Load", "Boarding" )
self:AddTransition( "Boarding", "Board", "Boarding" )
self:AddTransition( "Boarding", "Loaded", "Loaded" )
self:AddTransition( "Loaded", "Unload", "Unboarding" )
self:AddTransition( "Unboarding", "Unboard", "Unboarding" )
self:AddTransition( "Unboarding", "Unloaded", "Unloaded" )
self:AddTransition( "*", "Landed", "*" )
self:AddTransition( "*", "Destroyed", "Destroyed" )
--- Pickup Handler OnBefore for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] OnBeforePickup
-- @param #AI_CARGO_AIRPLANE self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @return #boolean
--- Pickup Handler OnAfter for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] OnAfterPickup
-- @param #AI_CARGO_AIRPLANE self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Wrapper.Airbase#AIRBASE Airbase
--- Pickup Trigger for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] Pickup
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Airbase#AIRBASE Airbase
--- Pickup Asynchronous Trigger for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] __Pickup
-- @param #AI_CARGO_AIRPLANE self
-- @param #number Delay
-- @param Wrapper.Airbase#AIRBASE Airbase
--- Deploy Handler OnBefore for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] OnBeforeDeploy
-- @param #AI_CARGO_AIRPLANE self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @return #boolean
--- Deploy Handler OnAfter for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] OnAfterDeploy
-- @param #AI_CARGO_AIRPLANE self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Wrapper.Airbase#AIRBASE Airbase
--- Deploy Trigger for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] Deploy
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Airbase#AIRBASE Airbase
--- Deploy Asynchronous Trigger for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] __Deploy
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param #number Delay
self:SetCarrier( Airplane )
return self
end
--- Set the Carrier.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
-- @return #AI_CARGO_AIRPLANE
function AI_CARGO_AIRPLANE:SetCarrier( Airplane )
local AICargo = self
self.Airplane = Airplane -- Wrapper.Group#GROUP
self.Airplane:SetState( self.Airplane, "AI_CARGO_AIRPLANE", self )
self.RoutePickup = false
self.RouteDeploy = false
Airplane:HandleEvent( EVENTS.Dead )
Airplane:HandleEvent( EVENTS.Hit )
Airplane:HandleEvent( EVENTS.EngineShutdown )
function Airplane:OnEventDead( EventData )
local AICargoTroops = self:GetState( self, "AI_CARGO_AIRPLANE" )
self:F({AICargoTroops=AICargoTroops})
if AICargoTroops then
self:F({})
if not AICargoTroops:Is( "Loaded" ) then
-- There are enemies within combat range. Unload the Airplane.
AICargoTroops:Destroyed()
end
end
end
function Airplane:OnEventHit( EventData )
local AICargoTroops = self:GetState( self, "AI_CARGO_AIRPLANE" )
if AICargoTroops then
self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } )
if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then
-- There are enemies within combat range. Unload the Airplane.
AICargoTroops:Unload()
end
end
end
function Airplane:OnEventEngineShutdown( EventData )
AICargo:Landed()
end
self.Coalition = self.Airplane:GetCoalition()
self:SetControllable( Airplane )
return self
end
--- Find a free Carrier within a range.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param #number Radius
-- @return Wrapper.Group#GROUP NewCarrier
function AI_CARGO_AIRPLANE:FindCarrier( Coordinate, Radius )
local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius )
CoordinateZone:Scan( { Object.Category.UNIT } )
for _, DCSUnit in pairs( CoordinateZone:GetScannedUnits() ) do
local NearUnit = UNIT:Find( DCSUnit )
self:F({NearUnit=NearUnit})
if not NearUnit:GetState( NearUnit, "AI_CARGO_AIRPLANE" ) then
local Attributes = NearUnit:GetDesc()
self:F({Desc=Attributes})
if NearUnit:HasAttribute( "Trucks" ) then
self:SetCarrier( NearUnit )
break
end
end
end
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
-- @param From
-- @param Event
-- @param To
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param #number Speed
function AI_CARGO_AIRPLANE:onafterLanded( Airplane, From, Event, To )
if Airplane and Airplane:IsAlive() then
if self.RoutePickup == true then
self:Load( Airplane:GetPointVec2() )
self.RoutePickup = false
end
if self.RouteDeploy == true then
self:Unload()
self.RouteDeploy = false
end
end
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
-- @param From
-- @param Event
-- @param To
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param #number Speed
function AI_CARGO_AIRPLANE:onafterPickup( Airplane, From, Event, To, Airbase, Speed )
if Airplane and Airplane:IsAlive() then
self:Route( Airplane, Airbase, Speed )
self.RoutePickup = true
self.Airbase = Airbase
end
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
-- @param From
-- @param Event
-- @param To
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param #number Speed
function AI_CARGO_AIRPLANE:onafterDeploy( Airplane, From, Event, To, Airbase, Speed )
if Airplane and Airplane:IsAlive() then
self:Route( Airplane, Airbase, Speed )
self.RouteDeploy = true
self.Airbase = Airbase
end
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
function AI_CARGO_AIRPLANE:onafterLoad( Airplane, From, Event, To, Coordinate )
if Airplane and Airplane:IsAlive() then
for _, Cargo in pairs( self.CargoSet:GetSet() ) do
if Cargo:IsInLoadRadius( Coordinate ) then
self:__Board( 5 )
Cargo:Board( Airplane, 25 )
self.Cargo = Cargo
break
end
end
end
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
function AI_CARGO_AIRPLANE:onafterBoard( Airplane, From, Event, To )
if Airplane and Airplane:IsAlive() then
self:F({ IsLoaded = self.Cargo:IsLoaded() } )
if not self.Cargo:IsLoaded() then
self:__Board( 10 )
else
self:__Loaded( 1 )
end
end
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
function AI_CARGO_AIRPLANE:onafterLoaded( Airplane, From, Event, To )
if Airplane and Airplane:IsAlive() then
end
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
function AI_CARGO_AIRPLANE:onafterUnload( Airplane, From, Event, To )
if Airplane and Airplane:IsAlive() then
self.Cargo:UnBoard()
self:__Unboard( 10 )
end
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
function AI_CARGO_AIRPLANE:onafterUnboard( Airplane, From, Event, To )
if Airplane and Airplane:IsAlive() then
if not self.Cargo:IsUnLoaded() then
self:__Unboard( 10 )
else
self:__Unloaded( 1 )
end
end
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
function AI_CARGO_AIRPLANE:onafterUnloaded( Airplane, From, Event, To )
if Airplane and Airplane:IsAlive() then
self.Airplane = Airplane
end
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param #number Speed
function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed )
if Airplane and Airplane:IsAlive() then
local PointVec3 = Airplane:GetPointVec3()
local Takeoff = SPAWN.Takeoff.Hot
local Template = Airplane:GetTemplate()
if Template then
local Points = {}
if self.Airbase then
local FromWaypoint = Template.route.points[1]
-- These are only for ships.
FromWaypoint.linkUnit = nil
FromWaypoint.helipadId = nil
FromWaypoint.airdromeId = nil
local AirbaseID = self.Airbase:GetID()
local AirbaseCategory = self.Airbase:GetDesc().category
FromWaypoint.airdromeId = AirbaseID
FromWaypoint.alt = 0
FromWaypoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type
FromWaypoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action
-- Translate the position of the Group Template to the Vec3.
for UnitID = 1, #Template.units do
self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. Template.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. Template.units[UnitID].y )
-- These cause a lot of confusion.
local UnitTemplate = Template.units[UnitID]
UnitTemplate.parking = 15
UnitTemplate.parking_id = "1"
UnitTemplate.alt = 0
local SX = UnitTemplate.x
local SY = UnitTemplate.y
local BX = FromWaypoint.x
local BY = FromWaypoint.y
local TX = PointVec3.x + ( SX - BX )
local TY = PointVec3.z + ( SY - BY )
UnitTemplate.x = TX
UnitTemplate.y = TY
self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. UnitTemplate.y )
end
FromWaypoint.x = PointVec3.x
FromWaypoint.y = PointVec3.z
Points[#Points+1] = FromWaypoint
else
local GroupPoint = Airplane:GetVec2()
local GroupVelocity = Airplane:GetUnit(1):GetDesc().speedMax
local FromWaypoint = {}
FromWaypoint.x = GroupPoint.x
FromWaypoint.y = GroupPoint.y
FromWaypoint.type = "Turning Point"
FromWaypoint.action = "Turning Point"
FromWaypoint.speed = GroupVelocity
Points[#Points+1] = FromWaypoint
end
local AirbasePointVec2 = Airbase:GetPointVec2()
local ToWaypoint = AirbasePointVec2:WaypointAir(
POINT_VEC3.RoutePointAltType.BARO,
"Land",
"Landing",
Speed or Airplane:GetUnit(1):GetDesc().speedMax
)
ToWaypoint["airdromeId"] = Airbase:GetID()
ToWaypoint["speed_locked"] = true,
self:F( ToWaypoint )
Points[#Points+1] = ToWaypoint
Template.x = PointVec3.x
Template.y = PointVec3.z
self:T3( Points )
Template.route.points = Points
--self:Respawn( Template )
local GroupSpawned = Airplane:Respawn( Template )
return GroupSpawned
end
end
end

View File

@@ -0,0 +1,356 @@
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI_Cargo_Dispatcher
--- @type AI_CARGO_DISPATCHER
-- @extends Core.Fsm#FSM_CONTROLLABLE
--- # AI\_CARGO\_DISPATCHER class, extends @{Core.Base#BASE}
--
-- ===
--
-- AI\_CARGO\_DISPATCHER brings a dynamic cargo handling capability for AI groups.
--
-- Armoured Personnel APCs (APC), Trucks, Jeeps and other carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
-- The AI\_CARGO\_DISPATCHER module uses the @{Cargo} capabilities within the MOOSE framework.
-- CARGO derived objects must be declared within the mission to make the AI\_CARGO\_DISPATCHER object recognize the cargo.
-- Please consult the @{Cargo} module for more information.
--
--
--
-- @field #AI_CARGO_DISPATCHER
AI_CARGO_DISPATCHER = {
ClassName = "AI_CARGO_DISPATCHER",
SetAPC = nil,
SetDeployZones = nil,
AI_CARGO_APC = {}
}
--- @type AI_CARGO_DISPATCHER.AI_CARGO_APC
-- @map <Wrapper.Group#GROUP, AI.AI_Cargo_APC#AI_CARGO_APC>
--- @field #AI_CARGO_DISPATCHER.AI_CARGO_APC
AI_CARGO_DISPATCHER.AI_Cargo = {}
--- @field #AI_CARGO_DISPATCHER.PickupCargo
AI_CARGO_DISPATCHER.PickupCargo = {}
--- Creates a new AI_CARGO_DISPATCHER object.
-- @param #AI_CARGO_DISPATCHER self
-- @param Core.Set#SET_GROUP SetAPC
-- @param Core.Set#SET_CARGO SetCargo
-- @param Core.Set#SET_ZONE SetDeployZone
-- @return #AI_CARGO_DISPATCHER
-- @usage
--
-- -- Create a new cargo dispatcher
-- SetAPC = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart()
-- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
-- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone )
--
function AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZones )
local self = BASE:Inherit( self, FSM:New() ) -- #AI_CARGO_DISPATCHER
self.SetAPC = SetAPC -- Core.Set#SET_GROUP
self.SetCargo = SetCargo -- Core.Set#SET_CARGO
self.SetDeployZones = SetDeployZones -- Core.Set#SET_ZONE
self:SetStartState( "Dispatch" )
self:AddTransition( "*", "Monitor", "*" )
self:AddTransition( "*", "Pickup", "*" )
self:AddTransition( "*", "Loading", "*" )
self:AddTransition( "*", "Loaded", "*" )
self:AddTransition( "*", "Deploy", "*" )
self:AddTransition( "*", "Unloading", "*" )
self:AddTransition( "*", "Unloaded", "*" )
self:AddTransition( "*", "Home", "*" )
self.MonitorTimeInterval = 30
self.DeployRadiusInner = 200
self.DeployRadiusOuter = 500
self.CarrierHome = {}
return self
end
--- Set the home zone.
-- When there is nothing anymore to pickup, the carriers will go to a random coordinate in this zone.
-- They will await here new orders.
-- @param #AI_CARGO_DISPATCHER self
-- @param Core.Zone#ZONE_BASE HomeZone
-- @return #AI_CARGO_DISPATCHER
-- @usage
--
-- -- Create a new cargo dispatcher
-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone )
--
-- -- Set the home coordinate
-- local HomeZone = ZONE:New( "Home" )
-- AICargoDispatcher:SetHomeZone( HomeZone )
--
function AI_CARGO_DISPATCHER:SetHomeZone( HomeZone )
self.HomeZone = HomeZone
return self
end
--- Sets or randomizes the pickup location for the carrier around the cargo coordinate in a radius defined an outer and optional inner radius.
-- This radius is influencing the location where the carrier will land to pickup the cargo.
-- There are two aspects that are very important to remember and take into account:
--
-- - Ensure that the outer and inner radius are within reporting radius set by the cargo.
-- For example, if the cargo has a reporting radius of 400 meters, and the outer and inner radius is set to 500 and 450 respectively,
-- then no cargo will be loaded!!!
-- - Also take care of the potential cargo position and possible reasons to crash the carrier. This is especially important
-- for locations which are crowded with other objects, like in the middle of villages or cities.
-- So, for the best operation of cargo operations, always ensure that the cargo is located at open spaces.
--
-- The default radius is 0, so the center. In case of a polygon zone, a random location will be selected as the center in the zone.
-- @param #AI_CARGO_DISPATCHER self
-- @param #number OuterRadius The outer radius in meters around the cargo coordinate.
-- @param #number InnerRadius (optional) The inner radius in meters around the cargo coordinate.
-- @return #AI_CARGO_DISPATCHER
-- @usage
--
-- -- Create a new cargo dispatcher
-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone )
--
-- -- Set the carrier to land within a band around the cargo coordinate between 500 and 300 meters!
-- AICargoDispatcher:SetPickupRadius( 500, 300 )
--
function AI_CARGO_DISPATCHER:SetPickupRadius( OuterRadius, InnerRadius )
OuterRadius = OuterRadius or 0
InnerRadius = InnerRadius or OuterRadius
self.PickupOuterRadius = OuterRadius
self.PickupInnerRadius = InnerRadius
return self
end
--- Set the speed or randomizes the speed in km/h to pickup the cargo.
-- @param #AI_CARGO_DISPATCHER self
-- @param #number MaxSpeed (optional) The maximum speed to move to the cargo pickup location.
-- @param #number MinSpeed The minimum speed to move to the cargo pickup location.
-- @return #AI_CARGO_DISPATCHER
-- @usage
--
-- -- Create a new cargo dispatcher
-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone )
--
-- -- Set the minimum pickup speed to be 100 km/h and the maximum speed to be 200 km/h.
-- AICargoDispatcher:SetPickupSpeed( 200, 100 )
--
function AI_CARGO_DISPATCHER:SetPickupSpeed( MaxSpeed, MinSpeed )
MaxSpeed = MaxSpeed or 999
MinSpeed = MinSpeed or MaxSpeed
self.PickupMinSpeed = MinSpeed
self.PickupMaxSpeed = MaxSpeed
return self
end
--- Sets or randomizes the deploy location for the carrier around the cargo coordinate in a radius defined an outer and an optional inner radius.
-- This radius is influencing the location where the carrier will land to deploy the cargo.
-- There is an aspect that is very important to remember and take into account:
--
-- - Take care of the potential cargo position and possible reasons to crash the carrier. This is especially important
-- for locations which are crowded with other objects, like in the middle of villages or cities.
-- So, for the best operation of cargo operations, always ensure that the cargo is located at open spaces.
--
-- The default radius is 0, so the center. In case of a polygon zone, a random location will be selected as the center in the zone.
-- @param #AI_CARGO_DISPATCHER self
-- @param #number OuterRadius The outer radius in meters around the cargo coordinate.
-- @param #number InnerRadius (optional) The inner radius in meters around the cargo coordinate.
-- @return #AI_CARGO_DISPATCHER
-- @usage
--
-- -- Create a new cargo dispatcher
-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone )
--
-- -- Set the carrier to land within a band around the cargo coordinate between 500 and 300 meters!
-- AICargoDispatcher:SetDeployRadius( 500, 300 )
--
function AI_CARGO_DISPATCHER:SetDeployRadius( OuterRadius, InnerRadius )
OuterRadius = OuterRadius or 0
InnerRadius = InnerRadius or OuterRadius
self.DeployOuterRadius = OuterRadius
self.DeployInnerRadius = InnerRadius
return self
end
--- Sets or randomizes the speed in km/h to deploy the cargo.
-- @param #AI_CARGO_DISPATCHER self
-- @param #number MaxSpeed The maximum speed to move to the cargo deploy location.
-- @param #number MinSpeed (optional) The minimum speed to move to the cargo deploy location.
-- @return #AI_CARGO_DISPATCHER
-- @usage
--
-- -- Create a new cargo dispatcher
-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone )
--
-- -- Set the minimum deploy speed to be 100 km/h and the maximum speed to be 200 km/h.
-- AICargoDispatcher:SetDeploySpeed( 200, 100 )
--
function AI_CARGO_DISPATCHER:SetDeploySpeed( MaxSpeed, MinSpeed )
MaxSpeed = MaxSpeed or 999
MinSpeed = MinSpeed or MaxSpeed
self.DeployMinSpeed = MinSpeed
self.DeployMaxSpeed = MaxSpeed
return self
end
--- The Start trigger event, which actually takes action at the specified time interval.
-- @param #AI_CARGO_DISPATCHER self
-- @param Wrapper.Group#GROUP APC
-- @return #AI_CARGO_DISPATCHER
function AI_CARGO_DISPATCHER:onafterMonitor()
for APCGroupName, Carrier in pairs( self.SetAPC:GetSet() ) do
local Carrier = Carrier -- Wrapper.Group#GROUP
local AI_Cargo = self.AI_Cargo[Carrier]
if not AI_Cargo then
-- ok, so this APC does not have yet an AI_CARGO_APC object...
-- let's create one and also declare the Loaded and UnLoaded handlers.
self.AI_Cargo[Carrier] = self:AICargo( Carrier, self.SetCargo, self.CombatRadius )
AI_Cargo = self.AI_Cargo[Carrier]
function AI_Cargo.OnAfterPickup( AI_Cargo, APC, From, Event, To, Cargo )
self:Pickup( APC, Cargo )
end
function AI_Cargo.OnAfterLoad( AI_Cargo, APC )
self:Loading( APC )
end
function AI_Cargo.OnAfterLoaded( AI_Cargo, APC, From, Event, To, Cargo )
self:Loaded( APC, Cargo )
end
function AI_Cargo.OnAfterDeploy( AI_Cargo, APC )
self:Deploy( APC )
end
function AI_Cargo.OnAfterUnload( AI_Cargo, APC )
self:Unloading( APC )
end
function AI_Cargo.OnAfterUnloaded( AI_Cargo, APC )
self:Unloaded( APC )
end
end
-- The Pickup sequence ...
-- Check if this APC need to go and Pickup something...
self:I( { IsTransporting = AI_Cargo:IsTransporting() } )
if AI_Cargo:IsTransporting() == false then
-- ok, so there is a free APC
-- now find the first cargo that is Unloaded
local PickupCargo = nil
for CargoName, Cargo in pairs( self.SetCargo:GetSet() ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
self:F( { Cargo = Cargo:GetName(), UnLoaded = Cargo:IsUnLoaded(), Deployed = Cargo:IsDeployed(), PickupCargo = self.PickupCargo[Cargo] ~= nil } )
if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then
local CargoCoordinate = Cargo:GetCoordinate()
local CoordinateFree = true
for APC, Coordinate in pairs( self.PickupCargo ) do
if CargoCoordinate:Get2DDistance( Coordinate ) <= 25 then
CoordinateFree = false
break
end
end
if CoordinateFree == true then
self.PickupCargo[Carrier] = CargoCoordinate
PickupCargo = Cargo
break
end
end
end
if PickupCargo then
self.CarrierHome[Carrier] = nil
local PickupCoordinate = PickupCargo:GetCoordinate():GetRandomCoordinateInRadius( self.PickupOuterRadius, self.PickupInnerRadius )
AI_Cargo:Pickup( PickupCoordinate, math.random( self.PickupMinSpeed, self.PickupMaxSpeed ) )
break
else
if self.HomeZone then
if not self.CarrierHome[Carrier] then
self.CarrierHome[Carrier] = true
AI_Cargo:__Home( 10, self.HomeZone:GetRandomPointVec2() )
end
end
end
end
end
self:__Monitor( self.MonitorTimeInterval )
return self
end
--- Make a APC run for a cargo deploy action after the cargo Pickup trigger has been initiated, by default.
-- @param #AI_CARGO_DISPATCHER self
-- @param Wrapper.Group#GROUP APC
-- @return #AI_CARGO_DISPATCHER
function AI_CARGO_DISPATCHER:onafterPickup( From, Event, To, APC, Cargo )
return self
end
--- Make a APC run for a cargo deploy action after the cargo has been loaded, by default.
-- @param #AI_CARGO_DISPATCHER self
-- @param Wrapper.Group#GROUP APC
-- @return #AI_CARGO_DISPATCHER
function AI_CARGO_DISPATCHER:OnAfterLoaded( From, Event, To, APC, Cargo )
self:I( { "Loaded Dispatcher", APC } )
local DeployZone = self.SetDeployZones:GetRandomZone()
self:I( { RandomZone = DeployZone } )
local DeployCoordinate = DeployZone:GetCoordinate():GetRandomCoordinateInRadius( self.DeployOuterRadius, self.DeployInnerRadius )
self.AI_Cargo[APC]:Deploy( DeployCoordinate, math.random( self.DeployMinSpeed, self.DeployMaxSpeed ) )
self.PickupCargo[APC] = nil
return self
end

View File

@@ -0,0 +1,67 @@
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo using APCs.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI_Cargo_Dispatcher_APC
--- @type AI_CARGO_DISPATCHER_APC
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER
--- # AI\_CARGO\_DISPATCHER\_APC class, extends @{Core.Base#BASE}
--
-- ===
--
-- AI\_CARGO\_DISPATCHER\_APC brings a dynamic cargo handling capability for AI groups.
--
-- Armoured Personnel APCs (APC), Trucks, Jeeps and other carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
-- The AI\_CARGO\_DISPATCHER\_APC module uses the @{Cargo} capabilities within the MOOSE framework.
-- CARGO derived objects must be declared within the mission to make the AI\_CARGO\_DISPATCHER\_APC object recognize the cargo.
-- Please consult the @{Cargo} module for more information.
--
--
--
-- @field #AI_CARGO_DISPATCHER_APC
AI_CARGO_DISPATCHER_APC = {
ClassName = "AI_CARGO_DISPATCHER_APC",
}
--- Creates a new AI_CARGO_DISPATCHER_APC object.
-- @param #AI_CARGO_DISPATCHER_APC self
-- @param Core.Set#SET_GROUP SetAPC
-- @param Core.Set#SET_CARGO SetCargo
-- @param Core.Set#SET_ZONE SetDeployZone
-- @return #AI_CARGO_DISPATCHER_APC
-- @usage
--
-- -- Create a new cargo dispatcher
-- SetAPC = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart()
-- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
-- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
-- AICargoDispatcher = AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo )
--
function AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZones )
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_APC
self.CombatRadius = 500
self:SetDeploySpeed( 70, 120 )
self:SetPickupSpeed( 70, 120 )
self:SetPickupRadius( 0, 0 )
self:SetDeployRadius( 0, 0 )
self:Monitor( 1 )
return self
end
function AI_CARGO_DISPATCHER_APC:AICargo( APC, SetCargo )
return AI_CARGO_APC:New( APC, SetCargo, self.CombatRadius )
end

View File

@@ -0,0 +1,54 @@
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo using Planes.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI_Cargo_Dispatcher_Airplane
--- @type AI_CARGO_DISPATCHER_AIRPLANE
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER
--- # AI\_CARGO\_DISPATCHER\_AIRPLANE class, extends @{Core.Base#BASE}
--
-- ===
--
-- AI\_CARGO\_DISPATCHER\_AIRPLANE brings a dynamic cargo handling capability for AI groups.
--
-- Airplanes can be mobilized to intelligently transport infantry and other cargo within the simulation.
-- The AI\_CARGO\_DISPATCHER\_AIRPLANE module uses the @{Cargo} capabilities within the MOOSE framework.
-- CARGO derived objects must be declared within the mission to make the AI\_CARGO\_DISPATCHER\_AIRPLANE object recognize the cargo.
-- Please consult the @{Cargo} module for more information.
--
--
--
-- @field #AI_CARGO_DISPATCHER_AIRPLANE
AI_CARGO_DISPATCHER_AIRPLANE = {
ClassName = "AI_CARGO_DISPATCHER_AIRPLANE",
}
--- Creates a new AI_CARGO_DISPATCHER_AIRPLANE object.
-- @param #AI_CARGO_DISPATCHER_AIRPLANE self
-- @param Core.Set#SET_GROUP SetAirplane
-- @param Core.Set#SET_CARGO SetCargo
-- @param Core.Set#SET_ZONE SetDeployZone
-- @return #AI_CARGO_DISPATCHER_AIRPLANE
-- @usage
--
-- -- Create a new cargo dispatcher
-- SetAirplane = SET_GROUP:New():FilterPrefixes( "Airplane" ):FilterStart()
-- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
-- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
-- AICargoDispatcher = AI_CARGO_DISPATCHER_AIRPLANE:New( SetAirplane, SetCargo )
--
function AI_CARGO_DISPATCHER_AIRPLANE:New( SetAirplane, SetCargo, SetDeployZones )
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetAirplane, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_AIRPLANE
return self
end

View File

@@ -0,0 +1,65 @@
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo using Helicopters.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI_Cargo_Dispatcher_Helicopter
--- @type AI_CARGO_DISPATCHER_HELICOPTER
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER
--- # AI\_CARGO\_DISPATCHER\_HELICOPTER class, extends @{Core.Base#BASE}
--
-- ===
--
-- AI\_CARGO\_DISPATCHER\_HELICOPTER brings a dynamic cargo handling capability for AI groups.
--
-- Helicopters can be mobilized to intelligently transport infantry and other cargo within the simulation.
-- The AI\_CARGO\_DISPATCHER\_HELICOPTER module uses the @{Cargo} capabilities within the MOOSE framework.
-- CARGO derived objects must be declared within the mission to make the AI\_CARGO\_DISPATCHER\_HELICOPTER object recognize the cargo.
-- Please consult the @{Cargo} module for more information.
--
--
--
-- @field #AI_CARGO_DISPATCHER_HELICOPTER
AI_CARGO_DISPATCHER_HELICOPTER = {
ClassName = "AI_CARGO_DISPATCHER_HELICOPTER",
}
--- Creates a new AI_CARGO_DISPATCHER_HELICOPTER object.
-- @param #AI_CARGO_DISPATCHER_HELICOPTER self
-- @param Core.Set#SET_GROUP SetHelicopter
-- @param Core.Set#SET_CARGO SetCargo
-- @param Core.Set#SET_ZONE SetDeployZone
-- @return #AI_CARGO_DISPATCHER_HELICOPTER
-- @usage
--
-- -- Create a new cargo dispatcher
-- SetHelicopter = SET_GROUP:New():FilterPrefixes( "Helicopter" ):FilterStart()
-- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
-- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
-- AICargoDispatcher = AI_CARGO_DISPATCHER_HELICOPTER:New( SetHelicopter, SetCargo )
--
function AI_CARGO_DISPATCHER_HELICOPTER:New( SetHelicopter, SetCargo, SetDeployZones )
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetHelicopter, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_HELICOPTER
self:SetDeploySpeed( 200, 150 )
self:SetPickupSpeed( 200, 150 )
self:SetPickupRadius( 0, 0 )
self:SetDeployRadius( 0, 0 )
self:Monitor( 1 )
return self
end
function AI_CARGO_DISPATCHER_HELICOPTER:AICargo( Helicopter, SetCargo )
return AI_CARGO_HELICOPTER:New( Helicopter, SetCargo )
end

View File

@@ -0,0 +1,685 @@
--- **AI** -- (R2.3) - Models the intelligent transportation of infantry (cargo).
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI_Cargo_Helicopter
--- @type AI_CARGO_HELICOPTER
-- @extends Core.Fsm#FSM_CONTROLLABLE
--- # AI\_CARGO\_TROOPS class, extends @{Core.Base@BASE}
--
-- ===
--
-- @field #AI_CARGO_HELICOPTER
AI_CARGO_HELICOPTER = {
ClassName = "AI_CARGO_HELICOPTER",
Coordinate = nil -- Core.Point#COORDINATE,
}
AI_CARGO_QUEUE = {}
--- Creates a new AI_CARGO_HELICOPTER object.
-- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @param Core.Set#SET_CARGO CargoSet
-- @param #number CombatRadius
-- @return #AI_CARGO_HELICOPTER
function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_CARGO_HELICOPTER
self.CargoSet = CargoSet -- Cargo.CargoGroup#CARGO_GROUP
self.Zone = ZONE_GROUP:New( Helicopter:GetName(), Helicopter, 300 )
self:SetStartState( "Unloaded" )
self:AddTransition( "Unloaded", "Pickup", "*" )
self:AddTransition( "Loaded", "Deploy", "*" )
self:AddTransition( "Unloaded", "Load", "Boarding" )
self:AddTransition( "Boarding", "Board", "Boarding" )
self:AddTransition( "Boarding", "Loaded", "Loaded" )
self:AddTransition( "Loaded", "Unload", "Unboarding" )
self:AddTransition( "Unboarding", "Unboard", "Unboarding" )
self:AddTransition( "Unboarding", "Unloaded", "Unloaded" )
self:AddTransition( "*", "Landed", "*" )
self:AddTransition( "*", "Queue", "*" )
self:AddTransition( "*", "Orbit" , "*" )
self:AddTransition( "*", "Home" , "*" )
self:AddTransition( "*", "Destroyed", "Destroyed" )
--- Pickup Handler OnBefore for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] OnBeforePickup
-- @param #AI_CARGO_HELICOPTER self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Point#COORDINATE Coordinate
-- @return #boolean
--- Pickup Handler OnAfter for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] OnAfterPickup
-- @param #AI_CARGO_HELICOPTER self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Point#COORDINATE Coordinate
--- Pickup Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] Pickup
-- @param #AI_CARGO_HELICOPTER self
-- @param Core.Point#COORDINATE Coordinate
--- Pickup Asynchronous Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] __Pickup
-- @param #AI_CARGO_HELICOPTER self
-- @param #number Delay
-- @param Core.Point#COORDINATE Coordinate
--- Deploy Handler OnBefore for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] OnBeforeDeploy
-- @param #AI_CARGO_HELICOPTER self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Point#COORDINATE Coordinate
-- @return #boolean
--- Deploy Handler OnAfter for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] OnAfterDeploy
-- @param #AI_CARGO_HELICOPTER self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Point#COORDINATE Coordinate
--- Deploy Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] Deploy
-- @param #AI_CARGO_HELICOPTER self
-- @param Core.Point#COORDINATE Coordinate
--- Deploy Asynchronous Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] __Deploy
-- @param #AI_CARGO_HELICOPTER self
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Delay
self:SetCarrier( Helicopter )
return self
end
function AI_CARGO_HELICOPTER:IsTransporting()
return self.Transporting == true
end
function AI_CARGO_HELICOPTER:IsRelocating()
return self.Relocating == true
end
--- Set the Carrier.
-- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @return #AI_CARGO_HELICOPTER
function AI_CARGO_HELICOPTER:SetCarrier( Helicopter )
local AICargo = self
self.Helicopter = Helicopter -- Wrapper.Group#GROUP
self.Helicopter:SetState( self.Helicopter, "AI_CARGO_HELICOPTER", self )
self.RoutePickup = false
self.RouteDeploy = false
Helicopter:HandleEvent( EVENTS.Dead )
Helicopter:HandleEvent( EVENTS.Hit )
Helicopter:HandleEvent( EVENTS.Land )
function Helicopter:OnEventDead( EventData )
local AICargoTroops = self:GetState( self, "AI_CARGO_HELICOPTER" )
self:F({AICargoTroops=AICargoTroops})
if AICargoTroops then
self:F({})
if not AICargoTroops:Is( "Loaded" ) then
-- There are enemies within combat range. Unload the Helicopter.
AICargoTroops:Destroyed()
end
end
end
function Helicopter:OnEventHit( EventData )
local AICargoTroops = self:GetState( self, "AI_CARGO_HELICOPTER" )
if AICargoTroops then
self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } )
if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then
-- There are enemies within combat range. Unload the Helicopter.
AICargoTroops:Unload()
end
end
end
function Helicopter:OnEventLand( EventData )
AICargo:Landed()
end
self.Coalition = self.Helicopter:GetCoalition()
self:SetControllable( Helicopter )
return self
end
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed
function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To )
if Helicopter and Helicopter:IsAlive() then
if self.RoutePickup == true then
self:Load( Helicopter:GetPointVec2() )
self.RoutePickup = false
self.Relocating = true
end
if self.RouteDeploy == true then
self:Unload( true )
self.RouteDeploy = false
self.Transporting = false
self.Relocating = false
end
end
end
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed
function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordinate )
local HelicopterInZone = false
if Helicopter and Helicopter:IsAlive() then
local Distance = Coordinate:DistanceFromPointVec2( Helicopter:GetCoordinate() )
if Distance > 500 then
self:__Queue( -10, Coordinate )
else
local ZoneFree = true
for Helicopter, ZoneQueue in pairs( AI_CARGO_QUEUE ) do
local ZoneQueue = ZoneQueue -- Core.Zone#ZONE_RADIUS
if ZoneQueue:IsCoordinateInZone( Coordinate ) then
ZoneFree = false
end
end
self:F({ZoneFree=ZoneFree})
if ZoneFree == true then
local ZoneQueue = ZONE_RADIUS:New( Helicopter:GetName(), Coordinate:GetVec2(), 100 )
AI_CARGO_QUEUE[Helicopter] = ZoneQueue
local Route = {}
-- local CoordinateFrom = Helicopter:GetCoordinate()
-- local WaypointFrom = CoordinateFrom:WaypointAir(
-- "RADIO",
-- POINT_VEC3.RoutePointType.TurningPoint,
-- POINT_VEC3.RoutePointAction.TurningPoint,
-- Speed,
-- true
-- )
-- Route[#Route+1] = WaypointFrom
local CoordinateTo = Coordinate
local WaypointTo = CoordinateTo:WaypointAir(
"RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
50,
true
)
Route[#Route+1] = WaypointTo
local Tasks = {}
Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() )
Route[#Route].task = Helicopter:TaskCombo( Tasks )
Route[#Route+1] = WaypointTo
-- Now route the helicopter
Helicopter:Route( Route, 0 )
else
self:__Queue( -10, Coordinate )
end
end
end
end
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed
function AI_CARGO_HELICOPTER:onafterOrbit( Helicopter, From, Event, To, Coordinate )
if Helicopter and Helicopter:IsAlive() then
if not self:IsTransporting() then
local Route = {}
-- local CoordinateFrom = Helicopter:GetCoordinate()
-- local WaypointFrom = CoordinateFrom:WaypointAir(
-- "RADIO",
-- POINT_VEC3.RoutePointType.TurningPoint,
-- POINT_VEC3.RoutePointAction.TurningPoint,
-- Speed,
-- true
-- )
-- Route[#Route+1] = WaypointFrom
local CoordinateTo = Coordinate
local WaypointTo = CoordinateTo:WaypointAir(
"RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
50,
true
)
Route[#Route+1] = WaypointTo
local Tasks = {}
Tasks[#Tasks+1] = Helicopter:TaskOrbitCircle( math.random( 30, 80 ), 0, CoordinateTo:GetRandomCoordinateInRadius( 800, 500 ) )
Route[#Route].task = Helicopter:TaskCombo( Tasks )
Route[#Route+1] = WaypointTo
-- Now route the helicopter
Helicopter:Route( Route, 0 )
end
end
end
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
function AI_CARGO_HELICOPTER:onbeforeLoad( Helicopter, From, Event, To, Coordinate )
local Boarding = false
if Helicopter and Helicopter:IsAlive() then
self.BoardingCount = 0
if Helicopter and Helicopter:IsAlive() then
self.Helicopter_Cargo = {}
for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do
local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT
for _, Cargo in pairs( self.CargoSet:GetSet() ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
self:F( { IsUnLoaded = Cargo:IsUnLoaded() } )
if Cargo:IsUnLoaded() then
if Cargo:IsInLoadRadius( HelicopterUnit:GetCoordinate() ) then
self:F( { "In radius", HelicopterUnit:GetName() } )
--Cargo:Ungroup()
Cargo:Board( HelicopterUnit, 25 )
self:__Board( 1, Cargo )
Boarding = true
-- So now this APCUnit has Cargo that is being loaded.
-- This will be used further in the logic to follow and to check cargo status.
self.Helicopter_Cargo[HelicopterUnit] = Cargo
break
end
end
end
end
end
end
return Boarding
end
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
function AI_CARGO_HELICOPTER:onafterBoard( Helicopter, From, Event, To, Cargo )
self:F( { APC, From, Event, To, Cargo } )
if Helicopter and Helicopter:IsAlive() then
self:F({ IsLoaded = Cargo:IsLoaded() } )
if not Cargo:IsLoaded() then
self:__Board( 10, Cargo )
else
self:__Loaded( 1, Cargo )
end
end
end
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
function AI_CARGO_HELICOPTER:onbeforeLoaded( Helicopter, From, Event, To, Cargo )
self:F( { APC, From, Event, To } )
local Loaded = true
if Helicopter and Helicopter:IsAlive() then
for HelicopterUnit, Cargo in pairs( self.Helicopter_Cargo ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed() } )
if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then
Loaded = false
end
end
end
return Loaded
end
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
function AI_CARGO_HELICOPTER:onafterUnload( Helicopter, From, Event, To, Deployed )
if Helicopter and Helicopter:IsAlive() then
for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do
local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT
for _, Cargo in pairs( HelicopterUnit:GetCargo() ) do
Cargo:UnBoard()
Cargo:SetDeployed( true )
self:__Unboard( 10, Cargo, Deployed )
end
end
end
end
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
function AI_CARGO_HELICOPTER:onafterUnboard( Helicopter, From, Event, To, Cargo, Deployed )
if Helicopter and Helicopter:IsAlive() then
if not Cargo:IsUnLoaded() then
self:__Unboard( 10, Cargo, Deployed )
else
self:__Unloaded( 1, Cargo, Deployed )
end
end
end
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
function AI_CARGO_HELICOPTER:onbeforeUnloaded( Helicopter, From, Event, To, Cargo, Deployed )
self:F( { APC, From, Event, To, Cargo:GetName(), Deployed = Deployed } )
local AllUnloaded = true
--Cargo:Regroup()
if Helicopter and Helicopter:IsAlive() then
for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do
local CargoCheck = self.Helicopter_Cargo[HelicopterUnit] -- Cargo.Cargo#CARGO
if CargoCheck then
self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } )
if CargoCheck:IsUnLoaded() == false then
AllUnloaded = false
break
end
end
end
if AllUnloaded == true then
if Deployed == true then
for HelicopterUnit, Cargo in pairs( self.Helicopter_Cargo ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
end
self.Helicopter_Cargo = {}
end
self.Helicopter = Helicopter
end
end
self:F( { AllUnloaded = AllUnloaded } )
return AllUnloaded
end
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
function AI_CARGO_HELICOPTER:onafterUnloaded( Helicopter, From, Event, To, Cargo, Deployed )
self:Orbit( Helicopter:GetCoordinate(), 50 )
AI_CARGO_QUEUE[Helicopter] = nil
end
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed
function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordinate )
if Helicopter and Helicopter:IsAlive() ~= nil then
Helicopter:Activate()
self.RoutePickup = true
Coordinate.y = math.random( 50, 200 )
local Route = {}
--- Calculate the target route point.
local CoordinateFrom = Helicopter:GetCoordinate()
local CoordinateTo = Coordinate
--- Create a route point of type air.
local WaypointFrom = CoordinateFrom:WaypointAir(
"RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
150,
true
)
--- Create a route point of type air.
local WaypointTo = CoordinateTo:WaypointAir(
"RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
150,
true
)
Route[#Route+1] = WaypointFrom
Route[#Route+1] = WaypointTo
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
Helicopter:WayPointInitialize( Route )
local Tasks = {}
Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() )
Route[#Route].task = Helicopter:TaskCombo( Tasks )
Route[#Route+1] = WaypointTo
-- Now route the helicopter
Helicopter:Route( Route, 1 )
self.Transporting = true
end
end
function AI_CARGO_HELICOPTER:_Deploy( AICargoHelicopter, Coordinate )
AICargoHelicopter:__Queue( -10, Coordinate, 100 )
end
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed
function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordinate )
if Helicopter and Helicopter:IsAlive() ~= nil then
self.RouteDeploy = true
local Route = {}
--- Calculate the target route point.
Coordinate.y = math.random( 50, 200 )
--- Create a route point of type air.
local CoordinateFrom = Helicopter:GetCoordinate()
local WaypointFrom = CoordinateFrom:WaypointAir(
"RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
150,
true
)
Route[#Route+1] = WaypointFrom
Route[#Route+1] = WaypointFrom
--- Create a route point of type air.
local CoordinateTo = Coordinate
local WaypointTo = CoordinateTo:WaypointAir(
"RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
150,
true
)
Route[#Route+1] = WaypointTo
Route[#Route+1] = WaypointTo
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
Helicopter:WayPointInitialize( Route )
local Tasks = {}
Tasks[#Tasks+1] = Helicopter:TaskFunction( "AI_CARGO_HELICOPTER._Deploy", self, Coordinate )
Tasks[#Tasks+1] = Helicopter:TaskOrbitCircle( math.random( 30, 100 ), 0, CoordinateTo:GetRandomCoordinateInRadius( 800, 500 ) )
--Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() )
Route[#Route].task = Helicopter:TaskCombo( Tasks )
Route[#Route+1] = WaypointTo
-- Now route the helicopter
Helicopter:Route( Route, 1 )
end
end
--- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed
function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinate )
if Helicopter and Helicopter:IsAlive() ~= nil then
self.RouteHome = true
local Route = {}
--- Calculate the target route point.
Coordinate.y = math.random( 50, 200 )
--- Create a route point of type air.
local CoordinateFrom = Helicopter:GetCoordinate()
local WaypointFrom = CoordinateFrom:WaypointAir(
"RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
150,
true
)
Route[#Route+1] = WaypointFrom
--- Create a route point of type air.
local CoordinateTo = Coordinate
local WaypointTo = CoordinateTo:WaypointAir(
"RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
150,
true
)
Route[#Route+1] = WaypointTo
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
Helicopter:WayPointInitialize( Route )
local Tasks = {}
Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() )
Route[#Route].task = Helicopter:TaskCombo( Tasks )
Route[#Route+1] = WaypointTo
-- Now route the helicopter
Helicopter:Route( Route, 0 )
end
end

View File

@@ -1,4 +1,6 @@
--- **AI** -- (R2.1) Build large **formations** of AI @{Group}s flying together.
--- **AI** -- (R2.2) - Build large airborne formations of aircraft.
--
-- ===
--
-- ![Banner Image](..\Presentations\AI_FORMATION\Dia1.JPG)
--
@@ -28,31 +30,20 @@
--
-- * @{#AI_FORMATION}: Create a formation from several @{GROUP}s.
--
-- ====
-- ===
--
-- # Demo Missions
--
-- ### [AI_FORMATION Demo Missions source code]()
--
-- ### [AI_FORMATION Demo Missions, only for beta testers]()
--
-- ### [ALL Demo Missions pack of the last release]()
--
-- ====
--
-- # YouTube Channel
--
--- ### [AI_FORMATION YouTube Channel]()
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/FOR%20-%20Formation)
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Contributions:
--
-- ### Authors:
--
-- * **FlightControl**: Concept, Design & Programming.
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0bFIJ9jIdYM22uaWmIN4oz)
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @module AI_Formation
@@ -68,7 +59,6 @@
-- @field #boolean ReportTargets If true, nearby targets are reported.
-- @Field DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the FollowGroup.
-- @field DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the FollowGroup.
-- @field Menu#MENU_CLIENT FollowMenuResumeMission
--- # AI_FORMATION class, extends @{Fsm#FSM_SET}
@@ -681,7 +671,7 @@ end
function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace ) --R2.1
self:F( { FollowGroupSet, From , Event ,To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace } )
FollowGroupSet:Flush()
FollowGroupSet:Flush( self )
local FollowSet = FollowGroupSet:GetSet()
@@ -960,7 +950,7 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1
-- @param Wrapper.Unit#UNIT ClientUnit
function( FollowGroup, Formation, ClientUnit, CT1, CV1, CT2, CV2 )
FollowGroup:OptionROTPassiveDefense()
FollowGroup:OptionROTEvadeFire()
FollowGroup:OptionROEReturnFire()
local GroupUnit = FollowGroup:GetUnit( 1 )

View File

@@ -1,4 +1,6 @@
--- **AI** -- **Air Patrolling or Staging.**
--- **AI** -- (R2.1) - Manages the independent process of Air Patrol for airplanes.
--
-- ===
--
-- ![Banner Image](..\Presentations\AI_PATROL\Dia1.JPG)
--
@@ -10,65 +12,27 @@
--
-- * @{#AI_PATROL_ZONE}: Perform a PATROL in a zone.
--
-- ====
-- ===
--
-- # Demo Missions
--
-- ### [AI_PATROL Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/PAT%20-%20Patrolling)
--
-- ### [AI_PATROL Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/PAT%20-%20Patrolling)
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
--
-- # YouTube Channel
--
-- ### [AI_PATROL YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl35HvYZKA6G22WMt7iI3zky)
--
-- ====
--
-- # **OPEN ISSUES**
--
-- 2017-01-17: When Spawned AI is located at an airbase, it will be routed first back to the airbase after take-off.
--
-- 2016-01-17:
-- -- Fixed problem with AI returning to base too early and unexpected.
-- -- ReSpawning of AI will reset the AI_PATROL and derived classes.
-- -- Checked the correct workings of SCHEDULER, and it DOES work correctly.
--
-- ====
--
-- # **API CHANGE HISTORY**
--
-- The underlying change log documents the API changes. Please read this carefully. The following notation is used:
--
-- * **Added** parts are expressed in bold type face.
-- * _Removed_ parts are expressed in italic type face.
--
-- Hereby the change log:
--
-- 2017-01-17: Rename of class: **AI\_PATROL\_ZONE** is the new name for the old _AI\_PATROLZONE_.
--
-- 2017-01-15: Complete revision. AI_PATROL_ZONE is the base class for other AI_PATROL like classes.
--
-- 2016-09-01: Initial class and API.
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/PAT%20-%20Patrolling)
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl35HvYZKA6G22WMt7iI3zky)
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Testing and API concept review.
--
-- ### Authors:
--
-- * **FlightControl**: Design & Programming.
-- ===
--
-- @module AI_Patrol
--- AI_PATROL_ZONE class
-- @type AI_PATROL_ZONE
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling.
@@ -77,7 +41,7 @@
-- @field Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @field Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @field Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @field Functional.Spawn#SPAWN CoordTest
-- @field Core.Spawn#SPAWN CoordTest
-- @extends Core.Fsm#FSM_CONTROLLABLE
--- # AI_PATROL_ZONE class, extends @{Fsm#FSM_CONTROLLABLE}
@@ -158,7 +122,7 @@
-- * @{#AI_PATROL_ZONE.SetDetectionOn}(): Set the detection on. The AI will detect for targets.
-- * @{#AI_PATROL_ZONE.SetDetectionOff}(): Set the detection off, the AI will not detect for targets. The existing target list will NOT be erased.
--
-- The detection frequency can be set with @{#AI_PATROL_ZONE.SetDetectionInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection.
-- The detection frequency can be set with @{#AI_PATROL_ZONE.SetRefreshTimeInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection.
-- Use the method @{#AI_PATROL_ZONE.GetDetectedUnits}() to obtain a list of the @{Unit}s detected by the AI.
--
-- The detection can be filtered to potential targets in a specific zone.
@@ -217,7 +181,7 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
-- defafult PatrolAltType to "RADIO" if not specified
self.PatrolAltType = PatrolAltType or "RADIO"
self:SetDetectionInterval( 30 )
self:SetRefreshTimeInterval( 30 )
self.CheckStatus = true
@@ -574,7 +538,7 @@ end
-- @param #AI_PATROL_ZONE self
-- @param #number Seconds The interval in seconds.
-- @return #AI_PATROL_ZONE self
function AI_PATROL_ZONE:SetDetectionInterval( Seconds )
function AI_PATROL_ZONE:SetRefreshTimeInterval( Seconds )
self:F2()
if Seconds then
@@ -621,13 +585,13 @@ end
-- 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.
-- Once the time is finished, the old AI will return to the base.
-- @param #AI_PATROL_ZONE self
-- @param #number PatrolFuelTresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
-- @param #number PatrolFuelThresholdPercentage The treshold 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.
-- @return #AI_PATROL_ZONE self
function AI_PATROL_ZONE:ManageFuel( PatrolFuelTresholdPercentage, PatrolOutOfFuelOrbitTime )
function AI_PATROL_ZONE:ManageFuel( PatrolFuelThresholdPercentage, PatrolOutOfFuelOrbitTime )
self.PatrolManageFuel = true
self.PatrolFuelTresholdPercentage = PatrolFuelTresholdPercentage
self.PatrolFuelThresholdPercentage = PatrolFuelThresholdPercentage
self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime
return self
@@ -640,12 +604,12 @@ end
-- 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.
-- @param #AI_PATROL_ZONE self
-- @param #number PatrolDamageTreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged.
-- @param #number PatrolDamageThreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged.
-- @return #AI_PATROL_ZONE self
function AI_PATROL_ZONE:ManageDamage( PatrolDamageTreshold )
function AI_PATROL_ZONE:ManageDamage( PatrolDamageThreshold )
self.PatrolManageDamage = true
self.PatrolDamageTreshold = PatrolDamageTreshold
self.PatrolDamageThreshold = PatrolDamageThreshold
return self
end
@@ -778,7 +742,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TakeOffParking,
POINT_VEC3.RoutePointAction.FromParkingArea,
@@ -793,7 +757,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -819,7 +783,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
--- Create a route point of type air.
local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir(
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -861,10 +825,9 @@ function AI_PATROL_ZONE:onafterStatus()
local RTB = false
local Fuel = self.Controllable:GetUnit(1):GetFuel()
if Fuel < self.PatrolFuelTresholdPercentage then
if Fuel < self.PatrolFuelThresholdPercentage then
self:E( self.Controllable:GetName() .. " is out of fuel:" .. Fuel .. ", RTB!" )
local OldAIControllable = self.Controllable
local AIControllableTemplate = self.Controllable:GetTemplate()
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
local TimedOrbitTask = OldAIControllable:TaskControlled( OrbitTask, OldAIControllable:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil ) )
@@ -876,7 +839,7 @@ function AI_PATROL_ZONE:onafterStatus()
-- TODO: Check GROUP damage function.
local Damage = self.Controllable:GetLife()
if Damage <= self.PatrolDamageTreshold then
if Damage <= self.PatrolDamageThreshold then
self:E( self.Controllable:GetName() .. " is damaged:" .. Damage .. ", RTB!" )
RTB = true
end
@@ -907,7 +870,7 @@ function AI_PATROL_ZONE:onafterRTB()
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,

View File

@@ -70,19 +70,20 @@ do -- ACT_ACCOUNT
-- Inherits from BASE
local self = BASE:Inherit( self, FSM_PROCESS:New() ) -- Core.Fsm#FSM_PROCESS
self:AddTransition( "Assigned", "Start", "Waiting")
self:AddTransition( "*", "Wait", "Waiting")
self:AddTransition( "*", "Report", "Report")
self:AddTransition( "*", "Event", "Account")
self:AddTransition( "Account", "More", "Wait")
self:AddTransition( "Account", "NoMore", "Accounted")
self:AddTransition( "*", "Fail", "Failed")
self:AddTransition( "Assigned", "Start", "Waiting" )
self:AddTransition( "*", "Wait", "Waiting" )
self:AddTransition( "*", "Report", "Report" )
self:AddTransition( "*", "Event", "Account" )
self:AddTransition( "Account", "Player", "AccountForPlayer" )
self:AddTransition( "Account", "Other", "AccountForOther" )
self:AddTransition( { "Account", "AccountForPlayer", "AccountForOther" }, "More", "Wait" )
self:AddTransition( { "Account", "AccountForPlayer", "AccountForOther" }, "NoMore", "Accounted" )
self:AddTransition( "*", "Fail", "Failed" )
self:AddEndState( "Accounted" )
self:AddEndState( "Failed" )
self:SetStartState( "Assigned" )
return self
end
@@ -90,13 +91,15 @@ do -- ACT_ACCOUNT
--- StateMachine callback function
-- @param #ACT_ACCOUNT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ACCOUNT:onafterStart( ProcessUnit, From, Event, To )
self:HandleEvent( EVENTS.Dead, self.onfuncEventDead )
self:HandleEvent( EVENTS.Crash, self.onfuncEventCrash )
self:HandleEvent( EVENTS.Hit )
self:__Wait( 1 )
end
@@ -104,7 +107,7 @@ do -- ACT_ACCOUNT
--- StateMachine callback function
-- @param #ACT_ACCOUNT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -122,7 +125,7 @@ do -- ACT_ACCOUNT
--- StateMachine callback function
-- @param #ACT_ACCOUNT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -152,7 +155,6 @@ do -- ACT_ACCOUNT_DEADS
-- @extends #ACT_ACCOUNT
ACT_ACCOUNT_DEADS = {
ClassName = "ACT_ACCOUNT_DEADS",
TargetSetUnit = nil,
}
@@ -160,13 +162,10 @@ do -- ACT_ACCOUNT_DEADS
-- @param #ACT_ACCOUNT_DEADS self
-- @param Set#SET_UNIT TargetSetUnit
-- @param #string TaskName
function ACT_ACCOUNT_DEADS:New( TargetSetUnit, TaskName )
function ACT_ACCOUNT_DEADS:New()
-- Inherits from BASE
local self = BASE:Inherit( self, ACT_ACCOUNT:New() ) -- #ACT_ACCOUNT_DEADS
self.TargetSetUnit = TargetSetUnit
self.TaskName = TaskName
self.DisplayInterval = 30
self.DisplayCount = 30
self.DisplayMessage = true
@@ -178,65 +177,113 @@ do -- ACT_ACCOUNT_DEADS
function ACT_ACCOUNT_DEADS:Init( FsmAccount )
self.TargetSetUnit = FsmAccount.TargetSetUnit
self.TaskName = FsmAccount.TaskName
self.Task = self:GetTask()
self.TaskName = self.Task:GetName()
end
--- Process Events
--- StateMachine callback function
-- @param #ACT_ACCOUNT_DEADS self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ACCOUNT_DEADS:onenterReport( ProcessUnit, Task, From, Event, To )
self:E( { ProcessUnit, From, Event, To } )
self:Message( "Your group with assigned " .. self.TaskName .. " task has " .. self.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed." )
local MessageText = "Your group with assigned " .. self.TaskName .. " task has " .. Task.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed."
self:GetCommandCenter():MessageTypeToGroup( MessageText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
end
--- StateMachine callback function
-- @param #ACT_ACCOUNT_DEADS self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Tasking.Task#TASK Task
-- @param #string From
-- @param #string Event
-- @param #string To
function ACT_ACCOUNT_DEADS:onenterAccount( ProcessUnit, Task, From, Event, To, EventData )
self:T( { ProcessUnit, EventData, From, Event, To } )
-- @param Core.Event#EVENTDATA EventData
function ACT_ACCOUNT_DEADS:onafterEvent( ProcessUnit, Task, From, Event, To, EventData )
self:T( { ProcessUnit:GetName(), Task:GetName(), From, Event, To, EventData } )
self:T({self.Controllable})
self.TargetSetUnit:Flush()
self:T( { "Before sending Message", EventData.IniUnitName, self.TargetSetUnit:FindUnit( EventData.IniUnitName ) } )
if self.TargetSetUnit:FindUnit( EventData.IniUnitName ) then
self:T( "Sending Message" )
local TaskGroup = ProcessUnit:GetGroup()
self.TargetSetUnit:Remove( EventData.IniUnitName )
self:Message( "You hit a target. Your group with assigned " .. self.TaskName .. " task has " .. self.TargetSetUnit:Count() .. " targets ( " .. self.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed." )
if Task.TargetSetUnit:FindUnit( EventData.IniUnitName ) then
local PlayerName = ProcessUnit:GetPlayerName()
local PlayerHit = self.PlayerHits and self.PlayerHits[EventData.IniUnitName]
if PlayerHit == PlayerName then
self:Player( EventData )
else
self:Other( EventData )
end
end
self:T( { "After sending Message" } )
end
--- StateMachine callback function
-- @param #ACT_ACCOUNT_DEADS self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Tasking.Task#TASK Task
-- @param #string From
-- @param #string Event
-- @param #string To
function ACT_ACCOUNT_DEADS:onafterEvent( ProcessUnit, Task, From, Event, To )
if self.TargetSetUnit:Count() > 0 then
-- @param Core.Event#EVENTDATA EventData
function ACT_ACCOUNT_DEADS:onenterAccountForPlayer( ProcessUnit, Task, From, Event, To, EventData )
self:T( { ProcessUnit:GetName(), Task:GetName(), From, Event, To, EventData } )
local TaskGroup = ProcessUnit:GetGroup()
Task.TargetSetUnit:Remove( EventData.IniUnitName )
local MessageText = "You have destroyed a target.\nYour group assigned with task " .. self.TaskName .. " has\n" .. Task.TargetSetUnit:Count() .. " targets ( " .. Task.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed."
self:GetCommandCenter():MessageTypeToGroup( MessageText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
local PlayerName = ProcessUnit:GetPlayerName()
Task:AddProgress( PlayerName, "Destroyed " .. EventData.IniTypeName, timer.getTime(), 1 )
if Task.TargetSetUnit:Count() > 0 then
self:__More( 1 )
else
self:__NoMore( 1 )
end
end
--- StateMachine callback function
-- @param #ACT_ACCOUNT_DEADS self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Tasking.Task#TASK Task
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Event#EVENTDATA EventData
function ACT_ACCOUNT_DEADS:onenterAccountForOther( ProcessUnit, Task, From, Event, To, EventData )
self:T( { ProcessUnit:GetName(), Task:GetName(), From, Event, To, EventData } )
local TaskGroup = ProcessUnit:GetGroup()
Task.TargetSetUnit:Remove( EventData.IniUnitName )
local MessageText = "One of the task targets has been destroyed.\nYour group assigned with task " .. self.TaskName .. " has\n" .. Task.TargetSetUnit:Count() .. " targets ( " .. Task.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed."
self:GetCommandCenter():MessageTypeToGroup( MessageText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
if Task.TargetSetUnit:Count() > 0 then
self:__More( 1 )
else
self:__NoMore( 1 )
end
end
--- DCS Events
--- @param #ACT_ACCOUNT_DEADS self
-- @param Core.Event#EVENTDATA EventData
function ACT_ACCOUNT_DEADS:OnEventHit( EventData )
self:T( { "EventDead", EventData } )
if EventData.IniPlayerName and EventData.TgtDCSUnitName then
self.PlayerHits = self.PlayerHits or {}
self.PlayerHits[EventData.TgtDCSUnitName] = EventData.IniPlayerName
end
end
--- @param #ACT_ACCOUNT_DEADS self
-- @param Event#EVENTDATA EventData
function ACT_ACCOUNT_DEADS:onfuncEventDead( EventData )
@@ -247,4 +294,16 @@ do -- ACT_ACCOUNT_DEADS
end
end
--- DCS Events
--- @param #ACT_ACCOUNT_DEADS self
-- @param Event#EVENTDATA EventData
function ACT_ACCOUNT_DEADS:onfuncEventCrash( EventData )
self:T( { "EventDead", EventData } )
if EventData.IniDCSUnit then
self:Event( EventData )
end
end
end -- ACT_ACCOUNT DEADS

View File

@@ -155,8 +155,7 @@ do -- ACT_ASSIGN_ACCEPT
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ASSIGN_ACCEPT:onafterStart( ProcessUnit, From, Event, To )
self:E( { ProcessUnit, From, Event, To } )
function ACT_ASSIGN_ACCEPT:onafterStart( ProcessUnit, Task, From, Event, To )
self:__Assign( 1 )
end
@@ -167,12 +166,8 @@ do -- ACT_ASSIGN_ACCEPT
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ASSIGN_ACCEPT:onenterAssigned( ProcessUnit, From, Event, To )
env.info( "in here" )
self:E( { ProcessUnit, From, Event, To } )
function ACT_ASSIGN_ACCEPT:onenterAssigned( ProcessUnit, Task, From, Event, To )
local ProcessGroup = ProcessUnit:GetGroup()
self.Task:Assign( ProcessUnit, ProcessUnit:GetPlayerName() )
end
@@ -193,99 +188,99 @@ do -- ACT_ASSIGN_MENU_ACCEPT
--- Init.
-- @param #ACT_ASSIGN_MENU_ACCEPT self
-- @param #string TaskName
-- @param #string TaskBriefing
-- @return #ACT_ASSIGN_MENU_ACCEPT self
function ACT_ASSIGN_MENU_ACCEPT:New( TaskName, TaskBriefing )
function ACT_ASSIGN_MENU_ACCEPT:New( TaskBriefing )
-- Inherits from BASE
local self = BASE:Inherit( self, ACT_ASSIGN:New() ) -- #ACT_ASSIGN_MENU_ACCEPT
self.TaskName = TaskName
self.TaskBriefing = TaskBriefing
return self
end
function ACT_ASSIGN_MENU_ACCEPT:Init( FsmAssign )
self.TaskName = FsmAssign.TaskName
self.TaskBriefing = FsmAssign.TaskBriefing
end
--- Creates a new task assignment state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator.
-- @param #ACT_ASSIGN_MENU_ACCEPT self
-- @param #string TaskName
-- @param #string TaskBriefing
-- @return #ACT_ASSIGN_MENU_ACCEPT self
function ACT_ASSIGN_MENU_ACCEPT:Init( TaskName, TaskBriefing )
function ACT_ASSIGN_MENU_ACCEPT:Init( TaskBriefing )
self.TaskBriefing = TaskBriefing
self.TaskName = TaskName
return self
end
--- StateMachine callback function
-- @param #ACT_ASSIGN_MENU_ACCEPT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ASSIGN_MENU_ACCEPT:onafterStart( ProcessUnit, From, Event, To )
self:E( { ProcessUnit, From, Event, To } )
function ACT_ASSIGN_MENU_ACCEPT:onafterStart( ProcessUnit, Task, From, Event, To )
self:Message( "Access the radio menu to accept the task. You have 30 seconds or the assignment will be cancelled." )
self:GetCommandCenter():MessageToGroup( "Task " .. self.Task:GetName() .. " has been assigned to you and your group!\nRead the briefing and use the Radio Menu (F10) / Task ... CONFIRMATION menu to accept or reject the task.\nYou have 2 minutes to accept, or the task assignment will be cancelled!", ProcessUnit:GetGroup(), 120 )
local ProcessGroup = ProcessUnit:GetGroup()
local TaskGroup = ProcessUnit:GetGroup()
self.Menu = MENU_GROUP:New( TaskGroup, "Task " .. self.Task:GetName() .. " CONFIRMATION" )
self.MenuAcceptTask = MENU_GROUP_COMMAND:New( TaskGroup, "Accept task " .. self.Task:GetName(), self.Menu, self.MenuAssign, self, TaskGroup )
self.MenuRejectTask = MENU_GROUP_COMMAND:New( TaskGroup, "Reject task " .. self.Task:GetName(), self.Menu, self.MenuReject, self, TaskGroup )
self.Menu = MENU_GROUP:New( ProcessGroup, "Task " .. self.TaskName .. " acceptance" )
self.MenuAcceptTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Accept task " .. self.TaskName, self.Menu, self.MenuAssign, self )
self.MenuRejectTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Reject task " .. self.TaskName, self.Menu, self.MenuReject, self )
self:__Reject( 120, TaskGroup )
end
--- Menu function.
-- @param #ACT_ASSIGN_MENU_ACCEPT self
function ACT_ASSIGN_MENU_ACCEPT:MenuAssign()
self:E( )
function ACT_ASSIGN_MENU_ACCEPT:MenuAssign( TaskGroup )
self:__Assign( 1 )
self:__Assign( -1, TaskGroup )
end
--- Menu function.
-- @param #ACT_ASSIGN_MENU_ACCEPT self
function ACT_ASSIGN_MENU_ACCEPT:MenuReject()
self:E( )
function ACT_ASSIGN_MENU_ACCEPT:MenuReject( TaskGroup )
self:__Reject( 1 )
self:__Reject( -1, TaskGroup )
end
--- StateMachine callback function
-- @param #ACT_ASSIGN_MENU_ACCEPT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ASSIGN_MENU_ACCEPT:onafterAssign( ProcessUnit, From, Event, To )
self:E( { ProcessUnit.UnitNameFrom, Event, To } )
function ACT_ASSIGN_MENU_ACCEPT:onafterAssign( ProcessUnit, Task, From, Event, To, TaskGroup )
self.Menu:Remove()
end
--- StateMachine callback function
-- @param #ACT_ASSIGN_MENU_ACCEPT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ASSIGN_MENU_ACCEPT:onafterReject( ProcessUnit, From, Event, To )
self:E( { ProcessUnit.UnitName, From, Event, To } )
function ACT_ASSIGN_MENU_ACCEPT:onafterReject( ProcessUnit, Task, From, Event, To, TaskGroup )
self:F( { TaskGroup = TaskGroup } )
self.Menu:Remove()
--TODO: need to resolve this problem ... it has to do with the events ...
--self.Task:UnAssignFromUnit( ProcessUnit )needs to become a callback funtion call upon the event
ProcessUnit:Destroy()
self.Task:RejectGroup( TaskGroup )
end
--- StateMachine callback function
-- @param #ACT_ASSIGN_ACCEPT self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ASSIGN_MENU_ACCEPT:onenterAssigned( ProcessUnit, Task, From, Event, To, TaskGroup )
--self.Task:AssignToGroup( TaskGroup )
self.Task:Assign( ProcessUnit, ProcessUnit:GetPlayerName() )
end
end -- ACT_ASSIGN_MENU_ACCEPT

View File

@@ -111,7 +111,6 @@ do -- ACT_ASSIST
local MissionMenu = self:GetMission():GetMenu( ProcessGroup )
local function MenuSmoke( MenuParam )
self:E( MenuParam )
local self = MenuParam.self
local SmokeColor = MenuParam.SmokeColor
self.SmokeColor = SmokeColor

View File

@@ -83,7 +83,7 @@ end
function PROCESS_JTAC:OnJTACMenuUpdate( Fsm, From, Event, To )
local function JTACMenuSpot( MenuParam )
self:E( MenuParam.TargetUnit.UnitName )
self:F( MenuParam.TargetUnit.UnitName )
local self = MenuParam.self
local TargetUnit = MenuParam.TargetUnit
@@ -91,7 +91,7 @@ function PROCESS_JTAC:OnJTACMenuUpdate( Fsm, From, Event, To )
end
local function JTACMenuCancel( MenuParam )
self:E( MenuParam )
self:F( MenuParam )
local self = MenuParam.self
local TargetUnit = MenuParam.TargetUnit
@@ -102,7 +102,7 @@ function PROCESS_JTAC:OnJTACMenuUpdate( Fsm, From, Event, To )
-- Loop each unit in the target set, and determine the threat levels map table.
local UnitThreatLevels = self.TargetSetUnit:GetUnitThreatLevels()
self:E( {"UnitThreadLevels", UnitThreatLevels } )
self:F( {"UnitThreadLevels", UnitThreatLevels } )
local JTACMenu = self.ProcessGroup:GetState( self.ProcessGroup, "JTACMenu" )

View File

@@ -97,7 +97,7 @@ end
function PROCESS_PICKUP:OnHitTarget( Fsm, From, Event, To, Event )
self.TargetSetUnit:Flush()
self.TargetSetUnit:Flush( self )
if self.TargetSetUnit:FindUnit( Event.IniUnitName ) then
self.TargetSetUnit:RemoveUnitsByName( Event.IniUnitName )

View File

@@ -123,16 +123,20 @@ do -- ACT_ROUTE
--- Set a Cancel Menu item.
-- @param #ACT_ROUTE self
-- @return #ACT_ROUTE
function ACT_ROUTE:SetMenuCancel( MenuGroup, MenuText, ParentMenu, MenuTime )
function ACT_ROUTE:SetMenuCancel( MenuGroup, MenuText, ParentMenu, MenuTime, MenuTag )
MENU_GROUP_COMMAND:New(
self.CancelMenuGroupCommand = MENU_GROUP_COMMAND:New(
MenuGroup,
MenuText,
ParentMenu,
self.MenuCancel,
self
):SetTime(MenuTime)
):SetTime( MenuTime ):SetTag( MenuTag )
ParentMenu:SetTime( MenuTime )
ParentMenu:Remove( MenuTime, MenuTag )
return self
end
@@ -154,42 +158,68 @@ do -- ACT_ROUTE
--- Get the routing text to be displayed.
-- The route mode determines the text displayed.
-- @param #ACT_ROUTE self
-- @param Wrapper.Unit#UNIT Controllable
-- @return #string
function ACT_ROUTE:GetRouteText( FromCoordinate )
function ACT_ROUTE:GetRouteText( Controllable )
local RouteText = ""
if self.Coordinate and self.RouteMode == "B" then
RouteText = "Route to " .. FromCoordinate:GetBRText( self.Coordinate ) .. " km."
local Coordinate = nil -- Core.Point#COORDINATE
if self.Coordinate then
Coordinate = self.Coordinate
end
if self.Coordinate and self.RouteMode == "C" then
RouteText = "Route to " .. self.Coordinate:ToString()
if self.Zone then
Coordinate = self.Zone:GetPointVec3( self.Altitude )
Coordinate:SetHeading( self.Heading )
end
if self.Zone and self.RouteMode == "B" then
local Coordinate = self.Zone:GetCoordinate()
RouteText = "Route to zone bearing " .. FromCoordinate:GetBRText( Coordinate ) .. " km."
local Task = self:GetTask() -- This is to dermine that the coordinates are for a specific task mode (A2A or A2G).
local CC = self:GetTask():GetMission():GetCommandCenter()
if CC then
if CC:IsModeWWII() then
-- Find closest reference point to the target.
local ShortestDistance = 0
local ShortestReferencePoint = nil
local ShortestReferenceName = ""
self:F( { CC.ReferencePoints } )
for ZoneName, Zone in pairs( CC.ReferencePoints ) do
self:F( { ZoneName = ZoneName } )
local Zone = Zone -- Core.Zone#ZONE
local ZoneCoord = Zone:GetCoordinate()
local ZoneDistance = ZoneCoord:Get2DDistance( self.Coordinate )
self:F( { ShortestDistance, ShortestReferenceName } )
if ShortestDistance == 0 or ZoneDistance < ShortestDistance then
ShortestDistance = ZoneDistance
ShortestReferencePoint = ZoneCoord
ShortestReferenceName = CC.ReferenceNames[ZoneName]
end
end
if ShortestReferencePoint then
RouteText = Coordinate:ToStringFromRP( ShortestReferencePoint, ShortestReferenceName, Controllable )
end
else
RouteText = Coordinate:ToString( Controllable, nil, Task )
end
end
if self.Zone and self.RouteMode == "C" then
local Coordinate = self.Zone:GetCoordinate()
RouteText = "Route to zone at " .. Coordinate:ToString()
end
return RouteText
end
function ACT_ROUTE:MenuCancel()
self:Cancel()
self:F("Cancelled")
self.CancelMenuGroupCommand:Remove()
self:__Cancel( 1 )
end
--- Task Events
--- StateMachine callback function
-- @param #ACT_ROUTE self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -201,7 +231,7 @@ do -- ACT_ROUTE
--- Check if the controllable has arrived.
-- @param #ACT_ROUTE self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @return #boolean
function ACT_ROUTE:onfuncHasArrived( ProcessUnit )
return false
@@ -209,15 +239,13 @@ do -- ACT_ROUTE
--- StateMachine callback function
-- @param #ACT_ROUTE self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ROUTE:onbeforeRoute( ProcessUnit, From, Event, To )
self:F( { "BeforeRoute 1", self.DisplayCount, self.DisplayInterval } )
if ProcessUnit:IsAlive() then
self:F( "BeforeRoute 2" )
local HasArrived = self:onfuncHasArrived( ProcessUnit ) -- Polymorphic
if self.DisplayCount >= self.DisplayInterval then
self:T( { HasArrived = HasArrived } )
@@ -229,8 +257,6 @@ do -- ACT_ROUTE
self.DisplayCount = self.DisplayCount + 1
end
self:T( { DisplayCount = self.DisplayCount } )
if HasArrived then
self:__Arrive( 1 )
else
@@ -313,7 +339,7 @@ do -- ACT_ROUTE_POINT
-- @param #ACT_ROUTE_POINT self
-- @param #number Range The Range to consider the arrival. Default is 10000 meters.
function ACT_ROUTE_POINT:SetRange( Range )
self:F2( { self.Range } )
self:F2( { Range } )
self.Range = Range or 10000
end
@@ -321,12 +347,13 @@ do -- ACT_ROUTE_POINT
-- @param #ACT_ROUTE_POINT self
-- @return #number The Range to consider the arrival. Default is 10000 meters.
function ACT_ROUTE_POINT:GetRange()
self:F2( { self.Range } )
return self.Range
end
--- Method override to check if the controllable has arrived.
-- @param #ACT_ROUTE_POINT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @return #boolean
function ACT_ROUTE_POINT:onfuncHasArrived( ProcessUnit )
@@ -335,7 +362,7 @@ do -- ACT_ROUTE_POINT
if Distance <= self.Range then
local RouteText = "You have arrived."
self:Message( RouteText )
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
return true
end
end
@@ -347,15 +374,15 @@ do -- ACT_ROUTE_POINT
--- StateMachine callback function
-- @param #ACT_ROUTE_POINT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ROUTE_POINT:onafterReport( ProcessUnit, From, Event, To )
local TaskUnitCoordinate = ProcessUnit:GetCoordinate()
local RouteText = self:GetRouteText( TaskUnitCoordinate )
self:Message( RouteText )
local RouteText = self:GetRouteText( ProcessUnit )
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Update )
end
end -- ACT_ROUTE_POINT
@@ -403,8 +430,12 @@ do -- ACT_ROUTE_ZONE
--- Set Zone
-- @param #ACT_ROUTE_ZONE self
-- @param Core.Zone#ZONE_BASE Zone The Zone object where to route to.
function ACT_ROUTE_ZONE:SetZone( Zone )
-- @param #number Altitude
-- @param #number Heading
function ACT_ROUTE_ZONE:SetZone( Zone, Altitude, Heading ) -- R2.2 Added altitude and heading
self.Zone = Zone
self.Altitude = Altitude
self.Heading = Heading
end
--- Get Zone
@@ -416,13 +447,13 @@ do -- ACT_ROUTE_ZONE
--- Method override to check if the controllable has arrived.
-- @param #ACT_ROUTE self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @return #boolean
function ACT_ROUTE_ZONE:onfuncHasArrived( ProcessUnit )
if ProcessUnit:IsInZone( self.Zone ) then
local RouteText = "You have arrived within the zone."
self:Message( RouteText )
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
end
return ProcessUnit:IsInZone( self.Zone )
@@ -432,18 +463,15 @@ do -- ACT_ROUTE_ZONE
--- StateMachine callback function
-- @param #ACT_ROUTE_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ROUTE_ZONE:onafterReport( ProcessUnit, From, Event, To )
self:F( { ProcessUnit = ProcessUnit } )
local ZoneVec2 = self.Zone:GetVec2()
local ZoneCoordinate = COORDINATE:New( ZoneVec2.x, ZoneVec2.y )
local TaskUnitVec2 = ProcessUnit:GetVec2()
local TaskUnitCoordinate = COORDINATE:New( TaskUnitVec2.x, TaskUnitVec2.y )
local RouteText = self:GetRouteText( TaskUnitCoordinate )
self:Message( RouteText )
local RouteText = self:GetRouteText( ProcessUnit )
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Update )
end
end -- ACT_ROUTE_ZONE

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,316 @@
--- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object.
--
-- ===
--
-- ![Banner Image](..\Presentations\CARGO\Dia1.JPG)
--
-- ===
--
-- ### [Demo Missions]()
--
-- ### [YouTube Playlist]()
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @module CargoCrate
do -- CARGO_CRATE
--- Models the behaviour of cargo crates, which can be slingloaded and boarded on helicopters.
-- @type CARGO_CRATE
-- @extends Cargo.Cargo#CARGO_REPRESENTABLE
--- # CARGO\_CRATE class, extends @{#CARGO_REPRESENTABLE}
--
-- The CARGO\_CRATE class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier.
-- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_CRATE objects to and from carriers.
--
-- ===
--
-- @field #CARGO_CRATE
CARGO_CRATE = {
ClassName = "CARGO_CRATE"
}
--- CARGO_CRATE Constructor.
-- @param #CARGO_CRATE self
-- @param Wrapper.Static#STATIC CargoStatic
-- @param #string Type
-- @param #string Name
-- @param #number LoadRadius (optional)
-- @param #number NearRadius (optional)
-- @return #CARGO_CRATE
function CARGO_CRATE:New( CargoStatic, Type, Name, LoadRadius, NearRadius )
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, LoadRadius, NearRadius ) ) -- #CARGO_CRATE
self:F( { Type, Name, NearRadius } )
self.CargoObject = CargoStatic -- Wrapper.Static#STATIC
-- Cargo objects are added to the _DATABASE and SET_CARGO objects.
_EVENTDISPATCHER:CreateEventNewCargo( self )
self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead )
self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead )
self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead )
self:SetEventPriority( 4 )
return self
end
--- @param #CARGO_CRATE self
-- @param Core.Event#EVENTDATA EventData
function CARGO_CRATE:OnEventCargoDead( EventData )
local Destroyed = false
if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() then
if self.CargoObject:GetName() == EventData.IniUnitName then
if not self.NoDestroy then
Destroyed = true
end
end
else
if self:IsLoaded() then
local CarrierName = self.CargoCarrier:GetName()
if CarrierName == EventData.IniDCSUnitName then
MESSAGE:New( "Cargo is lost from carrier " .. CarrierName, 15 ):ToAll()
Destroyed = true
self.CargoCarrier:ClearCargo()
end
end
end
if Destroyed then
self:I( { "Cargo crate destroyed: " .. self.CargoObject:GetName() } )
self:Destroyed()
end
end
--- Enter UnLoaded State.
-- @param #CARGO_CRATE self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2
function CARGO_CRATE:onenterUnLoaded( From, Event, To, ToPointVec2 )
--self:F( { ToPointVec2, From, Event, To } )
local Angle = 180
local Speed = 10
local Distance = 10
if From == "Loaded" then
local StartCoordinate = self.CargoCarrier:GetCoordinate()
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployCoord = StartCoordinate:Translate( Distance, CargoDeployHeading )
ToPointVec2 = ToPointVec2 or COORDINATE:NewFromVec2( { x= CargoDeployCoord.x, y = CargoDeployCoord.z } )
-- Respawn the group...
if self.CargoObject then
self.CargoObject:ReSpawnAt( ToPointVec2, 0 )
self.CargoCarrier = nil
end
end
if self.OnUnLoadedCallBack then
self.OnUnLoadedCallBack( self, unpack( self.OnUnLoadedParameters ) )
self.OnUnLoadedCallBack = nil
end
end
--- Loaded State.
-- @param #CARGO_CRATE self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
function CARGO_CRATE:onenterLoaded( From, Event, To, CargoCarrier )
--self:F( { From, Event, To, CargoCarrier } )
self.CargoCarrier = CargoCarrier
-- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects).
if self.CargoObject then
self:T("Destroying")
self.NoDestroy = true
self.CargoObject:Destroy()
--local Coordinate = self.CargoObject:GetCoordinate():GetRandomCoordinateInRadius( 50, 20 )
--self.CargoObject:ReSpawnAt( Coordinate, 0 )
end
end
--- Check if the cargo can be Boarded.
-- @param #CARGO_CRATE self
function CARGO_CRATE:CanBoard()
return false
end
--- Check if the cargo can be Unboarded.
-- @param #CARGO_CRATE self
function CARGO_CRATE:CanUnboard()
return false
end
--- Check if Cargo Crate is in the radius for the Cargo to be reported.
-- @param #CARGO self
-- @param Core.Point#COORDINATE Coordinate
-- @return #boolean true if the Cargo Crate is within the report radius.
function CARGO_CRATE:IsInReportRadius( Coordinate )
--self:F( { Coordinate, LoadRadius = self.LoadRadius } )
local Distance = 0
if self:IsUnLoaded() then
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
--self:T( Distance )
if Distance <= self.LoadRadius then
return true
end
end
return false
end
--- Check if Cargo Crate is in the radius for the Cargo to be Boarded or Loaded.
-- @param #CARGO self
-- @param Core.Point#Coordinate Coordinate
-- @return #boolean true if the Cargo Crate is within the loading radius.
function CARGO_CRATE:IsInLoadRadius( Coordinate )
--self:F( { Coordinate, LoadRadius = self.NearRadius } )
local Distance = 0
if self:IsUnLoaded() then
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
--self:T( Distance )
if Distance <= self.NearRadius then
return true
end
end
return false
end
--- Get the current Coordinate of the CargoGroup.
-- @param #CARGO_CRATE self
-- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup.
-- @return #nil There is no valid Cargo in the CargoGroup.
function CARGO_CRATE:GetCoordinate()
--self:F()
return self.CargoObject:GetCoordinate()
end
--- Check if the CargoGroup is alive.
-- @param #CARGO_CRATE self
-- @return #boolean true if the CargoGroup is alive.
-- @return #boolean false if the CargoGroup is dead.
function CARGO_CRATE:IsAlive()
local Alive = true
-- When the Cargo is Loaded, the Cargo is in the CargoCarrier, so we check if the CargoCarrier is alive.
-- When the Cargo is not Loaded, the Cargo is the CargoObject, so we check if the CargoObject is alive.
if self:IsLoaded() then
Alive = Alive == true and self.CargoCarrier:IsAlive()
else
Alive = Alive == true and self.CargoObject:IsAlive()
end
return Alive
end
--- Route Cargo to Coordinate and randomize locations.
-- @param #CARGO_CRATE self
-- @param Core.Point#COORDINATE Coordinate
function CARGO_CRATE:RouteTo( Coordinate )
self:F( {Coordinate = Coordinate } )
end
--- Check if Cargo is near to the Carrier.
-- The Cargo is near to the Carrier within NearRadius.
-- @param #CARGO_CRATE self
-- @param Wrapper.Group#GROUP CargoCarrier
-- @param #number NearRadius
-- @return #boolean The Cargo is near to the Carrier.
-- @return #nil The Cargo is not near to the Carrier.
function CARGO_CRATE:IsNear( CargoCarrier, NearRadius )
self:F( {NearRadius = NearRadius } )
return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius )
end
--- Respawn the CargoGroup.
-- @param #CARGO_CRATE self
function CARGO_CRATE:Respawn()
self:F( { "Respawning crate " .. self:GetName() } )
-- Respawn the group...
if self.CargoObject then
self.CargoObject:ReSpawn() -- A cargo destroy crates a DEAD event.
self:__Reset( -0.1 )
end
end
--- Respawn the CargoGroup.
-- @param #CARGO_CRATE self
function CARGO_CRATE:onafterReset()
self:F( { "Reset crate " .. self:GetName() } )
-- Respawn the group...
if self.CargoObject then
self:SetDeployed( false )
self:SetStartState( "UnLoaded" )
self.CargoCarrier = nil
-- Cargo objects are added to the _DATABASE and SET_CARGO objects.
_EVENTDISPATCHER:CreateEventNewCargo( self )
end
end
--- Get the transportation method of the Cargo.
-- @param #CARGO_CRATE self
-- @return #string The transportation method of the Cargo.
function CARGO_CRATE:GetTransportationMethod()
if self:IsLoaded() then
return "for unloading"
else
if self:IsUnLoaded() then
return "for loading"
else
if self:IsDeployed() then
return "delivered"
end
end
end
return ""
end
end

View File

@@ -0,0 +1,770 @@
--- **Cargo** -- Management of grouped cargo logistics, which are based on a @{Group} object.
--
-- ===
--
-- ![Banner Image](..\Presentations\CARGO\Dia1.JPG)
--
-- ===
--
-- ### [Demo Missions]()
--
-- ### [YouTube Playlist]()
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @module CargoGroup
do -- CARGO_GROUP
--- @type CARGO_GROUP
-- @extends Cargo.Cargo#CARGO_REPORTABLE
-- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects.
-- @field #string GroupName The name of the CargoGroup.
--- # CARGO\_GROUP class
--
-- The CARGO\_GROUP class defines a cargo that is represented by a @{Group} object within the simulator.
-- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers.
--
-- The above cargo classes are used by the AI\_CARGO\_ classes to allow AI groups to transport cargo:
--
-- * AI Armoured Personnel Carriers to transport cargo and engage in battles, using the @{AI.AI_Cargo_APC#AI_CARGO_APC} class.
-- * AI Helicopters to transport cargo, using the @{AI.AI_Cargo_Helicopter#AI_CARGO_HELICOPTER} class.
-- * AI Planes to transport cargo, using the @{AI.AI_Cargo_Plane#AI_CARGO_PLANE} class.
-- * AI Ships is planned.
--
-- The above cargo classes are also used by the TASK\_CARGO\_ classes to allow human players to transport cargo as part of a tasking:
--
-- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_TRANSPORT} to transport cargo by human players.
-- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_CSAR} to transport downed pilots by human players.
--
-- The
--
-- @field #CARGO_GROUP CARGO_GROUP
--
CARGO_GROUP = {
ClassName = "CARGO_GROUP",
}
--- CARGO_GROUP constructor.
-- This make a new CARGO_GROUP from a @{Group} object.
-- It will "ungroup" the group object within the sim, and will create a @{Set} of individual Unit objects.
-- @param #CARGO_GROUP self
-- @param Wrapper.Group#GROUP CargoGroup
-- @param #string Type
-- @param #string Name
-- @param #number LoadRadius (optional)
-- @param #number NearRadius (optional)
-- @return #CARGO_GROUP
function CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius )
local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, LoadRadius ) ) -- #CARGO_GROUP
self:F( { Type, Name, LoadRadius } )
self.CargoSet = SET_CARGO:New()
self.CargoGroup = CargoGroup
self.Grouped = true
self.CargoUnitTemplate = {}
self:SetDeployed( false )
local WeightGroup = 0
self.CargoGroup:Destroy()
local GroupName = CargoGroup:GetName()
self.CargoName = GroupName:match("(.*)~CARGO") or GroupName
self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ) )
local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
GroupTemplate.name = self.CargoName .. "#CARGO"
GroupTemplate.groupId = nil
GroupTemplate.units = {}
for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do
UnitTemplate.name = UnitTemplate.name .. "#CARGO"
local CargoUnitName = UnitTemplate.name
self.CargoUnitTemplate[CargoUnitName] = UnitTemplate
GroupTemplate.units[#GroupTemplate.units+1] = self.CargoUnitTemplate[CargoUnitName]
GroupTemplate.units[#GroupTemplate.units].unitId = nil
-- And we register the spawned unit as part of the CargoSet.
local Unit = UNIT:Register( CargoUnitName )
--local WeightUnit = Unit:GetDesc().massEmpty
--WeightGroup = WeightGroup + WeightUnit
local CargoUnit = CARGO_UNIT:New( Unit, Type, CargoUnitName, 10 )
self.CargoSet:Add( CargoUnitName, CargoUnit )
end
-- Then we register the new group in the database
self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID)
-- Now we spawn the new group based on the template created.
_DATABASE:Spawn( GroupTemplate )
self:SetWeight( WeightGroup )
self.CargoLimit = 10
self:T( { "Weight Cargo", WeightGroup } )
-- Cargo objects are added to the _DATABASE and SET_CARGO objects.
_EVENTDISPATCHER:CreateEventNewCargo( self )
self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead )
self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead )
self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead )
self:SetEventPriority( 4 )
return self
end
--- Ungroup the cargo group into individual groups with one unit.
-- This is required because by default a group will move in formation and this is really an issue for group control.
-- Therefore this method is made to be able to ungroup a group.
-- This works for ground only groups.
-- @param #CARGO_GROUP self
function CARGO_GROUP:Ungroup()
if self.Grouped == true then
self.Grouped = false
self.CargoGroup:Destroy()
for CargoUnitName, CargoUnit in pairs( self.CargoSet:GetSet() ) do
local CargoUnit = CargoUnit -- Cargo.CargoUnit#CARGO_UNIT
if CargoUnit:IsUnLoaded() then
local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
--local GroupName = env.getValueDictByKey( GroupTemplate.name )
-- We create a new group object with one unit...
-- First we prepare the template...
GroupTemplate.name = self.CargoName .. "#CARGO#" .. CargoUnitName
GroupTemplate.groupId = nil
if CargoUnit:IsUnLoaded() then
GroupTemplate.units = {}
GroupTemplate.units[1] = self.CargoUnitTemplate[CargoUnitName]
GroupTemplate.units[#GroupTemplate.units].unitId = nil
GroupTemplate.units[#GroupTemplate.units].x = CargoUnit:GetX()
GroupTemplate.units[#GroupTemplate.units].y = CargoUnit:GetY()
GroupTemplate.units[#GroupTemplate.units].heading = CargoUnit:GetHeading()
end
-- Then we register the new group in the database
local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID)
-- Now we spawn the new group based on the template created.
_DATABASE:Spawn( GroupTemplate )
end
end
end
end
--- Regroup the cargo group into one group with multiple unit.
-- This is required because by default a group will move in formation and this is really an issue for group control.
-- Therefore this method is made to be able to regroup a group.
-- This works for ground only groups.
-- @param #CARGO_GROUP self
function CARGO_GROUP:Regroup()
self:F("Regroup")
if self.Grouped == false then
self.Grouped = true
local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
GroupTemplate.name = self.CargoName .. "#CARGO"
GroupTemplate.groupId = nil
GroupTemplate.units = {}
for CargoUnitName, CargoUnit in pairs( self.CargoSet:GetSet() ) do
local CargoUnit = CargoUnit -- Cargo.CargoUnit#CARGO_UNIT
self:F( { CargoUnit:GetName(), UnLoaded = CargoUnit:IsUnLoaded() } )
if CargoUnit:IsUnLoaded() then
CargoUnit.CargoObject:Destroy()
GroupTemplate.units[#GroupTemplate.units+1] = self.CargoUnitTemplate[CargoUnitName]
GroupTemplate.units[#GroupTemplate.units].unitId = nil
GroupTemplate.units[#GroupTemplate.units].x = CargoUnit:GetX()
GroupTemplate.units[#GroupTemplate.units].y = CargoUnit:GetY()
GroupTemplate.units[#GroupTemplate.units].heading = CargoUnit:GetHeading()
end
end
-- Then we register the new group in the database
self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID)
self:F( { "Regroup", GroupTemplate } )
-- Now we spawn the new group based on the template created.
_DATABASE:Spawn( GroupTemplate )
end
end
--- @param #CARGO_GROUP self
-- @param Core.Event#EVENTDATA EventData
function CARGO_GROUP:OnEventCargoDead( EventData )
self:I( EventData )
local Destroyed = false
if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() or self:IsUnboarding() then
Destroyed = true
for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do
local Cargo = CargoData -- #CARGO
if Cargo:IsAlive() then
Destroyed = false
else
Cargo:Destroyed()
end
end
else
local CarrierName = self.CargoCarrier:GetName()
if CarrierName == EventData.IniDCSUnitName then
MESSAGE:New( "Cargo is lost from carrier " .. CarrierName, 15 ):ToAll()
Destroyed = true
self.CargoCarrier:ClearCargo()
end
end
if Destroyed then
self:Destroyed()
self:E( { "Cargo group destroyed" } )
end
end
--- Enter Boarding State.
-- @param #CARGO_GROUP self
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #string Event
-- @param #string From
-- @param #string To
function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
--self:F( { CargoCarrier.UnitName, From, Event, To } )
local NearRadius = NearRadius or 25
if From == "UnLoaded" then
-- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2
self.CargoSet:ForEach(
function( Cargo, ... )
Cargo:__Board( 1, CargoCarrier, NearRadius, ... )
end, ...
)
self:__Boarding( 1, CargoCarrier, NearRadius, ... )
end
end
--- Enter Loaded State.
-- @param #CARGO_GROUP self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... )
--self:F( { From, Event, To, CargoCarrier, ...} )
if From == "UnLoaded" then
-- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier.
for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do
Cargo:Load( CargoCarrier )
end
end
--self.CargoObject:Destroy()
self.CargoCarrier = CargoCarrier
self.CargoCarrier:AddCargo( self )
end
--- Leave Boarding State.
-- @param #CARGO_GROUP self
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #string Event
-- @param #string From
-- @param #string To
function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
--self:F( { CargoCarrier.UnitName, From, Event, To } )
local NearRadius = NearRadius or 100
local Boarded = true
local Cancelled = false
local Dead = true
self.CargoSet:Flush()
-- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2
for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do
self:T( { Cargo:GetName(), Cargo.current } )
if not Cargo:is( "Loaded" )
and (not Cargo:is( "Destroyed" )) then -- If one or more units of a group defined as CARGO_GROUP died, the CARGO_GROUP:Board() command does not trigger the CARGO_GRUOP:OnEnterLoaded() function.
Boarded = false
end
if Cargo:is( "UnLoaded" ) then
Cancelled = true
end
if not Cargo:is( "Destroyed" ) then
Dead = false
end
end
if not Dead then
if not Cancelled then
if not Boarded then
self:__Boarding( 1, CargoCarrier, NearRadius, ... )
else
self:F("Group Cargo is loaded")
self:__Load( 1, CargoCarrier, ... )
end
else
self:__CancelBoarding( 1, CargoCarrier, NearRadius, ... )
end
else
self:__Destroyed( 1, CargoCarrier, NearRadius, ... )
end
end
--- Enter UnBoarding State.
-- @param #CARGO_GROUP self
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #string Event
-- @param #string From
-- @param #string To
function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
--self:F( {From, Event, To, ToPointVec2, NearRadius } )
NearRadius = NearRadius or 25
local Timer = 1
if From == "Loaded" then
if self.CargoObject then
self.CargoObject:Destroy()
end
-- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2
self.CargoSet:ForEach(
--- @param Cargo.Cargo#CARGO Cargo
function( Cargo, NearRadius )
if not Cargo:IsDestroyed() then
Cargo:__UnBoard( Timer, ToPointVec2, NearRadius )
Timer = Timer + 3
end
end, { NearRadius }
)
self:__UnBoarding( 1, ToPointVec2, NearRadius, ... )
end
end
--- Leave UnBoarding State.
-- @param #CARGO_GROUP self
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #string Event
-- @param #string From
-- @param #string To
function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
--self:F( { From, Event, To, ToPointVec2, NearRadius } )
--local NearRadius = NearRadius or 25
local Angle = 180
local Speed = 10
local Distance = 5
if From == "UnBoarding" then
local UnBoarded = true
-- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2
for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do
self:T( { Cargo:GetName(), Cargo.current } )
if not Cargo:is( "UnLoaded" ) and not Cargo:IsDestroyed() then
UnBoarded = false
end
end
if UnBoarded then
return true
else
self:__UnBoarding( 1, ToPointVec2, NearRadius, ... )
end
return false
end
end
--- UnBoard Event.
-- @param #CARGO_GROUP self
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #string Event
-- @param #string From
-- @param #string To
function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
--self:F( { From, Event, To, ToPointVec2, NearRadius } )
--local NearRadius = NearRadius or 25
self:__UnLoad( 1, ToPointVec2, ... )
end
--- Enter UnLoaded State.
-- @param #CARGO_GROUP self
-- @param Core.Point#POINT_VEC2
-- @param #string Event
-- @param #string From
-- @param #string To
function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... )
--self:F( { From, Event, To, ToPointVec2 } )
if From == "Loaded" then
-- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2
self.CargoSet:ForEach(
function( Cargo )
--Cargo:UnLoad( ToPointVec2 )
local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(10)
Cargo:UnLoad( RandomVec2 )
end
)
end
self.CargoCarrier:RemoveCargo( self )
self.CargoCarrier = nil
end
--- Get the current Coordinate of the CargoGroup.
-- @param #CARGO_GROUP self
-- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup.
-- @return #nil There is no valid Cargo in the CargoGroup.
function CARGO_GROUP:GetCoordinate()
self:F()
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
if Cargo then
return Cargo.CargoObject:GetCoordinate()
end
return nil
end
--- Get the x position of the cargo.
-- @param #CARGO_GROUP self
-- @return #number
function CARGO:GetX()
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
if Cargo then
return Cargo:GetCoordinate().x
end
return nil
end
--- Get the y position of the cargo.
-- @param #CARGO_GROUP self
-- @return #number
function CARGO:GetY()
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
if Cargo then
return Cargo:GetCoordinate().z
end
return nil
end
--- Check if the CargoGroup is alive.
-- @param #CARGO_GROUP self
-- @return #boolean true if the CargoGroup is alive.
-- @return #boolean false if the CargoGroup is dead.
function CARGO_GROUP:IsAlive()
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
return Cargo ~= nil
end
--- Get the first alive Cargo Unit of the Cargo Group.
-- @param #CARGO_GROUP self
-- @return #CARGO_GROUP
function CARGO_GROUP:GetFirstAlive()
local CargoFirstAlive = nil
for _, Cargo in pairs( self.CargoSet:GetSet() ) do
if not Cargo:IsDestroyed() then
CargoFirstAlive = Cargo
break
end
end
return CargoFirstAlive
end
--- Get the amount of cargo units in the group.
-- @param #CARGO_GROUP self
-- @return #CARGO_GROUP
function CARGO_GROUP:GetCount()
return self.CargoSet:Count()
end
--- Get the amount of cargo units in the group.
-- @param #CARGO_GROUP self
-- @return #CARGO_GROUP
function CARGO_GROUP:GetGroup( Cargo )
local Cargo = Cargo or self:GetFirstAlive() -- Cargo.Cargo#CARGO
return Cargo.CargoObject:GetGroup()
end
--- Route Cargo to Coordinate and randomize locations.
-- @param #CARGO_GROUP self
-- @param Core.Point#COORDINATE Coordinate
function CARGO_GROUP:RouteTo( Coordinate )
--self:F( {Coordinate = Coordinate } )
-- For each Cargo within the CargoSet, route each object to the Coordinate
self.CargoSet:ForEach(
function( Cargo )
Cargo.CargoObject:RouteGroundTo( Coordinate, 10, "vee", 0 )
end
)
end
--- Check if Cargo is near to the Carrier.
-- The Cargo is near to the Carrier if the first unit of the Cargo Group is within NearRadius.
-- @param #CARGO_GROUP self
-- @param Wrapper.Group#GROUP CargoCarrier
-- @param #number NearRadius
-- @return #boolean The Cargo is near to the Carrier.
-- @return #nil The Cargo is not near to the Carrier.
function CARGO_GROUP:IsNear( CargoCarrier, NearRadius )
self:F( {NearRadius = NearRadius } )
for _, Cargo in pairs( self.CargoSet:GetSet() ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
if Cargo:IsAlive() then
if Cargo:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) then
self:F( "Near" )
return true
end
end
end
return nil
end
--- Check if Cargo Group is in the radius for the Cargo to be Boarded.
-- @param #CARGO_GROUP self
-- @param Core.Point#COORDINATE Coordinate
-- @return #boolean true if the Cargo Group is within the load radius.
function CARGO_GROUP:IsInLoadRadius( Coordinate )
--self:F( { Coordinate } )
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
if Cargo then
local Distance = 0
if Cargo:IsLoaded() then
Distance = Coordinate:Get2DDistance( Cargo.CargoCarrier:GetCoordinate() )
else
Distance = Coordinate:Get2DDistance( Cargo.CargoObject:GetCoordinate() )
end
self:F( { Distance = Distance, LoadRadius = self.LoadRadius } )
if Distance <= self.LoadRadius then
return true
else
return false
end
end
return nil
end
--- Check if Cargo Group is in the report radius.
-- @param #CARGO_GROUP self
-- @param Core.Point#Coordinate Coordinate
-- @return #boolean true if the Cargo Group is within the report radius.
function CARGO_GROUP:IsInReportRadius( Coordinate )
--self:F( { Coordinate } )
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
if Cargo then
self:F( { Cargo } )
local Distance = 0
if Cargo:IsUnLoaded() then
Distance = Coordinate:Get2DDistance( Cargo.CargoObject:GetCoordinate() )
--self:T( Distance )
if Distance <= self.LoadRadius then
return true
end
end
end
return nil
end
--- Respawn the CargoGroup.
-- @param #CARGO_GROUP self
function CARGO_GROUP:Respawn()
self:F( { "Respawning" } )
for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do
local Cargo = CargoData -- #CARGO
Cargo:Destroy()
Cargo:SetStartState( "UnLoaded" )
end
-- We iterate through the group template and for each unit in the template, we create a new group with one unit.
for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do
local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
local GroupName = env.getValueDictByKey( GroupTemplate.name )
-- We create a new group object with one unit...
-- First we prepare the template...
GroupTemplate.name = GroupName .. "#CARGO#" .. UnitID
GroupTemplate.groupId = nil
GroupTemplate.units = {}
GroupTemplate.units[1] = UnitTemplate
local UnitName = UnitTemplate.name .. "#CARGO"
GroupTemplate.units[1].name = UnitTemplate.name .. "#CARGO"
-- Then we register the new group in the database
local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID)
-- Now we spawn the new group based on the template created.
_DATABASE:Spawn( GroupTemplate )
-- And we register the spawned unit as part of the CargoSet.
local Unit = UNIT:FindByName( UnitName )
--local WeightUnit = Unit:GetDesc().massEmpty
--WeightGroup = WeightGroup + WeightUnit
local CargoUnit = CARGO_UNIT:New( Unit, Type, UnitName, 10 )
self.CargoSet:Add( UnitName, CargoUnit )
end
self:SetDeployed( false )
self:SetStartState( "UnLoaded" )
end
--- Signal a flare at the position of the CargoGroup.
-- @param #CARGO_GROUP self
-- @param Utilities.Utils#FLARECOLOR FlareColor
function CARGO_GROUP:Flare( FlareColor )
local Cargo = self.CargoSet:GetFirst() -- #CARGO
if Cargo then
Cargo:Flare( FlareColor )
end
end
--- Smoke the CargoGroup.
-- @param #CARGO_GROUP self
-- @param Utilities.Utils#SMOKECOLOR SmokeColor The color of the smoke.
-- @param #number Radius The radius of randomization around the center of the first element of the CargoGroup.
function CARGO_GROUP:Smoke( SmokeColor, Radius )
local Cargo = self.CargoSet:GetFirst() -- #CARGO
if Cargo then
Cargo:Smoke( SmokeColor, Radius )
end
end
--- Check if the first element of the CargoGroup is the given @{Zone}.
-- @param #CARGO self
-- @param Core.Zone#ZONE_BASE Zone
-- @return #boolean **true** if the first element of the CargoGroup is in the Zone
-- @return #boolean **false** if there is no element of the CargoGroup in the Zone.
function CARGO_GROUP:IsInZone( Zone )
--self:F( { Zone } )
local Cargo = self.CargoSet:GetFirst() -- #CARGO
if Cargo then
return Cargo:IsInZone( Zone )
end
return nil
end
--- Get the transportation method of the Cargo.
-- @param #CARGO_GROUP self
-- @return #string The transportation method of the Cargo.
function CARGO_GROUP:GetTransportationMethod()
if self:IsLoaded() then
return "for unboarding"
else
if self:IsUnLoaded() then
return "for boarding"
else
if self:IsDeployed() then
return "delivered"
end
end
end
return ""
end
end -- CARGO_GROUP

View File

@@ -0,0 +1,267 @@
--- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object. The cargo can only be slingloaded.
--
-- ===
--
-- ![Banner Image](..\Presentations\CARGO\Dia1.JPG)
--
-- ===
--
-- ### [Demo Missions]()
--
-- ### [YouTube Playlist]()
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @module CargoCrate
do -- CARGO_SLINGLOAD
--- Models the behaviour of cargo crates, which can only be slingloaded.
-- @type CARGO_SLINGLOAD
-- @extends Cargo.Cargo#CARGO_REPRESENTABLE
--- # CARGO\_CRATE class, extends @{#CARGO_REPRESENTABLE}
--
-- The CARGO\_CRATE class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier.
--
-- ===
--
-- @field #CARGO_SLINGLOAD
CARGO_SLINGLOAD = {
ClassName = "CARGO_SLINGLOAD"
}
--- CARGO_SLINGLOAD Constructor.
-- @param #CARGO_SLINGLOAD self
-- @param Wrapper.Static#STATIC CargoStatic
-- @param #string Type
-- @param #string Name
-- @param #number LoadRadius (optional)
-- @param #number NearRadius (optional)
-- @return #CARGO_SLINGLOAD
function CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius )
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, LoadRadius, NearRadius ) ) -- #CARGO_SLINGLOAD
self:F( { Type, Name, NearRadius } )
self.CargoObject = CargoStatic
-- Cargo objects are added to the _DATABASE and SET_CARGO objects.
_EVENTDISPATCHER:CreateEventNewCargo( self )
self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead )
self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead )
self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead )
self:SetEventPriority( 4 )
return self
end
--- @param #CARGO_SLINGLOAD self
-- @param Core.Event#EVENTDATA EventData
function CARGO_SLINGLOAD:OnEventCargoDead( EventData )
local Destroyed = false
if self:IsDestroyed() or self:IsUnLoaded() then
if self.CargoObject:GetName() == EventData.IniUnitName then
if not self.NoDestroy then
Destroyed = true
end
end
end
if Destroyed then
self:I( { "Cargo crate destroyed: " .. self.CargoObject:GetName() } )
self:Destroyed()
end
end
--- Check if the cargo can be Slingloaded.
-- @param #CARGO self
function CARGO:CanSlingload()
return true
end
--- Check if the cargo can be Boarded.
-- @param #CARGO_SLINGLOAD self
function CARGO_SLINGLOAD:CanBoard()
return false
end
--- Check if the cargo can be Unboarded.
-- @param #CARGO_SLINGLOAD self
function CARGO_SLINGLOAD:CanUnboard()
return false
end
--- Check if the cargo can be Loaded.
-- @param #CARGO_SLINGLOAD self
function CARGO_SLINGLOAD:CanLoad()
return false
end
--- Check if the cargo can be Unloaded.
-- @param #CARGO_SLINGLOAD self
function CARGO_SLINGLOAD:CanUnload()
return false
end
--- Check if Cargo Crate is in the radius for the Cargo to be reported.
-- @param #CARGO_SLINGLOAD self
-- @param Core.Point#COORDINATE Coordinate
-- @return #boolean true if the Cargo Crate is within the report radius.
function CARGO_SLINGLOAD:IsInReportRadius( Coordinate )
--self:F( { Coordinate, LoadRadius = self.LoadRadius } )
local Distance = 0
if self:IsUnLoaded() then
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
if Distance <= self.LoadRadius then
return true
end
end
return false
end
--- Check if Cargo Slingload is in the radius for the Cargo to be Boarded or Loaded.
-- @param #CARGO_SLINGLOAD self
-- @param Core.Point#COORDINATE Coordinate
-- @return #boolean true if the Cargo Slingload is within the loading radius.
function CARGO_SLINGLOAD:IsInLoadRadius( Coordinate )
--self:F( { Coordinate } )
local Distance = 0
if self:IsUnLoaded() then
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
if Distance <= self.NearRadius then
return true
end
end
return false
end
--- Get the current Coordinate of the CargoGroup.
-- @param #CARGO_SLINGLOAD self
-- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup.
-- @return #nil There is no valid Cargo in the CargoGroup.
function CARGO_SLINGLOAD:GetCoordinate()
--self:F()
return self.CargoObject:GetCoordinate()
end
--- Check if the CargoGroup is alive.
-- @param #CARGO_SLINGLOAD self
-- @return #boolean true if the CargoGroup is alive.
-- @return #boolean false if the CargoGroup is dead.
function CARGO_SLINGLOAD:IsAlive()
local Alive = true
-- When the Cargo is Loaded, the Cargo is in the CargoCarrier, so we check if the CargoCarrier is alive.
-- When the Cargo is not Loaded, the Cargo is the CargoObject, so we check if the CargoObject is alive.
if self:IsLoaded() then
Alive = Alive == true and self.CargoCarrier:IsAlive()
else
Alive = Alive == true and self.CargoObject:IsAlive()
end
return Alive
end
--- Route Cargo to Coordinate and randomize locations.
-- @param #CARGO_SLINGLOAD self
-- @param Core.Point#COORDINATE Coordinate
function CARGO_SLINGLOAD:RouteTo( Coordinate )
--self:F( {Coordinate = Coordinate } )
end
--- Check if Cargo is near to the Carrier.
-- The Cargo is near to the Carrier within NearRadius.
-- @param #CARGO_SLINGLOAD self
-- @param Wrapper.Group#GROUP CargoCarrier
-- @param #number NearRadius
-- @return #boolean The Cargo is near to the Carrier.
-- @return #nil The Cargo is not near to the Carrier.
function CARGO_SLINGLOAD:IsNear( CargoCarrier, NearRadius )
--self:F( {NearRadius = NearRadius } )
return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius )
end
--- Respawn the CargoGroup.
-- @param #CARGO_SLINGLOAD self
function CARGO_SLINGLOAD:Respawn()
--self:F( { "Respawning slingload " .. self:GetName() } )
-- Respawn the group...
if self.CargoObject then
self.CargoObject:ReSpawn() -- A cargo destroy crates a DEAD event.
self:__Reset( -0.1 )
end
end
--- Respawn the CargoGroup.
-- @param #CARGO_SLINGLOAD self
function CARGO_SLINGLOAD:onafterReset()
--self:F( { "Reset slingload " .. self:GetName() } )
-- Respawn the group...
if self.CargoObject then
self:SetDeployed( false )
self:SetStartState( "UnLoaded" )
self.CargoCarrier = nil
-- Cargo objects are added to the _DATABASE and SET_CARGO objects.
_EVENTDISPATCHER:CreateEventNewCargo( self )
end
end
--- Get the transportation method of the Cargo.
-- @param #CARGO_SLINGLOAD self
-- @return #string The transportation method of the Cargo.
function CARGO_SLINGLOAD:GetTransportationMethod()
if self:IsLoaded() then
return "for sling loading"
else
if self:IsUnLoaded() then
return "for sling loading"
else
if self:IsDeployed() then
return "delivered"
end
end
end
return ""
end
end

View File

@@ -0,0 +1,398 @@
--- **Cargo** -- Management of single cargo logistics, which are based on a @{Unit} object.
--
-- ===
--
-- ![Banner Image](..\Presentations\CARGO\Dia1.JPG)
--
-- ===
--
-- ### [Demo Missions]()
--
-- ### [YouTube Playlist]()
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @module CargoUnit
do -- CARGO_UNIT
--- Models CARGO in the form of units, which can be boarded, unboarded, loaded, unloaded.
-- @type CARGO_UNIT
-- @extends Cargo.Cargo#CARGO_REPRESENTABLE
--- # CARGO\_UNIT class, extends @{#CARGO_REPRESENTABLE}
--
-- The CARGO\_UNIT class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier.
-- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_UNIT objects to and from carriers.
--
-- ===
--
-- @field #CARGO_UNIT CARGO_UNIT
--
CARGO_UNIT = {
ClassName = "CARGO_UNIT"
}
--- CARGO_UNIT Constructor.
-- @param #CARGO_UNIT self
-- @param Wrapper.Unit#UNIT CargoUnit
-- @param #string Type
-- @param #string Name
-- @param #number Weight
-- @param #number LoadRadius (optional)
-- @param #number NearRadius (optional)
-- @return #CARGO_UNIT
function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, NearRadius )
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, NearRadius ) ) -- #CARGO_UNIT
self:I( { Type, Name, Weight, NearRadius } )
self:T( CargoUnit )
self.CargoObject = CargoUnit
self:T( self.ClassName )
self:SetEventPriority( 5 )
return self
end
--- Enter UnBoarding State.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } )
NearRadius = NearRadius or 25
local Angle = 180
local Speed = 60
local DeployDistance = 9
local RouteDistance = 60
if From == "Loaded" then
if not self:IsDestroyed() then
local CargoCarrier = self.CargoCarrier -- Wrapper.Controllable#CONTROLLABLE
if CargoCarrier:IsAlive() then
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoRoutePointVec2 = CargoCarrierPointVec2:Translate( RouteDistance, CargoDeployHeading )
-- if there is no ToPointVec2 given, then use the CargoRoutePointVec2
local FromDirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3( ToPointVec2 or CargoRoutePointVec2 )
local FromAngle = CargoCarrierPointVec2:GetAngleDegrees(FromDirectionVec3)
local FromPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, FromAngle )
--local CargoDeployPointVec2 = CargoCarrierPointVec2:GetRandomCoordinateInRadius( 10, 5 )
ToPointVec2 = ToPointVec2 or CargoCarrierPointVec2:GetRandomCoordinateInRadius( NearRadius, DeployDistance )
-- Respawn the group...
if self.CargoObject then
self.CargoObject:ReSpawnAt( FromPointVec2, CargoDeployHeading )
self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } )
self.CargoCarrier = nil
local Points = {}
-- From
Points[#Points+1] = FromPointVec2:WaypointGround( Speed, "Vee" )
-- To
Points[#Points+1] = ToPointVec2:WaypointGround( Speed, "Vee" )
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 1 )
self:__UnBoarding( 1, ToPointVec2, NearRadius )
end
else
-- the Carrier is dead. This cargo is dead too!
self:Destroyed()
end
end
end
end
--- Leave UnBoarding State.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } )
NearRadius = NearRadius or 100
local Angle = 180
local Speed = 10
local Distance = 5
if From == "UnBoarding" then
--if self:IsNear( ToPointVec2, NearRadius ) then
return true
--else
--self:__UnBoarding( 1, ToPointVec2, NearRadius )
--end
--return false
end
end
--- UnBoard Event.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } )
NearRadius = NearRadius or 100
self.CargoInAir = self.CargoObject:InAir()
self:T( self.CargoInAir )
-- Only unboard the cargo when the carrier is not in the air.
-- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
if not self.CargoInAir then
end
self:__UnLoad( 1, ToPointVec2, NearRadius )
end
--- Enter UnLoaded State.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2
function CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 )
self:F( { ToPointVec2, From, Event, To } )
local Angle = 180
local Speed = 10
local Distance = 5
if From == "Loaded" then
local StartPointVec2 = self.CargoCarrier:GetPointVec2()
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployCoord = StartPointVec2:Translate( Distance, CargoDeployHeading )
ToPointVec2 = ToPointVec2 or COORDINATE:New( CargoDeployCoord.x, CargoDeployCoord.z )
-- Respawn the group...
if self.CargoObject then
self.CargoObject:ReSpawnAt( ToPointVec2, 0 )
self.CargoCarrier = nil
end
end
if self.OnUnLoadedCallBack then
self.OnUnLoadedCallBack( self, unpack( self.OnUnLoadedParameters ) )
self.OnUnLoadedCallBack = nil
end
end
--- Board Event.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
function CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { From, Event, To, CargoCarrier, NearRadius } )
local NearRadius = NearRadius or 25
self.CargoInAir = self.CargoObject:InAir()
local Desc = self.CargoObject:GetDesc()
local MaxSpeed = Desc.speedMaxOffRoad
local TypeName = Desc.typeName
self:T( self.CargoInAir )
-- Only move the group to the carrier when the cargo is not in the air
-- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
if not self.CargoInAir then
if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
self:Load( CargoCarrier, NearRadius, ... )
else
if MaxSpeed and MaxSpeed == 0 or TypeName and TypeName == "Stinger comm" then
self:Load( CargoCarrier, NearRadius, ... )
else
local Speed = 90
local Angle = 180
local Distance = 5
NearRadius = NearRadius or 25
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading )
-- Set the CargoObject to state Green to ensure it is boarding!
self.CargoObject:OptionAlarmStateGreen()
local Points = {}
local PointStartVec2 = self.CargoObject:GetPointVec2()
Points[#Points+1] = PointStartVec2:WaypointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed )
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 2 )
self:__Boarding( -1, CargoCarrier, NearRadius )
self.RunCount = 0
end
end
end
end
--- Boarding Event.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Client#CLIENT CargoCarrier
-- @param #number NearRadius
function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
--self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } )
if CargoCarrier and CargoCarrier:IsAlive() and self.CargoObject and self.CargoObject:IsAlive() then
if CargoCarrier:InAir() == false then
if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
self:__Load( 1, CargoCarrier, ... )
else
self:__Boarding( -1, CargoCarrier, NearRadius, ... )
self.RunCount = self.RunCount + 1
if self.RunCount >= 40 then
self.RunCount = 0
local Speed = 90
local Angle = 180
local Distance = 5
NearRadius = NearRadius or 25
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading )
-- Set the CargoObject to state Green to ensure it is boarding!
self.CargoObject:OptionAlarmStateGreen()
local Points = {}
local PointStartVec2 = self.CargoObject:GetPointVec2()
Points[#Points+1] = PointStartVec2:WaypointGround( Speed, "Off road" )
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed, "Off road" )
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 0.2 )
end
end
else
self.CargoObject:MessageToGroup( "Cancelling Boarding... Get back on the ground!", 5, CargoCarrier:GetGroup(), self:GetName() )
self:CancelBoarding( CargoCarrier, NearRadius, ... )
self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) )
end
else
self:E("Something is wrong")
end
end
--- Enter Boarding State.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
function CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
--self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } )
local Speed = 90
local Angle = 180
local Distance = 5
local NearRadius = NearRadius or 25
if From == "UnLoaded" or From == "Boarding" then
end
end
--- Loaded State.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
function CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier )
self:F( { From, Event, To, CargoCarrier } )
self.CargoCarrier = CargoCarrier
-- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects).
if self.CargoObject then
self:T("Destroying")
self.CargoObject:Destroy()
--self.CargoObject:ReSpawnAt( COORDINATE:NewFromVec2( {x=0,y=0} ), 0 )
end
end
--- Get the transportation method of the Cargo.
-- @param #CARGO_UNIT self
-- @return #string The transportation method of the Cargo.
function CARGO_UNIT:GetTransportationMethod()
if self:IsLoaded() then
return "for unboarding"
else
if self:IsUnLoaded() then
return "for boarding"
else
if self:IsDeployed() then
return "delivered"
end
end
end
return ""
end
end -- CARGO_UNIT

View File

@@ -1,36 +1,13 @@
--- **Core** - BASE forms **the basis of the MOOSE framework**. Each class within the MOOSE framework derives from BASE.
--- **Core** -- BASE forms **the basis of the MOOSE framework**. Each class within the MOOSE framework derives from BASE.
--
-- ![Banner Image](..\Presentations\BASE\Dia1.JPG)
--
-- ===
--
-- The @{#BASE} class is the core root class from where every other class in moose is derived.
--
-- ===
--
-- # **API CHANGE HISTORY**
--
-- The underlying change log documents the API changes. Please read this carefully. The following notation is used:
--
-- * **Added** parts are expressed in bold type face.
-- * _Removed_ parts are expressed in italic type face.
--
-- YYYY-MM-DD: CLASS:**NewFunction**( Params ) replaces CLASS:_OldFunction_( Params )
-- YYYY-MM-DD: CLASS:**NewFunction( Params )** added
--
-- Hereby the change log:
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- * None.
--
-- ### Authors:
--
-- * **FlightControl**: Design & Programming
-- ===
--
-- @module Base
@@ -221,7 +198,17 @@ BASE = {
ClassID = 0,
Events = {},
States = {},
_ = {},
Debug = debug,
Scheduler = nil,
}
--- @field #BASE.__
BASE.__ = {}
--- @field #BASE._
BASE._ = {
Schedules = {} --- Contains the Schedulers Active
}
--- The Formation Class
@@ -247,47 +234,19 @@ FORMATION = {
-- @return #BASE
function BASE:New()
local self = routines.utils.deepCopy( self ) -- Create a new self instance
local MetaTable = {}
setmetatable( self, MetaTable )
self.__index = self
_ClassID = _ClassID + 1
self.ClassID = _ClassID
-- 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!
-- if rawget( self, "__" ) then
--setmetatable( self, { __index = self.__ } )
-- end
return self
end
function BASE:_Destructor()
--self:E("_Destructor")
--self:EventRemoveAll()
end
-- THIS IS WHY WE NEED LUA 5.2 ...
function BASE:_SetDestructor()
-- TODO: Okay, this is really technical...
-- When you set a proxy to a table to catch __gc, weak tables don't behave like weak...
-- Therefore, I am parking this logic until I've properly discussed all this with the community.
local proxy = newproxy(true)
local proxyMeta = getmetatable(proxy)
proxyMeta.__gc = function ()
env.info("In __gc for " .. self:GetClassNameAndID() )
if self._Destructor then
self:_Destructor()
end
end
-- keep the userdata from newproxy reachable until the object
-- table is about to be garbage-collected - then the __gc hook
-- will be invoked and the destructor called
rawset( self, '__proxy', proxy )
end
--- This is the worker method to inherit from a parent class.
-- @param #BASE self
-- @param Child is the Child class that inherits.
@@ -295,18 +254,40 @@ end
-- @return #BASE Child
function BASE:Inherit( Child, Parent )
local Child = routines.utils.deepCopy( Child )
--local Parent = routines.utils.deepCopy( Parent )
--local Parent = Parent
if Child ~= nil then
setmetatable( Child, Parent )
Child.__index = Child
-- 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!
if rawget( Child, "__" ) then
setmetatable( Child, { __index = Child.__ } )
setmetatable( Child.__, { __index = Parent } )
else
setmetatable( Child, { __index = Parent } )
end
--Child:_SetDestructor()
end
--self:T( 'Inherited from ' .. Parent.ClassName )
return Child
end
local function getParent( Child )
local Parent = nil
if Child.ClassName == 'BASE' then
Parent = nil
else
if rawget( Child, "__" ) then
Parent = getmetatable( Child.__ ).__index
else
Parent = getmetatable( Child ).__index
end
end
return Parent
end
--- This is the worker method to retrieve the Parent class.
-- Note that the Parent class must be passed to call the parent class method.
--
@@ -316,12 +297,91 @@ end
-- @param #BASE self
-- @param #BASE Child is the Child class from which the Parent class needs to be retrieved.
-- @return #BASE
function BASE:GetParent( Child )
local Parent = getmetatable( Child )
-- env.info('Inherited class of ' .. Child.ClassName .. ' is ' .. Parent.ClassName )
return Parent
function BASE:GetParent( Child, FromClass )
local Parent
-- BASE class has no parent
if Child.ClassName == 'BASE' then
Parent = nil
else
--self:E({FromClass = FromClass})
--self:E({Child = Child.ClassName})
if FromClass then
while( Child.ClassName ~= "BASE" and Child.ClassName ~= FromClass.ClassName ) do
Child = getParent( Child )
--self:E({Child.ClassName})
end
end
if Child.ClassName == 'BASE' then
Parent = nil
else
Parent = getParent( Child )
end
end
--self:E({Parent.ClassName})
return Parent
end
--- This is the worker method to check if an object is an (sub)instance of a class.
--
-- ### Examples:
--
-- * ZONE:New( 'some zone' ):IsInstanceOf( ZONE ) will return true
-- * ZONE:New( 'some zone' ):IsInstanceOf( 'ZONE' ) will return true
-- * ZONE:New( 'some zone' ):IsInstanceOf( 'zone' ) will return true
-- * ZONE:New( 'some zone' ):IsInstanceOf( 'BASE' ) will return true
--
-- * ZONE:New( 'some zone' ):IsInstanceOf( 'GROUP' ) will return false
--
-- @param #BASE self
-- @param ClassName is the name of the class or the class itself to run the check against
-- @return #boolean
function BASE:IsInstanceOf( ClassName )
-- Is className NOT a string ?
if type( ClassName ) ~= 'string' then
-- Is className a Moose class ?
if type( ClassName ) == 'table' and ClassName.ClassName ~= nil then
-- Get the name of the Moose class as a string
ClassName = ClassName.ClassName
-- className is neither a string nor a Moose class, throw an error
else
-- 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 )
self:E( err_str )
-- error( err_str )
return false
end
end
ClassName = string.upper( ClassName )
if string.upper( self.ClassName ) == ClassName then
return true
end
local Parent = getParent(self)
while Parent do
if string.upper( Parent.ClassName ) == ClassName then
return true
end
Parent = getParent( Parent )
end
return false
end
--- Get the ClassName + ClassID of the class instance.
-- The ClassName + ClassID is formatted as '%s#%09d'.
-- @param #BASE self
@@ -402,7 +462,7 @@ do -- Event Handling
-- @return #BASE
function BASE:UnHandleEvent( Event )
self:EventDispatcher():Remove( self, Event )
self:EventDispatcher():RemoveEvent( self, Event )
return self
end
@@ -585,6 +645,38 @@ function BASE:CreateEventCrash( EventTime, Initiator )
world.onEvent( Event )
end
--- Creation of a Dead Event.
-- @param #BASE self
-- @param Dcs.DCSTypes#Time EventTime The time stamp of the event.
-- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event.
function BASE:CreateEventDead( EventTime, Initiator )
self:F( { EventTime, Initiator } )
local Event = {
id = world.event.S_EVENT_DEAD,
time = EventTime,
initiator = Initiator,
}
world.onEvent( Event )
end
--- Creation of a Takeoff Event.
-- @param #BASE self
-- @param Dcs.DCSTypes#Time EventTime The time stamp of the event.
-- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event.
function BASE:CreateEventTakeoff( EventTime, Initiator )
self:F( { EventTime, Initiator } )
local Event = {
id = world.event.S_EVENT_TAKEOFF,
time = EventTime,
initiator = Initiator,
}
world.onEvent( Event )
end
-- TODO: Complete Dcs.DCSTypes#Event structure.
--- The main event handling function... This function captures all events generated for the class.
-- @param #BASE self
@@ -615,6 +707,96 @@ function BASE:onEvent(event)
end
end
do -- Scheduling
--- Schedule a new time event. Note that the schedule will only take place if the scheduler is *started*. Even for a single schedule event, the scheduler needs to be started also.
-- @param #BASE self
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
-- @return #number The ScheduleID of the planned schedule.
function BASE:ScheduleOnce( Start, SchedulerFunction, ... )
self:F2( { Start } )
self:T3( { ... } )
local ObjectName = "-"
ObjectName = self.ClassName .. self.ClassID
self:F3( { "ScheduleOnce: ", ObjectName, Start } )
if not self.Scheduler then
self.Scheduler = SCHEDULER:New( self )
end
self.Scheduler.SchedulerObject = self.Scheduler
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
self,
SchedulerFunction,
{ ... },
Start,
nil,
nil,
nil
)
self._.Schedules[#self._.Schedules+1] = ScheduleID
return self._.Schedules[#self._.Schedules]
end
--- Schedule a new time event. Note that the schedule will only take place if the scheduler is *started*. Even for a single schedule event, the scheduler needs to be started also.
-- @param #BASE self
-- @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 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 Stop Specifies the amount of seconds when the scheduler will be stopped.
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
-- @return #number The ScheduleID of the planned schedule.
function BASE:ScheduleRepeat( Start, Repeat, RandomizeFactor, Stop, SchedulerFunction, ... )
self:F2( { Start } )
self:T3( { ... } )
local ObjectName = "-"
ObjectName = self.ClassName .. self.ClassID
self:F3( { "ScheduleRepeat: ", ObjectName, Start, Repeat, RandomizeFactor, Stop } )
if not self.Scheduler then
self.Scheduler = SCHEDULER:New( self )
end
self.Scheduler.SchedulerObject = self.Scheduler
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
self,
SchedulerFunction,
{ ... },
Start,
Repeat,
RandomizeFactor,
Stop
)
self._.Schedules[#self._.Schedules+1] = ScheduleID
return self._.Schedules[#self._.Schedules]
end
--- Stops the Schedule.
-- @param #BASE self
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
function BASE:ScheduleStop( SchedulerFunction )
self:F3( { "ScheduleStop:" } )
_SCHEDULEDISPATCHER:Stop( self.Scheduler, self._.Schedules[SchedulerFunction] )
end
end
--- 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.
-- @param #BASE self
@@ -629,7 +811,6 @@ function BASE:SetState( Object, Key, Value )
self.States[ClassNameAndID] = self.States[ClassNameAndID] or {}
self.States[ClassNameAndID][Key] = Value
self:T2( { ClassNameAndID, Key, Value } )
return self.States[ClassNameAndID][Key]
end
@@ -640,7 +821,6 @@ end
-- @param #BASE self
-- @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 Value The value to is stored in the Object.
-- @return The Value retrieved.
function BASE:GetState( Object, Key )
@@ -648,7 +828,6 @@ function BASE:GetState( Object, Key )
if self.States[ClassNameAndID] then
local Value = self.States[ClassNameAndID][Key] or false
self:T2( { ClassNameAndID, Key, Value } )
return Value
end
@@ -669,7 +848,7 @@ end
-- TODO: Make trace function using variable parameters.
--- Set trace on or off
-- Note that when trace is off, no 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.
-- So tracing must be switched on manually in your mission if you are using Moose statically.
-- When moose is loading dynamically (for moose class development), tracing is switched on by default.
@@ -691,7 +870,7 @@ end
-- @return #boolean
function BASE:IsTrace()
if 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
else
return false
@@ -747,10 +926,10 @@ end
-- @param Arguments A #table or any field.
function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
if 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 debug.getinfo( 2, "nl" )
local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or debug.getinfo( 3, "l" )
local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or BASE.Debug.getinfo( 3, "l" )
local Function = "function"
if DebugInfoCurrent.name then
@@ -776,9 +955,9 @@ end
-- @param Arguments A #table or any field.
function BASE:F( Arguments )
if debug and _TraceOnOff then
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
local DebugInfoFrom = debug.getinfo( 3, "l" )
if BASE.Debug and _TraceOnOff then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
if _TraceLevel >= 1 then
self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom )
@@ -792,9 +971,9 @@ end
-- @param Arguments A #table or any field.
function BASE:F2( Arguments )
if debug and _TraceOnOff then
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
local DebugInfoFrom = debug.getinfo( 3, "l" )
if BASE.Debug and _TraceOnOff then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
if _TraceLevel >= 2 then
self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom )
@@ -807,9 +986,9 @@ end
-- @param Arguments A #table or any field.
function BASE:F3( Arguments )
if debug and _TraceOnOff then
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
local DebugInfoFrom = debug.getinfo( 3, "l" )
if BASE.Debug and _TraceOnOff then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
if _TraceLevel >= 3 then
self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom )
@@ -822,10 +1001,10 @@ end
-- @param Arguments A #table or any field.
function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
if 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 debug.getinfo( 2, "nl" )
local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or debug.getinfo( 3, "l" )
local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or BASE.Debug.getinfo( 3, "l" )
local Function = "function"
if DebugInfoCurrent.name then
@@ -851,9 +1030,9 @@ end
-- @param Arguments A #table or any field.
function BASE:T( Arguments )
if debug and _TraceOnOff then
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
local DebugInfoFrom = debug.getinfo( 3, "l" )
if BASE.Debug and _TraceOnOff then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
if _TraceLevel >= 1 then
self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom )
@@ -867,9 +1046,9 @@ end
-- @param Arguments A #table or any field.
function BASE:T2( Arguments )
if debug and _TraceOnOff then
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
local DebugInfoFrom = debug.getinfo( 3, "l" )
if BASE.Debug and _TraceOnOff then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
if _TraceLevel >= 2 then
self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom )
@@ -882,9 +1061,9 @@ end
-- @param Arguments A #table or any field.
function BASE:T3( Arguments )
if debug and _TraceOnOff then
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
local DebugInfoFrom = debug.getinfo( 3, "l" )
if BASE.Debug and _TraceOnOff then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
if _TraceLevel >= 3 then
self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom )
@@ -897,9 +1076,9 @@ end
-- @param Arguments A #table or any field.
function BASE:E( Arguments )
if debug then
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
local DebugInfoFrom = debug.getinfo( 3, "l" )
if BASE.Debug then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
local Function = "function"
if DebugInfoCurrent.name then
@@ -913,9 +1092,71 @@ function BASE:E( Arguments )
end
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
else
env.info( string.format( "%1s:%20s%05d(%s)" , "E", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
end
end
--- Log an information which will be traced always. Can be anywhere within the function logic.
-- @param #BASE self
-- @param Arguments A #table or any field.
function BASE:I( Arguments )
if BASE.Debug then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
local Function = "function"
if DebugInfoCurrent.name then
Function = DebugInfoCurrent.name
end
local LineCurrent = DebugInfoCurrent.currentline
local LineFrom = -1
if DebugInfoFrom then
LineFrom = DebugInfoFrom.currentline
end
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
else
env.info( string.format( "%1s:%20s%05d(%s)" , "I", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
end
end
--- old stuff
--function BASE:_Destructor()
-- --self:E("_Destructor")
--
-- --self:EventRemoveAll()
--end
-- THIS IS WHY WE NEED LUA 5.2 ...
--function BASE:_SetDestructor()
--
-- -- TODO: Okay, this is really technical...
-- -- When you set a proxy to a table to catch __gc, weak tables don't behave like weak...
-- -- Therefore, I am parking this logic until I've properly discussed all this with the community.
--
-- local proxy = newproxy(true)
-- local proxyMeta = getmetatable(proxy)
--
-- proxyMeta.__gc = function ()
-- env.info("In __gc for " .. self:GetClassNameAndID() )
-- if self._Destructor then
-- self:_Destructor()
-- end
-- end
--
-- -- keep the userdata from newproxy reachable until the object
-- -- table is about to be garbage-collected - then the __gc hook
-- -- will be invoked and the destructor called
-- rawset( self, '__proxy', proxy )
--
--end

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,20 @@
--- This module contains the DATABASE class, managing the database of mission objects.
--- **Core** -- DATABASE manages the database of mission objects.
--
-- ====
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @module Database
--- @type DATABASE
-- @extends Core.Base#BASE
--- # DATABASE class, extends @{Base#BASE}
--
-- 1) @{#DATABASE} class, extends @{Base#BASE}
-- ===================================================
-- Mission designers can use the DATABASE class to refer to:
--
-- * STATICS
@@ -17,30 +28,10 @@
--
-- On top, for internal MOOSE administration purposes, the DATBASE administers the Unit and Group TEMPLATES as defined within the Mission Editor.
--
-- Moose will automatically create one instance of the DATABASE class into the **global** object _DATABASE.
-- Moose refers to _DATABASE within the framework extensively, but you can also refer to the _DATABASE object within your missions if required.
-- The singleton object **_DATABASE** is automatically created by MOOSE, that administers all objects within the mission.
-- Moose refers to **_DATABASE** within the framework extensively, but you can also refer to the _DATABASE object within your missions if required.
--
-- 1.1) DATABASE iterators
-- -----------------------
-- You can iterate the database with the available iterator methods.
-- The iterator methods will walk the DATABASE set, and call for each element within the set a function that you provide.
-- The following iterator methods are currently available within the DATABASE:
--
-- * @{#DATABASE.ForEachUnit}: Calls a function for each @{UNIT} it finds within the DATABASE.
-- * @{#DATABASE.ForEachGroup}: Calls a function for each @{GROUP} it finds within the DATABASE.
-- * @{#DATABASE.ForEachPlayer}: Calls a function for each alive player it finds within the DATABASE.
-- * @{#DATABASE.ForEachPlayerJoined}: Calls a function for each joined player it finds within the DATABASE.
-- * @{#DATABASE.ForEachClient}: Calls a function for each @{CLIENT} it finds within the DATABASE.
-- * @{#DATABASE.ForEachClientAlive}: Calls a function for each alive @{CLIENT} it finds within the DATABASE.
--
-- ===
--
-- @module Database
-- @author FlightControl
--- DATABASE class
-- @type DATABASE
-- @extends Core.Base#BASE
-- @field #DATABASE
DATABASE = {
ClassName = "DATABASE",
Templates = {
@@ -56,12 +47,18 @@ DATABASE = {
GROUPS = {},
PLAYERS = {},
PLAYERSJOINED = {},
PLAYERUNITS = {},
CLIENTS = {},
CARGOS = {},
AIRBASES = {},
COUNTRY_ID = {},
COUNTRY_NAME = {},
NavPoints = {},
PLAYERSETTINGS = {},
ZONENAMES = {},
HITS = {},
DESTROYS = {},
ZONES = {},
}
local _DATABASECoalition =
@@ -96,46 +93,53 @@ function DATABASE:New()
self:HandleEvent( EVENTS.Birth, self._EventOnBirth )
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.Hit, self.AccountHits )
self:HandleEvent( EVENTS.NewCargo )
self:HandleEvent( EVENTS.DeleteCargo )
-- Follow alive players and clients
-- self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit )
--self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit ) -- This is not working anymore!, handling this through the birth event.
self:HandleEvent( EVENTS.PlayerLeaveUnit, self._EventOnPlayerLeaveUnit )
self:_RegisterTemplates()
self:_RegisterGroupsAndUnits()
self:_RegisterClients()
self:_RegisterStatics()
self:_RegisterPlayers()
--self:_RegisterPlayers()
self:_RegisterAirbases()
self.UNITS_Position = 0
--- @param #DATABASE self
local function CheckPlayers( self )
local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) }
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
--self:E( { "CoalitionData:", CoalitionData } )
for UnitId, UnitData in pairs( CoalitionData ) do
if UnitData and UnitData:isExist() then
local UnitName = UnitData:getName()
local PlayerName = UnitData:getPlayerName()
local PlayerUnit = UNIT:Find( UnitData )
--self:T( { "UnitData:", UnitData, UnitName, PlayerName, PlayerUnit } )
local UNITS_Count = #self.UNITS_Index
if UNITS_Count > 0 then
self.UNITS_Position = ( ( self.UNITS_Position <= UNITS_Count ) and self.UNITS_Position + 1 ) or 1
local PlayerUnit = self.UNITS[self.UNITS_Index[self.UNITS_Position]]
if PlayerUnit then
local UnitName = PlayerUnit:GetName()
local PlayerName = PlayerUnit:GetPlayerName()
--self:E( { UNITS_Count, self.UNITS_Position, UnitName, PlayerName } )
if PlayerName and PlayerName ~= "" then
if self.PLAYERS[PlayerName] == nil or self.PLAYERS[PlayerName] ~= UnitName then
self:E( { "Add player for unit:", UnitName, PlayerName } )
self:AddPlayer( UnitName, PlayerName )
--_EVENTDISPATCHER:CreateEventPlayerEnterUnit( PlayerUnit )
if PlayerName and PlayerName ~= "" then
if self.PLAYERS[PlayerName] == nil or self.PLAYERS[PlayerName] ~= UnitName then
--self:E( { "Add player for unit:", UnitName, PlayerName } )
self:AddPlayer( UnitName, PlayerName )
--_EVENTDISPATCHER:CreateEventPlayerEnterUnit( PlayerUnit )
local Settings = SETTINGS:Set( PlayerName )
Settings:SetPlayerMenu( PlayerUnit )
end
end
end
end
end
end
self:E( "Scheduling" )
--local PlayerCheckSchedule = SCHEDULER:New( nil, CheckPlayers, { self }, 2, 0.1 )
--self:E( "Scheduling" )
--PlayerCheckSchedule = SCHEDULER:New( nil, CheckPlayers, { self }, 1, 1 )
return self
end
@@ -200,6 +204,16 @@ function DATABASE:FindStatic( StaticName )
return StaticFound
end
--- Finds a AIRBASE based on the AirbaseName.
-- @param #DATABASE self
-- @param #string AirbaseName
-- @return Wrapper.Airbase#AIRBASE The found AIRBASE.
function DATABASE:FindAirbase( AirbaseName )
local AirbaseFound = self.AIRBASES[AirbaseName]
return AirbaseFound
end
--- Adds a Airbase based on the Airbase Name in the DATABASE.
-- @param #DATABASE self
-- @param #string AirbaseName The name of the airbase
@@ -229,35 +243,146 @@ function DATABASE:FindAirbase( AirbaseName )
return AirbaseFound
end
--- Adds a Cargo based on the Cargo Name in the DATABASE.
-- @param #DATABASE self
-- @param #string CargoName The name of the airbase
function DATABASE:AddCargo( Cargo )
if not self.CARGOS[Cargo.Name] then
self.CARGOS[Cargo.Name] = Cargo
do -- Zones
--- Finds a @{Zone} based on the zone name.
-- @param #DATABASE self
-- @param #string ZoneName The name of the zone.
-- @return Core.Zone#ZONE_BASE The found ZONE.
function DATABASE:FindZone( ZoneName )
local ZoneFound = self.ZONES[ZoneName]
return ZoneFound
end
--- Adds a @{Zone} based on the zone name in the DATABASE.
-- @param #DATABASE self
-- @param #string ZoneName The name of the zone.
-- @param Core.Zone#ZONE_BASE Zone The zone.
function DATABASE:AddZone( ZoneName, Zone )
if not self.ZONES[ZoneName] then
self.ZONES[ZoneName] = Zone
end
end
--- Deletes a @{Zone} from the DATABASE based on the zone name.
-- @param #DATABASE self
-- @param #string ZoneName The name of the zone.
function DATABASE:DeleteZone( ZoneName )
self.ZONES[ZoneName] = nil
end
--- Finds an @{Zone} based on the zone name in the DATABASE.
-- @param #DATABASE self
-- @param #string ZoneName
-- @return Core.Zone#ZONE_BASE The found @{Zone}.
function DATABASE:FindZone( ZoneName )
local ZoneFound = self.ZONES[ZoneName]
return ZoneFound
end
end
--- Deletes a Cargo from the DATABASE based on the Cargo Name.
-- @param #DATABASE self
-- @param #string CargoName The name of the airbase
function DATABASE:DeleteCargo( CargoName )
do -- cargo
self.CARGOS[CargoName] = nil
end
--- Adds a Cargo based on the Cargo Name in the DATABASE.
-- @param #DATABASE self
-- @param #string CargoName The name of the airbase
function DATABASE:AddCargo( Cargo )
if not self.CARGOS[Cargo.Name] then
self.CARGOS[Cargo.Name] = Cargo
end
end
--- Deletes a Cargo from the DATABASE based on the Cargo Name.
-- @param #DATABASE self
-- @param #string CargoName The name of the airbase
function DATABASE:DeleteCargo( CargoName )
self.CARGOS[CargoName] = nil
end
--- Finds an CARGO based on the CargoName.
-- @param #DATABASE self
-- @param #string CargoName
-- @return Wrapper.Cargo#CARGO The found CARGO.
function DATABASE:FindCargo( CargoName )
local CargoFound = self.CARGOS[CargoName]
return CargoFound
end
--- Checks if the Template name has a ~CARGO tag.
-- If yes, the group is a cargo.
-- @param #DATABASE self
-- @param #string TemplateName
-- @return #boolean
function DATABASE:IsCargo( TemplateName )
--- Finds an CARGO based on the CargoName.
-- @param #DATABASE self
-- @param #string CargoName
-- @return Wrapper.Cargo#CARGO The found CARGO.
function DATABASE:FindCargo( CargoName )
TemplateName = env.getValueDictByKey( TemplateName )
local Cargo = TemplateName:match( "~(CARGO)" )
local CargoFound = self.CARGOS[CargoName]
return CargoFound
end
return Cargo and Cargo == "CARGO"
end
--- Private method that registers new Static Templates within the DATABASE Object.
-- @param #DATABASE self
-- @return #DATABASE self
function DATABASE:RegisterCargos()
for CargoGroupName, CargoGroup in pairs( self.GROUPS ) do
if self:IsCargo( CargoGroupName ) then
local CargoInfo = CargoGroupName:match("~CARGO(.*)")
local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)")
local CargoName = CargoGroupName:match("(.*)~CARGO")
local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?")
local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName
local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") )
local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") )
self:F({"Register CargoGroup:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius})
CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius, NearRadius )
end
end
for CargoStaticName, CargoStatic in pairs( self.STATICS ) do
if self:IsCargo( CargoStaticName ) then
local CargoInfo = CargoStaticName:match("~CARGO(.*)")
local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)")
local CargoName = CargoStaticName:match("(.*)~CARGO")
local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?")
local Category = CargoParam and CargoParam:match( "C=([%a%d ]+),?")
local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName
local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") )
local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") )
if Category == "SLING" then
self:F({"Register CargoSlingload:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius})
CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius )
else
if Category == "CRATE" then
self:F({"Register CargoCrate:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius})
CARGO_CRATE:New( CargoStatic, Type, Name, LoadRadius, NearRadius )
end
end
end
end
end
end -- cargo
--- Finds a CLIENT based on the ClientName.
-- @param #DATABASE self
@@ -312,20 +437,60 @@ function DATABASE:AddPlayer( UnitName, PlayerName )
if PlayerName then
self:E( { "Add player for unit:", UnitName, PlayerName } )
self.PLAYERS[PlayerName] = UnitName
self.PLAYERUNITS[PlayerName] = self:FindUnit( UnitName )
self.PLAYERSJOINED[PlayerName] = PlayerName
end
end
--- Deletes a player from the DATABASE based on the Player Name.
-- @param #DATABASE self
function DATABASE:DeletePlayer( PlayerName )
function DATABASE:DeletePlayer( UnitName, PlayerName )
if PlayerName then
self:E( { "Clean player:", PlayerName } )
self.PLAYERS[PlayerName] = nil
self.PLAYERUNITS[PlayerName] = nil
end
end
--- Get the player table from the DATABASE.
-- The player table contains all unit names with the key the name of the player (PlayerName).
-- @param #DATABASE self
-- @usage
-- local Players = _DATABASE:GetPlayers()
-- for PlayerName, UnitName in pairs( Players ) do
-- ..
-- end
function DATABASE:GetPlayers()
return self.PLAYERS
end
--- Get the player table from the DATABASE, which contains all UNIT objects.
-- The player table contains all UNIT objects of the player with the key the name of the player (PlayerName).
-- @param #DATABASE self
-- @usage
-- local PlayerUnits = _DATABASE:GetPlayerUnits()
-- for PlayerName, PlayerUnit in pairs( PlayerUnits ) do
-- ..
-- end
function DATABASE:GetPlayerUnits()
return self.PLAYERUNITS
end
--- Get the player table from the DATABASE which have joined in the mission historically.
-- The player table contains all UNIT objects with the key the name of the player (PlayerName).
-- @param #DATABASE self
-- @usage
-- local PlayersJoined = _DATABASE:GetPlayersJoined()
-- for PlayerName, PlayerUnit in pairs( PlayersJoined ) do
-- ..
-- end
function DATABASE:GetPlayersJoined()
return self.PLAYERSJOINED
end
--- Instantiate new Groups within the DCSRTE.
-- This method expects EXACTLY the same structure as a structure within the ME, and needs 2 additional fields defined:
@@ -359,7 +524,12 @@ function DATABASE:Spawn( SpawnTemplate )
SpawnTemplate.CountryID = SpawnCountryID
SpawnTemplate.CategoryID = SpawnCategoryID
-- Ensure that for the spawned group and its units, there are GROUP and UNIT objects created in the DATABASE.
local SpawnGroup = self:AddGroup( SpawnTemplate.name )
for UnitID, UnitData in pairs( SpawnTemplate.units ) do
self:AddUnit( UnitData.name )
end
return SpawnGroup
end
@@ -384,13 +554,14 @@ end
--- Private method that registers new Group Templates within the DATABASE Object.
-- @param #DATABASE self
-- @param #table GroupTemplate
-- @param Dcs.DCScoalition#coalition.side CoalitionSide The coalition.side of the object.
-- @param Dcs.DCSObject#Object.Category CategoryID The Object.category of the object.
-- @param Dcs.DCScountry#country.id CountryID the country.id of the object
-- @return #DATABASE self
function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionID, CategoryID, CountryID )
function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID, GroupName )
local GroupTemplateName = env.getValueDictByKey(GroupTemplate.name)
local GroupTemplateName = GroupName or env.getValueDictByKey( GroupTemplate.name )
local TraceTable = {}
if not self.Templates.Groups[GroupTemplateName] then
self.Templates.Groups[GroupTemplateName] = {}
self.Templates.Groups[GroupTemplateName].Status = nil
@@ -402,7 +573,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionID, CategoryID
end
GroupTemplate.CategoryID = CategoryID
GroupTemplate.CoalitionID = CoalitionID
GroupTemplate.CoalitionID = CoalitionSide
GroupTemplate.CountryID = CountryID
self.Templates.Groups[GroupTemplateName].GroupName = GroupTemplateName
@@ -411,21 +582,10 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionID, CategoryID
self.Templates.Groups[GroupTemplateName].UnitCount = #GroupTemplate.units
self.Templates.Groups[GroupTemplateName].Units = GroupTemplate.units
self.Templates.Groups[GroupTemplateName].CategoryID = CategoryID
self.Templates.Groups[GroupTemplateName].CoalitionID = CoalitionID
self.Templates.Groups[GroupTemplateName].CoalitionID = CoalitionSide
self.Templates.Groups[GroupTemplateName].CountryID = CountryID
TraceTable[#TraceTable+1] = "Group"
TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].GroupName
TraceTable[#TraceTable+1] = "Coalition"
TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CoalitionID
TraceTable[#TraceTable+1] = "Category"
TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CategoryID
TraceTable[#TraceTable+1] = "Country"
TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CountryID
TraceTable[#TraceTable+1] = "Units"
local UnitNames = {}
for unit_num, UnitTemplate in pairs( GroupTemplate.units ) do
@@ -438,21 +598,27 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionID, CategoryID
self.Templates.Units[UnitTemplate.name].GroupTemplate = GroupTemplate
self.Templates.Units[UnitTemplate.name].GroupId = GroupTemplate.groupId
self.Templates.Units[UnitTemplate.name].CategoryID = CategoryID
self.Templates.Units[UnitTemplate.name].CoalitionID = CoalitionID
self.Templates.Units[UnitTemplate.name].CoalitionID = CoalitionSide
self.Templates.Units[UnitTemplate.name].CountryID = CountryID
if UnitTemplate.skill and (UnitTemplate.skill == "Client" or UnitTemplate.skill == "Player") then
self.Templates.ClientsByName[UnitTemplate.name] = UnitTemplate
self.Templates.ClientsByName[UnitTemplate.name].CategoryID = CategoryID
self.Templates.ClientsByName[UnitTemplate.name].CoalitionID = CoalitionID
self.Templates.ClientsByName[UnitTemplate.name].CoalitionID = CoalitionSide
self.Templates.ClientsByName[UnitTemplate.name].CountryID = CountryID
self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate
end
TraceTable[#TraceTable+1] = self.Templates.Units[UnitTemplate.name].UnitName
UnitNames[#UnitNames+1] = self.Templates.Units[UnitTemplate.name].UnitName
end
self:E( TraceTable )
self:I( { Group = self.Templates.Groups[GroupTemplateName].GroupName,
Coalition = self.Templates.Groups[GroupTemplateName].CoalitionID,
Category = self.Templates.Groups[GroupTemplateName].CategoryID,
Country = self.Templates.Groups[GroupTemplateName].CountryID,
Units = UnitNames
}
)
end
function DATABASE:GetGroupTemplate( GroupName )
@@ -469,8 +635,6 @@ end
-- @return #DATABASE self
function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID )
local TraceTable = {}
local StaticTemplateName = env.getValueDictByKey(StaticTemplate.name)
self.Templates.Statics[StaticTemplateName] = self.Templates.Statics[StaticTemplateName] or {}
@@ -486,28 +650,22 @@ function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, Category
self.Templates.Statics[StaticTemplateName].CoalitionID = CoalitionID
self.Templates.Statics[StaticTemplateName].CountryID = CountryID
self:I( { Static = self.Templates.Statics[StaticTemplateName].StaticName,
Coalition = self.Templates.Statics[StaticTemplateName].CoalitionID,
Category = self.Templates.Statics[StaticTemplateName].CategoryID,
Country = self.Templates.Statics[StaticTemplateName].CountryID
}
)
self:AddStatic( StaticTemplateName )
TraceTable[#TraceTable+1] = "Static"
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].GroupName
TraceTable[#TraceTable+1] = "Coalition"
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CoalitionID
TraceTable[#TraceTable+1] = "Category"
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CategoryID
TraceTable[#TraceTable+1] = "Country"
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CountryID
self:E( TraceTable )
end
--- @param #DATABASE self
function DATABASE:GetStaticUnitTemplate( StaticName )
local StaticTemplate = self.Templates.Statics[StaticName].UnitTemplate
StaticTemplate.SpawnCoalitionID = self.Templates.Statics[StaticName].CoalitionID
StaticTemplate.SpawnCategoryID = self.Templates.Statics[StaticName].CategoryID
StaticTemplate.SpawnCountryID = self.Templates.Statics[StaticName].CountryID
return StaticTemplate
return StaticTemplate, self.Templates.Statics[StaticName].CoalitionID, self.Templates.Statics[StaticName].CategoryID, self.Templates.Statics[StaticName].CountryID
end
@@ -615,6 +773,7 @@ end
function DATABASE:_RegisterStatics()
local CoalitionsData = { GroupsRed = coalition.getStaticObjects( coalition.side.RED ), GroupsBlue = coalition.getStaticObjects( coalition.side.BLUE ) }
self:E( { Statics = CoalitionsData } )
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
for DCSStaticId, DCSStatic in pairs( CoalitionData ) do
@@ -641,7 +800,7 @@ function DATABASE:_RegisterAirbases()
local DCSAirbaseName = DCSAirbase:getName()
self:E( { "Register Airbase:", DCSAirbaseName } )
self:E( { "Register Airbase:", DCSAirbaseName, DCSAirbase:getID() } )
self:AddAirbase( DCSAirbaseName )
end
end
@@ -667,7 +826,21 @@ function DATABASE:_EventOnBirth( Event )
self:AddGroup( Event.IniDCSGroupName )
end
end
self:_EventOnPlayerEnterUnit( Event )
if Event.IniObjectCategory == 1 then
Event.IniUnit = self:FindUnit( Event.IniDCSUnitName )
Event.IniGroup = self:FindGroup( Event.IniDCSGroupName )
local PlayerName = Event.IniUnit:GetPlayerName()
self:E( { "PlayerName:", PlayerName } )
if PlayerName then
self:E( { "Player Joined:", PlayerName } )
if not self.PLAYERS[PlayerName] then
self:AddPlayer( Event.IniUnitName, PlayerName )
end
local Settings = SETTINGS:Set( PlayerName )
Settings:SetPlayerMenu( Event.IniUnit )
--MENU_INDEX:Refresh( Event.IniGroup )
end
end
end
end
@@ -691,6 +864,8 @@ function DATABASE:_EventOnDeadOrCrash( Event )
end
end
end
self:AccountDestroys( Event )
end
@@ -700,14 +875,17 @@ end
function DATABASE:_EventOnPlayerEnterUnit( Event )
self:F2( { Event } )
if Event.IniUnit then
if Event.IniDCSUnit then
if Event.IniObjectCategory == 1 then
self:AddUnit( Event.IniDCSUnitName )
Event.IniUnit = self:FindUnit( Event.IniDCSUnitName )
self:AddGroup( Event.IniDCSGroupName )
local PlayerName = Event.IniUnit:GetPlayerName()
local PlayerName = Event.IniDCSUnit:getPlayerName()
if not self.PLAYERS[PlayerName] then
self:AddPlayer( Event.IniUnitName, PlayerName )
self:AddPlayer( Event.IniDCSUnitName, PlayerName )
end
local Settings = SETTINGS:Set( PlayerName )
Settings:SetPlayerMenu( Event.IniUnit )
end
end
end
@@ -722,8 +900,11 @@ function DATABASE:_EventOnPlayerLeaveUnit( Event )
if Event.IniUnit then
if Event.IniObjectCategory == 1 then
local PlayerName = Event.IniUnit:GetPlayerName()
if self.PLAYERS[PlayerName] then
self:DeletePlayer( PlayerName )
if PlayerName and self.PLAYERS[PlayerName] then
self:E( { "Player Left:", PlayerName } )
local Settings = SETTINGS:Set( PlayerName )
Settings:RemovePlayerMenu( Event.IniUnit )
self:DeletePlayer( Event.IniUnit, PlayerName )
end
end
end
@@ -808,10 +989,10 @@ end
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept a GROUP parameter.
-- @return #DATABASE self
function DATABASE:ForEachGroup( IteratorFunction, ... )
function DATABASE:ForEachGroup( IteratorFunction, FinalizeFunction, ... )
self:F2( arg )
self:ForEach( IteratorFunction, arg, self.GROUPS )
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.GROUPS )
return self
end
@@ -821,10 +1002,10 @@ end
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept the player name.
-- @return #DATABASE self
function DATABASE:ForEachPlayer( IteratorFunction, ... )
function DATABASE:ForEachPlayer( IteratorFunction, FinalizeFunction, ... )
self:F2( arg )
self:ForEach( IteratorFunction, arg, self.PLAYERS )
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.PLAYERS )
return self
end
@@ -834,14 +1015,27 @@ end
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept a UNIT parameter.
-- @return #DATABASE self
function DATABASE:ForEachPlayerJoined( IteratorFunction, ... )
function DATABASE:ForEachPlayerJoined( IteratorFunction, FinalizeFunction, ... )
self:F2( arg )
self:ForEach( IteratorFunction, arg, self.PLAYERSJOINED )
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.PLAYERSJOINED )
return self
end
--- Iterate the DATABASE and call an iterator function for each **ALIVE** player UNIT, providing the player UNIT and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept the player name.
-- @return #DATABASE self
function DATABASE:ForEachPlayerUnit( IteratorFunction, FinalizeFunction, ... )
self:F2( arg )
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.PLAYERUNITS )
return self
end
--- Iterate the DATABASE and call an iterator function for each CLIENT, providing the CLIENT to the function and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called object in the database. The function needs to accept a CLIENT parameter.
@@ -891,6 +1085,29 @@ function DATABASE:OnEventDeleteCargo( EventData )
end
--- Gets the player settings
-- @param #DATABASE self
-- @param #string PlayerName
-- @return Core.Settings#SETTINGS
function DATABASE:GetPlayerSettings( PlayerName )
self:F2( { PlayerName } )
return self.PLAYERSETTINGS[PlayerName]
end
--- Sets the player settings
-- @param #DATABASE self
-- @param #string PlayerName
-- @param Core.Settings#SETTINGS Settings
-- @return Core.Settings#SETTINGS
function DATABASE:SetPlayerSettings( PlayerName, Settings )
self:F2( { PlayerName, Settings } )
self.PLAYERSETTINGS[PlayerName] = Settings
end
--- @param #DATABASE self
function DATABASE:_RegisterTemplates()
self:F2()
@@ -905,7 +1122,6 @@ function DATABASE:_RegisterTemplates()
local CoalitionSide = coalition.side[string.upper(CoalitionName)]
----------------------------------------------
-- build nav points DB
self.Navpoints[CoalitionName] = {}
if coa_data.nav_points then --navpoints
@@ -920,8 +1136,9 @@ function DATABASE:_RegisterTemplates()
self.Navpoints[CoalitionName][nav_ind]['point']['y'] = 0
self.Navpoints[CoalitionName][nav_ind]['point']['z'] = nav_data.y
end
end
end
end
-------------------------------------------------
if coa_data.country then --there is a country table
for cntry_id, cntry_data in pairs(coa_data.country) do
@@ -974,9 +1191,111 @@ function DATABASE:_RegisterTemplates()
end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then
end --for coa_name, coa_data in pairs(mission.coalition) do
for ZoneID, ZoneData in pairs( env.mission.triggers.zones ) do
local ZoneName = ZoneData.name
self.ZONENAMES[ZoneName] = ZoneName
self:AddZone( ZoneName, ZONE:New( ZoneName ) )
self:I( "Added ZONE " .. ZoneName )
end
return self
end
--- Account the Hits of the Players.
-- @param #DATABASE self
-- @param Core.Event#EVENTDATA Event
function DATABASE:AccountHits( Event )
self:F( { Event } )
if Event.IniPlayerName ~= nil then -- It is a player that is hitting something
self:T( "Hitting Something" )
-- What is he hitting?
if Event.TgtCategory then
-- A target got hit
self.HITS[Event.TgtUnitName] = self.HITS[Event.TgtUnitName] or {}
local Hit = self.HITS[Event.TgtUnitName]
Hit.Players = Hit.Players or {}
Hit.Players[Event.IniPlayerName] = true
end
end
-- It is a weapon initiated by a player, that is hitting something
-- This seems to occur only with scenery and static objects.
if Event.WeaponPlayerName ~= nil then
self:T( "Hitting Scenery" )
-- What is he hitting?
if Event.TgtCategory then
if Event.IniCoalition then -- A coalition object was hit, probably a static.
-- A target got hit
self.HITS[Event.TgtUnitName] = self.HITS[Event.TgtUnitName] or {}
local Hit = self.HITS[Event.TgtUnitName]
Hit.Players = Hit.Players or {}
Hit.Players[Event.WeaponPlayerName] = true
else -- A scenery object was hit.
end
end
end
end
--- Account the destroys.
-- @param #DATABASE self
-- @param Core.Event#EVENTDATA Event
function DATABASE:AccountDestroys( Event )
self:F( { Event } )
local TargetUnit = nil
local TargetGroup = nil
local TargetUnitName = ""
local TargetGroupName = ""
local TargetPlayerName = ""
local TargetCoalition = nil
local TargetCategory = nil
local TargetType = nil
local TargetUnitCoalition = nil
local TargetUnitCategory = nil
local TargetUnitType = nil
if Event.IniDCSUnit then
TargetUnit = Event.IniUnit
TargetUnitName = Event.IniDCSUnitName
TargetGroup = Event.IniDCSGroup
TargetGroupName = Event.IniDCSGroupName
TargetPlayerName = Event.IniPlayerName
TargetCoalition = Event.IniCoalition
--TargetCategory = TargetUnit:getCategory()
--TargetCategory = TargetUnit:getDesc().category -- Workaround
TargetCategory = Event.IniCategory
TargetType = Event.IniTypeName
TargetUnitType = TargetType
self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } )
end
self:T( "Something got destroyed" )
local Destroyed = false
-- What is the player destroying?
if self.HITS[Event.IniUnitName] then -- Was there a hit for this unit for this player before registered???
self.DESTROYS[Event.IniUnitName] = self.DESTROYS[Event.IniUnitName] or {}
self.DESTROYS[Event.IniUnitName] = true
end
end

View File

@@ -1,4 +1,4 @@
--- **Core R2.1** - EVENT models DCS **event dispatching** using a **publish-subscribe** model.
--- **Core** -- EVENT models DCS **event dispatching** using a **publish-subscribe** model.
--
-- ![Banner Image](..\Presentations\EVENT\Dia1.JPG)
--
@@ -157,33 +157,12 @@
--
-- When a static object is involved in the event, the Group and Player fields won't be populated.
--
-- ====
--
-- # **API CHANGE HISTORY**
--
-- The underlying change log documents the API changes. Please read this carefully. The following notation is used:
--
-- * **Added** parts are expressed in bold type face.
-- * _Removed_ parts are expressed in italic type face.
--
-- YYYY-MM-DD: CLASS:**NewFunction**( Params ) replaces CLASS:_OldFunction_( Params )
-- YYYY-MM-DD: CLASS:**NewFunction( Params )** added
--
-- Hereby the change log:
--
-- * 2017-03-07: Added the correct event dispatching in case the event is subscribed by a GROUP.
--
-- * 2017-02-07: Did a complete revision of the Event Handing API and underlying mechanisms.
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ### Authors:
--
-- * [**FlightControl**](https://forums.eagle.ru/member.php?u=89536): Design & Programming & documentation.
-- ===
--
-- @module Event
@@ -195,6 +174,7 @@
EVENT = {
ClassName = "EVENT",
ClassID = 0,
MissionEnd = false,
}
world.event.S_EVENT_NEW_CARGO = world.event.S_EVENT_MAX + 1000
@@ -471,16 +451,16 @@ end
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
-- @param Dcs.DCSWorld#world.event EventID
-- @return #EVENT.Events
function EVENT:Remove( EventClass, EventID )
function EVENT:RemoveEvent( EventClass, EventID )
self:E( { "Removing subscription for class: ", EventClass:GetClassNameAndID() } )
self:F2( { "Removing subscription for class: ", EventClass:GetClassNameAndID() } )
local EventPriority = EventClass:GetEventPriority()
self.EventsDead = self.EventsDead or {}
self.EventsDead[EventID] = self.EventsDead[EventID] or {}
self.EventsDead[EventID][EventPriority] = self.EventsDead[EventID][EventPriority] or {}
self.EventsDead[EventID][EventPriority][EventClass] = self.Events[EventID][EventPriority][EventClass]
self.Events = self.Events or {}
self.Events[EventID] = self.Events[EventID] or {}
self.Events[EventID][EventPriority] = self.Events[EventID][EventPriority] or {}
self.Events[EventID][EventPriority][EventClass] = self.Events[EventID][EventPriority][EventClass]
self.Events[EventID][EventPriority][EventClass] = nil
@@ -493,7 +473,7 @@ end
-- @return #EVENT.Events
function EVENT:Reset( EventObject ) --R2.1
self:E( { "Resetting subscriptions for class: ", EventObject:GetClassNameAndID() } )
self:F( { "Resetting subscriptions for class: ", EventObject:GetClassNameAndID() } )
local EventPriority = EventObject:GetEventPriority()
for EventID, EventData in pairs( self.Events ) do
@@ -582,12 +562,12 @@ end
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
-- @param EventID
-- @return #EVENT
function EVENT:OnEventForGroup( GroupName, EventFunction, EventClass, EventID )
self:F2( GroupName )
function EVENT:OnEventForGroup( GroupName, EventFunction, EventClass, EventID, ... )
local Event = self:Init( EventID, EventClass )
Event.EventGroup = true
Event.EventFunction = EventFunction
Event.Params = arg
return self
end
@@ -754,7 +734,7 @@ function EVENT:onEvent( Event )
local ErrorHandler = function( errmsg )
env.info( "Error in SCHEDULER function:" .. errmsg )
if debug ~= nil then
if BASE.Debug ~= nil then
env.info( debug.traceback() )
end
@@ -764,10 +744,20 @@ function EVENT:onEvent( Event )
local EventMeta = _EVENTMETA[Event.id]
if self and self.Events and self.Events[Event.id] then
--self:E( { EventMeta.Text, Event } ) -- Activate the see all incoming events ...
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
self.MissionEnd = true
end
if Event.initiator then
Event.IniObjectCategory = Event.initiator:getCategory()
if Event.IniObjectCategory == Object.Category.UNIT then
@@ -804,13 +794,23 @@ function EVENT:onEvent( Event )
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
end
if Event.IniObjectCategory == Object.Category.CARGO then
Event.IniDCSUnit = Event.initiator
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
Event.IniUnitName = Event.IniDCSUnitName
Event.IniUnit = CARGO:FindByName( Event.IniDCSUnitName )
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
Event.IniCategory = Event.IniDCSUnit:getDesc().category
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
end
if Event.IniObjectCategory == Object.Category.SCENERY then
Event.IniDCSUnit = Event.initiator
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
Event.IniUnitName = Event.IniDCSUnitName
Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator )
Event.IniCategory = Event.IniDCSUnit:getDesc().category
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
Event.IniTypeName = Event.initiator:isExist() and Event.IniDCSUnit:getTypeName() or "SCENERY" -- TODO: Bug fix for 2.1!
end
end
@@ -842,7 +842,7 @@ function EVENT:onEvent( Event )
Event.TgtDCSUnit = Event.target
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
Event.TgtUnitName = Event.TgtDCSUnitName
Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName )
Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false )
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
@@ -888,10 +888,10 @@ 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.
for EventClass, EventData in pairs( self.Events[Event.id][EventPriority] ) do
if Event.IniObjectCategory ~= Object.Category.STATIC then
--self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } )
end
--if Event.IniObjectCategory ~= Object.Category.STATIC then
-- self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } )
--end
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName )
@@ -901,6 +901,7 @@ function EVENT:onEvent( Event )
-- So now the EventClass must be a UNIT class!!! We check if it is still "Alive".
if EventClass:IsAlive() or
Event.id == EVENTS.PlayerEnterUnit or
Event.id == EVENTS.Crash or
Event.id == EVENTS.Dead then
@@ -913,7 +914,7 @@ function EVENT:onEvent( Event )
if EventData.EventFunction then
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
self:F( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
end
local Result, Value = xpcall(
@@ -929,7 +930,7 @@ function EVENT:onEvent( Event )
-- Now call the default event function.
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
self:F( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
end
local Result, Value = xpcall(
@@ -941,7 +942,7 @@ function EVENT:onEvent( Event )
end
else
-- The EventClass is not alive anymore, we remove it from the EventHandlers...
self:Remove( EventClass, Event.id )
self:RemoveEvent( EventClass, Event.id )
end
else
@@ -950,6 +951,7 @@ function EVENT:onEvent( Event )
-- So now the EventClass must be a GROUP class!!! We check if it is still "Alive".
if EventClass:IsAlive() or
Event.id == EVENTS.PlayerEnterUnit or
Event.id == EVENTS.Crash or
Event.id == EVENTS.Dead then
@@ -963,12 +965,12 @@ function EVENT:onEvent( Event )
if EventData.EventFunction then
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
self:F( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
end
local Result, Value = xpcall(
function()
return EventData.EventFunction( EventClass, Event )
return EventData.EventFunction( EventClass, Event, unpack( EventData.Params ) )
end, ErrorHandler )
else
@@ -979,19 +981,19 @@ function EVENT:onEvent( Event )
-- Now call the default event function.
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling " .. EventMeta.Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } )
self:F( { "Calling " .. EventMeta.Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } )
end
local Result, Value = xpcall(
function()
return EventFunction( EventClass, Event )
return EventFunction( EventClass, Event, unpack( EventData.Params ) )
end, ErrorHandler )
end
end
end
else
-- The EventClass is not alive anymore, we remove it from the EventHandlers...
self:Remove( EventClass, Event.id )
--self:RemoveEvent( EventClass, Event.id )
end
else
@@ -1004,7 +1006,7 @@ function EVENT:onEvent( Event )
-- There is an EventFunction defined, so call the EventFunction.
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventPriority } )
self:F2( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventPriority } )
end
local Result, Value = xpcall(
function()
@@ -1018,7 +1020,7 @@ function EVENT:onEvent( Event )
-- Now call the default event function.
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
self:F2( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
end
local Result, Value = xpcall(
@@ -1035,8 +1037,18 @@ function EVENT:onEvent( Event )
end
end
end
-- When cargo was deleted, it may probably be because of an S_EVENT_DEAD.
-- However, in the loading logic, an S_EVENT_DEAD is also generated after a Destroy() call.
-- And this is a problem because it will remove all entries from the SET_CARGOs.
-- To prevent this from happening, the Cargo object has a flag NoDestroy.
-- When true, the SET_CARGO won't Remove the Cargo object from the set.
-- But we need to switch that flag off after the event handlers have been called.
if Event.id == EVENTS.DeleteCargo then
Event.Cargo.NoDestroy = nil
end
else
self:E( { EventMeta.Text, Event } )
self:T( { EventMeta.Text, Event } )
end
Event = nil

View File

@@ -1,4 +1,4 @@
--- **Core** - The **FSM** (**F**inite **S**tate **M**achine) class and derived **FSM\_** classes
--- **Core** -- The **FSM** (**F**inite **S**tate **M**achine) class and derived **FSM\_** classes
-- are design patterns allowing efficient (long-lasting) processes and workflows.
--
-- ![Banner Image](..\Presentations\FSM\Dia1.JPG)
@@ -56,33 +56,13 @@
-- * @{#FSM_SET}: 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.
--
-- ====
--
-- # **API CHANGE HISTORY**
--
-- The underlying change log documents the API changes. Please read this carefully. The following notation is used:
--
-- * **Added** parts are expressed in bold type face.
-- * _Removed_ parts are expressed in italic type face.
--
-- YYYY-MM-DD: CLASS:**NewFunction**( Params ) replaces CLASS:_OldFunction_( Params )
-- YYYY-MM-DD: CLASS:**NewFunction( Params )** added
--
-- Hereby the change log:
--
-- * 2016-12-18: Released.
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- * [**Pikey**](https://forums.eagle.ru/member.php?u=62835): Review of documentation & advice for improvements.
--
-- ### Authors:
--
-- * [**FlightControl**](https://forums.eagle.ru/member.php?u=89536): Design & Programming & documentation.
-- ===
--
-- @module Fsm
@@ -357,7 +337,7 @@ do -- FSM
--- Creates a new FSM object.
-- @param #FSM self
-- @return #FSM
function FSM:New( FsmT )
function FSM:New()
-- Inherits from BASE
self = BASE:Inherit( self, BASE:New() )
@@ -416,7 +396,7 @@ do -- FSM
Transition.Event = Event
Transition.To = To
self:T( Transition )
self:T2( Transition )
self._Transitions[Transition] = Transition
self:_eventmap( self.Events, Transition )
@@ -438,7 +418,7 @@ do -- FSM
-- @param #table ReturnEvents A table indicating for which returned events of the SubFSM which Event must be triggered in the FSM.
-- @return Core.Fsm#FSM_PROCESS The SubFSM.
function FSM:AddProcess( From, Event, Process, ReturnEvents )
self:T( { From, Event, Process, ReturnEvents } )
self:T( { From, Event } )
local Sub = {}
Sub.From = From
@@ -461,6 +441,8 @@ do -- FSM
-- @return #table
function FSM:GetProcesses()
self:F( { Processes = self._Processes } )
return self._Processes or {}
end
@@ -475,6 +457,18 @@ do -- FSM
error( "Sub-Process from state " .. From .. " with event " .. Event .. " not found!" )
end
function FSM:SetProcess( From, Event, Fsm )
for ProcessID, Process in pairs( self:GetProcesses() ) do
if Process.From == From and Process.Event == Event then
Process.fsm = Fsm
return true
end
end
error( "Sub-Process from state " .. From .. " with event " .. Event .. " not found!" )
end
--- Adds an End state.
function FSM:AddEndState( State )
@@ -554,14 +548,14 @@ do -- FSM
local __Event = "__" .. EventStructure.Event
self[Event] = self[Event] or self:_create_transition(Event)
self[__Event] = self[__Event] or self:_delayed_transition(Event)
self:T( "Added methods: " .. Event .. ", " .. __Event )
self:T2( "Added methods: " .. Event .. ", " .. __Event )
Events[Event] = self.Events[Event] or { map = {} }
self:_add_to_map( Events[Event].map, EventStructure )
end
function FSM:_submap( subs, sub, name )
self:F( { sub = sub, name = name } )
--self:F( { sub = sub, name = name } )
subs[sub.From] = subs[sub.From] or {}
subs[sub.From][sub.Event] = subs[sub.From][sub.Event] or {}
@@ -577,95 +571,130 @@ do -- FSM
end
function FSM:_call_handler( handler, params, EventName )
function FSM:_call_handler( step, trigger, params, EventName )
local handler = step .. trigger
local ErrorHandler = function( errmsg )
env.info( "Error in SCHEDULER function:" .. errmsg )
if debug ~= nil then
env.info( debug.traceback() )
if BASE.Debug ~= nil then
env.info( BASE.Debug.traceback() )
end
return errmsg
end
if self[handler] then
self:T( "Calling " .. handler )
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] )
self._EventSchedules[EventName] = nil
local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler )
return Value
end
end
--- @param #FSM self
function FSM._handler( self, EventName, ... )
local Can, to = self:can( EventName )
local Can, To = self:can( EventName )
if to == "*" then
to = self.current
if To == "*" then
To = self.current
end
if Can then
local from = self.current
local params = { from, EventName, to, ... }
local From = self.current
local Params = { From, EventName, To, ... }
if self.Controllable then
self:T( "FSM Transition for " .. self.Controllable.ControllableName .. " :" .. self.current .. " --> " .. EventName .. " --> " .. to )
if self["onleave".. From] or
self["OnLeave".. From] or
self["onbefore".. EventName] or
self["OnBefore".. EventName] or
self["onafter".. EventName] or
self["OnAfter".. EventName] or
self["onenter".. To] or
self["OnEnter".. To]
then
if self:_call_handler( "onbefore", EventName, Params, EventName ) == false then
self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** onbefore" .. EventName )
return false
else
if self:_call_handler( "OnBefore", EventName, Params, EventName ) == false then
self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** OnBefore" .. EventName )
return false
else
if self:_call_handler( "onleave", From, Params, EventName ) == false then
self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** onleave" .. From )
return false
else
if self:_call_handler( "OnLeave", From, Params, EventName ) == false then
self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** OnLeave" .. From )
return false
end
end
end
end
else
self:T( "FSM Transition:" .. self.current .. " --> " .. EventName .. " --> " .. to )
end
local ClassName = self:GetClassName()
if ClassName == "FSM" then
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To )
end
if ( self:_call_handler("onbefore" .. EventName, params, EventName ) == false )
or ( self:_call_handler("OnBefore" .. EventName, params, EventName ) == false )
or ( self:_call_handler("onleave" .. from, params, EventName ) == false )
or ( self:_call_handler("OnLeave" .. from, params, EventName ) == false ) then
self:T( "Cancel Transition" )
return false
if ClassName == "FSM_TASK" then
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** Task: " .. self.TaskName )
end
if ClassName == "FSM_CONTROLLABLE" then
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** TaskUnit: " .. self.Controllable.ControllableName .. " *** " )
end
if ClassName == "FSM_PROCESS" then
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** Task: " .. self.Task:GetName() .. ", TaskUnit: " .. self.Controllable.ControllableName .. " *** " )
end
end
self.current = to
self.current = To
local execute = true
local subtable = self:_gosub( from, EventName )
local subtable = self:_gosub( From, EventName )
for _, sub in pairs( subtable ) do
--if sub.nextevent then
-- self:F2( "nextevent = " .. sub.nextevent )
-- self[sub.nextevent]( self )
--end
self:T( "calling sub start event: " .. sub.StartEvent )
self:T( "*** FSM *** Sub *** " .. sub.StartEvent )
sub.fsm.fsmparent = self
sub.fsm.ReturnEvents = sub.ReturnEvents
sub.fsm[sub.StartEvent]( sub.fsm )
execute = false
end
local fsmparent, Event = self:_isendstate( to )
local fsmparent, Event = self:_isendstate( To )
if fsmparent and Event then
self:F2( { "end state: ", fsmparent, Event } )
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("onstatechange", params, EventName )
self:T( "*** FSM *** End *** " .. Event )
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("onstate", "change", Params, EventName )
fsmparent[Event]( fsmparent )
execute = false
end
if execute then
self:_call_handler("onafter", EventName, Params, EventName )
self:_call_handler("OnAfter", EventName, Params, EventName )
-- only execute the call if the From state is not equal to the To state! Otherwise this function should never execute!
--if from ~= to then
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 )
--end
self:_call_handler("onafter" .. EventName, params, EventName )
self:_call_handler("OnAfter" .. EventName, params, EventName )
self:_call_handler("onstatechange", params, EventName )
self:_call_handler("onstate", "change", Params, EventName )
end
else
self:T( "Cannot execute transition." )
self:T( { From = self.current, Event = EventName, To = to, Can = Can } )
self:T( "*** FSM *** NO Transition *** " .. self.current .. " --> " .. EventName .. " --> ? " )
end
return nil
@@ -711,17 +740,16 @@ do -- FSM
function FSM:_isendstate( Current )
local FSMParent = self.fsmparent
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
local ParentFrom = FSMParent.current
self:T( ParentFrom )
self:T( self.ReturnEvents )
--self:T( { ParentFrom, self.ReturnEvents } )
local Event = self.ReturnEvents[Current]
self:T( { ParentFrom, Event, self.ReturnEvents } )
--self:T( { Event } )
if Event then
return FSMParent, Event
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
@@ -744,6 +772,10 @@ do -- FSM
return self.current
end
function FSM:GetCurrentState()
return self.current
end
function FSM:Is( State )
return self.current == State
@@ -789,10 +821,10 @@ do -- FSM_CONTROLLABLE
-- @param #table FSMT Finite State Machine Table
-- @param Wrapper.Controllable#CONTROLLABLE Controllable (optional) The CONTROLLABLE object that the FSM_CONTROLLABLE governs.
-- @return #FSM_CONTROLLABLE
function FSM_CONTROLLABLE:New( FSMT, Controllable )
function FSM_CONTROLLABLE:New( Controllable )
-- Inherits from BASE
local self = BASE:Inherit( self, FSM:New( FSMT ) ) -- Core.Fsm#FSM_CONTROLLABLE
local self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM_CONTROLLABLE
if Controllable then
self:SetControllable( Controllable )
@@ -864,7 +896,7 @@ do -- FSM_CONTROLLABLE
-- @param Wrapper.Controllable#CONTROLLABLE FSMControllable
-- @return #FSM_CONTROLLABLE
function FSM_CONTROLLABLE:SetControllable( FSMControllable )
self:F( FSMControllable )
--self:F( FSMControllable:GetName() )
self.Controllable = FSMControllable
end
@@ -875,20 +907,22 @@ do -- FSM_CONTROLLABLE
return self.Controllable
end
function FSM_CONTROLLABLE:_call_handler( handler, params, EventName )
function FSM_CONTROLLABLE:_call_handler( step, trigger, params, EventName )
local handler = step .. trigger
local ErrorHandler = function( errmsg )
env.info( "Error in SCHEDULER function:" .. errmsg )
if debug ~= nil then
env.info( debug.traceback() )
if BASE.Debug ~= nil then
env.info( BASE.Debug.traceback() )
end
return errmsg
end
if self[handler] then
self:F3( "Calling " .. handler )
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] .. " *** TaskUnit: " .. self.Controllable:GetName() )
self._EventSchedules[EventName] = nil
local Result, Value = xpcall( function() return self[handler]( self, self.Controllable, unpack( params ) ) end, ErrorHandler )
return Value
@@ -924,10 +958,10 @@ do -- FSM_PROCESS
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_PROCESS
self:F( Controllable, Task )
--self:F( Controllable )
self:Assign( Controllable, Task )
return self
end
@@ -935,22 +969,28 @@ do -- FSM_PROCESS
self:T( "No Initialisation" )
end
function FSM_PROCESS:_call_handler( handler, params, EventName )
function FSM_PROCESS:_call_handler( step, trigger, params, EventName )
local handler = step .. trigger
local ErrorHandler = function( errmsg )
env.info( "Error in FSM_PROCESS call handler:" .. errmsg )
if debug ~= nil then
env.info( debug.traceback() )
if BASE.Debug ~= nil then
env.info( BASE.Debug.traceback() )
end
return errmsg
end
if self[handler] then
self:F3( "Calling " .. handler )
if handler ~= "onstatechange" then
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] .. " *** Task: " .. self.Task:GetName() .. ", TaskUnit: " .. self.Controllable:GetName() )
end
self._EventSchedules[EventName] = nil
local Result, Value = xpcall( function() return self[handler]( self, self.Controllable, self.Task, unpack( params ) ) end, ErrorHandler )
if self.Controllable and self.Controllable:IsAlive() == true then
local Result, Value = xpcall( function() return self[handler]( self, self.Controllable, self.Task, unpack( params ) ) end, ErrorHandler )
end
return Value
--return self[handler]( self, self.Controllable, unpack( params ) )
end
@@ -966,7 +1006,7 @@ do -- FSM_PROCESS
local NewFsm = self:New( Controllable, Task ) -- Core.Fsm#FSM_PROCESS
NewFsm:Assign( Controllable, Task )
-- Polymorphic call to initialize the new FSM_PROCESS based on self FSM_PROCESS
NewFsm:Init( self )
@@ -980,7 +1020,7 @@ do -- FSM_PROCESS
-- Copy Processes
for ProcessID, Process in pairs( self:GetProcesses() ) do
self:E( { Process} )
--self:E( { Process:GetName() } )
local FsmProcess = NewFsm:AddProcess( Process.From, Process.Event, Process.fsm:Copy( Controllable, Task ), Process.ReturnEvents )
end
@@ -1010,7 +1050,6 @@ do -- FSM_PROCESS
-- Copy Processes
for ProcessID, Process in pairs( self:GetProcesses() ) do
self:E( { Process} )
if Process.fsm then
Process.fsm:Remove()
Process.fsm = nil
@@ -1058,21 +1097,21 @@ do -- FSM_PROCESS
-- 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.
-- @param #FSM_PROCESS self
function FSM_PROCESS:Message( Message )
self:F( { Message = Message } )
local CC = self:GetCommandCenter()
local TaskGroup = self.Controllable:GetGroup()
-- @param #FSM_PROCESS self
function FSM_PROCESS:Message( Message )
self:F( { Message = Message } )
local PlayerName = self.Controllable:GetPlayerName() -- Only for a unit
PlayerName = PlayerName and " (" .. PlayerName .. ")" or "" -- If PlayerName is nil, then keep it nil, otherwise add brackets.
local Callsign = self.Controllable:GetCallsign()
local Prefix = Callsign and " @ " .. Callsign .. PlayerName or ""
Message = Prefix .. ": " .. Message
CC:MessageToGroup( Message, TaskGroup )
end
local CC = self:GetCommandCenter()
local TaskGroup = self.Controllable:GetGroup()
local PlayerName = self.Controllable:GetPlayerName() -- Only for a unit
PlayerName = PlayerName and " (" .. PlayerName .. ")" or "" -- If PlayerName is nil, then keep it nil, otherwise add brackets.
local Callsign = self.Controllable:GetCallsign()
local Prefix = Callsign and " @ " .. Callsign .. PlayerName or ""
Message = Prefix .. ": " .. Message
CC:MessageToGroup( Message, TaskGroup )
end
@@ -1083,7 +1122,7 @@ end
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @return #FSM_PROCESS self
function FSM_PROCESS:Assign( ProcessUnit, Task )
self:T( { Task, ProcessUnit } )
--self:T( { Task:GetName(), ProcessUnit:GetName() } )
self:SetControllable( ProcessUnit )
self:SetTask( Task )
@@ -1093,23 +1132,20 @@ end
return self
end
function FSM_PROCESS:onenterAssigned( ProcessUnit )
self:T( "Assign" )
-- function FSM_PROCESS:onenterAssigned( ProcessUnit, Task, From, Event, To )
--
-- if From( "Planned" ) then
-- self:T( "*** FSM *** Assign *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To )
-- self.Task:Assign()
-- end
-- end
self.Task:Assign()
end
function FSM_PROCESS:onenterFailed( ProcessUnit )
self:T( "Failed" )
function FSM_PROCESS:onenterFailed( ProcessUnit, Task, From, Event, To )
self:T( "*** FSM *** Failed *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To )
self.Task:Fail()
end
function FSM_PROCESS:onenterSuccess( ProcessUnit )
self:T( "Success" )
self.Task:Success()
end
--- StateMachine callback function for a FSM_PROCESS
-- @param #FSM_PROCESS self
@@ -1117,14 +1153,17 @@ end
-- @param #string Event
-- @param #string From
-- @param #string To
function FSM_PROCESS:onstatechange( ProcessUnit, Task, From, Event, To, Dummy )
self:T( { ProcessUnit, From, Event, To, Dummy, self:IsTrace() } )
function FSM_PROCESS:onstatechange( ProcessUnit, Task, From, Event, To )
if self:IsTrace() then
--MESSAGE:New( "@ Process " .. self:GetClassNameAndID() .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll()
if From ~= To then
self:T( "*** FSM *** Change *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To )
end
self:T( { Scores = self._Scores, To = To } )
-- if self:IsTrace() then
-- MESSAGE:New( "@ Process " .. self:GetClassNameAndID() .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll()
-- self:F2( { Scores = self._Scores, To = To } )
-- end
-- 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
@@ -1159,22 +1198,23 @@ do -- FSM_TASK
--- Creates a new FSM_TASK object.
-- @param #FSM_TASK self
-- @param #table FSMT
-- @param Tasking.Task#TASK Task
-- @param Wrapper.Unit#UNIT TaskUnit
-- @param #string TaskName The name of the task.
-- @return #FSM_TASK
function FSM_TASK:New( FSMT )
function FSM_TASK:New( TaskName )
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New( FSMT ) ) -- Core.Fsm#FSM_TASK
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_TASK
self["onstatechange"] = self.OnStateChange
self.TaskName = TaskName
return self
end
function FSM_TASK:_call_handler( handler, params, EventName )
function FSM_TASK:_call_handler( step, trigger, params, EventName )
local handler = step .. trigger
if self[handler] then
self:T( "Calling " .. handler )
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] .. " *** Task: " .. self.TaskName )
self._EventSchedules[EventName] = nil
return self[handler]( self, unpack( params ) )
end
@@ -1236,9 +1276,10 @@ do -- FSM_SET
return self.Controllable
end
function FSM_SET:_call_handler( handler, params, EventName )
function FSM_SET:_call_handler( step, trigger, params, EventName )
local handler = step .. trigger
if self[handler] then
self:T( "Calling " .. handler )
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] )
self._EventSchedules[EventName] = nil
return self[handler]( self, self.Set, unpack( params ) )
end

View File

@@ -0,0 +1,146 @@
--- **Core (WIP)** -- Base class to allow the modeling of processes to achieve Goals.
--
-- ===
--
-- GOAL models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module Goal
do -- Goal
--- @type GOAL
-- @extends Core.Fsm#FSM
--- # GOAL class, extends @{Fsm#FSM}
--
-- GOAL models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized.
--
-- ## 1. GOAL constructor
--
-- * @{#GOAL.New}(): Creates a new GOAL object.
--
-- ## 2. GOAL is a finite state machine (FSM).
--
-- ### 2.1 GOAL States
--
-- * **Pending**: The goal object is in progress.
-- * **Achieved**: The goal objective is Achieved.
--
-- ### 2.2 GOAL Events
--
-- * **Achieved**: Set the goal objective to Achieved.
--
-- @field #GOAL
GOAL = {
ClassName = "GOAL",
}
--- @field #table GOAL.Players
GOAL.Players = {}
--- @field #number GOAL.TotalContributions
GOAL.TotalContributions = 0
--- GOAL Constructor.
-- @param #GOAL self
-- @return #GOAL
function GOAL:New()
local self = BASE:Inherit( self, FSM:New() ) -- #GOAL
self:F( {} )
--- Achieved State for GOAL
-- @field GOAL.Achieved
--- Achieved State Handler OnLeave for GOAL
-- @function [parent=#GOAL] OnLeaveAchieved
-- @param #GOAL self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Achieved State Handler OnEnter for GOAL
-- @function [parent=#GOAL] OnEnterAchieved
-- @param #GOAL self
-- @param #string From
-- @param #string Event
-- @param #string To
self:SetStartState( "Pending" )
self:AddTransition( "*", "Achieved", "Achieved" )
--- Achieved Handler OnBefore for GOAL
-- @function [parent=#GOAL] OnBeforeAchieved
-- @param #GOAL self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Achieved Handler OnAfter for GOAL
-- @function [parent=#GOAL] OnAfterAchieved
-- @param #GOAL self
-- @param #string From
-- @param #string Event
-- @param #string To
--- Achieved Trigger for GOAL
-- @function [parent=#GOAL] Achieved
-- @param #GOAL self
--- Achieved Asynchronous Trigger for GOAL
-- @function [parent=#GOAL] __Achieved
-- @param #GOAL self
-- @param #number Delay
self:SetEventPriority( 5 )
return self
end
--- @param #GOAL self
-- @param #string PlayerName
function GOAL:AddPlayerContribution( PlayerName )
self.Players[PlayerName] = self.Players[PlayerName] or 0
self.Players[PlayerName] = self.Players[PlayerName] + 1
self.TotalContributions = self.TotalContributions + 1
end
--- @param #GOAL self
-- @param #number Player contribution.
function GOAL:GetPlayerContribution( PlayerName )
return self.Players[PlayerName] or 0
end
--- @param #GOAL self
function GOAL:GetPlayerContributions()
return self.Players or {}
end
--- @param #GOAL self
function GOAL:GetTotalContributions()
return self.TotalContributions or 0
end
--- @param #GOAL self
-- @return #boolean true if the goal is Achieved
function GOAL:IsAchieved()
return self:Is( "Achieved" )
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
--- **Core** - MESSAGE class takes are of the **real-time notifications** and **messages to players** during a simulation.
--- **Core** -- MESSAGE class takes are of the **real-time notifications** and **messages to players** during a simulation.
--
-- ![Banner Image](..\Presentations\MESSAGE\Dia1.JPG)
--
@@ -39,6 +39,13 @@
-- * To all players using @{Message#MESSAGE.ToAllIf}().
-- * To a coalition using @{Message#MESSAGE.ToCoalitionIf}().
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @field #MESSAGE
MESSAGE = {
ClassName = "MESSAGE",
@@ -46,6 +53,16 @@ MESSAGE = {
MessageID = 0,
}
--- Message Types
-- @type MESSAGE.Type
MESSAGE.Type = {
Update = "Update",
Information = "Information",
Briefing = "Briefing Report",
Overview = "Overview 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.
-- @param self
@@ -67,6 +84,9 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory )
local self = BASE:Inherit( self, BASE:New() )
self:F( { MessageText, MessageDuration, MessageCategory } )
self.MessageType = nil
-- When no MessageCategory is given, we don't show it as a title...
if MessageCategory and MessageCategory ~= "" then
if MessageCategory:sub(-1) ~= "\n" then
@@ -80,7 +100,7 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory )
self.MessageDuration = MessageDuration or 5
self.MessageTime = timer.getTime()
self.MessageText = MessageText
self.MessageText = MessageText:gsub("^\n","",1):gsub("\n$","",1)
self.MessageSent = false
self.MessageGroup = false
@@ -89,6 +109,37 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory )
return self
end
--- Creates a new MESSAGE object of a certain type.
-- 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.
-- The message display times are automatically defined based on the timing settings in the @{Settings} menu.
-- @param self
-- @param #string MessageText is the text of the Message.
-- @param #MESSAGE.Type MessageType The type of the message.
-- @return #MESSAGE
-- @usage
-- 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 )
-- 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 )
function MESSAGE:NewType( MessageText, MessageType )
local self = BASE:Inherit( self, BASE:New() )
self:F( { MessageText } )
self.MessageType = MessageType
self.MessageTime = timer.getTime()
self.MessageText = MessageText:gsub("^\n","",1):gsub("\n$","",1)
return self
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".
-- @param #MESSAGE self
-- @param Wrapper.Client#CLIENT Client is the Group of the Client.
@@ -108,14 +159,22 @@ end
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" )
-- MessageClient1:ToClient( ClientGroup )
-- MessageClient2:ToClient( ClientGroup )
function MESSAGE:ToClient( Client )
function MESSAGE:ToClient( Client, Settings )
self:F( Client )
if Client and Client:GetClientGroupID() then
local ClientGroupID = Client:GetClientGroupID()
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 )
if self.MessageType then
local Settings = Settings or ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
self.MessageCategory = "" -- self.MessageType .. ": "
end
if self.MessageDuration ~= 0 then
local ClientGroupID = Client:GetClientGroupID()
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 )
end
end
return self
@@ -125,13 +184,21 @@ end
-- @param #MESSAGE self
-- @param Wrapper.Group#GROUP Group is the Group.
-- @return #MESSAGE
function MESSAGE:ToGroup( Group )
function MESSAGE:ToGroup( Group, Settings )
self:F( Group.GroupName )
if Group then
if self.MessageType then
local Settings = Settings or ( Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
self.MessageCategory = "" -- self.MessageType .. ": "
end
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 )
if self.MessageDuration ~= 0 then
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 )
end
end
return self
@@ -186,12 +253,20 @@ end
-- or
-- 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 )
function MESSAGE:ToCoalition( CoalitionSide, Settings )
self:F( CoalitionSide )
if self.MessageType then
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
self.MessageCategory = "" -- self.MessageType .. ": "
end
if CoalitionSide then
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
trigger.action.outTextForCoalition( CoalitionSide, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
if self.MessageDuration ~= 0 then
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
trigger.action.outTextForCoalition( CoalitionSide, self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
end
end
return self
@@ -225,8 +300,16 @@ end
function MESSAGE:ToAll()
self:F()
self:ToCoalition( coalition.side.RED )
self:ToCoalition( coalition.side.BLUE )
if self.MessageType then
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
self.MessageCategory = "" -- self.MessageType .. ": "
end
if self.MessageDuration ~= 0 then
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 )
end
return self
end
@@ -238,8 +321,7 @@ end
function MESSAGE:ToAllIf( Condition )
if Condition and Condition == true then
self:ToCoalition( coalition.side.RED )
self:ToCoalition( coalition.side.BLUE )
self:ToAll()
end
return self

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
--- **Core** - The RADIO Module is responsible for everything that is related to radio transmission and you can hear in DCS, be it TACAN beacons, Radio transmissions...
--- **Core** -- The RADIO Module is responsible for everything that is related to radio transmission and you can hear in DCS, be it TACAN beacons, Radio transmissions...
--
-- ![Banner Image](..\Presentations\RADIO\Dia1.JPG)
--
@@ -79,7 +79,7 @@
-- @field #string Subtitle Subtitle of the transmission
-- @field #number SubtitleDuration Duration of the Subtitle in seconds
-- @field #number Power Power of the antenna is Watts
-- @field #boolean Loop
-- @field #boolean Loop (default true)
-- @extends Core.Base#BASE
RADIO = {
ClassName = "RADIO",
@@ -89,7 +89,7 @@ RADIO = {
Subtitle = "",
SubtitleDuration = 0,
Power = 100,
Loop = 0,
Loop = true,
}
--- Create a new RADIO Object. This doesn't broadcast a transmission, though, use @{#RADIO.Broadcast} to actually broadcast
@@ -101,6 +101,7 @@ RADIO = {
function RADIO:New(Positionable)
local self = BASE:Inherit( self, BASE:New() ) -- Core.Radio#RADIO
self.Loop = true -- default Loop to true (not sure the above RADIO definition actually is working)
self:F(Positionable)
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure positionable is valid
@@ -296,6 +297,7 @@ end
-- @return #RADIO self
function RADIO:Broadcast()
self:F()
-- If the POSITIONABLE is actually a UNIT or a GROUP, use the more complicated DCS command system
if self.Positionable.ClassName == "UNIT" or self.Positionable.ClassName == "GROUP" then
self:T2("Broadcasting from a UNIT or a GROUP")

View File

@@ -0,0 +1,86 @@
--- The REPORT class
-- @type REPORT
-- @extends Core.Base#BASE
REPORT = {
ClassName = "REPORT",
Title = "",
}
--- Create a new REPORT.
-- @param #REPORT self
-- @param #string Title
-- @return #REPORT
function REPORT:New( Title )
local self = BASE:Inherit( self, BASE:New() ) -- #REPORT
self.Report = {}
self:SetTitle( Title or "" )
self:SetIndent( 3 )
return self
end
--- Has the REPORT Text?
-- @param #REPORT self
-- @return #boolean
function REPORT:HasText() --R2.1
return #self.Report > 0
end
--- Set indent of a REPORT.
-- @param #REPORT self
-- @param #number Indent
-- @return #REPORT
function REPORT:SetIndent( Indent ) --R2.1
self.Indent = Indent
return self
end
--- Add a new line to a REPORT.
-- @param #REPORT self
-- @param #string Text
-- @return #REPORT
function REPORT:Add( Text )
self.Report[#self.Report+1] = Text
return self
end
--- Add a new line to a REPORT.
-- @param #REPORT self
-- @param #string Text
-- @return #REPORT
function REPORT:AddIndent( Text, Separator ) --R2.1
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
end
--- Produces the text of the report, taking into account an optional delimeter, which is \n by default.
-- @param #REPORT self
-- @param #string Delimiter (optional) A delimiter text.
-- @return #string The report text.
function REPORT:Text( Delimiter )
Delimiter = Delimiter or "\n"
local ReportText = ( self.Title ~= "" and self.Title .. Delimiter or self.Title ) .. table.concat( self.Report, Delimiter ) or ""
return ReportText
end
--- Sets the title of the report.
-- @param #REPORT self
-- @param #string Title The title of the report.
-- @return #REPORT
function REPORT:SetTitle( Title )
self.Title = Title
return self
end
--- Gets the amount of report items contained in the report.
-- @param #REPORT self
-- @return #number Returns the number of report items contained in the report. 0 is returned if no report items are contained in the report. The title is not counted for.
function REPORT:GetCount()
return #self.Report
end

View File

@@ -1,4 +1,4 @@
--- This module defines the SCHEDULEDISPATCHER class, which is used by a central object called _SCHEDULEDISPATCHER.
--- **Core** -- SCHEDULEDISPATCHER dispatches the different schedules.
--
-- ===
--
@@ -27,8 +27,6 @@
--
-- ===
--
-- ===
--
-- ### Contributions: -
-- ### Authors: FlightControl : Design & Programming
--
@@ -57,6 +55,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
self:F2( { Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop } )
self.CallID = self.CallID + 1
local CallID = self.CallID .. "#" .. ( Scheduler.MasterObject and Scheduler.MasterObject.GetClassNameAndID and Scheduler.MasterObject:GetClassNameAndID() or "" ) or ""
-- Initialize the ObjectSchedulers array, which is a weakly coupled table.
-- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array.
@@ -64,36 +63,36 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
-- Initialize the ObjectSchedulers array, which is a weakly coupled table.
-- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array.
self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } ) -- or {}
self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } )
if Scheduler.MasterObject then
self.ObjectSchedulers[self.CallID] = Scheduler
self:F3( { CallID = self.CallID, ObjectScheduler = tostring(self.ObjectSchedulers[self.CallID]), MasterObject = tostring(Scheduler.MasterObject) } )
self.ObjectSchedulers[CallID] = Scheduler
self:F3( { CallID = CallID, ObjectScheduler = tostring(self.ObjectSchedulers[CallID]), MasterObject = tostring(Scheduler.MasterObject) } )
else
self.PersistentSchedulers[self.CallID] = Scheduler
self:F3( { CallID = self.CallID, PersistentScheduler = self.PersistentSchedulers[self.CallID] } )
self.PersistentSchedulers[CallID] = Scheduler
self:F3( { CallID = CallID, PersistentScheduler = self.PersistentSchedulers[CallID] } )
end
self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } )
self.Schedule[Scheduler] = self.Schedule[Scheduler] or {}
self.Schedule[Scheduler][self.CallID] = {}
self.Schedule[Scheduler][self.CallID].Function = ScheduleFunction
self.Schedule[Scheduler][self.CallID].Arguments = ScheduleArguments
self.Schedule[Scheduler][self.CallID].StartTime = timer.getTime() + ( Start or 0 )
self.Schedule[Scheduler][self.CallID].Start = Start + .1
self.Schedule[Scheduler][self.CallID].Repeat = Repeat
self.Schedule[Scheduler][self.CallID].Randomize = Randomize
self.Schedule[Scheduler][self.CallID].Stop = Stop
self.Schedule[Scheduler][CallID] = {}
self.Schedule[Scheduler][CallID].Function = ScheduleFunction
self.Schedule[Scheduler][CallID].Arguments = ScheduleArguments
self.Schedule[Scheduler][CallID].StartTime = timer.getTime() + ( Start or 0 )
self.Schedule[Scheduler][CallID].Start = Start + .1
self.Schedule[Scheduler][CallID].Repeat = Repeat or 0
self.Schedule[Scheduler][CallID].Randomize = Randomize or 0
self.Schedule[Scheduler][CallID].Stop = Stop
self:T3( self.Schedule[Scheduler][self.CallID] )
self:T3( self.Schedule[Scheduler][CallID] )
self.Schedule[Scheduler][self.CallID].CallHandler = function( CallID )
self:F2( CallID )
self.Schedule[Scheduler][CallID].CallHandler = function( CallID )
--self:E( CallID )
local ErrorHandler = function( errmsg )
env.info( "Error in timer function: " .. errmsg )
if debug ~= nil then
env.info( debug.traceback() )
if BASE.Debug ~= nil then
env.info( BASE.Debug.traceback() )
end
return errmsg
end
@@ -102,16 +101,17 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
if not Scheduler then
Scheduler = self.PersistentSchedulers[CallID]
end
self:T3( { Scheduler = Scheduler } )
--self:T3( { Scheduler = Scheduler } )
if Scheduler then
local MasterObject = tostring(Scheduler.MasterObject)
local Schedule = self.Schedule[Scheduler][CallID]
self:T3( { Schedule = Schedule } )
--self:T3( { Schedule = Schedule } )
local ScheduleObject = Scheduler.SchedulerObject
local SchedulerObject = Scheduler.SchedulerObject
--local ScheduleObjectName = Scheduler.SchedulerObject:GetNameAndClassID()
local ScheduleFunction = Schedule.Function
local ScheduleArguments = Schedule.Arguments
@@ -122,9 +122,10 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
local ScheduleID = Schedule.ScheduleID
local Status, Result
if ScheduleObject then
--self:E( { SchedulerObject = SchedulerObject } )
if SchedulerObject then
local function Timer()
return ScheduleFunction( ScheduleObject, unpack( ScheduleArguments ) )
return ScheduleFunction( SchedulerObject, unpack( ScheduleArguments ) )
end
Status, Result = xpcall( Timer, ErrorHandler )
else
@@ -135,10 +136,13 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
end
local CurrentTime = timer.getTime()
local StartTime = CurrentTime + Start
local StartTime = Schedule.StartTime
self:F3( { 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 Repeat ~= 0 and ( Stop == 0 ) or ( Stop ~= 0 and CurrentTime <= StartTime + Stop ) then
if Repeat ~= 0 and ( ( Stop == 0 ) or ( Stop ~= 0 and CurrentTime <= StartTime + Stop ) ) then
local ScheduleTime =
CurrentTime +
Repeat +
@@ -147,7 +151,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
( Randomize * Repeat / 2 )
) +
0.01
self:T3( { Repeat = CallID, CurrentTime, ScheduleTime, ScheduleArguments } )
--self:T3( { Repeat = CallID, CurrentTime, ScheduleTime, ScheduleArguments } )
return ScheduleTime -- returns the next time the function needs to be called.
else
self:Stop( Scheduler, CallID )
@@ -156,15 +160,15 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
self:Stop( Scheduler, CallID )
end
else
self:E( "Scheduled obscolete call for CallID: " .. CallID )
self:E( "Scheduled obsolete call for CallID: " .. CallID )
end
return nil
end
self:Start( Scheduler, self.CallID )
self:Start( Scheduler, CallID )
return self.CallID
return CallID
end
function SCHEDULEDISPATCHER:RemoveSchedule( Scheduler, CallID )
@@ -184,10 +188,11 @@ function SCHEDULEDISPATCHER:Start( Scheduler, CallID )
-- Only start when there is no ScheduleID defined!
-- This prevents to "Start" the scheduler twice with the same CallID...
if not Schedule[CallID].ScheduleID then
Schedule[CallID].StartTime = timer.getTime() -- Set the StartTime field to indicate when the scheduler started.
Schedule[CallID].ScheduleID = timer.scheduleFunction(
Schedule[CallID].CallHandler,
CallID,
timer.getTime() + Schedule[CallID].Start
timer.getTime() + Schedule[CallID].Start
)
end
else

View File

@@ -1,4 +1,4 @@
--- **Core** - SCHEDULER prepares and handles the **execution of functions over scheduled time (intervals)**.
--- **Core** -- SCHEDULER prepares and handles the **execution of functions over scheduled time (intervals)**.
--
-- ![Banner Image](..\Presentations\SCHEDULER\Dia1.JPG)
--
@@ -21,13 +21,13 @@
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
-- ===
--
-- # YouTube Channel
--
-- ### [SCHEDULER YouTube Channel (none)]()
--
-- ====
-- ===
--
-- ### Contributions:
--
@@ -210,7 +210,8 @@ SCHEDULER = {
-- @return #SCHEDULER self.
-- @return #number The ScheduleID of the planned schedule.
function SCHEDULER:New( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop )
local self = BASE:Inherit( self, BASE:New() )
local self = BASE:Inherit( self, BASE:New() ) -- #SCHEDULER
self:F2( { Start, Repeat, RandomizeFactor, Stop } )
local ScheduleID = nil

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,839 @@
--- **Core** -- Manages various settings for MOOSE classes.
--
-- ![Banner Image](..\Presentations\SETTINGS\Dia1.JPG)
--
-- ===
--
-- The documentation of the SETTINGS class can be found further in this document.
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Contributions:
--
-- ### Authors:
--
-- * **FlightControl**: Design & Programming
--
-- @module Settings
--- @type SETTINGS
-- @extends Core.Base#BASE
--- # SETTINGS class, extends @{Base#BASE}
-- The SETTINGS class takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework.
--
-- ===
--
-- ![Banner Image](..\Presentations\SETTINGS\Dia1.JPG)
--
-- ===
--
-- The SETTINGS class takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework.
-- SETTINGS can work on 2 levels:
--
-- - **Default settings**: A running mission has **Default settings**.
-- - **Player settings**: For each player its own **Player settings** can be defined, overriding the **Default settings**.
--
-- So, when there isn't any **Player setting** defined for a player for a specific setting, or, the player cannot be identified, the **Default setting** will be used instead.
--
-- ## 1. \_SETTINGS object
--
-- MOOSE defines by default a singleton object called **\_SETTINGS**. Use this object to modify all the **Default settings** for a running mission.
-- For each player, MOOSE will automatically allocate also a **player settings** object, and will expose a radio menu to allow the player to adapt the settings to his own preferences.
--
-- ## 2. SETTINGS Menu
--
-- Settings can be adapted by the Players and by the Mission Administrator through **radio menus, which are automatically available in the mission**.
-- These menus can be found **on level F10 under "Settings"**. There are two kinds of menus generated by the system.
--
-- ### 2.1. Default settings menu
--
-- 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**!
-- Note that the **Default settings** will only be used when a player has not choosen its own settings.
--
-- ### 2.2. Player settings menu
--
-- A menu is created automatically per Player Slot (group) that allows to modify the **Player** settings.
-- So, when joining a slot, a menu wil be available that allows to change the settings parameters **FOR THE PLAYER ONLY**!
-- Note that when a player has not chosen a specific setting, the **Default settings** will be used.
--
-- ### 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**.
-- 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.
-- The option will only have effect when a player enters a new slot or changes a slot.
--
-- Example:
--
-- _SETTINGS:SetPlayerMenuOff() -- will disable the player menus.
-- _SETTINGS:SetPlayerMenuOn() -- will enable the player menus.
-- -- But only when a player exits and reenters the slot these settings will have effect!
--
--
-- ## 3. Settings
--
-- There are different settings that are managed and applied within the MOOSE framework.
-- See below a comprehensive description of each.
--
-- ### 3.1. **A2G coordinates** display formatting
--
-- #### 3.1.1. A2G coordinates setting **types**
--
-- Will customize which display format is used to indicate A2G coordinates in text as part of the Command Center communications.
--
-- - 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 LL DMS: Lattitude 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.
--
-- #### 3.1.2. A2G coordinates setting **menu**
--
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
--
-- #### 3.1.3. A2G coordinates setting **methods**
--
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
--
-- - @{#SETTINGS.SetA2G_BR}(): Enable the BR display formatting by default.
-- - @{#SETTINGS.SetA2G_MGRS}(): Enable the MGRS display formatting by default. Use @{SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
-- - @{#SETTINGS.SetA2G_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
-- - @{#SETTINGS.SetA2G_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
--
-- #### 3.1.4. A2G coordinates setting - additional notes
--
-- One additional note on BR. In a situation when a BR coordinate should be given,
-- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied!
--
-- ### 3.2. **A2A coordinates** formatting
--
-- #### 3.2.1. A2A coordinates setting **types**
--
-- Will customize which display format is used to indicate A2A coordinates in text as part of the Command Center communications.
--
-- - A2A BRAA: [Bearing Range Altitude Aspect](https://en.wikipedia.org/wiki/Bearing_(navigation)).
-- - A2A MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted.
-- - A2A LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
-- - A2A LL DDM: Lattitude Longitude [Decimal Degrees and Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
-- - A2A BULLS: [Bullseye](http://falcon4.wikidot.com/concepts:bullseye).
--
-- #### 3.2.2. A2A coordinates setting **menu**
--
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
--
-- #### 3.2.3. A2A coordinates setting **methods**
--
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
--
-- - @{#SETTINGS.SetA2A_BRAA}(): Enable the BR display formatting by default.
-- - @{#SETTINGS.SetA2A_MGRS}(): Enable the MGRS display formatting by default. Use @{SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
-- - @{#SETTINGS.SetA2A_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
-- - @{#SETTINGS.SetA2A_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
-- - @{#SETTINGS.SetA2A_BULLS}(): Enable the BULLSeye display formatting by default.
--
-- #### 3.2.4. A2A coordinates settings - additional notes
--
-- One additional note on BRAA. In a situation when a BRAA coordinate should be given,
-- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied!
--
-- ### 3.3. **Measurements** formatting
--
-- #### 3.3.1. Measurements setting **types**
--
-- Will customize the measurements system being used as part as part of the Command Center communications.
--
-- - **Metrics** system: Applies the [Metrics system](https://en.wikipedia.org/wiki/Metric_system) ...
-- - **Imperial** system: Applies the [Imperial system](https://en.wikipedia.org/wiki/Imperial_units) ...
--
-- #### 3.3.2. Measurements setting **menu**
--
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
--
-- #### 3.3.3. Measurements setting **methods**
--
-- There are different methods that can be used to change the **Default settings** using the \_SETTINGS object.
--
-- - @{#SETTINGS.SetMetric}(): Enable the Metric system.
-- - @{#SETTINGS.SetImperial}(): Enable the Imperial system.
--
-- ### 3.4. **Message** display times
--
-- #### 3.4.1. Message setting **types**
--
-- There are various **Message Types** that will influence the duration how long a message will appear as part of the Command Center communications.
--
-- - **Update** message: A short update message.
-- - **Information** message: Provides new information **while** executing a mission.
-- - **Briefing** message: Provides a complete briefing **before** executing a mission.
-- - **Overview report**: Provides a short report overview, the summary of the report.
-- - **Detailed report**: Provides a complete report.
--
-- #### 3.4.2. Message setting **menu**
--
-- 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.
-- The Settings Menu will provide for each Message Type a selection of proposed durations from which can be choosen.
-- 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!
--
-- #### 3.4.3. Message setting **methods**
--
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
--
-- - @{#SETTINGS.SetMessageTime}(): Define for a specific @{Message.MESSAGE.MessageType} the duration to be displayed in seconds.
-- - @{#SETTINGS.GetMessageTime}(): Retrieves for a specific @{Message.MESSAGE.MessageType} the duration to be displayed in seconds.
--
-- ===
--
-- @field #SETTINGS
SETTINGS = {
ClassName = "SETTINGS",
ShowPlayerMenu = true,
}
do -- SETTINGS
--- SETTINGS constructor.
-- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:Set( PlayerName )
if PlayerName == nil then
local self = BASE:Inherit( self, BASE:New() ) -- #SETTINGS
self:SetMetric() -- Defaults
self:SetA2G_BR() -- Defaults
self:SetA2A_BRAA() -- Defaults
self:SetLL_Accuracy( 3 ) -- Defaults
self:SetMGRS_Accuracy( 5 ) -- Defaults
self:SetMessageTime( MESSAGE.Type.Briefing, 180 )
self:SetMessageTime( MESSAGE.Type.Detailed, 60 )
self:SetMessageTime( MESSAGE.Type.Information, 30 )
self:SetMessageTime( MESSAGE.Type.Overview, 60 )
self:SetMessageTime( MESSAGE.Type.Update, 15 )
return self
else
local Settings = _DATABASE:GetPlayerSettings( PlayerName )
if not Settings then
Settings = BASE:Inherit( self, BASE:New() ) -- #SETTINGS
_DATABASE:SetPlayerSettings( PlayerName, Settings )
end
return Settings
end
end
--- Sets the SETTINGS metric.
-- @param #SETTINGS self
function SETTINGS:SetMetric()
self.Metric = true
end
--- Gets if the SETTINGS is metric.
-- @param #SETTINGS self
-- @return #boolean true if metric.
function SETTINGS:IsMetric()
return ( self.Metric ~= nil and self.Metric == true ) or ( self.Metric == nil and _SETTINGS:IsMetric() )
end
--- Sets the SETTINGS imperial.
-- @param #SETTINGS self
function SETTINGS:SetImperial()
self.Metric = false
end
--- Gets if the SETTINGS is imperial.
-- @param #SETTINGS self
-- @return #boolean true if imperial.
function SETTINGS:IsImperial()
return ( self.Metric ~= nil and self.Metric == false ) or ( self.Metric == nil and _SETTINGS:IsMetric() )
end
--- Sets the SETTINGS LL accuracy.
-- @param #SETTINGS self
-- @param #number LL_Accuracy
-- @return #SETTINGS
function SETTINGS:SetLL_Accuracy( LL_Accuracy )
self.LL_Accuracy = LL_Accuracy
end
--- Gets the SETTINGS LL accuracy.
-- @param #SETTINGS self
-- @return #number
function SETTINGS:GetLL_DDM_Accuracy()
return self.LL_DDM_Accuracy or _SETTINGS:GetLL_DDM_Accuracy()
end
--- Sets the SETTINGS MGRS accuracy.
-- @param #SETTINGS self
-- @param #number MGRS_Accuracy
-- @return #SETTINGS
function SETTINGS:SetMGRS_Accuracy( MGRS_Accuracy )
self.MGRS_Accuracy = MGRS_Accuracy
end
--- Gets the SETTINGS MGRS accuracy.
-- @param #SETTINGS self
-- @return #number
function SETTINGS:GetMGRS_Accuracy()
return self.MGRS_Accuracy or _SETTINGS:GetMGRS_Accuracy()
end
--- Sets the SETTINGS Message Display Timing of a MessageType
-- @param #SETTINGS self
-- @param Core.Message#MESSAGE MessageType The type of the message.
-- @param #number MessageTime The display time duration in seconds of the MessageType.
function SETTINGS:SetMessageTime( MessageType, MessageTime )
self.MessageTypeTimings = self.MessageTypeTimings or {}
self.MessageTypeTimings[MessageType] = MessageTime
end
--- Gets the SETTINGS Message Display Timing of a MessageType
-- @param #SETTINGS self
-- @param Core.Message#MESSAGE MessageType The type of the message.
-- @return #number
function SETTINGS:GetMessageTime( MessageType )
return ( self.MessageTypeTimings and self.MessageTypeTimings[MessageType] ) or _SETTINGS:GetMessageTime( MessageType )
end
--- Sets A2G LL DMS
-- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:SetA2G_LL_DMS()
self.A2GSystem = "LL DMS"
end
--- Sets A2G LL DDM
-- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:SetA2G_LL_DDM()
self.A2GSystem = "LL DDM"
end
--- Is LL DMS
-- @param #SETTINGS self
-- @return #boolean true if LL DMS
function SETTINGS:IsA2G_LL_DMS()
return ( self.A2GSystem and self.A2GSystem == "LL DMS" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_LL_DMS() )
end
--- Is LL DDM
-- @param #SETTINGS self
-- @return #boolean true if LL DDM
function SETTINGS:IsA2G_LL_DDM()
return ( self.A2GSystem and self.A2GSystem == "LL DDM" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_LL_DDM() )
end
--- Sets A2G MGRS
-- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:SetA2G_MGRS()
self.A2GSystem = "MGRS"
end
--- Is MGRS
-- @param #SETTINGS self
-- @return #boolean true if MGRS
function SETTINGS:IsA2G_MGRS()
return ( self.A2GSystem and self.A2GSystem == "MGRS" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_MGRS() )
end
--- Sets A2G BRA
-- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:SetA2G_BR()
self.A2GSystem = "BR"
end
--- Is BRA
-- @param #SETTINGS self
-- @return #boolean true if BRA
function SETTINGS:IsA2G_BR()
return ( self.A2GSystem and self.A2GSystem == "BR" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_BR() )
end
--- Sets A2A BRA
-- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:SetA2A_BRAA()
self.A2ASystem = "BRAA"
end
--- Is BRA
-- @param #SETTINGS self
-- @return #boolean true if BRA
function SETTINGS:IsA2A_BRAA()
self:E( { BRA = ( 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
--- Sets A2A BULLS
-- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:SetA2A_BULLS()
self.A2ASystem = "BULLS"
end
--- Is BULLS
-- @param #SETTINGS self
-- @return #boolean true if BULLS
function SETTINGS:IsA2A_BULLS()
return ( self.A2ASystem and self.A2ASystem == "BULLS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BULLS() )
end
--- Sets A2A LL DMS
-- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:SetA2A_LL_DMS()
self.A2ASystem = "LL DMS"
end
--- Sets A2A LL DDM
-- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:SetA2A_LL_DDM()
self.A2ASystem = "LL DDM"
end
--- Is LL DMS
-- @param #SETTINGS self
-- @return #boolean true if LL DMS
function SETTINGS:IsA2A_LL_DMS()
return ( self.A2ASystem and self.A2ASystem == "LL DMS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_LL_DMS() )
end
--- Is LL DDM
-- @param #SETTINGS self
-- @return #boolean true if LL DDM
function SETTINGS:IsA2A_LL_DDM()
return ( self.A2ASystem and self.A2ASystem == "LL DDM" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_LL_DDM() )
end
--- Sets A2A MGRS
-- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:SetA2A_MGRS()
self.A2ASystem = "MGRS"
end
--- Is MGRS
-- @param #SETTINGS self
-- @return #boolean true if MGRS
function SETTINGS:IsA2A_MGRS()
return ( self.A2ASystem and self.A2ASystem == "MGRS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_MGRS() )
end
--- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:SetSystemMenu( MenuGroup, RootMenu )
local MenuText = "System Settings"
local MenuTime = timer.getTime()
local SettingsMenu = MENU_GROUP:New( MenuGroup, MenuText, RootMenu ):SetTime( MenuTime )
local A2GCoordinateMenu = MENU_GROUP:New( MenuGroup, "A2G Coordinate System", SettingsMenu ):SetTime( MenuTime )
if not self:IsA2G_LL_DMS() then
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Min Sec (LL DMS)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
end
if not self:IsA2G_LL_DDM() then
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
end
if self:IsA2G_LL_DDM() then
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 3", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
end
if not self:IsA2G_BR() then
MENU_GROUP_COMMAND:New( MenuGroup, "Bearing, Range (BR)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "BR" ):SetTime( MenuTime )
end
if not self:IsA2G_MGRS() then
MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
end
if self:IsA2G_MGRS() then
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 1", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 2", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 3", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 4", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 4 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 5", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime )
end
local A2ACoordinateMenu = MENU_GROUP:New( MenuGroup, "A2A Coordinate System", SettingsMenu ):SetTime( MenuTime )
if not self:IsA2A_LL_DMS() then
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Min Sec (LL DMS)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
end
if not self:IsA2A_LL_DDM() then
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
end
if self:IsA2A_LL_DDM() then
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 1", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 2", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 3", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
end
if not self:IsA2A_BULLS() then
MENU_GROUP_COMMAND:New( MenuGroup, "Bullseye (BULLS)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BULLS" ):SetTime( MenuTime )
end
if not self:IsA2A_BRAA() then
MENU_GROUP_COMMAND:New( MenuGroup, "Bearing Range Altitude Aspect (BRAA)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BRAA" ):SetTime( MenuTime )
end
if not self:IsA2A_MGRS() then
MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
end
if self:IsA2A_MGRS() then
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 1", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 2", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 3", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 4", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 4 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 5", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime )
end
local MetricsMenu = MENU_GROUP:New( MenuGroup, "Measures and Weights System", SettingsMenu ):SetTime( MenuTime )
if self:IsMetric() then
MENU_GROUP_COMMAND:New( MenuGroup, "Imperial (Miles,Feet)", MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, false ):SetTime( MenuTime )
end
if self:IsImperial() then
MENU_GROUP_COMMAND:New( MenuGroup, "Metric (Kilometers,Meters)", MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, true ):SetTime( MenuTime )
end
local MessagesMenu = MENU_GROUP:New( MenuGroup, "Messages and Reports", SettingsMenu ):SetTime( MenuTime )
local UpdateMessagesMenu = MENU_GROUP:New( MenuGroup, "Update Messages", MessagesMenu ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "Off", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 0 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "5 seconds", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 5 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "10 seconds", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 10 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 15 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 30 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 60 ):SetTime( MenuTime )
local InformationMessagesMenu = MENU_GROUP:New( MenuGroup, "Information Messages", MessagesMenu ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "5 seconds", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 5 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "10 seconds", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 10 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 15 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 30 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 60 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 120 ):SetTime( MenuTime )
local BriefingReportsMenu = MENU_GROUP:New( MenuGroup, "Briefing Reports", MessagesMenu ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 15 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 30 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 60 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 120 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "3 minutes", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 180 ):SetTime( MenuTime )
local OverviewReportsMenu = MENU_GROUP:New( MenuGroup, "Overview Reports", MessagesMenu ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 15 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 30 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 60 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 120 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "3 minutes", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 180 ):SetTime( MenuTime )
local DetailedReportsMenu = MENU_GROUP:New( MenuGroup, "Detailed Reports", MessagesMenu ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 15 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 30 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 60 ):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 )
SettingsMenu:Remove( MenuTime )
return self
end
--- Sets the player menus on, so that the **Player setting menus** show up for the players.
-- But only when a player exits and reenters the slot these settings will have effect!
-- It is advised to use this method at the start of the mission.
-- @param #SETTINGS self
-- @return #SETTINGS
-- @usage
-- _SETTINGS:SetPlayerMenuOn() -- will enable the player menus.
function SETTINGS:SetPlayerMenuOn()
self.ShowPlayerMenu = true
end
--- Sets the player menus off, so that the **Player setting menus** won't show up for the players.
-- But only when a player exits and reenters the slot these settings will have effect!
-- It is advised to use this method at the start of the mission.
-- @param #SETTINGS self
-- @return #SETTINGS self
-- @usage
-- _SETTINGS:SetPlayerMenuOff() -- will disable the player menus.
function SETTINGS:SetPlayerMenuOff()
self.ShowPlayerMenu = false
end
--- Updates the menu of the player seated in the PlayerUnit.
-- @param #SETTINGS self
-- @param Wrapper.Client#CLIENT PlayerUnit
-- @return #SETTINGS self
function SETTINGS:SetPlayerMenu( PlayerUnit )
if _SETTINGS.ShowPlayerMenu == true then
local PlayerGroup = PlayerUnit:GetGroup()
local PlayerName = PlayerUnit:GetPlayerName()
local PlayerNames = PlayerGroup:GetPlayerNames()
local PlayerMenu = MENU_GROUP:New( PlayerGroup, 'Settings "' .. PlayerName .. '"' )
self.PlayerMenu = PlayerMenu
local A2GCoordinateMenu = MENU_GROUP:New( PlayerGroup, "A2G Coordinate System", PlayerMenu )
if not self:IsA2G_LL_DMS() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Min Sec (LL DMS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
end
if not self:IsA2G_LL_DDM() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
end
if self:IsA2G_LL_DDM() then
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 3", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
end
if not self:IsA2G_BR() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Bearing, Range (BR)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" )
end
if not self:IsA2G_MGRS() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
end
if self:IsA2G_MGRS() then
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 1", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 2", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 3", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 4", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 5", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 5 )
end
local A2ACoordinateMenu = MENU_GROUP:New( PlayerGroup, "A2A Coordinate System", PlayerMenu )
if not self:IsA2A_LL_DMS() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Min Sec (LL DMS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
end
if not self:IsA2A_LL_DDM() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
end
if self:IsA2A_LL_DDM() then
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 3", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
end
if not self:IsA2A_BULLS() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Bullseye (BULLS)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" )
end
if not self:IsA2A_BRAA() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Bearing Range Altitude Aspect (BRAA)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRAA" )
end
if not self:IsA2A_MGRS() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
end
if self:IsA2A_MGRS() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 1", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 2", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 3", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 4", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 5", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 5 )
end
local MetricsMenu = MENU_GROUP:New( PlayerGroup, "Measures and Weights System", PlayerMenu )
if self:IsMetric() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Imperial (Miles,Feet)", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, false )
end
if self:IsImperial() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Metric (Kilometers,Meters)", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true )
end
local MessagesMenu = MENU_GROUP:New( PlayerGroup, "Messages and Reports", PlayerMenu )
local UpdateMessagesMenu = MENU_GROUP:New( PlayerGroup, "Update Messages", MessagesMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "Off", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 0 )
MENU_GROUP_COMMAND:New( PlayerGroup, "5 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 5 )
MENU_GROUP_COMMAND:New( PlayerGroup, "10 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 10 )
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 15 )
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 30 )
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 60 )
local InformationMessagesMenu = MENU_GROUP:New( PlayerGroup, "Information Messages", MessagesMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "5 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 5 )
MENU_GROUP_COMMAND:New( PlayerGroup, "10 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 10 )
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 15 )
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 30 )
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 60 )
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 120 )
local BriefingReportsMenu = MENU_GROUP:New( PlayerGroup, "Briefing Reports", MessagesMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 15 )
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 30 )
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 60 )
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 120 )
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 180 )
local OverviewReportsMenu = MENU_GROUP:New( PlayerGroup, "Overview Reports", MessagesMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 15 )
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 30 )
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 60 )
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 120 )
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 180 )
local DetailedReportsMenu = MENU_GROUP:New( PlayerGroup, "Detailed Reports", MessagesMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 15 )
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 30 )
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 60 )
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 120 )
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 180 )
end
return self
end
--- Removes the player menu from the PlayerUnit.
--- @param #SETTINGS self
-- @param Wrapper.Client#CLIENT PlayerUnit
-- @return #SETTINGS self
function SETTINGS:RemovePlayerMenu( PlayerUnit )
if self.PlayerMenu then
self.PlayerMenu:Remove()
self.PlayerMenu = nil
end
return self
end
--- @param #SETTINGS self
function SETTINGS:A2GMenuSystem( MenuGroup, RootMenu, A2GSystem )
self.A2GSystem = A2GSystem
MESSAGE:New( string.format("Settings: Default A2G coordinate system set to %s for all players!", A2GSystem ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu )
end
--- @param #SETTINGS self
function SETTINGS:A2AMenuSystem( MenuGroup, RootMenu, A2ASystem )
self.A2ASystem = A2ASystem
MESSAGE:New( string.format("Settings: Default A2A coordinate system set to %s for all players!", A2ASystem ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu )
end
--- @param #SETTINGS self
function SETTINGS:MenuLL_DDM_Accuracy( MenuGroup, RootMenu, 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()
self:SetSystemMenu( MenuGroup, RootMenu )
end
--- @param #SETTINGS self
function SETTINGS:MenuMGRS_Accuracy( MenuGroup, RootMenu, 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()
self:SetSystemMenu( MenuGroup, RootMenu )
end
--- @param #SETTINGS self
function SETTINGS:MenuMWSystem( MenuGroup, RootMenu, 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()
self:SetSystemMenu( MenuGroup, RootMenu )
end
--- @param #SETTINGS self
function SETTINGS:MenuMessageTimingsSystem( MenuGroup, RootMenu, MessageType, MessageTime )
self:SetMessageTime( MessageType, MessageTime )
MESSAGE:New( string.format( "Settings: Default message time set for %s to %d.", MessageType, MessageTime ), 5 ):ToAll()
end
do
--- @param #SETTINGS self
function SETTINGS:MenuGroupA2GSystem( PlayerUnit, PlayerGroup, PlayerName, A2GSystem )
BASE:E( {self, PlayerUnit:GetName(), A2GSystem} )
self.A2GSystem = A2GSystem
MESSAGE:New( string.format( "Settings: A2G format set to %s for player %s.", A2GSystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
self:RemovePlayerMenu(PlayerUnit)
self:SetPlayerMenu(PlayerUnit)
end
--- @param #SETTINGS self
function SETTINGS:MenuGroupA2ASystem( PlayerUnit, PlayerGroup, PlayerName, A2ASystem )
self.A2ASystem = A2ASystem
MESSAGE:New( string.format( "Settings: A2A format set to %s for player %s.", A2ASystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
self:RemovePlayerMenu(PlayerUnit)
self:SetPlayerMenu(PlayerUnit)
end
--- @param #SETTINGS self
function SETTINGS:MenuGroupLL_DDM_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, LL_Accuracy )
self.LL_Accuracy = LL_Accuracy
MESSAGE:New( string.format( "Settings: A2G LL format accuracy set to %d for player %s.", LL_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
self:RemovePlayerMenu(PlayerUnit)
self:SetPlayerMenu(PlayerUnit)
end
--- @param #SETTINGS self
function SETTINGS:MenuGroupMGRS_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, MGRS_Accuracy )
self.MGRS_Accuracy = MGRS_Accuracy
MESSAGE:New( string.format( "Settings: A2G MGRS format accuracy set to %d for player %s.", MGRS_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
self:RemovePlayerMenu(PlayerUnit)
self:SetPlayerMenu(PlayerUnit)
end
--- @param #SETTINGS self
function SETTINGS:MenuGroupMWSystem( PlayerUnit, PlayerGroup, PlayerName, 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 )
self:RemovePlayerMenu(PlayerUnit)
self:SetPlayerMenu(PlayerUnit)
end
--- @param #SETTINGS self
function SETTINGS:MenuGroupMessageTimingsSystem( PlayerUnit, PlayerGroup, PlayerName, MessageType, MessageTime )
self:SetMessageTime( MessageType, MessageTime )
MESSAGE:New( string.format( "Settings: Default message time set for %s to %d.", MessageType, MessageTime ), 5 ):ToGroup( PlayerGroup )
end
end
end

View File

@@ -1,44 +1,29 @@
--- **Functional** -- Spawn dynamically new GROUPs in your missions.
--- **Core** -- SPAWN class dynamically spawns new groups of units in your missions.
--
-- ![Banner Image](..\Presentations\SPAWN\SPAWN.JPG)
--
-- ====
-- ===
--
-- The documentation of the SPAWN class can be found further in this document.
--
-- ====
-- ===
--
-- # Demo Missions
--
-- ### [SPAWN Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/SPA%20-%20Spawning)
--
-- ### [SPAWN Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SPA%20-%20Spawning)
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
--
-- # YouTube Channel
--
-- ### [SPAWN YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1jirWIo4t4YxqN-HxjqRkL)
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/SPA%20-%20Spawning)
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1jirWIo4t4YxqN-HxjqRkL)
--
-- ### Contributions:
-- ===
--
-- * **Aaron**: Posed the idea for Group position randomization at SpawnInZone and make the Unit randomization separate from the Group randomization.
-- * [**Entropy**](https://forums.eagle.ru/member.php?u=111471), **Afinegan**: Came up with the requirement for AIOnOff().
-- ### Author: **FlightControl**
-- ### Contributions: A lot of people within this community!
--
-- ### Authors:
--
-- * **FlightControl**: Design & Programming
-- ===
--
-- @module Spawn
--- SPAWN Class
-- @type SPAWN
-- @field ClassName
@@ -54,8 +39,12 @@
--- # SPAWN class, extends @{Base#BASE}
--
-- -- ![Banner Image](..\Presentations\SPAWN\SPAWN.JPG)
--
-- ===
--
-- The SPAWN class allows to spawn dynamically new groups.
-- Each SPAWN object needs to be have a related **template group** setup in the Mission Editor (ME),
-- Each SPAWN object needs to be have related **template groups** setup in the Mission Editor (ME),
-- which is a normal group with the **Late Activation** flag set.
-- This template group will never be activated in your mission.
-- SPAWN uses that **template group** to reference to all the characteristics
@@ -199,6 +188,7 @@
-- * @{#SPAWN.SpawnFromStatic}(): Spawn a new group from a structure, taking the position of a @{Static}.
-- * @{#SPAWN.SpawnFromUnit}(): Spawn a new group taking the position of a @{Unit}.
-- * @{#SPAWN.SpawnInZone}(): Spawn a new group in a @{Zone}.
-- * @{#SPAWN.SpawnAtAirbase}(): Spawn a new group at an @{Airbase}, which can be an airdrome, ship or helipad.
--
-- Note that @{#SPAWN.Spawn} and @{#SPAWN.ReSpawn} return a @{GROUP#GROUP.New} object, that contains a reference to the DCSGroup object.
-- You can use the @{GROUP} object to do further actions with the DCSGroup.
@@ -264,6 +254,18 @@ SPAWN = {
}
--- Enumerator for spawns at airbases
-- @type SPAWN.Takeoff
-- @extends Wrapper.Group#GROUP.Takeoff
--- @field #SPAWN.Takeoff Takeoff
SPAWN.Takeoff = {
Air = 1,
Runway = 2,
Hot = 3,
Cold = 4,
}
--- @type SPAWN.SpawnZoneTable
-- @list <Core.Zone#ZONE_BASE> SpawnZone
@@ -280,25 +282,26 @@ function SPAWN:New( SpawnTemplatePrefix )
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWN
self:F( { SpawnTemplatePrefix } )
local TemplateGroup = Group.getByName( SpawnTemplatePrefix )
local TemplateGroup = GROUP:FindByName( SpawnTemplatePrefix )
if TemplateGroup then
self.SpawnTemplatePrefix = SpawnTemplatePrefix
self.SpawnIndex = 0
self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart.
self.AliveUnits = 0 -- Contains the counter how many units are currently alive
self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not.
self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not.
self.SpawnTemplate = self._GetTemplate( self, SpawnTemplatePrefix ) -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!!
self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning.
self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts.
self.SpawnInitLimit = false -- By default, no InitLimit
self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time.
self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned.
self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false.
self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned.
self.AIOnOff = true -- The AI is on by default when spawning a group.
self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning.
self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts.
self.SpawnInitLimit = false -- By default, no InitLimit
self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time.
self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned.
self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false.
self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned.
self.AIOnOff = true -- The AI is on by default when spawning a group.
self.SpawnUnControlled = false
self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name.
self.DelayOnOff = false -- No intial delay when spawning the first group.
self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name.
self.DelayOnOff = false -- No intial delay when spawning the first group.
self.Grouping = nil -- No grouping
self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned.
else
@@ -306,6 +309,7 @@ function SPAWN:New( SpawnTemplatePrefix )
end
self:SetEventPriority( 5 )
self.SpawnHookScheduler = SCHEDULER:New( nil )
return self
end
@@ -323,26 +327,27 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix )
local self = BASE:Inherit( self, BASE:New() )
self:F( { SpawnTemplatePrefix, SpawnAliasPrefix } )
local TemplateGroup = Group.getByName( SpawnTemplatePrefix )
local TemplateGroup = GROUP:FindByName( SpawnTemplatePrefix )
if TemplateGroup then
self.SpawnTemplatePrefix = SpawnTemplatePrefix
self.SpawnAliasPrefix = SpawnAliasPrefix
self.SpawnIndex = 0
self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart.
self.AliveUnits = 0 -- Contains the counter how many units are currently alive
self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not.
self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not.
self.SpawnTemplate = self._GetTemplate( self, SpawnTemplatePrefix ) -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!!
self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning.
self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts.
self.SpawnInitLimit = false -- By default, no InitLimit
self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time.
self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned.
self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false.
self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned.
self.AIOnOff = true -- The AI is on by default when spawning a group.
self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning.
self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts.
self.SpawnInitLimit = false -- By default, no InitLimit
self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time.
self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned.
self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false.
self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned.
self.AIOnOff = true -- The AI is on by default when spawning a group.
self.SpawnUnControlled = false
self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name.
self.DelayOnOff = false -- No intial delay when spawning the first group.
self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name.
self.DelayOnOff = false -- No intial delay when spawning the first group.
self.Grouping = nil
self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned.
else
@@ -350,11 +355,61 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix )
end
self:SetEventPriority( 5 )
self.SpawnHookScheduler = SCHEDULER:New( nil )
return self
end
--- Creates a new SPAWN instance to create new groups based on the provided template.
-- @param #SPAWN self
-- @param #table SpawnTemplate is the Template of the Group. This must be a valid Group Template structure!
-- @param #string SpawnTemplatePrefix is the name of the Group that will be given at each spawn.
-- @param #string SpawnAliasPrefix (optional) is the name that will be given to the Group at runtime.
-- @return #SPAWN
-- @usage
-- -- Create a new SPAWN object based on a Group Template defined from scratch.
-- Spawn_BE_KA50 = SPAWN:NewWithAlias( 'BE KA-50@RAMP-Ground Defense', 'Helicopter Attacking a City' )
-- @usage
-- -- Create a new CSAR_Spawn object based on a normal Group Template to spawn a soldier.
-- local CSAR_Spawn = SPAWN:NewWithFromTemplate( Template, "CSAR", "Pilot" )
function SPAWN:NewFromTemplate( SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPrefix )
local self = BASE:Inherit( self, BASE:New() )
self:F( { SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPrefix } )
if SpawnTemplate then
self.SpawnTemplate = SpawnTemplate -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!!
self.SpawnTemplatePrefix = SpawnTemplatePrefix
self.SpawnAliasPrefix = SpawnAliasPrefix
self.SpawnIndex = 0
self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart.
self.AliveUnits = 0 -- Contains the counter how many units are currently alive
self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not.
self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning.
self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts.
self.SpawnInitLimit = false -- By default, no InitLimit.
self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time.
self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned.
self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false.
self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned.
self.AIOnOff = true -- The AI is on by default when spawning a group.
self.SpawnUnControlled = false
self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name.
self.DelayOnOff = false -- No intial delay when spawning the first group.
self.Grouping = nil
self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned.
else
error( "There is no template provided for SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" )
end
self:SetEventPriority( 5 )
self.SpawnHookScheduler = SCHEDULER:New( nil )
return self
end
--- Limits the Maximum amount of Units that can be alive at the same time, and the maximum amount of groups that can be spawned.
-- Note that this method is exceptionally important to balance the performance of the mission. Depending on the machine etc, a mission can only process a maximum amount of units.
-- If the time interval must be short, but there should not be more Units or Groups alive than a maximum amount of units, then this method should be used...
@@ -398,6 +453,57 @@ function SPAWN:InitKeepUnitNames()
return self
end
--- Defines the Heading for the new spawned units.
-- The heading can be given as one fixed degree, or can be randomized between minimum and maximum degrees.
-- @param #SPAWN self
-- @param #number HeadingMin The minimum or fixed heading in degrees.
-- @param #number HeadingMax (optional) The maximum heading in degrees. This there is no maximum heading, then the heading will be fixed for all units using minimum heading.
-- @return #SPAWN self
-- @usage
--
-- Spawn = SPAWN:New( ... )
--
-- -- Spawn the units pointing to 100 degrees.
-- Spawn:InitHeading( 100 )
--
-- -- Spawn the units pointing between 100 and 150 degrees.
-- Spawn:InitHeading( 100, 150 )
--
function SPAWN:InitHeading( HeadingMin, HeadingMax )
self:F( )
self.SpawnInitHeadingMin = HeadingMin
self.SpawnInitHeadingMax = HeadingMax
return self
end
function SPAWN:InitCoalition( Coalition )
self:F( )
self.SpawnInitCoalition = Coalition
return self
end
function SPAWN:InitCountry( Country )
self:F( )
self.SpawnInitCountry = Country
return self
end
function SPAWN:InitCategory( Category )
self:F( )
self.SpawnInitCategory = Category
return self
end
--- Randomizes the defined route of the SpawnTemplatePrefix group in the ME. This is very useful to define extra variation of the behaviour of groups.
-- @param #SPAWN self
@@ -509,6 +615,87 @@ function SPAWN:InitRandomizeTemplate( SpawnTemplatePrefixTable )
return self
end
--- Randomize templates to be used as the unit representatives for the Spawned group, defined using a SET_GROUP object.
-- This method becomes useful when you need to spawn groups with random templates of groups defined within the mission editor,
-- but they will all follow the same Template route and have the same prefix name.
-- In other words, this method randomizes between a defined set of groups the template to be used for each new spawn of a group.
-- @param #SPAWN self
-- @param Core.Set#SET_GROUP SpawnTemplateSet A SET_GROUP object set, that contains the groups that are possible unit representatives of the group to be spawned.
-- @return #SPAWN
-- @usage
-- -- NATO Tank Platoons invading Gori.
--
-- -- Choose between different 'US Tank Platoon Template' configurations to be spawned for the
-- -- 'US Tank Platoon Left', 'US Tank Platoon Middle' and 'US Tank Platoon Right' SPAWN objects.
--
-- -- Each new SPAWN will randomize the route, with a defined time interval of 200 seconds with 40% time variation (randomization) and
-- -- with a limit set of maximum 12 Units alive simulteneously and 150 Groups to be spawned during the whole mission.
--
-- Spawn_US_PlatoonSet = SET_GROUP:New():FilterPrefixes( "US Tank Platoon Templates" ):FilterOnce()
--
-- --- Now use the Spawn_US_PlatoonSet to define the templates using InitRandomizeTemplateSet.
-- Spawn_US_Platoon_Left = SPAWN:New( 'US Tank Platoon Left' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplateSet( Spawn_US_PlatoonSet ):InitRandomizeRoute( 3, 3, 2000 )
-- Spawn_US_Platoon_Middle = SPAWN:New( 'US Tank Platoon Middle' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplateSet( Spawn_US_PlatoonSet ):InitRandomizeRoute( 3, 3, 2000 )
-- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplateSet( Spawn_US_PlatoonSet ):InitRandomizeRoute( 3, 3, 2000 )
function SPAWN:InitRandomizeTemplateSet( SpawnTemplateSet ) -- R2.3
self:F( { self.SpawnTemplatePrefix } )
self.SpawnTemplatePrefixTable = SpawnTemplateSet:GetSetNames()
self.SpawnRandomizeTemplate = true
for SpawnGroupID = 1, self.SpawnMaxGroups do
self:_RandomizeTemplate( SpawnGroupID )
end
return self
end
--- Randomize templates to be used as the unit representatives for the Spawned group, defined by specifying the prefix names.
-- This method becomes useful when you need to spawn groups with random templates of groups defined within the mission editor,
-- but they will all follow the same Template route and have the same prefix name.
-- In other words, this method randomizes between a defined set of groups the template to be used for each new spawn of a group.
-- @param #SPAWN self
-- @param #string SpawnTemplatePrefixes A string or a list of string that contains the prefixes of the groups that are possible unit representatives of the group to be spawned.
-- @return #SPAWN
-- @usage
-- -- NATO Tank Platoons invading Gori.
--
-- -- Choose between different 'US Tank Platoon Templates' configurations to be spawned for the
-- -- 'US Tank Platoon Left', 'US Tank Platoon Middle' and 'US Tank Platoon Right' SPAWN objects.
--
-- -- Each new SPAWN will randomize the route, with a defined time interval of 200 seconds with 40% time variation (randomization) and
-- -- with a limit set of maximum 12 Units alive simulteneously and 150 Groups to be spawned during the whole mission.
--
-- Spawn_US_Platoon_Left = SPAWN:New( 'US Tank Platoon Left' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplatePrefixes( "US Tank Platoon Templates" ):InitRandomizeRoute( 3, 3, 2000 )
-- Spawn_US_Platoon_Middle = SPAWN:New( 'US Tank Platoon Middle' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplatePrefixes( "US Tank Platoon Templates" ):InitRandomizeRoute( 3, 3, 2000 )
-- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplatePrefixes( "US Tank Platoon Templates" ):InitRandomizeRoute( 3, 3, 2000 )
function SPAWN:InitRandomizeTemplatePrefixes( SpawnTemplatePrefixes ) --R2.3
self:F( { self.SpawnTemplatePrefix } )
local SpawnTemplateSet = SET_GROUP:New():FilterPrefixes( SpawnTemplatePrefixes ):FilterOnce()
self:InitRandomizeTemplateSet( SpawnTemplateSet )
return self
end
--- When spawning a new group, make the grouping of the units according the InitGrouping setting.
-- @param #SPAWN self
-- @param #number Grouping Indicates the maximum amount of units in the group.
-- @return #SPAWN
function SPAWN:InitGrouping( Grouping ) -- R2.2
self:F( { self.SpawnTemplatePrefix, Grouping } )
self.SpawnGrouping = Grouping
return self
end
--TODO: Add example.
--- This method provides the functionality to randomize the spawning of the Groups at a given list of zones of different types.
-- @param #SPAWN self
@@ -544,7 +731,13 @@ end
-- @usage
-- -- RU Su-34 - AI Ship Attack
-- -- Re-SPAWN the Group(s) after each landing and Engine Shut-Down automatically.
-- SpawnRU_SU34 = SPAWN:New( 'TF1 RU Su-34 Krymsk@AI - Attack Ships' ):Schedule( 2, 3, 1800, 0.4 ):SpawnUncontrolled():InitRandomizeRoute( 1, 1, 3000 ):RepeatOnEngineShutDown()
-- SpawnRU_SU34 = SPAWN
-- :New( 'Su-34' )
-- :Schedule( 2, 3, 1800, 0.4 )
-- :SpawnUncontrolled()
-- :InitRandomizeRoute( 1, 1, 3000 )
-- :InitRepeatOnEngineShutDown()
--
function SPAWN:InitRepeat()
self:F( { self.SpawnTemplatePrefix, self.SpawnIndex } )
@@ -558,6 +751,16 @@ end
--- Respawn group after landing.
-- @param #SPAWN self
-- @return #SPAWN self
-- @usage
-- -- RU Su-34 - AI Ship Attack
-- -- Re-SPAWN the Group(s) after each landing and Engine Shut-Down automatically.
-- SpawnRU_SU34 = SPAWN
-- :New( 'Su-34' )
-- :Schedule( 2, 3, 1800, 0.4 )
-- :SpawnUncontrolled()
-- :InitRandomizeRoute( 1, 1, 3000 )
-- :InitRepeatOnLanding()
--
function SPAWN:InitRepeatOnLanding()
self:F( { self.SpawnTemplatePrefix } )
@@ -572,6 +775,16 @@ end
--- Respawn after landing when its engines have shut down.
-- @param #SPAWN self
-- @return #SPAWN self
-- @usage
-- -- RU Su-34 - AI Ship Attack
-- -- Re-SPAWN the Group(s) after each landing and Engine Shut-Down automatically.
-- SpawnRU_SU34 = SPAWN
-- :New( 'Su-34' )
-- :Schedule( 2, 3, 1800, 0.4 )
-- :SpawnUncontrolled()
-- :InitRandomizeRoute( 1, 1, 3000 )
-- :InitRepeatOnEngineShutDown()
--
function SPAWN:InitRepeatOnEngineShutDown()
self:F( { self.SpawnTemplatePrefix } )
@@ -588,7 +801,8 @@ end
-- @param #SPAWN self
-- @param #string SpawnCleanUpInterval The interval to check for inactive groups within seconds.
-- @return #SPAWN self
-- @usage Spawn_Helicopter:CleanUp( 20 ) -- CleanUp the spawning of the helicopters every 20 seconds when they become inactive.
-- @usage
-- Spawn_Helicopter:InitCleanUp( 20 ) -- CleanUp the spawning of the helicopters every 20 seconds when they become inactive.
function SPAWN:InitCleanUp( SpawnCleanUpInterval )
self:F( { self.SpawnTemplatePrefix, SpawnCleanUpInterval } )
@@ -615,7 +829,11 @@ end
-- @return #SPAWN self
-- @usage
-- -- Define an array of Groups.
-- Spawn_BE_Ground = SPAWN:New( 'BE Ground' ):InitLimit( 2, 24 ):InitArray( 90, "Diamond", 10, 100, 50 )
-- Spawn_BE_Ground = SPAWN
-- :New( 'BE Ground' )
-- :InitLimit( 2, 24 )
-- :InitArray( 90, 10, 100, 50 )
--
function SPAWN:InitArray( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY )
self:F( { self.SpawnTemplatePrefix, SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY } )
@@ -823,6 +1041,18 @@ function SPAWN:SpawnWithIndex( SpawnIndex )
end
end
-- If Heading is given, point all the units towards the given Heading.
if self.SpawnInitHeadingMin then
for UnitID = 1, #SpawnTemplate.units do
SpawnTemplate.units[UnitID].heading = self.SpawnInitHeadingMax and math.random( self.SpawnInitHeadingMin, self.SpawnInitHeadingMax ) or self.SpawnInitHeadingMin
end
end
SpawnTemplate.CategoryID = self.SpawnInitCategory or SpawnTemplate.CategoryID
SpawnTemplate.CountryID = self.SpawnInitCountry or SpawnTemplate.CountryID
SpawnTemplate.CoalitionID = self.SpawnInitCoalition or SpawnTemplate.CoalitionID
if SpawnTemplate.CategoryID == Group.Category.HELICOPTER or SpawnTemplate.CategoryID == Group.Category.AIRPLANE then
if SpawnTemplate.route.points[1].type == "TakeOffParking" then
SpawnTemplate.uncontrolled = self.SpawnUnControlled
@@ -855,7 +1085,8 @@ function SPAWN:SpawnWithIndex( SpawnIndex )
-- If there is a SpawnFunction hook defined, call it.
if self.SpawnFunctionHook then
self.SpawnFunctionHook( self.SpawnGroups[self.SpawnIndex].Group, unpack( self.SpawnFunctionArguments ) )
-- delay calling this for .1 seconds so that it hopefully comes after the BIRTH event of the group.
self.SpawnHookScheduler:Schedule( nil, self.SpawnFunctionHook, { self.SpawnGroups[self.SpawnIndex].Group, unpack( self.SpawnFunctionArguments)}, 0.1 )
end
-- TODO: Need to fix this by putting an "R" in the name of the group when the group repeats.
--if self.Repeat then
@@ -954,6 +1185,151 @@ function SPAWN:OnSpawnGroup( SpawnCallBackFunction, ... )
return self
end
--- Will spawn a group at an @{Airbase}.
-- This method is mostly advisable to be used if you want to simulate spawning units at an airbase.
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.
-- You can use the returned group to further define the route to be followed.
--
-- The @{Airbase#AIRBASE} object must refer to a valid airbase known in the sim.
-- You can use the following enumerations to search for the pre-defined airbases on the current known maps of DCS:
--
-- * @{Airbase#AIRBASE.Caucasus}: The airbases on the Caucasus map.
-- * @{Airbase#AIRBASE.Nevada}: The airbases on the Nevada (NTTR) map.
-- * @{Airbase#AIRBASE.Normandy}: The airbases on the Normandy map.
--
-- Use the method @{Airbase#AIRBASE.FindByName}() to retrieve the airbase object.
-- The known AIRBASE objects are automatically imported at mission start by MOOSE.
-- Therefore, there isn't any New() constructor defined for AIRBASE objects.
--
-- Ships and Farps are added within the mission, and are therefore not known.
-- For these AIRBASE objects, there isn't an @{Airbase#AIRBASE} enumeration defined.
-- You need to provide the **exact name** of the airbase as the parameter to the @{Airbase#AIRBASE.FindByName}() method!
--
-- @param #SPAWN self
-- @param Wrapper.Airbase#AIRBASE SpawnAirbase The @{Airbase} where to spawn the group.
-- @param #SPAWN.Takeoff Takeoff (optional) The location and takeoff method. Default is Hot.
-- @param #number TakeoffAltitude (optional) The altitude above the ground.
-- @return Wrapper.Group#GROUP that was spawned.
-- @return #nil Nothing was spawned.
-- @usage
-- Spawn_Plane = SPAWN:New( "Plane" )
-- Spawn_Plane:SpawnAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Krymsk ), SPAWN.Takeoff.Cold )
-- Spawn_Plane:SpawnAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Krymsk ), SPAWN.Takeoff.Hot )
-- Spawn_Plane:SpawnAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Krymsk ), SPAWN.Takeoff.Runway )
--
-- Spawn_Plane:SpawnAtAirbase( AIRBASE:FindByName( "Carrier" ), SPAWN.Takeoff.Cold )
--
-- Spawn_Heli = SPAWN:New( "Heli")
--
-- Spawn_Heli:SpawnAtAirbase( AIRBASE:FindByName( "FARP Cold" ), SPAWN.Takeoff.Cold )
-- Spawn_Heli:SpawnAtAirbase( AIRBASE:FindByName( "FARP Hot" ), SPAWN.Takeoff.Hot )
-- Spawn_Heli:SpawnAtAirbase( AIRBASE:FindByName( "FARP Runway" ), SPAWN.Takeoff.Runway )
-- Spawn_Heli:SpawnAtAirbase( AIRBASE:FindByName( "FARP Air" ), SPAWN.Takeoff.Air )
--
-- Spawn_Heli:SpawnAtAirbase( AIRBASE:FindByName( "Carrier" ), SPAWN.Takeoff.Cold )
--
function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude ) -- R2.2
self:F( { self.SpawnTemplatePrefix, SpawnAirbase, Takeoff, TakeoffAltitude } )
local PointVec3 = SpawnAirbase:GetPointVec3()
self:T2(PointVec3)
Takeoff = Takeoff or SPAWN.Takeoff.Hot
if self:_GetSpawnIndex( self.SpawnIndex + 1 ) then
local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate
if SpawnTemplate then
self:T( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
local SpawnPoint = SpawnTemplate.route.points[1]
-- These are only for ships.
SpawnPoint.linkUnit = nil
SpawnPoint.helipadId = nil
SpawnPoint.airdromeId = nil
local AirbaseID = SpawnAirbase:GetID()
local AirbaseCategory = SpawnAirbase:GetDesc().category
self:F( { AirbaseCategory = AirbaseCategory } )
if AirbaseCategory == Airbase.Category.SHIP then
SpawnPoint.linkUnit = AirbaseID
SpawnPoint.helipadId = AirbaseID
elseif AirbaseCategory == Airbase.Category.HELIPAD then
SpawnPoint.linkUnit = AirbaseID
SpawnPoint.helipadId = AirbaseID
elseif AirbaseCategory == Airbase.Category.AIRDROME then
SpawnPoint.airdromeId = AirbaseID
end
SpawnPoint.alt = 0
SpawnPoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type
SpawnPoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action
-- Translate the position of the Group Template to the Vec3.
for UnitID = 1, #SpawnTemplate.units do
self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y )
-- These cause a lot of confusion.
local UnitTemplate = SpawnTemplate.units[UnitID]
UnitTemplate.parking = nil
UnitTemplate.parking_id = nil
UnitTemplate.alt = 0
local SX = UnitTemplate.x
local SY = UnitTemplate.y
local BX = SpawnPoint.x
local BY = SpawnPoint.y
local TX = PointVec3.x + ( SX - BX )
local TY = PointVec3.z + ( SY - BY )
UnitTemplate.x = TX
UnitTemplate.y = TY
if Takeoff == GROUP.Takeoff.Air then
UnitTemplate.alt = PointVec3.y + ( TakeoffAltitude or 200 )
--else
-- UnitTemplate.alt = PointVec3.y + 10
end
self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. UnitTemplate.y )
end
SpawnPoint.x = PointVec3.x
SpawnPoint.y = PointVec3.z
if Takeoff == GROUP.Takeoff.Air then
SpawnPoint.alt = PointVec3.y + ( TakeoffAltitude or 200 )
--else
-- SpawnPoint.alt = PointVec3.y + 10
end
SpawnTemplate.x = PointVec3.x
SpawnTemplate.y = PointVec3.z
local GroupSpawned = self:SpawnWithIndex( self.SpawnIndex )
-- When spawned in the air, we need to generate a Takeoff Event
if Takeoff == GROUP.Takeoff.Air then
for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do
SCHEDULER:New( nil, BASE.CreateEventTakeoff, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() } , 1 )
end
end
return GroupSpawned
end
end
return nil
end
--- Will spawn a group from a Vec3 in 3D space.
-- This method is mostly advisable to be used if you want to simulate spawning units in the air, like helicopters or airplanes.
@@ -982,29 +1358,40 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
if SpawnTemplate then
self:T( { "Current point of ", self.SpawnTemplatePrefix, Vec3 } )
local TemplateHeight = SpawnTemplate.route and SpawnTemplate.route.points[1].alt or nil
SpawnTemplate.route = SpawnTemplate.route or {}
SpawnTemplate.route.points = SpawnTemplate.route.points or {}
SpawnTemplate.route.points[1] = SpawnTemplate.route.points[1] or {}
SpawnTemplate.route.points[1].x = SpawnTemplate.route.points[1].x or 0
SpawnTemplate.route.points[1].y = SpawnTemplate.route.points[1].y or 0
-- Translate the position of the Group Template to the Vec3.
for UnitID = 1, #SpawnTemplate.units do
self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y )
--self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y )
local UnitTemplate = SpawnTemplate.units[UnitID]
local SX = UnitTemplate.x
local SY = UnitTemplate.y
local SX = UnitTemplate.x or 0
local SY = UnitTemplate.y or 0
local BX = SpawnTemplate.route.points[1].x
local BY = SpawnTemplate.route.points[1].y
local TX = Vec3.x + ( SX - BX )
local TY = Vec3.z + ( SY - BY )
SpawnTemplate.units[UnitID].x = TX
SpawnTemplate.units[UnitID].y = TY
SpawnTemplate.units[UnitID].alt = Vec3.y
if SpawnTemplate.CategoryID ~= Group.Category.SHIP then
SpawnTemplate.units[UnitID].alt = Vec3.y or TemplateHeight
end
self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y )
end
SpawnTemplate.route.points[1].x = Vec3.x
SpawnTemplate.route.points[1].y = Vec3.z
SpawnTemplate.route.points[1].alt = Vec3.y
if SpawnTemplate.CategoryID ~= Group.Category.SHIP then
SpawnTemplate.route.points[1].alt = Vec3.y or TemplateHeight
end
SpawnTemplate.x = Vec3.x
SpawnTemplate.y = Vec3.z
SpawnTemplate.alt = Vec3.y or TemplateHeight
return self:SpawnWithIndex( self.SpawnIndex )
end
@@ -1013,36 +1400,135 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
return nil
end
--- Will spawn a group from a Coordinate in 3D space.
-- This method is mostly advisable to be used if you want to simulate spawning units in the air, like helicopters or airplanes.
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.
-- You can use the returned group to further define the route to be followed.
-- @param #SPAWN self
-- @param Core.Point#Coordinate Coordinate The Coordinate coordinates where to spawn the group.
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
-- @return Wrapper.Group#GROUP that was spawned.
-- @return #nil Nothing was spawned.
function SPAWN:SpawnFromCoordinate( Coordinate, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, SpawnIndex } )
return self:SpawnFromVec3( Coordinate:GetVec3(), SpawnIndex )
end
--- Will spawn a group from a PointVec3 in 3D space.
-- This method is mostly advisable to be used if you want to simulate spawning units in the air, like helicopters or airplanes.
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.
-- You can use the returned group to further define the route to be followed.
-- @param #SPAWN self
-- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 coordinates where to spawn the group.
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
-- @return Wrapper.Group#GROUP that was spawned.
-- @return #nil Nothing was spawned.
-- @usage
--
-- local SpawnPointVec3 = ZONE:New( ZoneName ):GetPointVec3( 2000 ) -- Get the center of the ZONE object at 2000 meters from the ground.
--
-- -- Spawn at the zone center position at 2000 meters from the ground!
-- SpawnAirplanes:SpawnFromPointVec3( SpawnPointVec3 )
--
function SPAWN:SpawnFromPointVec3( PointVec3, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, SpawnIndex } )
return self:SpawnFromVec3( PointVec3:GetVec3(), SpawnIndex )
end
--- Will spawn a group from a Vec2 in 3D space.
-- This method is mostly advisable to be used if you want to simulate spawning groups on the ground from air units, like vehicles.
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.
-- You can use the returned group to further define the route to be followed.
-- @param #SPAWN self
-- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 coordinates where to spawn the group.
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
-- @return Wrapper.Group#GROUP that was spawned.
-- @return #nil Nothing was spawned.
function SPAWN:SpawnFromVec2( Vec2, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, Vec2, SpawnIndex } )
-- @usage
--
-- local SpawnVec2 = ZONE:New( ZoneName ):GetVec2()
--
-- -- Spawn at the zone center position at the height specified in the ME of the group template!
-- SpawnAirplanes:SpawnFromVec2( SpawnVec2 )
--
-- -- Spawn from the static position at the height randomized between 2000 and 4000 meters.
-- SpawnAirplanes:SpawnFromVec2( SpawnVec2, 2000, 4000 )
--
function SPAWN:SpawnFromVec2( Vec2, MinHeight, MaxHeight, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, self.SpawnIndex, Vec2, MinHeight, MaxHeight, SpawnIndex } )
local PointVec2 = POINT_VEC2:NewFromVec2( Vec2 )
return self:SpawnFromVec3( PointVec2:GetVec3(), SpawnIndex )
local Height = nil
if MinHeight and MaxHeight then
Height = math.random( MinHeight, MaxHeight)
end
return self:SpawnFromVec3( { x = Vec2.x, y = Height, z = Vec2.y }, SpawnIndex ) -- y can be nil. In this case, spawn on the ground for vehicles, and in the template altitude for air.
end
--- Will spawn a group from a POINT_VEC2 in 3D space.
-- This method is mostly advisable to be used if you want to simulate spawning groups on the ground from air units, like vehicles.
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.
-- You can use the returned group to further define the route to be followed.
-- @param #SPAWN self
-- @param Core.Point#POINT_VEC2 PointVec2 The PointVec2 coordinates where to spawn the group.
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
-- @return Wrapper.Group#GROUP that was spawned.
-- @return #nil Nothing was spawned.
-- @usage
--
-- local SpawnPointVec2 = ZONE:New( ZoneName ):GetPointVec2()
--
-- -- Spawn at the zone center position at the height specified in the ME of the group template!
-- SpawnAirplanes:SpawnFromPointVec2( SpawnPointVec2 )
--
-- -- Spawn from the static position at the height randomized between 2000 and 4000 meters.
-- SpawnAirplanes:SpawnFromPointVec2( SpawnPointVec2, 2000, 4000 )
--
function SPAWN:SpawnFromPointVec2( PointVec2, MinHeight, MaxHeight, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, self.SpawnIndex } )
return self:SpawnFromVec2( PointVec2:GetVec2(), MinHeight, MaxHeight, SpawnIndex )
end
--- Will spawn a group from a hosting unit. This method is mostly advisable to be used if you want to simulate spawning from air units, like helicopters, which are dropping infantry into a defined Landing Zone.
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.
-- You can use the returned group to further define the route to be followed.
-- @param #SPAWN self
-- @param Wrapper.Unit#UNIT HostUnit The air or ground unit dropping or unloading the group.
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
-- @return Wrapper.Group#GROUP that was spawned.
-- @return #nil Nothing was spawned.
function SPAWN:SpawnFromUnit( HostUnit, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, HostUnit, SpawnIndex } )
-- @usage
--
-- local SpawnStatic = STATIC:FindByName( StaticName )
--
-- -- Spawn from the static position at the height specified in the ME of the group template!
-- SpawnAirplanes:SpawnFromUnit( SpawnStatic )
--
-- -- Spawn from the static position at the height randomized between 2000 and 4000 meters.
-- SpawnAirplanes:SpawnFromUnit( SpawnStatic, 2000, 4000 )
--
function SPAWN:SpawnFromUnit( HostUnit, MinHeight, MaxHeight, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, HostUnit, MinHeight, MaxHeight, SpawnIndex } )
if HostUnit and HostUnit:IsAlive() ~= nil then -- and HostUnit:getUnit(1):inAir() == false then
return self:SpawnFromVec3( HostUnit:GetVec3(), SpawnIndex )
return self:SpawnFromVec2( HostUnit:GetVec2(), MinHeight, MaxHeight, SpawnIndex )
end
return nil
@@ -1052,14 +1538,26 @@ end
-- You can use the returned group to further define the route to be followed.
-- @param #SPAWN self
-- @param Wrapper.Static#STATIC HostStatic The static dropping or unloading the group.
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
-- @return Wrapper.Group#GROUP that was spawned.
-- @return #nil Nothing was spawned.
function SPAWN:SpawnFromStatic( HostStatic, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, HostStatic, SpawnIndex } )
-- @usage
--
-- local SpawnStatic = STATIC:FindByName( StaticName )
--
-- -- Spawn from the static position at the height specified in the ME of the group template!
-- SpawnAirplanes:SpawnFromStatic( SpawnStatic )
--
-- -- Spawn from the static position at the height randomized between 2000 and 4000 meters.
-- SpawnAirplanes:SpawnFromStatic( SpawnStatic, 2000, 4000 )
--
function SPAWN:SpawnFromStatic( HostStatic, MinHeight, MaxHeight, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, HostStatic, MinHeight, MaxHeight, SpawnIndex } )
if HostStatic and HostStatic:IsAlive() then
return self:SpawnFromVec3( HostStatic:GetVec3(), SpawnIndex )
return self:SpawnFromVec2( HostStatic:GetVec2(), MinHeight, MaxHeight, SpawnIndex )
end
return nil
@@ -1072,17 +1570,38 @@ end
-- @param #SPAWN self
-- @param Core.Zone#ZONE Zone The zone where the group is to be spawned.
-- @param #boolean RandomizeGroup (optional) Randomization of the @{Group} position in the zone.
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
-- @return Wrapper.Group#GROUP that was spawned.
-- @return #nil when nothing was spawned.
function SPAWN:SpawnInZone( Zone, RandomizeGroup, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, Zone, RandomizeGroup, SpawnIndex } )
-- @usage
--
-- local SpawnZone = ZONE:New( ZoneName )
--
-- -- Spawn at the zone center position at the height specified in the ME of the group template!
-- SpawnAirplanes:SpawnInZone( SpawnZone )
--
-- -- Spawn in the zone at a random position at the height specified in the Me of the group template.
-- SpawnAirplanes:SpawnInZone( SpawnZone, true )
--
-- -- Spawn in the zone at a random position at the height randomized between 2000 and 4000 meters.
-- SpawnAirplanes:SpawnInZone( SpawnZone, true, 2000, 4000 )
--
-- -- Spawn at the zone center position at the height randomized between 2000 and 4000 meters.
-- SpawnAirplanes:SpawnInZone( SpawnZone, false, 2000, 4000 )
--
-- -- Spawn at the zone center position at the height randomized between 2000 and 4000 meters.
-- SpawnAirplanes:SpawnInZone( SpawnZone, nil, 2000, 4000 )
--
function SPAWN:SpawnInZone( Zone, RandomizeGroup, MinHeight, MaxHeight, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, Zone, RandomizeGroup, MinHeight, MaxHeight, SpawnIndex } )
if Zone then
if RandomizeGroup then
return self:SpawnFromVec2( Zone:GetRandomVec2(), SpawnIndex )
return self:SpawnFromVec2( Zone:GetRandomVec2(), MinHeight, MaxHeight, SpawnIndex )
else
return self:SpawnFromVec2( Zone:GetVec2(), SpawnIndex )
return self:SpawnFromVec2( Zone:GetVec2(), MinHeight, MaxHeight, SpawnIndex )
end
end
@@ -1109,6 +1628,19 @@ function SPAWN:InitUnControlled( UnControlled )
end
--- Get the Coordinate of the Group that is Late Activated as the template for the SPAWN object.
-- @param #SPAWN self
-- @return Core.Point#COORDINATE The Coordinate
function SPAWN:GetCoordinate()
local LateGroup = GROUP:FindByName( self.SpawnTemplatePrefix )
if LateGroup then
return LateGroup:GetCoordinate()
end
return nil
end
--- Will return the SpawnGroupName either with with a specific count number or without any count.
-- @param #SPAWN self
@@ -1348,7 +1880,10 @@ function SPAWN:_GetTemplate( SpawnTemplatePrefix )
local SpawnTemplate = nil
SpawnTemplate = routines.utils.deepCopy( _DATABASE.Templates.Groups[SpawnTemplatePrefix].Template )
local Template = _DATABASE.Templates.Groups[SpawnTemplatePrefix].Template
self:F( { Template = Template } )
SpawnTemplate = UTILS.DeepCopy( _DATABASE.Templates.Groups[SpawnTemplatePrefix].Template )
if SpawnTemplate == nil then
error( 'No Template returned for SpawnTemplatePrefix = ' .. SpawnTemplatePrefix )
@@ -1367,10 +1902,15 @@ end
-- @param #string SpawnTemplatePrefix
-- @param #number SpawnIndex
-- @return #SPAWN self
function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex )
function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) --R2.2
self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } )
local SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix )
-- if not self.SpawnTemplate then
-- self.SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix )
-- end
local SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix )
--local SpawnTemplate = self.SpawnTemplate
SpawnTemplate.name = self:SpawnGroupName( SpawnIndex )
SpawnTemplate.groupId = nil
@@ -1382,6 +1922,23 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex )
SpawnTemplate.visible = false
end
if self.SpawnGrouping then
local UnitAmount = #SpawnTemplate.units
self:F( { UnitAmount = UnitAmount, SpawnGrouping = self.SpawnGrouping } )
if UnitAmount > self.SpawnGrouping then
for UnitID = self.SpawnGrouping + 1, UnitAmount do
SpawnTemplate.units[UnitID] = nil
end
else
if UnitAmount < self.SpawnGrouping then
for UnitID = UnitAmount + 1, self.SpawnGrouping do
SpawnTemplate.units[UnitID] = UTILS.DeepCopy( SpawnTemplate.units[1] )
SpawnTemplate.units[UnitID].unitId = nil
end
end
end
end
if self.SpawnInitKeepUnitNames == false then
for UnitID = 1, #SpawnTemplate.units do
SpawnTemplate.units[UnitID].name = string.format( SpawnTemplate.name .. '-%02d', UnitID )
@@ -1446,7 +2003,7 @@ function SPAWN:_RandomizeTemplate( SpawnIndex )
if self.SpawnRandomizeTemplate then
self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix = self.SpawnTemplatePrefixTable[ math.random( 1, #self.SpawnTemplatePrefixTable ) ]
self.SpawnGroups[SpawnIndex].SpawnTemplate = self:_Prepare( self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix, SpawnIndex )
self.SpawnGroups[SpawnIndex].SpawnTemplate.route = routines.utils.deepCopy( self.SpawnTemplate.route )
self.SpawnGroups[SpawnIndex].SpawnTemplate.route = UTILS.DeepCopy( self.SpawnTemplate.route )
self.SpawnGroups[SpawnIndex].SpawnTemplate.x = self.SpawnTemplate.x
self.SpawnGroups[SpawnIndex].SpawnTemplate.y = self.SpawnTemplate.y
self.SpawnGroups[SpawnIndex].SpawnTemplate.start_time = self.SpawnTemplate.start_time
@@ -1565,6 +2122,7 @@ function SPAWN:_GetSpawnIndex( SpawnIndex )
if ( self.SpawnMaxGroups == 0 ) or ( SpawnIndex <= self.SpawnMaxGroups ) then
if ( self.SpawnMaxUnitsAlive == 0 ) or ( self.AliveUnits + #self.SpawnTemplate.units <= self.SpawnMaxUnitsAlive ) or self.UnControlled == true then
self:F( { SpawnCount = self.SpawnCount, SpawnIndex = SpawnIndex } )
if SpawnIndex and SpawnIndex >= self.SpawnCount + 1 then
self.SpawnCount = self.SpawnCount + 1
SpawnIndex = self.SpawnCount

View File

@@ -1,12 +1,12 @@
--- (R2.1) **Core** -- Spawn dynamically new STATICs in your missions.
--- **Core** -- Spawn dynamically new STATICs in your missions.
--
-- ![Banner Image](..\Presentations\SPAWNSTATIC\Dia1.JPG)
--
-- ====
-- ===
--
-- SPAWNSTATIC spawns static structures in your missions dynamically. See below the SPAWNSTATIC class documentation.
--
-- ====
-- ===
--
-- # Demo Missions
--
@@ -16,32 +16,18 @@
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
-- ===
--
-- # YouTube Channel
--
-- ### [SPAWNSTATIC YouTube Channel]()
--
-- ====
--
-- # **API CHANGE HISTORY**
--
-- The underlying change log documents the API changes. Please read this carefully. The following notation is used:
--
-- * **Added** parts are expressed in bold type face.
-- * _Removed_ parts are expressed in italic type face.
--
-- Hereby the change log:
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ### Authors:
--
-- * **FlightControl**: Design & Programming
-- ===
--
-- @module SpawnStatic
@@ -95,14 +81,16 @@ SPAWNSTATIC = {
-- @param #SPAWNSTATIC self
-- @param #string SpawnTemplatePrefix is the name of the Group in the ME that defines the Template. Each new group will have the name starting with SpawnTemplatePrefix.
-- @return #SPAWNSTATIC
function SPAWNSTATIC:NewFromStatic( SpawnTemplatePrefix, CountryID ) --R2.1
function SPAWNSTATIC:NewFromStatic( SpawnTemplatePrefix, SpawnCountryID ) --R2.1
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
self:F( { SpawnTemplatePrefix } )
local TemplateStatic = StaticObject.getByName( SpawnTemplatePrefix )
local TemplateStatic, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticUnitTemplate( SpawnTemplatePrefix )
if TemplateStatic then
self.SpawnTemplatePrefix = SpawnTemplatePrefix
self.CountryID = CountryID
self.CountryID = SpawnCountryID or CountryID
self.CategoryID = CategoryID
self.CoalitionID = CoalitionID
self.SpawnIndex = 0
else
error( "SPAWNSTATIC:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" )
@@ -131,6 +119,40 @@ function SPAWNSTATIC:NewFromType( SpawnTypeName, SpawnShapeName, SpawnCategory,
end
--- Creates a new @{Static} at the original position.
-- @param #SPAWNSTATIC self
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
-- @param #string (optional) The name of the new static.
-- @return #SPAWNSTATIC
function SPAWNSTATIC:Spawn( Heading, NewName ) --R2.3
self:F( { Heading, NewName } )
local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix )
if StaticTemplate then
local CountryID = self.CountryID
local CountryName = _DATABASE.COUNTRY_NAME[CountryID]
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
StaticTemplate.heading = ( Heading / 180 ) * math.pi
StaticTemplate.CountryID = nil
StaticTemplate.CoalitionID = nil
StaticTemplate.CategoryID = nil
local Static = coalition.addStaticObject( CountryID, StaticTemplate )
self.SpawnIndex = self.SpawnIndex + 1
return Static
end
return nil
end
--- Creates a new @{Static} from a POINT_VEC2.
-- @param #SPAWNSTATIC self
-- @param Core.Point#POINT_VEC2 PointVec2 The 2D coordinate where to spawn the static.
@@ -140,27 +162,101 @@ end
function SPAWNSTATIC:SpawnFromPointVec2( PointVec2, Heading, NewName ) --R2.1
self:F( { PointVec2, Heading, NewName } )
local CountryName = _DATABASE.COUNTRY_NAME[self.CountryID]
local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix )
if StaticTemplate then
local CountryID = self.CountryID
local CountryName = _DATABASE.COUNTRY_NAME[CountryID]
StaticTemplate.x = PointVec2.x
StaticTemplate.y = PointVec2.z
StaticTemplate.units = nil
StaticTemplate.route = nil
StaticTemplate.groupId = nil
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
StaticTemplate.heading = ( Heading / 180 ) * math.pi
StaticTemplate.CountryID = nil
StaticTemplate.CoalitionID = nil
StaticTemplate.CategoryID = nil
local Static = coalition.addStaticObject( CountryID, StaticTemplate )
self.SpawnIndex = self.SpawnIndex + 1
return Static
end
return nil
end
--- Creates the original @{Static} at a POINT_VEC2.
-- @param #SPAWNSTATIC self
-- @param Core.Point#POINT_VEC2 PointVec2 The 2D coordinate where to spawn the static.
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
-- @param #string (optional) The name of the new static.
-- @return #SPAWNSTATIC
function SPAWNSTATIC:ReSpawn()
local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix )
StaticTemplate.x = PointVec2:GetLat()
StaticTemplate.y = PointVec2:GetLon()
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
StaticTemplate.heading = ( Heading / 180 ) * math.pi
StaticTemplate.CountryID = nil
StaticTemplate.CoalitionID = nil
StaticTemplate.CategoryID = nil
local Static = coalition.addStaticObject( self.CountryID, StaticTemplate )
self.SpawnIndex = self.SpawnIndex + 1
if StaticTemplate then
return Static
local CountryID = self.CountryID
local CountryName = _DATABASE.COUNTRY_NAME[CountryID]
StaticTemplate.units = nil
StaticTemplate.route = nil
StaticTemplate.groupId = nil
StaticTemplate.CountryID = nil
StaticTemplate.CoalitionID = nil
StaticTemplate.CategoryID = nil
local Static = coalition.addStaticObject( CountryID, StaticTemplate )
return Static
end
return nil
end
--- Creates the original @{Static} at a POINT_VEC2.
-- @param #SPAWNSTATIC self
-- @param Core.Point#COORDINATE Coordinate The 2D coordinate where to spawn the static.
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
-- @return #SPAWNSTATIC
function SPAWNSTATIC:ReSpawnAt( Coordinate, Heading )
local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix )
if StaticTemplate then
local CountryID = self.CountryID
StaticTemplate.x = Coordinate.x
StaticTemplate.y = Coordinate.z
StaticTemplate.heading = Heading and ( ( Heading / 180 ) * math.pi ) or StaticTemplate.heading
StaticTemplate.CountryID = nil
StaticTemplate.CoalitionID = nil
StaticTemplate.CategoryID = nil
local Static = coalition.addStaticObject( CountryID, StaticTemplate )
return Static
end
return nil
end
--- Creates a new @{Static} from a @{Zone}.
-- @param #SPAWNSTATIC self
-- @param Core.Zone#ZONE_BASE Zone The Zone where to spawn the static.

View File

@@ -1,4 +1,4 @@
--- **Core 2.1** -- Management of SPOT logistics, that can be transported from and to transportation carriers.
--- **Core** -- Management of SPOT logistics, that can be transported from and to transportation carriers.
--
-- ![Banner Image](..\Presentations\SPOT\Dia1.JPG)
--
@@ -11,7 +11,7 @@
-- * Provide a @{Unit} as a target, instead of a point.
-- * Implement a status machine, LaseOn, LaseOff.
--
-- ====
-- ===
--
-- # Demo Missions
--
@@ -21,7 +21,7 @@
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
-- ===
--
-- # YouTube Channel
--
@@ -29,18 +29,14 @@
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- * [**Ciribob**](https://forums.eagle.ru/member.php?u=112175): Showing the way how to lase targets + how laser codes work!!! Explained the autolase script.
-- * [**EasyEB**](https://forums.eagle.ru/member.php?u=112055): Ideas and Beta Testing
-- * [**Wingthor**](https://forums.eagle.ru/member.php?u=123698): Beta Testing
--
--
-- ### Authors:
--
-- * **FlightControl**: Design & Programming
-- ===
--
-- @module Spot
@@ -204,7 +200,7 @@ do
-- @param #number LaserCode
-- @param #number Duration
function SPOT:onafterLaseOn( From, Event, To, Target, LaserCode, Duration )
self:E( { "LaseOn", Target, LaserCode, Duration } )
self:F( { "LaseOn", Target, LaserCode, Duration } )
local function StopLase( self )
self:LaseOff()
@@ -226,16 +222,16 @@ do
self:HandleEvent( EVENTS.Dead )
self:__Lasing( -0.2 )
self:__Lasing( -1 )
end
--- @param #SPOT self
-- @param Core.Event#EVENTDATA EventData
function SPOT:OnEventDead(EventData)
self:E( { Dead = EventData.IniDCSUnitName, Target = self.Target } )
self:F( { Dead = EventData.IniDCSUnitName, Target = self.Target } )
if self.Target then
if EventData.IniDCSUnitName == self.Target:GetName() then
self:E( {"Target dead ", self.Target:GetName() } )
self:F( {"Target dead ", self.Target:GetName() } )
self:Destroyed()
self:LaseOff()
end
@@ -253,7 +249,7 @@ do
self.SpotLaser:setPoint( self.Target:GetPointVec3():AddY(1):GetVec3() )
self:__Lasing( -0.2 )
else
self:E( { "Target is not alive", self.Target:IsAlive() } )
self:F( { "Target is not alive", self.Target:IsAlive() } )
end
end
@@ -265,7 +261,7 @@ do
-- @return #SPOT
function SPOT:onafterLaseOff( From, Event, To )
self:E( {"Stopped lasing for ", self.Target:GetName() , SpotIR = self.SportIR, SpotLaser = self.SpotLaser } )
self:F( {"Stopped lasing for ", self.Target:GetName() , SpotIR = self.SportIR, SpotLaser = self.SpotLaser } )
self.Lasing = false

View File

@@ -0,0 +1,95 @@
--- **Core (WIP)** -- Manage user flags.
--
-- ===
--
-- Management of DCS User Flags.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module UserFlag
do -- UserFlag
--- @type USERFLAG
-- @extends Core.Base#BASE
--- # USERFLAG class, extends @{Base#BASE}
--
-- Management of DCS User Flags.
--
-- ## 1. USERFLAG constructor
--
-- * @{#USERFLAG.New}(): Creates a new USERFLAG object.
--
-- @field #USERFLAG
USERFLAG = {
ClassName = "USERFLAG",
}
--- USERFLAG Constructor.
-- @param #USERFLAG self
-- @param #string UserFlagName The name of the userflag, which is a free text string.
-- @return #USERFLAG
function USERFLAG:New( UserFlagName ) --R2.3
local self = BASE:Inherit( self, BASE:New() ) -- #USERFLAG
self.UserFlagName = UserFlagName
return self
end
--- Set the userflag to a given Number.
-- @param #USERFLAG self
-- @param #number Number The number value to be checked if it is the same as the userflag.
-- @return #USERFLAG The userflag instance.
-- @usage
-- local BlueVictory = USERFLAG:New( "VictoryBlue" )
-- BlueVictory:Set( 100 ) -- Set the UserFlag VictoryBlue to 100.
--
function USERFLAG:Set( Number ) --R2.3
self:F( { Number = Number } )
trigger.action.setUserFlag( self.UserFlagName, Number )
return self
end
--- Get the userflag Number.
-- @param #USERFLAG self
-- @return #number Number The number value to be checked if it is the same as the userflag.
-- @usage
-- local BlueVictory = USERFLAG:New( "VictoryBlue" )
-- local BlueVictoryValue = BlueVictory:Get() -- Get the UserFlag VictoryBlue value.
--
function USERFLAG:Get( Number ) --R2.3
return trigger.misc.getUserFlag( self.UserFlagName )
end
--- Check if the userflag has a value of Number.
-- @param #USERFLAG self
-- @param #number Number The number value to be checked if it is the same as the userflag.
-- @return #boolean true if the Number is the value of the userflag.
-- @usage
-- local BlueVictory = USERFLAG:New( "VictoryBlue" )
-- if BlueVictory:Is( 1 ) then
-- return "Blue has won"
-- end
function USERFLAG:Is( Number ) --R2.3
return trigger.misc.getUserFlag( self.UserFlagName ) == Number
end
end

View File

@@ -0,0 +1,129 @@
--- **Core (WIP)** -- Manage user sound.
--
-- ===
--
-- Management of DCS User Sound.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module UserSound
do -- UserSound
--- @type USERSOUND
-- @extends Core.Base#BASE
--- # USERSOUND class, extends @{Base#BASE}
--
-- Management of DCS User Sound.
--
-- ## 1. USERSOUND constructor
--
-- * @{#USERSOUND.New}(): Creates a new USERSOUND object.
--
-- @field #USERSOUND
USERSOUND = {
ClassName = "USERSOUND",
}
--- USERSOUND Constructor.
-- @param #USERSOUND self
-- @param #string UserSoundFileName The filename of the usersound.
-- @return #USERSOUND
function USERSOUND:New( UserSoundFileName ) --R2.3
local self = BASE:Inherit( self, BASE:New() ) -- #USERSOUND
self.UserSoundFileName = UserSoundFileName
return self
end
--- Set usersound filename.
-- @param #USERSOUND self
-- @param #string UserSoundFileName The filename of the usersound.
-- @return #USERSOUND The usersound instance.
-- @usage
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
-- BlueVictory:SetFileName( "BlueVictoryLoud.ogg" ) -- Set the BlueVictory to change the file name to play a louder sound.
--
function USERSOUND:SetFileName( UserSoundFileName ) --R2.3
self.UserSoundFileName = UserSoundFileName
return self
end
--- Play the usersound to all players.
-- @param #USERSOUND self
-- @return #USERSOUND The usersound instance.
-- @usage
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
-- BlueVictory:ToAll() -- Play the sound that Blue has won.
--
function USERSOUND:ToAll() --R2.3
trigger.action.outSound( self.UserSoundFileName )
return self
end
--- Play the usersound to the given coalition.
-- @param #USERSOUND self
-- @param Dcs.DCScoalition#coalition Coalition The coalition to play the usersound to.
-- @return #USERSOUND The usersound instance.
-- @usage
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
-- BlueVictory:ToCoalition( coalition.side.BLUE ) -- Play the sound that Blue has won to the blue coalition.
--
function USERSOUND:ToCoalition( Coalition ) --R2.3
trigger.action.outSoundForCoalition(Coalition, self.UserSoundFileName )
return self
end
--- Play the usersound to the given country.
-- @param #USERSOUND self
-- @param Dcs.DCScountry#country Country The country to play the usersound to.
-- @return #USERSOUND The usersound instance.
-- @usage
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
-- BlueVictory:ToCountry( country.id.USA ) -- Play the sound that Blue has won to the USA country.
--
function USERSOUND:ToCountry( Country ) --R2.3
trigger.action.outSoundForCountry( Country, self.UserSoundFileName )
return self
end
--- Play the usersound to the given @{Group}.
-- @param #USERSOUND self
-- @param Wrapper.Group#GROUP Group The @{Group} to play the usersound to.
-- @return #USERSOUND The usersound instance.
-- @usage
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
-- local PlayerGroup = GROUP:FindByName( "PlayerGroup" ) -- Search for the active group named "PlayerGroup", that contains a human player.
-- BlueVictory:ToGroup( PlayerGroup ) -- Play the sound that Blue has won to the player group.
--
function USERSOUND:ToGroup( Group ) --R2.3
trigger.action.outSoundForGroup( Group:GetID(), self.UserSoundFileName )
return self
end
end

View File

@@ -0,0 +1,184 @@
--- **Core** -- VELOCITY models a speed, which can be expressed in various formats according the Settings.
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @module Velocity
do -- Velocity
--- @type VELOCITY
-- @extends Core.Base#BASE
--- # VELOCITY class, extends @{Base#BASE}
--
-- VELOCITY models a speed, which can be expressed in various formats according the Settings.
--
-- ## 1. VELOCITY constructor
--
-- * @{#VELOCITY.New}(): Creates a new VELOCITY object.
--
-- @field #VELOCITY
VELOCITY = {
ClassName = "VELOCITY",
}
--- VELOCITY Constructor.
-- @param #VELOCITY self
-- @param #number VelocityMps The velocity in meters per second.
-- @return #VELOCITY
function VELOCITY:New( VelocityMps )
local self = BASE:Inherit( self, BASE:New() ) -- #VELOCITY
self:F( {} )
self.Velocity = VelocityMps
return self
end
--- Set the velocity in Mps (meters per second).
-- @param #VELOCITY self
-- @param #number VelocityMps The velocity in meters per second.
-- @return #VELOCITY
function VELOCITY:Set( VelocityMps )
self.Velocity = VelocityMps
return self
end
--- Get the velocity in Mps (meters per second).
-- @param #VELOCITY self
-- @return #number The velocity in meters per second.
function VELOCITY:Get()
return self.Velocity
end
--- Set the velocity in Kmph (kilometers per hour).
-- @param #VELOCITY self
-- @param #number VelocityKmph The velocity in kilometers per hour.
-- @return #VELOCITY
function VELOCITY:SetKmph( VelocityKmph )
self.Velocity = UTILS.KmphToMps( VelocityKmph )
return self
end
--- Get the velocity in Kmph (kilometers per hour).
-- @param #VELOCITY self
-- @return #number The velocity in kilometers per hour.
function VELOCITY:GetKmph()
return UTILS.MpsToKmph( self.Velocity )
end
--- Set the velocity in Miph (miles per hour).
-- @param #VELOCITY self
-- @param #number VelocityMiph The velocity in miles per hour.
-- @return #VELOCITY
function VELOCITY:SetMiph( VelocityMiph )
self.Velocity = UTILS.MiphToMps( VelocityMiph )
return self
end
--- Get the velocity in Miph (miles per hour).
-- @param #VELOCITY self
-- @return #number The velocity in miles per hour.
function VELOCITY:GetMiph()
return UTILS.MpsToMiph( self.Velocity )
end
--- Get the velocity in text, according the player @{Settings}.
-- @param #VELOCITY self
-- @param Core.Settings#SETTINGS Settings
-- @return #string The velocity in text.
function VELOCITY:GetText( Settings )
local Settings = Settings or _SETTINGS
if self.Velocity ~= 0 then
if Settings:IsMetric() then
return string.format( "%d km/h", UTILS.MpsToKmph( self.Velocity ) )
else
return string.format( "%d mi/h", UTILS.MpsToMiph( self.Velocity ) )
end
else
return "stationary"
end
end
--- Get the velocity in text, according the player or default @{Settings}.
-- @param #VELOCITY self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @param Core.Settings#SETTINGS Settings
-- @return #string The velocity in text according the player or default @{Settings}
function VELOCITY:ToString( VelocityGroup, Settings ) -- R2.3
self:F( { Group = VelocityGroup and VelocityGroup:GetName() } )
local Settings = Settings or ( VelocityGroup and _DATABASE:GetPlayerSettings( VelocityGroup:GetPlayerName() ) ) or _SETTINGS
return self:GetText( Settings )
end
end
do -- VELOCITY_POSITIONABLE
--- @type VELOCITY_POSITIONABLE
-- @extends Core.Base#BASE
--- # VELOCITY_POSITIONABLE class, extends @{Base#BASE}
--
-- VELOCITY_POSITIONABLE monitors the speed of an @{Positionable} in the simulation, which can be expressed in various formats according the Settings.
--
-- ## 1. VELOCITY_POSITIONABLE constructor
--
-- * @{#VELOCITY_POSITIONABLE.New}(): Creates a new VELOCITY_POSITIONABLE object.
--
-- @field #VELOCITY_POSITIONABLE
VELOCITY_POSITIONABLE = {
ClassName = "VELOCITY_POSITIONABLE",
}
--- VELOCITY_POSITIONABLE Constructor.
-- @param #VELOCITY_POSITIONABLE self
-- @param Wrapper.Positionable#POSITIONABLE Positionable The Positionable to monitor the speed.
-- @return #VELOCITY_POSITIONABLE
function VELOCITY_POSITIONABLE:New( Positionable )
local self = BASE:Inherit( self, VELOCITY:New() ) -- #VELOCITY_POSITIONABLE
self:F( {} )
self.Positionable = Positionable
return self
end
--- Get the velocity in Mps (meters per second).
-- @param #VELOCITY_POSITIONABLE self
-- @return #number The velocity in meters per second.
function VELOCITY_POSITIONABLE:Get()
return self.Positionable:GetVelocityMPS() or 0
end
--- Get the velocity in Kmph (kilometers per hour).
-- @param #VELOCITY_POSITIONABLE self
-- @return #number The velocity in kilometers per hour.
function VELOCITY_POSITIONABLE:GetKmph()
return UTILS.MpsToKmph( self.Positionable:GetVelocityMPS() or 0)
end
--- Get the velocity in Miph (miles per hour).
-- @param #VELOCITY_POSITIONABLE self
-- @return #number The velocity in miles per hour.
function VELOCITY_POSITIONABLE:GetMiph()
return UTILS.MpsToMiph( self.Positionable:GetVelocityMPS() or 0 )
end
--- Get the velocity in text, according the player or default @{Settings}.
-- @param #VELOCITY_POSITIONABLE self
-- @return #string The velocity in text according the player or default @{Settings}
function VELOCITY_POSITIONABLE:ToString() -- R2.3
self:F( { Group = self.Positionable and self.Positionable:GetName() } )
local Settings = Settings or ( self.Positionable and _DATABASE:GetPlayerSettings( self.Positionable:GetPlayerName() ) ) or _SETTINGS
self.Velocity = self.Positionable:GetVelocityMPS()
return self:GetText( Settings )
end
end

View File

@@ -1,4 +1,4 @@
--- **Core** - ZONE classes define **zones** within your mission of **various forms**, with **various capabilities**.
--- **Core** -- ZONE classes define **zones** within your mission of **various forms**, with **various capabilities**.
--
-- ![Banner Image](..\Presentations\ZONE\Dia1.JPG)
--
@@ -29,37 +29,8 @@
--
-- ===
--
-- # **API CHANGE HISTORY**
--
-- The underlying change log documents the API changes. Please read this carefully. The following notation is used:
--
-- * **Added** parts are expressed in bold type face.
-- * _Removed_ parts are expressed in italic type face.
--
-- Hereby the change log:
--
-- 2017-02-28: ZONE\_BASE:**IsVec2InZone()** replaces ZONE\_BASE:_IsPointVec2InZone()_.
-- 2017-02-28: ZONE\_BASE:**IsVec3InZone()** replaces ZONE\_BASE:_IsPointVec3InZone()_.
-- 2017-02-28: ZONE\_RADIUS:**IsVec2InZone()** replaces ZONE\_RADIUS:_IsPointVec2InZone()_.
-- 2017-02-28: ZONE\_RADIUS:**IsVec3InZone()** replaces ZONE\_RADIUS:_IsPointVec3InZone()_.
-- 2017-02-28: ZONE\_POLYGON:**IsVec2InZone()** replaces ZONE\_POLYGON:_IsPointVec2InZone()_.
-- 2017-02-28: ZONE\_POLYGON:**IsVec3InZone()** replaces ZONE\_POLYGON:_IsPointVec3InZone()_.
--
-- 2017-02-18: ZONE\_POLYGON_BASE:**GetRandomPointVec2()** added.
--
-- 2017-02-18: ZONE\_POLYGON_BASE:**GetRandomPointVec3()** added.
--
-- 2017-02-18: ZONE\_RADIUS:**GetRandomPointVec3( inner, outer )** added.
--
-- 2017-02-18: ZONE\_RADIUS:**GetRandomPointVec2( inner, outer )** added.
--
-- 2016-08-15: ZONE\_BASE:**GetName()** added.
--
-- 2016-08-15: ZONE\_BASE:**SetZoneProbability( ZoneProbability )** added.
--
-- 2016-08-15: ZONE\_BASE:**GetZoneProbability()** added.
--
-- 2016-08-15: ZONE\_BASE:**GetZoneMaybe()** added.
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
@@ -79,6 +50,8 @@
-- ## Each zone has a name:
--
-- * @{#ZONE_BASE.GetName}(): Returns the name of the zone.
-- * @{#ZONE_BASE.SetName}(): Sets the name of the zone.
--
--
-- ## Each zone implements two polymorphic functions defined in @{Zone#ZONE_BASE}:
--
@@ -141,6 +114,8 @@ function ZONE_BASE:New( ZoneName )
return self
end
--- Returns the name of the zone.
-- @param #ZONE_BASE self
-- @return #string The name of the zone.
@@ -150,6 +125,17 @@ function ZONE_BASE:GetName()
return self.ZoneName
end
--- Sets the name of the zone.
-- @param #ZONE_BASE self
-- @param #string ZoneName The name of the zone.
-- @return #ZONE_BASE
function ZONE_BASE:SetName( ZoneName )
self:F2()
self.ZoneName = ZoneName
end
--- Returns if a Vec2 is within the zone.
-- @param #ZONE_BASE self
-- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 to test.
@@ -165,10 +151,16 @@ end
-- @param Dcs.DCSTypes#Vec3 Vec3 The point to test.
-- @return #boolean true if the Vec3 is within the zone.
function ZONE_BASE:IsVec3InZone( Vec3 )
self:F2( Vec3 )
local InZone = self:IsVec2InZone( { x = Vec3.x, y = Vec3.z } )
return InZone
end
--- Returns if a Coordinate is within the zone.
-- @param #ZONE_BASE self
-- @param Core.Point#COORDINATE Coordinate The coordinate to test.
-- @return #boolean true if the coordinate is within the zone.
function ZONE_BASE:IsCoordinateInZone( Coordinate )
local InZone = self:IsVec2InZone( Coordinate:GetVec2() )
return InZone
end
@@ -177,10 +169,7 @@ end
-- @param Core.Point#POINT_VEC2 PointVec2 The PointVec2 to test.
-- @return #boolean true if the PointVec2 is within the zone.
function ZONE_BASE:IsPointVec2InZone( PointVec2 )
self:F2( PointVec2 )
local InZone = self:IsVec2InZone( PointVec2:GetVec2() )
return InZone
end
@@ -189,10 +178,7 @@ end
-- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 to test.
-- @return #boolean true if the PointVec3 is within the zone.
function ZONE_BASE:IsPointVec3InZone( PointVec3 )
self:F2( PointVec3 )
local InZone = self:IsPointVec2InZone( PointVec3 )
return InZone
end
@@ -201,8 +187,6 @@ end
-- @param #ZONE_BASE self
-- @return #nil.
function ZONE_BASE:GetVec2()
self:F2( self.ZoneName )
return nil
end
@@ -225,7 +209,6 @@ end
--- Returns a @{Point#COORDINATE} of the zone.
-- @param #ZONE_BASE self
-- @param Dcs.DCSTypes#Distance Height The height to add to the land height where the center of the zone is located.
-- @return Core.Point#COORDINATE The Coordinate of the zone.
function ZONE_BASE:GetCoordinate()
self:F2( self.ZoneName )
@@ -251,7 +234,7 @@ function ZONE_BASE:GetVec3( Height )
local Vec2 = self:GetVec2()
local Vec3 = { x = Vec2.x, y = land.getHeight( self:GetVec2() ) + Height, z = Vec2.y }
local Vec3 = { x = Vec2.x, y = Height and Height or land.getHeight( self:GetVec2() ), z = Vec2.y }
self:T2( { Vec3 } )
@@ -475,12 +458,17 @@ end
-- @param #ZONE_RADIUS self
-- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color.
-- @param #number Points (optional) The amount of points in the circle.
-- @param #number AddHeight (optional) The height to be added for the smoke.
-- @param #number AddOffSet (optional) The angle to be added for the smoking start position.
-- @return #ZONE_RADIUS self
function ZONE_RADIUS:SmokeZone( SmokeColor, Points )
function ZONE_RADIUS:SmokeZone( SmokeColor, Points, AddHeight, AngleOffset )
self:F2( SmokeColor )
local Point = {}
local Vec2 = self:GetVec2()
AddHeight = AddHeight or 0
AngleOffset = AngleOffset or 0
Points = Points and Points or 360
@@ -488,10 +476,10 @@ function ZONE_RADIUS:SmokeZone( SmokeColor, Points )
local RadialBase = math.pi*2
for Angle = 0, 360, 360 / Points do
local Radial = Angle * RadialBase / 360
local Radial = ( Angle + AngleOffset ) * RadialBase / 360
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
POINT_VEC2:New( Point.x, Point.y ):Smoke( SmokeColor )
POINT_VEC2:New( Point.x, Point.y, AddHeight ):Smoke( SmokeColor )
end
return self
@@ -503,13 +491,16 @@ end
-- @param Utilities.Utils#FLARECOLOR FlareColor The flare color.
-- @param #number Points (optional) The amount of points in the circle.
-- @param Dcs.DCSTypes#Azimuth Azimuth (optional) Azimuth The azimuth of the flare.
-- @param #number AddHeight (optional) The height to be added for the smoke.
-- @return #ZONE_RADIUS self
function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth )
function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth, AddHeight )
self:F2( { FlareColor, Azimuth } )
local Point = {}
local Vec2 = self:GetVec2()
AddHeight = AddHeight or 0
Points = Points and Points or 360
local Angle
@@ -519,7 +510,7 @@ function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth )
local Radial = Angle * RadialBase / 360
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
POINT_VEC2:New( Point.x, Point.y ):Flare( FlareColor, Azimuth )
POINT_VEC2:New( Point.x, Point.y, AddHeight ):Flare( FlareColor, Azimuth )
end
return self
@@ -592,6 +583,233 @@ function ZONE_RADIUS:GetVec3( Height )
end
--- Scan the zone for the presence of units of the given ObjectCategories.
-- Note that after a zone has been scanned, the zone can be evaluated by:
--
-- * @{ZONE_RADIUS.IsAllInZoneOfCoalition}(): Scan the presence of units in the zone of a coalition.
-- * @{ZONE_RADIUS.IsAllInZoneOfOtherCoalition}(): Scan the presence of units in the zone of an other coalition.
-- * @{ZONE_RADIUS.IsSomeInZoneOfCoalition}(): Scan if there is some presence of units in the zone of the given coalition.
-- * @{ZONE_RADIUS.IsNoneInZoneOfCoalition}(): Scan if there isn't any presence of units in the zone of an other coalition than the given one.
-- * @{ZONE_RADIUS.IsNoneInZone}(): Scan if the zone is empty.
-- @{#ZONE_RADIUS.
-- @param #ZONE_RADIUS self
-- @param ObjectCategories
-- @param Coalition
-- @usage
-- self.Zone:Scan()
-- local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
function ZONE_RADIUS:Scan( ObjectCategories )
self.ScanData = {}
self.ScanData.Coalitions = {}
self.ScanData.Scenery = {}
self.ScanData.Units = {}
local ZoneCoord = self:GetCoordinate()
local ZoneRadius = self:GetRadius()
self:F({ZoneCoord = ZoneCoord, ZoneRadius = ZoneRadius, ZoneCoordLL = ZoneCoord:ToStringLLDMS()})
local SphereSearch = {
id = world.VolumeType.SPHERE,
params = {
point = ZoneCoord:GetVec3(),
radius = ZoneRadius,
}
}
local function EvaluateZone( ZoneObject )
--if ZoneObject:isExist() then --FF: isExist always returns false for SCENERY objects since DCS 2.2 and still in DCS 2.5
if ZoneObject then
local ObjectCategory = ZoneObject:getCategory()
if ( ObjectCategory == Object.Category.UNIT and ZoneObject:isExist() and ZoneObject:isActive() ) or
(ObjectCategory == Object.Category.STATIC and ZoneObject:isExist()) then
local CoalitionDCSUnit = ZoneObject:getCoalition()
self.ScanData.Coalitions[CoalitionDCSUnit] = true
self.ScanData.Units[ZoneObject] = ZoneObject
self:F( { Name = ZoneObject:getName(), Coalition = CoalitionDCSUnit } )
end
if ObjectCategory == Object.Category.SCENERY then
local SceneryType = ZoneObject:getTypeName()
local SceneryName = ZoneObject:getName()
self.ScanData.Scenery[SceneryType] = self.ScanData.Scenery[SceneryType] or {}
self.ScanData.Scenery[SceneryType][SceneryName] = SCENERY:Register( SceneryName, ZoneObject )
self:F( { SCENERY = self.ScanData.Scenery[SceneryType][SceneryName] } )
end
end
return true
end
world.searchObjects( ObjectCategories, SphereSearch, EvaluateZone )
end
function ZONE_RADIUS:GetScannedUnits()
return self.ScanData.Units
end
function ZONE_RADIUS:CountScannedCoalitions()
local Count = 0
for CoalitionID, Coalition in pairs( self.ScanData.Coalitions ) do
Count = Count + 1
end
return Count
end
--- Get Coalitions of the units in the Zone, or Check if there are units of the given Coalition in the Zone.
-- Returns nil if there are none ot two Coalitions in the zone!
-- Returns one Coalition if there are only Units of one Coalition in the Zone.
-- Returns the Coalition for the given Coalition if there are units of the Coalition in the Zone
-- @param #ZONE_RADIUS self
-- @return #table
function ZONE_RADIUS:GetScannedCoalition( Coalition )
if Coalition then
return self.ScanData.Coalitions[Coalition]
else
local Count = 0
local ReturnCoalition = nil
for CoalitionID, Coalition in pairs( self.ScanData.Coalitions ) do
Count = Count + 1
ReturnCoalition = CoalitionID
end
if Count ~= 1 then
ReturnCoalition = nil
end
return ReturnCoalition
end
end
function ZONE_RADIUS:GetScannedSceneryType( SceneryType )
return self.ScanData.Scenery[SceneryType]
end
function ZONE_RADIUS:GetScannedScenery()
return self.ScanData.Scenery
end
--- Is All in Zone of Coalition?
-- @param #ZONE_RADIUS self
-- @param Coalition
-- @return #boolean
-- @usage
-- self.Zone:Scan()
-- local IsGuarded = self.Zone:IsAllInZoneOfCoalition( self.Coalition )
function ZONE_RADIUS:IsAllInZoneOfCoalition( Coalition )
--self:E( { Coalitions = self.Coalitions, Count = self:CountScannedCoalitions() } )
return self:CountScannedCoalitions() == 1 and self:GetScannedCoalition( Coalition ) == true
end
--- Is All in Zone of Other Coalition?
-- You first need to use the @{#ZONE_RADIUS.Scan} method to scan the zone before it can be evaluated!
-- Note that once a zone has been scanned, multiple evaluations can be done on the scan result set.
-- @param #ZONE_RADIUS self
-- @param Coalition
-- @return #boolean
-- @usage
-- self.Zone:Scan()
-- local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
function ZONE_RADIUS:IsAllInZoneOfOtherCoalition( Coalition )
--self:E( { Coalitions = self.Coalitions, Count = self:CountScannedCoalitions() } )
return self:CountScannedCoalitions() == 1 and self:GetScannedCoalition( Coalition ) == nil
end
--- Is Some in Zone of Coalition?
-- You first need to use the @{#ZONE_RADIUS.Scan} method to scan the zone before it can be evaluated!
-- Note that once a zone has been scanned, multiple evaluations can be done on the scan result set.
-- @param #ZONE_RADIUS self
-- @param Coalition
-- @return #boolean
-- @usage
-- self.Zone:Scan()
-- local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
function ZONE_RADIUS:IsSomeInZoneOfCoalition( Coalition )
return self:CountScannedCoalitions() > 1 and self:GetScannedCoalition( Coalition ) == true
end
--- Is None in Zone of Coalition?
-- You first need to use the @{#ZONE_RADIUS.Scan} method to scan the zone before it can be evaluated!
-- Note that once a zone has been scanned, multiple evaluations can be done on the scan result set.
-- @param #ZONE_RADIUS self
-- @param Coalition
-- @return #boolean
-- @usage
-- self.Zone:Scan()
-- local IsOccupied = self.Zone:IsNoneInZoneOfCoalition( self.Coalition )
function ZONE_RADIUS:IsNoneInZoneOfCoalition( Coalition )
return self:GetScannedCoalition( Coalition ) == nil
end
--- Is None in Zone?
-- You first need to use the @{#ZONE_RADIUS.Scan} method to scan the zone before it can be evaluated!
-- Note that once a zone has been scanned, multiple evaluations can be done on the scan result set.
-- @param #ZONE_RADIUS self
-- @return #boolean
-- @usage
-- self.Zone:Scan()
-- local IsEmpty = self.Zone:IsNoneInZone()
function ZONE_RADIUS:IsNoneInZone()
return self:CountScannedCoalitions() == 0
end
--- Searches the zone
-- @param #ZONE_RADIUS self
-- @param ObjectCategories A list of categories, which are members of Object.Category
-- @param EvaluateFunction
function ZONE_RADIUS:SearchZone( EvaluateFunction, ObjectCategories )
local SearchZoneResult = true
local ZoneCoord = self:GetCoordinate()
local ZoneRadius = self:GetRadius()
self:F({ZoneCoord = ZoneCoord, ZoneRadius = ZoneRadius, ZoneCoordLL = ZoneCoord:ToStringLLDMS()})
local SphereSearch = {
id = world.VolumeType.SPHERE,
params = {
point = ZoneCoord:GetVec3(),
radius = ZoneRadius / 2,
}
}
local function EvaluateZone( ZoneDCSUnit )
env.info( ZoneDCSUnit:getName() )
local ZoneUnit = UNIT:Find( ZoneDCSUnit )
return EvaluateFunction( ZoneUnit )
end
world.searchObjects( Object.Category.UNIT, SphereSearch, EvaluateZone )
end
--- Returns if a location is within the zone.
-- @param #ZONE_RADIUS self
-- @param Dcs.DCSTypes#Vec2 Vec2 The location to test.
@@ -652,13 +870,29 @@ end
function ZONE_RADIUS:GetRandomPointVec2( inner, outer )
self:F( self.ZoneName, inner, outer )
local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2() )
local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2( inner, outer ) )
self:T3( { PointVec2 } )
return PointVec2
end
--- Returns Returns a random Vec3 location within the zone.
-- @param #ZONE_RADIUS self
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
-- @return Dcs.DCSTypes#Vec3 The random location within the zone.
function ZONE_RADIUS:GetRandomVec3( inner, outer )
self:F( self.ZoneName, inner, outer )
local Vec2 = self:GetRandomVec2( inner, outer )
self:T3( { x = Vec2.x, y = self.y, z = Vec2.y } )
return { x = Vec2.x, y = self.y, z = Vec2.y }
end
--- Returns a @{Point#POINT_VEC3} object reflecting a random 3D location within the zone.
-- @param #ZONE_RADIUS self
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
@@ -667,7 +901,7 @@ end
function ZONE_RADIUS:GetRandomPointVec3( inner, outer )
self:F( self.ZoneName, inner, outer )
local PointVec3 = POINT_VEC3:NewFromVec2( self:GetRandomVec2() )
local PointVec3 = POINT_VEC3:NewFromVec2( self:GetRandomVec2( inner, outer ) )
self:T3( { PointVec3 } )
@@ -675,6 +909,22 @@ function ZONE_RADIUS:GetRandomPointVec3( inner, outer )
end
--- Returns a @{Point#COORDINATE} object reflecting a random 3D location within the zone.
-- @param #ZONE_RADIUS self
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
-- @return Core.Point#COORDINATE
function ZONE_RADIUS:GetRandomCoordinate( inner, outer )
self:F( self.ZoneName, inner, outer )
local Coordinate = COORDINATE:NewFromVec2( self:GetRandomVec2() )
self:T3( { Coordinate = Coordinate } )
return Coordinate
end
--- @type ZONE
-- @extends #ZONE_RADIUS
@@ -712,6 +962,17 @@ function ZONE:New( ZoneName )
return self
end
--- Find a zone in the _DATABASE using the name of the zone.
-- @param #ZONE_BASE self
-- @param #string ZoneName The name of the zone.
-- @return #ZONE_BASE self
function ZONE:FindByName( ZoneName )
local ZoneFound = _DATABASE:FindZone( ZoneName )
return ZoneFound
end
--- @type ZONE_UNIT
-- @field Wrapper.Unit#UNIT ZoneUNIT
@@ -864,6 +1125,20 @@ function ZONE_GROUP:GetRandomVec2()
return Point
end
--- Returns a @{Point#POINT_VEC2} object reflecting a random 2D location within the zone.
-- @param #ZONE_GROUP self
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
-- @return Core.Point#POINT_VEC2 The @{Point#POINT_VEC2} object reflecting the random 3D location within the zone.
function ZONE_GROUP:GetRandomPointVec2( inner, outer )
self:F( self.ZoneName, inner, outer )
local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2() )
self:T3( { PointVec2 } )
return PointVec2
end
--- @type ZONE_POLYGON_BASE
@@ -1107,6 +1382,20 @@ function ZONE_POLYGON_BASE:GetRandomPointVec3()
end
--- Return a @{Point#COORDINATE} object representing a random 3D point at landheight within the zone.
-- @param #ZONE_POLYGON_BASE self
-- @return Core.Point#COORDINATE
function ZONE_POLYGON_BASE:GetRandomCoordinate()
self:F2()
local Coordinate = COORDINATE:NewFromVec2( self:GetRandomVec2() )
self:T2( Coordinate )
return Coordinate
end
--- Get the bounding square the zone.
-- @param #ZONE_POLYGON_BASE self
-- @return #ZONE_POLYGON_BASE.BoundingSquare The bounding square.
@@ -1144,7 +1433,7 @@ ZONE_POLYGON = {
ClassName="ZONE_POLYGON",
}
--- Constructor to create a ZONE_POLYGON instance, taking the zone name and the name of the @{Group#GROUP} defined within the Mission Editor.
--- Constructor to create a ZONE_POLYGON instance, taking the zone name and the @{Group#GROUP} defined within the Mission Editor.
-- The @{Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected by ZONE_POLYGON.
-- @param #ZONE_POLYGON self
-- @param #string ZoneName Name of the zone.
@@ -1160,3 +1449,22 @@ function ZONE_POLYGON:New( ZoneName, ZoneGroup )
return self
end
--- Constructor to create a ZONE_POLYGON instance, taking the zone name and the **name** of the @{Group#GROUP} defined within the Mission Editor.
-- The @{Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected by ZONE_POLYGON.
-- @param #ZONE_POLYGON self
-- @param #string ZoneName Name of the zone.
-- @param #string GroupName The group name of the GROUP defining the waypoints within the Mission Editor to define the polygon shape.
-- @return #ZONE_POLYGON self
function ZONE_POLYGON:NewFromGroupName( GroupName )
local ZoneGroup = GROUP:FindByName( GroupName )
local GroupPoints = ZoneGroup:GetTaskRoute()
local self = BASE:Inherit( self, ZONE_POLYGON_BASE:New( GroupName, GroupPoints ) )
self:F( { GroupName, ZoneGroup, self._.Polygon } )
return self
end

View File

@@ -0,0 +1,54 @@
-------------------------------------------------------------------------------
-- @module DCSAirbase
--- Represents airbases: airdromes, helipads and ships with flying decks or landing pads.
-- @type Airbase
-- @extends Dcs.DCSCoalitionWrapper.Object#CoalitionObject
-- @field #Airbase.ID ID Identifier of an airbase. It assigned to an airbase by the Mission Editor automatically. This identifier is used in AI tasks to refer an airbase that exists (spawned and not dead) or not.
-- @field #Airbase.Category Category enum contains identifiers of airbase categories.
-- @field #Airbase.Desc Desc Airbase descriptor. Airdromes are unique and their types are unique, but helipads and ships are not always unique and may have the same type.
--- Enum contains identifiers of airbase categories.
-- @type Airbase.Category
-- @field AIRDROME
-- @field HELIPAD
-- @field SHIP
--- Airbase descriptor. Airdromes are unique and their types are unique, but helipads and ships are not always unique and may have the same type.
-- @type Airbase.Desc
-- @extends #Desc
-- @field #Airbase.Category category Category of the airbase type.
--- Returns airbase by its name. If no airbase found the function will return nil.
-- @function [parent=#Airbase] getByName
-- @param #string name
-- @return #Airbase
--- Returns airbase descriptor by type name. If no descriptor is found the function will return nil.
-- @function [parent=#Airbase] getDescByName
-- @param #TypeName typeName Airbase type name.
-- @return #Airbase.Desc
--- Returns Unit that is corresponded to the airbase. Works only for ships.
-- @function [parent=#Airbase] getUnit
-- @param self
-- @return Wrapper.Unit#Unit
--- Returns identifier of the airbase.
-- @function [parent=#Airbase] getID
-- @param self
-- @return #Airbase.ID
--- Returns the airbase's callsign - the localized string.
-- @function [parent=#Airbase] getCallsign
-- @param self
-- @return #string
--- Returns descriptor of the airbase.
-- @function [parent=#Airbase] getDesc
-- @param self
-- @return #Airbase.Desc
Airbase = {} --#Airbase

View File

@@ -0,0 +1,20 @@
-------------------------------------------------------------------------------
-- @module DCSCoalitionObject
--- @type CoalitionObject
-- @extends Dcs.DCSWrapper.Object#Object
--- Returns coalition of the object.
-- @function [parent=#CoalitionObject] getCoalition
-- @param #CoalitionObject self
-- @return Dcs.DCSTypes#coalition.side
--- Returns object country.
-- @function [parent=#CoalitionObject] getCountry
-- @param #CoalitionObject self
-- @return #country.id
CoalitionObject = {} --#CoalitionObject

View File

@@ -0,0 +1,10 @@
--- @module DCSCommand
--- @type Command
-- @field #string id
-- @field #Command.params params
--- @type Command.params
env.info( "Command defined" )

View File

@@ -0,0 +1,115 @@
-------------------------------------------------------------------------------
-- @module DCSController
--- Controller is an object that performs A.I.-routines. Other words controller is an instance of A.I.. Controller stores current main task, active enroute tasks and behavior options. Controller performs commands. Please, read DCS A-10C GUI Manual EN.pdf chapter "Task Planning for Unit Groups", page 91 to understand A.I. system of DCS:A-10C.
--
-- This class has 2 types of functions:
--
-- * Tasks
-- * Commands: Commands are instant actions those required zero time to perform. Commands may be used both for control unit/group behavior and control game mechanics.
-- @type Controller
-- @field #Controller.Detection Detection Enum contains identifiers of surface types.
--- Enables and disables the controller.
-- Note: Now it works only for ground / naval groups!
-- @function [parent=#Controller] setOnOff
-- @param self
-- @param #boolean value Enable / Disable.
-- Tasks
--- Resets current task and then sets the task to the controller. Task is a table that contains task identifier and task parameters.
-- @function [parent=#Controller] setTask
-- @param self
-- @param #Task task
--- Resets current task of the controller.
-- @function [parent=#Controller] resetTask
-- @param self
--- Pushes the task to the front of the queue and makes the task active. Further call of function Controller.setTask() function will stop current task, clear the queue and set the new task active. If the task queue is empty the function will work like function Controller.setTask() function.
-- @function [parent=#Controller] pushTask
-- @param self
-- @param #Task task
--- Pops current (front) task from the queue and makes active next task in the queue (if exists). If no more tasks in the queue the function works like function Controller.resetTask() function. Does nothing if the queue is empty.
-- @function [parent=#Controller] popTask
-- @param self
--- Returns true if the controller has a task.
-- @function [parent=#Controller] hasTask
-- @param self
-- @return #boolean
-- Commands
--TODO: describe #Command structure
--- Sets the command to perform by controller.
-- @function [parent=#Controller] setCommand
-- @param self
-- @param #Command command Table that contains command identifier and command parameters.
-- Behaviours
--- Sets the option to the controller.
-- Option is a pair of identifier and value. Behavior options are global parameters those affect controller behavior in all tasks it performs.
-- Option identifiers and values are stored in table AI.Option in subtables Air, Ground and Naval.
--
-- OptionId = @{#AI.Option.Air.id} or @{#AI.Option.Ground.id} or @{#AI.Option.Naval.id}
-- OptionValue = AI.Option.Air.val[optionName] or AI.Option.Ground.val[optionName] or AI.Option.Naval.val[optionName]
--
-- @function [parent=#Controller] setOption
-- @param self
-- @param #OptionId optionId Option identifier.
-- @param #OptionValue optionValue Value of the option.
-- Detection
--- Enum contains identifiers of surface types.
-- @type Controller.Detection
-- @field VISUAL
-- @field OPTIC
-- @field RADAR
-- @field IRST
-- @field RWR
-- @field DLINK
--- Detected target.
-- @type DetectedTarget
-- @field Wrapper.Object#Object object The target
-- @field #boolean visible The target is visible
-- @field #boolean type The target type is known
-- @field #boolean distance Distance to the target is known
--- Checks if the target is detected or not. If one or more detection method is specified the function will return true if the target is detected by at least one of these methods. If no detection methods are specified the function will return true if the target is detected by any method.
-- @function [parent=#Controller] isTargetDetected
-- @param self
-- @param Wrapper.Object#Object target Target to check
-- @param #Controller.Detection detection Controller.Detection detection1, Controller.Detection detection2, ... Controller.Detection detectionN
-- @return #boolean detected True if the target is detected.
-- @return #boolean visible Has effect only if detected is true. True if the target is visible now.
-- @return #ModelTime lastTime Has effect only if visible is false. Last time when target was seen.
-- @return #boolean type Has effect only if detected is true. True if the target type is known.
-- @return #boolean distance Has effect only if detected is true. True if the distance to the target is known.
-- @return #Vec3 lastPos Has effect only if visible is false. Last position of the target when it was seen.
-- @return #Vec3 lastVel Has effect only if visible is false. Last velocity of the target when it was seen.
--- Returns list of detected targets. If one or more detection method is specified the function will return targets which were detected by at least one of these methods. If no detection methods are specified the function will return targets which were detected by any method.
-- @function [parent=#Controller] getDetectedTargets
-- @param self
-- @param #Controller.Detection detection Controller.Detection detection1, Controller.Detection detection2, ... Controller.Detection detectionN
-- @return #list<#DetectedTarget> array of DetectedTarget
--- Know a target.
-- @function [parent=#Controller] knowTarget
-- @param self
-- @param Wrapper.Object#Object object The target.
-- @param #boolean type Target type is known.
-- @param #boolean distance Distance to target is known.
Controller = {} --#Controller

View File

@@ -0,0 +1,83 @@
-------------------------------------------------------------------------------
-- @module DCSGroup
--- Represents group of Units.
-- @type Group
-- @field #ID ID Identifier of a group. It is assigned to a group by Mission Editor automatically.
-- @field #Group.Category Category Enum contains identifiers of group types.
--- Enum contains identifiers of group types.
-- @type Group.Category
-- @field AIRPLANE
-- @field HELICOPTER
-- @field GROUND
-- @field SHIP
-- Static Functions
--- Returns group by the name assigned to the group in Mission Editor.
-- @function [parent=#Group] getByName
-- @param #string name
-- @return #Group
-- Member Functions
--- returns true if the group exist or false otherwise.
-- @function [parent=#Group] isExist
-- @param #Group self
-- @return #boolean
--- Destroys the group and all of its units.
-- @function [parent=#Group] destroy
-- @param #Group self
--- Returns category of the group.
-- @function [parent=#Group] getCategory
-- @param #Group self
-- @return #Group.Category
--TODO check coalition.side
--- Returns the coalition of the group.
-- @function [parent=#Group] getCoalition
-- @param #Group self
-- @return Dcs.DCSCoalitionWrapper.Object#coalition.side
--- Returns the group's name. This is the same name assigned to the group in Mission Editor.
-- @function [parent=#Group] getName
-- @param #Group self
-- @return #string
--- Returns the group identifier.
-- @function [parent=#Group] getID
-- @param #Group self
-- @return #ID
--- Returns the unit with number unitNumber. If the unit is not exists the function will return nil.
-- @function [parent=#Group] getUnit
-- @param #Group self
-- @param #number unitNumber
-- @return Dcs.DCSWrapper.Unit#Unit
--- Returns current size of the group. If some of the units will be destroyed, As units are destroyed the size of the group will be changed.
-- @function [parent=#Group] getSize
-- @param #Group self
-- @return #number
--- Returns initial size of the group. If some of the units will be destroyed, initial size of the group will not be changed. Initial size limits the unitNumber parameter for Group.getUnit() function.
-- @function [parent=#Group] getInitialSize
-- @param #Group self
-- @return #number
--- Returns array of the units present in the group now. Destroyed units will not be enlisted at all.
-- @function [parent=#Group] getUnits
-- @param #Group self
-- @return #list<Dcs.DCSWrapper.Unit#Unit> array of Units
--- Returns controller of the group.
-- @function [parent=#Group] getController
-- @param #Group self
-- @return Controller#Controller
Group = {} --#Group

View File

@@ -0,0 +1,73 @@
-------------------------------------------------------------------------------
-- @module DCSObject
--- @type Object
-- @field #Object.Category Category
-- @field #Object.Desc Desc
--- @type Object.Category
-- @field UNIT
-- @field WEAPON
-- @field STATIC
-- @field SCENERY
-- @field BASE
--- @type Object.Desc
-- @extends #Desc
-- @field #number life initial life level
-- @field #Box3 box bounding box of collision geometry
--- @function [parent=#Object] isExist
-- @param #Object self
-- @return #boolean
--- @function [parent=#Object] destroy
-- @param #Object self
--- @function [parent=#Object] getCategory
-- @param #Object self
-- @return #Object.Category
--- Returns type name of the Object.
-- @function [parent=#Object] getTypeName
-- @param #Object self
-- @return #string
--- Returns object descriptor.
-- @function [parent=#Object] getDesc
-- @param #Object self
-- @return #Object.Desc
--- Returns true if the object belongs to the category.
-- @function [parent=#Object] hasAttribute
-- @param #Object self
-- @param #AttributeName attributeName Attribute name to check.
-- @return #boolean
--- Returns name of the object. This is the name that is assigned to the object in the Mission Editor.
-- @function [parent=#Object] getName
-- @param #Object self
-- @return #string
--- Returns object coordinates for current time.
-- @function [parent=#Object] getPoint
-- @param #Object self
-- @return #Vec3
--- Returns object position for current time.
-- @function [parent=#Object] getPosition
-- @param #Object self
-- @return #Position3
--- Returns the unit's velocity vector.
-- @function [parent=#Object] getVelocity
-- @param #Object self
-- @return #Vec3
--- Returns true if the unit is in air.
-- @function [parent=#Object] inAir
-- @param #Object self
-- @return #boolean
Object = {} --#Object

View File

@@ -0,0 +1,34 @@
-------------------------------------------------------------------------------
-- @module DCSStaticObject
-------------------------------------------------------------------------------
-- @module StaticObject
-- @extends CoalitionWrapper.Object#CoalitionObject
--- Represents static object added in the Mission Editor.
-- @type StaticObject
-- @field #StaticObject.ID ID Identifier of a StaticObject. It assigned to an StaticObject by the Mission Editor automatically.
-- @field #StaticObject.Desc Desc Descriptor of StaticObject and Unit are equal. StaticObject is just a passive variant of Unit.
--- StaticObject descriptor. Airdromes are unique and their types are unique, but helipads and ships are not always unique and may have the same type.
-- @type StaticObject.Desc
-- @extends Wrapper.Unit#Unit.Desc
--- Returns static object by its name. If no static object found nil will be returned.
-- @function [parent=#StaticObject] getByName
-- @param #string name Name of static object to find.
-- @return #StaticObject
--- returns identifier of the static object.
-- @function [parent=#StaticObject] getID
-- @param #StaticObject self
-- @return #StaticObject.ID
--- Returns descriptor of the StaticObject.
-- @function [parent=#StaticObject] getDesc
-- @param #StaticObject self
-- @return #StaticObject.Desc
StaticObject = {} --#StaticObject

View File

@@ -0,0 +1,15 @@
--- @module DCSTask
--- A task descriptor (internal structure for DCS World)
-- @type Task
-- @field #string id
-- @field #Task.param param
--- @type Task.param
--- List of @{#Task}
-- @type TaskArray
-- @list <#Task>
env.info( "Task defined" )

View File

@@ -0,0 +1,8 @@
-------------------------------------------------------------------------------
-- @module DCSTime
--- @type ModelTime
-- @extends #number
--- @type Time
-- @extends #number

View File

@@ -0,0 +1,246 @@
-------------------------------------------------------------------------------
-- @module DCSTypes
--- Time is given in seconds.
-- @type Time
-- @extends #number
--- Model time is the time that drives the simulation. Model time may be stopped, accelerated and decelerated relative real time.
-- @type ModelTime
-- @extends #number
--- Mission time is a model time plus time of the mission start.
-- @type MissionTime
-- @extends #number
--- Distance is given in meters.
-- @type Distance
-- @extends #number
--- Angle is given in radians.
-- @type Angle
-- @extends #number
--- Azimuth is an angle of rotation around world axis y counter-clockwise.
-- @type Azimuth
-- @extends #number
--- Mass is given in kilograms.
-- @type Mass
-- @extends #number
--- Vec3 type is a 3D-vector.
-- DCS world has 3-dimensional coordinate system. DCS ground is an infinite plain.
-- @type Vec3
-- @field #Distance x is directed to the north
-- @field #Distance z is directed to the east
-- @field #Distance y is directed up
--- Vec2 is a 2D-vector for the ground plane as a reference plane.
-- @type Vec2
-- @field #Distance x Vec2.x = Vec3.x
-- @field #Distance y Vec2.y = Vec3.z
--- Position is a composite structure. It consists of both coordinate vector and orientation matrix. Position3 (also known as "Pos3" for short) is a table that has following format:
-- @type Position3
-- @field #Vec3 p
-- @field #Vec3 x
-- @field #Vec3 y
-- @field #Vec3 z
--- 3-dimensional box.
-- @type Box3
-- @field #Vec3 min
-- @field #Vec3 max
--- Each object belongs to a type. Object type is a named couple of properties those independent of mission and common for all units of the same type. Name of unit type is a string. Samples of unit type: "Su-27", "KAMAZ" and "M2 Bradley".
-- @type TypeName
-- @extends #string
--- AttributeName = string
-- Each object type may have attributes.
-- Attributes are enlisted in ./Scripts/Database/db_attributes.Lua.
-- To know what attributes the object type has, look for the unit type script in sub-directories planes/, helicopter/s, vehicles, navy/ of ./Scripts/Database/ directory.
-- @type AttributeName
-- @extends #string
--- List of @{#AttributeName}
-- @type AttributeNameArray
-- @list <#AttributeName>
--- @type AI
-- @field #AI.Skill Skill
-- @field #AI.Task Task
-- @field #AI.Option Option
--- @type AI.Skill
-- @field AVERAGE
-- @field GOOD
-- @field HIGH
-- @field EXCELLENT
-- @field PLAYER
-- @field CLIENT
--- @type AI.Task
-- @field #AI.Task.WeaponExpend WeaponExpend
-- @field #AI.Task.OrbitPattern OrbitPattern
-- @field #AI.Task.Designation Designation
-- @field #AI.Task.WaypointType WaypointType
-- @field #AI.Task.TurnMethod TurnMethod
-- @field #AI.Task.AltitudeType AltitudeType
-- @field #AI.Task.VehicleFormation VehicleFormation
--- @type AI.Task.WeaponExpend
-- @field ONE
-- @field TWO
-- @field FOUR
-- @field QUARTER
-- @field HALF
-- @field ALL
--- @type AI.Task.OrbitPattern
-- @field CIRCLE
-- @field RACE_TRACK
--- @type AI.Task.Designation
-- @field NO
-- @field AUTO
-- @field WP
-- @field IR_POINTER
-- @field LASER
--- @type AI.Task.WaypointType
-- @field TAKEOFF
-- @field TAKEOFF_PARKING
-- @field TURNING_POINT
-- @field LAND
--- @type AI.Task.TurnMethod
-- @field FLY_OVER_POINT
-- @field FIN_POINT
--- @type AI.Task.AltitudeType
-- @field BARO
-- @field RADIO
--- @type AI.Task.VehicleFormation
-- @field OFF_ROAD
-- @field ON_ROAD
-- @field RANK
-- @field CONE
-- @field DIAMOND
-- @field VEE
-- @field ECHELON_LEFT
-- @field ECHELON_RIGHT
--- @type AI.Option
-- @field #AI.Option.Air Air
-- @field #AI.Option.Ground Ground
-- @field #AI.Option.Naval Naval
--- @type AI.Option.Air
-- @field #AI.Option.Air.id id
-- @field #AI.Option.Air.val val
--- @type AI.Option.Ground
-- @field #AI.Option.Ground.id id
-- @field #AI.Option.Ground.val val
--- @type AI.Option.Naval
-- @field #AI.Option.Naval.id id
-- @field #AI.Option.Naval.val val
--TODO: work on formation
--- @type AI.Option.Air.id
-- @field NO_OPTION
-- @field ROE
-- @field REACTION_ON_THREAT
-- @field RADAR_USING
-- @field FLARE_USING
-- @field FORMATION
-- @field RTB_ON_BINGO
-- @field SILENCE
--- @type AI.Option.Air.val
-- @field #AI.Option.Air.val.ROE ROE
-- @field #AI.Option.Air.val.REACTION_ON_THREAT REACTION_ON_THREAT
-- @field #AI.Option.Air.val.RADAR_USING RADAR_USING
-- @field #AI.Option.Air.val.FLARE_USING FLARE_USING
--- @type AI.Option.Air.val.ROE
-- @field WEAPON_FREE
-- @field OPEN_FIRE_WEAPON_FREE
-- @field OPEN_FIRE
-- @field RETURN_FIRE
-- @field WEAPON_HOLD
--- @type AI.Option.Air.val.REACTION_ON_THREAT
-- @field NO_REACTION
-- @field PASSIVE_DEFENCE
-- @field EVADE_FIRE
-- @field BYPASS_AND_ESCAPE
-- @field ALLOW_ABORT_MISSION
--- @type AI.Option.Air.val.RADAR_USING
-- @field NEVER
-- @field FOR_ATTACK_ONLY
-- @field FOR_SEARCH_IF_REQUIRED
-- @field FOR_CONTINUOUS_SEARCH
--- @type AI.Option.Air.val.FLARE_USING
-- @field NEVER
-- @field AGAINST_FIRED_MISSILE
-- @field WHEN_FLYING_IN_SAM_WEZ
-- @field WHEN_FLYING_NEAR_ENEMIES
--- @type AI.Option.Ground.id
-- @field NO_OPTION
-- @field ROE @{#AI.Option.Ground.val.ROE}
-- @field DISPERSE_ON_ATTACK true or false
-- @field ALARM_STATE @{#AI.Option.Ground.val.ALARM_STATE}
--- @type AI.Option.Ground.val
-- @field #AI.Option.Ground.val.ROE ROE
-- @field #AI.Option.Ground.val.ALARM_STATE ALARM_STATE
--- @type AI.Option.Ground.val.ROE
-- @field OPEN_FIRE
-- @field RETURN_FIRE
-- @field WEAPON_HOLD
--- @type AI.Option.Ground.val.ALARM_STATE
-- @field AUTO
-- @field GREEN
-- @field RED
--- @type AI.Option.Naval.id
-- @field NO_OPTION
-- @field ROE
--- @type AI.Option.Naval.val
-- @field #AI.Option.Naval.val.ROE ROE
--- @type AI.Option.Naval.val.ROE
-- @field OPEN_FIRE
-- @field RETURN_FIRE
-- @field WEAPON_HOLD
AI = {} --#AI
--- @type Desc
-- @field #TypeName typeName type name
-- @field #string displayName localized display name
-- @field #table attributes object type attributes
--- A distance type
-- @type Distance
--- An angle type
-- @type Angle
env.info( 'AI types created' )

View File

@@ -0,0 +1,241 @@
-------------------------------------------------------------------------------
-- @module DCSUnit
--- @type Unit
-- @extends Dcs.DCSCoalitionWrapper.Object#CoalitionObject
-- @field ID Identifier of an unit. It assigned to an unit by the Mission Editor automatically.
-- @field #Unit.Category Category
-- @field #Unit.RefuelingSystem RefuelingSystem
-- @field #Unit.SensorType SensorType
-- @field #Unit.OpticType OpticType
-- @field #Unit.RadarType RadarType
-- @field #Unit.Desc Desc
-- @field #Unit.DescAircraft DescAircraft
-- @field #Unit.DescAirplane DescAirplane
-- @field #Unit.DescHelicopter DescHelicopter
-- @field #Unit.DescVehicle DescVehicle
-- @field #Unit.DescShip DescShip
-- @field #Unit.AmmoItem AmmoItem
-- @field #list<#Unit.AmmoItem> Ammo
-- @field #Unit.Sensor Sensor
-- @field #Unit.Optic Optic
-- @field #Unit.Radar Radar
-- @field #Unit.IRST IRST
--- Enum that stores unit categories.
-- @type Unit.Category
-- @field AIRPLANE
-- @field HELICOPTER
-- @field GROUND_UNIT
-- @field SHIP
-- @field STRUCTURE
--- Enum that stores aircraft refueling system types.
-- @type Unit.RefuelingSystem
-- @field BOOM_AND_RECEPTACLE
-- @field PROBE_AND_DROGUE
--- Enum that stores sensor types.
-- @type Unit.SensorType
-- @field OPTIC
-- @field RADAR
-- @field IRST
-- @field RWR
--- Enum that stores types of optic sensors.
-- @type Unit.OpticType
-- @field TV TV-sensor
-- @field LLTV Low-level TV-sensor
-- @field IR Infra-Red optic sensor
--- Enum that stores radar types.
-- @type Unit.RadarType
-- @field AS air search radar
-- @field SS surface/land search radar
--- A unit descriptor.
-- @type Unit.Desc
-- @extends Wrapper.Object#Object.Desc
-- @field #Unit.Category category Unit Category
-- @field #Mass massEmpty mass of empty unit
-- @field #number speedMax istance / Time, --maximal velocity
--- An aircraft descriptor.
-- @type Unit.DescAircraft
-- @extends Wrapper.Unit#Unit.Desc
-- @field #Mass fuelMassMax maximal inner fuel mass
-- @field #Distance range Operational range
-- @field #Distance Hmax Ceiling
-- @field #number VyMax #Distance / #Time, --maximal climb rate
-- @field #number NyMin minimal safe acceleration
-- @field #number NyMax maximal safe acceleration
-- @field #Unit.RefuelingSystem tankerType refueling system type
--- An airplane descriptor.
-- @type Unit.DescAirplane
-- @extends Wrapper.Unit#Unit.DescAircraft
-- @field #number speedMax0 Distance / Time maximal TAS at ground level
-- @field #number speedMax10K Distance / Time maximal TAS at altitude of 10 km
--- A helicopter descriptor.
-- @type Unit.DescHelicopter
-- @extends Wrapper.Unit#Unit.DescAircraft
-- @field #Distance HmaxStat static ceiling
--- A vehicle descriptor.
-- @type Unit.DescVehicle
-- @extends Wrapper.Unit#Unit.Desc
-- @field #Angle maxSlopeAngle maximal slope angle
-- @field #boolean riverCrossing can the vehicle cross a rivers
--- A ship descriptor.
-- @type Unit.DescShip
-- @extends #Unit.Desc
--- ammunition item: "type-count" pair.
-- @type Unit.AmmoItem
-- @field #Weapon.Desc desc ammunition descriptor
-- @field #number count ammunition count
--- A unit sensor.
-- @type Unit.Sensor
-- @field #TypeName typeName
-- @field #Unit.SensorType type
--- An optic sensor.
-- @type Unit.Optic
-- @extends Wrapper.Unit#Unit.Sensor
-- @field #Unit.OpticType opticType
--- A radar.
-- @type Unit.Radar
-- @extends Wrapper.Unit#Unit.Sensor
-- @field #Distance detectionDistanceRBM detection distance for RCS=1m^2 in real-beam mapping mode, nil if radar doesn't support surface/land search
-- @field #Distance detectionDistanceHRM detection distance for RCS=1m^2 in high-resolution mapping mode, nil if radar has no HRM
-- @field #Unit.Radar.detectionDistanceAir detectionDistanceAir detection distance for RCS=1m^2 airborne target, nil if radar doesn't support air search
--- @type Unit.Radar.detectionDistanceAir
-- @field #Unit.Radar.detectionDistanceAir.upperHemisphere upperHemisphere
-- @field #Unit.Radar.detectionDistanceAir.lowerHemisphere lowerHemisphere
--- @type Unit.Radar.detectionDistanceAir.upperHemisphere
-- @field #Distance headOn
-- @field #Distance tailOn
--- @type Unit.Radar.detectionDistanceAir.lowerHemisphere
-- @field #Distance headOn
-- @field #Distance tailOn
--- An IRST.
-- @type Wrapper.Unit#Unit.IRST
-- @extends Unit.Sensor
-- @field #Distance detectionDistanceIdle detection of tail-on target with heat signature = 1 in upper hemisphere, engines are in idle
-- @field #Distance detectionDistanceMaximal ..., engines are in maximal mode
-- @field #Distance detectionDistanceAfterburner ..., engines are in afterburner mode
--- An RWR.
-- @type Unit.RWR
-- @extends Wrapper.Unit#Unit.Sensor
--- table that stores all unit sensors.
-- TODO @type Sensors
--
--- Returns unit object by the name assigned to the unit in Mission Editor. If there is unit with such name or the unit is destroyed the function will return nil. The function provides access to non-activated units too.
-- @function [parent=#Unit] getByName
-- @param #string name
-- @return #Unit
--- Returns if the unit is activated.
-- @function [parent=#Unit] isActive
-- @param #Unit self
-- @return #boolean
--- Returns name of the player that control the unit or nil if the unit is controlled by A.I.
-- @function [parent=#Unit] getPlayerName
-- @param #Unit self
-- @return #string
--- returns the unit's unique identifier.
-- @function [parent=#Unit] getID
-- @param #Unit self
-- @return #Unit.ID
--- Returns the unit's number in the group. The number is the same number the unit has in ME. It may not be changed during the mission. If any unit in the group is destroyed, the numbers of another units will not be changed.
-- @function [parent=#Unit] getNumber
-- @param #Unit self
-- @return #number
--- Returns controller of the unit if it exist and nil otherwise
-- @function [parent=#Unit] getController
-- @param #Unit self
-- @return #Controller
--- Returns the unit's group if it exist and nil otherwise
-- @function [parent=#Unit] getGroup
-- @param #Unit self
-- @return Dcs.DCSWrapper.Group#Group
--- Returns the unit's callsign - the localized string.
-- @function [parent=#Unit] getCallsign
-- @param #Unit self
-- @return #string
--- Returns the unit's health. Dead units has health <= 1.0
-- @function [parent=#Unit] getLife
-- @param #Unit self
-- @return #number
--- returns the unit's initial health.
-- @function [parent=#Unit] getLife0
-- @param #Unit self
-- @return #number
--- Returns relative amount of fuel (from 0.0 to 1.0) the unit has in its internal tanks. If there are additional fuel tanks the value may be greater than 1.0.
-- @function [parent=#Unit] getFuel
-- @param #Unit self
-- @return #number
--- Returns the unit ammunition.
-- @function [parent=#Unit] getAmmo
-- @param #Unit self
-- @return #Unit.Ammo
--- Returns the unit sensors.
-- @function [parent=#Unit] getSensors
-- @param #Unit self
-- @return #Unit.Sensors
--- Returns true if the unit has specified types of sensors. This function is more preferable than Unit.getSensors() if you don't want to get information about all the unit's sensors, and just want to check if the unit has specified types of sensors.
-- @function [parent=#Unit] hasSensors
-- @param #Unit self
-- @param #Unit.SensorType sensorType (= nil) Sensor type.
-- @param ... Additional parameters.
-- @return #boolean
-- @usage
-- If sensorType is Unit.SensorType.OPTIC, additional parameters are optic sensor types. Following example checks if the unit has LLTV or IR optics:
-- unit:hasSensors(Unit.SensorType.OPTIC, Unit.OpticType.LLTV, Unit.OpticType.IR)
-- If sensorType is Unit.SensorType.RADAR, additional parameters are radar types. Following example checks if the unit has air search radars:
-- unit:hasSensors(Unit.SensorType.RADAR, Unit.RadarType.AS)
-- If no additional parameters are specified the function returns true if the unit has at least one sensor of specified type.
-- If sensor type is not specified the function returns true if the unit has at least one sensor of any type.
--
--- returns two values:
-- First value indicates if at least one of the unit's radar(s) is on.
-- Second value is the object of the radar's interest. Not nil only if at least one radar of the unit is tracking a target.
-- @function [parent=#Unit] getRadar
-- @param #Unit self
-- @return #boolean, Wrapper.Object#Object
--- Returns unit descriptor. Descriptor type depends on unit category.
-- @function [parent=#Unit] getDesc
-- @param #Unit self
-- @return #Unit.Desc
Unit = {} --#Unit

View File

@@ -0,0 +1,11 @@
-------------------------------------------------------------------------------
-- @module DCSVec3
---
-- @type Vec3
-- @field #number x
-- @field #number y
-- @field #number z
Vec3 = {}

View File

@@ -0,0 +1,10 @@
-------------------------------------------------------------------------------
-- @module DCSZone
---
-- @type Zone
-- @field DCSVec3#Vec3 point
-- @field #number radius
Zone = {}

View File

@@ -0,0 +1,16 @@
-------------------------------------------------------------------------------
-- @module DCScoalition
--- @type coalition
-- @field #coalition.side side
--- @type coalition.side
-- @field NEUTRAL
-- @field RED
-- @field BLUE
--- @function [parent=#coalition] getCountryCoalition
-- @param #number countryId
-- @return #number coalitionId
coalition = coalition -- #coalition

View File

@@ -0,0 +1,27 @@
-------------------------------------------------------------------------------
-- @module DCScountry
--- @type country
-- @field #country.id id
country = country -- #country
--- @type country.id
-- @field RUSSIA
-- @field UKRAINE
-- @field USA
-- @field TURKEY
-- @field UK
-- @field FRANCE
-- @field GERMANY
-- @field CANADA
-- @field SPAIN
-- @field THE_NETHERLANDS
-- @field BELGIUM
-- @field NORWAY
-- @field DENMARK
-- @field ISRAEL
-- @field GEORGIA
-- @field INSURGENTS
-- @field ABKHAZIA
-- @field SOUTH_OSETIA
-- @field ITALY

View File

@@ -0,0 +1,27 @@
-------------------------------------------------------------------------------
-- @module env
--- @type env
--- Add message to simulator log with caption "INFO". Message box is optional.
-- @function [parent=#env] info
-- @field #string message message string to add to log.
-- @field #boolean showMessageBox If the parameter is true Message Box will appear. Optional.
--- Add message to simulator log with caption "WARNING". Message box is optional.
-- @function [parent=#env] warning
-- @field #string message message string to add to log.
-- @field #boolean showMessageBox If the parameter is true Message Box will appear. Optional.
--- Add message to simulator log with caption "ERROR". Message box is optional.
-- @function [parent=#env] error
-- @field #string message message string to add to log.
-- @field #boolean showMessageBox If the parameter is true Message Box will appear. Optional.
--- Enables/disables appearance of message box each time lua error occurs.
-- @function [parent=#env] setErrorMessageBoxEnabled
-- @field #boolean on if true message box appearance is enabled.
env = {} --#env

View File

@@ -0,0 +1,26 @@
-------------------------------------------------------------------------------
-- @module land
--- @type land
-- @field #land.SurfaceType SurfaceType
--- @type land.SurfaceType
-- @field LAND
-- @field SHALLOW_WATER
-- @field WATER
-- @field ROAD
-- @field RUNWAY
--- Returns altitude MSL of the point.
-- @function [parent=#land] getHeight
-- @param #Vec2 point point on the ground.
-- @return Dcs.DCSTypes#Distance
--- returns surface type at the given point.
-- @function [parent=#land] getSurfaceType
-- @param #Vec2 point Point on the land.
-- @return #land.SurfaceType
land = {} --#land

View File

@@ -0,0 +1,45 @@
-------------------------------------------------------------------------------
-- @module DCStimer
--- @type timer
--- Returns model time in seconds.
-- @function [parent=#timer] getTime
-- @return #Time
--- Returns mission time in seconds.
-- @function [parent=#timer] getAbsTime
-- @return #Time
--- Returns mission start time in seconds.
-- @function [parent=#timer] getTime0
-- @return #Time
--- Schedules function to call at desired model time.
-- Time function FunctionToCall(any argument, Time time)
--
-- ...
--
-- return ...
--
-- end
--
-- Must return model time of next call or nil. Note that the DCS scheduler calls the function in protected mode and any Lua errors in the called function will be trapped and not reported. If the function triggers a Lua error then it will be terminated and not scheduled to run again.
-- @function [parent=#timer] scheduleFunction
-- @param #FunctionToCall functionToCall Lua-function to call. Must have prototype of FunctionToCall.
-- @param functionArgument Function argument of any type to pass to functionToCall.
-- @param #Time time Model time of the function call.
-- @return functionId
--- Re-schedules function to call at another model time.
-- @function [parent=#timer] setFunctionTime
-- @param functionId Lua-function to call. Must have prototype of FunctionToCall.
-- @param #Time time Model time of the function call.
--- Removes the function from schedule.
-- @function [parent=#timer] removeFunction
-- @param functionId Function identifier to remove from schedule
timer = {} --#timer

View File

@@ -0,0 +1,8 @@
-------------------------------------------------------------------------------
-- @module DCStrigger
trigger = {} --#timer

View File

@@ -0,0 +1,35 @@
-------------------------------------------------------------------------------
-- @module DCSWorld
--- @type world
-- @field #world.event event
--- @type world.event
-- @field S_EVENT_INVALID
-- @field S_EVENT_SHOT
-- @field S_EVENT_HIT
-- @field S_EVENT_TAKEOFF
-- @field S_EVENT_LAND
-- @field S_EVENT_CRASH
-- @field S_EVENT_EJECTION
-- @field S_EVENT_REFUELING
-- @field S_EVENT_DEAD
-- @field S_EVENT_PILOT_DEAD
-- @field S_EVENT_BASE_CAPTURED
-- @field S_EVENT_MISSION_START
-- @field S_EVENT_MISSION_END
-- @field S_EVENT_TOOK_CONTROL
-- @field S_EVENT_REFUELING_STOP
-- @field S_EVENT_BIRTH
-- @field S_EVENT_HUMAN_FAILURE
-- @field S_EVENT_ENGINE_STARTUP
-- @field S_EVENT_ENGINE_SHUTDOWN
-- @field S_EVENT_PLAYER_ENTER_UNIT
-- @field S_EVENT_PLAYER_LEAVE_UNIT
-- @field S_EVENT_PLAYER_COMMENT
-- @field S_EVENT_SHOOTING_START
-- @field S_EVENT_SHOOTING_END
-- @field S_EVENT_MAX
world = {} --#world

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,135 +1,234 @@
--- The CLEANUP class keeps an area clean of crashing or colliding airplanes. It also prevents airplanes from firing within this area.
--- **Functional** -- The CLEANUP_AIRBASE class keeps an area clean of crashing or colliding airplanes. It also prevents airplanes from firing within this area.
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @module CleanUp
-- @author Flightcontrol
--- The CLEANUP class.
-- @type CLEANUP
--- @type CLEANUP_AIRBASE.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-)
-- @field #map<#string,Wrapper.Airbase#AIRBASE> Airbases Map of Airbases.
-- @extends Core.Base#BASE
CLEANUP = {
ClassName = "CLEANUP",
ZoneNames = {},
TimeInterval = 300,
--- @type CLEANUP_AIRBASE
-- @extends #CLEANUP_AIRBASE.__
--- # CLEANUP_AIRBASE, extends @{Base#BASE}
--
-- ![Banner Image](..\Presentations\CLEANUP_AIRBASE\Dia1.JPG)
--
-- The CLEANUP_AIRBASE class keeps airbases clean, and tries to guarantee continuous airbase operations, even under combat.
-- Specific airbases need to be provided that need to be guarded. Each airbase registered, will be guarded within a zone of 8 km around the airbase.
-- Any unit that fires a missile, or shoots within the zone of an airbase, will be monitored by CLEANUP_AIRBASE.
-- Within the 8km zone, units cannot fire any missile, which prevents the airbase runway to receive missile or bomb hits.
-- Any airborne or ground unit that is on the runway below 30 meters (default value) will be automatically removed if it is damaged.
--
-- This is not a full 100% secure implementation. It is still possible that CLEANUP_AIRBASE cannot prevent (in-time) to keep the airbase clean.
-- The following situations may happen that will still stop the runway of an airbase:
--
-- * A damaged unit is not removed on time when above the runway, and crashes on the runway.
-- * A bomb or missile is still able to dropped on the runway.
-- * Units collide on the airbase, and could not be removed on time.
--
-- When a unit is within the airbase zone and needs to be monitored,
-- its status will be checked every 0.25 seconds! This is required to ensure that the airbase is kept clean.
-- But as a result, there is more CPU overload.
--
-- So as an advise, I suggest you use the CLEANUP_AIRBASE class with care:
--
-- * Only monitor airbases that really need to be monitored!
-- * Try not to monitor airbases that are likely to be invaded by enemy troops.
-- For these airbases, there is little use to keep them clean, as they will be invaded anyway...
--
-- By following the above guidelines, you can add airbase cleanup with acceptable CPU overhead.
--
-- ## 1. CLEANUP_AIRBASE Constructor
--
-- Creates the main object which is preventing the airbase to get polluted with debris on the runway, which halts the airbase.
--
-- -- Clean these Zones.
-- CleanUpAirports = CLEANUP_AIRBASE:New( { AIRBASE.Caucasus.Tbilisi, AIRBASE.Caucasus.Kutaisi )
--
-- -- or
-- CleanUpTbilisi = CLEANUP_AIRBASE:New( AIRBASE.Caucasus.Tbilisi )
-- CleanUpKutaisi = CLEANUP_AIRBASE:New( AIRBASE.Caucasus.Kutaisi )
--
-- ## 2. Add or Remove airbases
--
-- The method @{#CLEANUP_AIRBASE.AddAirbase}() to add an airbase to the cleanup validation process.
-- The method @{#CLEANUP_AIRBASE.RemoveAirbase}() removes an airbase from the cleanup validation process.
--
-- ## 3. Clean missiles and bombs within the airbase zone.
--
-- When missiles or bombs hit the runway, the airbase operations stop.
-- Use the method @{#CLEANUP_AIRBASE.SetCleanMissiles}() to control the cleaning of missiles, which will prevent airbases to stop.
-- Note that this method will not allow anymore airbases to be attacked, so there is a trade-off here to do.
--
-- @field #CLEANUP_AIRBASE
CLEANUP_AIRBASE = {
ClassName = "CLEANUP_AIRBASE",
TimeInterval = 0.2,
CleanUpList = {},
}
-- @field #CLEANUP_AIRBASE.__
CLEANUP_AIRBASE.__ = {}
--- @field #CLEANUP_AIRBASE.__.Airbases
CLEANUP_AIRBASE.__.Airbases = {}
--- Creates the main object which is handling the cleaning of the debris within the given Zone Names.
-- @param #CLEANUP self
-- @param #table ZoneNames Is a table of zone names where the debris should be cleaned. Also a single string can be passed with one zone name.
-- @param #number TimeInterval The interval in seconds when the clean activity takes place. The default is 300 seconds, thus every 5 minutes.
-- @return #CLEANUP
-- @param #CLEANUP_AIRBASE self
-- @param #list<#string> AirbaseNames Is a table of airbase names where the debris should be cleaned. Also a single string can be passed with one airbase name.
-- @return #CLEANUP_AIRBASE
-- @usage
-- -- Clean these Zones.
-- CleanUpAirports = CLEANUP:New( { 'CLEAN Tbilisi', 'CLEAN Kutaisi' }, 150 )
-- CleanUpAirports = CLEANUP_AIRBASE:New( { AIRBASE.Caucasus.Tbilisi, AIRBASE.Caucasus.Kutaisi )
-- or
-- CleanUpTbilisi = CLEANUP:New( 'CLEAN Tbilisi', 150 )
-- CleanUpKutaisi = CLEANUP:New( 'CLEAN Kutaisi', 600 )
function CLEANUP:New( ZoneNames, TimeInterval )
-- CleanUpTbilisi = CLEANUP_AIRBASE:New( AIRBASE.Caucasus.Tbilisi )
-- CleanUpKutaisi = CLEANUP_AIRBASE:New( AIRBASE.Caucasus.Kutaisi )
function CLEANUP_AIRBASE:New( AirbaseNames )
local self = BASE:Inherit( self, BASE:New() ) -- #CLEANUP
self:F( { ZoneNames, TimeInterval } )
local self = BASE:Inherit( self, BASE:New() ) -- #CLEANUP_AIRBASE
self:F( { AirbaseNames } )
if type( ZoneNames ) == 'table' then
self.ZoneNames = ZoneNames
if type( AirbaseNames ) == 'table' then
for AirbaseID, AirbaseName in pairs( AirbaseNames ) do
self:AddAirbase( AirbaseName )
end
else
self.ZoneNames = { ZoneNames }
end
if TimeInterval then
self.TimeInterval = TimeInterval
local AirbaseName = AirbaseNames
self:AddAirbase( AirbaseName )
end
self:HandleEvent( EVENTS.Birth )
self:HandleEvent( EVENTS.Birth, self.__.OnEventBirth )
self.CleanUpScheduler = SCHEDULER:New( self, self._CleanUpScheduler, {}, 1, TimeInterval )
self.__.CleanUpScheduler = SCHEDULER:New( self, self.__.CleanUpSchedule, {}, 1, self.TimeInterval )
self:HandleEvent( EVENTS.EngineShutdown , self.__.EventAddForCleanUp )
self:HandleEvent( EVENTS.EngineStartup, self.__.EventAddForCleanUp )
self:HandleEvent( EVENTS.Hit, self.__.EventAddForCleanUp )
self:HandleEvent( EVENTS.PilotDead, self.__.OnEventCrash )
self:HandleEvent( EVENTS.Dead, self.__.OnEventCrash )
self:HandleEvent( EVENTS.Crash, self.__.OnEventCrash )
return self
end
--- Destroys a group from the simulator, but checks first if it is still existing!
-- @param #CLEANUP self
-- @param Dcs.DCSWrapper.Group#Group GroupObject The object to be destroyed.
-- @param #string CleanUpGroupName The groupname...
function CLEANUP:_DestroyGroup( GroupObject, CleanUpGroupName )
self:F( { GroupObject, CleanUpGroupName } )
if GroupObject then -- and GroupObject:isExist() then
trigger.action.deactivateGroup(GroupObject)
self:T( { "GroupObject Destroyed", GroupObject } )
end
--- Adds an airbase to the airbase validation list.
-- @param #CLEANUP_AIRBASE self
-- @param #string AirbaseName
-- @return #CLEANUP_AIRBASE
function CLEANUP_AIRBASE:AddAirbase( AirbaseName )
self.__.Airbases[AirbaseName] = AIRBASE:FindByName( AirbaseName )
self:F({"Airbase:", AirbaseName, self.__.Airbases[AirbaseName]:GetDesc()})
return self
end
--- Destroys a @{DCSWrapper.Unit#Unit} from the simulator, but checks first if it is still existing!
-- @param #CLEANUP self
-- @param Dcs.DCSWrapper.Unit#Unit CleanUpUnit The object to be destroyed.
-- @param #string CleanUpUnitName The Unit name ...
function CLEANUP:_DestroyUnit( CleanUpUnit, CleanUpUnitName )
self:F( { CleanUpUnit, CleanUpUnitName } )
--- Removes an airbase from the airbase validation list.
-- @param #CLEANUP_AIRBASE self
-- @param #string AirbaseName
-- @return #CLEANUP_AIRBASE
function CLEANUP_AIRBASE:RemoveAirbase( AirbaseName )
self.__.Airbases[AirbaseName] = nil
return self
end
--- Enables or disables the cleaning of missiles within the airbase zones.
-- Airbase operations stop when a missile or bomb is dropped at a runway.
-- Note that when this method is used, the airbase operations won't stop if
-- the missile or bomb was cleaned within the airbase zone, which is 8km from the center of the airbase.
-- However, there is a trade-off to make. Attacks on airbases won't be possible anymore if this method is used.
-- Note, one can also use the method @{#CLEANUP_AIRBASE.RemoveAirbase}() to remove the airbase from the control process as a whole,
-- when an enemy unit is near. That is also an option...
-- @param #CLEANUP_AIRBASE self
-- @param #string CleanMissiles (Default=true) If true, missiles fired are immediately destroyed. If false missiles are not controlled.
-- @return #CLEANUP_AIRBASE
function CLEANUP_AIRBASE:SetCleanMissiles( CleanMissiles )
if CleanMissiles then
self:HandleEvent( EVENTS.Shot, self.__.OnEventShot )
else
self:UnHandleEvent( EVENTS.Shot )
end
end
function CLEANUP_AIRBASE.__:IsInAirbase( Vec2 )
local InAirbase = false
for AirbaseName, Airbase in pairs( self.__.Airbases ) do
local Airbase = Airbase -- Wrapper.Airbase#AIRBASE
if Airbase:GetZone():IsVec2InZone( Vec2 ) then
InAirbase = true
break;
end
end
return InAirbase
end
--- Destroys a @{Unit} from the simulator, but checks first if it is still existing!
-- @param #CLEANUP_AIRBASE self
-- @param Wrapper.Unit#UNIT CleanUpUnit The object to be destroyed.
function CLEANUP_AIRBASE.__:DestroyUnit( CleanUpUnit )
self:F( { CleanUpUnit } )
if CleanUpUnit then
local CleanUpGroup = Unit.getGroup(CleanUpUnit)
local CleanUpUnitName = CleanUpUnit:GetName()
local CleanUpGroup = CleanUpUnit:GetGroup()
-- TODO Client bug in 1.5.3
if CleanUpGroup and CleanUpGroup:isExist() then
local CleanUpGroupUnits = CleanUpGroup:getUnits()
if CleanUpGroup:IsAlive() then
local CleanUpGroupUnits = CleanUpGroup:GetUnits()
if #CleanUpGroupUnits == 1 then
local CleanUpGroupName = CleanUpGroup:getName()
--self:CreateEventCrash( timer.getTime(), CleanUpUnit )
CleanUpGroup:destroy()
self:T( { "Destroyed Group:", CleanUpGroupName } )
local CleanUpGroupName = CleanUpGroup:GetName()
CleanUpGroup:Destroy()
else
CleanUpUnit:destroy()
self:T( { "Destroyed Unit:", CleanUpUnitName } )
CleanUpUnit:Destroy()
end
self.CleanUpList[CleanUpUnitName] = nil -- Cleaning from the list
CleanUpUnit = nil
self.CleanUpList[CleanUpUnitName] = nil
end
end
end
-- TODO check Dcs.DCSTypes#Weapon
--- Destroys a missile from the simulator, but checks first if it is still existing!
-- @param #CLEANUP self
-- @param Dcs.DCSTypes#Weapon MissileObject
function CLEANUP:_DestroyMissile( MissileObject )
self:F( { MissileObject } )
--- Destroys a missile from the simulator, but checks first if it is still existing!
-- @param #CLEANUP_AIRBASE self
-- @param Dcs.DCSTypes#Weapon MissileObject
function CLEANUP_AIRBASE.__:DestroyMissile( MissileObject )
self:F( { MissileObject } )
if MissileObject and MissileObject:isExist() then
MissileObject:destroy()
self:T( "MissileObject Destroyed")
end
end
--- @param #CLEANUP self
--- @param #CLEANUP_AIRBASE self
-- @param Core.Event#EVENTDATA EventData
function CLEANUP:_OnEventBirth( EventData )
function CLEANUP_AIRBASE.__:OnEventBirth( EventData )
self:F( { EventData } )
self.CleanUpList[EventData.IniDCSUnitName] = {}
self.CleanUpList[EventData.IniDCSUnitName].CleanUpUnit = EventData.IniDCSUnit
self.CleanUpList[EventData.IniDCSUnitName].CleanUpGroup = EventData.IniDCSGroup
self.CleanUpList[EventData.IniDCSUnitName].CleanUpUnit = EventData.IniUnit
self.CleanUpList[EventData.IniDCSUnitName].CleanUpGroup = EventData.IniGroup
self.CleanUpList[EventData.IniDCSUnitName].CleanUpGroupName = EventData.IniDCSGroupName
self.CleanUpList[EventData.IniDCSUnitName].CleanUpUnitName = EventData.IniDCSUnitName
EventData.IniUnit:HandleEvent( EVENTS.EngineShutdown , self._EventAddForCleanUp )
EventData.IniUnit:HandleEvent( EVENTS.EngineStartup, self._EventAddForCleanUp )
EventData.IniUnit:HandleEvent( EVENTS.Hit, self._EventAddForCleanUp )
EventData.IniUnit:HandleEvent( EVENTS.PilotDead, self._EventCrash )
EventData.IniUnit:HandleEvent( EVENTS.Dead, self._EventCrash )
EventData.IniUnit:HandleEvent( EVENTS.Crash, self._EventCrash )
EventData.IniUnit:HandleEvent( EVENTS.Shot, self._EventShot )
end
--- Detects if a crash event occurs.
-- Crashed units go into a CleanUpList for removal.
-- @param #CLEANUP self
-- @param Dcs.DCSTypes#Event event
function CLEANUP:_EventCrash( Event )
-- @param #CLEANUP_AIRBASE self
-- @param Core.Event#EVENTDATA Event
function CLEANUP_AIRBASE.__:OnEventCrash( Event )
self:F( { Event } )
--TODO: This stuff is not working due to a DCS bug. Burning units cannot be destroyed.
@@ -140,171 +239,164 @@ function CLEANUP:_EventCrash( Event )
-- self:T("after deactivateGroup")
-- event.initiator:destroy()
self.CleanUpList[Event.IniDCSUnitName] = {}
self.CleanUpList[Event.IniDCSUnitName].CleanUpUnit = Event.IniDCSUnit
self.CleanUpList[Event.IniDCSUnitName].CleanUpGroup = Event.IniDCSGroup
self.CleanUpList[Event.IniDCSUnitName].CleanUpGroupName = Event.IniDCSGroupName
self.CleanUpList[Event.IniDCSUnitName].CleanUpUnitName = Event.IniDCSUnitName
if Event.IniDCSUnitName and Event.IniCategory == Object.Category.UNIT then
self.CleanUpList[Event.IniDCSUnitName] = {}
self.CleanUpList[Event.IniDCSUnitName].CleanUpUnit = Event.IniUnit
self.CleanUpList[Event.IniDCSUnitName].CleanUpGroup = Event.IniGroup
self.CleanUpList[Event.IniDCSUnitName].CleanUpGroupName = Event.IniDCSGroupName
self.CleanUpList[Event.IniDCSUnitName].CleanUpUnitName = Event.IniDCSUnitName
end
end
--- Detects if a unit shoots a missile.
-- If this occurs within one of the zones, then the weapon used must be destroyed.
-- @param #CLEANUP self
-- @param Dcs.DCSTypes#Event event
function CLEANUP:_EventShot( Event )
-- If this occurs within one of the airbases, then the weapon used must be destroyed.
-- @param #CLEANUP_AIRBASE self
-- @param Core.Event#EVENTDATA Event
function CLEANUP_AIRBASE.__:OnEventShot( Event )
self:F( { Event } )
-- Test if the missile was fired within one of the CLEANUP.ZoneNames.
local CurrentLandingZoneID = 0
CurrentLandingZoneID = routines.IsUnitInZones( Event.IniDCSUnit, self.ZoneNames )
if ( CurrentLandingZoneID ) then
-- Okay, the missile was fired within the CLEANUP.ZoneNames, destroy the fired weapon.
--_SEADmissile:destroy()
SCHEDULER:New( self, CLEANUP._DestroyMissile, { Event.Weapon }, 0.1 )
-- Test if the missile was fired within one of the CLEANUP_AIRBASE.AirbaseNames.
if self:IsInAirbase( Event.IniUnit:GetVec2() ) then
-- Okay, the missile was fired within the CLEANUP_AIRBASE.AirbaseNames, destroy the fired weapon.
self:DestroyMissile( Event.Weapon )
end
end
--- Detects if the Unit has an S_EVENT_HIT within the given ZoneNames. If this is the case, destroy the unit.
-- @param #CLEANUP self
-- @param Dcs.DCSTypes#Event event
function CLEANUP:_EventHitCleanUp( Event )
--- Detects if the Unit has an S_EVENT_HIT within the given AirbaseNames. If this is the case, destroy the unit.
-- @param #CLEANUP_AIRBASE self
-- @param Core.Event#EVENTDATA Event
function CLEANUP_AIRBASE.__:OnEventHit( Event )
self:F( { Event } )
if Event.IniDCSUnit then
if routines.IsUnitInZones( Event.IniDCSUnit, self.ZoneNames ) ~= nil then
self:T( { "Life: ", Event.IniDCSUnitName, ' = ', Event.IniDCSUnit:getLife(), "/", Event.IniDCSUnit:getLife0() } )
if Event.IniDCSUnit:getLife() < Event.IniDCSUnit:getLife0() then
if Event.IniUnit then
if self:IsInAirbase( Event.IniUnit:GetVec2() ) then
self:T( { "Life: ", Event.IniDCSUnitName, ' = ', Event.IniUnit:GetLife(), "/", Event.IniUnit:GetLife0() } )
if Event.IniUnit:GetLife() < Event.IniUnit:GetLife0() then
self:T( "CleanUp: Destroy: " .. Event.IniDCSUnitName )
SCHEDULER:New( self, CLEANUP._DestroyUnit, { Event.IniDCSUnit }, 0.1 )
CLEANUP_AIRBASE.__:DestroyUnit( Event.IniUnit )
end
end
end
if Event.TgtDCSUnit then
if routines.IsUnitInZones( Event.TgtDCSUnit, self.ZoneNames ) ~= nil then
self:T( { "Life: ", Event.TgtDCSUnitName, ' = ', Event.TgtDCSUnit:getLife(), "/", Event.TgtDCSUnit:getLife0() } )
if Event.TgtDCSUnit:getLife() < Event.TgtDCSUnit:getLife0() then
if Event.TgtUnit then
if self:IsInAirbase( Event.TgtUnit:GetVec2() ) then
self:T( { "Life: ", Event.TgtDCSUnitName, ' = ', Event.TgtUnit:GetLife(), "/", Event.TgtUnit:GetLife0() } )
if Event.TgtUnit:GetLife() < Event.TgtUnit:GetLife0() then
self:T( "CleanUp: Destroy: " .. Event.TgtDCSUnitName )
SCHEDULER:New( self, CLEANUP._DestroyUnit, { Event.TgtDCSUnit }, 0.1 )
CLEANUP_AIRBASE.__:DestroyUnit( Event.TgtUnit )
end
end
end
end
--- Add the @{DCSWrapper.Unit#Unit} to the CleanUpList for CleanUp.
function CLEANUP:_AddForCleanUp( CleanUpUnit, CleanUpUnitName )
-- @param #CLEANUP_AIRBASE self
-- @param Wrapper.Unit#UNIT CleanUpUnit
-- @oaram #string CleanUpUnitName
function CLEANUP_AIRBASE.__:AddForCleanUp( CleanUpUnit, CleanUpUnitName )
self:F( { CleanUpUnit, CleanUpUnitName } )
self.CleanUpList[CleanUpUnitName] = {}
self.CleanUpList[CleanUpUnitName].CleanUpUnit = CleanUpUnit
self.CleanUpList[CleanUpUnitName].CleanUpUnitName = CleanUpUnitName
self.CleanUpList[CleanUpUnitName].CleanUpGroup = Unit.getGroup(CleanUpUnit)
self.CleanUpList[CleanUpUnitName].CleanUpGroupName = Unit.getGroup(CleanUpUnit):getName()
local CleanUpGroup = CleanUpUnit:GetGroup()
self.CleanUpList[CleanUpUnitName].CleanUpGroup = CleanUpGroup
self.CleanUpList[CleanUpUnitName].CleanUpGroupName = CleanUpGroup:GetName()
self.CleanUpList[CleanUpUnitName].CleanUpTime = timer.getTime()
self.CleanUpList[CleanUpUnitName].CleanUpMoved = false
self:T( { "CleanUp: Add to CleanUpList: ", Unit.getGroup(CleanUpUnit):getName(), CleanUpUnitName } )
self:T( { "CleanUp: Add to CleanUpList: ", CleanUpGroup:GetName(), CleanUpUnitName } )
end
--- Detects if the Unit has an S_EVENT_ENGINE_SHUTDOWN or an S_EVENT_HIT within the given ZoneNames. If this is the case, add the Group to the CLEANUP List.
-- @param #CLEANUP self
-- @param Dcs.DCSTypes#Event event
function CLEANUP:_EventAddForCleanUp( Event )
--- Detects if the Unit has an S_EVENT_ENGINE_SHUTDOWN or an S_EVENT_HIT within the given AirbaseNames. If this is the case, add the Group to the CLEANUP_AIRBASE List.
-- @param #CLEANUP_AIRBASE.__ self
-- @param Core.Event#EVENTDATA Event
function CLEANUP_AIRBASE.__:EventAddForCleanUp( Event )
if Event.IniDCSUnit then
self:F({Event})
if Event.IniDCSUnit and Event.IniCategory == Object.Category.UNIT then
if self.CleanUpList[Event.IniDCSUnitName] == nil then
if routines.IsUnitInZones( Event.IniDCSUnit, self.ZoneNames ) ~= nil then
self:_AddForCleanUp( Event.IniDCSUnit, Event.IniDCSUnitName )
if self:IsInAirbase( Event.IniUnit:GetVec2() ) then
self:AddForCleanUp( Event.IniUnit, Event.IniDCSUnitName )
end
end
end
if Event.TgtDCSUnit then
if Event.TgtDCSUnit and Event.TgtCategory == Object.Category.UNIT then
if self.CleanUpList[Event.TgtDCSUnitName] == nil then
if routines.IsUnitInZones( Event.TgtDCSUnit, self.ZoneNames ) ~= nil then
self:_AddForCleanUp( Event.TgtDCSUnit, Event.TgtDCSUnitName )
if self:IsInAirbase( Event.TgtUnit:GetVec2() ) then
self:AddForCleanUp( Event.TgtUnit, Event.TgtDCSUnitName )
end
end
end
end
local CleanUpSurfaceTypeText = {
"LAND",
"SHALLOW_WATER",
"WATER",
"ROAD",
"RUNWAY"
}
--- At the defined time interval, CleanUp the Groups within the CleanUpList.
-- @param #CLEANUP self
function CLEANUP:_CleanUpScheduler()
self:F( { "CleanUp Scheduler" } )
-- @param #CLEANUP_AIRBASE self
function CLEANUP_AIRBASE.__:CleanUpSchedule()
local CleanUpCount = 0
for CleanUpUnitName, UnitData in pairs( self.CleanUpList ) do
for CleanUpUnitName, CleanUpListData in pairs( self.CleanUpList ) do
CleanUpCount = CleanUpCount + 1
self:T( { CleanUpUnitName, UnitData } )
local CleanUpUnit = Unit.getByName(UnitData.CleanUpUnitName)
local CleanUpGroupName = UnitData.CleanUpGroupName
local CleanUpUnitName = UnitData.CleanUpUnitName
if CleanUpUnit then
self:T( { "CleanUp Scheduler", "Checking:", CleanUpUnitName } )
local CleanUpUnit = CleanUpListData.CleanUpUnit -- Wrapper.Unit#UNIT
local CleanUpGroupName = CleanUpListData.CleanUpGroupName
if CleanUpUnit:IsAlive() ~= nil then
if _DATABASE:GetStatusGroup( CleanUpGroupName ) ~= "ReSpawn" then
local CleanUpUnitVec3 = CleanUpUnit:getPoint()
--self:T( CleanUpUnitVec3 )
local CleanUpUnitVec2 = {}
CleanUpUnitVec2.x = CleanUpUnitVec3.x
CleanUpUnitVec2.y = CleanUpUnitVec3.z
--self:T( CleanUpUnitVec2 )
local CleanUpSurfaceType = land.getSurfaceType(CleanUpUnitVec2)
--self:T( CleanUpSurfaceType )
if CleanUpUnit and CleanUpUnit:getLife() <= CleanUpUnit:getLife0() * 0.95 then
if CleanUpSurfaceType == land.SurfaceType.RUNWAY then
if CleanUpUnit:inAir() then
local CleanUpLandHeight = land.getHeight(CleanUpUnitVec2)
local CleanUpUnitHeight = CleanUpUnitVec3.y - CleanUpLandHeight
self:T( { "CleanUp Scheduler", "Height = " .. CleanUpUnitHeight } )
if CleanUpUnitHeight < 30 then
local CleanUpCoordinate = CleanUpUnit:GetCoordinate()
self:T( { "CleanUp Scheduler", CleanUpUnitName } )
if CleanUpUnit:GetLife() <= CleanUpUnit:GetLife0() * 0.95 then
if CleanUpUnit:IsAboveRunway() then
if CleanUpUnit:InAir() then
local CleanUpLandHeight = CleanUpCoordinate:GetLandHeight()
local CleanUpUnitHeight = CleanUpCoordinate.y - CleanUpLandHeight
if CleanUpUnitHeight < 100 then
self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because below safe height and damaged." } )
self:_DestroyUnit(CleanUpUnit, CleanUpUnitName)
self:DestroyUnit( CleanUpUnit )
end
else
self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because on runway and damaged." } )
self:_DestroyUnit(CleanUpUnit, CleanUpUnitName)
self:DestroyUnit( CleanUpUnit )
end
end
end
-- Clean Units which are waiting for a very long time in the CleanUpZone.
if CleanUpUnit then
local CleanUpUnitVelocity = CleanUpUnit:getVelocity()
local CleanUpUnitVelocityTotal = math.abs(CleanUpUnitVelocity.x) + math.abs(CleanUpUnitVelocity.y) + math.abs(CleanUpUnitVelocity.z)
if CleanUpUnitVelocityTotal < 1 then
if UnitData.CleanUpMoved then
if UnitData.CleanUpTime + 180 <= timer.getTime() then
local CleanUpUnitVelocity = CleanUpUnit:GetVelocityKMH()
if CleanUpUnitVelocity < 1 then
if CleanUpListData.CleanUpMoved then
if CleanUpListData.CleanUpTime + 180 <= timer.getTime() then
self:T( { "CleanUp Scheduler", "Destroy due to not moving anymore " .. CleanUpUnitName } )
self:_DestroyUnit(CleanUpUnit, CleanUpUnitName)
self:DestroyUnit( CleanUpUnit )
end
end
else
UnitData.CleanUpTime = timer.getTime()
UnitData.CleanUpMoved = true
CleanUpListData.CleanUpTime = timer.getTime()
CleanUpListData.CleanUpMoved = true
end
end
else
-- Do nothing ...
self.CleanUpList[CleanUpUnitName] = nil -- Not anymore in the DCSRTE
self.CleanUpList[CleanUpUnitName] = nil
end
else
self:T( "CleanUp: Group " .. CleanUpUnitName .. " cannot be found in DCS RTE, removing ..." )
self.CleanUpList[CleanUpUnitName] = nil -- Not anymore in the DCSRTE
self.CleanUpList[CleanUpUnitName] = nil
end
end
self:T(CleanUpCount)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,9 @@
--- Taking the lead of AI escorting your flight.
--- **Functional** -- Taking the lead of AI escorting your flight.
--
-- ===
--
-- @{#ESCORT} class
-- ================
-- ===
-- The @{#ESCORT} class allows you to interact with escorting AI on your flight and take the lead.
-- Each escorting group can be commanded with a whole set of radio commands (radio menu in your flight, and then F10).
--
@@ -9,7 +11,7 @@
-- Ships and Ground troops will have a more limited set, but they can provide support through the bombing of targets designated by the other escorts.
--
-- RADIO MENUs that can be created:
-- ================================
-- ===
-- Find a summary below of the current available commands:
--
-- Navigation ...:
@@ -77,13 +79,13 @@
-- Note that this is really fantastic, as you now have the dynamic of taking control of the escort groups, and allowing them to resume their path or mission.
--
-- ESCORT construction methods.
-- ============================
-- ===
-- Create a new SPAWN object with the @{#ESCORT.New} method:
--
-- * @{#ESCORT.New}: Creates a new ESCORT object from a @{Group#GROUP} for a @{Client#CLIENT}, with an optional briefing text.
--
-- ESCORT initialization methods.
-- ==============================
-- ===
-- The following menus are created within the RADIO MENU (F10) of an active unit hosted by a player:
--
-- * @{#ESCORT.MenuFollowAt}: Creates a menu to make the escort follow the client.
@@ -127,8 +129,7 @@
-- @field #boolean ReportTargets If true, nearby targets are reported.
-- @Field Dcs.DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the EscortGroup.
-- @field Dcs.DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the EscortGroup.
-- @field Core.Menu#MENU_CLIENT EscortMenuResumeMission
-- @field Functional.Detection#DETECTION_BASE Detection
-- @field FunctionalMENU_GROUPDETECTION_BASE Detection
ESCORT = {
ClassName = "ESCORT",
EscortName = nil, -- The Escort Name
@@ -205,7 +206,7 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
self.EscortClient._EscortGroups[EscortGroup:GetName()].Detection = self.EscortGroup.Detection
end
self.EscortMenu = MENU_CLIENT:New( self.EscortClient, self.EscortName )
self.EscortMenu = MENU_GROUP:New( self.EscortClient:GetGroup(), self.EscortName )
self.EscortGroup:WayPointInitialize(1)
@@ -301,14 +302,14 @@ function ESCORT:MenuFollowAt( Distance )
if self.EscortGroup:IsAir() then
if not self.EscortMenuReportNavigation then
self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu )
self.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortClient:GetGroup(), "Navigation", self.EscortMenu )
end
if not self.EscortMenuJoinUpAndFollow then
self.EscortMenuJoinUpAndFollow = {}
end
self.EscortMenuJoinUpAndFollow[#self.EscortMenuJoinUpAndFollow+1] = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow at " .. Distance, self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, self, Distance )
self.EscortMenuJoinUpAndFollow[#self.EscortMenuJoinUpAndFollow+1] = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Join-Up and Follow at " .. Distance, self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, self, Distance )
self.EscortMode = ESCORT.MODE.FOLLOW
end
@@ -330,7 +331,7 @@ function ESCORT:MenuHoldAtEscortPosition( Height, Seconds, MenuTextFormat )
if self.EscortGroup:IsAir() then
if not self.EscortMenuHold then
self.EscortMenuHold = MENU_CLIENT:New( self.EscortClient, "Hold position", self.EscortMenu )
self.EscortMenuHold = MENU_GROUP:New( self.EscortClient:GetGroup(), "Hold position", self.EscortMenu )
end
if not Height then
@@ -360,9 +361,9 @@ function ESCORT:MenuHoldAtEscortPosition( Height, Seconds, MenuTextFormat )
self.EscortMenuHoldPosition = {}
end
self.EscortMenuHoldPosition[#self.EscortMenuHoldPosition+1] = MENU_CLIENT_COMMAND
self.EscortMenuHoldPosition[#self.EscortMenuHoldPosition+1] = MENU_GROUP_COMMAND
:New(
self.EscortClient,
self.EscortClient:GetGroup(),
MenuText,
self.EscortMenuHold,
ESCORT._HoldPosition,
@@ -391,7 +392,7 @@ function ESCORT:MenuHoldAtLeaderPosition( Height, Seconds, MenuTextFormat )
if self.EscortGroup:IsAir() then
if not self.EscortMenuHold then
self.EscortMenuHold = MENU_CLIENT:New( self.EscortClient, "Hold position", self.EscortMenu )
self.EscortMenuHold = MENU_GROUP:New( self.EscortClient:GetGroup(), "Hold position", self.EscortMenu )
end
if not Height then
@@ -421,9 +422,9 @@ function ESCORT:MenuHoldAtLeaderPosition( Height, Seconds, MenuTextFormat )
self.EscortMenuHoldAtLeaderPosition = {}
end
self.EscortMenuHoldAtLeaderPosition[#self.EscortMenuHoldAtLeaderPosition+1] = MENU_CLIENT_COMMAND
self.EscortMenuHoldAtLeaderPosition[#self.EscortMenuHoldAtLeaderPosition+1] = MENU_GROUP_COMMAND
:New(
self.EscortClient,
self.EscortClient:GetGroup(),
MenuText,
self.EscortMenuHold,
ESCORT._HoldPosition,
@@ -450,7 +451,7 @@ function ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat )
if self.EscortGroup:IsAir() then
if not self.EscortMenuScan then
self.EscortMenuScan = MENU_CLIENT:New( self.EscortClient, "Scan for targets", self.EscortMenu )
self.EscortMenuScan = MENU_GROUP:New( self.EscortClient:GetGroup(), "Scan for targets", self.EscortMenu )
end
if not Height then
@@ -480,9 +481,9 @@ function ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat )
self.EscortMenuScanForTargets = {}
end
self.EscortMenuScanForTargets[#self.EscortMenuScanForTargets+1] = MENU_CLIENT_COMMAND
self.EscortMenuScanForTargets[#self.EscortMenuScanForTargets+1] = MENU_GROUP_COMMAND
:New(
self.EscortClient,
self.EscortClient:GetGroup(),
MenuText,
self.EscortMenuScan,
ESCORT._ScanTargets,
@@ -506,7 +507,7 @@ function ESCORT:MenuFlare( MenuTextFormat )
self:F()
if not self.EscortMenuReportNavigation then
self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu )
self.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortClient:GetGroup(), "Navigation", self.EscortMenu )
end
local MenuText = ""
@@ -517,11 +518,11 @@ function ESCORT:MenuFlare( MenuTextFormat )
end
if not self.EscortMenuFlare then
self.EscortMenuFlare = MENU_CLIENT:New( self.EscortClient, MenuText, self.EscortMenuReportNavigation, ESCORT._Flare, self )
self.EscortMenuFlareGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Green, "Released a green flare!" )
self.EscortMenuFlareRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Red, "Released a red flare!" )
self.EscortMenuFlareWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.White, "Released a white flare!" )
self.EscortMenuFlareYellow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release yellow flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Yellow, "Released a yellow flare!" )
self.EscortMenuFlare = MENU_GROUP:New( self.EscortClient:GetGroup(), MenuText, self.EscortMenuReportNavigation, ESCORT._Flare, self )
self.EscortMenuFlareGreen = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release green flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Green, "Released a green flare!" )
self.EscortMenuFlareRed = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release red flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Red, "Released a red flare!" )
self.EscortMenuFlareWhite = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release white flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.White, "Released a white flare!" )
self.EscortMenuFlareYellow = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release yellow flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Yellow, "Released a yellow flare!" )
end
return self
@@ -539,7 +540,7 @@ function ESCORT:MenuSmoke( MenuTextFormat )
if not self.EscortGroup:IsAir() then
if not self.EscortMenuReportNavigation then
self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu )
self.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortClient:GetGroup(), "Navigation", self.EscortMenu )
end
local MenuText = ""
@@ -550,12 +551,12 @@ function ESCORT:MenuSmoke( MenuTextFormat )
end
if not self.EscortMenuSmoke then
self.EscortMenuSmoke = MENU_CLIENT:New( self.EscortClient, "Smoke", self.EscortMenuReportNavigation, ESCORT._Smoke, self )
self.EscortMenuSmokeGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Green, "Releasing green smoke!" )
self.EscortMenuSmokeRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Red, "Releasing red smoke!" )
self.EscortMenuSmokeWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.White, "Releasing white smoke!" )
self.EscortMenuSmokeOrange = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release orange smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Orange, "Releasing orange smoke!" )
self.EscortMenuSmokeBlue = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release blue smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Blue, "Releasing blue smoke!" )
self.EscortMenuSmoke = MENU_GROUP:New( self.EscortClient:GetGroup(), "Smoke", self.EscortMenuReportNavigation, ESCORT._Smoke, self )
self.EscortMenuSmokeGreen = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release green smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Green, "Releasing green smoke!" )
self.EscortMenuSmokeRed = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release red smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Red, "Releasing red smoke!" )
self.EscortMenuSmokeWhite = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release white smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.White, "Releasing white smoke!" )
self.EscortMenuSmokeOrange = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release orange smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Orange, "Releasing orange smoke!" )
self.EscortMenuSmokeBlue = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release blue smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Blue, "Releasing blue smoke!" )
end
end
@@ -572,7 +573,7 @@ function ESCORT:MenuReportTargets( Seconds )
self:F( { Seconds } )
if not self.EscortMenuReportNearbyTargets then
self.EscortMenuReportNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Report targets", self.EscortMenu )
self.EscortMenuReportNearbyTargets = MENU_GROUP:New( self.EscortClient:GetGroup(), "Report targets", self.EscortMenu )
end
if not Seconds then
@@ -580,12 +581,12 @@ function ESCORT:MenuReportTargets( Seconds )
end
-- Report Targets
self.EscortMenuReportNearbyTargetsNow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets now!", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargetsNow, self )
self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets on", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, self, true )
self.EscortMenuReportNearbyTargetsOff = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets off", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, self, false )
self.EscortMenuReportNearbyTargetsNow = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Report targets now!", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargetsNow, self )
self.EscortMenuReportNearbyTargetsOn = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Report targets on", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, self, true )
self.EscortMenuReportNearbyTargetsOff = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Report targets off", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, self, false )
-- Attack Targets
self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack targets", self.EscortMenu )
self.EscortMenuAttackNearbyTargets = MENU_GROUP:New( self.EscortClient:GetGroup(), "Attack targets", self.EscortMenu )
self.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, Seconds )
@@ -603,7 +604,7 @@ function ESCORT:MenuAssistedAttack()
-- Request assistance from other escorts.
-- This is very useful to let f.e. an escorting ship attack a target detected by an escorting plane...
self.EscortMenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, "Request assistance from", self.EscortMenu )
self.EscortMenuTargetAssistance = MENU_GROUP:New( self.EscortClient:GetGroup(), "Request assistance from", self.EscortMenu )
return self
end
@@ -617,18 +618,18 @@ function ESCORT:MenuROE( MenuTextFormat )
if not self.EscortMenuROE then
-- Rules of Engagement
self.EscortMenuROE = MENU_CLIENT:New( self.EscortClient, "ROE", self.EscortMenu )
self.EscortMenuROE = MENU_GROUP:New( self.EscortClient:GetGroup(), "ROE", self.EscortMenu )
if self.EscortGroup:OptionROEHoldFirePossible() then
self.EscortMenuROEHoldFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEHoldFire(), "Holding weapons!" )
self.EscortMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Hold Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEHoldFire(), "Holding weapons!" )
end
if self.EscortGroup:OptionROEReturnFirePossible() then
self.EscortMenuROEReturnFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Return Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEReturnFire(), "Returning fire!" )
self.EscortMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Return Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEReturnFire(), "Returning fire!" )
end
if self.EscortGroup:OptionROEOpenFirePossible() then
self.EscortMenuROEOpenFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Open Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEOpenFire(), "Opening fire on designated targets!!" )
self.EscortMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Open Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEOpenFire(), "Opening fire on designated targets!!" )
end
if self.EscortGroup:OptionROEWeaponFreePossible() then
self.EscortMenuROEWeaponFree = MENU_CLIENT_COMMAND:New( self.EscortClient, "Weapon Free", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEWeaponFree(), "Opening fire on targets of opportunity!" )
self.EscortMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Weapon Free", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEWeaponFree(), "Opening fire on targets of opportunity!" )
end
end
@@ -646,18 +647,18 @@ function ESCORT:MenuEvasion( MenuTextFormat )
if self.EscortGroup:IsAir() then
if not self.EscortMenuEvasion then
-- Reaction to Threats
self.EscortMenuEvasion = MENU_CLIENT:New( self.EscortClient, "Evasion", self.EscortMenu )
self.EscortMenuEvasion = MENU_GROUP:New( self.EscortClient:GetGroup(), "Evasion", self.EscortMenu )
if self.EscortGroup:OptionROTNoReactionPossible() then
self.EscortMenuEvasionNoReaction = MENU_CLIENT_COMMAND:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTNoReaction(), "Fighting until death!" )
self.EscortMenuEvasionNoReaction = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Fight until death", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTNoReaction(), "Fighting until death!" )
end
if self.EscortGroup:OptionROTPassiveDefensePossible() then
self.EscortMenuEvasionPassiveDefense = MENU_CLIENT_COMMAND:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTPassiveDefense(), "Defending using jammers, chaff and flares!" )
self.EscortMenuEvasionPassiveDefense = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTPassiveDefense(), "Defending using jammers, chaff and flares!" )
end
if self.EscortGroup:OptionROTEvadeFirePossible() then
self.EscortMenuEvasionEvadeFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTEvadeFire(), "Evading on enemy fire!" )
self.EscortMenuEvasionEvadeFire = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Evade enemy fire", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTEvadeFire(), "Evading on enemy fire!" )
end
if self.EscortGroup:OptionROTVerticalPossible() then
self.EscortMenuOptionEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTVertical(), "Evading on enemy fire with vertical manoeuvres!" )
self.EscortMenuOptionEvasionVertical = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTVertical(), "Evading on enemy fire with vertical manoeuvres!" )
end
end
end
@@ -674,7 +675,7 @@ function ESCORT:MenuResumeMission()
if not self.EscortMenuResumeMission then
-- Mission Resume Menu Root
self.EscortMenuResumeMission = MENU_CLIENT:New( self.EscortClient, "Resume mission from", self.EscortMenu )
self.EscortMenuResumeMission = MENU_GROUP:New( self.EscortClient:GetGroup(), "Resume mission from", self.EscortMenu )
end
return self
@@ -845,11 +846,11 @@ function _Resume( EscortGroup )
end
--- @param #ESCORT self
-- @param #number DetectedItemID
function ESCORT:_AttackTarget( DetectedItemID )
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
function ESCORT:_AttackTarget( DetectedItem )
local EscortGroup = self.EscortGroup -- Wrapper.Group#GROUP
self:E( EscortGroup )
self:F( EscortGroup )
local EscortClient = self.EscortClient
@@ -860,7 +861,7 @@ function ESCORT:_AttackTarget( DetectedItemID )
EscortGroup:OptionROTPassiveDefense()
EscortGroup:SetState( EscortGroup, "Escort", self )
local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID )
local DetectedSet = self.Detection:GetDetectedSet( DetectedItem )
local Tasks = {}
@@ -873,7 +874,7 @@ function ESCORT:_AttackTarget( DetectedItemID )
end, Tasks
)
Tasks[#Tasks+1] = EscortGroup:TaskFunction( 1, 2, "_Resume", { "''" } )
Tasks[#Tasks+1] = EscortGroup:TaskFunction( "_Resume", { "''" } )
EscortGroup:SetTask(
EscortGroup:TaskCombo(
@@ -883,7 +884,7 @@ function ESCORT:_AttackTarget( DetectedItemID )
else
local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID )
local DetectedSet = self.Detection:GetDetectedSet( DetectedItem )
local Tasks = {}
@@ -909,8 +910,9 @@ function ESCORT:_AttackTarget( DetectedItemID )
end
---
-- @param #number DetectedItemID
function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItemID )
--- @param #ESCORT self
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItem )
local EscortGroup = self.EscortGroup
local EscortClient = self.EscortClient
@@ -921,7 +923,7 @@ function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItemID )
EscortGroupAttack:OptionROEOpenFire()
EscortGroupAttack:OptionROTVertical()
local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID )
local DetectedSet = self.Detection:GetDetectedSet( DetectedItem )
local Tasks = {}
@@ -943,7 +945,7 @@ function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItemID )
)
else
local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID )
local DetectedSet = self.Detection:GetDetectedSet( DetectedItem )
local Tasks = {}
@@ -1150,7 +1152,7 @@ function ESCORT:_ReportTargetsScheduler()
end
local DetectedItems = self.Detection:GetDetectedItems()
self:E( DetectedItems )
self:F( DetectedItems )
local DetectedTargets = false
@@ -1159,36 +1161,42 @@ function ESCORT:_ReportTargetsScheduler()
for ClientEscortGroupName, EscortGroupData in pairs( self.EscortClient._EscortGroups ) do
local ClientEscortTargets = EscortGroupData.Detection
--local EscortUnit = EscortGroupData:GetUnit( 1 )
for DetectedItemID, DetectedItem in ipairs( DetectedItems ) do
self:E( { DetectedItemID, DetectedItem } )
for DetectedItemIndex, DetectedItem in pairs( DetectedItems ) do
self:F( { DetectedItemIndex, DetectedItem } )
-- Remove the sub menus of the Attack menu of the Escort for the EscortGroup.
local DetectedItemReportSummary = self.Detection:DetectedItemReportSummary( DetectedItemID )
local DetectedItemReportSummary = self.Detection:DetectedItemReportSummary( DetectedItem, EscortGroupData.EscortGroup, _DATABASE:GetPlayerSettings( self.EscortClient:GetPlayerName() ) )
if ClientEscortGroupName == EscortGroupName then
DetectedMsgs[#DetectedMsgs+1] = DetectedItemReportSummary
local DetectedMsg = DetectedItemReportSummary:Text("\n")
DetectedMsgs[#DetectedMsgs+1] = DetectedMsg
self:T( DetectedMsg )
MENU_CLIENT_COMMAND:New( self.EscortClient,
DetectedItemReportSummary,
MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(),
DetectedMsg,
self.EscortMenuAttackNearbyTargets,
ESCORT._AttackTarget,
self,
DetectedItemID
DetectedItem
)
else
if self.EscortMenuTargetAssistance then
self:T( DetectedItemReportSummary )
local MenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance )
MENU_CLIENT_COMMAND:New( self.EscortClient,
DetectedItemReportSummary,
local DetectedMsg = DetectedItemReportSummary:Text("\n")
self:T( DetectedMsg )
local MenuTargetAssistance = MENU_GROUP:New( self.EscortClient:GetGroup(), EscortGroupData.EscortName, self.EscortMenuTargetAssistance )
MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(),
DetectedMsg,
MenuTargetAssistance,
ESCORT._AssistTarget,
self,
EscortGroupData.EscortGroup,
DetectedItemID
DetectedItem
)
end
end
@@ -1197,9 +1205,9 @@ function ESCORT:_ReportTargetsScheduler()
end
end
self:E( DetectedMsgs )
self:F( DetectedMsgs )
if DetectedTargets then
self.EscortGroup:MessageToClient( "Detected targets:\n" .. table.concat( DetectedMsgs, "\n" ), 20, self.EscortClient )
self.EscortGroup:MessageToClient( "Reporting detected targets:\n" .. table.concat( DetectedMsgs, "\n" ), 20, self.EscortClient )
else
self.EscortGroup:MessageToClient( "No targets detected.", 10, self.EscortClient )
end
@@ -1319,7 +1327,7 @@ function ESCORT:_ReportTargetsScheduler()
--
-- if ClientEscortGroupName == EscortGroupName then
--
-- MENU_CLIENT_COMMAND:New( self.EscortClient,
-- MENU_GROUP_COMMAND:New( self.EscortClient,
-- EscortTargetMessage,
-- self.EscortMenuAttackNearbyTargets,
-- ESCORT._AttackTarget,
@@ -1330,8 +1338,8 @@ function ESCORT:_ReportTargetsScheduler()
-- EscortTargetMessages = EscortTargetMessages .. "\n - " .. EscortTargetMessage
-- else
-- if self.EscortMenuTargetAssistance then
-- local MenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance )
-- MENU_CLIENT_COMMAND:New( self.EscortClient,
-- local MenuTargetAssistance = MENU_GROUP:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance )
-- MENU_GROUP_COMMAND:New( self.EscortClient,
-- EscortTargetMessage,
-- MenuTargetAssistance,
-- ESCORT._AssistTarget,
@@ -1370,7 +1378,7 @@ function ESCORT:_ReportTargetsScheduler()
-- local Distance = ( ( WayPoint.x - EscortVec3.x )^2 +
-- ( WayPoint.y - EscortVec3.z )^2
-- ) ^ 0.5 / 1000
-- MENU_CLIENT_COMMAND:New( self.EscortClient, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } )
-- MENU_GROUP_COMMAND:New( self.EscortClient, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } )
-- end
-- end
--

View File

@@ -1,9 +1,9 @@
--- This module contains the MISSILETRAINER class.
--- **Functional** -- MISSILETRAINER helps you to train missile avoidance.
--
-- ===
--
-- 1) @{MissileTrainer#MISSILETRAINER} class, extends @{Base#BASE}
-- ===============================================================
-- ===
-- The @{#MISSILETRAINER} class uses the DCS world messaging system to be alerted of any missiles fired, and when a missile would hit your aircraft,
-- the class will destroy the missile within a certain range, to avoid damage to your aircraft.
-- It suports the following functionality:
@@ -71,7 +71,7 @@
-- ===
--
-- CREDITS
-- =======
-- ===
-- **Stuka (Danny)** Who you can search on the Eagle Dynamics Forums.
-- Working together with Danny has resulted in the MISSILETRAINER class.
-- Danny has shared his ideas and together we made a design.
@@ -99,39 +99,39 @@ function MISSILETRAINER._Alive( Client, self )
if self.MenusOnOff == true then
Client:Message( "Use the 'Radio Menu' -> 'Other (F10)' -> 'Missile Trainer' menu options to change the Missile Trainer settings (for all players).", 15, "Trainer" )
Client.MainMenu = MENU_CLIENT:New( Client, "Missile Trainer", nil ) -- Menu#MENU_CLIENT
Client.MainMenu = MENU_GROUP:New( Client:GetGroup(), "Missile Trainer", nil ) -- Menu#MENU_GROUP
Client.MenuMessages = MENU_CLIENT:New( Client, "Messages", Client.MainMenu )
Client.MenuOn = MENU_CLIENT_COMMAND:New( Client, "Messages On", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = true } )
Client.MenuOff = MENU_CLIENT_COMMAND:New( Client, "Messages Off", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = false } )
Client.MenuMessages = MENU_GROUP:New( Client:GetGroup(), "Messages", Client.MainMenu )
Client.MenuOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Messages On", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = true } )
Client.MenuOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Messages Off", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = false } )
Client.MenuTracking = MENU_CLIENT:New( Client, "Tracking", Client.MainMenu )
Client.MenuTrackingToAll = MENU_CLIENT_COMMAND:New( Client, "To All", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = true } )
Client.MenuTrackingToTarget = MENU_CLIENT_COMMAND:New( Client, "To Target", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = false } )
Client.MenuTrackOn = MENU_CLIENT_COMMAND:New( Client, "Tracking On", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = true } )
Client.MenuTrackOff = MENU_CLIENT_COMMAND:New( Client, "Tracking Off", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = false } )
Client.MenuTrackIncrease = MENU_CLIENT_COMMAND:New( Client, "Frequency Increase", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = -1 } )
Client.MenuTrackDecrease = MENU_CLIENT_COMMAND:New( Client, "Frequency Decrease", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = 1 } )
Client.MenuTracking = MENU_GROUP:New( Client:GetGroup(), "Tracking", Client.MainMenu )
Client.MenuTrackingToAll = MENU_GROUP_COMMAND:New( Client:GetGroup(), "To All", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = true } )
Client.MenuTrackingToTarget = MENU_GROUP_COMMAND:New( Client:GetGroup(), "To Target", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = false } )
Client.MenuTrackOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Tracking On", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = true } )
Client.MenuTrackOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Tracking Off", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = false } )
Client.MenuTrackIncrease = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Frequency Increase", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = -1 } )
Client.MenuTrackDecrease = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Frequency Decrease", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = 1 } )
Client.MenuAlerts = MENU_CLIENT:New( Client, "Alerts", Client.MainMenu )
Client.MenuAlertsToAll = MENU_CLIENT_COMMAND:New( Client, "To All", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = true } )
Client.MenuAlertsToTarget = MENU_CLIENT_COMMAND:New( Client, "To Target", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = false } )
Client.MenuHitsOn = MENU_CLIENT_COMMAND:New( Client, "Hits On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = true } )
Client.MenuHitsOff = MENU_CLIENT_COMMAND:New( Client, "Hits Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = false } )
Client.MenuLaunchesOn = MENU_CLIENT_COMMAND:New( Client, "Launches On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = true } )
Client.MenuLaunchesOff = MENU_CLIENT_COMMAND:New( Client, "Launches Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = false } )
Client.MenuAlerts = MENU_GROUP:New( Client:GetGroup(), "Alerts", Client.MainMenu )
Client.MenuAlertsToAll = MENU_GROUP_COMMAND:New( Client:GetGroup(), "To All", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = true } )
Client.MenuAlertsToTarget = MENU_GROUP_COMMAND:New( Client:GetGroup(), "To Target", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = false } )
Client.MenuHitsOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Hits On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = true } )
Client.MenuHitsOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Hits Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = false } )
Client.MenuLaunchesOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Launches On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = true } )
Client.MenuLaunchesOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Launches Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = false } )
Client.MenuDetails = MENU_CLIENT:New( Client, "Details", Client.MainMenu )
Client.MenuDetailsDistanceOn = MENU_CLIENT_COMMAND:New( Client, "Range On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = true } )
Client.MenuDetailsDistanceOff = MENU_CLIENT_COMMAND:New( Client, "Range Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = false } )
Client.MenuDetailsBearingOn = MENU_CLIENT_COMMAND:New( Client, "Bearing On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = true } )
Client.MenuDetailsBearingOff = MENU_CLIENT_COMMAND:New( Client, "Bearing Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = false } )
Client.MenuDetails = MENU_GROUP:New( Client:GetGroup(), "Details", Client.MainMenu )
Client.MenuDetailsDistanceOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Range On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = true } )
Client.MenuDetailsDistanceOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Range Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = false } )
Client.MenuDetailsBearingOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Bearing On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = true } )
Client.MenuDetailsBearingOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Bearing Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = false } )
Client.MenuDistance = MENU_CLIENT:New( Client, "Set distance to plane", Client.MainMenu )
Client.MenuDistance50 = MENU_CLIENT_COMMAND:New( Client, "50 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 50 / 1000 } )
Client.MenuDistance100 = MENU_CLIENT_COMMAND:New( Client, "100 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 100 / 1000 } )
Client.MenuDistance150 = MENU_CLIENT_COMMAND:New( Client, "150 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 150 / 1000 } )
Client.MenuDistance200 = MENU_CLIENT_COMMAND:New( Client, "200 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 200 / 1000 } )
Client.MenuDistance = MENU_GROUP:New( Client:GetGroup(), "Set distance to plane", Client.MainMenu )
Client.MenuDistance50 = MENU_GROUP_COMMAND:New( Client:GetGroup(), "50 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 50 / 1000 } )
Client.MenuDistance100 = MENU_GROUP_COMMAND:New( Client:GetGroup(), "100 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 100 / 1000 } )
Client.MenuDistance150 = MENU_GROUP_COMMAND:New( Client:GetGroup(), "150 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 150 / 1000 } )
Client.MenuDistance200 = MENU_GROUP_COMMAND:New( Client:GetGroup(), "200 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 200 / 1000 } )
else
if Client.MainMenu then
Client.MainMenu:Remove()
@@ -177,13 +177,13 @@ function MISSILETRAINER:New( Distance, Briefing )
-- for ClientID, Client in pairs( self.DBClients.Database ) do
-- self:E( "ForEach:" .. Client.UnitName )
-- self:F( "ForEach:" .. Client.UnitName )
-- Client:Alive( self._Alive, self )
-- end
--
self.DBClients:ForEachClient(
function( Client )
self:E( "ForEach:" .. Client.UnitName )
self:F( "ForEach:" .. Client.UnitName )
Client:Alive( self._Alive, self )
end
)
@@ -442,7 +442,7 @@ function MISSILETRAINER._MenuMessages( MenuParameters )
if MenuParameters.Distance ~= nil then
self.Distance = MenuParameters.Distance
MESSAGE:New( "Hit detection distance set to " .. self.Distance * 1000 .. " meters", 15, "Menu" ):ToAll()
MESSAGE:New( "Hit detection distance set to " .. ( self.Distance * 1000 ) .. " meters", 15, "Menu" ):ToAll()
end
end
@@ -570,72 +570,76 @@ function MISSILETRAINER:_TrackMissiles()
for ClientDataID, ClientData in pairs( self.TrackingMissiles ) do
local Client = ClientData.Client
self:T2( { Client:GetName() } )
if Client and Client:IsAlive() then
for MissileDataID, MissileData in pairs( ClientData.MissileData ) do
self:T3( MissileDataID )
local TrainerSourceUnit = MissileData.TrainerSourceUnit
local TrainerWeapon = MissileData.TrainerWeapon
local TrainerTargetUnit = MissileData.TrainerTargetUnit
local TrainerWeaponTypeName = MissileData.TrainerWeaponTypeName
local TrainerWeaponLaunched = MissileData.TrainerWeaponLaunched
for MissileDataID, MissileData in pairs( ClientData.MissileData ) do
self:T3( MissileDataID )
if Client and Client:IsAlive() and TrainerSourceUnit and TrainerSourceUnit:IsAlive() and TrainerWeapon and TrainerWeapon:isExist() and TrainerTargetUnit and TrainerTargetUnit:IsAlive() then
local PositionMissile = TrainerWeapon:getPosition().p
local TargetVec3 = Client:GetVec3()
local Distance = ( ( PositionMissile.x - TargetVec3.x )^2 +
( PositionMissile.y - TargetVec3.y )^2 +
( PositionMissile.z - TargetVec3.z )^2
) ^ 0.5 / 1000
if Distance <= self.Distance then
-- Hit alert
TrainerWeapon:destroy()
if self.MessagesOnOff == true and self.AlertsHitsOnOff == true then
self:T( "killed" )
local Message = MESSAGE:New(
string.format( "%s launched by %s killed %s",
TrainerWeapon:getTypeName(),
TrainerSourceUnit:GetTypeName(),
TrainerTargetUnit:GetPlayerName()
), 15, "Hit Alert" )
if self.AlertsToAll == true then
Message:ToAll()
else
Message:ToClient( Client )
local TrainerSourceUnit = MissileData.TrainerSourceUnit
local TrainerWeapon = MissileData.TrainerWeapon
local TrainerTargetUnit = MissileData.TrainerTargetUnit
local TrainerWeaponTypeName = MissileData.TrainerWeaponTypeName
local TrainerWeaponLaunched = MissileData.TrainerWeaponLaunched
if Client and Client:IsAlive() and TrainerSourceUnit and TrainerSourceUnit:IsAlive() and TrainerWeapon and TrainerWeapon:isExist() and TrainerTargetUnit and TrainerTargetUnit:IsAlive() then
local PositionMissile = TrainerWeapon:getPosition().p
local TargetVec3 = Client:GetVec3()
local Distance = ( ( PositionMissile.x - TargetVec3.x )^2 +
( PositionMissile.y - TargetVec3.y )^2 +
( PositionMissile.z - TargetVec3.z )^2
) ^ 0.5 / 1000
if Distance <= self.Distance then
-- Hit alert
TrainerWeapon:destroy()
if self.MessagesOnOff == true and self.AlertsHitsOnOff == true then
self:T( "killed" )
local Message = MESSAGE:New(
string.format( "%s launched by %s killed %s",
TrainerWeapon:getTypeName(),
TrainerSourceUnit:GetTypeName(),
TrainerTargetUnit:GetPlayerName()
), 15, "Hit Alert" )
if self.AlertsToAll == true then
Message:ToAll()
else
Message:ToClient( Client )
end
MissileData = nil
table.remove( ClientData.MissileData, MissileDataID )
self:T(ClientData.MissileData)
end
end
else
if not ( TrainerWeapon and TrainerWeapon:isExist() ) then
if self.MessagesOnOff == true and self.AlertsLaunchesOnOff == true then
-- Weapon does not exist anymore. Delete from Table
local Message = MESSAGE:New(
string.format( "%s launched by %s self destructed!",
TrainerWeaponTypeName,
TrainerSourceUnit:GetTypeName()
), 5, "Tracking" )
if self.AlertsToAll == true then
Message:ToAll()
else
Message:ToClient( Client )
end
end
MissileData = nil
table.remove( ClientData.MissileData, MissileDataID )
self:T(ClientData.MissileData)
self:T( ClientData.MissileData )
end
end
else
if not ( TrainerWeapon and TrainerWeapon:isExist() ) then
if self.MessagesOnOff == true and self.AlertsLaunchesOnOff == true then
-- Weapon does not exist anymore. Delete from Table
local Message = MESSAGE:New(
string.format( "%s launched by %s self destructed!",
TrainerWeaponTypeName,
TrainerSourceUnit:GetTypeName()
), 5, "Tracking" )
if self.AlertsToAll == true then
Message:ToAll()
else
Message:ToClient( Client )
end
end
MissileData = nil
table.remove( ClientData.MissileData, MissileDataID )
self:T( ClientData.MissileData )
end
end
else
self.TrackingMissiles[ClientDataID] = nil
end
end
@@ -651,7 +655,7 @@ function MISSILETRAINER:_TrackMissiles()
for ClientDataID, ClientData in pairs( self.TrackingMissiles ) do
local Client = ClientData.Client
self:T2( { Client:GetName() } )
--self:T2( { Client:GetName() } )
ClientData.MessageToClient = ""
@@ -661,7 +665,7 @@ function MISSILETRAINER:_TrackMissiles()
for TrackingDataID, TrackingData in pairs( self.TrackingMissiles ) do
for MissileDataID, MissileData in pairs( TrackingData.MissileData ) do
self:T3( MissileDataID )
--self:T3( MissileDataID )
local TrainerSourceUnit = MissileData.TrainerSourceUnit
local TrainerWeapon = MissileData.TrainerWeapon

View File

@@ -1,4 +1,8 @@
--- Limit the simultaneous movement of Groups within a running Mission.
--- **Functional** -- Limit the MOVEMENT of simulaneous moving ground vehicles.
--
-- ===
--
-- Limit the simultaneous movement of Groups within a running Mission.
-- This module is defined to improve the performance in missions, and to bring additional realism for GROUND vehicles.
-- Performance: If in a DCSRTE there are a lot of moving GROUND units, then in a multi player mission, this WILL create lag if
-- the main DCS execution core of your CPU is fully utilized. So, this class will limit the amount of simultaneous moving GROUND units

View File

@@ -0,0 +1,305 @@
--- **Functional** -- The PROTECT class handles the protection of objects, which can be zones, units, scenery.
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions: **MillerTime**
--
-- ===
--
-- @module Protect
--- @type PROTECT.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-)
-- @extends Core.Fsm#FSM
--- @type PROTECT
-- @extends #PROTECT.__
--- # PROTECT, extends @{Base#BASE}
--
-- @field #PROTECT
PROTECT = {
ClassName = "PROTECT",
}
--- Get the ProtectZone
-- @param #PROTECT self
-- @return Core.Zone#ZONE_BASE
function PROTECT:GetProtectZone()
return self.ProtectZone
end
--- Get the name of the ProtectZone
-- @param #PROTECT self
-- @return #string
function PROTECT:GetProtectZoneName()
return self.ProtectZone:GetName()
end
--- Set the owning coalition of the zone.
-- @param #PROTECT self
-- @param DCSCoalition.DCSCoalition#coalition Coalition
function PROTECT:SetCoalition( Coalition )
self.Coalition = Coalition
end
--- Get the owning coalition of the zone.
-- @param #PROTECT self
-- @return DCSCoalition.DCSCoalition#coalition Coalition.
function PROTECT:GetCoalition()
return self.Coalition
end
--- Get the owning coalition name of the zone.
-- @param #PROTECT self
-- @return #string Coalition name.
function PROTECT:GetCoalitionName()
if self.Coalition == coalition.side.BLUE then
return "Blue"
end
if self.Coalition == coalition.side.RED then
return "Red"
end
if self.Coalition == coalition.side.NEUTRAL then
return "Neutral"
end
return ""
end
function PROTECT:IsGuarded()
local IsGuarded = self.ProtectZone:IsAllInZoneOfCoalition( self.Coalition )
self:F( { IsGuarded = IsGuarded } )
return IsGuarded
end
function PROTECT:IsCaptured()
local IsCaptured = self.ProtectZone:IsAllInZoneOfOtherCoalition( self.Coalition )
self:F( { IsCaptured = IsCaptured } )
return IsCaptured
end
function PROTECT:IsAttacked()
local IsAttacked = self.ProtectZone:IsSomeInZoneOfCoalition( self.Coalition )
self:F( { IsAttacked = IsAttacked } )
return IsAttacked
end
function PROTECT:IsEmpty()
local IsEmpty = self.ProtectZone:IsNoneInZone()
self:F( { IsEmpty = IsEmpty } )
return IsEmpty
end
--- Check if the units are still alive.
-- @param #PROTECT self
function PROTECT:AreProtectUnitsAlive()
local IsAlive = false
local UnitSet = self.ProtectUnitSet
UnitSet:Flush( self )
local UnitList = UnitSet:GetSet()
for UnitID, ProtectUnit in pairs( UnitList ) do
local IsUnitAlive = ProtectUnit:IsAlive()
if IsUnitAlive == true then
IsAlive = true
break
end
end
return IsAlive
end
--- Check if the statics are still alive.
-- @param #PROTECT self
function PROTECT:AreProtectStaticsAlive()
local IsAlive = false
local StaticSet = self.ProtectStaticSet
StaticSet:Flush( self )
local StaticList = StaticSet:GetSet()
for UnitID, ProtectStatic in pairs( StaticList ) do
local IsStaticAlive = ProtectStatic:IsAlive()
if IsStaticAlive == true then
IsAlive = true
break
end
end
return IsAlive
end
--- Check if there is a capture unit in the zone.
-- @param #PROTECT self
function PROTECT:IsCaptureUnitInZone()
local CaptureUnitSet = self.CaptureUnitSet
CaptureUnitSet:Flush( self )
local IsInZone = self.CaptureUnitSet:IsPartiallyInZone( self.ProtectZone )
self:F({IsInZone = IsInZone})
return IsInZone
end
--- Smoke.
-- @param #PROTECT self
-- @param #SMOKECOLOR.Color SmokeColor
function PROTECT:Smoke( SmokeColor )
self.SmokeColor = SmokeColor
end
--- Flare.
-- @param #PROTECT self
-- @param #SMOKECOLOR.Color FlareColor
function PROTECT:Flare( FlareColor )
self.ProtectZone:FlareZone( FlareColor, math.random( 1, 360 ) )
end
--- Mark.
-- @param #PROTECT self
function PROTECT:Mark()
local Coord = self.ProtectZone:GetCoordinate()
local ZoneName = self:GetProtectZoneName()
local State = self:GetState()
if self.MarkRed and self.MarkBlue then
self:F( { MarkRed = self.MarkRed, MarkBlue = self.MarkBlue } )
Coord:RemoveMark( self.MarkRed )
Coord:RemoveMark( self.MarkBlue )
end
if self.Coalition == coalition.side.BLUE then
self.MarkBlue = Coord:MarkToCoalitionBlue( "Guard Zone: " .. ZoneName .. "\nStatus: " .. State )
self.MarkRed = Coord:MarkToCoalitionRed( "Capture Zone: " .. ZoneName .. "\nStatus: " .. State )
else
self.MarkRed = Coord:MarkToCoalitionRed( "Guard Zone: " .. ZoneName .. "\nStatus: " .. State )
self.MarkBlue = Coord:MarkToCoalitionBlue( "Capture Zone: " .. ZoneName .. "\nStatus: " .. State )
end
end
--- Bound.
-- @param #PROTECT self
function PROTECT:onafterStart()
self:ScheduleRepeat( 5, 15, 0.1, nil, self.StatusCoalition, self )
self:ScheduleRepeat( 5, 15, 0.1, nil, self.StatusZone, self )
self:ScheduleRepeat( 10, 15, 0, nil, self.StatusSmoke, self )
end
--- Bound.
-- @param #PROTECT self
function PROTECT:onenterGuarded()
if self.Coalition == coalition.side.BLUE then
--elf.ProtectZone:BoundZone( 12, country.id.USA )
else
--self.ProtectZone:BoundZone( 12, country.id.RUSSIA )
end
self:Mark()
end
function PROTECT:onenterCaptured()
local NewCoalition = self.ProtectZone:GetCoalition()
self:F( { NewCoalition = NewCoalition } )
self:SetCoalition( NewCoalition )
self:Mark()
end
function PROTECT:onenterEmpty()
self:Mark()
end
function PROTECT:onenterAttacked()
self:Mark()
end
--- Check status Coalition ownership.
-- @param #PROTECT self
function PROTECT:StatusCoalition()
self:F( { State = self:GetState() } )
self.ProtectZone:Scan()
if self:IsGuarded() then
self:Guard()
else
if self:IsCaptured() then
self:Capture()
end
end
end
--- Check status Zone.
-- @param #PROTECT self
function PROTECT:StatusZone()
self:F( { State = self:GetState() } )
self.ProtectZone:Scan()
if self:IsAttacked() then
self:Attack()
else
if self:IsEmpty() then
self:Empty()
end
end
end
--- Check status Smoke.
-- @param #PROTECT self
function PROTECT:StatusSmoke()
local CurrentTime = timer.getTime()
if self.SmokeTime == nil or self.SmokeTime + 300 <= CurrentTime then
if self.SmokeColor then
self.ProtectZone:GetCoordinate():Smoke( self.SmokeColor )
--self.SmokeColor = nil
self.SmokeTime = CurrentTime
end
end
end

File diff suppressed because it is too large Load Diff

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