Compare commits

...

2079 Commits

Author SHA1 Message Date
Frank
e67b819df9 Merge pull request #1224 from FlightControl-Master/FF/Develop
RANGE v2.2.0
2019-11-09 14:56:55 -05:00
Frank
efccefecad RANGE v2.2.0
- Added option for range instructor and range control radio (needs voice overs).
- Reduced number of smokes for strafe pits.
- Updated docs.
- SetAutoSave will auto load as well.
- other
2019-11-09 20:55:28 +01:00
Frank
faa2debbae DATABASE & RAT
- DATABASE: spawned units (ships) are registered as airbases.
- RAT v2.3.8: script will not crash if (spawned) AIRBASE cannot be found .
2019-11-04 22:17:26 +01:00
Frank
ddf61d1bf3 ARTY v1.1.5
- Fixed bug for tac nukes (critial mass insufficient to trigger nuclear fission).
2019-10-31 18:55:21 +01:00
Frank
c5d514efdf Merge pull request #1220 from FlightControl-Master/FF/Develop
AI_Air_Patrol
2019-10-22 17:28:42 -04:00
Frank
f1c16def9a Update AI_Air_Patrol.lua
- fixed bug that route is not called for racetrack
2019-10-22 23:25:30 +02:00
Frank
626db45a7e Merge pull request #1219 from FlightControl-Master/FF/Develop
AI_Air_Patrol
2019-10-22 16:54:52 -04:00
Frank
21a7594134 Update AI_Air_Patrol.lua
- fixed bug that altitude and speed are not defined for racetrack patterns
2019-10-22 22:53:04 +02:00
Frank
5fd20477d9 Merge pull request #1218 from FlightControl-Master/FF/Develop
AIRBOSS v1.0.9
2019-10-22 08:46:45 -04:00
Frank
01dd3c93d2 AIRBOSS v1.0.9
- Case II/III marshal stacks are not collapsed.
- Fixed little bug that Charlie time cannot be calculated if no future recovery window is defined.
2019-10-22 14:35:10 +02:00
Frank
b733e3b6d8 Merge pull request #1217 from FlightControl-Master/FF/Develop
ATIS v0.5.0
2019-10-21 16:47:44 -04:00
Frank
fe2ef11f8d ATIS v0.5.0 2019-10-21 22:29:45 +02:00
Frank
9b6994749b Merge branch 'develop' into FF/Develop 2019-10-21 00:30:02 +02:00
Frank
9b209d6ce0 ATIS 2019-10-21 00:29:46 +02:00
Frank
ed649747bd Merge pull request #1215 from FlightControl-Master/FF/Develop
ATIS v0.4.1
2019-10-18 15:17:31 -04:00
Frank
f5f1c9043b ATIS v0.4.1
ATIS v0.4.1
- Fixed schedulers being deallocated by lua garbage collector.

RADIOQUEUE
- Added alias optional name.
- Minor.
2019-10-18 21:15:53 +02:00
Frank
c7c371dc34 Merge pull request #1212 from FlightControl-Master/FF/Develop
COORDINATE
2019-10-14 08:36:17 -04:00
Frank
1cea10f03a Update Point.lua
Fixed bug in GetClosestAirbase() function.
2019-10-14 14:34:53 +02:00
Frank
3e9f54aaa5 Merge pull request #1210 from FlightControl-Master/FF/Develop
ATIS v0.4.0
2019-10-10 19:33:48 -04:00
Frank
ab1cd41d79 Update ATIS.lua 2019-10-11 01:23:26 +02:00
Frank
dc9f730d7d ATIS v0.4.0
ATIS
UTILS
AIRBASE
2019-10-09 21:13:08 +02:00
Frank
c0e48288de ATIS v0.3.3
- Improved soud file duration.
- Added Nav point data option.
2019-10-08 00:21:41 +02:00
Frank
a13b79ced1 Merge pull request #1209 from FlightControl-Master/FF/Develop
ATIS v0.3.1
2019-10-03 06:15:02 -04:00
Frank
cd845d385f ATIS v0.3.1
- Fixed bug in NATO alphabet (entry 14 missing)
2019-10-03 12:13:38 +02:00
Frank
dea7a5674c Merge pull request #1208 from FlightControl-Master/FF/Develop
ATIS
2019-10-02 14:55:53 -04:00
Frank
8d1d2179f9 ATIS v0.3.0 2019-10-02 20:43:51 +02:00
Frank
9b96ff5978 AIRBASE
- Added runwaydata and active runway functions
2019-10-02 19:47:33 +02:00
Frank
6cc233cac7 ATIS
- COORDINATE
- RADIO
- RADIOQUEUE
- ATIS
- UTILS
- CONTROLLABLE
2019-10-02 19:45:37 +02:00
FlightControl
ad2ce8df78 Improvements to A2A and A2G Dispatchers 2019-09-30 10:35:29 +02:00
FlightControl
4ea44308bc Fix for older A2A dispatcher CAP api altitude problem during takeoff ... 2019-09-26 19:36:42 +03:00
FlightControl
5cdaf53727 - Added a NoTrace option to the scheduler, so for those schedulers that have a schedule in microseconds, you may wanna use the function NoTrace(), to avoid spamming the dcs.log.
- Started with the implementation of multiple languages of speech. Got now a Russian and English prototype working.
- Moved radio frequency settings to a squadron, so multiple squadrons can communicate in their own radio frequency.
2019-09-25 17:53:11 +03:00
FlightControl
fb875077d7 Speech optimizations for A2A dispatcher 2019-09-22 20:30:59 +02:00
FlightControl
c579aad606 API V2 of the A2A and A2G dispatchers. Now a more fine grained attack is possible. You can now tweak the altitude and speed when units engage the target. Especially useful for ground attacks when SEAD, CAS or BAI.You can model low altitude approaches. Added 2 new test missions under the IAD - A2G API v2. Please report any bugs. 2019-09-22 08:23:28 +02:00
FlightControl
8c54b7298d Tuning A2A AI dispatcher to work with new sound speech system. 2019-09-15 18:36:27 +02:00
FlightControl
b309c25619 Speech Engine Prototype 2019-09-15 18:02:45 +02:00
Frank
04a699f990 Merge pull request #1197 from FlightControl-Master/FF/Develop
Update ScheduleDispatcher.lua
2019-09-13 13:38:52 -04:00
Frank
d51fc5de8a Update ScheduleDispatcher.lua
better fix
2019-09-13 19:37:13 +02:00
Frank
e458c70a7b Merge pull request #1196 from FlightControl-Master/FF/Develop
ScheduleDispatcher Source=nil fix
2019-09-13 12:58:54 -04:00
Frank
2d4a4fb2ca Update ScheduleDispatcher.lua
Fix for Source (=Infor.source) nil problem.
2019-09-13 18:57:27 +02:00
FlightControl
e23ebd622a - Fixing repetition of Patrolling in A2G dispatcher. 2019-09-09 20:24:51 +03:00
FlightControl
98e2f2c09b - Added A2G voice overs to some of the basic events during defender flight. More to come, like multiple languages, and also more voice overs concerning some of the more detailed events, like:
- Damage
  - Firing
  - Enemy location
  - Callsigns
  - Numbers for distance and degrees.
2019-09-09 19:38:22 +03:00
FlightControl
1fd9cbec1f - Added A2G voice overs to some of the basic events during defender flight. More to come, like multiple languages, and also more voice overs concerning some of the more detailed events, like:
- Damage
  - Firing
  - Enemy location
  - Callsigns
  - Numbers for distance and degrees.
2019-09-09 11:17:45 +02:00
FlightControl
1aedcf1ae4 Radio Queue 2019-09-09 08:19:48 +02:00
FlightControl
e0075cc9ac - Added a new UTILS.kpairs iterator, which will base the iteration on a different key, which can be determined before the iteration starts. eg. the key should be a sort in ascending order on the distance of the information in the set, and it should return the distance + item in the set for each element in the set.
- Resolved for TASK_CAPTURE_ZONES the whole logic of determining correctly the player and AI defense zones, as to be displayed in the information panel, this was a very difficult exercise for me.
2019-09-08 08:38:33 +02:00
FlightControl
372dd704d2 - Added a randomization to some of the internal schedulers to ensure that the simulation does not get unnecessary hickups and guarantees more fluent play.
- Added the option SetFlashStatus() to the CommandCenter to ensure flashing of subscribed tasks automatically to inform the player while in-flight. Also extended TASK to ensure the flasing gets initialized once the player joins the task.
2019-09-03 17:25:45 +02:00
FlightControl
14b35cb069 Improvements in trace output:
- Scheduled calls are traced with ---> or +++> prefixes... This is handy to find where scheduled calls were actually called in the code. Line number and function is shown correctly now. ---> is for one schedule, and +++> for repeated schedules.
- Fsm output is now also organized better. All Fsm calls are shown with :::> prefix. The onafter, onbefore, onenter or onleave method names are also shown, and also the state transition including the function call place is shown now.
-- Now for each trace line, the class name has 30 characters space.
2019-08-31 07:24:31 +02:00
FlightControl
c1b240857f - Remove unnecessary trace lines
- Implement Scheduled Trace - Now source and line number are shown for scheduled calls.
- Info lines are now shown where appropriate.
- The width of trace for the class name is now 25 characters instead of 20.
2019-08-26 08:26:14 +02:00
Frank
0f5eb30a0f Merge pull request #1192 from FlightControl-Master/FF/Develop
DATABASE fix
2019-08-25 16:09:05 -04:00
Frank
9e0f2c22b6 DATABASE fix
- Fix bug for RED templates being registered as NEUTRAL
2019-08-25 22:06:51 +02:00
FlightControl
c0771c0096 - Bugfix when enemy plane has crashed, AttackerDetection is not existing anymore.
Implemented an important fix. Refuel airplanes also when they are engaging targets and the fuel treshold has been reached.
- Inherit ZONE_BASE from FSM instead of BASE. Opens a range of possibilities.
- Remove from ZONE_GOAL the Zone field, and make it inherit from ZONE_BASE instead of FSM!
- Rework the new inheritance tree in the code. (Remove .Zone fields).
- Implement the determination of attack and defense zones.
- Reworked the TaskInfo to include Type and ShowKey.
- Flash A2G Tasking Details. Added menu option.
2019-08-25 06:42:03 +02:00
FlightControl
c716ba16b3 - Bugfix when enemy plane has crashed, AttackerDetection is not existing anymore. 2019-08-24 22:28:44 +02:00
FlightControl
96a904c077 Implemented an important fix. Refuel airplanes also when they are engaging targets and the fuel treshold has been reached. 2019-08-24 08:56:50 +02:00
FlightControl
f951aae3ee - Inherit ZONE_BASE from FSM instead of BASE. Opens a range of possibilities.
- Remove from ZONE_GOAL the Zone field, and make it inherit from ZONE_BASE instead of FSM!
- Rework the new inheritance tree in the code. (Remove .Zone fields).
- Implement the determination of attack and defense zones.
- Reworked the TaskInfo to include Type and ShowKey.
- Flash A2G Tasking Details. Added menu option.
2019-08-21 22:04:11 +03:00
Frank
7a859f20bb Merge pull request #1190 from FlightControl-Master/FF/Develop
Ff/develop
2019-08-18 16:26:02 -04:00
Frank
3bfa8830a5 Merge branch 'develop' into FF/Develop 2019-08-18 22:21:54 +02:00
Frank
ec85b42a38 OPS
AIRBOSS v1.0.8
- Fixed bug that status reset after wave off causes a unitcorn grade.
- Optimized radio scheduler calls ==> leads to less mem consumtion according to collectgarbage("count").

RESCUEHELO v1.0.9
- Adjusted default follow time interval to 1.0 sec.
- Added SetFollowTimeInterval() function.
- Respawn after returned delayed by 5 sec.

GROUP
- Added nil check in RespawnAtCurrentAirbase() function.
2019-08-18 22:21:41 +02:00
FlightControl
a216eb4e74 Defense test for TASK_CAPTURE_ZONE 2019-08-18 16:44:20 +02:00
FlightControl
94476e418e Messaging and Tactical Menu 2019-08-17 10:25:26 +02:00
FlightControl
fd1eb5f601 AI_A2A_DISPATCHER and AI_A2G_DISPATCHER ... Fixed in-air refuelling problem. Now refuelling is executed instateneously when patrolling in the air and the fuel treshold has been reached. 2019-08-16 22:15:55 +02:00
Frank
db7ec60c86 Merge pull request #1189 from FlightControl-Master/FF/Develop
Ff/develop
2019-08-14 16:44:20 -04:00
Frank
97e1a65b52 WAREHOUSE v0.9.6
- respawn after destroyed keeps assets
2019-08-14 22:36:39 +02:00
Frank
23497dddd4 ARTY v1.1.3
Unfixed workaround for wrong markpoint coordinates. Was fixed in DCS 2.5.5.34644
2019-08-14 22:32:45 +02:00
Frank
e8a7def26e Update Airboss.lua 2019-08-14 21:51:55 +02:00
Frank
28a23c21f4 Update Airboss.lua 2019-08-14 00:35:54 +02:00
Frank
f32094aa43 up 2019-08-12 22:55:56 +02:00
Frank
c215255ae2 Merge branch 'develop' into FF/Develop 2019-08-11 20:39:31 +02:00
Frank
53b998cfab Airboss v1.0.7
- Corrected Foul Deck waveoff.
- Added LSOGrade event.
2019-08-11 20:25:33 +02:00
FlightControl
0a0a7d0fc3 Added a task message when it is engaging or not. Important for communication to the player. 2019-08-11 12:59:43 +02:00
FlightControl
d84ae236eb Added a task message when it is engaging or not. Important for communication to the player. 2019-08-11 12:59:21 +02:00
FlightControl
6dff84f435 Fixed problem with detections escalating. Too much events fired. 2019-08-11 11:00:53 +02:00
FlightControl
1bfa5b5ee0 Fixed problem with detections escalating. Too much events fired. 2019-08-11 11:00:33 +02:00
FlightControl
c3618bdc26 - Fixed Messaging of A2G defenses to players within the same coalition. Now the callsign will be used to communicate, not the user id. 2019-08-11 10:06:35 +02:00
FlightControl
eebc5d90d1 - Fixed Messaging of A2G defenses to players within the same coalition. Now the callsign will be used to communicate, not the user id. 2019-08-11 10:06:16 +02:00
FlightControl
596b3ddb4a Fixes issue with SetDetectionLimit
Optimized the detection intervals + fixed bugs with player detection.
2019-08-11 09:46:25 +02:00
FlightControl
e770af9fc9 Optimized the detection intervals + fixed bugs with player detection. 2019-08-11 09:45:28 +02:00
FlightControl
d3c76da7a2 Fixes issue with SetDetectionLimit 2019-08-11 08:32:34 +02:00
FlightControl
5f9880f17d - Implemented attack nearest target.
- Implemented attack nearest ground target.
- Implemented attack nearest air target.
- Report all targets.
- Report only ground targets.
- Report only ground targets with radar.
- Report only air targets.
- Sort targest from nearest to furthest.
- Improved menu system.
- Improved detection of ground targets and air targets and reporting.
- Added the task TASK_CAPTURE as part of the reporting framework.
- Improved the detection of targets. Now targets with specific detection methods are correctly detected. f.e. disabling DLINK will now work correctly!

All these fixes are great improvements to the AI_ESCORT framework!
2019-08-10 15:42:00 +02:00
FlightControl
d6b1018700 - Implemented attack nearest target.
- Implemented attack nearest ground target.
- Implemented attack nearest air target.
- Report all targets.
- Report only ground targets.
- Report only ground targets with radar.
- Report only air targets.
- Sort targest from nearest to furthest.
- Improved menu system.
- Improved detection of ground targets and air targets and reporting.
- Added the task TASK_CAPTURE as part of the reporting framework.
- Improved the detection of targets. Now targets with specific detection methods are correctly detected. f.e. disabling DLINK will now work correctly!

All these fixes are great improvements to the AI_ESCORT framework!
2019-08-10 15:41:34 +02:00
Frank
f934c8cb77 Update Warehouse.lua 2019-08-08 23:27:45 +02:00
Frank
db4b5383fa Merge branch 'develop' into FF/Develop 2019-08-07 22:58:07 +02:00
Frank
4982cabcfb AIRBOSS v1.0.7
Corrected foul deck wave off.
2019-08-07 22:17:16 +02:00
FlightControl
5594cd8fdf Removed the escorts to detect targets using DLINK. Now escorts will only report targets that were detected by its own onboard detection methods. 2019-08-07 16:42:08 +02:00
FlightControl
fbb32a9e45 Removed the escorts to detect targets using DLINK. Now escorts will only report targets that were detected by its own onboard detection methods. 2019-08-07 16:41:21 +02:00
FlightControl
1c559110a2 Merged 'develop'. 2019-08-07 16:08:10 +02:00
Frank
6f170db344 Update SWAPR.lua 2019-08-05 21:37:28 +02:00
Frank
27a1401ae1 SWAPR v0.0.2 2019-08-05 18:04:59 +02:00
Frank
debf784d0c SWAPR v0.0.1 2019-08-05 11:15:45 +02:00
FlightControl
5a97f68778 Escort menus are deleted once the escort crashes. 2019-08-02 21:10:56 +03:00
FlightControl
d2ef75b22c Fixed nasty bug where the same plane would be chosen all the time for request spawns. Root cause was the inherit. self variables were also copied during inherit of the chile object, resulting in a bad bad bad behaviour.
Also cleaned up the menus once the player exists the client. When rejoining, it will only see the menu of the current or requested escorts.
I still need to fix a method to renew unused (but alive and intact) escorts for gamey play.
2019-08-01 21:17:46 +03:00
FlightControl
115743263b Fixed nasty bug where the same plane would be chosen all the time for request spawns. Root cause was the inherit. self variables were also copied during inherit of the chile object, resulting in a bad bad bad behaviour. 2019-08-01 21:16:01 +03:00
FlightControl
59447999f0 Updates 2019-08-01 18:29:57 +03:00
Frank
4554ac1f3e Merge pull request #1188 from FlightControl-Master/FF/Develop
AIRBOSS v1.0.6
2019-07-28 22:49:25 +02:00
Frank
d08d8db298 AIRBOSS v1.0.6
- Added Marshal radial to skipper menu.
- Adjusted grading and groove time start for LUL issue.
2019-07-28 22:43:10 +02:00
Frank
099f95f3cc Merge pull request #1187 from FlightControl-Master/FF/Develop
Misc Updates and Fixes
2019-07-22 21:45:06 +02:00
Frank
20cf69c182 Update Airboss.lua 2019-07-22 21:20:05 +02:00
Frank
f931af2ee9 Updates 2019-07-22 21:06:12 +02:00
Frank
96fe9d51d6 Typo bug fix 2019-07-22 16:55:17 +02:00
Frank
d264c6f6a5 Update RecoveryTanker.lua 2019-07-21 23:59:35 +02:00
Frank
e17e635710 Updates 2019-07-21 23:59:05 +02:00
Frank
d4b9fc9e40 Updates 2019-07-21 23:35:09 +02:00
Frank
d66672a29c Merge pull request #1184 from FlightControl-Master/FF/Develop
Updates
2019-07-12 22:27:17 +02:00
Frank
345b0055f3 Update Fox.lua 2019-07-12 21:53:52 +02:00
Frank
7fdc049079 Update Fox.lua 2019-07-12 20:39:07 +02:00
Frank
5caab9c6f3 FOX
- adjustment of destruction distance
- tracking missiles with "unknown" target
2019-07-12 18:38:13 +02:00
Frank
03042c8282 AIRBOSS v1.0.4
One stack per flight group in CASE II/III
2019-07-12 09:41:13 +02:00
Frank
c46028ff2d FOX v0.6.0
FOX v0.6.0
- Missile target constantly updated.
- Increased safety distance to 200 m.
- Added safety distance for BIG missiles > 50 kg TNT as 400 m.
- More output to dcs.log file.

SPAWN
- enabled uncontrolled

UTILS
- LLDMS accurracy fix.

AI_A2A_DISPATCHER
- Squadron visible improvements

ZONE
- Added MarkZone function for F10 zone markings.

AI_PATROL_ZONE
- Some WP code improvements.
2019-07-10 22:29:49 +02:00
Frank
bd83344c21 Merge pull request #1179 from FlightControl-Master/FF/Develop
CAP
2019-07-06 23:43:21 +02:00
Frank
183c05bcf5 CAP
AI_A2A_PATROL
- Added CAP coordinates option.

AI_A2A_DISPATCHER
- Added CAP coordinates option.
2019-07-06 23:39:48 +02:00
Frank
a94591d811 Merge pull request #1178 from FlightControl-Master/FF/Develop
CAP
2019-07-06 20:27:50 +02:00
Frank
6973e8c028 CAP
AI_A2A_PATROL:
- Added optional race track pattern.

AI_A2A_DISPATCHER:
- Added option for CAP patrolling in a race track pattern.
2019-07-06 20:23:07 +02:00
Frank
ab0b3f9b91 Merge pull request #1177 from FlightControl-Master/FF/Develop
Fixes and Docs
2019-07-05 20:47:12 +02:00
Frank
6f140be710 Update
A2A_DISPATCHER
- Docs

CONTROLLABLE
- OptionROEOpenFireWeaponFree()
- Fixed OptionRTBBingoFuel()
2019-07-05 20:01:26 +02:00
Frank
8780ec3687 Docs
Updated docs and function argument description of DETECTION and A2A_DISPATCHER.
2019-07-03 22:13:56 +02:00
FlightControl
1afe1c48b4 Updates - Much improved version! 2019-07-01 17:29:23 +03:00
Frank
14b834e8ad Merge pull request #1175 from FlightControl-Master/FF/Develop
SPOT
2019-06-30 20:07:38 +02:00
Frank
0b53bd8f7e Merge branch 'develop' into FF/Develop 2019-06-30 17:34:22 +02:00
Frank
376a3553fa SPOT
- Fixed bug in LaseOnCoordinate.
- Minor stuff.
2019-06-30 17:34:00 +02:00
FlightControl
35653898cd WIP 2019-06-28 17:15:40 +03:00
Frank
ab1ba9595d Merge pull request #1174 from FlightControl-Master/FF/Develop
MISC Fixes and Improvements
2019-06-26 19:56:15 +02:00
Frank
2a7b9cf898 DETECTION, SET, ARTY, WAREHOUSE, AIRBOSS, A2A_DISPATCHER
DETECTION
- Fixed bug with late activated groups.

ARTY v1.1.2
- Added attack group task for ships.
- Added respawn option.

WAREHOUSE v0.9.5
- Added respawn option.

AIRBOSS v1.0.3
- Recovery time extended if flights are still in the pattern.

SET
- Added CountAlive() function.

A2A_DISPATCHER
- Bug fixes in :ParkDefender() function.
2019-06-26 19:19:17 +02:00
Frank
1224fb2d5a Merge branch 'develop' into FF/Develop 2019-06-24 23:17:32 +02:00
Frank
ac1d07ec66 updates 2019-06-24 23:17:18 +02:00
Frank
1a534108bf Updates
ARTY v1.1.0
- added attack group
- target data struckture

WAREHOUSE v0.9.4
- assignment as descriptor

AIRBOSS v1.0.3
- removed warehouse table
- no stoping of recovery window if pattern is not empty
- changes in patrol route
2019-06-24 14:19:36 +02:00
Frank
c88f7bede5 SPOT
LaseCoordinate
Alarm state ships
zonRadius in task fire at point.
2019-06-24 13:38:01 +02:00
Frank
598ef58849 Merge pull request #1172 from FlightControl-Master/FF/Develop
Rescue Helo v1.0.7
2019-06-21 20:04:00 +02:00
Frank
2a485ef85a Rescue Helo v1.0.7
RESCUEHELO v1.0.7
Compatibility fix for AI_FORMATION changes.
2019-06-21 19:57:55 +02:00
Frank
98ce42e9aa Merge branch 'develop' into FF/Develop 2019-06-21 17:26:10 +02:00
FlightControl
3612d5d171 Fixes 2019-06-20 21:50:52 +03:00
FlightControl
83f8e76584 Fixed error in SPAWN logic. Sorry. fixed now. 2019-06-20 20:42:47 +03:00
FlightControl
a108751e0c Updates 2019-06-19 18:32:39 +03:00
FlightControl
6f4d6c3daf Updates 2019-06-19 18:32:21 +03:00
FlightControl
a907369082 FlightMode 2019-06-19 18:17:12 +03:00
FlightControl
bc9060adfc Initial flight mode is formation. 2019-06-19 18:13:00 +03:00
FlightControl
4296dbade7 Small fixes 2019-06-19 06:57:40 +03:00
FlightControl
b1cee9969f Fixes 2019-06-19 05:17:51 +03:00
FlightControl
9c0c4a11b1 Finish Feature-Escort 2019-06-18 20:22:38 +03:00
FlightControl
b4324cb057 Optimized inclination for formation flying. 2019-06-18 20:18:43 +03:00
FlightControl
1d4dad0180 Updates 2019-06-18 20:03:24 +03:00
FlightControl
1e0e67c13d Updates 2019-06-18 07:06:00 +03:00
FlightControl
9c523cad52 Updates 2019-06-17 20:25:50 +03:00
FlightControl
6a1bf50700 Updated 2019-06-17 10:19:15 +03:00
FlightControl
d34cff1675 Temporary 2019-06-17 09:00:45 +02:00
FlightControl
0a027caa47 Test 2019-06-15 12:47:24 +02:00
Frank
10bfefdd06 pseudoATC
- Fixed bug for ReportBR.
2019-06-08 23:06:45 +02:00
Frank
ead1aed8d5 Merge pull request #1167 from FlightControl-Master/FF/Develop
Airboss v1.0.2
2019-06-04 17:39:33 +02:00
Frank
bc229f1a86 Update Warehouse.lua 2019-06-04 17:36:23 +02:00
Frank
94f9cb4a79 Update Airboss.lua 2019-06-03 23:18:54 +02:00
Frank
acd5b1bdca minor 2019-06-03 22:58:53 +02:00
Frank
9fed91b16f AIRBOSS v1.0.2
- Added skipper menu.
- Added turn help waypoints.
2019-06-02 23:12:08 +02:00
Frank
1627c92460 Airboss v1.0.1 2019-06-01 23:25:44 +02:00
FlightControl
7bae22248a Optimizations ROE and ROT and flight modes. 2019-06-01 08:06:18 +02:00
FlightControl
7b5b57c087 updates 2019-05-31 16:35:35 +02:00
Frank
271217cf04 Update Warehouse.lua 2019-05-28 23:58:14 +02:00
FlightControl
c5236d337e Updates 2019-05-28 20:44:51 +03:00
Frank
747bb949da Merge pull request #1164 from FlightControl-Master/FF/Develop
WH v0.9.1
2019-05-28 19:04:52 +02:00
Frank
a53bb1aac6 WH v0.9.1
- Added request as parameter in AssetSpawned event.
2019-05-28 00:24:47 +02:00
FlightControl
d3ecbac40a Updates for mission mode. 2019-05-27 17:10:19 +02:00
Frank
28fe8c5a0e Merge pull request #1162 from FlightControl-Master/FF/Develop
RANGE 2.1.2
2019-05-27 14:32:57 +02:00
Frank
6d79bbfb45 RANGE 2.1.2
fixes
2019-05-27 14:15:17 +02:00
Frank
944c76c250 Merge pull request #1161 from FlightControl-Master/FF/Develop
FOX Missile Trainer and Misc
2019-05-26 21:30:15 +02:00
Frank
256ef2c7b4 Update Warehouse.lua 2019-05-26 21:25:11 +02:00
thebgpikester
2a0ae95e3e Merge pull request #1160 from FlightControl-Master/wingthor_fixes
Wingthor fixes
2019-05-26 16:06:01 +01:00
Wingthor
604ff07933 fix issue #948 in Scoring.lua
Changed ScoreGoals to PenaltyGoals in function CORING:ReportScoreAllSummary( PlayerGroup )
2019-05-26 16:49:56 +02:00
thebgpikester
be8fc4e2e6 Merge pull request #1151 from TommyC81/patch-1
Corrected AIRBASE name comment.
2019-05-26 15:31:07 +01:00
thebgpikester
e92a625c5c Merge pull request #1142 from FlightControl-Master/wingthor_fixes
Wingthor fixes
2019-05-26 15:29:09 +01:00
Frank
e141823556 FOX Missile Trainer
FOX v0.5.0
- Added new missile trainer.
RANGE v2.1.1
- Fixed bugs.
WAREHOUSE v0.9.0
- Added events AssetSpawned and AssetLowFuel
- Improved Arrived function.
2019-05-26 12:15:21 +02:00
Frank
fbd0e9839d Merge pull request #1159 from FlightControl-Master/FF/Develop
Fixed Database OnEventNewZone function
2019-05-23 21:16:21 +02:00
Frank
889ce8f64b Fixed Database OnEventNewZone function 2019-05-23 21:10:48 +02:00
FlightControl
6be56b1b86 Progress 2019-05-23 16:33:47 +03:00
FlightControl
78a5e89928 Synth 2019-05-17 21:12:02 +02:00
FlightControl
e09a02ec14 Escort menus reworked. It took a while (sorry), was involved in many projects in RL. 2019-05-13 11:22:49 +02:00
Frank
32ff4db36a Merge pull request #1154 from FlightControl-Master/FF/Develop
MISC
2019-05-07 22:06:42 +02:00
Frank
9bb1c83999 MISC
RANGE v2.1
- Added events when players enter/exit range zone.
- misc

RADIO
- Added RADIOQUEUE class.

WAREHOUSE v0.7.0
- Fixed bug in aircraft speed.
- Decreased output if queues are empty.
2019-05-07 22:00:07 +02:00
FlightControl
93951dd4b4 WIP, not for playing. 2019-05-04 07:10:09 +02:00
FlightControl
1440f6c626 WIP, not for play. 2019-05-03 19:11:53 +02:00
Frank
aacf83fd11 Merge pull request #1153 from FlightControl-Master/FF/Develop
RANGE 2.0
2019-05-01 18:00:56 +02:00
Frank
6c35892f05 RANGE 2.0
Range v2.0.0
- Turned into FSM.
- Added radial to bomb impact info.
- Added option to add coordinates as bomb target.
- Added option to save bombing results to file.

AIRBOSS v1.0.0
- Added option to disable welcome message.
- Increased output load/save.
2019-05-01 17:56:25 +02:00
FlightControl
3657a19645 Updates of working version. 2019-04-26 18:42:42 +02:00
FlightControl
ab423b3ba4 First working version of AI_ESCORT_REQUEST. 2019-04-25 18:52:46 +02:00
FlightControl
b4d6f78e42 WIP, need to make a new class next week, AI_ESCORT_REQUEST. Need to solve the issue with the formation flying uof multiple escort classes working together. Planes may not crash into each other. 2019-04-25 08:59:07 +03:00
TommyC81
49217291ad Corrected AIRBASE name comment.
Corrected array name for Bandar-e-Jask Airfield.
2019-04-24 17:22:41 +04:00
FlightControl
315d6bf82a ParkAtAirbase new method. 2019-04-23 20:33:21 +03:00
Frank
486fc83323 Merge pull request #1149 from FlightControl-Master/FF/Develop
Ops and Range
2019-04-23 19:17:49 +02:00
Frank
3dbb013e16 Ops and Range
RANGE v1.3.0
- Generalized weapon handling.
- Decreased time before weapon tracking starts from 1.0 to 0.1 sec.

RESCUE HELO v1.0.6
- Got rid of IsAlive() check in rescue operation.

AIRBOSS v0.9.9.9.9
- Fixed bug in trap sheet output.
2019-04-23 19:13:03 +02:00
FlightControl
b21ff707ba Updates escort before plane trip. 2019-04-23 19:59:11 +03:00
FlightControl
d985d9a41d WIP 2019-04-16 19:49:46 +02:00
Frank
178ee09614 Merge pull request #1145 from FlightControl-Master/FF/Develop
Persian Gulf Airbases Update (Final)
2019-04-13 10:15:31 +02:00
Frank
95b67550eb Persian Gulf Airbases Update (Final)
Thanks to Shadowze.
2019-04-13 10:07:55 +02:00
Frank
48e0f8add6 Merge pull request #1144 from FlightControl-Master/FF/Develop
AIRBOSS v0.9.9.8
2019-04-12 22:23:07 +02:00
Frank
d4f6ba2bdb Airboss v0.9.9.8 2019-04-12 21:59:53 +02:00
Frank
e26b2f4919 Merge branch 'develop' into FF/Develop 2019-04-12 17:57:15 +02:00
Frank
208761fa46 Static and Delay 2019-04-11 21:46:54 +02:00
FlightControl
03c47cc9f9 documentation 2019-04-10 18:49:05 +02:00
funkyfranky
eb62810911 Range 2019-04-10 16:24:45 +02:00
FlightControl
bf449492b5 Updated approach speed logic to prevent airplanes to fly beyond the hold position. 2019-04-09 17:45:29 +02:00
funkyfranky
4c08002d3e AB 0998 2019-04-09 14:56:20 +02:00
FlightControl
5e67861ea9 Improvements 2019-04-08 17:55:24 +02:00
FlightControl
c657ba9218 Added different formations to the menus. 2019-04-08 06:42:00 +02:00
FlightControl
ddfc22bb50 wip 2019-04-08 06:41:22 +02:00
FlightControl
f9f4b3a9fd wip 2019-04-08 05:39:57 +02:00
FlightControl
0e14624d39 wip 2019-04-07 11:07:20 +02:00
FlightControl
f1d217b6d7 wip 2019-04-07 08:31:22 +02:00
Wingthor
8126b198ba Fixed bug with SPAWN:GetLastAliveGroup() issue 1141
Changed line 2208
2019-04-07 02:56:41 +02:00
Wingthor
c2b46ceea1 Fixes GitHub issue 1140
SPAWN: GetLastAliveGroup() #1140 generating a nil value...

  "attempt to index field 'SpawnTemplatePrefixself' (a nil value)"
2019-04-07 02:04:08 +02:00
FlightControl
fcceb278ec First version 2019-04-06 16:34:00 +02:00
FlightControl
7a89960d21 Updates 2019-04-06 16:33:22 +02:00
FlightControl
4abdad5f35 First version 2019-04-06 13:04:28 +02:00
Frank
6593a262bb Update Airboss.lua 2019-04-03 23:36:22 +02:00
Frank
b2f6b141d4 Merge pull request #1138 from FlightControl-Master/FF/Develop
AIRBOSS v0.9.9.7
2019-04-02 21:29:36 +02:00
funkyfranky
4bcf43122f AB 2019-04-02 16:27:41 +02:00
Frank
70f30d2c53 AIBOSS v0.9.9.7 2019-04-01 18:28:17 +02:00
Frank
a29a8d7d81 AIBOSS v0.9.9.7 2019-04-01 18:17:52 +02:00
Frank
77f1bb4fdd Merge branch 'develop' into FF/Develop 2019-03-31 21:58:28 +02:00
Frank
53166b555f AIRBOSS v0.9.9.7 2019-03-31 21:55:30 +02:00
funkyfranky
5f58fd3550 AB 0996w 2019-03-28 16:35:38 +01:00
Frank
b7b6034d76 AIRBOSS v0.9.9.6w 2019-03-27 23:29:41 +01:00
FlightControl
59974ea33e New Zone Detection module. 2019-03-27 19:18:12 +01:00
funkyfranky
e4935d8717 Merge branch 'FF/Develop' of https://github.com/FlightControl-Master/MOOSE into FF/Develop 2019-03-27 16:24:17 +01:00
funkyfranky
de0c8e3789 AB 0.996w 2019-03-27 16:23:39 +01:00
FlightControl
bd290ffdab Fixing hit problem in multi player for database when hitting static objects. 2019-03-23 11:24:04 +01:00
FlightControl
bfb11b6f79 Updates on goal logic 2019-03-23 10:45:41 +01:00
Frank
8667c98449 Merge branch 'develop' into FF/Develop 2019-03-22 22:43:57 +01:00
Frank
4c72496599 Merge pull request #1133 from FlightControl-Master/FF/Develop
AIRBOSS v0.9.9.6
2019-03-22 22:42:40 +01:00
Frank
aa8498ce0b AIRBOSS v0.9.9.6 2019-03-22 22:05:25 +01:00
funkyfranky
ec155ed80c AB v0.9.9.6w 2019-03-22 16:23:22 +01:00
FlightControl
f849732f55 Various improvements 2019-03-21 07:01:24 +01:00
FlightControl
9856a8625d Goal 2019-03-21 06:57:04 +01:00
FlightControl
b1e99dc317 Goal 2019-03-21 06:31:13 +01:00
FlightControl
310ba9bb8a Reverse 2019-03-21 06:18:48 +01:00
FlightControl
565a3062cb Fixing goal state machine rule 2019-03-21 06:11:59 +01:00
FlightControl
e8b74f0fc7 handling static in scan 2019-03-21 06:03:13 +01:00
FlightControl
ca65154ecd Fixes 2019-03-21 05:49:48 +01:00
FlightControl
e996a30333 Updates 2019-03-21 05:21:16 +01:00
Frank
e33a38556e Merge pull request #1132 from FlightControl-Master/FF/Develop
AIRBOSS v0.9.9.5
2019-03-20 22:17:15 +01:00
Frank
3f2b3e0e1a AIRBOSS v0.9.9.5
- Added Raynor LSO/Marshal voice over parameters.
- Added nil checks for events.
2019-03-20 21:59:32 +01:00
Frank
dab0aef1e3 AIRBOSS v0.9.9.5 2019-03-20 21:57:18 +01:00
FlightControl
d9fb9c4928 Report Mission fix 2019-03-20 18:36:55 +01:00
FlightControl
964a6d0708 Debug 2019-03-20 18:15:37 +01:00
FlightControl
985282ba55 Debug 2019-03-20 18:03:24 +01:00
funkyfranky
8534afe0e3 AB 2019-03-20 16:22:00 +01:00
Frank
a70fa066fe AB 0995 2019-03-20 00:12:04 +01:00
FlightControl
3f8468dcc7 Fixed shortest distance to airbase. 2019-03-19 21:50:34 +01:00
FlightControl
d9d9235fba Great new additions:
- Defense tactics (SetDefenseApproach) now can be:
  AI_A2G_DISPATCHER.DefenseApproach.Random -- random detected item
  AI_A2G_DISPATCHER.DefenseApproach.Distance -- shortest distance between defense point and detected item.
2019-03-19 19:34:28 +01:00
funkyfranky
5e20b244c5 AB 0995w 2019-03-19 16:32:43 +01:00
Frank
40ebc4e990 AB v0.9.9.5 2019-03-19 01:18:34 +01:00
FlightControl
70e7857b62 Implemented the linking of TASK_CAPTURE_DISPATCHER and AI_A2G_DISPATCHER. 2019-03-18 19:53:12 +01:00
FlightControl
02a486e457 In progress. 2019-03-18 18:04:08 +01:00
FlightControl
9e09a5bac9 First version of new Feature-Detection-Zones 2019-03-17 08:26:16 +01:00
FlightControl
ece7fc3ea9 Threat level report for TASK_CAPTURE_ZONE 2019-03-17 08:20:42 +01:00
FlightControl
0ea5c7fa48 Updated bug in Detection and other classes. Now only alive units are considered when broadcasting a message to a SET_GROUP. Made DESIGNATE crash in certain cases. 2019-03-17 07:33:28 +01:00
Frank
3f64a1b33f Merge pull request #1130 from FlightControl-Master/FF/Develop
AIRBOSS v0.9.9.4
2019-03-16 22:38:23 +01:00
Frank
02ee12402a AIRBOSS v0.9.9.4
**AIRBOSS v0.9.9.4**
- Script now supports human RIOs.
- Added optional prefix for trap sheet files.
- Fixed invalid characters in trap sheet file name cause script to crash (untested). Data will not be saved at all.
- Inverted sign of line up error in trap sheet data to make it more intuetive.
- Player who leave are deleted from self.players table.
2019-03-16 22:34:03 +01:00
FlightControl
837361e899 Updates 2019-03-16 12:57:14 +01:00
FlightControl
cff4f60923 Improvements on reporting. 2019-03-16 12:13:39 +01:00
FlightControl
fb23ac1d55 Updates to make the tasking work correctly. 2019-03-16 09:51:09 +01:00
FlightControl
87a44f7f7f Still need to fix that index issue. 2019-03-15 13:08:48 +01:00
FlightControl
3b520ab0c4 New detection method based on zones and scanning. 2019-03-15 12:39:06 +01:00
FlightControl
044b5cba7c Updates 2019-03-15 11:01:06 +01:00
FlightControl
0f9591464a First version 2019-03-15 09:57:50 +01:00
Frank
6a301060bf Merge pull request #1129 from FlightControl-Master/FF/Develop
AIRBOSS v0.9.9.3
2019-03-13 20:56:46 +01:00
Frank
1e0b51a0a9 AIRBOSS v0.9.9.3
- Added F-14 support.
2019-03-13 20:52:57 +01:00
FlightControl
e19f0402da Only auto assign tasks to planned; replanned or assigned tasks. 2019-03-10 16:48:38 +01:00
FlightControl
925ce3ad63 Auto assignment of tasks with prioritization of an auto assign method. The default assign method is random, which is set at the command center. Each task type implements a prioritization mechanism which calculates the priotity of the task based on various methods: random, distance or priority. The distance is calculated from the task coordinate from the command center location.
Also fixed in a first try the route bug on Controllables.
2019-03-10 16:41:53 +01:00
FlightControl
afc918c5e5 Updates in defense system. Added SetSquadronEngageProbability method to decide per squadron what is the probability when it will engage. 2019-03-09 17:29:18 +01:00
FlightControl
10b96f6cce Updates to decision engine of the AI_A2G_DISPATCHER 2019-03-09 10:09:03 +01:00
FlightControl
d72e89d52b Fixes in AI_A2G_DISPATCHER 2019-03-09 06:32:11 +01:00
FlightControl
ef1a9330a4 Updates, many fixes. Now also the communication to the players is working. 2019-03-08 10:03:58 +01:00
FlightControl
eee1aca14f Disabled SetSquadronVisible due to a bug fix that is required. 2019-03-07 14:02:49 +01:00
FlightControl
c8c95e063d Now the task routing is also working towards the capture zones. 2019-03-07 09:54:33 +01:00
FlightControl
0af9e57b82 Now the task routing is also working towards the capture zones. 2019-03-07 09:54:15 +01:00
FlightControl
e0899a8a9d Merge remote-tracking branch 'origin/develop' into develop 2019-03-06 22:41:38 +01:00
FlightControl
093dadc0f6 Finish Task_zone_capture_dispatcher 2019-03-06 22:40:59 +01:00
FlightControl
23f92e49dd New TASK CAPTURE DISPATCHER class.
This class allows to send capture tasks to players.
It needs a ZONE_CAPTURE_COALITION class to function.
2019-03-06 22:40:44 +01:00
Frank
d1c909e9ed Merge pull request #1128 from FlightControl-Master/FF/Develop
RAT v2.3.7
2019-03-05 23:24:26 +01:00
Frank
5dbc3b1ba1 Update RAT.lua 2019-03-05 23:09:43 +01:00
Frank
85febea3d9 RAT v2.3.7
Added EPLRS datalink option.
2019-03-05 23:07:35 +01:00
FlightControl
dca772cac6 Automatic assignment of tasks; and automatic accepts of tasks. Documented. Tested. Works. 2019-03-05 09:56:51 +01:00
FlightControl
26347ce779 Automatic assignment of tasks; and automatic accepts of tasks. Documented. Tested. Works. 2019-03-05 09:56:19 +01:00
Frank
b49f3c5b0c Merge pull request #1126 from FlightControl-Master/FF/Develop
Carrier Ops Update
2019-03-04 23:18:09 +01:00
Frank
79be7cbd2c Update Airboss.lua 2019-03-04 23:08:59 +01:00
FlightControl
6fe8667885 Some important fixes that improves the routing of the engagements of aircraft. when ground forces move, the aircraft engaging will approach correctly.
also added the squaddrons with resources in the tactical information panel.
and for patrols, now the amount of resources are correctly calculated.
2019-03-04 20:27:40 +01:00
Frank
b56d62c777 Carrier Ops Update
AIRBOSS v0.9.9.2
RECOVERYTANKER v1.0.7
2019-03-04 17:50:45 +01:00
FlightControl
6f13aa2c5b These changes will blast the hell out of A2G... this is going to be great. 2019-03-03 19:46:51 +01:00
Frank
d4510af249 Merge pull request #1125 from FlightControl-Master/FF/Develop
AIRBOSS v0.9.9.1
2019-02-28 23:15:12 +01:00
Frank
fb784a9a96 AIRBOSS v0.9.9.1 2019-02-28 23:06:03 +01:00
Frank
25c7b1ddac AIRBOSS v0.9.9.1 2019-02-28 22:38:17 +01:00
Frank
71c7e15fc3 Update Airboss.lua 2019-02-27 23:32:46 +01:00
funkyfranky
e6e0cf5977 AB 0991 2019-02-27 16:33:24 +01:00
funkyfranky
775757e657 AB Docs 2019-02-26 16:58:57 +01:00
Frank
1a303ec7c2 Merge pull request #1123 from FlightControl-Master/FF/Develop
AIRBOSS v0.9.9
2019-02-25 20:34:16 +01:00
Frank
c16edd65b0 AIRBOSS v0.9.9 2019-02-25 20:23:03 +01:00
FlightControl
1ff41ec7ec Improvements 2019-02-25 19:16:18 +01:00
FlightControl
d874456361 Optimized attack. Prevent airborne defenders to fly over enemy zones to target areas behind enemy lines! This is an important feature. I still need to optimize the attack for SEAD; so when SEAD is behind enemy lines and crossing an enemy area that is in line of the attack; the SEAD won't be engaged. Further optimization is required, but it works already quite well! 2019-02-23 14:57:06 +01:00
Frank
6853eecffa Merge pull request #1122 from FlightControl-Master/FF/Develop
AIRBOSS v0.9.8
2019-02-21 10:20:59 +01:00
Frank
71001adc5e AIRBOSS v0.9.8 2019-02-21 09:55:57 +01:00
Frank
b6a19d34c6 AIRBOSS v0.9.8 2019-02-20 09:41:16 +01:00
FlightControl
1364115b07 Updates in docs 2019-02-19 17:48:57 +01:00
Frank
48c7254c84 Update Airboss.lua 2019-02-19 10:41:58 +01:00
Frank
60b6d2ade0 Update Airboss.lua 2019-02-17 23:16:07 +01:00
funkyfranky
df43ff0841 AB v0.9.8w 2019-02-15 17:00:22 +01:00
Frank
5ee0ae44cd Update Airboss.lua 2019-02-15 01:23:42 +01:00
funkyfranky
9df35840fe AB v0.9.8w 2019-02-14 16:54:59 +01:00
Frank
cff9557217 AB v0.9.8 wip 2019-02-14 00:53:22 +01:00
funkyfranky
b5b6d398ae AB 0.9.8w 2019-02-13 16:46:15 +01:00
Frank
aba0c19215 AB v0.9.8wip 2019-02-13 00:15:31 +01:00
funkyfranky
5050371e0d AB v0.9.8w 2019-02-12 16:26:44 +01:00
Frank
81b36ef37d Merge pull request #1121 from FlightControl-Master/FF/Develop
AIBOSS v0.9.7
2019-02-11 13:57:48 +01:00
Frank
59e219e3d6 WAREHOUSE v0.6.9
Fixed memory issue.
2019-02-11 12:31:28 +01:00
Frank
412d9e7a82 AIRBOSS v0.9.7 2019-02-11 12:24:52 +01:00
funkyfranky
d01b55c790 AB v0.9.7w 2019-02-08 16:41:23 +01:00
Frank
5ed768065c Update Airboss.lua 2019-02-08 01:04:07 +01:00
funkyfranky
e64703de03 AB v0.96w 2019-02-07 16:16:17 +01:00
Frank
71126eb34d AIRBOSS v0.96 2019-02-06 23:50:41 +01:00
funkyfranky
6992e47a66 AB 0.95wip 2019-02-06 16:16:29 +01:00
Frank
70d1f96681 AB v0.95wip 2019-02-06 00:12:24 +01:00
funkyfranky
83ed456c29 AB 0.9.5wip 2019-02-05 16:41:20 +01:00
Frank
26607776a2 Merge pull request #1120 from FlightControl-Master/FF/Develop
AIRBOSS v0.95
2019-02-04 23:21:24 +01:00
Frank
7a075e73ca AIRBOSS v0.95
- Fixed bug in counting units
- Carrier will only turn into the wind if wind > 0.1 m/s
2019-02-04 23:15:12 +01:00
Frank
6c15091df2 Merge pull request #1119 from FlightControl-Master/FF/Develop
AIRBOSS v0.9.4
2019-02-04 20:37:32 +01:00
Frank
e063379cd8 AIRBOSS v0.9.4
- Added AV-8B and USS Tarawa.
- Corrected A-4E AoA threshold.
- Other minor adjustments.

RADIO: Fixed frequency check.
2019-02-04 20:34:45 +01:00
Frank
3a49f2258b Merge pull request #1118 from FlightControl-Master/FF/Develop
AIRBOSS v0.9.3
2019-01-31 21:55:42 +01:00
Frank
dddf056b20 AIRBOSS v0.9.3
- Added tower frequency.
- Added AI exclude set.
2019-01-31 21:54:44 +01:00
Frank
bdbfed13ff Merge pull request #1114 from 131stGutts/Functional-PseudoATC_Allow_Human_Group
Fix bug when 2 humans are in the same group of planes
2019-01-31 19:15:45 +01:00
Frank
9eb0800b66 Merge pull request #1113 from 131stGutts/Functional-ATC_Ground_AlertFreqCustom_PersianGulf
Functional atc ground alert freq custom persian gulf
2019-01-31 18:26:21 +01:00
Frank
713ec61031 Merge branch 'develop' into Functional-ATC_Ground_AlertFreqCustom_PersianGulf 2019-01-31 18:25:25 +01:00
Frank
264e84649e Merge pull request #1112 from FlightControl-Master/FF/Develop
Carrier Ops
2019-01-31 14:21:49 +01:00
Frank
c4016cfa4d RESCUEHELO v1.0.5
- Added Returned event.
- Fixed automatic RTB on low fuel bug.
2019-01-31 13:43:17 +01:00
Frank
1cb248692b CONTROLLABLE
Setting output of SetTask from self:I() to self:T(). AI_FORMATION class (used by RESCUEHELO) calls the function twice per second and is spamming the DCS log file with messages and causing large file I/O.
2019-01-30 20:18:47 +01:00
Frank
331315a83e Merge branch 'develop' into FF/Develop 2019-01-30 20:11:11 +01:00
Frank
e325b2192b AIRBOSS, RECOVERYTANKER, RESCUEHELO, RANGE
AIRBOSS v0.9.3
RECOVERYTANKER v1.0.6
RESCUEHELO v1.0.4
RANGE v1.2.4
SPAWN added modex
GROUP added modex respawn
2019-01-30 20:10:41 +01:00
FlightControl
86094bc6d2 Improvements in the attack methods! This is going to be great!
# Conflicts:
#	Moose Development/Moose/AI/AI_A2G_Dispatcher.lua
2019-01-29 20:51:03 +01:00
FlightControl
f2b2b1974d Improvements in the attack methods! This is going to be great! 2019-01-29 19:58:06 +01:00
Frank
080c496cc3 Merge pull request #1111 from FlightControl-Master/FF/Develop
RECOVERYTANKER v1.0.5
2019-01-29 17:11:58 +01:00
Frank
bcfa0f9ac5 RECOVERYTANKER v1.0.5
Recoverytanker:
- Added AWACS roll
- Added function to set callsign

UTILS
- Added callsigns enumerator

CONTROLLABLE
- Added command SetCallsign
2019-01-29 17:07:48 +01:00
Frank
746c0d25f7 Merge pull request #1110 from FlightControl-Master/FF/Develop
RECOVERYTANKER v1.0.4
2019-01-28 22:07:30 +01:00
Frank
9e450ce76b RECOVERYTANKER v1.0.4
- Fixed PG airbase enumerator names
- Rescuehelo v1.0.3
- minor stuff
2019-01-28 22:03:21 +01:00
FlightControl
77bee89ea5 Updates 2019-01-27 17:19:41 +01:00
Frank
dbc80183e6 Merge pull request #1109 from FlightControl-Master/FF/Develop
CONTROLLABLE
2019-01-27 13:09:33 +01:00
Frank
ff0371faa5 CONTROLLABLE
Fixed task bombing runway.
2019-01-27 13:07:48 +01:00
Frank
ebaddb3fe4 Merge pull request #1107 from FlightControl-Master/FF/Develop
AIRBOSS v0.9.2
2019-01-26 23:30:29 +01:00
Frank
8f3aeeb182 AIRBOSS v0.92 2019-01-26 23:12:24 +01:00
Frank
3157e4f986 Merge branch 'develop' into FF/Develop 2019-01-23 11:24:31 +01:00
Frank
0fe18ee5b4 Merge pull request #1104 from FlightControl-Master/FF/Develop
AIRBOSS v0.9.1
2019-01-23 11:09:11 +01:00
Frank
265d6da331 AIRBOSS v0.9.1 2019-01-23 11:00:36 +01:00
FlightControl
1c063ca308 Optimizations 2019-01-22 08:51:17 +01:00
FlightControl
5a5340431e Improvements ...
-- Implementation of queueing of aircraft launches.
-- Fixed the RTB bug resulting in "lost control".
-- Communication of AI to players (first version).
-- Aircraft engage distance calculation for each wave.
2019-01-20 17:03:18 +01:00
Frank
869a8a57e1 Merge pull request #1103 from FlightControl-Master/FF/Develop
AIRBOSS v0.9.0 and other fixes/improvements
2019-01-20 02:33:05 +01:00
Frank
dd15da28b2 AIBOSS v0.9.0
SPAWN: Added delay for respawn on landing.
RAT v2.3.5: Fixed bug for Vmax cruise.
RECOVERYTANKER v1.0.3
RESCUEHELO v1.0.2
POSITIONABLE: Added GetOffsetCoordinate function
UNIT: Added Explode function.
2019-01-20 02:02:22 +01:00
131stGutts
47778c6fe7 Set the time frequency of alert with PersianGulf
Add new functions "Start" for
  ATC_GROUND_CAUCASUS,
  ATC_GROUND_NEVADA,
  ATC_GROUND_NORMANDY,
  ATC_GROUND_PERSIANGULF

 which accept none or one parameter for setting the SCHEDULER frequency.

If none defined, value set before (0.05) is used.
The SCHEDULER is not anymore in "New" functions of ATC_GROUND_XXX but in "Start"

Usages:
atcGroundCaucasus=ATC_GROUND_CAUCASUS:New()
atcGroundCausasus:Start()

or

atcGroundCaucasus=ATC_GROUND_CAUCASUS:New()
atcGroundCausasus:Start(0.5)

Relative to PullRequest #1094, #1096, #1098
Include grammar issues fix from ticket #753
2019-01-13 16:27:58 +01:00
131stGutts
0d90eed270 Implements PersianGulf ATC_Ground supervisor
All Persian Gulf airbases and runways added so ATC_Ground supervisor
Minor correction to comment for Normandy (saying Caucasus)
2019-01-13 12:45:21 +01:00
Frank
d8147348c6 Merge pull request #1097 from FlightControl-Master/FF/Develop
AIRBOSS v0.8.1
2019-01-13 00:28:42 +01:00
Frank
6b85141a39 AIRBOSS v0.8.1
* Persistence
* Fixed menu mark zones bug
* minor things
2019-01-13 00:23:27 +01:00
131stGutts
0fcc379ede Fix bug when 2 humans are in the same group of planes
If more than one human is in a plane's group, the menu bug and a lot of PSEUDOATC menu are shown.
The new menu structure is:
- F10
-  PSEUDOATC
-   <PlayerName>
-    <PSEUDOATC Functions>

For achieving that goal, the self structure has changed from self.player[GID] to self.group[GID].player[UID]. Doing that way, if the last player pit leave the group this functionality do not generate a nil error anymore.
Some text have been changed to indicate CallSign or PlayerName.
2019-01-12 21:35:05 +01:00
Frank
f22f62339f Merge pull request #1092 from FlightControl-Master/FF/Develop
AIRBOSS v0.8.0
2019-01-10 17:50:19 +01:00
Frank
934b9d9cf1 Merge branch 'develop' into FF/Develop 2019-01-10 17:26:57 +01:00
Frank
47dd068655 AIRBOSS v0.8.0 2019-01-10 17:26:37 +01:00
FlightControl
382dfd797c Optimizations A2G 2019-01-09 21:31:22 +01:00
FlightControl
8e66031afe Optimizations A2G 2019-01-09 21:30:21 +01:00
FlightControl
eea1d56468 Optimizations A2G 2019-01-09 21:29:45 +01:00
FlightControl
6edcc58b9a updates 2019-01-09 07:36:36 +01:00
Frank
7a8197208c Merge pull request #1087 from FlightControl-Master/FF/Develop
AIRBOSS v0.7.2
2019-01-05 10:33:23 +01:00
Frank
acd6e0f423 AIRBOSS v0.7.2 2019-01-05 09:51:19 +01:00
Frank
e741e0d1d6 Merge pull request #1085 from FlightControl-Master/FF/Develop
AIRBOSS v0.7.1
2019-01-04 00:25:39 +01:00
Frank
09f28a555f AIRBOSS v0.7.1
* Fixed radio transmission subtitle bug.
* Added on-the-fly LSO grading to attitude monitor.
* Added doc menu images.
2019-01-04 00:22:42 +01:00
Frank
a9590561d2 Merge pull request #1084 from FlightControl-Master/FF/Develop
Controllable SetTask debug output
2019-01-03 15:32:10 +01:00
Frank
9700776468 Controllable log output
Controllable, changed self:E to self:F/T2 since it was spamming the DCS log.
Airboss docs.
Spawn scheduler(self,...) --> scheduler(nil,...)
2019-01-03 14:09:19 +01:00
Frank
cec6940aeb Merge pull request #1083 from FlightControl-Master/FF/Develop
AIRBOSS v0.7.0
2019-01-03 01:05:24 +01:00
Frank
e082ee17e4 Merge branch 'develop' into FF/Develop 2019-01-03 00:30:27 +01:00
Frank
2327fa7e4b AIRBOSS v0.7.0
RECOVERYTANKER v1.0.1
RESCUEHELO v1.0.1
2019-01-03 00:30:03 +01:00
FlightControl
bd25a8ccb4 Fixing too small static Moose.lua 2018-12-29 23:49:52 +01:00
FlightControl
fff0c8ccd3 New dynamic loader and adapted Moose.lua creation from Modules.lua in the MOOSE root directory. 2018-12-28 09:30:49 +01:00
FlightControl
df6a10862e New dynamic loader and adapted Moose.lua creation from Modules.lua in the MOOSE root directory. 2018-12-28 09:29:33 +01:00
FlightControl
a33b7b2769 Merged 'develop'. 2018-12-27 07:34:29 +01:00
FlightControl
5e01db8809 New stuff 2018-12-27 07:33:51 +01:00
FlightControl
32c064a1be Remove Moose.lua 2018-12-26 09:10:03 +01:00
FlightControl
610938b6e8 Changes 2018-12-26 09:06:16 +01:00
FlightControl
ea93e3863b Loader 2018-12-26 07:42:47 +01:00
Frank
ab38efd69e Merge pull request #1077 from FlightControl-Master/FF/Develop
New classes, fixes and improvements.
2018-12-26 04:50:56 +01:00
Frank
8dc5642599 AIBOSS v0.6.3
Recovery Tanker v1.0.0
Rescue Helo v1.0.0
Fixed spawn after engine shutdown bug.
Added new PG airbases.
2018-12-25 18:55:35 +01:00
Frank
d8c5ab7eae AIRBOSS v0.6.2 2018-12-23 01:30:33 +01:00
Frank
49e7a24e28 AIRBOSS v0.6.1
Lineup, glide slope fixes.
2018-12-22 15:55:43 +01:00
Frank
6f2de65b64 AIRBOSS v0.6.0 2018-12-22 09:27:51 +01:00
funkyfranky
34603d69ab AIRBOSS v0.5.9w 2018-12-21 16:17:42 +01:00
Frank
afb79391dd AIRBOSS v0.5.9 2018-12-21 00:34:25 +01:00
funkyfranky
7f1dcf93d9 AIRBOSS v0.58w 2018-12-20 16:16:29 +01:00
Frank
04722a7d83 AIRBOSS v0.5.8 2018-12-20 00:49:41 +01:00
funkyfranky
fd6a319928 AIRBOSS v0.5.7w 2018-12-19 17:02:58 +01:00
FlightControl
e91a744bd9 Fixed for A2G. Default parameters and proper amount of spawnings. Now also altitude is added for engage. And RTB has min and max speed set. Defaults of speed between 50% and 75% of maximum speed of group. And altitude defaults to 1000 and 1500 meters. 2018-12-19 07:24:01 +01:00
Frank
876b369c0d AIRBOSS v0.5.7 2018-12-19 00:40:42 +01:00
Frank
75ac76a8e5 AIBOSS v0.5.6
RESCUEHELO v0.9.9
2018-12-18 14:04:31 +01:00
FlightControl
6c4bde4ceb Fixes 2018-12-17 20:59:58 +01:00
FlightControl
cfc9c655c5 Fixes for patrol. 2018-12-17 19:39:23 +01:00
Frank
d576573cf8 RECOVERYTANKER v0.9.9
RESCUEHELO v0.9.8
2018-12-16 16:59:53 +01:00
Frank
1559f14f11 RESCUEHELO v0.9.7
- Fixed spawn bug with multiple helos.
- Adjusted default parameters.
- Changed RTB to respawn (not perfect).
- Improved documentation.
2018-12-15 23:06:36 +01:00
Frank
242151eedf AIBOSS v0.5.5 2018-12-15 08:47:01 +01:00
funkyfranky
7cf10e90f8 AIRBOSS 0.5.4w 2018-12-14 16:44:00 +01:00
Frank
5201c73d35 AIRBOSS v0.5.4 2018-12-14 00:17:11 +01:00
funkyfranky
07f313a4a6 AIRBOSS v0.5.3w 2018-12-13 16:08:59 +01:00
Frank
fa08434690 AIRBOSS v0.5.3 2018-12-12 23:38:48 +01:00
funkyfranky
8969c58ca5 AIRBOS v0.5.2w 2018-12-12 16:03:37 +01:00
FlightControl
810cebfe0a Optimizations 2018-12-12 07:31:08 +01:00
Frank
d607b96021 AIRBOSS v0.5.2 2018-12-12 00:50:42 +01:00
FlightControl
d098930351 -- New SEAD, BAI and CAS files.
-- Correct handling of task assignments.
-- Added Weapon stuff in DCS.lua.
-- Dispatcher optimizations.
2018-12-11 19:20:11 +01:00
funkyfranky
143e729a5e AIRBOSS v0.5.1w 2018-12-11 16:02:45 +01:00
Frank
5ef4b593a2 AIRBOSS v0.5.1 2018-12-11 00:19:14 +01:00
funkyfranky
7eb98c05eb AIRBOSS v0.5.0w 2018-12-10 16:59:00 +01:00
Frank
43ec58fe85 RT & RH
Recovery Tanker
Rescue Helo
2018-12-09 23:11:44 +01:00
Frank
0a5f042555 Merge branch 'FF/Development' into FF/Develop 2018-12-09 21:25:47 +01:00
Frank
44f8c2a933 WAREHOUSE v0.6.7
SPAWNSTATIC
UNIT
2018-12-09 21:16:47 +01:00
Frank
ecbdbedd96 Warehouse v0.6.6
Again
2018-12-09 19:32:39 +01:00
Frank
c6a4e4c533 Warehouse v0.6.6
Again
2018-12-09 19:32:07 +01:00
Frank
afb0a8af33 Manual diff merge from FF/Development
Hopefully cleans up the mess now.
2018-12-09 19:11:46 +01:00
Frank
8d222fd0c3 Merge branch 'FF/Development' into FF/Develop 2018-12-09 12:12:32 +01:00
Frank
9795d5655f Improvements and Fixes from FF/Develop 2018-12-09 12:01:15 +01:00
Frank
db6c7f1a2c AIROSS v0.5.0 2018-12-09 01:06:01 +01:00
funkyfranky
cfdce853a3 AIRBOSS w 2018-12-07 15:36:41 +01:00
Frank
01b2f238c5 AIRBOSS v0.4.9
RECOVERYTANKER v0.9.7
2018-12-06 23:36:37 +01:00
funkyfranky
5a327b1d6b AIRBOSS v0.4.8w 2018-12-06 16:10:17 +01:00
Frank
96b60d8ac0 AIRBOSS v0.4.8 2018-12-06 00:05:41 +01:00
Frank
e7f1d98b64 AIRBOSS v0.4.7 2018-12-05 23:58:37 +01:00
Frank
c2ddf17aa2 AIRBOS v0.4.6 2018-12-05 23:35:03 +01:00
funkyfranky
302d9dfad4 AIRBOSS v0.4.5w 2018-12-05 15:57:26 +01:00
Frank
a83008aad3 AIRBOSS v0.4.5 2018-12-04 23:37:56 +01:00
funkyfranky
047df5917a AIRBOSS v0.4.4w 2018-12-04 16:05:15 +01:00
funkyfranky
6b53e9f9a8 Merge branch 'FF/Develop' of https://github.com/FlightControl-Master/MOOSE into FF/Develop 2018-12-04 11:37:14 +01:00
funkyfranky
d66028a1b9 AIRBOSS v0.4.3w 2018-12-04 11:37:07 +01:00
Frank
51de6756a7 AIRBOSS update 2018-12-03 23:07:08 +01:00
Frank
74d97cc220 AIRBOSS v0.4.3 2018-12-02 23:48:39 +01:00
Frank
cf2ad6f277 AIRBOSS v0.4.2 2018-12-02 00:30:22 +01:00
Frank
b05d3fbde2 AIRBOSS v0.4.1 2018-11-30 23:48:59 +01:00
funkyfranky
7b0db24e00 AIRBOSS v0.4.0w 2018-11-30 16:02:53 +01:00
Frank
21f0094d7c AIRBOSS v0.4.0 2018-11-29 23:41:57 +01:00
funkyfranky
99c2e76e53 AIRBOSS v0.3.9w 2018-11-29 16:19:19 +01:00
Frank
50c40cb4e9 AIRBOSS v0.3.9 2018-11-28 23:55:14 +01:00
funkyfranky
5e8b461478 AIRBOSS v0.3.6w 2018-11-28 17:17:05 +01:00
funkyfranky
73db4b365b Merge branch 'FF/Develop' of https://github.com/FlightControl-Master/MOOSE into FF/Develop 2018-11-28 11:52:06 +01:00
funkyfranky
0cf5bee09a Pics 2018-11-28 11:52:02 +01:00
Frank
3d54d78be8 AIRBOSS v0.3.7
Zones.
2018-11-27 23:37:48 +01:00
Frank
bd537ece00 Revert "Merge branch 'develop' into FF/Develop"
This reverts commit 1f282693b3, reversing
changes made to e16f306e1d.
2018-11-27 18:38:21 +01:00
Frank
1f282693b3 Merge branch 'develop' into FF/Develop 2018-11-27 18:13:58 +01:00
Frank
e16f306e1d AIRBOSS v0.3.6 2018-11-27 00:03:45 +01:00
funkyfranky
6b24673b6f AIRBOSS v0.3.5w 2018-11-26 16:35:35 +01:00
Frank
58886dc42d AIRBOSS v0.3.5 2018-11-26 00:43:38 +01:00
Frank
8cea501748 RESCUEHELO v0.9.4 2018-11-25 11:10:11 +01:00
Frank
c5171e8722 RECOVERYTANKER v0.9.4 2018-11-25 00:05:31 +01:00
Frank
5af235a345 AIRBOSS v0.3.4 2018-11-23 23:57:54 +01:00
funkyfranky
8133ef2036 AIRBOSS v0.3.3w 2018-11-23 16:30:32 +01:00
Frank
9269e1e943 AIBOSS v0.3.3
little bug fixes
2018-11-22 23:27:43 +01:00
funkyfranky
b4c82d0aac docs 2018-11-22 16:12:00 +01:00
Frank
39ffc28cb4 AIRBOSS v0.3.2 2018-11-21 23:45:24 +01:00
funkyfranky
e23488a723 AIRBOSS v0.3.1w 2018-11-21 16:01:10 +01:00
Frank
ba1cb61f4d AIRBOSS v0.3.1
Tanker v0.9.3
* added TACAN option

Helo v0.9.3
* added respawn and uncontrolled
2018-11-21 00:55:00 +01:00
FlightControl
921ec8732c A lot of optimizations ...
- Depart from runway now works again.
 - Depart from hotspot works again.
 - Depart from ramp works again.
 - Implemented the limit, it works, but it is not waterproof (yet).
2018-11-20 20:00:38 +01:00
Frank
51a1f56011 AIRBOSS v0.3.0
RESCUEHELO v0.9.2
RECOVERYTANKER v0.9.2
2018-11-20 00:15:39 +01:00
Frank
2feb293c12 AIRBOSS v0.2.9
- Added holding check (WIP)
- Many improvents and fixes.
2018-11-18 23:57:41 +01:00
Frank
9d9f233c15 AIRBOSS v0.2.8
good commit, improved and fixed a lot of stuff.
2018-11-18 00:45:18 +01:00
funkyfranky
9ad948632c AIRBOSS v0.2.7w 2018-11-16 16:24:01 +01:00
Frank
9b40ebe00c AIRBOSS v0.2.7 2018-11-15 23:16:58 +01:00
funkyfranky
dab3ed5fbe AIRBOSS v0.2.6w 2018-11-15 16:11:14 +01:00
Frank
34d7b18c26 AIRBOSS v0.2.6 2018-11-14 23:23:46 +01:00
FlightControl
dc4115d4e3 Finish 2.4.14 2018-11-14 20:09:35 +01:00
FlightControl
5cfd0aac1c Finish 2.4.14 2018-11-14 20:09:35 +01:00
FlightControl
9481cbf7e8 Fixing issue #1054 related to ZONE_CAPTURE_COALITION going into Attacked state when the zone is attacked, meaning, when a unit is hit that is in the zone. 2018-11-14 20:01:29 +01:00
FlightControl
748f9b52aa Finish 2.4.13 2018-11-14 19:22:23 +01:00
FlightControl
c5ce3342e2 Finish 2.4.13 2018-11-14 19:22:22 +01:00
FlightControl
6c4ca046a9 Fixed problem with DESIGNATE:SetFlashStatusMenu() documentation. 2018-11-14 19:22:10 +01:00
FlightControl
256697c39e Fixing problem in SET_BASE:FindNearestObjectFromPointVec2( PointVec2 ). 2018-11-14 18:58:44 +01:00
FlightControl
4017876fe2 Fixing problem in SET_BASE:FindNearestObjectFromPointVec2( PointVec2 ). 2018-11-14 18:58:43 +01:00
FlightControl
9651614894 Fixing problem in SET_BASE:FindNearestObjectFromPointVec2( PointVec2 ). 2018-11-14 18:58:08 +01:00
funkyfranky
3bc2baaf9d AIRBOSS v0.2.5w 2018-11-14 16:11:54 +01:00
Frank
fa05352882 AIRBOSS v0.2.5 2018-11-13 23:39:29 +01:00
FlightControl
849ca24ac8 Finish Feature-AI-A2G-Dispatcher 2018-11-13 20:21:00 +01:00
FlightControl
84e9d225e9 Fixing problem with squadron not found for CAS tasking. 2018-11-13 20:20:42 +01:00
funkyfranky
7b53a43c5c AB v0.2.4 2018-11-13 16:24:08 +01:00
Frank
e3121781d0 AIRBOSS v0.2.4 2018-11-13 00:00:20 +01:00
FlightControl
2c788b1b38 Finish 2.4.11 2018-11-12 19:38:49 +01:00
FlightControl
369606f0f1 Finish 2.4.11 2018-11-12 19:38:48 +01:00
FlightControl
8d4ce5e486 Fixing autolase problem... now the duration is fixed.
I think I also fixed the lase duration problem ...
2018-11-12 19:38:22 +01:00
FlightControl
1b691e5887 Documentation 2018-11-12 19:35:32 +01:00
Frank
2d7d19880f AIRBOSS v0.2.3
group fixed init heading
2018-11-11 23:55:19 +01:00
FlightControl
8b06af01b0 More documentation for A2G dispatcher. 2018-11-11 21:51:11 +01:00
FlightControl
ea3899f469 More documentation for A2G dispatcher. 2018-11-11 21:50:41 +01:00
FlightControl
adb8b6cbca Fixed overhead (again), and optimized defense radius logic. 2018-11-11 08:43:39 +01:00
FlightControl
252950af73 Fixed overhead (again), and optimized defense radius logic. 2018-11-11 08:43:20 +01:00
FlightControl
14189e1bca Images 2018-11-11 07:31:13 +01:00
FlightControl
ed60c5dca4 Images 2018-11-11 07:25:47 +01:00
FlightControl
c4984a7576 Doc update 2018-11-11 07:22:22 +01:00
FlightControl
6a1052d95f Introduction documentation of A2G dispatching. 2018-11-10 16:30:31 +01:00
FlightControl
caa3bcb02b Introduction documentation of A2G dispatching. 2018-11-10 16:30:00 +01:00
FlightControl
74123d8ff3 Fixed overhead bug in dispatchiing from ground. 2018-11-10 13:21:46 +01:00
FlightControl
70b858d200 - Optimized the overhead problem in case of engage from patrol.
- Change in defense reactivity and distance calculations.
- Select correct template to engage is working now also.
2018-11-10 12:44:13 +01:00
FlightControl
3ca712a223 Optimized the overhead problem in case of engage from patrol. 2018-11-10 12:42:16 +01:00
Frank
cf4be99093 AB v0.2.2 2018-11-10 00:57:14 +01:00
FlightControl
900a55614b Change in defense reactivity and distance calculations. 2018-11-09 17:00:40 +01:00
FlightControl
f76b0dc7d3 Select correct template to engage is working now also. 2018-11-09 16:47:06 +01:00
funkyfranky
4542c96eae AB v0.2.1w 2018-11-09 16:07:30 +01:00
FlightControl
dd242bc1fe Finish 2.4.10 2018-11-09 07:44:37 +01:00
FlightControl
456a38022f Finish 2.4.10 2018-11-09 07:44:37 +01:00
FlightControl
34d73af8bf Changed the default lase duration for designations to 120 seconds. A new method has been added to change the lase duration yourself. Use SetLaseDuratioin API! 2018-11-09 07:44:11 +01:00
FlightControl
238b1cb925 Finish 2.4.9 2018-11-09 06:46:24 +01:00
FlightControl
604255bfba Finish 2.4.9 2018-11-09 06:46:23 +01:00
FlightControl
cfc0367c55 Fixing problems with A2A_GCI. 2018-11-09 06:45:34 +01:00
FlightControl
488804308b Undo my last stupid mistakes. 2018-11-09 06:27:16 +01:00
Frank
6fac8fe940 CT v0.2.1 2018-11-09 00:17:57 +01:00
funkyfranky
b53b1edd29 CT v0.2.0w 2018-11-08 16:04:51 +01:00
FlightControl
5a2bac9979 Got engage working from the air. Now I need to fix:
- Overhead
- Correct Defense Type assignment to engage.

# Conflicts:
#	Moose Development/Moose/AI/AI_A2G_Dispatcher.lua
#	Moose Setup/Moose.files
2018-11-08 07:44:50 +01:00
FlightControl
e7181c255b Got engage working from the air. Now I need to fix:
- Overhead
- Correct Defense Type assignment to engage.
2018-11-08 07:38:04 +01:00
Frank
ac074ca23d CT v0.2.0 2018-11-07 23:26:51 +01:00
funkyfranky
b21bb3d433 CT v0.1.9w 2018-11-07 16:08:13 +01:00
FlightControl
0e656c8520 Progress, patrolling works. Engagement not yet. 2018-11-07 07:24:45 +01:00
Frank
708ff794b0 CT v0.1.9 2018-11-07 00:37:49 +01:00
FlightControl
6e34f12ac8 Finish 2.4.8 2018-11-06 19:11:26 +01:00
FlightControl
f4a89d62e3 Finish 2.4.8 2018-11-06 19:11:25 +01:00
FlightControl
a36e39205b Further fixes and optimizations for the A2A dispatcher plane optimization. 2018-11-06 18:50:42 +01:00
funkyfranky
6d45c09ea2 CTv0.18w 2018-11-06 16:04:19 +01:00
Frank
9fac65f31f CT v0.1..8 2018-11-06 00:04:52 +01:00
FlightControl
3789674666 First version of AI_A2G_DISPATCHER ...
- Created a new AI_AIR class. AI_A2A and AI_A2G inherit from AI_AIR.
- Created a new AI_A2G_DISPATCHER class.
- Created a new AI_A2G_ENGAGE class, that implements the SEAD, CAS and BAI actions.
- The AI_A2G_DISPATCHER implements now:
  * SEAD, CAS and BAI attacks from airbases.
  * AddDefenseCoordinate() to set a defense coordinate.
  * RemoveDefenseCoordinate() to remove a defense coordinate.
  * SetDefenseReactivenessHigh() for high reactiveness.
  * SetDefenseReactivenessMedium() for medium reactiveness.
  * SetDefenseReactivenessLow() for low reactiveness.
  * Overhead for ground attacks.
  * Grouping for ground attacks.
  * Evaluates task type based on enemy group composition.

- Tested AI_A2A_DISPATCHER for backward compatibility.
- Implemented spawning of airplanes in AI_A2A_DISPATCHER:
  * SetSquadronVisible() method to make the squadron visible at the airport.
2018-11-05 21:52:31 +01:00
FlightControl
a22774b278 Fixing takeoff bug in air for dispatchers. 2018-11-05 21:44:47 +01:00
FlightControl
81bb8dd65f Reworking a confusion with the takeoff in air spawning. 2018-11-05 21:41:52 +01:00
FlightControl
9d3796b605 Changes 2018-11-05 21:26:47 +01:00
funkyfranky
ba4caf179a CTv0.1.7w 2018-11-05 16:18:15 +01:00
Frank
1febe765bf CT v0.1.7 2018-11-05 00:35:48 +01:00
Frank
087ac992a2 CT v0.1.6 2018-11-04 01:14:47 +01:00
FlightControl
3e3dfc83aa First Version of AI_A2G_DISPATCHER. There are lots of challenges here to overcome. One of the first one is the defense points. 2018-11-02 16:43:06 +01:00
funkyfranky
27bf6069d7 CT v0.1.5w 2018-11-02 16:07:40 +01:00
Frank
3153d196a2 CT v0.1.5 2018-11-02 00:29:50 +01:00
funkyfranky
8c320f729a CT v0.1.4w 2018-11-01 16:20:49 +01:00
Frank
c7fdc77ec8 CT v0.1.4
Added aircraft check.
Fixed problems with new player.
2018-11-01 00:09:58 +01:00
Frank
dfd20ced59 CT v0.1.3 2018-10-30 00:02:45 +01:00
funkyfranky
5f40feb1af CTv0.1.2w 2018-10-29 16:25:09 +01:00
Frank
ae754fe334 CT v0.1.2 2018-10-29 00:01:53 +01:00
Frank
e062db9411 Merge pull request #1050 from FlightControl-Master/FF/Develop
Several improvements and fixes.
2018-10-28 14:16:07 +01:00
Frank
023eae825d RCT 2018-10-28 13:16:32 +01:00
Frank
1a4baeafb6 Warehose v0.6.6
WAREHOUSE:
- Improved parking spot check for airbase ship.
AI_FORMATION:
- Added Stop option
CT:
- fixes
COORDINATE:
- Improved landing waypoint.
2018-10-28 13:15:38 +01:00
Frank
b754972490 Merge branch 'FF/Develop' of https://github.com/FlightControl-Master/MOOSE into FF/Develop 2018-10-26 18:55:41 +02:00
Frank
0c36e4e40d CT 2018-10-26 18:55:36 +02:00
funkyfranky
1f97495fdd CT,RAT,WH work 2018-10-26 16:04:02 +02:00
FlightControl
c164c0f9e3 Merge branch 'hotfix/2.4.8' into feature/Feature-AI-A2A-Dispatcher 2018-10-26 14:09:25 +02:00
FlightControl
f0b5ec1025 Fixed the out of fuel bug. 2018-10-26 12:08:48 +02:00
Frank
b72ea2d02c minor 2018-10-26 00:12:21 +02:00
Frank
238fcf1176 WAREHOUSE v0.6.5
* fixed bug for assignments
2018-10-24 23:13:56 +02:00
Frank
c354fecc6d Merge branch 'develop' into FF/Develop 2018-10-24 21:47:52 +02:00
Frank
4434d1da21 Fixes
AI_FORMATION:
* added stop possibility ad interval input
WAREHOUSE
* added autodefence assignment
UNIT:
* improved  InAir() check function
2018-10-24 21:32:07 +02:00
FlightControl
17ffc7cef9 Updates for visibility of squadrons before start. 2018-10-24 20:55:04 +02:00
Frank
006fd25e56 Merge pull request #1044 from cjbehm/bugfix/CONTROLLABLE-honor-GotPath
Honor the GotPath return value from COORDINATE
2018-10-24 15:20:18 +02:00
Chris
f2eafe0302 Honor the GotPath return value from COORDINATE
PathOnRoad is always defined, at least as an empty table.
Use the 3rd return value instead, which indicates whether
a road route was found
2018-10-24 00:17:26 -04:00
FlightControl
52069cc1d0 Respawning of existing visible resources at the airbases is working. 2018-10-24 00:18:02 +02:00
Frank
d9374f0389 Controllable
Added more general orbit task.
2018-10-23 23:35:25 +02:00
Frank
19520f9688 CT v0.1.0 2018-10-22 23:41:48 +02:00
FlightControl
1eda5af7df Visible before start, uncontrolled planes. 2018-10-22 07:06:24 +02:00
Frank
2ea8487e04 ARTY v1.0.7
Fixed bug when targets get removed because ARTY group is immobile and not declared as cargo.
CT fixes
2018-10-22 00:08:38 +02:00
FlightControl
b0885ada00 Fixing resuming task after refuelling. 2018-10-21 14:36:31 +02:00
FlightControl
1c6c0c4d81 Fixing resuming task after refuelling. 2018-10-21 14:36:05 +02:00
FlightControl
3011b0ac8e Merge branch 'develop' 2018-10-21 13:18:29 +02:00
FlightControl
e4334cccb3 Fixing back to the inclusion of inactive units. 2018-10-21 13:12:20 +02:00
Frank
645ca570a8 CT 0.0.9
many fixes
2018-10-20 12:20:35 +02:00
FlightControl
fd30da2f95 Merge branch 'develop' 2018-10-20 04:31:59 +02:00
FlightControl
b378ad2885 Fixing path calculation. Direct route when the length between the two coordinates is less than 2 km. 2018-10-20 04:26:45 +02:00
FlightControl
9c45031a33 Merge branch 'develop' 2018-10-19 17:01:11 +02:00
FlightControl
e4606b4d05 Fixing path calculation. Direct route when the length between the two coordinates is less than 1 km. 2018-10-19 17:00:43 +02:00
funkyfranky
07e690caf0 CT008 2018-10-19 15:09:26 +02:00
Frank
223de9d1aa Range 2018-10-18 22:51:51 +02:00
FlightControl
a22b9e925a Merge branch 'develop' 2018-10-18 20:25:35 +02:00
FlightControl
90e7688cea Optimized the boarding and unboarding of cargo. fixed bug when in defence of APC, cargo would not be loaded. The boarding and unboarding has become much more stable now. 2018-10-18 20:25:21 +02:00
FlightControl
9ecd48f523 Merge branch 'develop' 2018-10-18 20:11:49 +02:00
FlightControl
ce9d1837a7 Optimized the boarding and unboarding of cargo. fixed bug when in defence of APC, cargo would not be loaded. The boarding and unboarding has become much more stable now. 2018-10-18 20:11:31 +02:00
FlightControl
bbf83eca3e Merge branch 'develop' 2018-10-18 18:24:56 +02:00
FlightControl
65c28d6628 Optimized the boarding and unboarding of cargo. fixed bug when in defence of APC, cargo would not be loaded. The boarding and unboarding has become much more stable now. 2018-10-18 18:24:25 +02:00
funkyfranky
7d7c521bce CT007 2018-10-18 16:50:08 +02:00
FlightControl
f0ac7818b3 Optimized the boarding and unboarding of cargo. fixed bug when in defence of APC, cargo would not be loaded. The boarding and unboarding has become much more stable now. 2018-10-18 07:27:50 +02:00
FlightControl
07d666b030 Optimized the boarding and unboarding of cargo. fixed bug when in defence of APC, cargo would not be loaded. The boarding and unboarding has become much more stable now. 2018-10-18 07:27:09 +02:00
Frank
baaee9f92e Merge branch 'develop' into FF/Develop 2018-10-17 22:10:04 +02:00
Frank
3a9be7a890 CTA 0.0.6 2018-10-17 22:07:11 +02:00
Frank
3c1547bd6c Merge pull request #1033 from FlightControl-Master/FF/Develop
Warehouse v0.6.4
2018-10-17 21:59:57 +02:00
Frank
92bf8b59e6 CTR 2018-10-17 21:54:44 +02:00
Frank
4b39312c2c CT 2018-10-17 21:20:30 +02:00
Frank
ea767650ae Merge branch 'develop' into FF/Develop 2018-10-17 21:20:19 +02:00
Frank
e0afd19a94 Warehouse v0.6.4
- Added possibility to auto save assets on mission end.
- Minor bug fixes.
2018-10-17 21:17:45 +02:00
FlightControl
767bb58ac9 Merge branch 'develop' 2018-10-17 19:23:47 +02:00
FlightControl
8a78308dbc Improvements on the pickup. Avoid a template as part of a CarrierSet to be considered as a valid carrier for pickup. And improved the timing of the loading. 2018-10-17 19:21:35 +02:00
funkyfranky
d2db1e56cc WH 2018-10-17 16:00:22 +02:00
Frank
5f8ebbaf6a CCT 2018-10-17 00:28:08 +02:00
Frank
52758b6900 Merge pull request #1031 from FlightControl-Master/FF/Develop
Warehouse v0.6.3
2018-10-17 00:22:19 +02:00
Frank
3bb2405563 Merge branch 'develop' into FF/Develop 2018-10-17 00:17:44 +02:00
Frank
c6403325f5 Warehouse v0.6.3
Persistance of assets.
2018-10-17 00:17:25 +02:00
funkyfranky
e17b5356dd WH 2018-10-16 16:32:35 +02:00
Frank
d87cb41b75 Warehouse v0.6.2
added first version of save/load assets

PseudoATC
fixed bearing info
other bugs reported!
2018-10-15 23:50:40 +02:00
funkyfranky
40154788d6 WH, CT WIP 2018-10-15 16:19:43 +02:00
FlightControl
a8f42d61fa APC defense ... optimized the unloading of infantry when enemies are nearby. Now the infantry is reloading into the APCs when the enemies are eliminated. 2018-10-15 07:20:46 +02:00
Frank
b923f66c56 CT v0.0.6 2018-10-14 22:27:30 +02:00
FlightControl
a0355af13b Fixing a stupid typo with the dead event handler in SET_UNIT.
Addint methods in Point.lua and Utils.lua.
2018-10-14 14:07:42 +02:00
FlightControl
112945b3f6 Fixing a stupid typo with the dead event handler in SET_UNIT. 2018-10-14 14:05:27 +02:00
Frank
09c46595e5 Merge pull request #1030 from FlightControl-Master/FF/Develop
Added wind to AoA
2018-10-13 23:27:12 +02:00
Frank
003b0c875e Added wind ot AoA
COORDINATE
* added GetWindWithTurbulences function

POSITIONABLE
* Included wind in AoA calculation
2018-10-13 23:25:45 +02:00
Frank
ee2668ac65 Merge pull request #1029 from FlightControl-Master/FF/Develop
Aircraft attitude
2018-10-13 19:53:05 +02:00
Frank
f47bf4771f Remove CT 2018-10-13 19:45:26 +02:00
Frank
8551830517 Merge branch 'develop' into FF/Develop 2018-10-13 19:42:30 +02:00
Frank
8b78090a57 CT v0.0.5 2018-10-13 19:42:17 +02:00
FlightControl
d2bdb2a791 Merge branch 'develop' 2018-10-13 07:54:28 +02:00
FlightControl
f8f0114f06 Documentation and exact location of test missions. 2018-10-13 07:54:15 +02:00
FlightControl
8619d48c80 Merge branch 'develop' 2018-10-13 07:49:34 +02:00
FlightControl
4171cc45f5 Fixing a mistake on capture. 2018-10-13 07:49:14 +02:00
FlightControl
5bccd2c6c9 Merge branch 'develop' 2018-10-13 07:34:01 +02:00
FlightControl
a60626468c Implemented the capturing of the airbase. 2018-10-13 07:33:25 +02:00
Frank
f9cb5d5966 CT v0.0.4
Fixed wrong z-position.
Generalized abort parameters.
Added preliminary F10 menu.
2018-10-13 00:37:15 +02:00
FlightControl
cad1c8c462 Merge branch 'develop' 2018-10-12 21:11:32 +02:00
FlightControl
19e2af08e0 increased the altitude of hover. 2018-10-12 21:10:58 +02:00
FlightControl
4386b19b06 Merge branch 'develop' 2018-10-12 20:20:16 +02:00
FlightControl
da90826bd0 Fix height problem in workaround solution. 2018-10-12 20:15:10 +02:00
funkyfranky
33509a49e0 CT v0.0.3 2018-10-12 16:16:39 +02:00
FlightControl
514d9f3eb3 Implemented workaround request to board and unboard cargo from buildings. Now "InAir" means a velocity < 1 m/s and a height < 30 m. Once DCS properly fixes the flag to land on buildings, this workaround can be removed. 2018-10-12 07:17:56 +02:00
FlightControl
690805d7ca Implemented workaround request to board and unboard cargo from buildings. Now "InAir" means a velocity < 1 m/s and a height < 30 m. Once DCS properly fixes the flag to land on buildings, this workaround can be removed. 2018-10-12 07:14:05 +02:00
Frank
eda359e20f CT v0.0.2 2018-10-12 00:11:39 +02:00
Frank
46882ed192 Merge branch 'develop' into FF/Develop 2018-10-11 19:36:57 +02:00
FlightControl
f1f37b6598 Merge branch 'develop' 2018-10-11 19:18:01 +02:00
FlightControl
08c593578f Fixing issues with cargo loading for helos and apcs when the near range was too small... 2018-10-11 19:17:33 +02:00
FlightControl
6625de9005 Some optimizations for group. 2018-10-11 17:44:49 +02:00
funkyfranky
bbd5766688 CT general dist 2018-10-11 16:17:58 +02:00
Frank
ccf2f60068 CT 2018-10-11 00:34:14 +02:00
funkyfranky
fa4abed028 Added AoA function and carrier training WIP 2018-10-10 15:56:34 +02:00
FlightControl
804a356f13 Merge branch 'develop' 2018-10-09 20:13:32 +02:00
FlightControl
f03a2e3657 Revision of core classes documentation. 2018-10-09 19:30:57 +02:00
FlightControl
e6f51af34c Documentation 2018-10-09 09:47:22 +02:00
FlightControl
db85883026 Merge branch 'develop' 2018-10-08 06:43:30 +02:00
FlightControl
a3e29a8d5c Documentation 2018-10-08 06:05:44 +02:00
FlightControl
e5e9bc2ef7 docuemntation 2018-10-08 06:01:49 +02:00
FlightControl
41aee35b5d Documentation 2018-10-08 05:56:14 +02:00
FlightControl
7081a9eff5 ATC ground updates 2018-10-08 05:42:18 +02:00
FlightControl
be839f3a3b Fixing late activated HQs for command centers. 2018-10-08 04:57:53 +02:00
FlightControl
f35b27451f Update CargoGroup.lua 2018-10-07 18:46:19 +02:00
Frank
016e59860f Merge pull request #1022 from FlightControl-Master/FF/Develop
Warehouse v0.6.1
2018-10-07 16:58:28 +02:00
Frank
d9719923c1 Warehouse v0.6.1
- Added spawn zone max distance as optional parameter to SetSpawnZone function.
- Added optional RefCoord parameter to FindNearestWarehouse function.
2018-10-07 16:54:26 +02:00
Frank
15a6c5f6a8 Merge pull request #1021 from FlightControl-Master/FF/Develop
Warehouse v0.6.0
2018-10-07 16:13:45 +02:00
Frank
88d4580f9e Warehouse v0.6.0
- Added user function to find nearest warehouse.
- Fixed bug in GetNumberOfAssets function.
2018-10-07 16:11:34 +02:00
Frank
87d82aa674 Merge pull request #1019 from FlightControl-Master/FF/Develop
Warehouse v0.5.9
2018-10-07 00:21:52 +02:00
Frank
d58c7f8fab Warehouse v0.5.9
* Fixed bug for distance to spawn zone.
* Fixed bug when carriers get killed.
* Added example for supply chains to docs.
* Added option to specify skll and livery when adding assets.
* Added option for specifying assignments when adding assets.
2018-10-07 00:18:32 +02:00
FlightControl
8d30dfacd5 Merge branch 'develop' 2018-10-06 07:56:40 +02:00
Frank
7340b0aad3 Merge pull request #1015 from FlightControl-Master/FF/Develop
Warehouse v0.5.8
2018-10-05 23:11:07 +02:00
Frank
03fd8c93eb Merge branch 'develop' into FF/Develop 2018-10-05 22:45:54 +02:00
Frank
f727aa0a17 Revert "Merge branch 'master' into FF/Develop"
This reverts commit 502c356784, reversing
changes made to 0e7291a912.
2018-10-05 22:44:19 +02:00
Frank
502c356784 Merge branch 'master' into FF/Develop 2018-10-05 22:44:07 +02:00
Frank
0e7291a912 WAREHOUSE v0.5.8
Fixed bug with dist to spawn zone.
2018-10-05 22:43:31 +02:00
funkyfranky
2dc14097b8 SPOT parameters and docu 2018-10-05 15:34:04 +02:00
Frank
9655d60bf8 Merge pull request #1014 from FlightControl-Master/FF/Develop
Warehouse v0.5.7
2018-10-05 01:50:40 +02:00
Frank
cc920682fd Merge branch 'develop' into FF/Develop 2018-10-05 01:47:28 +02:00
Frank
205f69b3ab Warehouse v0.5.7
- Added check if spawn zones are on land
- Removed check that ground units cannot go to ships
- Added check that spawn zone is 5 km from warehouse (needs to be revised).

Coordinate:
- added surface type checks api functions
2018-10-05 01:47:10 +02:00
FlightControl
c4376f081b Pushing a fix for shadowze 2018-10-04 21:37:19 +02:00
FlightControl
1ae062dc6e Fixed in CLEANUP
- Scan initial units within the subscribed airbases.
- Scan if at a birth the unit is within an airbase.
- Scan upon checking if the units are within the airbases.
2018-10-04 21:28:45 +02:00
funkyfranky
ea3bae39cc Warehouse v0.5.6w 2018-10-04 16:28:18 +02:00
FlightControl
0bb62ce43f Merge pull request #1012 from FlightControl-Master/FF/Develop
Warehouse v0.5.6
2018-10-03 21:57:46 +02:00
Frank
a4595090c4 Warehouse v0.5.6
- Neutral warehouses can be captured
- Added example 16 for resupply
2018-10-03 21:41:33 +02:00
FlightControl
9df3f52fd5 Warehouse 2018-10-02 21:42:16 +02:00
FlightControl
6f37ff1831 remove old release notes 2018-10-02 19:37:33 +02:00
FlightControl
7d4b773b48 Finish 2.4.0 2018-10-02 18:19:39 +02:00
funkyfranky
cba7bec477 WH and ARTY 2018-10-02 15:27:46 +02:00
Frank
e990db8070 Merge branch 'develop' into FF/Develop 2018-10-01 22:20:31 +02:00
FlightControl
ec9a5efdde -- Added AnyInZone stuff.
-- Now for tasking, routing messages show the task name...
2018-10-01 22:06:42 +02:00
FlightControl
8f6a3d5c49 I have the refuel again working for the AI_A2A_DISPATCHER.
And the status checks are again functional for CAP and GCI!
2018-10-01 20:29:33 +02:00
FlightControl
d037614861 Changes. 2018-10-01 19:47:11 +02:00
funkyfranky
f8404f336d Arty v1.0.6 2018-10-01 16:24:13 +02:00
Frank
86fab3985b Merge pull request #1009 from FlightControl-Master/FF/Develop
Warehouse v0.5.5
2018-09-30 23:34:37 +02:00
Frank
8c524f160e Merge branch 'develop' into FF/Develop 2018-09-30 11:45:31 +02:00
FlightControl
064111407b Fixing SET_GROUP RemoveGroupsByName method. 2018-09-30 08:03:03 +02:00
Frank
31207c3368 Merge branch 'develop' into FF/Develop 2018-09-30 00:19:21 +02:00
Frank
7e5495bcd8 Warehouse v0.5.5
Added AssetDead event.
Some fixes.
2018-09-30 00:19:08 +02:00
FlightControl
a84f0e228a - pushing fix for issue with command center reporting.
- pushing fix for issue with markings in cargo tasking not displayed.
- i have removed the workaround for the DCS bug workaround, get the DCS API (getPlayerName()) for a unit is returning "" or nil.
2018-09-29 15:34:21 +02:00
FlightControl
dc41852e45 fixed documentation in SPAWN 2018-09-29 13:55:00 +02:00
FlightControl
3a8530227d Documentation 2018-09-28 22:16:09 +02:00
funkyfranky
ffee1b119b Warehouse v0.5.4w 2018-09-28 16:23:17 +02:00
Frank
9637d0e545 Warehouse 0.5.4 2018-09-27 23:56:02 +02:00
Frank
2af52b294c Merge branch 'develop' into FF/Develop 2018-09-27 23:46:26 +02:00
Frank
a744e08a75 Merge branch 'FF/Develop' of https://github.com/FlightControl-Master/MOOSE into FF/Develop 2018-09-27 23:44:06 +02:00
Frank
9bfbfcfd6a stuff 2018-09-27 23:44:04 +02:00
FlightControl
5becf001ba -- Fixed NearRadius.
-- Some documentation errors.
2018-09-27 22:08:08 +02:00
funkyfranky
4625bc73a9 Warehouse v0.5.3w 2018-09-27 16:21:29 +02:00
Frank
8fb1807ec0 Merge branch 'develop' into FF/Develop 2018-09-26 22:38:30 +02:00
Frank
f09443c949 Merge branch 'develop' into FF/Develop 2018-09-26 22:36:52 +02:00
FlightControl
2dc7ca0cb2 Fixing nearrange bug and command center tasking auto assignment optimization. Moved auto assignment task menu to the command center group menu structure. I hope it will work ... 2018-09-26 22:14:59 +02:00
Frank
a76ea8f393 Stuff 2018-09-26 21:40:18 +02:00
FlightControl
3275fd2e5b Fixed issue with NearRadius. 2018-09-26 21:16:47 +02:00
FlightControl
1d5ddb3928 Fixes documentation 2018-09-26 20:59:21 +02:00
Frank
7ab14e0bf9 Merge branch 'develop' into FF/Develop 2018-09-26 20:20:49 +02:00
FlightControl
98f51116bb Improved documentation of detection. 2018-09-26 18:01:09 +02:00
funkyfranky
159c3a21c0 Merge branch 'develop' into FF/Develop 2018-09-25 17:18:56 +02:00
FlightControl
51b6703b58 Documentation 2018-09-25 17:05:56 +02:00
Frank
125dc09e4d Warehouse v0.5.3
Added optional loadradius.
Improved documentation.
Changes in deploy radius.
2018-09-24 22:58:23 +02:00
Frank
49d2f5eef1 Back 2018-09-24 10:44:23 +02:00
Frank
71415a9796 Merge branch 'develop' into FF/Develop 2018-09-24 10:06:24 +02:00
Frank
483c5deddd Wrong 2018-09-24 10:00:43 +02:00
FlightControl
def7a1513e fixes stupid error I did on AI_CARGO_DISPATCHER. 2018-09-24 05:40:40 +02:00
Frank
954ca31c79 Strange Things! 2018-09-23 21:45:19 +02:00
Frank
762ce9a6b1 Merge branch 'develop' into FF/Develop 2018-09-23 11:06:01 +02:00
Frank
fd70ffc836 Warehouse v0.5.2
Added NewAsset event.
2018-09-23 11:02:36 +02:00
FlightControl
ddeb832f12 Documentation 2018-09-22 10:29:52 +02:00
FlightControl
bef91cea35 Documentation 2018-09-22 10:24:47 +02:00
FlightControl
163e42ee6e Documentation 2018-09-22 10:06:19 +02:00
FlightControl
9ca61c680e Documentation 2018-09-22 09:57:46 +02:00
FlightControl
d86419f893 Documentation 2018-09-22 09:55:40 +02:00
FlightControl
6e67da1672 Dispatcher documentation. 2018-09-22 09:45:57 +02:00
FlightControl
6b2e9fcb5f Documentation 2018-09-22 09:34:36 +02:00
FlightControl
136a2ce5f2 Documentation test 2018-09-22 09:28:08 +02:00
FlightControl
e274ac3151 Documentation 2018-09-21 21:18:40 +02:00
FlightControl
c8f2786611 Unboarding and Unboarding timing updates. 2018-09-21 16:29:53 +02:00
FlightControl
8516cb349c Test 2018-09-21 15:24:40 +02:00
FlightControl
fc5cbb7862 Documentation 2018-09-21 13:21:04 +02:00
FlightControl
99b1532974 docs 2018-09-20 22:02:27 +02:00
FlightControl
3625ad37b4 Documentation 2018-09-20 21:43:05 +02:00
FlightControl
1345bdcb10 Refinement of the code.
- ALL the Pickup event code has changed. A Height parameter has been added.
- ALL the Deploy event code has changed. A Height parameter has been added.
- ALL the Home event code has changed. A Height parameter has been added.
- ZONE_POLYGON now also has a create zone event triggered.
2018-09-20 20:08:00 +02:00
FlightControl
337e7eab53 Fixed the remaining issues with APCs, Helicopter and Airplane cargo dispatchers. 2018-09-19 05:14:20 +02:00
Frank
f655e7e652 Merge pull request #986 from FlightControl-Master/FF/Develop
WAREHOUSE v0.5.1
2018-09-18 17:01:01 +02:00
funkyfranky
35e41570df Spawn and Group
Removed debug markers.
2018-09-18 16:41:17 +02:00
funkyfranky
bab1d21cc0 Warehouse v0.5.1
Final polish.
2018-09-18 16:18:40 +02:00
funkyfranky
f5022a12f8 Merge branch 'develop' into FF/Develop 2018-09-18 14:53:35 +02:00
FlightControl
08fffb9004 Improvements to cargo AI handling. 2018-09-18 13:49:37 +02:00
FlightControl
02aff87b9f Frank, pushing a fix for APCs, please test. Helicopters will be adapted and planes too later. 2018-09-18 13:08:02 +02:00
funkyfranky
ab5f080191 Warehouse
self:I --> self:T
2018-09-18 11:39:36 +02:00
funkyfranky
3bf9198b6f Merge branch 'develop' into FF/Develop 2018-09-18 11:03:31 +02:00
FlightControl
e0c8d55a5d Updated to CARGO TASKING model. Now capture from the dispatcher the CargoPickedUp and CargoDeployed events. 2018-09-18 10:25:13 +02:00
FlightControl
7cd40e2d2c Some code cleanup. 2018-09-18 07:59:43 +02:00
FlightControl
ea851af6ea @shadowze I've done a fix to remove the event handlers from SET_CARGO using :FilterStop(). Can you check this please? 2018-09-18 07:45:11 +02:00
funkyfranky
94c21db81c Warehouse v0.5.0
Improved documentation including examples.
Fixed destroy state.
Added pictures.
2018-09-18 00:00:19 +02:00
funkyfranky
0275ba8b6b warehouse
little changes
2018-09-17 14:04:55 +02:00
funkyfranky
f4f942d8d4 Warehouse
little updates
static countryid
2018-09-17 14:04:30 +02:00
funkyfranky
85640c5884 Merge branch 'develop' into FF/Develop 2018-09-17 12:53:40 +02:00
FlightControl
6de86ac708 Frank can you retry? 2018-09-17 12:35:05 +02:00
FlightControl
f8e1c21a13 Improvement of the C-130 and C-17A 2018-09-17 11:17:59 +02:00
funkyfranky
14e1ab9497 Merge branch 'develop' into FF/Develop 2018-09-17 10:04:00 +02:00
funkyfranky
98b427a26f Warehouse v0.4.9
Added option to force cargo bay limit and cargo asset weight.
2018-09-17 00:23:04 +02:00
FlightControl
f5a68db7ef Documented Alarm States 2018-09-16 16:22:03 +02:00
FlightControl
a0502a12fa Fixing SPAWNING of STATICS for CARGO and respawning of STATICS for CARGO. Please test. 2018-09-16 15:37:22 +02:00
funkyfranky
2d029c6405 Warehouse v0.4.8
Set loadradius no nil for APC dispatcher.

Adjustet general image.
Use SetAirbase() function in New()
Remove Stop() from Destroyed.
2018-09-16 12:52:13 +02:00
funkyfranky
8f08fd87be Warehouse v0.4.7
Added EWR as attribute.
Fixed bug in shipping lanes.
Added airbase check in arrived event.
Removed starting point from shipping lane since it is in the port zone anyway.
2018-09-16 01:36:41 +02:00
funkyfranky
e16d6c0ca4 Warehouse v0.4.6
Little adjustments.
Controllable: Fixed bombing task.
2018-09-15 20:26:08 +02:00
funkyfranky
d9bcb8b168 Merge branch 'develop' into FF/Develop 2018-09-15 12:59:35 +02:00
FlightControl
f8f000eae5 Fixing problems with STATICS used for task transportation. I think it should work now. 2018-09-15 07:45:20 +02:00
FlightControl
47aaf6f6b2 Redo including set of friendlies 2018-09-15 07:06:07 +02:00
funkyfranky
88734fa9fc Warehouse v0.4.5
Fixed overlapping aircraft on parking spots.
Other fixes.
2018-09-15 00:31:55 +02:00
FlightControl
4ab94ecf26 Fixes for performance in DESIGNATE. 2018-09-14 21:59:30 +02:00
funkyfranky
06ff755702 Merge branch 'develop' into FF/Develop 2018-09-14 17:09:03 +02:00
funkyfranky
c7c63b37fe Warehouse v0.4.4w 2018-09-14 15:25:06 +02:00
FlightControl
7fa7f0fb79 Added DetectedItem event 2018-09-14 05:48:48 +02:00
funkyfranky
fdfb5266b3 Merge branch 'develop' into FF/Develop 2018-09-13 23:22:23 +02:00
FlightControl
3b630be4f4 Hopefully this fixes the cargo lost :-) 2018-09-13 22:19:48 +02:00
FlightControl
36aa36398c Hopefully this fixes the cargo lost :-) 2018-09-13 21:51:21 +02:00
FlightControl
337b7a69b2 Pushing some big fixes for DETECTION, SPAWN and AI_A2A_DISPATCHER. Fingers crossed. 2018-09-13 20:48:38 +02:00
FlightControl
44866e6d58 Communicate in the trace the GCICAP setup correctly. 2018-09-13 18:04:44 +02:00
FlightControl
80545fa208 Pushing a fix for the cargo destroys after respawn. 2018-09-13 18:00:48 +02:00
funkyfranky
956d4fa248 Warehouse v0.4.4w 2018-09-13 16:16:33 +02:00
funkyfranky
54ae3ed62b Warehouse v0.4.4
- Fixed little bug in warehouse.
- Added home event function to cargo airplane. Planes are now going home after job is done.
- Added false option for :Destroy() to generate no event.
- Added false parameter to respawn function.
2018-09-12 23:04:39 +02:00
funkyfranky
a6ea157b4f Merge branch 'develop' into FF/Develop 2018-09-12 20:43:34 +02:00
funkyfranky
3d0f1faadc Warehouse v0.4.3
- Cleaned up tracing output.
- Added home zone for airplane dispatcher.
- Fixed bugs in relative quantities.
- Added parking check for transports.
2018-09-12 20:43:24 +02:00
FlightControl
a0ac366bec Fix for respawning cargo (should not go dead). 2018-09-12 19:08:46 +02:00
funkyfranky
d6cbd40575 Merge branch 'develop' into FF/Develop 2018-09-12 00:27:54 +02:00
funkyfranky
b7644efea5 Warehouse v0.4.2
Improved destroyed group handling.
Many other fixes.
2018-09-11 23:51:18 +02:00
FlightControl
9c9633ba23 Added FilterActive() method in SET\_UNIT, SET\GROUP, SET\_CLIENT.
Haven't tested the behaviour for CLIENTs joining and leaving.
2018-09-11 20:38:09 +02:00
FlightControl
d5e2365bb3 More updates to fix the RemoveUnit problems for DATABASE and SETs. 2018-09-11 15:26:23 +02:00
FlightControl
9647a1a84e Implementation of unit maintenance in DATABASE and SETs for Cargo objects. Pls retest. 2018-09-11 10:04:33 +02:00
FlightControl
c1191e286a Added the new event S_EVENT_REMOVE_UNIT to trigger the removal of units (from groups also) when a :Destroy(false) or :Destroy() is called for a UNIT object.
The units are then removed from each SET that is subscribed to a set of UNIT objects or GROUP objects! Also the DATABASE is correctly managing this new removal method.
This to prevent the DATABASE getting corrupted with dead units, which were removed with :Destroy(), but which weren't cleaned from the database.
2018-09-11 09:00:30 +02:00
funkyfranky
552718e303 Warehouse v0.4.1alpha
Not working version.
fixed a few bugs.
Uncommented check for coordinate in CargoGroup.lua
etc.
2018-09-11 00:04:33 +02:00
funkyfranky
85505f3feb Warehouse v0.4.1w 2018-09-10 16:32:10 +02:00
funkyfranky
cc9b695b68 Warehouse v0.4.1
Improved JobDone function.
Fixed bugs.
2018-09-09 23:57:17 +02:00
funkyfranky
64ed3a119f Merge branch 'develop' into FF/Develop 2018-09-09 22:04:52 +02:00
funkyfranky
53ac9ca500 Warehouse v0.4.0
Added some onevent functions for AI_CARGO
Added start command for CONTROLLER
2018-09-09 22:04:31 +02:00
FlightControl
72538597ad Fixing additional problems with AI cargo helicopters 2018-09-09 19:45:49 +02:00
FlightControl
5c5b9df470 Fixing problem with AI cargo helicopter pickup 2018-09-09 18:44:04 +02:00
funkyfranky
7c3a8f448c Merge branch 'develop' into FF/Develop 2018-09-09 13:46:22 +02:00
funkyfranky
bd1aec6deb Warehouse v0.3.9
Fixes and minor adjustments.
2018-09-09 13:46:12 +02:00
FlightControl
492563d6f3 Fixing errors with Aborted, Failed and Cancelled state transitions. The handling was wrong, causing the root handlers not being called anymore, causing the task not being able to fail, cancel, abort. 2018-09-09 07:39:13 +02:00
funkyfranky
3ec2d525a9 Merge branch 'develop' into FF/Develop 2018-09-09 00:04:25 +02:00
funkyfranky
dbd358be35 Warehosue v0.3.8
Added AAA, SAM, UAV general attributes.
Added Quantity enumerator.
Updated to new dispatcher API (still WIP).
Improved handling for immobile groups.
Fixed some bugs.
2018-09-08 23:50:11 +02:00
FlightControl
69934a8cae Fixes for relocation. 2018-09-08 17:08:52 +02:00
FlightControl
e13cf07999 Fixing respawn problem. 2018-09-08 16:42:45 +02:00
FlightControl
0948229335 Implemented the option for APC dispatcher and APC cargo, not to disembark when enemies are nearby. The CombatRadius is zero. 2018-09-08 15:42:06 +02:00
FlightControl
a0e77c04e0 Fix for shadowze on the cargo templates not correctly destroyed after being respawned. The original groups should be cleaned from the database. 2018-09-08 14:14:31 +02:00
funkyfranky
718679b5dd Warehouse v0.3.7w 2018-09-07 16:41:23 +02:00
funkyfranky
107c2da635 Merge branch 'develop' into FF/Develop 2018-09-06 23:28:40 +02:00
funkyfranky
c2064690f1 AI CARGO
Added new routines by Sven.
Due to conflicts just overwriting the old ones.
2018-09-06 23:25:19 +02:00
funkyfranky
3f875ce276 Warehouse v0.3.7
Added global warehouse table.
Fixed bugs for prending queue
2018-09-06 23:20:47 +02:00
FlightControl
703dac8251 Optimization solving the overloading problem with Loaded event for cargo deployment. 2018-09-06 20:31:33 +02:00
FlightControl
5bd6f4901f Fixed issues with pickup zones. 2018-09-06 19:23:13 +02:00
FlightControl
5c29f48a88 Home event handler implementation for APCs and Helicopters. airplanes is to be further investigated. 2018-09-06 18:36:31 +02:00
funkyfranky
012122e8da Warehouse v0.3.6w 2018-09-06 16:22:56 +02:00
funkyfranky
a039745b0f Warehouse v0.3.6
moved updatepending function to addasset.
not a good idea, since now the pending queue of the wrong warehouse is updated!
2018-09-05 21:58:44 +02:00
FlightControl
e97badd092 Optimize 2018-09-05 21:57:50 +02:00
FlightControl
c160ecbce5 Cargo documentation optimization 2018-09-05 21:37:01 +02:00
FlightControl
ea60e43584 Documentation updates 2018-09-05 21:24:11 +02:00
FlightControl
ab19c696c3 Fixing an issue with cargo links. 2018-09-05 20:55:56 +02:00
FlightControl
da4664eff5 Finish Feature-Cargo-Rework to consolidate code and to:
- If multiple units are in a carrier group, pickup will switch unit until all units are full with cargo.
- The loading picks the heaviest cargo first.
- PickupZone added. APIs of the dispatches have changed.
- Improved event handling. check out the documentation of the AI_CARGO_DISPATCHER.
- Deployed and PickedUp events added.
- Added a new AI_Cargo.lua file
- Improved the unboarding of cargo, much more smooth now.
- Improved the loading of cargo, much more smooth now.
- Improved airplane logic.
- Improved documentation.
2018-09-05 20:19:43 +02:00
FlightControl
415b740196 Workable solution? 2018-09-05 20:11:41 +02:00
funkyfranky
7ab11d8fef Warehouse v0.3.5w 2018-09-05 16:41:59 +02:00
FlightControl
01add98b7a Improved logic 2018-09-05 16:33:31 +02:00
FlightControl
31fba973e5 Progress 2018-09-05 06:59:22 +02:00
FlightControl
81b0c3a050 Reworking cargo 2018-09-05 06:03:56 +02:00
funkyfranky
c790f71002 Warehouse v0.3.5
Improved queue output.
2018-09-05 00:20:05 +02:00
funkyfranky
61a304f861 Warehouse v0.3.4w 2018-09-04 16:23:24 +02:00
funkyfranky
13451ed602 Warehosue v0.3.4
Fixed some bugs.
Helos on ships are now not spawned in uncontrolled state due to DCS bug.
Self requests are not deleted from the pending queue any more in case they return to their warehouse.
2018-09-03 21:51:38 +02:00
funkyfranky
14bc7922d0 Warehouse v0.3.3w 2018-09-03 16:14:50 +02:00
funkyfranky
c9e44dd865 Warehosue v0.3.3 2018-09-02 23:49:02 +02:00
funkyfranky
08cdb8b080 Merge branch 'develop' into FF/Develop 2018-09-02 09:25:45 +02:00
funkyfranky
c1dee54493 Warehouse v0.3.2
Added new flightplan.
Fixed some bugs.
2018-09-02 00:07:49 +02:00
FlightControl
ed3345b00a Documentation of cargo declaration in the mission editor using #CARGO tag. 2018-09-01 06:50:18 +02:00
funkyfranky
1097c02b06 Merge branch 'develop' into FF/Develop 2018-08-31 20:11:18 +02:00
FlightControl
8d41e4699c Patched weight issues with mortars. 5000 kg is a bit too much for a mortar i think. Ed to fix this. 2018-08-31 17:30:23 +02:00
FlightControl
89051d5439 I've published the trucks weight adaptions. Can you try in 5 minutes the trucks? 2018-08-31 17:05:03 +02:00
funkyfranky
075fe729aa Warehouse v0.3.1w 2018-08-31 16:21:13 +02:00
funkyfranky
d51690a3cf Warehouse v0.3.1
Ships back to stock is now working.
Fixed some bugs.
2018-08-31 00:42:15 +02:00
FlightControl
97feeaeaf3 Update 2018-08-30 20:56:10 +02:00
FlightControl
d4d05f4693 Updates on cargo handling of core engine. 2018-08-30 20:48:14 +02:00
funkyfranky
0ebbbde6c3 Merge branch 'develop' into FF/Develop 2018-08-30 17:56:36 +02:00
funkyfranky
1ba84003d3 Warehouse v0.3.0w 2018-08-30 16:40:59 +02:00
FlightControl
42b04dedaa Optimized boarding logic. Now it works correct.
Adjust speed at the end to ensure that vehicles park closer to the cargo when carriers are in formation.
2018-08-30 06:07:26 +02:00
funkyfranky
6fbf584e81 Warehouse v0.3.0 2018-08-29 23:33:13 +02:00
FlightControl
8e6fc439ec Finish Cargo/Optimization_Dispatcher 2018-08-29 19:23:58 +02:00
FlightControl
25777afdd1 - Now the cargo is sorted from large to small for dispatching.
- The carrier which has a unit that fits the group size, will be routed towards that cargo.
- When boarding, the carrier(s) will then be boarded with any cargo group that is available that fits the remaining cargo bays.
2018-08-29 19:23:46 +02:00
funkyfranky
46edf5ce32 Merge branch 'develop' into FF/Develop 2018-08-29 17:03:22 +02:00
funkyfranky
ae04196584 Warehouse v0.2.9w 2018-08-29 15:49:41 +02:00
FlightControl
7b338ca9d0 Fixed the weight of an average infantry from 70 kg to 95 kg. 2018-08-29 08:18:03 +02:00
FlightControl
daaedd24d2 Reworked the menu system for cargo transportation. The Route to Pickup cargo sub menu now shows boarding, loading or sling loading sub menus, and allows to handle much more cargo. 2018-08-29 08:07:13 +02:00
funkyfranky
a8d96d332f Warehouse v0.2.9
not working, need to find a way for transports
2018-08-29 00:16:57 +02:00
funkyfranky
6b7a778eac Merge branch 'develop' into FF/Develop 2018-08-28 17:45:13 +02:00
funkyfranky
2112915dd2 Warehouse v0.2.8w 2018-08-28 16:29:03 +02:00
FlightControl
46cfcddf68 - Added cache to a ZONE_GROUP to prevent a zone to be unknown when enquired and the GROUP is destroyed. 2018-08-28 07:36:55 +02:00
FlightControl
1aabb1bfbd - fixed cargo APC unloading in case of enemy presence and loading in case of enemy destroy or leave.
- fixed boarding near range to 5 meters for cargo units.
2018-08-28 07:16:42 +02:00
funkyfranky
8e16fbd000 Warehouse v0.2.8
- Added first version of naval assets (self propelled).
- Changed WAREHOUSE.Attribute
2018-08-28 00:34:26 +02:00
funkyfranky
a9a040626e Warehouse 0.2.7w 2018-08-27 16:46:46 +02:00
funkyfranky
508e35aec3 Warehouse v0.2.7 2018-08-27 00:10:05 +02:00
funkyfranky
171f20e898 Merge branch 'develop' into FF/Develop 2018-08-26 17:29:45 +02:00
funkyfranky
64355fb772 Warehouse v0.2.6
Several fixes including BoundZone.
Warehouse ID is not number not string.
Updated Documentation.
Fixed bug that invalid requests are not recognized.
2018-08-26 17:29:31 +02:00
FlightControl
dffd66940d Added 3 meters to the bounding radius to ensure infantry gets properly boarded around the carrier unit. 2018-08-26 09:05:48 +02:00
FlightControl
185c27013d Fix for clients which weren't initialized with a cargo bay weight limit value. Each time a cargo bay weight limit is enquired through the method GetCargoBayFeeWeight(), if there isn't a cargo bay weight limit set, the default cargo bay weight limit will be calculated, so that the logic will always be executed. 2018-08-26 08:45:36 +02:00
FlightControl
d9a5618773 Fix crash in AI_CARGO_AIRPLANE 2018-08-25 09:20:50 +02:00
funkyfranky
b8a83aadb2 Merge branch 'FF/Develop' of https://github.com/FlightControl-Master/MOOSE into FF/Develop 2018-08-24 21:19:56 +02:00
funkyfranky
5b7852ef6c Warehouse v0.2.5 2018-08-24 21:19:53 +02:00
funkyfranky
76f34e448c Warehouse v0.2.6w 2018-08-24 11:59:59 +02:00
funkyfranky
743b595465 Warehouse v0.2.6w 2018-08-24 11:09:51 +02:00
funkyfranky
448110de08 Merge branch 'develop' into FF/Develop 2018-08-23 17:24:18 +02:00
funkyfranky
7148fe0c12 Warehouse v0.25w 2018-08-23 16:30:38 +02:00
funkyfranky
b0ac01f25a Warehouse v0.2.5 2018-08-23 00:31:40 +02:00
FlightControl
4f38d8109d Finish Cargo/Limits 2018-08-22 21:40:49 +02:00
FlightControl
bf903c0cc7 New weight driven limits logic for cargo to load multiple cargo.
Fixed near range issue for carriers. now the infantry disappearance range for boarding is calculated by the carrier bounding range, which is derived from the bounding rectangle on the Y-axis. The near range parameter can still be provided and will be interpreted as the loading range for static cargo objects!
2018-08-22 20:41:37 +02:00
funkyfranky
c46d687990 Warehouse v0.2.4w 2018-08-22 16:44:58 +02:00
funkyfranky
64e67494b6 Warehouse v0.2.4 2018-08-21 23:58:22 +02:00
funkyfranky
31a5bfee9e Warehouse 0.2.3w 2018-08-21 16:38:55 +02:00
funkyfranky
e40105495a Warehouse v0.2.3 2018-08-20 23:05:35 +02:00
funkyfranky
f9b4eeef67 Warehouse v0.2.2w 2018-08-20 16:29:04 +02:00
funkyfranky
d1aa5d5de3 Warehouse v0.2.2 2018-08-20 00:08:19 +02:00
FlightControl
7a2dee4162 OK. Revised cargo for AI is working. 2018-08-19 07:26:50 +02:00
funkyfranky
8bcdbef426 Warehouse v0.2.1 2018-08-19 00:19:55 +02:00
funkyfranky
76ce28cdcc Warehouse 0.20
Capture update
2018-08-18 01:29:19 +02:00
funkyfranky
6c586d69ac Warehouse 0.1.9w 2018-08-17 16:36:16 +02:00
FlightControl
a02d3c1950 Cargo Dispatcher APC - Multiple Cargo Groups and Weight in APC 2018-08-17 07:59:53 +02:00
funkyfranky
5a2e1f01b4 Warehouse 0.1.9
Many bugs spotted
2018-08-16 23:10:23 +02:00
funkyfranky
22da329fca Warehouse v0.1.8w 2018-08-16 16:20:36 +02:00
funkyfranky
3ce59eee35 Warehouse v0.1.8
Lots of changes and improvements.
2018-08-16 00:11:47 +02:00
funkyfranky
4e63bf6a22 Warehouse 0.1.7w 2018-08-15 15:59:09 +02:00
funkyfranky
7599459779 Warehouse 0.1.7w 2018-08-15 15:58:20 +02:00
funkyfranky
7a5aa3a4f9 bla 2018-08-15 00:13:33 +02:00
FlightControl
9650129769 AI helicopter dispatcher working to load multiple infantry groups ! 2018-08-14 22:40:28 +02:00
FlightControl
e4f8b5afc3 Working plane cargo AI dispatcher, but still need to work on the collisions on the runway etc of moving vehicles with planes... 2018-08-14 21:04:11 +02:00
funkyfranky
7e4c1d8d3d Warehouse 0.1.7 2018-08-14 16:01:45 +02:00
funkyfranky
d21cee9358 Warehouse v0.1.6 2018-08-14 00:10:42 +02:00
FlightControl
4d7812b368 Working version for airplanes, now need to debug to make it also happen for helicopters and apcs 2018-08-13 21:42:44 +02:00
funkyfranky
ab5b74cf31 Warehouse v0.1.5 2018-08-13 16:25:51 +02:00
FlightControl
74e9599df9 Got the airplanes finally to load together ... 2018-08-13 07:38:18 +02:00
funkyfranky
d91166c3c4 Warehouse 0.1.4
zone: fixed GetRandomCoordinate inner, outer missing
controllable: fixed path cannot be found
group: added getrange
unit: added getrange
2018-08-13 00:36:34 +02:00
FlightControl
7f9f9b33fd - Have added cargo bay limits based on volume and weight.
- AI Cargo Dispatcher works with cargo bay limits for carrier. (i still need to add options to set the parameters for this).
- Carriers load now multiple cargo.
- Added weight and volume attached to cargo objects for units. I reworked the respawning of cargo units, so that these volumes and weights are collected from the unit Descriptor properties!
- There are still bugs, which I need to resolve, but it is going in the right direction.
2018-08-11 11:33:43 +02:00
funkyfranky
195459d6d8 Warehouse v0.1.3 2018-08-10 16:26:39 +02:00
funkyfranky
06688366c6 Warehouse 0.1.2 2018-08-09 23:40:56 +02:00
funkyfranky
a2aa482bc1 WH 2018-08-09 16:23:35 +02:00
funkyfranky
498ec4f86b WAREHOUSE etc 2018-08-09 00:56:25 +02:00
FlightControl
a14c2ef589 Work in progress. Limit functions for POSITIONABLE. 2018-08-08 22:41:02 +02:00
FlightControl
b438df27a4 Merge branch 'FF/Develop' into feature/Cargo/Limits 2018-08-08 22:08:49 +02:00
funkyfranky
009e38b6f7 WAREHOUSE 2018-08-08 21:36:23 +02:00
funkyfranky
b46c238dda WAREHOUSE 2018-08-08 16:21:50 +02:00
funkyfranky
a71c7dc181 WAREHOUSE 2018-08-08 01:13:39 +02:00
funkyfranky
86e4654474 Warehouse etc 2018-08-07 21:22:06 +02:00
funkyfranky
891a725ccb WAREHOUSE 2018-08-07 16:21:02 +02:00
funkyfranky
aa53004ec8 WAREHOUSE 2018-08-06 23:49:23 +02:00
funkyfranky
321803730d RAT,Warehouse 2018-08-06 16:25:45 +02:00
funkyfranky
d53c444c62 Warehouse and other things 2018-08-06 00:21:22 +02:00
funkyfranky
d3273b631f Merge branch 'feature/Feature-AI_Cargo_Dispatching_Airplane' into FF/Develop 2018-08-04 18:41:00 +02:00
funkyfranky
1ce55f3d3d WAREHOUSE 2018-08-04 18:27:44 +02:00
FlightControl
e93f2c54b2 Working version, but needs to be upgraded. 2018-08-04 16:47:18 +02:00
funkyfranky
77f7826084 WAREHOUSE 2018-08-03 16:02:16 +02:00
funkyfranky
4a424dd3d8 WAREHOUSE 2018-08-03 00:01:41 +02:00
funkyfranky
f8b1056c98 WAREHOUSE 2018-08-02 16:35:25 +02:00
funkyfranky
52e69cb697 WAREHOUSE 2018-08-02 00:29:14 +02:00
funkyfranky
d4449f7913 WAREHOUSE 2018-08-01 15:56:07 +02:00
funkyfranky
e0564876f4 RANGE 1.2.1, WAREHOUSE 0.1.0 2018-08-01 01:11:24 +02:00
FlightControl
12be42ee2f Documentation updates 2018-07-31 21:47:25 +02:00
funkyfranky
5a034ecf4f G2G Warehouse 2018-07-31 15:43:31 +02:00
FlightControl
9a6be14fab Revised the documentation. 2018-07-31 07:26:33 +02:00
funkyfranky
1146684144 G2G improvments 2018-07-30 23:41:02 +02:00
FlightControl
12dc173aea added features 2018-07-30 19:56:01 +02:00
FlightControl
0a68e7e2f1 Pictures changed 2018-07-30 19:48:15 +02:00
funkyfranky
849120a885 G2G 2018-07-30 16:04:07 +02:00
funkyfranky
1dc6b91d37 G2G Dispatcher Draft 2018-07-30 00:11:08 +02:00
Frank
e7f0aad920 Merge pull request #969 from FlightControl-Master/FF/Develop
ARTY v1.0.5 and other minor changes.
2018-07-29 00:28:59 +02:00
funkyfranky
fa785a06bb ARTY v1.0.5
ARTY
* Groups can now be transported as cargo via ARTY:NewFromCargoGroup() function.
* If immobile units are defined as cargo, targets out of range are not deleted from the queue.

AI_CARGO_APC
* Adjusted function documentation.

AI_CARGO_DISPATCHER
* Adjusted function documentation.

AI_CARGO_HELICOPTER
* Adjusted function documentation.

CARGOG_ROUP
* Ajusted function documentation.

MESSAGE
* Adjusted function documentation.
* Added missing Settings parameter to some functions.

DCS
* Improved documentation.

MISSION:
* Adusted function documentatoin.
2018-07-29 00:24:05 +02:00
funkyfranky
ef45e9b4c9 Merge branch 'develop' into FF/Develop 2018-07-27 16:39:38 +02:00
funkyfranky
52f429a991 DCS, Detection, Controllable, Group 2018-07-27 15:08:28 +02:00
FlightControl
4dbcaf120f - Fixed a bug with the deploy zones, (they werent listed anymore for deployment!), when using the task dispatcher.
- Added documentation for task cargo! Pictures and a decent explanation.
2018-07-27 12:13:14 +02:00
funkyfranky
a09cd6e667 JTAC 2018-07-24 15:59:42 +02:00
Frank
ea51622213 Merge pull request #966 from FlightControl-Master/FF/Develop
DESIGNATE Class fix
2018-07-23 22:28:34 +02:00
funkyfranky
3526203ccb DESIGNATE Class Fix
DESIGNATE
- GetRootMenu() function seems obsolete and caused a crash in DESIGNATE class. Needs to be replaced by GetMenu() Function. This bug only appeared when a mission is given in DESIGNATE:New(...)
2018-07-23 22:24:59 +02:00
funkyfranky
dc39107daa JTAC 2018-07-23 15:54:09 +02:00
Frank
79cfe13035 Merge pull request #962 from FlightControl-Master/FF/Develop
AI_CARGO_DISPATCHER
2018-07-21 16:33:39 +02:00
funkyfranky
6991550d1b AI_CARGO_DISPATCHER
APCs and helos will now obey speeds set by SetPickupSpeed() and SetDeploySpeed().
2018-07-21 16:32:25 +02:00
Frank
c22d598b8f Merge pull request #961 from FlightControl-Master/FF/Develop
Fixes for ARTY and DESIGNATE classes
2018-07-21 00:33:40 +02:00
funkyfranky
53c0599075 Removed GetVec2 2018-07-21 00:30:02 +02:00
funkyfranky
c7aa799378 Fixes
ARTY:
* Rearming group will not always use 20 km/h = 11 mph.

SET_GROUP(+DESIGNATE):
* Fixed bug in SET_GROUP:FindNearestGroupFromPointVec2( PointVec2 ) function. This caused DESIGNATE class to crash!
2018-07-21 00:26:46 +02:00
Frank
b669ce6d98 Merge pull request #959 from FlightControl-Master/FF/Develop
Added Shiraz and Kerman Airports to enumerators
2018-07-19 23:53:37 +02:00
funkyfranky
267401a1f3 Added Shiraz and Kerman Airports to enumerators 2018-07-19 23:52:07 +02:00
thebgpikester
6d8b8f41ad Merge pull request #957 from FlightControl-Master/FF/Develop
Various minor updates and fixes.
2018-07-18 17:02:32 +01:00
funkyfranky
6aa30f91e6 Debug output 2018-07-18 17:41:21 +02:00
funkyfranky
c60bb29303 Minor fixes
Task_A2G: fixt GetAlt()
AI_Formation: fixed comma in equation
2018-07-17 22:19:25 +02:00
funkyfranky
72343bce29 Improved TaskOnRoad logic
- direct route if path length on route is less than 5%
2018-07-12 23:23:00 +02:00
funkyfranky
258e3d2921 CARGO_GROUP
- Fixed issue that units are spawned on top of each other on unboarding.
2018-07-11 23:27:44 +02:00
funkyfranky
fda061d8c8 Improved GroundOnRoad functions 2018-07-10 23:47:12 +02:00
Van De Velde
9e13ac3f68 First version of documentation of cargo. 2018-07-05 19:25:07 +02:00
Van De Velde
9f644b65fd Merge branch 'develop' of https://github.com/FlightControl-Master/MOOSE into develop 2018-07-05 08:48:17 +02:00
Van De Velde
727aea604f Correctly interprete the _ in the documentation!
Generate new documentation with markdown _ change avoiding wrong italics in the documentation. This is an important change improving the documentation quality!
2018-07-05 08:48:05 +02:00
Frank
1062d512d1 Merge pull request #951 from FlightControl-Master/FF/Develop
RAT v2.3.2
2018-07-04 22:42:35 +02:00
funkyfranky
b3e62fbd50 Merge branch 'develop' into FF/Develop 2018-07-04 22:38:34 +02:00
funkyfranky
fdb1db6f85 RAT v2.3.2
AIRBASE:
- FindFreeParkikng: Added check that units of a group dont overlap with previous members of the same group.
RAT:
- Added check for all units of a group that did not move within a certain time.
2018-07-04 22:38:17 +02:00
Frank
86633597b9 Merge pull request #946 from FlightControl-Master/FF/Develop
RATMANAGER
2018-07-01 21:43:28 +02:00
funkyfranky
2faf7631cb RATMANAGER
RATMANAGER:
- Added interval between spawns.
RAT:
- changed some default parameter values
2018-07-01 21:22:38 +02:00
Van De Velde
8fb6fc8c6d Small change 2018-07-01 09:07:31 +02:00
Van De Velde
8bee670bc9 Added first boarding cargo manual 2018-07-01 08:54:46 +02:00
Van De Velde
5124b842f5 Merge branch 'develop' of https://github.com/FlightControl-Master/MOOSE into develop 2018-06-30 09:37:45 +02:00
Van De Velde
3c2ff2d7a1 Updated documentation 2018-06-30 09:37:28 +02:00
Frank
61761c2fc8 Merge pull request #940 from FlightControl-Master/FF/Develop
SPAWN set correct initial heading
2018-06-30 00:05:44 +02:00
funkyfranky
7b1825aca5 SPAWN set correct initial heading 2018-06-30 00:02:46 +02:00
Frank
ce6cb9c3e6 Merge pull request #937 from FlightControl-Master/FF/Develop
Spawn fixes and improvements.
2018-06-29 17:27:50 +02:00
funkyfranky
5d87672657 Spawn fixes
AIRBASE:
* Added parameter of how many parking spots are required in find free parking spots routine.
SPAWN:
* Fixed grouping bug in SpawnAtAirbase.
* Fixed spawn on runway bug.
* Added user functions for livery  and skill.
RAT:
* Fixed spawn on runway bug.
2018-06-29 17:24:50 +02:00
Van De Velde
5e92b822d7 Merge branch 'develop' of https://github.com/FlightControl-Master/MOOSE into develop 2018-06-29 05:05:39 +02:00
Van De Velde
4452cbd2ab Documentation 2018-06-29 05:05:31 +02:00
thebgpikester
4bdb75245b Merge pull request #934 from jtoppins/issue-932
a2a-dispatcher: add check for not in air in OnEventEngineShutdown
2018-06-29 00:35:27 +01:00
thebgpikester
e85c320844 Merge pull request #935 from jtoppins/issue-875
a2a-dispatcher: remove fuel check in OnEventLand() handler
2018-06-29 00:35:12 +01:00
thebgpikester
1a4370d433 Merge pull request #936 from FlightControl-Master/FF/Develop
No conflicts.
2018-06-28 20:54:53 +01:00
funkyfranky
d46da07f61 Improvements RAT, SPAWAN, AIRBASE
SPAWN:
- Added options to find parking spots function.
RAT:
- Added user functions for parking.
- Added return of self for user functions.
- Added new check on runway function and removed old version.
- Removed old RAT parking spot DB.
AIRBASE:
- Added verysafe option for find free parking function.
- Other minor changes.
2018-06-28 20:59:09 +02:00
Jonathan Toppins
c952f134d8 a2a-dispatcher: remove fuel check in OnEventLand() handler
This effectivally reverts the change made in commit
ea96a5e0a3 ("Planes remaining at airfield fixed") to declutter
airbases of aircraft which land at incorrect bases.

The problem with the logic is an RTB command will not be issued until
the fuel threshold is reached. Therefore the check will always be true
resulting the the unit always being deleted.

Bug: 875
Signed-off-by: Jonathan Toppins <jtoppins@users.sourceforge.net>
2018-06-28 00:38:08 -04:00
Jonathan Toppins
169dcfe3f6 a2a-dispatcher: add check for not in air in OnEventEngineShutdown
This fixes the problem of planes owned by gcicap would immediately
despawn when shot causing their engine to quit.

While not ultimately satisfying as planes shot while taxiing will still
immediately despawn. One is now able to see their air victories in all
their glory, including the fiery crash into the ground.

Bug: 932
Signed-off-by: Jonathan Toppins <jtoppins@users.sourceforge.net>
2018-06-28 00:26:13 -04:00
funkyfranky
a7afb43ab6 Spawn improvements
COORDINATE:
- Improved GetClosestParkingSpot functions.
- Improved ScanObject function.
SPAWN:
- Improved SpawnAtAirbase function
RAT:
- Improved spawn function
- Added some takeoff type user functions.
UTILS:
- Added clock vs second functions
- Added split function
AIRBASE:
- Added checkonrunway function
- Other improvemetns.
2018-06-28 00:20:48 +02:00
funkyfranky
08ea3cd219 New sophisticated FindParkingSpot routine.
AIRBASE:
- Added new find parking spot routine. Taking into accound dimension of AC etc.
- Added more termial type combinations.
COORDINATE:
- minor changes in scanobjects() function.
RAT and SPAWN
- improved modifyspawntemplate() function ==> new find routine, helos
2018-06-26 23:53:21 +02:00
funkyfranky
bfbdb37b65 Merge branch 'develop' into FF/Develop 2018-06-25 22:39:00 +02:00
funkyfranky
f5eb77cbf5 RAT 2.3.0
RAT:
- Added getparking function wrappers to determin free parking spots.
- Terminal type can be specified.
- respawndelay is used as delay for despawn as well.
- commute has new option for star shape routes.
DATABASE:
- Added neutral coalition support.
COORDINATE:
- added new search world function
- added new get closest parking spot function
SPAWN:
- updated SpawnAtAirbase function to use getparking wrapper function.
DCS:
- updated country.id list
AIRBASE:
- Added Persion Gulf map airports
- Added wrapper function for new DCS API getparking() function.
2018-06-25 22:38:47 +02:00
Van De Velde
3ed9555705 Revert "Merge pull request #929 from Lugghawk/918_Fix_FindByName_Error_Flag"
This reverts commit d6cdc098ce, reversing
changes made to 6b04237a3f.
2018-06-24 20:47:41 +02:00
Sven Van de Velde
17e9538740 Merge pull request #927 from jtoppins/code-cleanup
cleanup: remove unreferenced variables
2018-06-24 09:20:19 +02:00
Sven Van de Velde
d6cdc098ce Merge pull request #929 from Lugghawk/918_Fix_FindByName_Error_Flag
Error flag fixed.
2018-06-24 09:11:50 +02:00
FlightControl-User
6b04237a3f Fixed Offset issue. 2018-06-24 08:49:36 +02:00
Van De Velde
07aff74126 Merge branch 'develop' of https://github.com/FlightControl-Master/MOOSE into develop 2018-06-22 05:59:45 +02:00
Van De Velde
ea89c6255b Documentation improvements 2018-06-22 05:59:28 +02:00
Frank
18450acea1 Merge pull request #931 from FlightControl-Master/FF/Develop
Min fuel behavior
2018-06-20 20:28:12 +02:00
funkyfranky
7d90a94927 ARTY
Updated docs.
Added SetSpeed() function.
2018-06-19 23:10:08 +02:00
funkyfranky
82d40759b5 Get Fuel Min
AI_A2A_Dispatcher
Changed tac display from ave fuel to min fuel
2018-06-18 23:55:31 +02:00
funkyfranky
19197bf234 Min Fuel Fixes
AI_A2A and AI_Patrol:
Changed average fuel for controllable to new min fuel function. Hopefully provides better RTB behavior.

CONTROLLABLE:
Added GetFuelMin and GetFuelAve functions to ensure polymorphic behavior.

UNIT:
Added GetFuelMin and GetFuelAve functions for completeness and potential polymorphism.
2018-06-18 23:13:21 +02:00
Jonathan Toppins
64c4d57a7b cleanup: remove unreferenced variables
PatrolManageFuel seems to have been forgotten after a code refactor
in commit ce0be4dcf7 ("Fixing TASK_DISPATCHER and optimizing reports")

$ git rev-parse --show-toplevel
projects/moose
$ pwd
projects/moose
$ git grep "PatrolManageFuel"
Moose Development/Moose/AI/AI_A2A.lua:  self.PatrolManageFuel = true
Moose Development/Moose/AI/AI_Patrol.lua:  self.PatrolManageFuel = true

Signed-off-by: Jonathan Toppins <jtoppins@users.sourceforge.net>
2018-06-18 16:05:35 -04:00
Frank
99963c28e9 Merge pull request #923 from ezietsman/feature/zone-unit-offsets
Feature/zone unit offsets
2018-06-18 19:58:41 +02:00
Frank
9360513831 Merge pull request #928 from jtoppins/fix-group-getfuel
GROUP: modify GetFuel to return the minimum
2018-06-18 19:53:58 +02:00
Jonathan Toppins
20c1f6bab4 GROUP: provide a new GetFuelMin() method
Taking the average fuel available across an entire flight is not really
realistic and does not present an accurate representation of if a group
needs to be sent to refuel or rtb.

An example, a flight of 2 planes; plane 1 has 45% and plane 2 has 25%
(45 + 25)/2 = 35, and 25% is the RTB threshold, plane 2 needs to go home
now. However with the current averaging function plane 2 will have as
little as 15% fuel (assume equal consumption) before the flight
gets ordered home.

Signed-off-by: Jonathan Toppins <jtoppins@users.sourceforge.net>
2018-06-18 12:52:42 -04:00
Dave Lugg
6bdf0122e4 Error flag fixed. 2018-06-18 12:48:27 -04:00
FlightControl_Master
16b279c5db Documentation first version 2018-06-17 07:38:02 +02:00
Frank
5290ad8b2e Merge pull request #924 from FlightControl-Master/FF/Develop
ARTY v1.0.4
2018-06-16 19:10:47 +02:00
funkyfranky
8c76314884 Merge branch 'develop' into FF/Develop 2018-06-16 19:03:58 +02:00
funkyfranky
79d8113df3 ARTY v1.0.4
Minor adjustments.
Fixed bug that coordinates from mark points are always at an altitude of 5 meters.
2018-06-16 19:03:44 +02:00
Ewald Zietsman
601c00e637 Merge branch 'develop' into feature/zone-unit-offsets 2018-06-16 15:39:14 +02:00
Ewald Zietsman
58e5ffa283 Changed offsets argument to use a table for clarity. 2018-06-16 15:33:59 +02:00
Ewald Zietsman
ec0b32321a Added Rho/Theta offset handling to ZoneUnit 2018-06-15 19:58:26 +02:00
funkyfranky
ca2eec8878 ARTY v1.0.3
Fixed bug in illu and smoke shell impementation.
2018-06-15 00:07:35 +02:00
funkyfranky
851c55e985 ARTY v1.0.3 buggy
something wrong with nuke, illu smoke
2018-06-13 23:00:05 +02:00
funkyfranky
6c9c4432cc ARTY v1.0.3
Added "set" mark commands for rearming place and rearming group.
2018-06-13 00:12:26 +02:00
Frank
5c7312cd41 Merge pull request #914 from alexproust/patch-1
Update Routines.lua
2018-06-12 23:15:46 +02:00
Frank
6bce3ebb8b Merge pull request #919 from FlightControl-Master/FF/Develop
ARTY v1.0.2
2018-06-12 23:13:23 +02:00
funkyfranky
89e67ba54d ARTY v1.0.2
Changed behavior that if no arty group is addressed explicitly, nothing is happening. Before all groups were addressed.
2018-06-12 19:50:21 +02:00
Frank
e5c481c161 Merge pull request #917 from FlightControl-Master/FF/Develop
ARTY v1.0.1
2018-06-11 20:38:55 +02:00
funkyfranky
3fee4a87da ARTY v1.0.1
Added cluster and alias assignment via marks.
2018-06-11 20:29:58 +02:00
Frank
87a13f3784 Merge pull request #915 from FlightControl-Master/FF/Develop
ARTY v1.0.0
2018-06-11 09:01:28 +02:00
funkyfranky
d5d2de7577 Controllable alarm state
ships don't have option to change alarm state to other than green
2018-06-10 23:41:07 +02:00
funkyfranky
8241f9de60 Merge branch 'develop' into FF/Develop 2018-06-10 23:36:20 +02:00
funkyfranky
ba2d359af2 ARTY 1.0.0
- Added pseudo functions for FMS states.
- Fixed a few bugs.
2018-06-10 23:35:22 +02:00
gunterlund
5ebf0b8d6c Merge remote-tracking branch 'refs/remotes/origin/master' into develop 2018-06-10 07:13:46 -07:00
Ewald Zietsman
804b8a800e Added basic offset support to ZoneUnit 2018-06-10 01:46:22 +02:00
funkyfranky
e8ff153427 ARTY v0.9.96
Improved marker logic.
2018-06-10 00:05:55 +02:00
funkyfranky
403f22bd2b ARTY v0.9.95
Reworked rearming behavior for selected weapons.
Many other improvements.
2018-06-09 18:33:20 +02:00
funkyfranky
c6fc571c95 ARTY
adjusted docu
some improvemens
2018-06-08 00:00:41 +02:00
alexproust
8b3d7ebf04 Update Routines.lua
Correction MessageToBlue function
2018-06-07 12:57:10 +02:00
funkyfranky
38a03f4cbc ARTY v0.9.94
Bug fixes and improvements.
2018-06-06 22:57:04 +02:00
funkyfranky
a2790f500c ARTY v0.9.93
added new mark parameters
LLDMS coordinate assignment
2018-06-06 00:51:59 +02:00
funkyfranky
927ae59f75 Merge branch 'develop' into FF/Develop 2018-06-05 00:29:06 +02:00
funkyfranky
8b667071b7 ARTY v0.9.92
- adjusted DB
- other minor fixes and improvements
2018-06-05 00:28:52 +02:00
funkyfranky
0a34cfdafa ARTY v0.9.91
- Added automatic relocation if not in firing range.
- Added first version of ARTY DB with artillery unit parameters min/max firing range.
2018-06-03 23:38:15 +02:00
FlightControl_Master
2d43af7c0d docu 2018-06-03 22:02:26 +02:00
FlightControl_Master
83fab80d88 Updated documentation. 2018-06-03 21:50:07 +02:00
FlightControl_Master
6a71921270 Documentation AI 2018-06-03 18:07:00 +02:00
funkyfranky
8ff3530916 Merge branch 'develop' into FF/Develop 2018-06-03 09:40:46 +02:00
FlightControl_Master
bd7c822def Documentation 2018-06-03 09:14:27 +02:00
FlightControl_Master
7b3f84f468 orbit with speed 2018-06-03 08:05:42 +02:00
funkyfranky
bf7523fa85 messages clearsceen 2018-06-03 01:00:16 +02:00
funkyfranky
0d246d3f49 ARTY v0.9.9
ARTY:
Fixed CTD bug. Caused by group:ClearTasks() when no task is assigned (group arrived).
Many other improvements
Cleared up function location.
MESSAGES:
Added optional clear screen parameter.
2018-06-03 00:58:24 +02:00
funkyfranky
e9a055219e ARTY v0.9.8-buggy
Improved marker assignments.
There is a bug that makes DCS crash when a group is ordered to move and reaches its destination, i.e. arrives.
2018-06-02 19:13:26 +02:00
FlightControl_Master
d9d53db53f Documentation improvements. 2018-06-02 18:23:06 +02:00
FlightControl_Master
e9473e9179 Documentation improvements 2018-06-02 07:25:43 +02:00
funkyfranky
0b95930674 ARTY v0.9.8
Improved maker targets and moves assignments.
Removed env.info()
2018-06-01 23:51:53 +02:00
FlightControl_Master
43a4052dc8 Documentation cleanup 2018-06-01 16:00:42 +02:00
FlightControl_Master
18098d402b Documentation updates 2018-06-01 10:59:53 +02:00
FlightControl_Master
f556077ff6 Cleanup 2018-06-01 06:52:36 +02:00
funkyfranky
da452ed8ce ARTY v0.9.7
Improved Mark Target Assignments.
Improved documentation.
2018-05-30 21:17:09 +02:00
funkyfranky
9d62c60071 Merge branch 'develop' into FF/Develop 2018-05-30 00:40:09 +02:00
funkyfranky
fd4d7f49a5 ARTY v0.9.6
Added first WIP version with Markers.
2018-05-30 00:39:43 +02:00
FlightControl_Master
43b320ca90 New versions with documentation 2018-05-29 22:34:33 +02:00
funkyfranky
ae4d4ca97d Merge branch 'develop' into FF/Develop 2018-05-28 22:19:48 +02:00
funkyfranky
b6ac79a9df ARTY Mark WIP 2018-05-28 22:19:35 +02:00
FlightControl_Master
f03f9a3308 Landing event made a bit more loose. 2018-05-28 20:03:35 +02:00
Frank
d4fead8294 Merge pull request #910 from FlightControl-Master/FF/Develop
ARTY v0.95
2018-05-28 17:09:20 +02:00
funkyfranky
1861e742b0 ARTY v0.9.5
Added/fixed relocate option
2018-05-28 17:07:55 +02:00
Frank
d11d4e09a4 Merge pull request #909 from FlightControl-Master/FF/Develop
ARTY v0.9.4
2018-05-28 16:54:00 +02:00
funkyfranky
8927504801 Minor 2018-05-28 16:51:01 +02:00
funkyfranky
cb6673332d ARTY v0.9.4
ARTY: improved outofammo/rearming behaviour
2018-05-28 16:47:32 +02:00
funkyfranky
21ce0cac8d ARTY v0.9.3
ARTY:
- Improved tac nukes implementation. Added user functions.
- Added relocation option after engagements.
COORDINATE:
- Added get surface type function.
2018-05-28 14:38:04 +02:00
funkyfranky
7ce20d92cb Merge branch 'develop' into FF/Develop 2018-05-28 08:22:58 +02:00
FlightControl_Master
c5dcd63dea Updated Settings documentation. 2018-05-28 06:39:41 +02:00
FlightControl_Master
0553e4b14e Fixing AI_CARGO_HELICOPTER to interprete the real height correctly and also allow for pickup when the helo is still speeding more than 7 km/h. 2018-05-28 06:13:14 +02:00
funkyfranky
6dc4a122f3 Merge branch 'develop' into FF/Develop 2018-05-28 00:37:45 +02:00
funkyfranky
4941b5ee98 ARTY v0.9.2
Added tactical nukes.
2018-05-28 00:33:58 +02:00
Frank
4c5d5a32dc Merge pull request #905 from FlightControl-Master/FF/Develop
RANGE v1.2 and "Speed"
2018-05-27 22:21:33 +02:00
FlightControl_Master
073bfbf9c9 Documentation Improvements 2018-05-27 08:57:44 +02:00
funkyfranky
950c121f38 Merge branch 'develop' into FF/Develop 2018-05-26 14:56:33 +02:00
funkyfranky
ad75a7ddb5 RANGE v1.2 and other changes
RANGE:
-Optimized performance. Bombs are now only tracked if the player is within a certain distance of the range.

CONTROLLABLE:
- Added speed unit to @param description. Sometimes it was unclear if speed needs to be given in m/s or km/h.
- Fixed some default speed and conversions.
COORDINATE:
- Cleaned up some speed unit stuff.
- Reintroduced PathOnRoad function to contain the full path. Useful as interface to DCS API function.
- Fixed some default speed and conversions.

AI_CARGO_APC:
Speed is not fixed any more but set to 50% of the max speed a given unit can move at.
2018-05-26 14:46:23 +02:00
FlightControl_Master
11516228fa First images 2018-05-26 10:56:22 +02:00
funkyfranky
d98f207bcf Merge branch 'develop' into FF/Develop 2018-05-24 19:39:48 +02:00
funkyfranky
369ea08fd1 Minor changes
ARTY corrected MISSILE category.
2018-05-24 19:36:53 +02:00
Sven Van de Velde
7013db0b67 Merge pull request #904 from Kalbuth/Kalbuth/RADIO-Fix
Fix for RADIO:NewUnitTransmission wrong method call - Issue #897
2018-05-23 13:55:55 +02:00
FlightControl_Master
5e2a5cf5e8 Tasking and Functional 2018-05-23 13:51:47 +02:00
FlightControl_Master
1b39f5d6e6 Optimized comments and documentation set 2018-05-23 10:42:27 +02:00
Kalbuth
b560aaa147 Fix for RADIO:NewUnitTransmission wrong method call - Issue #897 2018-05-23 08:30:50 +02:00
funkyfranky
9585959431 Merge branch 'develop' into FF/Develop 2018-05-22 17:03:35 +02:00
FlightControl_Master
fe2f59660d AI test 2018-05-22 11:15:51 +02:00
FlightControl_Master
e78cd56752 Core modules 2018-05-21 22:51:43 +02:00
FlightControl_Master
3d48dee23f 2.4.a 2018-05-21 22:42:28 +02:00
FlightControl_Master
51192f9a4c moose-docs 2018-05-21 22:39:05 +02:00
FlightControl_Master
9dc329f151 New version 2018-05-21 22:37:12 +02:00
FlightControl_Master
6a4741d0dc New version 2018-05-21 22:34:19 +02:00
Frank
25e4d171ab Added GetSpeedMax function 2018-05-21 21:43:19 +02:00
FlightControl_Master
be48f7751c Test 2018-05-21 20:39:13 +02:00
Frank
f7403758ce Merge branch 'develop' into FF/Develop 2018-05-21 17:49:00 +02:00
FlightControl_Master
d8a189b1fd Finish ZONE_tags 2018-05-21 09:02:15 +02:00
Frank
5bde59b7e3 Merge branch 'develop' into FF/Develop 2018-05-20 09:54:38 +02:00
FlightControl_Master
adbbeafef9 Removed one obscolete line. 2018-05-20 09:08:34 +02:00
FlightControl_Master
3d5fbdf42d Fixed the new events
- S_EVENT_MARK_ADDED
- S_EVENT_MARK_CHANGE
- S_EVENT_MARK_REMOVED
2018-05-20 08:59:20 +02:00
FlightControl_Master
a408f45078 Fixed the new events
- S_EVENT_MARK_ADDED
- S_EVENT_MARK_CHANGE
- S_EVENT_MARK_REMOVED
2018-05-20 08:59:18 +02:00
FlightControl_Master
c1fb803780 Fixed the new events
- S_EVENT_MARK_ADDED
- S_EVENT_MARK_CHANGE
- S_EVENT_MARK_DELETED
2018-05-20 08:58:54 +02:00
FlightControl_Master
0b378063c0 - Fixed infantry deploying when helicopter was hit.
- Fixed further landing coordinate lockups.
2018-05-20 08:37:02 +02:00
Frank
0d6117e5b4 Merge branch 'develop' into FF/Develop 2018-05-19 09:53:49 +02:00
FlightControl_Master
cdecf4a4c9 Finish Cargo/AI_Cargo_Helicopter 2018-05-19 08:08:08 +02:00
FlightControl_Master
d5d5d52bd5 Added Task Status Change Events as part of Dispatcher logic!!!! This is great! 2018-05-19 06:55:19 +02:00
FlightControl_Master
d05973f487 Finish Cargo/AI_Cargo_Helicopter 2018-05-19 06:12:37 +02:00
Frank
623c907900 Merge branch 'develop' into FF/Develop 2018-05-18 20:55:01 +02:00
FlightControl_Master
d07d063265 Removed Start(). Now Start() needs to be called outside the logic. 2018-05-17 10:24:59 +02:00
FlightControl_Master
533b5d035e - Documentation
- Added the methods Added and Removed to the SET
- Cleanup of code.
2018-05-17 08:51:59 +02:00
FlightControl_Master
b82e85997f # Conflicts:
#	Moose Development/Moose/Core/Zone.lua
2018-05-15 19:13:11 +02:00
FlightControl_Master
4309aa326f Finish Cargo/AI_Cargo_Helicopter 2018-05-15 19:06:55 +02:00
FlightControl_Master
ac72e6fad2 Zone probability implementation. 2018-05-15 19:02:17 +02:00
FlightControl_Master
48384ac758 Added the dynamic creation of a SET_ZONE, but you still need to declare all zones within the mission script. 2018-05-14 08:12:15 +02:00
FlightControl_Master
7598a6ce5c Finish Cargo/AI_Cargo_Helicopter 2018-05-14 06:53:45 +02:00
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
funkyfranky
000d7d3ce2 Merge branch 'develop' into FF/Develop 2018-05-12 22:32:39 +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
Sven Van de Velde
74d2ee9430 Improvements 2018-03-25 20:49:49 +02:00
Sven Van de Velde
856bd56cde Improved dynamic loading 2018-03-25 20:33:43 +02:00
Sven Van de Velde
4c91880a85 Improved dynamic loader process 2018-03-25 20:27:18 +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
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
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
833 changed files with 124862 additions and 297953 deletions

85
.appveyor/appveyor.yml Normal file
View File

@@ -0,0 +1,85 @@
version: 2.4.a.{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' -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-docs'; branch = "$env:appveyor_repo_branch"; 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,214 @@
--- **AI** -- (R2.2) - Models the process of Combat Air Patrol (CAP) for airplanes.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_A2A_Cap
-- @image AI_Combat_Air_Patrol.JPG
--- @type AI_A2A_CAP
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
--- The AI_A2A_CAP class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.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 @{Wrapper.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.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
-- * **@{AI.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.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
-- * **@{#AI_A2A_CAP.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
-- * **@{#AI_A2A_CAP.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
--
-- ## 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.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.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 DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
-- @return #AI_A2A_CAP
function AI_A2A_CAP:New2( AICap, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, PatrolZone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType )
-- Multiple inheritance ... :-)
local AI_Air = AI_AIR:New( AICap )
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL
local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AICap, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
local self = BASE:Inherit( self, AI_Air_Engage )
self:SetFuelThreshold( .2, 60 )
self:SetDamageThreshold( 0.4 )
self:SetDisengageRadius( 70000 )
return self
end
--- 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#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#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 )
return self:New2( AICap, EngageMinSpeed, EngageMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolZone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, PatrolAltType )
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:onafterStart( AICap, From, Event, To )
self:GetParent( self, AI_A2A_CAP ).onafterStart( self, 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
--- Evaluate the attack and create an AttackUnitTask list.
-- @param #AI_A2A_CAP self
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders.
-- @param #number EngageAltitude The altitude to engage the targets.
-- @return #AI_A2A_CAP self
function AI_A2A_CAP:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
local AttackUnitTasks = {}
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
-- TODO: Add coalition check? Only attack units of if AttackUnit:GetCoalition()~=AICap:GetCoalition()
-- Maybe the detected set also contains
self:T( { "Attacking Task:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsAir() } )
AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit )
end
end
return AttackUnitTasks
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,178 @@
--- **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.AI_A2A_GCI
-- @image AI_Ground_Control_Intercept.JPG
--- @type AI_A2A_GCI
-- @extends AI.AI_A2A#AI_A2A
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
--
-- ![Process](..\Presentations\AI_GCI\Dia3.JPG)
--
-- The AI_A2A_GCI is assigned a @{Wrapper.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.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
-- * **@{AI.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.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
-- * **@{#AI_A2A_GCI.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
-- * **@{#AI_A2A_GCI.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
--
-- ## 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.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.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
-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
-- @return #AI_A2A_GCI
function AI_A2A_GCI:New2( AIIntercept, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
local AI_Air = AI_AIR:New( AIIntercept )
local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air, AIIntercept, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
local self = BASE:Inherit( self, AI_Air_Engage ) -- #AI_A2A_GCI
self:SetFuelThreshold( .2, 60 )
self:SetDamageThreshold( 0.4 )
self:SetDisengageRadius( 70000 )
return self
end
--- Creates a new AI_A2A_GCI object
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept
-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
-- @return #AI_A2A_GCI
function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
return self:New2( AIIntercept, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
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 )
self:GetParent( self, AI_A2A_GCI ).onafterStart( self, AIIntercept, From, Event, To )
end
--- Evaluate the attack and create an AttackUnitTask list.
-- @param #AI_A2A_GCI self
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders.
-- @param #number EngageAltitude The altitude to engage the targets.
-- @return #AI_A2A_GCI self
function AI_A2A_GCI:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
local AttackUnitTasks = {}
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
-- TODO: Add coalition check? Only attack units of if AttackUnit:GetCoalition()~=AICap:GetCoalition()
-- Maybe the detected set also contains
AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit )
end
end
return AttackUnitTasks
end

View File

@@ -0,0 +1,405 @@
--- **AI** -- (R2.2) - Models the process of air patrol of airplanes.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_A2A_Patrol
-- @image AI_Air_Patrolling.JPG
--- @type AI_A2A_PATROL
-- @extends AI.AI_A2A#AI_A2A
--- Implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}.
--
-- ![Process](..\Presentations\AI_PATROL\Dia3.JPG)
--
-- The AI_A2A_PATROL is assigned a @{Wrapper.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 @{Wrapper.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#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#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 )
local AI_Air = AI_AIR:New( AIPatrol )
local AI_Air_Patrol = AI_A2A_PATROL:New( AI_Air, AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
local self = BASE:Inherit( self, AI_Air_Patrol ) -- #AI_A2A_PATROL
self:SetFuelThreshold( .2, 60 )
self:SetDamageThreshold( 0.4 )
self:SetDisengageRadius( 70000 )
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#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.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#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCS#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 and AIPatrol:IsAlive() then
local PatrolRoute = {}
--- Calculate the target route point.
local CurrentCoord = AIPatrol:GetCoordinate()
-- Random altitude.
local altitude=math.random(self.PatrolFloorAltitude, self.PatrolCeilingAltitude)
-- Random speed in km/h.
local speedkmh = math.random(self.PatrolMinSpeed, self.PatrolMaxSpeed)
-- First waypoint is current position.
PatrolRoute[1]=CurrentCoord:WaypointAirTurningPoint(nil, speedkmh, {}, "Current")
if self.racetrack then
-- Random heading.
local heading = math.random(self.racetrackheadingmin, self.racetrackheadingmax)
-- Random leg length.
local leg=math.random(self.racetracklegmin, self.racetracklegmax)
-- Random duration if any.
local duration = self.racetrackdurationmin
if self.racetrackdurationmax then
duration=math.random(self.racetrackdurationmin, self.racetrackdurationmax)
end
-- CAP coordinate.
local c0=self.PatrolZone:GetRandomCoordinate()
if self.racetrackcapcoordinates and #self.racetrackcapcoordinates>0 then
c0=self.racetrackcapcoordinates[math.random(#self.racetrackcapcoordinates)]
end
-- Race track points.
local c1=c0:SetAltitude(altitude) --Core.Point#COORDINATE
local c2=c1:Translate(leg, heading):SetAltitude(altitude)
self:SetTargetDistance(c0) -- For RTB status check
-- Debug:
self:T(string.format("Patrol zone race track: v=%.1f knots, h=%.1f ft, heading=%03d, leg=%d m, t=%s sec", UTILS.KmphToKnots(speedkmh), UTILS.MetersToFeet(altitude), heading, leg, tostring(duration)))
--c1:MarkToAll("Race track c1")
--c2:MarkToAll("Race track c2")
-- Task to orbit.
local taskOrbit=AIPatrol:TaskOrbit(c1, altitude, UTILS.KmphToMps(speedkmh), c2)
-- Task function to redo the patrol at other random position.
local taskPatrol=AIPatrol:TaskFunction("AI_A2A_PATROL.PatrolRoute", self)
-- Controlled task with task condition.
local taskCond=AIPatrol:TaskCondition(nil, nil, nil, nil, duration, nil)
local taskCont=AIPatrol:TaskControlled(taskOrbit, taskCond)
-- Second waypoint
PatrolRoute[2]=c1:WaypointAirTurningPoint(self.PatrolAltType, speedkmh, {taskCont, taskPatrol}, "CAP Orbit")
else
-- Target coordinate.
local ToTargetCoord=self.PatrolZone:GetRandomCoordinate() --Core.Point#COORDINATE
ToTargetCoord:SetAltitude(altitude)
self:SetTargetDistance( ToTargetCoord ) -- For RTB status check
local taskReRoute=AIPatrol:TaskFunction( "AI_A2A_PATROL.PatrolRoute", self )
PatrolRoute[2]=ToTargetCoord:WaypointAirTurningPoint(self.PatrolAltType, speedkmh, {taskReRoute}, "Patrol Point")
end
-- ROE
AIPatrol:OptionROEReturnFire()
AIPatrol:OptionROTEvadeFire()
-- Patrol.
AIPatrol:Route( PatrolRoute, 0.5)
end
end

View File

@@ -0,0 +1,99 @@
--- **AI** -- Models the process of air to ground BAI engagement for airplanes and helicopters.
--
-- This is a class used in the @{AI_A2G_Dispatcher}.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_A2G_BAI
-- @image AI_Air_To_Ground_Engage.JPG
--- @type AI_A2G_BAI
-- @extends AI.AI_A2A_Engage#AI_A2A_Engage
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
--
-- ===
--
-- @field #AI_A2G_BAI
AI_A2G_BAI = {
ClassName = "AI_A2G_BAI",
}
--- Creates a new AI_A2G_BAI object
-- @param #AI_A2G_BAI self
-- @param Wrapper.Group#GROUP AIGroup
-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @return #AI_A2G_BAI
function AI_A2G_BAI:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
local AI_Air = AI_AIR:New( AIGroup )
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL
local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
local self = BASE:Inherit( self, AI_Air_Engage )
return self
end
--- Creates a new AI_A2G_BAI object
-- @param #AI_A2G_BAI self
-- @param Wrapper.Group#GROUP AIGroup
-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @return #AI_A2G_BAI
function AI_A2G_BAI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
return self:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType)
end
--- Evaluate the attack and create an AttackUnitTask list.
-- @param #AI_A2G_BAI self
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders.
-- @param #number EngageAltitude The altitude to engage the targets.
-- @return #AI_A2G_BAI self
function AI_A2G_BAI:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
local AttackUnitTasks = {}
local AttackSetUnitPerThreatLevel = AttackSetUnit:GetSetPerThreatLevel( 10, 0 )
for AttackUnitIndex, AttackUnit in ipairs( AttackSetUnitPerThreatLevel or {} ) do
if AttackUnit then
if AttackUnit:IsAlive() and AttackUnit:IsGround() then
self:T( { "BAI Unit:", AttackUnit:GetName() } )
AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit, true, false, nil, nil, EngageAltitude )
end
end
end
return AttackUnitTasks
end

View File

@@ -0,0 +1,100 @@
--- **AI** -- Models the process of air to ground engagement for airplanes and helicopters.
--
-- This is a class used in the @{AI_A2G_Dispatcher}.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_A2G_CAS
-- @image AI_Air_To_Ground_Engage.JPG
--- @type AI_A2G_CAS
-- @extends AI.AI_A2G_Patrol#AI_AIR_PATROL
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
--
-- ===
--
-- @field #AI_A2G_CAS
AI_A2G_CAS = {
ClassName = "AI_A2G_CAS",
}
--- Creates a new AI_A2G_CAS object
-- @param #AI_A2G_CAS self
-- @param Wrapper.Group#GROUP AIGroup
-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @return #AI_A2G_CAS
function AI_A2G_CAS:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
local AI_Air = AI_AIR:New( AIGroup )
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL
local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
local self = BASE:Inherit( self, AI_Air_Engage )
return self
end
--- Creates a new AI_A2G_CAS object
-- @param #AI_A2G_CAS self
-- @param Wrapper.Group#GROUP AIGroup
-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @return #AI_A2G_CAS
function AI_A2G_CAS:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
return self:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType)
end
--- Evaluate the attack and create an AttackUnitTask list.
-- @param #AI_A2G_CAS self
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders.
-- @param #number EngageAltitude The altitude to engage the targets.
-- @return #AI_A2G_CAS self
function AI_A2G_CAS:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
local AttackUnitTasks = {}
local AttackSetUnitPerThreatLevel = AttackSetUnit:GetSetPerThreatLevel( 10, 0 )
for AttackUnitIndex, AttackUnit in ipairs( AttackSetUnitPerThreatLevel or {} ) do
if AttackUnit then
if AttackUnit:IsAlive() and AttackUnit:IsGround() then
self:T( { "CAS Unit:", AttackUnit:GetName() } )
AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit, true, false, nil, nil, EngageAltitude )
end
end
end
return AttackUnitTasks
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,152 @@
--- **AI** -- Models the process of air to ground SEAD engagement for airplanes and helicopters.
--
-- This is a class used in the @{AI_A2G_Dispatcher}.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_A2G_SEAD
-- @image AI_Air_To_Ground_Engage.JPG
--- @type AI_A2G_SEAD
-- @extends AI.AI_A2G_Patrol#AI_AIR_PATROL
--- Implements the core functions to SEAD intruders. Use the Engage trigger to intercept intruders.
--
-- ![Process](..\Presentations\AI_GCI\Dia3.JPG)
--
-- The AI_A2G_SEAD is assigned a @{Wrapper.Group} and this must be done before the AI_A2G_SEAD 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_A2G_SEAD constructor
--
-- * @{#AI_A2G_SEAD.New}(): Creates a new AI_A2G_SEAD object.
--
-- ## 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.AI_GCI#AI_A2G_SEAD.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.AI_Cap#AI_A2G_SEAD.SetEngageZone}() to define that Zone.
--
-- ===
--
-- @field #AI_A2G_SEAD
AI_A2G_SEAD = {
ClassName = "AI_A2G_SEAD",
}
--- Creates a new AI_A2G_SEAD object
-- @param #AI_A2G_SEAD self
-- @param Wrapper.Group#GROUP AIGroup
-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @return #AI_A2G_SEAD
function AI_A2G_SEAD:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
local AI_Air = AI_AIR:New( AIGroup )
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL
local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
local self = BASE:Inherit( self, AI_Air_Engage )
return self
end
--- Creates a new AI_A2G_SEAD object
-- @param #AI_A2G_SEAD self
-- @param Wrapper.Group#GROUP AIGroup
-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @return #AI_A2G_SEAD
function AI_A2G_SEAD:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
return self:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
end
--- Evaluate the attack and create an AttackUnitTask list.
-- @param #AI_A2G_SEAD self
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders.
-- @param #number EngageAltitude The altitude to engage the targets.
-- @return #AI_A2G_SEAD self
function AI_A2G_SEAD:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
local AttackUnitTasks = {}
local AttackSetUnitPerThreatLevel = AttackSetUnit:GetSetPerThreatLevel( 10, 0 )
for AttackUnitID, AttackUnit in ipairs( AttackSetUnitPerThreatLevel ) do
if AttackUnit then
if AttackUnit:IsAlive() and AttackUnit:IsGround() then
local HasRadar = AttackUnit:HasSEAD()
if HasRadar then
self:F( { "SEAD Unit:", AttackUnit:GetName() } )
AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit, true, false, nil, nil, EngageAltitude )
end
end
end
end
return AttackUnitTasks
end

View File

@@ -0,0 +1,800 @@
--- **AI** -- Models the process of AI air operations.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_Air
-- @image MOOSE.JPG
--- @type AI_AIR
-- @extends Core.Fsm#FSM_CONTROLLABLE
--- The AI_AIR class implements the core functions to operate an AI @{Wrapper.Group}.
--
--
-- # 1) AI_AIR constructor
--
-- * @{#AI_AIR.New}(): Creates a new AI_AIR object.
--
-- # 2) AI_AIR is a Finite State Machine.
--
-- This section must be read as follows. Each of the rows indicate a state transition, triggered through an event, and with an ending state of the event was executed.
-- The first column is the **From** state, the second column the **Event**, and the third column the **To** state.
--
-- So, each of the rows have the following structure.
--
-- * **From** => **Event** => **To**
--
-- Important to know is that an event can only be executed if the **current state** is the **From** state.
-- This, when an **Event** that is being triggered has a **From** state that is equal to the **Current** state of the state machine, the event will be executed,
-- and the resulting state will be the **To** state.
--
-- These are the different possible state transitions of this state machine implementation:
--
-- * Idle => Start => Monitoring
--
-- ## 2.1) AI_AIR States.
--
-- * **Idle**: The process is idle.
--
-- ## 2.2) AI_AIR Events.
--
-- * **Start**: Start the transport process.
-- * **Stop**: Stop the transport process.
-- * **Monitor**: Monitor and take action.
--
-- @field #AI_AIR
AI_AIR = {
ClassName = "AI_AIR",
}
AI_AIR.TaskDelay = 0.5 -- The delay of each task given to the AI.
--- Creates a new AI_AIR process.
-- @param #AI_AIR self
-- @param Wrapper.Group#GROUP AIGroup The group object to receive the A2G Process.
-- @return #AI_AIR
function AI_AIR:New( AIGroup )
-- Inherits from BASE
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_AIR
self:SetControllable( AIGroup )
self:SetStartState( "Stopped" )
self:AddTransition( "*", "Queue", "Queued" )
self:AddTransition( "*", "Start", "Started" )
--- Start Handler OnBefore for AI_AIR
-- @function [parent=#AI_AIR] OnBeforeStart
-- @param #AI_AIR self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Start Handler OnAfter for AI_AIR
-- @function [parent=#AI_AIR] OnAfterStart
-- @param #AI_AIR self
-- @param #string From
-- @param #string Event
-- @param #string To
--- Start Trigger for AI_AIR
-- @function [parent=#AI_AIR] Start
-- @param #AI_AIR self
--- Start Asynchronous Trigger for AI_AIR
-- @function [parent=#AI_AIR] __Start
-- @param #AI_AIR self
-- @param #number Delay
self:AddTransition( "*", "Stop", "Stopped" )
--- OnLeave Transition Handler for State Stopped.
-- @function [parent=#AI_AIR] OnLeaveStopped
-- @param #AI_AIR 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_AIR] OnEnterStopped
-- @param #AI_AIR 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_AIR] OnBeforeStop
-- @param #AI_AIR 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_AIR] OnAfterStop
-- @param #AI_AIR 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_AIR] Stop
-- @param #AI_AIR self
--- Asynchronous Event Trigger for Event Stop.
-- @function [parent=#AI_AIR] __Stop
-- @param #AI_AIR self
-- @param #number Delay The delay in seconds.
self:AddTransition( "*", "Status", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR.
--- OnBefore Transition Handler for Event Status.
-- @function [parent=#AI_AIR] OnBeforeStatus
-- @param #AI_AIR 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_AIR] OnAfterStatus
-- @param #AI_AIR 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_AIR] Status
-- @param #AI_AIR self
--- Asynchronous Event Trigger for Event Status.
-- @function [parent=#AI_AIR] __Status
-- @param #AI_AIR self
-- @param #number Delay The delay in seconds.
self:AddTransition( "*", "RTB", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR.
--- OnBefore Transition Handler for Event RTB.
-- @function [parent=#AI_AIR] OnBeforeRTB
-- @param #AI_AIR 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_AIR] OnAfterRTB
-- @param #AI_AIR 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_AIR] RTB
-- @param #AI_AIR self
--- Asynchronous Event Trigger for Event RTB.
-- @function [parent=#AI_AIR] __RTB
-- @param #AI_AIR self
-- @param #number Delay The delay in seconds.
--- OnLeave Transition Handler for State Returning.
-- @function [parent=#AI_AIR] OnLeaveReturning
-- @param #AI_AIR 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_AIR] OnEnterReturning
-- @param #AI_AIR 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_AIR
-- @function [parent=#AI_AIR] OnBeforeRefuel
-- @param #AI_AIR 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_AIR
-- @function [parent=#AI_AIR] OnAfterRefuel
-- @param #AI_AIR 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_AIR
-- @function [parent=#AI_AIR] Refuel
-- @param #AI_AIR self
--- Refuel Asynchronous Trigger for AI_AIR
-- @function [parent=#AI_AIR] __Refuel
-- @param #AI_AIR 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_AIR:SetDispatcher( Dispatcher )
self.Dispatcher = Dispatcher
end
function AI_AIR:GetDispatcher()
return self.Dispatcher
end
function AI_AIR: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_AIR:ClearTargetDistance()
self.TargetDistance = nil
self.ClosestTargetDistance = nil
end
--- Sets (modifies) the minimum and maximum speed of the patrol.
-- @param #AI_AIR self
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h.
-- @return #AI_AIR self
function AI_AIR:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
self.PatrolMinSpeed = PatrolMinSpeed
self.PatrolMaxSpeed = PatrolMaxSpeed
end
--- Sets (modifies) the minimum and maximum RTB speed of the patrol.
-- @param #AI_AIR self
-- @param DCS#Speed RTBMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
-- @param DCS#Speed RTBMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h.
-- @return #AI_AIR self
function AI_AIR:SetRTBSpeed( RTBMinSpeed, RTBMaxSpeed )
self:F( { RTBMinSpeed, RTBMaxSpeed } )
self.RTBMinSpeed = RTBMinSpeed
self.RTBMaxSpeed = RTBMaxSpeed
end
--- Sets the floor and ceiling altitude of the patrol.
-- @param #AI_AIR self
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @return #AI_AIR self
function AI_AIR:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } )
self.PatrolFloorAltitude = PatrolFloorAltitude
self.PatrolCeilingAltitude = PatrolCeilingAltitude
end
--- Sets the home airbase.
-- @param #AI_AIR self
-- @param Wrapper.Airbase#AIRBASE HomeAirbase
-- @return #AI_AIR self
function AI_AIR:SetHomeAirbase( HomeAirbase )
self:F2( { HomeAirbase } )
self.HomeAirbase = HomeAirbase
end
--- Sets to refuel at the given tanker.
-- @param #AI_AIR self
-- @param Wrapper.Group#GROUP TankerName The group name of the tanker as defined within the Mission Editor or spawned.
-- @return #AI_AIR self
function AI_AIR: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_AIR self
-- @param #number DisengageRadius The disengage range.
-- @return #AI_AIR self
function AI_AIR:SetDisengageRadius( DisengageRadius )
self:F2( { DisengageRadius } )
self.DisengageRadius = DisengageRadius
end
--- Set the status checking off.
-- @param #AI_AIR self
-- @return #AI_AIR self
function AI_AIR: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_AIR.
-- Once the time is finished, the old AI will return to the base.
-- @param #AI_AIR self
-- @param #number FuelThresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
-- @param #number OutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base.
-- @return #AI_AIR self
function AI_AIR:SetFuelThreshold( FuelThresholdPercentage, OutOfFuelOrbitTime )
self.FuelThresholdPercentage = FuelThresholdPercentage
self.OutOfFuelOrbitTime = OutOfFuelOrbitTime
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_AIR self
-- @param #number PatrolDamageThreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged.
-- @return #AI_AIR self
function AI_AIR: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_AIR self
-- @return #AI_AIR 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_AIR:onafterStart( Controllable, From, Event, To )
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
--- Coordinates the approriate returning action.
-- @param #AI_AIR self
-- @return #AI_AIR 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_AIR:onafterReturn( Controllable, From, Event, To )
self:__RTB( self.TaskDelay )
end
--- @param #AI_AIR self
function AI_AIR:onbeforeStatus()
return self.CheckStatus
end
--- @param #AI_AIR self
function AI_AIR:onafterStatus()
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() )
if DistanceFromHomeBase > self.DisengageRadius then
self:I( self.Controllable:GetName() .. " is too far from home base, RTB!" )
self:Hold( 300 )
RTB = false
end
end
-- I think this code is not requirement anymore after release 2.5.
-- if self:Is( "Fuel" ) or self:Is( "Damaged" ) or self:Is( "LostControl" ) then
-- if DistanceFromHomeBase < 5000 then
-- self:E( self.Controllable:GetName() .. " is near the home base, RTB!" )
-- self:Home( "Destroy" )
-- end
-- end
if not self:Is( "Fuel" ) and not self:Is( "Home" ) and not self:is( "Refuelling" )then
local Fuel = self.Controllable:GetFuelMin()
-- If the fuel in the controllable is below the treshold percentage,
-- then send for refuel in case of a tanker, otherwise RTB.
if Fuel < self.FuelThresholdPercentage then
if self.TankerName then
self:I( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" )
self:Refuel()
else
self:I( 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.OutOfFuelOrbitTime,nil ) )
OldAIControllable:SetTask( TimedOrbitTask, 10 )
self:Fuel()
end
else
end
end
if self:Is( "Fuel" ) and not self:Is( "Home" ) and not self:is( "Refuelling" ) then
RTB = true
end
-- TODO: Check GROUP damage function.
local Damage = self.Controllable:GetLife()
local InitialLife = self.Controllable:GetLife0()
-- If the group is damaged, then RTB.
-- Note that a group can consist of more units, so if one unit is damaged of a group, the mission may continue.
-- The damaged unit will RTB due to DCS logic, and the others will continue to engage.
if ( Damage / InitialLife ) < self.PatrolDamageThreshold then
self:I( self.Controllable:GetName() .. " is damaged: " .. Damage .. " ... RTB!" )
self:Damaged()
RTB = true
self:SetStatusOff()
end
-- Check if planes went RTB and are out of control.
-- We only check if planes are out of control, when they are in duty.
if self.Controllable:HasTask() == false then
if not self:Is( "Started" ) and
not self:Is( "Stopped" ) and
not self:Is( "Fuel" ) and
not self:Is( "Damaged" ) and
not self:Is( "Home" ) then
if self.IdleCount >= 10 then
if Damage ~= InitialLife then
self:Damaged()
else
self:I( 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( self.TaskDelay )
end
if not self:Is("Home") then
self:__Status( 10 )
end
end
end
--- @param Wrapper.Group#GROUP AIGroup
function AI_AIR.RTBRoute( AIGroup, Fsm )
AIGroup:F( { "AI_AIR.RTBRoute:", AIGroup:GetName() } )
if AIGroup:IsAlive() then
Fsm:RTB()
end
end
--- @param Wrapper.Group#GROUP AIGroup
function AI_AIR.RTBHold( AIGroup, Fsm )
AIGroup:F( { "AI_AIR.RTBHold:", AIGroup:GetName() } )
if AIGroup:IsAlive() then
Fsm:__RTB( Fsm.TaskDelay )
Fsm:Return()
local Task = AIGroup:TaskOrbitCircle( 4000, 400 )
AIGroup:SetTask( Task )
end
end
--- @param #AI_AIR self
-- @param Wrapper.Group#GROUP AIGroup
function AI_AIR:onafterRTB( AIGroup, From, Event, To )
self:F( { AIGroup, From, Event, To } )
if AIGroup and AIGroup:IsAlive() then
self:I( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" )
self:ClearTargetDistance()
--AIGroup:ClearTasks()
local EngageRoute = {}
--- Calculate the target route point.
local FromCoord = AIGroup:GetCoordinate()
local ToTargetCoord = self.HomeAirbase:GetCoordinate()
if not self.RTBMinSpeed and not self.RTBMaxSpeed then
local RTBSpeedMax = AIGroup:GetSpeedMax()
self:SetRTBSpeed( RTBSpeedMax * 0.25, RTBSpeedMax * 0.25 )
end
local RTBSpeed = math.random( self.RTBMinSpeed, self.RTBMaxSpeed )
local ToAirbaseAngle = FromCoord:GetAngleDegrees( FromCoord:GetDirectionVec3( ToTargetCoord ) )
local Distance = FromCoord:Get2DDistance( ToTargetCoord )
local ToAirbaseCoord = FromCoord:Translate( 5000, ToAirbaseAngle )
if Distance < 5000 then
self:I( "RTB and near the airbase!" )
self:Home()
return
end
if not AIGroup:InAir() == true then
self:I( "Not anymore in the air, considered Home." )
self:Home()
return
end
--- Create a route point of type air.
local FromRTBRoutePoint = FromCoord:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
RTBSpeed,
true
)
--- Create a route point of type air.
local ToRTBRoutePoint = ToAirbaseCoord:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
RTBSpeed,
true
)
EngageRoute[#EngageRoute+1] = FromRTBRoutePoint
EngageRoute[#EngageRoute+1] = ToRTBRoutePoint
local Tasks = {}
Tasks[#Tasks+1] = AIGroup:TaskFunction( "AI_AIR.RTBRoute", self )
EngageRoute[#EngageRoute].task = AIGroup:TaskCombo( Tasks )
AIGroup:OptionROEHoldFire()
AIGroup:OptionROTEvadeFire()
--- NOW ROUTE THE GROUP!
AIGroup:Route( EngageRoute, self.TaskDelay )
end
end
--- @param #AI_AIR self
-- @param Wrapper.Group#GROUP AIGroup
function AI_AIR:onafterHome( AIGroup, From, Event, To )
self:F( { AIGroup, From, Event, To } )
self:I( "Group " .. self.Controllable:GetName() .. " ... Home! ( " .. self:GetState() .. " )" )
if AIGroup and AIGroup:IsAlive() then
end
end
--- @param #AI_AIR self
-- @param Wrapper.Group#GROUP AIGroup
function AI_AIR:onafterHold( AIGroup, From, Event, To, HoldTime )
self:F( { AIGroup, From, Event, To } )
self:I( "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_AIR.RTBHold", self )
local OrbitHoldTask = AIGroup:TaskOrbitCircle( 4000, self.PatrolMinSpeed )
--AIGroup:SetState( AIGroup, "AI_AIR", self )
AIGroup:SetTask( AIGroup:TaskCombo( { TimedOrbitTask, RTBTask, OrbitHoldTask } ), 1 )
end
end
--- @param Wrapper.Group#GROUP AIGroup
function AI_AIR.Resume( AIGroup, Fsm )
AIGroup:I( { "AI_AIR.Resume:", AIGroup:GetName() } )
if AIGroup:IsAlive() then
Fsm:__RTB( Fsm.TaskDelay )
end
end
--- @param #AI_AIR self
-- @param Wrapper.Group#GROUP AIGroup
function AI_AIR:onafterRefuel( AIGroup, From, Event, To )
self:F( { AIGroup, From, Event, To } )
if AIGroup and AIGroup:IsAlive() then
local Tanker = GROUP:FindByName( self.TankerName )
if Tanker:IsAlive() and Tanker:IsAirPlane() then
self:I( "Group " .. self.Controllable:GetName() .. " ... Refuelling! ( " .. self:GetState() .. "), at tanker " .. self.TankerName )
local RefuelRoute = {}
--- Calculate the target route point.
local FromRefuelCoord = AIGroup:GetCoordinate()
local ToRefuelCoord = Tanker:GetCoordinate()
local ToRefuelSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
--- Create a route point of type air.
local FromRefuelRoutePoint = FromRefuelCoord:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToRefuelSpeed,
true
)
--- Create a route point of type air.
local ToRefuelRoutePoint = FromRefuelCoord:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToRefuelSpeed,
true
)
self:F( { ToRefuelSpeed = ToRefuelSpeed } )
RefuelRoute[#RefuelRoute+1] = FromRefuelRoutePoint
--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, self.TaskDelay )
else
self:RTB()
end
end
end
--- @param #AI_AIR self
function AI_AIR:onafterDead()
self:SetStatusOff()
end
--- @param #AI_AIR self
-- @param Core.Event#EVENTDATA EventData
function AI_AIR:OnCrash( EventData )
if self.Controllable:IsAlive() and EventData.IniDCSGroupName == self.Controllable:GetName() then
if #self.Controllable:GetUnits() == 1 then
self:__Crash( self.TaskDelay, EventData )
end
end
end
--- @param #AI_AIR self
-- @param Core.Event#EVENTDATA EventData
function AI_AIR:OnEjection( EventData )
if self.Controllable:IsAlive() and EventData.IniDCSGroupName == self.Controllable:GetName() then
self:__Eject( self.TaskDelay, EventData )
end
end
--- @param #AI_AIR self
-- @param Core.Event#EVENTDATA EventData
function AI_AIR:OnPilotDead( EventData )
if self.Controllable:IsAlive() and EventData.IniDCSGroupName == self.Controllable:GetName() then
self:__PilotDead( self.TaskDelay, EventData )
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,613 @@
--- **AI** -- Models the process of air to ground engagement for airplanes and helicopters.
--
-- This is a class used in the @{AI_A2G_Dispatcher}.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_Air_Engage
-- @image AI_Air_To_Ground_Engage.JPG
--- @type AI_AIR_ENGAGE
-- @extends AI.AI_AIR#AI_AIR
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
--
-- ![Process](..\Presentations\AI_GCI\Dia3.JPG)
--
-- The AI_AIR_ENGAGE is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_ENGAGE 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_AIR_ENGAGE constructor
--
-- * @{#AI_AIR_ENGAGE.New}(): Creates a new AI_AIR_ENGAGE object.
--
-- ## 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.AI_GCI#AI_AIR_ENGAGE.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.AI_Cap#AI_AIR_ENGAGE.SetEngageZone}() to define that Zone.
--
-- ===
--
-- @field #AI_AIR_ENGAGE
AI_AIR_ENGAGE = {
ClassName = "AI_AIR_ENGAGE",
}
--- Creates a new AI_AIR_ENGAGE object
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup
-- @param DCS#Speed EngageMinSpeed (optional, default = 50% of max speed) The minimum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Speed EngageMaxSpeed (optional, default = 75% of max speed) The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
-- @param DCS#Altitude EngageFloorAltitude (optional, default = 1000m ) The lowest altitude in meters where to execute the engagement.
-- @param DCS#Altitude EngageCeilingAltitude (optional, default = 1500m ) The highest altitude in meters where to execute the engagement.
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
-- @return #AI_AIR_ENGAGE
function AI_AIR_ENGAGE:New( AI_Air, AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
-- Inherits from BASE
local self = BASE:Inherit( self, AI_Air ) -- #AI_AIR_ENGAGE
self.Accomplished = false
self.Engaging = false
local SpeedMax = AIGroup:GetSpeedMax()
self.EngageMinSpeed = EngageMinSpeed or SpeedMax * 0.5
self.EngageMaxSpeed = EngageMaxSpeed or SpeedMax * 0.75
self.EngageFloorAltitude = EngageFloorAltitude or 1000
self.EngageCeilingAltitude = EngageCeilingAltitude or 1500
self.EngageAltType = EngageAltType or "RADIO"
self:AddTransition( { "Started", "Engaging", "Returning", "Airborne", "Patrolling" }, "EngageRoute", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_ENGAGE.
--- OnBefore Transition Handler for Event EngageRoute.
-- @function [parent=#AI_AIR_ENGAGE] OnBeforeEngageRoute
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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 EngageRoute.
-- @function [parent=#AI_AIR_ENGAGE] OnAfterEngageRoute
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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 EngageRoute.
-- @function [parent=#AI_AIR_ENGAGE] EngageRoute
-- @param #AI_AIR_ENGAGE self
--- Asynchronous Event Trigger for Event EngageRoute.
-- @function [parent=#AI_AIR_ENGAGE] __EngageRoute
-- @param #AI_AIR_ENGAGE self
-- @param #number Delay The delay in seconds.
--- OnLeave Transition Handler for State Engaging.
-- @function [parent=#AI_AIR_ENGAGE] OnLeaveEngaging
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE] OnEnterEngaging
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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( { "Started", "Engaging", "Returning", "Airborne", "Patrolling" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_ENGAGE.
--- OnBefore Transition Handler for Event Engage.
-- @function [parent=#AI_AIR_ENGAGE] OnBeforeEngage
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE] OnAfterEngage
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE] Engage
-- @param #AI_AIR_ENGAGE self
--- Asynchronous Event Trigger for Event Engage.
-- @function [parent=#AI_AIR_ENGAGE] __Engage
-- @param #AI_AIR_ENGAGE self
-- @param #number Delay The delay in seconds.
--- OnLeave Transition Handler for State Engaging.
-- @function [parent=#AI_AIR_ENGAGE] OnLeaveEngaging
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE] OnEnterEngaging
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE.
--- OnBefore Transition Handler for Event Fired.
-- @function [parent=#AI_AIR_ENGAGE] OnBeforeFired
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE] OnAfterFired
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE] Fired
-- @param #AI_AIR_ENGAGE self
--- Asynchronous Event Trigger for Event Fired.
-- @function [parent=#AI_AIR_ENGAGE] __Fired
-- @param #AI_AIR_ENGAGE self
-- @param #number Delay The delay in seconds.
self:AddTransition( "*", "Destroy", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_ENGAGE.
--- OnBefore Transition Handler for Event Destroy.
-- @function [parent=#AI_AIR_ENGAGE] OnBeforeDestroy
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE] OnAfterDestroy
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE] Destroy
-- @param #AI_AIR_ENGAGE self
--- Asynchronous Event Trigger for Event Destroy.
-- @function [parent=#AI_AIR_ENGAGE] __Destroy
-- @param #AI_AIR_ENGAGE self
-- @param #number Delay The delay in seconds.
self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_ENGAGE.
--- OnBefore Transition Handler for Event Abort.
-- @function [parent=#AI_AIR_ENGAGE] OnBeforeAbort
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE] OnAfterAbort
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE] Abort
-- @param #AI_AIR_ENGAGE self
--- Asynchronous Event Trigger for Event Abort.
-- @function [parent=#AI_AIR_ENGAGE] __Abort
-- @param #AI_AIR_ENGAGE self
-- @param #number Delay The delay in seconds.
self:AddTransition( "Engaging", "Accomplish", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_ENGAGE.
--- OnBefore Transition Handler for Event Accomplish.
-- @function [parent=#AI_AIR_ENGAGE] OnBeforeAccomplish
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE] OnAfterAccomplish
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE] Accomplish
-- @param #AI_AIR_ENGAGE self
--- Asynchronous Event Trigger for Event Accomplish.
-- @function [parent=#AI_AIR_ENGAGE] __Accomplish
-- @param #AI_AIR_ENGAGE self
-- @param #number Delay The delay in seconds.
self:AddTransition( { "Patrolling", "Engaging" }, "Refuel", "Refuelling" )
return self
end
--- onafter event handler for Start event.
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE:onafterStart( AIGroup, From, Event, To )
self:GetParent( self, AI_AIR_ENGAGE ).onafterStart( self, AIGroup, From, Event, To )
AIGroup:HandleEvent( EVENTS.Takeoff, nil, self )
end
--- onafter event handler for Engage event.
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE:onafterEngage( AIGroup, From, Event, To )
self:HandleEvent( EVENTS.Dead )
end
-- todo: need to fix this global function
--- onbefore event handler for Engage event.
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE:onbeforeEngage( AIGroup, From, Event, To )
if self.Accomplished == true then
return false
end
end
--- onafter event handler for Abort event.
-- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE:onafterAbort( AIGroup, From, Event, To )
AIGroup:ClearTasks()
self:Return()
end
--- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE:onafterAccomplish( AIGroup, From, Event, To )
self.Accomplished = true
self:SetDetectionOff()
end
--- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup 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_AIR_ENGAGE:onafterDestroy( AIGroup, From, Event, To, EventData )
if EventData.IniUnit then
self.AttackUnits[EventData.IniUnit] = nil
end
end
--- @param #AI_AIR_ENGAGE self
-- @param Core.Event#EVENTDATA EventData
function AI_AIR_ENGAGE:OnEventDead( EventData )
self:F( { "EventDead", EventData } )
if EventData.IniDCSUnit then
if self.AttackUnits and self.AttackUnits[EventData.IniUnit] then
self:__Destroy( self.TaskDelay, EventData )
end
end
end
--- @param Wrapper.Group#GROUP AIControllable
function AI_AIR_ENGAGE.___EngageRoute( AIGroup, Fsm, AttackSetUnit )
Fsm:I( { "AI_AIR_ENGAGE.___EngageRoute:", AIGroup:GetName() } )
if AIGroup:IsAlive() then
Fsm:__EngageRoute( Fsm.TaskDelay, AttackSetUnit )
--local Task = AIGroup:TaskOrbitCircle( 4000, 400 )
--AIGroup:SetTask( Task )
end
end
--- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP DefenderGroup 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_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, AttackSetUnit )
self:I( { DefenderGroup, From, Event, To, AttackSetUnit } )
local DefenderGroupName = DefenderGroup:GetName()
self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air!
local AttackCount = AttackSetUnit:Count()
if AttackCount > 0 then
if DefenderGroup:IsAlive() then
local EngageAltitude = math.random( self.EngageFloorAltitude, self.EngageCeilingAltitude )
local EngageSpeed = math.random( self.EngageMinSpeed, self.EngageMaxSpeed )
-- Determine the distance to the target.
-- If it is less than 10km, then attack without a route.
-- Otherwise perform a route attack.
local DefenderCoord = DefenderGroup:GetPointVec3()
DefenderCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
local TargetCoord = AttackSetUnit:GetFirst():GetPointVec3()
TargetCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
local TargetDistance = DefenderCoord:Get2DDistance( TargetCoord )
local EngageDistance = ( DefenderGroup:IsHelicopter() and 5000 ) or ( DefenderGroup:IsAirPlane() and 10000 )
if TargetDistance <= EngageDistance * 3 then
self:__Engage( 0.1, AttackSetUnit )
else
local EngageRoute = {}
local AttackTasks = {}
--- Calculate the target route point.
local FromWP = DefenderCoord:WaypointAir(
self.PatrolAltType or "RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
EngageSpeed,
true
)
EngageRoute[#EngageRoute+1] = FromWP
self:SetTargetDistance( TargetCoord ) -- For RTB status check
local FromEngageAngle = DefenderCoord:GetAngleDegrees( DefenderCoord:GetDirectionVec3( TargetCoord ) )
local ToWP = DefenderCoord:Translate( EngageDistance, FromEngageAngle, true ):WaypointAir(
self.PatrolAltType or "RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
EngageSpeed,
true
)
EngageRoute[#EngageRoute+1] = ToWP
AttackTasks[#AttackTasks+1] = DefenderGroup:TaskFunction( "AI_AIR_ENGAGE.___EngageRoute", self, AttackSetUnit )
EngageRoute[#EngageRoute].task = DefenderGroup:TaskCombo( AttackTasks )
DefenderGroup:OptionROEReturnFire()
DefenderGroup:OptionROTEvadeFire()
DefenderGroup:Route( EngageRoute, self.TaskDelay )
end
end
else
self:I( DefenderGroupName .. ": No targets found -> Going RTB")
self:Return()
end
end
--- @param Wrapper.Group#GROUP AIControllable
function AI_AIR_ENGAGE.___Engage( AIGroup, Fsm, AttackSetUnit )
Fsm:I( { "AI_AIR_ENGAGE.___Engage:", AIGroup:GetName() } )
if AIGroup:IsAlive() then
Fsm:__Engage( Fsm.TaskDelay, AttackSetUnit )
end
end
--- @param #AI_AIR_ENGAGE self
-- @param Wrapper.Group#GROUP DefenderGroup 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_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit )
self:F( { DefenderGroup, From, Event, To, AttackSetUnit} )
local DefenderGroupName = DefenderGroup:GetName()
self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air!
local AttackCount = AttackSetUnit:Count()
self:I({AttackCount = AttackCount})
if AttackCount > 0 then
if DefenderGroup:IsAlive() then
local EngageAltitude = math.random( self.EngageFloorAltitude or 500, self.EngageCeilingAltitude or 1000 )
local EngageSpeed = math.random( self.EngageMinSpeed, self.EngageMaxSpeed )
local DefenderCoord = DefenderGroup:GetPointVec3()
DefenderCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
local TargetCoord = AttackSetUnit:GetFirst():GetPointVec3()
TargetCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
local TargetDistance = DefenderCoord:Get2DDistance( TargetCoord )
local EngageDistance = ( DefenderGroup:IsHelicopter() and 5000 ) or ( DefenderGroup:IsAirPlane() and 10000 )
local EngageRoute = {}
local AttackTasks = {}
local FromWP = DefenderCoord:WaypointAir(
self.EngageAltType or "RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
EngageSpeed,
true
)
EngageRoute[#EngageRoute+1] = FromWP
self:SetTargetDistance( TargetCoord ) -- For RTB status check
local FromEngageAngle = DefenderCoord:GetAngleDegrees( DefenderCoord:GetDirectionVec3( TargetCoord ) )
local ToWP = DefenderCoord:Translate( EngageDistance, FromEngageAngle, true ):WaypointAir(
self.EngageAltType or "RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
EngageSpeed,
true
)
EngageRoute[#EngageRoute+1] = ToWP
if TargetDistance <= EngageDistance * 3 then
local AttackUnitTasks = self:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude ) -- Polymorphic
if #AttackUnitTasks == 0 then
self:I( DefenderGroupName .. ": No valid targets found -> Going RTB")
self:Return()
return
else
self:I( DefenderGroupName .. ": Engaging targets " )
DefenderGroup:OptionROEOpenFire()
DefenderGroup:OptionROTEvadeFire()
DefenderGroup:OptionKeepWeaponsOnThreat()
AttackTasks[#AttackTasks+1] = DefenderGroup:TaskCombo( AttackUnitTasks )
end
end
AttackTasks[#AttackTasks+1] = DefenderGroup:TaskFunction( "AI_AIR_ENGAGE.___Engage", self, AttackSetUnit )
EngageRoute[#EngageRoute].task = DefenderGroup:TaskCombo( AttackTasks )
DefenderGroup:Route( EngageRoute, self.TaskDelay )
end
else
self:I( DefenderGroupName .. ": No targets found -> returning.")
self:Return()
return
end
end
--- @param Wrapper.Group#GROUP AIEngage
function AI_AIR_ENGAGE.Resume( AIEngage, Fsm )
AIEngage:F( { "Resume:", AIEngage:GetName() } )
if AIEngage:IsAlive() then
Fsm:__Reset( Fsm.TaskDelay )
Fsm:__EngageRoute( Fsm.TaskDelay, Fsm.AttackSetUnit )
end
end

View File

@@ -0,0 +1,409 @@
--- **AI** -- Models the process of A2G patrolling and engaging ground targets for airplanes and helicopters.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_Air_Patrol
-- @image AI_Air_To_Ground_Patrol.JPG
--- @type AI_AIR_PATROL
-- @extends AI.AI_Air#AI_AIR
--- The AI_AIR_PATROL class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.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_AIR_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_PATROL 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_AIR_PATROL constructor
--
-- * @{#AI_AIR_PATROL.New}(): Creates a new AI_AIR_PATROL object.
--
-- ## 2. AI_AIR_PATROL is a FSM
--
-- ![Process](..\Presentations\AI_CAP\Dia2.JPG)
--
-- ### 2.1 AI_AIR_PATROL 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_AIR_PATROL Events
--
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.PatrolRoute}**: Route the AI to a new random 3D point within the Patrol Zone.
-- * **@{#AI_AIR_PATROL.Engage}**: Let the AI engage the bogeys.
-- * **@{#AI_AIR_PATROL.Abort}**: Aborts the engagement and return patrolling in the patrol zone.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
-- * **@{#AI_AIR_PATROL.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
-- * **@{#AI_AIR_PATROL.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
--
-- ## 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.AI_CAP#AI_AIR_PATROL.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.AI_Cap#AI_AIR_PATROL.SetEngageZone}() to define that Zone.
--
-- ===
--
-- @field #AI_AIR_PATROL
AI_AIR_PATROL = {
ClassName = "AI_AIR_PATROL",
}
--- Creates a new AI_AIR_PATROL object
-- @param #AI_AIR_PATROL self
-- @param Wrapper.Group#GROUP AIGroup
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param DCS#Altitude PatrolFloorAltitude (optional, default = 1000m ) The lowest altitude in meters where to execute the patrol.
-- @param DCS#Altitude PatrolCeilingAltitude (optional, default = 1500m ) The highest altitude in meters where to execute the patrol.
-- @param DCS#Speed PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#Speed PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed of the @{Wrapper.Group} in km/h.
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO.
-- @return #AI_AIR_PATROL
function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
-- Inherits from BASE
local self = BASE:Inherit( self, AI_Air ) -- #AI_AIR_PATROL
local SpeedMax = AIGroup:GetSpeedMax()
self.PatrolZone = PatrolZone
self.PatrolFloorAltitude = PatrolFloorAltitude or 1000
self.PatrolCeilingAltitude = PatrolCeilingAltitude or 1500
self.PatrolMinSpeed = PatrolMinSpeed or SpeedMax * 0.5
self.PatrolMaxSpeed = PatrolMaxSpeed or SpeedMax * 0.75
-- 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_AIR_PATROL] OnBeforePatrol
-- @param #AI_AIR_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_AIR_PATROL] OnAfterPatrol
-- @param #AI_AIR_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_AIR_PATROL] Patrol
-- @param #AI_AIR_PATROL self
--- Asynchronous Event Trigger for Event Patrol.
-- @function [parent=#AI_AIR_PATROL] __Patrol
-- @param #AI_AIR_PATROL self
-- @param #number Delay The delay in seconds.
--- OnLeave Transition Handler for State Patrolling.
-- @function [parent=#AI_AIR_PATROL] OnLeavePatrolling
-- @param #AI_AIR_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_AIR_PATROL] OnEnterPatrolling
-- @param #AI_AIR_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", "PatrolRoute", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_PATROL.
--- OnBefore Transition Handler for Event PatrolRoute.
-- @function [parent=#AI_AIR_PATROL] OnBeforePatrolRoute
-- @param #AI_AIR_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 PatrolRoute.
-- @function [parent=#AI_AIR_PATROL] OnAfterPatrolRoute
-- @param #AI_AIR_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 PatrolRoute.
-- @function [parent=#AI_AIR_PATROL] PatrolRoute
-- @param #AI_AIR_PATROL self
--- Asynchronous Event Trigger for Event PatrolRoute.
-- @function [parent=#AI_AIR_PATROL] __PatrolRoute
-- @param #AI_AIR_PATROL self
-- @param #number Delay The delay in seconds.
self:AddTransition( "*", "Reset", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_PATROL.
return self
end
--- Set the Engage Range when the AI will engage with airborne enemies.
-- @param #AI_AIR_PATROL self
-- @param #number EngageRange The Engage Range.
-- @return #AI_AIR_PATROL self
function AI_AIR_PATROL:SetEngageRange( EngageRange )
self:F2()
if EngageRange then
self.EngageRange = EngageRange
else
self.EngageRange = nil
end
end
--- Set race track parameters. CAP flights will perform race track patterns rather than randomly patrolling the zone.
-- @param #AI_AIR_PATROL self
-- @param #number LegMin Min Length of the race track leg in meters. Default 10,000 m.
-- @param #number LegMax Max length of the race track leg in meters. Default 15,000 m.
-- @param #number HeadingMin Min heading of the race track in degrees. Default 0 deg, i.e. from South to North.
-- @param #number HeadingMax Max heading of the race track in degrees. Default 180 deg, i.e. from South to North.
-- @param #number DurationMin (Optional) Min duration before switching the orbit position. Default is keep same orbit until RTB or engage.
-- @param #number DurationMax (Optional) Max duration before switching the orbit position. Default is keep same orbit until RTB or engage.
-- @param #table CapCoordinates Table of coordinates of first race track point. Second point is determined by leg length and heading.
-- @return #AI_AIR_PATROL self
function AI_AIR_PATROL:SetRaceTrackPattern(LegMin, LegMax, HeadingMin, HeadingMax, DurationMin, DurationMax, CapCoordinates)
self.racetrack=true
self.racetracklegmin=LegMin or 10000
self.racetracklegmax=LegMax or 15000
self.racetrackheadingmin=HeadingMin or 0
self.racetrackheadingmax=HeadingMax or 180
self.racetrackdurationmin=DurationMin
self.racetrackdurationmax=DurationMax
if self.racetrackdurationmax and not self.racetrackdurationmin then
self.racetrackdurationmin=self.racetrackdurationmax
end
self.racetrackcapcoordinates=CapCoordinates
end
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
-- @param #AI_AIR_PATROL self
-- @return #AI_AIR_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_AIR_PATROL:onafterPatrol( AIPatrol, From, Event, To )
self:F2()
self:ClearTargetDistance()
self:__PatrolRoute( self.TaskDelay )
AIPatrol:OnReSpawn(
function( PatrolGroup )
self:__Reset( self.TaskDelay )
self:__PatrolRoute( self.TaskDelay )
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_AIR_PATROL.___PatrolRoute( AIPatrol, Fsm )
AIPatrol:F( { "AI_AIR_PATROL.___PatrolRoute:", AIPatrol:GetName() } )
if AIPatrol:IsAlive() then
Fsm:PatrolRoute()
end
end
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
-- @param #AI_AIR_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_AIR_PATROL:onafterPatrolRoute( 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 altitude= math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude )
local ToTargetCoord = self.PatrolZone:GetRandomPointVec2()
ToTargetCoord:SetAlt( altitude )
self:SetTargetDistance( ToTargetCoord ) -- For RTB status check
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
local speedkmh=ToTargetSpeed
local FromWP = CurrentCoord:WaypointAir(
self.PatrolAltType or "RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToTargetSpeed,
true
)
PatrolRoute[#PatrolRoute+1] = FromWP
if self.racetrack then
-- Random heading.
local heading = math.random(self.racetrackheadingmin, self.racetrackheadingmax)
-- Random leg length.
local leg=math.random(self.racetracklegmin, self.racetracklegmax)
-- Random duration if any.
local duration = self.racetrackdurationmin
if self.racetrackdurationmax then
duration=math.random(self.racetrackdurationmin, self.racetrackdurationmax)
end
-- CAP coordinate.
local c0=self.PatrolZone:GetRandomCoordinate()
if self.racetrackcapcoordinates and #self.racetrackcapcoordinates>0 then
c0=self.racetrackcapcoordinates[math.random(#self.racetrackcapcoordinates)]
end
-- Race track points.
local c1=c0:SetAltitude(altitude) --Core.Point#COORDINATE
local c2=c1:Translate(leg, heading):SetAltitude(altitude)
self:SetTargetDistance(c0) -- For RTB status check
-- Debug:
self:T(string.format("Patrol zone race track: v=%.1f knots, h=%.1f ft, heading=%03d, leg=%d m, t=%s sec", UTILS.KmphToKnots(speedkmh), UTILS.MetersToFeet(altitude), heading, leg, tostring(duration)))
--c1:MarkToAll("Race track c1")
--c2:MarkToAll("Race track c2")
-- Task to orbit.
local taskOrbit=AIPatrol:TaskOrbit(c1, altitude, UTILS.KmphToMps(speedkmh), c2)
-- Task function to redo the patrol at other random position.
local taskPatrol=AIPatrol:TaskFunction("AI_A2A_PATROL.PatrolRoute", self)
-- Controlled task with task condition.
local taskCond=AIPatrol:TaskCondition(nil, nil, nil, nil, duration, nil)
local taskCont=AIPatrol:TaskControlled(taskOrbit, taskCond)
-- Second waypoint
PatrolRoute[2]=c1:WaypointAirTurningPoint(self.PatrolAltType, speedkmh, {taskCont, taskPatrol}, "CAP Orbit")
else
--- Create a route point of type air.
local ToWP = ToTargetCoord:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToTargetSpeed,
true
)
PatrolRoute[#PatrolRoute+1] = ToWP
local Tasks = {}
Tasks[#Tasks+1] = AIPatrol:TaskFunction( "AI_AIR_PATROL.___PatrolRoute", self )
PatrolRoute[#PatrolRoute].task = AIPatrol:TaskCombo( Tasks )
end
AIPatrol:OptionROEReturnFire()
AIPatrol:OptionROTEvadeFire()
AIPatrol:Route( PatrolRoute, self.TaskDelay )
end
end
--- @param Wrapper.Group#GROUP AIPatrol
function AI_AIR_PATROL.Resume( AIPatrol, Fsm )
AIPatrol:F( { "AI_AIR_PATROL.Resume:", AIPatrol:GetName() } )
if AIPatrol:IsAlive() then
Fsm:__Reset( Fsm.TaskDelay )
Fsm:__PatrolRoute( Fsm.TaskDelay )
end
end

View File

@@ -0,0 +1,289 @@
--- **AI** -- Models squadrons for airplanes and helicopters.
--
-- This is a class used in the @{AI_Air_Dispatcher} and derived dispatcher classes.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_Air_Squadron
-- @image AI_Air_To_Air_Engage.JPG
--- @type AI_AIR_SQUADRON
-- @extends Core.Base#BASE
--- Implements the core functions modeling squadrons for airplanes and helicopters.
--
-- ===
--
-- @field #AI_AIR_SQUADRON
AI_AIR_SQUADRON = {
ClassName = "AI_AIR_SQUADRON",
}
--- Creates a new AI_AIR_SQUADRON object
-- @param #AI_AIR_SQUADRON self
-- @return #AI_AIR_SQUADRON
function AI_AIR_SQUADRON:New( SquadronName, AirbaseName, TemplatePrefixes, ResourceCount )
self:I( { Air_Squadron = { SquadronName, AirbaseName, TemplatePrefixes, ResourceCount } } )
local AI_Air_Squadron = BASE:New() -- #AI_AIR_SQUADRON
AI_Air_Squadron.Name = SquadronName
AI_Air_Squadron.Airbase = AIRBASE:FindByName( AirbaseName )
AI_Air_Squadron.AirbaseName = AI_Air_Squadron.Airbase:GetName()
if not AI_Air_Squadron.Airbase then
error( "Cannot find airbase with name:" .. AirbaseName )
end
AI_Air_Squadron.Spawn = {}
if type( TemplatePrefixes ) == "string" then
local SpawnTemplate = TemplatePrefixes
self.DefenderSpawns[SpawnTemplate] = self.DefenderSpawns[SpawnTemplate] or SPAWN:New( SpawnTemplate ) -- :InitCleanUp( 180 )
AI_Air_Squadron.Spawn[1] = self.DefenderSpawns[SpawnTemplate]
else
for TemplateID, SpawnTemplate in pairs( TemplatePrefixes ) do
self.DefenderSpawns[SpawnTemplate] = self.DefenderSpawns[SpawnTemplate] or SPAWN:New( SpawnTemplate ) -- :InitCleanUp( 180 )
AI_Air_Squadron.Spawn[#AI_Air_Squadron.Spawn+1] = self.DefenderSpawns[SpawnTemplate]
end
end
AI_Air_Squadron.ResourceCount = ResourceCount
AI_Air_Squadron.TemplatePrefixes = TemplatePrefixes
AI_Air_Squadron.Captured = false -- Not captured. This flag will be set to true, when the airbase where the squadron is located, is captured.
self:SetSquadronLanguage( SquadronName, "EN" ) -- Squadrons speak English by default.
return AI_Air_Squadron
end
--- Set the Name of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @param #string Name The Squadron Name.
-- @return #AI_AIR_SQUADRON The Squadron.
function AI_AIR_SQUADRON:SetName( Name )
self.Name = Name
return self
end
--- Get the Name of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @return #string The Squadron Name.
function AI_AIR_SQUADRON:GetName()
return self.Name
end
--- Set the ResourceCount of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @param #number ResourceCount The Squadron ResourceCount.
-- @return #AI_AIR_SQUADRON The Squadron.
function AI_AIR_SQUADRON:SetResourceCount( ResourceCount )
self.ResourceCount = ResourceCount
return self
end
--- Get the ResourceCount of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @return #number The Squadron ResourceCount.
function AI_AIR_SQUADRON:GetResourceCount()
return self.ResourceCount
end
--- Add Resources to the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @param #number Resources The Resources to be added.
-- @return #AI_AIR_SQUADRON The Squadron.
function AI_AIR_SQUADRON:AddResources( Resources )
self.ResourceCount = self.ResourceCount + Resources
return self
end
--- Remove Resources to the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @param #number Resources The Resources to be removed.
-- @return #AI_AIR_SQUADRON The Squadron.
function AI_AIR_SQUADRON:RemoveResources( Resources )
self.ResourceCount = self.ResourceCount - Resources
return self
end
--- Set the Overhead of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @param #number Overhead The Squadron Overhead.
-- @return #AI_AIR_SQUADRON The Squadron.
function AI_AIR_SQUADRON:SetOverhead( Overhead )
self.Overhead = Overhead
return self
end
--- Get the Overhead of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @return #number The Squadron Overhead.
function AI_AIR_SQUADRON:GetOverhead()
return self.Overhead
end
--- Set the Grouping of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @param #number Grouping The Squadron Grouping.
-- @return #AI_AIR_SQUADRON The Squadron.
function AI_AIR_SQUADRON:SetGrouping( Grouping )
self.Grouping = Grouping
return self
end
--- Get the Grouping of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @return #number The Squadron Grouping.
function AI_AIR_SQUADRON:GetGrouping()
return self.Grouping
end
--- Set the FuelThreshold of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @param #number FuelThreshold The Squadron FuelThreshold.
-- @return #AI_AIR_SQUADRON The Squadron.
function AI_AIR_SQUADRON:SetFuelThreshold( FuelThreshold )
self.FuelThreshold = FuelThreshold
return self
end
--- Get the FuelThreshold of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @return #number The Squadron FuelThreshold.
function AI_AIR_SQUADRON:GetFuelThreshold()
return self.FuelThreshold
end
--- Set the EngageProbability of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @param #number EngageProbability The Squadron EngageProbability.
-- @return #AI_AIR_SQUADRON The Squadron.
function AI_AIR_SQUADRON:SetEngageProbability( EngageProbability )
self.EngageProbability = EngageProbability
return self
end
--- Get the EngageProbability of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @return #number The Squadron EngageProbability.
function AI_AIR_SQUADRON:GetEngageProbability()
return self.EngageProbability
end
--- Set the Takeoff of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @param #number Takeoff The Squadron Takeoff.
-- @return #AI_AIR_SQUADRON The Squadron.
function AI_AIR_SQUADRON:SetTakeoff( Takeoff )
self.Takeoff = Takeoff
return self
end
--- Get the Takeoff of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @return #number The Squadron Takeoff.
function AI_AIR_SQUADRON:GetTakeoff()
return self.Takeoff
end
--- Set the Landing of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @param #number Landing The Squadron Landing.
-- @return #AI_AIR_SQUADRON The Squadron.
function AI_AIR_SQUADRON:SetLanding( Landing )
self.Landing = Landing
return self
end
--- Get the Landing of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @return #number The Squadron Landing.
function AI_AIR_SQUADRON:GetLanding()
return self.Landing
end
--- Set the TankerName of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @param #string TankerName The Squadron Tanker Name.
-- @return #AI_AIR_SQUADRON The Squadron.
function AI_AIR_SQUADRON:SetTankerName( TankerName )
self.TankerName = TankerName
return self
end
--- Get the Tanker Name of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @return #string The Squadron Tanker Name.
function AI_AIR_SQUADRON:GetTankerName()
return self.TankerName
end
--- Set the Radio of the Squadron.
-- @param #AI_AIR_SQUADRON self
-- @param #number RadioFrequency The frequency of communication.
-- @param #number RadioModulation The modulation of communication.
-- @param #number RadioPower The power in Watts of communication.
-- @param #string Language The language of the radio speech.
-- @return #AI_AIR_SQUADRON The Squadron.
function AI_AIR_SQUADRON:SetRadio( RadioFrequency, RadioModulation, RadioPower, Language )
self.RadioFrequency = RadioFrequency
self.RadioModulation = RadioModulation or radio.modulation.AM
self.RadioPower = RadioPower or 100
if self.RadioSpeech then
self.RadioSpeech:Stop()
end
self.RadioSpeech = nil
self.RadioSpeech = RADIOSPEECH:New( RadioFrequency, RadioModulation )
self.RadioSpeech.power = RadioPower
self.RadioSpeech:Start( 0.5 )
self.RadioSpeech:SetLanguage( Language )
return self
end

View File

@@ -1,75 +1,48 @@
--- **AI** -- **Provide Battlefield Air Interdiction (bombing).**
--- **AI** -- Peform Battlefield Area Interdiction (BAI) within an engagement zone.
--
-- ![Banner Image](..\Presentations\AI_BAI\Dia1.JPG)
-- **Features:**
--
-- * Hold and standby within a patrol zone.
-- * Engage upon command the assigned targets within an engagement zone.
-- * Loop the zone until all targets are eliminated.
-- * Trigger different events upon the results achieved.
-- * After combat, return to the patrol zone and hold.
-- * RTB when commanded or after out of fuel.
--
-- ===
--
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/BAI%20-%20Battlefield%20Air%20Interdiction)
--
-- ===
--
-- 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)
-- ### [YouTube Playlist]()
--
-- ===
--
-- # **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:
--
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision.
--
-- ===
--
-- ### Authors:
--
-- * **FlightControl**: Concept, Design & Programming.
--
-- @module AI_Bai
-- @module AI.AI_Bai
-- @image AI_Battlefield_Air_Interdiction.JPG
--- AI_BAI_ZONE class
-- @type AI_BAI_ZONE
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling.
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
-- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed.
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
--- # AI_BAI_ZONE class, extends @{AI_Patrol#AI_PATROL_ZONE}
--- Implements the core functions to provide BattleGround Air Interdiction in an Engage @{Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
--
-- AI_BAI_ZONE derives from the @{AI_Patrol#AI_PATROL_ZONE}, inheriting its methods and behaviour.
--
-- The AI_BAI_ZONE class implements the core functions to provide BattleGround Air Interdiction in an Engage @{Zone} by an AIR @{Controllable} or @{Group}.
-- The AI_BAI_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
--
-- ![HoldAndEngage](..\Presentations\AI_BAI\Dia3.JPG)
--
-- The AI_BAI_ZONE is assigned a @{Group} and this must be done before the AI_BAI_ZONE process can be started through the **Start** event.
-- The AI_BAI_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_BAI_ZONE process can be started through the **Start** event.
--
-- ![Start Event](..\Presentations\AI_BAI\Dia4.JPG)
--
@@ -135,15 +108,15 @@
--
-- ### 2.2. AI_BAI_ZONE 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.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone.
-- * **@{#AI_BAI_ZONE.Engage}**: Engage the AI to provide BOMB in the Engage Zone, destroying any target it finds.
-- * **@{#AI_BAI_ZONE.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_BAI_ZONE.Destroy}**: The AI has destroyed a target @{Unit}.
-- * **@{#AI_BAI_ZONE.Destroyed}**: The AI has destroyed all target @{Unit}s assigned in the BOMB task.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
-- * **@{#AI_BAI_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}.
-- * **@{#AI_BAI_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the BOMB task.
-- * **Status**: The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
--
-- ## 3. Modify the Engage Zone behaviour to pinpoint a **map object** or **scenery object**
@@ -170,12 +143,12 @@ AI_BAI_ZONE = {
--- Creates a new AI_BAI_ZONE object
-- @param #AI_BAI_ZONE self
-- @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 @{Controllable} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h.
-- @param Core.Zone#ZONE_BASE EngageZone The zone where the engage will happen.
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @return #AI_BAI_ZONE self
function AI_BAI_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType )
@@ -212,24 +185,24 @@ function AI_BAI_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
-- @function [parent=#AI_BAI_ZONE] Engage
-- @param #AI_BAI_ZONE self
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
-- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
-- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack.
-- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
-- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack.
-- If parameter is not defined the unit / controllable will choose expend on its own discretion.
-- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack.
-- Use the structure @{DCS#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack.
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
-- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
-- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
--- Asynchronous Event Trigger for Event Engage.
-- @function [parent=#AI_BAI_ZONE] __Engage
-- @param #AI_BAI_ZONE self
-- @param #number Delay The delay in seconds.
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
-- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
-- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack.
-- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
-- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack.
-- If parameter is not defined the unit / controllable will choose expend on its own discretion.
-- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack.
-- Use the structure @{DCS#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack.
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
-- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
-- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
--- OnLeave Transition Handler for State Engaging.
-- @function [parent=#AI_BAI_ZONE] OnLeaveEngaging
@@ -516,10 +489,10 @@ end
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
-- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
-- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
-- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
-- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
-- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
-- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
EngageSpeed,
EngageAltitude,
@@ -546,7 +519,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 +576,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 +600,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,69 +1,44 @@
--- 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** -- Balance player slots with AI to create an engaging simulation environment, independent of the amount of players.
--
-- ![Banner Image](..\Presentations\AI_Balancer\Dia1.JPG)
--
-- ====
-- **Features:**
--
-- # 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)
-- * Automatically spawn AI as a replacement of free player slots for a coalition.
-- * Make the AI to perform tasks.
-- * Define a maximum amount of AI to be active at the same time.
-- * Configure the behaviour of AI when a human joins a slot for which an AI is active.
--
-- ===
--
-- # **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
-- @module AI.AI_Balancer
-- @image AI_Balancing.JPG
--- @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
--- # AI_BALANCER class, extends @{Fsm#FSM_SET}
--
-- The AI_BALANCER class monitors and manages as many replacement AI groups as there are
-- CLIENTS in a SET_CLIENT collection, which are not occupied by human players.
--- Monitors and manages as many replacement AI groups as there are
-- CLIENTS in a SET\_CLIENT collection, which are not occupied by human players.
-- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI in multi player missions.
--
-- The parent class @{Fsm#FSM_SET} manages the functionality to control the Finite State Machine (FSM).
-- The parent class @{Core.Fsm#FSM_SET} manages the functionality to control the Finite State Machine (FSM).
-- The mission designer can tailor the behaviour of the AI_BALANCER, by defining event and state transition methods.
-- An explanation about state and event transition methods can be found in the @{FSM} module documentation.
--
@@ -105,8 +80,8 @@
-- However, there are 2 additional options that you can use to customize the destroy behaviour.
-- When a human player joins a slot, you can configure to let the AI return to:
--
-- * @{#AI_BALANCER.ReturnToHomeAirbase}: Returns the AI to the **home** @{Airbase#AIRBASE}.
-- * @{#AI_BALANCER.ReturnToNearestAirbases}: Returns the AI to the **nearest friendly** @{Airbase#AIRBASE}.
-- * @{#AI_BALANCER.ReturnToHomeAirbase}: Returns the AI to the **home** @{Wrapper.Airbase#AIRBASE}.
-- * @{#AI_BALANCER.ReturnToNearestAirbases}: Returns the AI to the **nearest friendly** @{Wrapper.Airbase#AIRBASE}.
--
-- Note that when AI returns to an airbase, the AI_BALANCER will trigger the **Return** event and the AI will return,
-- otherwise the AI_BALANCER will trigger a **Destroy** event, and the AI will be destroyed.
@@ -125,7 +100,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 )
@@ -168,24 +143,24 @@ function AI_BALANCER:InitSpawnInterval( Earliest, Latest )
return self
end
--- Returns the AI to the nearest friendly @{Airbase#AIRBASE}.
--- Returns the AI to the nearest friendly @{Wrapper.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 Core.Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Set#SET_AIRBASE}s to evaluate where to return to.
function AI_BALANCER:ReturnToNearestAirbases( ReturnTresholdRange, ReturnAirbaseSet )
-- @param DCS#Distance ReturnThresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}.
-- @param Core.Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Core.Set#SET_AIRBASE}s to evaluate where to return to.
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}.
--- Returns the AI to the home @{Wrapper.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#Distance ReturnThresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}.
function AI_BALANCER:ReturnToHomeAirbase( ReturnThresholdRange )
self.ToHomeAirbase = true
self.ReturnTresholdRange = ReturnTresholdRange
self.ReturnThresholdRange = ReturnThresholdRange
end
--- @param #AI_BALANCER self
@@ -197,9 +172,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 +191,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 +234,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 +280,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,77 +1,50 @@
--- **AI** - **Execute Combat Air Patrol (CAP).**
--- **AI** -- Perform Combat Air Patrolling (CAP) for airplanes.
--
-- ![Banner Image](..\Presentations\AI_CAP\Dia1.JPG)
-- **Features:**
--
-- * Patrol AI airplanes within a given zone.
-- * Trigger detected events when enemy airplanes are detected.
-- * Manage a fuel treshold to RTB on time.
-- * Engage the enemy when detected.
--
--
-- ===
--
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAP%20-%20Combat%20Air%20Patrol)
--
-- ===
--
-- AI CAP classes makes AI Controllables execute a Combat Air Patrol.
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1YCyPxJgoZn-CfhwyeW65L)
--
-- 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:
--
-- ### 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
-- @module AI.AI_Cap
-- @image AI_Combat_Air_Patrol.JPG
--- @type AI_CAP_ZONE
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling.
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
-- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed.
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
--- # AI_CAP_ZONE class, extends @{AI_CAP#AI_PATROL_ZONE}
--
-- The AI_CAP_ZONE class implements the core functions to patrol a @{Zone} by an AI @{Controllable} or @{Group}
--- Implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.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_CAP_ZONE is assigned a @{Group} and this must be done before the AI_CAP_ZONE process can be started using the **Start** event.
-- The AI_CAP_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_CAP_ZONE process can be started using the **Start** event.
--
-- ![Process](..\Presentations\AI_CAP\Dia4.JPG)
--
@@ -114,15 +87,15 @@
--
-- ### 2.2 AI_CAP_ZONE 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.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone.
-- * **@{#AI_CAP_ZONE.Engage}**: Let the AI engage the bogeys.
-- * **@{#AI_CAP_ZONE.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_CAP_ZONE.Destroy}**: The AI has destroyed a bogey @{Unit}.
-- * **@{#AI_CAP_ZONE.Destroyed}**: The AI has destroyed all bogeys @{Unit}s assigned in the CAS task.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
-- * **@{#AI_CAP_ZONE.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
-- * **@{#AI_CAP_ZONE.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
--
-- ## 3. Set the Range of Engagement
@@ -133,7 +106,7 @@
-- 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_CAP_ZONE.SetEngageRange}() to define that range.
-- Use the method @{AI.AI_CAP#AI_CAP_ZONE.SetEngageRange}() to define that range.
--
-- ## 4. Set the Zone of Engagement
--
@@ -141,7 +114,7 @@
--
-- 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_CAP_ZONE.SetEngageZone}() to define that Zone.
-- Use the method @{AI.AI_Cap#AI_CAP_ZONE.SetEngageZone}() to define that Zone.
--
-- ===
--
@@ -155,11 +128,11 @@ AI_CAP_ZONE = {
--- Creates a new AI_CAP_ZONE object
-- @param #AI_CAP_ZONE self
-- @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 @{Controllable} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h.
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @return #AI_CAP_ZONE self
function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
@@ -373,16 +346,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 +394,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 +432,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 +456,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 +467,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
Controllable:OptionROEOpenFire()
Controllable:OptionROTPassiveDefense()
Controllable:OptionROTEvadeFire()
local AttackTasks = {}
@@ -500,13 +477,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 +495,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,64 +1,48 @@
--- **AI** -- **Provide Close Air Support to friendly ground troops.**
--- **AI** -- Perform Close Air Support (CAS) near friendlies.
--
-- ![Banner Image](..\Presentations\AI_CAS\Dia1.JPG)
-- **Features:**
--
-- * Hold and standby within a patrol zone.
-- * Engage upon command the enemies within an engagement zone.
-- * Loop the zone until all enemies are eliminated.
-- * Trigger different events upon the results achieved.
-- * After combat, return to the patrol zone and hold.
-- * RTB when commanded or after fuel.
--
-- ===
--
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAS%20-%20Close%20Air%20Support)
--
-- ===
--
-- 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)
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl3JBO1WDqqpyYRRmIkR2ir2)
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Contributions:
--
-- ### 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
-- @module AI.AI_Cas
-- @image AI_Close_Air_Support.JPG
--- AI_CAS_ZONE class
-- @type AI_CAS_ZONE
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling.
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
-- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed.
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
--- # AI_CAS_ZONE class, extends @{AI_Patrol#AI_PATROL_ZONE}
--
-- AI_CAS_ZONE derives from the @{AI_Patrol#AI_PATROL_ZONE}, inheriting its methods and behaviour.
--
-- The AI_CAS_ZONE class implements the core functions to provide Close Air Support in an Engage @{Zone} by an AIR @{Controllable} or @{Group}.
--- Implements the core functions to provide Close Air Support in an Engage @{Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
-- The AI_CAS_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
--
-- ![HoldAndEngage](..\Presentations\AI_CAS\Dia3.JPG)
--
-- The AI_CAS_ZONE is assigned a @{Group} and this must be done before the AI_CAS_ZONE process can be started through the **Start** event.
-- The AI_CAS_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_CAS_ZONE process can be started through the **Start** event.
--
-- ![Start Event](..\Presentations\AI_CAS\Dia4.JPG)
--
@@ -107,11 +91,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)
--
@@ -124,15 +108,15 @@
--
-- ### 2.2. AI_CAS_ZONE 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.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone.
-- * **@{#AI_CAS_ZONE.Engage}**: Engage the AI to provide CAS in the Engage Zone, destroying any target it finds.
-- * **@{#AI_CAS_ZONE.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_CAS_ZONE.Destroy}**: The AI has destroyed a target @{Unit}.
-- * **@{#AI_CAS_ZONE.Destroyed}**: The AI has destroyed all target @{Unit}s assigned in the CAS task.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
-- * **@{#AI_CAS_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}.
-- * **@{#AI_CAS_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the CAS task.
-- * **Status**: The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
--
-- ===
@@ -147,12 +131,12 @@ AI_CAS_ZONE = {
--- Creates a new AI_CAS_ZONE object
-- @param #AI_CAS_ZONE self
-- @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 @{Controllable} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h.
-- @param Core.Zone#ZONE_BASE EngageZone The zone where the engage will happen.
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @return #AI_CAS_ZONE self
function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType )
@@ -188,24 +172,24 @@ function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
-- @function [parent=#AI_CAS_ZONE] Engage
-- @param #AI_CAS_ZONE self
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
-- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
-- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack.
-- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
-- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack.
-- If parameter is not defined the unit / controllable will choose expend on its own discretion.
-- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack.
-- Use the structure @{DCS#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack.
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
-- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
-- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
--- Asynchronous Event Trigger for Event Engage.
-- @function [parent=#AI_CAS_ZONE] __Engage
-- @param #AI_CAS_ZONE self
-- @param #number Delay The delay in seconds.
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
-- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
-- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack.
-- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
-- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack.
-- If parameter is not defined the unit / controllable will choose expend on its own discretion.
-- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack.
-- Use the structure @{DCS#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack.
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
-- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
-- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
--- OnLeave Transition Handler for State Engaging.
-- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging
@@ -374,12 +358,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 +388,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 +398,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 )
@@ -445,10 +431,10 @@ end
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
-- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
-- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
-- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
-- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
-- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
-- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
EngageSpeed,
EngageAltitude,
@@ -465,6 +451,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 +463,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 +475,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 +493,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 +506,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 +515,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,568 @@
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_Cargo
-- @image Cargo.JPG
--- @type AI_CARGO
-- @extends Core.Fsm#FSM_CONTROLLABLE
--- Base class for the dynamic cargo handling capability for AI groups.
--
-- Carriers can be mobilized to intelligently transport infantry and other cargo within the simulation.
-- The AI_CARGO module uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
-- CARGO derived objects must be declared within the mission to make the AI_CARGO object recognize the cargo.
-- Please consult the @{Cargo.Cargo} module for more information.
--
-- The derived classes from this module are:
--
-- * @{AI.AI_Cargo_APC} - Cargo transportation using APCs and other vehicles between zones.
-- * @{AI.AI_Cargo_Helicopter} - Cargo transportation using helicopters between zones.
-- * @{AI.AI_Cargo_Airplane} - Cargo transportation using airplanes to and from airbases.
--
-- @field #AI_CARGO
AI_CARGO = {
ClassName = "AI_CARGO",
Coordinate = nil, -- Core.Point#COORDINATE,
Carrier_Cargo = {},
}
--- Creates a new AI_CARGO object.
-- @param #AI_CARGO self
-- @param Wrapper.Group#GROUP Carrier
-- @param Core.Set#SET_CARGO CargoSet
-- @param #number CombatRadius
-- @return #AI_CARGO
function AI_CARGO:New( Carrier, CargoSet )
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New( Carrier ) ) -- #AI_CARGO
self.CargoSet = CargoSet -- Core.Set#SET_CARGO
self.CargoCarrier = Carrier -- Wrapper.Group#GROUP
self:SetStartState( "Unloaded" )
self:AddTransition( "Unloaded", "Pickup", "*" )
self:AddTransition( "Loaded", "Deploy", "*" )
self:AddTransition( "*", "Load", "Boarding" )
self:AddTransition( { "Boarding", "Loaded" }, "Board", "Boarding" )
self:AddTransition( "Boarding", "Loaded", "Boarding" )
self:AddTransition( "Boarding", "PickedUp", "Loaded" )
self:AddTransition( "Loaded", "Unload", "Unboarding" )
self:AddTransition( "Unboarding", "Unboard", "Unboarding" )
self:AddTransition( "Unboarding", "Unloaded", "Unboarding" )
self:AddTransition( "Unboarding", "Deployed", "Unloaded" )
--- Pickup Handler OnBefore for AI_CARGO
-- @function [parent=#AI_CARGO] OnBeforePickup
-- @param #AI_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
-- @return #boolean
--- Pickup Handler OnAfter for AI_CARGO
-- @function [parent=#AI_CARGO] OnAfterPickup
-- @param #AI_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
--- Pickup Trigger for AI_CARGO
-- @function [parent=#AI_CARGO] Pickup
-- @param #AI_CARGO self
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
--- Pickup Asynchronous Trigger for AI_CARGO
-- @function [parent=#AI_CARGO] __Pickup
-- @param #AI_CARGO self
-- @param #number Delay
-- @param Core.Point#COORDINATE Coordinate Pickup place. If not given, loading starts at the current location.
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
--- Deploy Handler OnBefore for AI_CARGO
-- @function [parent=#AI_CARGO] OnBeforeDeploy
-- @param #AI_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
-- @return #boolean
--- Deploy Handler OnAfter for AI_CARGO
-- @function [parent=#AI_CARGO] OnAfterDeploy
-- @param #AI_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
--- Deploy Trigger for AI_CARGO
-- @function [parent=#AI_CARGO] Deploy
-- @param #AI_CARGO self
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
--- Deploy Asynchronous Trigger for AI_CARGO
-- @function [parent=#AI_CARGO] __Deploy
-- @param #AI_CARGO self
-- @param #number Delay
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
--- Loaded Handler OnAfter for AI_CARGO
-- @function [parent=#AI_CARGO] OnAfterLoaded
-- @param #AI_CARGO self
-- @param Wrapper.Group#GROUP Carrier
-- @param #string From
-- @param #string Event
-- @param #string To
--- Unloaded Handler OnAfter for AI_CARGO
-- @function [parent=#AI_CARGO] OnAfterUnloaded
-- @param #AI_CARGO self
-- @param Wrapper.Group#GROUP Carrier
-- @param #string From
-- @param #string Event
-- @param #string To
for _, CarrierUnit in pairs( Carrier:GetUnits() ) do
local CarrierUnit = CarrierUnit -- Wrapper.Unit#UNIT
CarrierUnit:SetCargoBayWeightLimit()
end
self.Transporting = false
self.Relocating = false
return self
end
function AI_CARGO:IsTransporting()
return self.Transporting == true
end
function AI_CARGO:IsRelocating()
return self.Relocating == true
end
--- On after Pickup event.
-- @param #AI_CARGO self
-- @param Wrapper.Group#GROUP APC
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate of the pickup point.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
-- @param #number Height Height in meters to move to the home coordinate.
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
function AI_CARGO:onafterPickup( APC, From, Event, To, Coordinate, Speed, Height, PickupZone )
self.Transporting = false
self.Relocating = true
end
--- On after Deploy event.
-- @param #AI_CARGO self
-- @param Wrapper.Group#GROUP APC
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate Deploy place.
-- @param #number Speed Speed in km/h to drive to the depoly coordinate. Default is 50% of max possible speed the unit can go.
-- @param #number Height Height in meters to move to the deploy coordinate.
-- @param Core.Zone#ZONE DeployZone The zone where the cargo will be deployed.
function AI_CARGO:onafterDeploy( APC, From, Event, To, Coordinate, Speed, Height, DeployZone )
self.Relocating = false
self.Transporting = true
end
--- On before Load event.
-- @param #AI_CARGO self
-- @param Wrapper.Group#GROUP Carrier
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
function AI_CARGO:onbeforeLoad( Carrier, From, Event, To, PickupZone )
self:F( { Carrier, From, Event, To } )
local Boarding = false
local LoadInterval = 2
local LoadDelay = 1
local Carrier_List = {}
local Carrier_Weight = {}
if Carrier and Carrier:IsAlive() then
self.Carrier_Cargo = {}
for _, CarrierUnit in pairs( Carrier:GetUnits() ) do
local CarrierUnit = CarrierUnit -- Wrapper.Unit#UNIT
local CargoBayFreeWeight = CarrierUnit:GetCargoBayFreeWeight()
self:F({CargoBayFreeWeight=CargoBayFreeWeight})
Carrier_List[#Carrier_List+1] = CarrierUnit
Carrier_Weight[CarrierUnit] = CargoBayFreeWeight
end
local Carrier_Count = #Carrier_List
local Carrier_Index = 1
local Loaded = false
for _, Cargo in UTILS.spairs( self.CargoSet:GetSet(), function( t, a, b ) return t[a]:GetWeight() > t[b]:GetWeight() end ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
self:F( { IsUnLoaded = Cargo:IsUnLoaded(), IsDeployed = Cargo:IsDeployed(), Cargo:GetName(), Carrier:GetName() } )
-- Try all Carriers, but start from the one according the Carrier_Index
for Carrier_Loop = 1, #Carrier_List do
local CarrierUnit = Carrier_List[Carrier_Index] -- Wrapper.Unit#UNIT
-- This counters loop through the available Carriers.
Carrier_Index = Carrier_Index + 1
if Carrier_Index > Carrier_Count then
Carrier_Index = 1
end
if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then
if Cargo:IsInLoadRadius( CarrierUnit:GetCoordinate() ) then
self:F( { "In radius", CarrierUnit:GetName() } )
local CargoWeight = Cargo:GetWeight()
-- Only when there is space within the bay to load the next cargo item!
if Carrier_Weight[CarrierUnit] > CargoWeight then --and CargoBayFreeVolume > CargoVolume then
Carrier:RouteStop()
--Cargo:Ungroup()
Cargo:__Board( -LoadDelay, CarrierUnit )
self:__Board( LoadDelay, Cargo, CarrierUnit, PickupZone )
LoadDelay = LoadDelay + Cargo:GetCount() * LoadInterval
-- So now this CarrierUnit has Cargo that is being loaded.
-- This will be used further in the logic to follow and to check cargo status.
self.Carrier_Cargo[Cargo] = CarrierUnit
Boarding = true
Carrier_Weight[CarrierUnit] = Carrier_Weight[CarrierUnit] - CargoWeight
Loaded = true
-- Ok, we loaded a cargo, now we can stop the loop.
break
end
end
end
end
end
if not Loaded == true then
-- No loading happened, so we need to pickup something else.
self.Relocating = false
end
end
return Boarding
end
--- On before Reload event.
-- @param #AI_CARGO self
-- @param Wrapper.Group#GROUP Carrier
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
function AI_CARGO:onbeforeReload( Carrier, From, Event, To )
self:F( { Carrier, From, Event, To } )
local Boarding = false
local LoadInterval = 2
local LoadDelay = 1
local Carrier_List = {}
local Carrier_Weight = {}
if Carrier and Carrier:IsAlive() then
for _, CarrierUnit in pairs( Carrier:GetUnits() ) do
local CarrierUnit = CarrierUnit -- Wrapper.Unit#UNIT
Carrier_List[#Carrier_List+1] = CarrierUnit
end
local Carrier_Count = #Carrier_List
local Carrier_Index = 1
local Loaded = false
for Cargo, CarrierUnit in pairs( self.Carrier_Cargo ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
self:F( { IsUnLoaded = Cargo:IsUnLoaded(), IsDeployed = Cargo:IsDeployed(), Cargo:GetName(), Carrier:GetName() } )
-- Try all Carriers, but start from the one according the Carrier_Index
for Carrier_Loop = 1, #Carrier_List do
local CarrierUnit = Carrier_List[Carrier_Index] -- Wrapper.Unit#UNIT
-- This counters loop through the available Carriers.
Carrier_Index = Carrier_Index + 1
if Carrier_Index > Carrier_Count then
Carrier_Index = 1
end
if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then
Carrier:RouteStop()
Cargo:__Board( -LoadDelay, CarrierUnit )
self:__Board( LoadDelay, Cargo, CarrierUnit )
LoadDelay = LoadDelay + Cargo:GetCount() * LoadInterval
-- So now this CarrierUnit has Cargo that is being loaded.
-- This will be used further in the logic to follow and to check cargo status.
self.Carrier_Cargo[Cargo] = CarrierUnit
Boarding = true
Loaded = true
end
end
end
if not Loaded == true then
-- No loading happened, so we need to pickup something else.
self.Relocating = false
end
end
return Boarding
end
--- On after Board event.
-- @param #AI_CARGO self
-- @param Wrapper.Group#GROUP Carrier
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Cargo.Cargo#CARGO Cargo Cargo object.
-- @param Wrapper.Unit#UNIT CarrierUnit
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
function AI_CARGO:onafterBoard( Carrier, From, Event, To, Cargo, CarrierUnit, PickupZone )
self:F( { Carrier, From, Event, To, Cargo, CarrierUnit:GetName() } )
if Carrier and Carrier:IsAlive() then
self:F({ IsLoaded = Cargo:IsLoaded(), Cargo:GetName(), Carrier:GetName() } )
if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then
self:__Board( -10, Cargo, CarrierUnit, PickupZone )
return
end
end
self:__Loaded( 0.1, Cargo, CarrierUnit, PickupZone )
end
--- On after Loaded event.
-- @param #AI_CARGO self
-- @param Wrapper.Group#GROUP Carrier
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @return #boolean Cargo loaded.
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
function AI_CARGO:onafterLoaded( Carrier, From, Event, To, Cargo, PickupZone )
self:F( { Carrier, From, Event, To } )
local Loaded = true
if Carrier and Carrier:IsAlive() then
for Cargo, CarrierUnit in pairs( self.Carrier_Cargo ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed(), Cargo:GetName(), Carrier:GetName() } )
if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then
Loaded = false
end
end
end
if Loaded then
self:__PickedUp( 0.1, PickupZone )
end
end
--- On after PickedUp event.
-- @param #AI_CARGO self
-- @param Wrapper.Group#GROUP Carrier
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
function AI_CARGO:onafterPickedUp( Carrier, From, Event, To, PickupZone )
self:F( { Carrier, From, Event, To } )
Carrier:RouteResume()
local HasCargo = false
if Carrier and Carrier:IsAlive() then
for Cargo, CarrierUnit in pairs( self.Carrier_Cargo ) do
HasCargo = true
break
end
end
self.Relocating = false
if HasCargo then
self:F( "Transporting" )
self.Transporting = true
end
end
--- On after Unload event.
-- @param #AI_CARGO self
-- @param Wrapper.Group#GROUP Carrier
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
function AI_CARGO:onafterUnload( Carrier, From, Event, To, DeployZone, Defend )
self:F( { Carrier, From, Event, To, DeployZone, Defend = Defend } )
local UnboardInterval = 5
local UnboardDelay = 5
if Carrier and Carrier:IsAlive() then
for _, CarrierUnit in pairs( Carrier:GetUnits() ) do
local CarrierUnit = CarrierUnit -- Wrapper.Unit#UNIT
Carrier:RouteStop()
for _, Cargo in pairs( CarrierUnit:GetCargo() ) do
self:F( { Cargo = Cargo:GetName(), Isloaded = Cargo:IsLoaded() } )
if Cargo:IsLoaded() then
Cargo:__UnBoard( UnboardDelay )
UnboardDelay = UnboardDelay + Cargo:GetCount() * UnboardInterval
self:__Unboard( UnboardDelay, Cargo, CarrierUnit, DeployZone, Defend )
if not Defend == true then
Cargo:SetDeployed( true )
end
end
end
end
end
end
--- On after Unboard event.
-- @param #AI_CARGO self
-- @param Wrapper.Group#GROUP Carrier
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #string Cargo.Cargo#CARGO Cargo Cargo object.
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
function AI_CARGO:onafterUnboard( Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone, Defend )
self:F( { Carrier, From, Event, To, Cargo:GetName(), DeployZone = DeployZone, Defend = Defend } )
if Carrier and Carrier:IsAlive() then
if not Cargo:IsUnLoaded() then
self:__Unboard( 10, Cargo, CarrierUnit, DeployZone, Defend )
return
end
end
self:Unloaded( Cargo, CarrierUnit, DeployZone, Defend )
end
--- On after Unloaded event.
-- @param #AI_CARGO self
-- @param Wrapper.Group#GROUP Carrier
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #string Cargo.Cargo#CARGO Cargo Cargo object.
-- @param #boolean Deployed Cargo is deployed.
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
function AI_CARGO:onafterUnloaded( Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone, Defend )
self:F( { Carrier, From, Event, To, Cargo:GetName(), DeployZone = DeployZone, Defend = Defend } )
local AllUnloaded = true
--Cargo:Regroup()
if Carrier and Carrier:IsAlive() then
for _, CarrierUnit in pairs( Carrier:GetUnits() ) do
local CarrierUnit = CarrierUnit -- Wrapper.Unit#UNIT
local IsEmpty = CarrierUnit:IsCargoEmpty()
self:I({ IsEmpty = IsEmpty })
if not IsEmpty then
AllUnloaded = false
break
end
end
if AllUnloaded == true then
if DeployZone == true then
self.Carrier_Cargo = {}
end
self.CargoCarrier = Carrier
end
end
if AllUnloaded == true then
self:__Deployed( 5, DeployZone, Defend )
end
end
--- On after Deployed event.
-- @param #AI_CARGO self
-- @param Wrapper.Group#GROUP Carrier
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
function AI_CARGO:onafterDeployed( Carrier, From, Event, To, DeployZone, Defend )
self:F( { Carrier, From, Event, To, DeployZone = DeployZone, Defend = Defend } )
if not Defend == true then
self.Transporting = false
else
self:F( "Defending" )
end
end

View File

@@ -0,0 +1,531 @@
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_Cargo_APC
-- @image AI_Cargo_Dispatching_For_APC.JPG
--- @type AI_CARGO_APC
-- @extends AI.AI_Cargo#AI_CARGO
--- Brings a dynamic cargo handling capability for an AI vehicle group.
--
-- 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 class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
-- @{Cargo.Cargo} must be declared within the mission to make the AI_CARGO_APC object recognize the cargo.
-- Please consult the @{Cargo.Cargo} module for more information.
--
-- ## Cargo loading.
--
-- The module will load automatically cargo when the APCs are within boarding or loading radius.
-- The boarding or loading radius is specified when the cargo is created in the simulation, and therefore, this radius depends on the type of cargo
-- and the specified boarding radius.
--
-- ## **Defending** the APCs when enemies nearby.
--
-- Cargo will defend the carrier with its available arms, and to avoid cargo being lost within the battlefield.
--
-- 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 radius needs to be specified in meters at the @{#AI_CARGO_APC.New}() method.
-- This combat radius will trigger the unboarding of troops when enemies are within the combat radius around the APCs.
-- During my tests, I've noticed that there is a balance between ensuring that the infantry is within sufficient hit radius (effectiveness) versus
-- vulnerability of the infantry. It all depends on the kind of enemies that are expected to be encountered.
-- A combat radius of 350 meters to 500 meters has been proven to be the most effective and efficient.
--
-- However, when the defense of the carrier, is not required, it must be switched off.
-- This is done by disabling the defense of the carrier using the method @{#AI_CARGO_APC.SetCombatRadius}(), and providing a combat radius of 0 meters.
-- It can be switched on later when required by reenabling the defense using the method and providing a combat radius larger than 0.
--
-- ## Infantry or cargo **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,
}
--- Creates a new AI_CARGO_APC object.
-- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC The carrier APC group.
-- @param Core.Set#SET_CARGO CargoSet The set of cargo to be transported.
-- @param #number CombatRadius Provide the combat radius to defend the carrier by unboarding the cargo when enemies are nearby. When the combat radius is 0, no defense will happen of the carrier.
-- @return #AI_CARGO_APC
function AI_CARGO_APC:New( APC, CargoSet, CombatRadius )
local self = BASE:Inherit( self, AI_CARGO:New( APC, CargoSet ) ) -- #AI_CARGO_APC
self:AddTransition( "*", "Monitor", "*" )
self:AddTransition( "*", "Follow", "Following" )
self:AddTransition( "*", "Guard", "Unloaded" )
self:AddTransition( "*", "Home", "*" )
self:AddTransition( "*", "Reload", "Boarding" )
self:AddTransition( "*", "Destroyed", "Destroyed" )
self:SetCombatRadius( CombatRadius )
self:SetCarrier( APC )
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 )
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 radius. Unload the CargoCarrier.
AICargoTroops:Destroyed()
end
end
end
-- CargoCarrier:HandleEvent( EVENTS.Hit )
--
-- 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 radius. 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
--- Find a free Carrier within a radius.
-- @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
--- Enable/Disable unboarding of cargo (infantry) when enemies are nearby (to help defend the carrier).
-- This is only valid for APCs and trucks etc, thus ground vehicles.
-- @param #AI_CARGO_APC self
-- @param #number CombatRadius Provide the combat radius to defend the carrier by unboarding the cargo when enemies are nearby.
-- When the combat radius is 0, no defense will happen of the carrier.
-- When the combat radius is not provided, no defense will happen!
-- @return #AI_CARGO_APC
-- @usage
--
-- -- Disembark the infantry when the carrier is under attack.
-- AICargoAPC:SetCombatRadius( true )
--
-- -- Keep the cargo in the carrier when the carrier is under attack.
-- AICargoAPC:SetCombatRadius( false )
function AI_CARGO_APC:SetCombatRadius( CombatRadius )
self.CombatRadius = CombatRadius or 0
if self.CombatRadius > 0 then
self:__Monitor( -5 )
end
return self
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
--- On after Monitor event.
-- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function AI_CARGO_APC:onafterMonitor( APC, From, Event, To )
self:F( { APC, From, Event, To, IsTransporting = self:IsTransporting() } )
if self.CombatRadius > 0 then
if APC and APC:IsAlive() then
if self.CarrierCoordinate then
if self:IsTransporting() == true then
local Coordinate = APC:GetCoordinate()
if self:Is( "Unloaded" ) or self:Is( "Loaded" ) then
self.Zone:Scan( { Object.Category.UNIT } )
if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
if self:Is( "Unloaded" ) then
-- There are no enemies within combat radius. Reload the CargoCarrier.
self:Reload()
end
else
if self:Is( "Loaded" ) then
-- There are enemies within combat radius. Unload the CargoCarrier.
self:__Unload( 1, nil, true ) -- The 2nd parameter is true, which means that the unload is for defending the carrier, not to deploy!
else
if self:Is( "Unloaded" ) then
--self:Follow()
end
self:F( "I am here" .. self:GetCurrentState() )
if self:Is( "Following" ) then
for Cargo, APCUnit in pairs( self.Carrier_Cargo ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
local APCUnit = APCUnit -- Wrapper.Unit#UNIT
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
end
self.CarrierCoordinate = APC:GetCoordinate()
end
self:__Monitor( -5 )
end
end
--- On after Follow event.
-- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
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 Cargo, APCUnit in pairs( self.Carrier_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, Coordinate, Speed, PickupZone )
APC:F( { "AI_CARGO_APC._Pickup:", APC:GetName() } )
if APC:IsAlive() then
self:Load( PickupZone )
end
end
function AI_CARGO_APC._Deploy( APC, self, Coordinate, DeployZone )
APC:F( { "AI_CARGO_APC._Deploy:", APC } )
if APC:IsAlive() then
self:Unload( DeployZone )
end
end
--- On after Pickup event.
-- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate of the pickup point.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
-- @param #number Height Height in meters to move to the pickup coordinate. This parameter is ignored for APCs.
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate, Speed, Height, PickupZone )
if APC and APC:IsAlive() then
if Coordinate then
self.RoutePickup = true
local _speed=Speed or APC:GetSpeedMax()*0.5
local Waypoints = APC:TaskGroundOnRoad( Coordinate, _speed, "Line abreast", true )
local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Pickup", self, Coordinate, Speed, PickupZone )
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, Coordinate, Speed, PickupZone )
end
self:GetParent( self, AI_CARGO_APC ).onafterPickup( self, APC, From, Event, To, Coordinate, Speed, Height, PickupZone )
end
end
--- On after Deploy event.
-- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate Deploy place.
-- @param #number Speed Speed in km/h to drive to the depoly coordinate. Default is 50% of max possible speed the unit can go.
-- @param #number Height Height in meters to move to the deploy coordinate. This parameter is ignored for APCs.
-- @param Core.Zone#ZONE DeployZone The zone where the cargo will be deployed.
function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate, Speed, Height, DeployZone )
if APC and APC:IsAlive() then
self.RouteDeploy = true
local _speed=Speed or APC:GetSpeedMax()*0.5
local Waypoints = APC:TaskGroundOnRoad( Coordinate, _speed, "Line abreast", true )
local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Deploy", self, Coordinate, DeployZone )
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.
self:GetParent( self, AI_CARGO_APC ).onafterDeploy( self, APC, From, Event, To, Coordinate, Speed, Height, DeployZone )
end
end
--- On after Unloaded event.
-- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP Carrier
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #string Cargo.Cargo#CARGO Cargo Cargo object.
-- @param #boolean Deployed Cargo is deployed.
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
function AI_CARGO_APC:onafterUnloaded( Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone, Defend )
self:F( { Carrier, From, Event, To, DeployZone = DeployZone, Defend = Defend } )
self:GetParent( self, AI_CARGO_APC ).onafterUnloaded( self, Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone, Defend )
-- If Defend == true then we need to scan for possible enemies within combat zone and engage only ground forces.
if Defend == true then
self.Zone:Scan( { Object.Category.UNIT } )
if not self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
-- OK, enemies nearby, now find the enemies and attack them.
local AttackUnits = self.Zone:GetScannedUnits() -- #list<DCS#Unit>
local Move = {}
local CargoGroup = Cargo.CargoObject -- Wrapper.Group#GROUP
Move[#Move+1] = CargoGroup:GetCoordinate():WaypointGround( 70, "Custom" )
for UnitId, AttackUnit in pairs( AttackUnits ) do
local MooseUnit = UNIT:Find( AttackUnit )
if MooseUnit:GetCoalition() ~= CargoGroup:GetCoalition() then
Move[#Move+1] = MooseUnit:GetCoordinate():WaypointGround( 70, "Line abreast" )
--MoveTo.Task = CargoGroup:TaskCombo( CargoGroup:TaskAttackUnit( MooseUnit, true ) )
self:F( { MooseUnit = MooseUnit:GetName(), CargoGroup = CargoGroup:GetName() } )
end
end
CargoGroup:RoutePush( Move, 0.1 )
end
end
end
--- On after Deployed event.
-- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP Carrier
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
function AI_CARGO_APC:onafterDeployed( APC, From, Event, To, DeployZone, Defend )
self:F( { APC, From, Event, To, DeployZone = DeployZone, Defend = Defend } )
self:__Guard( 0.1 )
self:GetParent( self, AI_CARGO_APC ).onafterDeployed( self, APC, From, Event, To, DeployZone, Defend )
end
--- On after Home event.
-- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate Home place.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
-- @param #number Height Height in meters to move to the home coordinate. This parameter is ignored for APCs.
function AI_CARGO_APC:onafterHome( APC, From, Event, To, Coordinate, Speed, Height, HomeZone )
if APC and APC:IsAlive() ~= nil then
self.RouteHome = true
Speed = Speed or APC:GetSpeedMax()*0.5
local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed, "Line abreast", true )
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,484 @@
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry (cargo).
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_Cargo_Airplane
-- @image AI_Cargo_Dispatching_For_Airplanes.JPG
--- @type AI_CARGO_AIRPLANE
-- @extends Core.Fsm#FSM_CONTROLLABLE
--- Brings a dynamic cargo handling capability for an AI airplane group.
--
-- Airplane carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation between airbases.
--
-- The AI_CARGO_AIRPLANE module uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
-- @{Cargo.Cargo} must be declared within the mission to make AI_CARGO_AIRPLANE recognize the cargo.
-- Please consult the @{Cargo.Cargo} module for more information.
--
-- ## Cargo pickup.
--
-- Using the @{#AI_CARGO_AIRPLANE.Pickup}() method, you are able to direct the helicopters towards a point on the battlefield to board/load the cargo at the specific coordinate.
-- Ensure that the landing zone is horizontally flat, and that trees cannot be found in the landing vicinity, or the helicopters won't land or will even crash!
--
-- ## Cargo deployment.
--
-- Using the @{#AI_CARGO_AIRPLANE.Deploy}() method, you are able to direct the helicopters towards a point on the battlefield to unboard/unload the cargo at the specific coordinate.
-- Ensure that the landing zone is horizontally flat, and that trees cannot be found in the landing vicinity, or the helicopters won't land or will even crash!
--
-- ## 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, 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 ...
--
--
-- @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 Plane used for transportation of cargo.
-- @param Core.Set#SET_CARGO CargoSet Cargo set to be transported.
-- @return #AI_CARGO_AIRPLANE
function AI_CARGO_AIRPLANE:New( Airplane, CargoSet )
local self = BASE:Inherit( self, AI_CARGO:New( Airplane, CargoSet ) ) -- #AI_CARGO_AIRPLANE
self:AddTransition( "*", "Landed", "*" )
self:AddTransition( "*", "Home" , "*" )
self:AddTransition( "*", "Destroyed", "Destroyed" )
--- Pickup Handler OnBefore for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] OnBeforePickup
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up.
-- @param #number Speed in km/h for travelling to pickup base.
-- @return #boolean
--- Pickup Handler OnAfter for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] OnAfterPickup
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo plane.
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up.
-- @param #number Speed in km/h for travelling to pickup base.
--- Pickup Trigger for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] Pickup
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up.
-- @param #number Speed in km/h for travelling to pickup base.
--- Pickup Asynchronous Trigger for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] __Pickup
-- @param #AI_CARGO_AIRPLANE self
-- @param #number Delay Delay in seconds.
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up.
-- @param #number Speed in km/h for travelling to pickup base.
--- Deploy Handler OnBefore for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] OnBeforeDeploy
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo plane.
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed.
-- @param #number Speed Speed in km/h for travelling to deploy base.
-- @return #boolean
--- Deploy Handler OnAfter for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] OnAfterDeploy
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo plane.
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed.
-- @param #number Speed Speed in km/h for travelling to deploy base.
--- Deploy Trigger for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] Deploy
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed.
-- @param #number Speed Speed in km/h for travelling to deploy base.
--- Deploy Asynchronous Trigger for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] __Deploy
-- @param #AI_CARGO_AIRPLANE self
-- @param #number Delay Delay in seconds.
-- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed.
-- @param #number Speed Speed in km/h for travelling to deploy base.
--- On after Loaded event, i.e. triggered when the cargo is inside the carrier.
-- @function [parent=#AI_CARGO_AIRPLANE] OnAfterLoaded
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo plane.
-- @param From
-- @param Event
-- @param To
-- Set carrier.
self:SetCarrier( Airplane )
return self
end
--- Set the Carrier (controllable). Also initializes events for carrier and defines the coalition.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Transport plane.
-- @return #AI_CARGO_AIRPLANE self
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.Relocating = false
AICargo:Landed( self.Airplane )
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
--- On after "Landed" event. Called on engine shutdown and initiates the pickup mission or unloading event.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
-- @param From
-- @param Event
-- @param To
function AI_CARGO_AIRPLANE:onafterLanded( Airplane, From, Event, To )
self:F({Airplane, From, Event, To})
if Airplane and Airplane:IsAlive()~=nil then
-- Aircraft was sent to this airbase to pickup troops. Initiate loadling.
if self.RoutePickup == true then
self:Load( self.PickupZone )
end
-- Aircraft was send to this airbase to deploy troops. Initiate unloading.
if self.RouteDeploy == true then
self:Unload()
self.RouteDeploy = false
end
end
end
--- On after "Pickup" event. Routes transport to pickup airbase.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed in km/h for travelling to pickup base.
-- @param #number Height Height in meters to move to the pickup coordinate.
-- @param Core.Zone#ZONE_AIRBASE (optional) PickupZone The zone where the cargo will be picked up.
function AI_CARGO_AIRPLANE:onafterPickup( Airplane, From, Event, To, Coordinate, Speed, Height, PickupZone )
if Airplane and Airplane:IsAlive() then
self.PickupZone = PickupZone
-- Get closest airbase of current position.
local ClosestAirbase, DistToAirbase=Airplane:GetCoordinate():GetClosestAirbase()
-- Two cases. Aircraft spawned in air or at an airbase.
if Airplane:InAir() then
self.Airbase=nil --> route will start in air
else
self.Airbase=ClosestAirbase
end
-- Set pickup airbase.
local Airbase = PickupZone:GetAirbase()
-- Distance from closest to pickup airbase ==> we need to know if we are already at the pickup airbase.
local Dist = Airbase:GetCoordinate():Get2DDistance(ClosestAirbase:GetCoordinate())
--env.info("Distance closest to pickup airbase = "..Dist)
if Airplane:InAir() or Dist>500 then
-- Route aircraft to pickup airbase.
self:Route( Airplane, Airbase, Speed, Height )
-- Set airbase as starting point in the next Route() call.
self.Airbase = Airbase
-- Aircraft is on a pickup mission.
self.RoutePickup = true
else
-- We are already at the right airbase ==> Landed ==> triggers loading of troops. Is usually called at engine shutdown event.
self.RoutePickup=true
self:Landed()
end
self:GetParent( self, AI_CARGO_AIRPLANE ).onafterPickup( self, Airplane, From, Event, To, Coordinate, Speed, Height, PickupZone )
end
end
--- On after Depoly event. Routes plane to the airbase where the troops are deployed.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed in km/h for travelling to pickup base.
-- @param #number Height Height in meters to move to the home coordinate.
-- @param Core.Zone#ZONE_AIRBASE DeployZone The zone where the cargo will be deployed.
function AI_CARGO_AIRPLANE:onafterDeploy( Airplane, From, Event, To, Coordinate, Speed, Height, DeployZone )
if Airplane and Airplane:IsAlive()~=nil then
local Airbase = DeployZone:GetAirbase()
-- Activate uncontrolled airplane.
if Airplane:IsAlive()==false then
Airplane:SetCommand({id = 'Start', params = {}})
end
-- Route to destination airbase.
self:Route( Airplane, Airbase, Speed, Height )
-- Aircraft is on a depoly mission.
self.RouteDeploy = true
-- Set destination airbase for next :Route() command.
self.Airbase = Airbase
self:GetParent( self, AI_CARGO_AIRPLANE ).onafterDeploy( self, Airplane, From, Event, To, Coordinate, Speed, Height, DeployZone )
end
end
--- On after Unload event. Cargo is beeing unloaded, i.e. the unboarding process is started.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function AI_CARGO_AIRPLANE:onafterUnload( Airplane, From, Event, To, DeployZone )
local UnboardInterval = 10
local UnboardDelay = 10
if Airplane and Airplane:IsAlive() then
for _, AirplaneUnit in pairs( Airplane:GetUnits() ) do
local Cargos = AirplaneUnit:GetCargo()
for CargoID, Cargo in pairs( Cargos ) do
local Angle = 180
local CargoCarrierHeading = Airplane:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
self:T( { CargoCarrierHeading, CargoDeployHeading } )
local CargoDeployCoordinate = Airplane:GetPointVec2():Translate( 150, CargoDeployHeading )
Cargo:__UnBoard( UnboardDelay, CargoDeployCoordinate )
UnboardDelay = UnboardDelay + UnboardInterval
Cargo:SetDeployed( true )
self:__Unboard( UnboardDelay, Cargo, AirplaneUnit, DeployZone )
end
end
end
end
--- Route the airplane from one airport or it's current position to another airbase.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Airplane group to be routed.
-- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase.
-- @param #number Speed Speed in km/h. Default is 80% of max possible speed the group can do.
-- @param #number Height Height in meters to move to the Airbase.
-- @param #boolean Uncontrolled If true, spawn group in uncontrolled state.
function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed, Height, Uncontrolled )
if Airplane and Airplane:IsAlive() then
-- Set takeoff type.
local Takeoff = SPAWN.Takeoff.Cold
-- Get template of group.
local Template = Airplane:GetTemplate()
-- Nil check
if Template==nil then
return
end
-- Waypoints of the route.
local Points={}
-- To point.
local AirbasePointVec2 = Airbase:GetPointVec2()
local ToWaypoint = AirbasePointVec2:WaypointAir(
POINT_VEC3.RoutePointAltType.BARO,
"Land",
"Landing",
Speed or Airplane:GetSpeedMax()*0.8
)
ToWaypoint["airdromeId"] = Airbase:GetID()
ToWaypoint["speed_locked"] = true
-- If self.Airbase~=nil then group is currently at an airbase, where it should be respawned.
if self.Airbase then
-- Second point of the route. First point is done in RespawnAtCurrentAirbase() routine.
Template.route.points[2] = ToWaypoint
-- Respawn group at the current airbase.
Airplane:RespawnAtCurrentAirbase(Template, Takeoff, Uncontrolled)
else
-- From point.
local GroupPoint = Airplane:GetVec2()
local FromWaypoint = {}
FromWaypoint.x = GroupPoint.x
FromWaypoint.y = GroupPoint.y
FromWaypoint.type = "Turning Point"
FromWaypoint.action = "Turning Point"
FromWaypoint.speed = Airplane:GetSpeedMax()*0.8
-- The two route points.
Points[1] = FromWaypoint
Points[2] = ToWaypoint
local PointVec3 = Airplane:GetPointVec3()
Template.x = PointVec3.x
Template.y = PointVec3.z
Template.route.points = Points
local GroupSpawned = Airplane:Respawn(Template)
end
end
end
--- On after Home event. Aircraft will be routed to their home base.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane The cargo plane.
-- @param From From state.
-- @param Event Event.
-- @param To To State.
-- @param Core.Point#COORDINATE Coordinate Home place (not used).
-- @param #number Speed Speed in km/h to fly to the home airbase (zone). Default is 80% of max possible speed the unit can go.
-- @param #number Height Height in meters to move to the home coordinate.
-- @param Core.Zone#ZONE_AIRBASE HomeZone The home airbase (zone) where the plane should return to.
function AI_CARGO_AIRPLANE:onafterHome(Airplane, From, Event, To, Coordinate, Speed, Height, HomeZone )
if Airplane and Airplane:IsAlive() then
-- We are going home!
self.RouteHome = true
-- Home Base.
local HomeBase=HomeZone:GetAirbase()
self.Airbase=HomeBase
-- Now route the airplane home
self:Route( Airplane, HomeBase, Speed, Height )
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,209 @@
--- **AI** -- (2.4) - Models the intelligent transportation of infantry and other cargo using APCs.
--
-- ## Features:
--
-- * Quickly transport cargo to various deploy zones using ground vehicles (APCs, trucks ...).
-- * Various @{Cargo.Cargo#CARGO} types can be transported. These are infantry groups and crates.
-- * Define a list of deploy zones of various types to transport the cargo to.
-- * The vehicles follow the roads to ensure the fastest possible cargo transportation over the ground.
-- * Multiple vehicles can transport multiple cargo as one vehicle group.
-- * Multiple vehicle groups can be enabled as one collaborating transportation process.
-- * Infantry loaded as cargo, will unboard in case enemies are nearby and will help defending the vehicles.
-- * Different ranges can be setup for enemy defenses.
-- * Different options can be setup to tweak the cargo transporation behaviour.
--
-- ===
--
-- ## Test Missions:
--
-- Test missions can be located on the main GITHUB site.
--
-- [FlightControl-Master/MOOSE_MISSIONS/AID - AI Dispatching/AID-CGO - AI Cargo Dispatching/]
-- (https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/AID%20-%20AI%20Dispatching/AID-CGO%20-%20AI%20Cargo%20Dispatching)
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_Cargo_Dispatcher_APC
-- @image AI_Cargo_Dispatching_For_APC.JPG
--- @type AI_CARGO_DISPATCHER_APC
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER
--- A dynamic cargo transportation 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 is derived from the AI_CARGO_DISPATCHER module.
--
-- ## Note! In order to fully understand the mechanisms of the AI_CARGO_DISPATCHER_APC class, it is recommended that you first consult and READ the documentation of the @{AI.AI_Cargo_Dispatcher} module!!!
--
-- Especially to learn how to **Tailor the different cargo handling events**, this will be very useful!
--
-- On top, the AI_CARGO_DISPATCHER_APC class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
-- Also ensure that you fully understand how to declare and setup Cargo objects within the MOOSE framework before using this class.
-- CARGO derived objects must be declared within the mission to make the AI_CARGO_DISPATCHER_HELICOPTER object recognize the cargo.
--
--
-- # 1) AI_CARGO_DISPATCHER_APC constructor.
--
-- * @{#AI_CARGO_DISPATCHER_APC.New}(): Creates a new AI_CARGO_DISPATCHER_APC object.
--
-- ---
--
-- # 2) AI_CARGO_DISPATCHER_APC is a Finite State Machine.
--
-- This section must be read as follows. Each of the rows indicate a state transition, triggered through an event, and with an ending state of the event was executed.
-- The first column is the **From** state, the second column the **Event**, and the third column the **To** state.
--
-- So, each of the rows have the following structure.
--
-- * **From** => **Event** => **To**
--
-- Important to know is that an event can only be executed if the **current state** is the **From** state.
-- This, when an **Event** that is being triggered has a **From** state that is equal to the **Current** state of the state machine, the event will be executed,
-- and the resulting state will be the **To** state.
--
-- These are the different possible state transitions of this state machine implementation:
--
-- * Idle => Start => Monitoring
-- * Monitoring => Monitor => Monitoring
-- * Monitoring => Stop => Idle
--
-- * Monitoring => Pickup => Monitoring
-- * Monitoring => Load => Monitoring
-- * Monitoring => Loading => Monitoring
-- * Monitoring => Loaded => Monitoring
-- * Monitoring => PickedUp => Monitoring
-- * Monitoring => Deploy => Monitoring
-- * Monitoring => Unload => Monitoring
-- * Monitoring => Unloaded => Monitoring
-- * Monitoring => Deployed => Monitoring
-- * Monitoring => Home => Monitoring
--
--
-- ## 2.1) AI_CARGO_DISPATCHER States.
--
-- * **Monitoring**: The process is dispatching.
-- * **Idle**: The process is idle.
--
-- ## 2.2) AI_CARGO_DISPATCHER Events.
--
-- * **Start**: Start the transport process.
-- * **Stop**: Stop the transport process.
-- * **Monitor**: Monitor and take action.
--
-- * **Pickup**: Pickup cargo.
-- * **Load**: Load the cargo.
-- * **Loading**: The dispatcher is coordinating the loading of a cargo.
-- * **Loaded**: Flag that the cargo is loaded.
-- * **PickedUp**: The dispatcher has loaded all requested cargo into the CarrierGroup.
-- * **Deploy**: Deploy cargo to a location.
-- * **Unload**: Unload the cargo.
-- * **Unloaded**: Flag that the cargo is unloaded.
-- * **Deployed**: All cargo is unloaded from the carriers in the group.
-- * **Home**: A Carrier is going home.
--
-- ## 2.3) Enhance your mission scripts with **Tailored** Event Handling!
--
-- Within your mission, you can capture these events when triggered, and tailor the events with your own code!
-- Check out the @{AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER} class at chapter 3 for details on the different event handlers that are available and how to use them.
--
-- **There are a lot of templates available that allows you to quickly setup an event handler for a specific event type!**
--
-- ---
--
-- # 3) Set the pickup parameters.
--
-- Several parameters can be set to pickup cargo:
--
-- * @{#AI_CARGO_DISPATCHER_APC.SetPickupRadius}(): Sets or randomizes the pickup location for the APC around the cargo coordinate in a radius defined an outer and optional inner radius.
-- * @{#AI_CARGO_DISPATCHER_APC.SetPickupSpeed}(): Set the speed or randomizes the speed in km/h to pickup the cargo.
--
-- # 4) Set the deploy parameters.
--
-- Several parameters can be set to deploy cargo:
--
-- * @{#AI_CARGO_DISPATCHER_APC.SetDeployRadius}(): Sets or randomizes the deploy location for the APC around the cargo coordinate in a radius defined an outer and an optional inner radius.
-- * @{#AI_CARGO_DISPATCHER_APC.SetDeploySpeed}(): Set the speed or randomizes the speed in km/h to deploy the cargo.
--
-- # 5) Set the home zone when there isn't any more cargo to pickup.
--
-- A home zone can be specified to where the APCs will move when there isn't any cargo left for pickup.
-- Use @{#AI_CARGO_DISPATCHER_APC.SetHomeZone}() to specify the home zone.
--
-- If no home zone is specified, the APCs will wait near the deploy zone for a new pickup command.
--
-- ===
--
-- @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 APCSet The set of @{Wrapper.Group#GROUP} objects of vehicles, trucks, APCs that will transport the cargo.
-- @param Core.Set#SET_CARGO CargoSet The set of @{Cargo.Cargo#CARGO} objects, which can be CARGO_GROUP, CARGO_CRATE, CARGO_SLINGLOAD objects.
-- @param Core.Set#SET_ZONE PickupZoneSet (optional) The set of pickup zones, which are used to where the cargo can be picked up by the APCs. If nil, then cargo can be picked up everywhere.
-- @param Core.Set#SET_ZONE DeployZoneSet The set of deploy zones, which are used to where the cargo will be deployed by the APCs.
-- @param DCS#Distance CombatRadius The cargo will be unloaded from the APC and engage the enemy if the enemy is within CombatRadius range. The radius is in meters, the default value is 500 meters.
-- @return #AI_CARGO_DISPATCHER_APC
-- @usage
--
-- -- An AI dispatcher object for a vehicle squadron, moving infantry from pickup zones to deploy zones.
--
-- local SetCargoInfantry = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
-- local SetAPC = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart()
-- local SetDeployZones = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
--
-- AICargoDispatcherAPC = AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargoInfantry, nil, SetDeployZones )
-- AICargoDispatcherAPC:Start()
--
function AI_CARGO_DISPATCHER_APC:New( APCSet, CargoSet, PickupZoneSet, DeployZoneSet, CombatRadius )
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( APCSet, CargoSet, PickupZoneSet, DeployZoneSet ) ) -- #AI_CARGO_DISPATCHER_APC
self:SetDeploySpeed( 120, 70 )
self:SetPickupSpeed( 120, 70 )
self:SetPickupRadius( 0, 0 )
self:SetDeployRadius( 0, 0 )
self:SetPickupHeight()
self:SetDeployHeight()
self:SetCombatRadius( CombatRadius )
return self
end
function AI_CARGO_DISPATCHER_APC:AICargo( APC, CargoSet )
return AI_CARGO_APC:New( APC, CargoSet, self.CombatRadius )
end
--- Enable/Disable unboarding of cargo (infantry) when enemies are nearby (to help defend the carrier).
-- This is only valid for APCs and trucks etc, thus ground vehicles.
-- @param #AI_CARGO_DISPATCHER_APC self
-- @param #number CombatRadius Provide the combat radius to defend the carrier by unboarding the cargo when enemies are nearby.
-- When the combat radius is 0, no defense will happen of the carrier.
-- When the combat radius is not provided, no defense will happen!
-- @return #AI_CARGO_DISPATCHER_APC
-- @usage
--
-- -- Disembark the infantry when the carrier is under attack.
-- AICargoDispatcher:SetCombatRadius( true )
--
-- -- Keep the cargo in the carrier when the carrier is under attack.
-- AICargoDispatcher:SetCombatRadius( false )
function AI_CARGO_DISPATCHER_APC:SetCombatRadius( CombatRadius )
self.CombatRadius = CombatRadius or 0
return self
end

View File

@@ -0,0 +1,164 @@
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo using Planes.
--
-- ## Features:
--
-- * The airplanes will fly towards the pickup airbases to pickup the cargo.
-- * The airplanes will fly towards the deploy airbases to deploy the cargo.
--
-- ===
--
-- ## Test Missions:
--
-- Test missions can be located on the main GITHUB site.
--
-- [FlightControl-Master/MOOSE_MISSIONS/AID - AI Dispatching/AID-CGO - AI Cargo Dispatching/]
-- (https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/AID%20-%20AI%20Dispatching/AID-CGO%20-%20AI%20Cargo%20Dispatching)
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_Cargo_Dispatcher_Airplane
-- @image AI_Cargo_Dispatching_For_Airplanes.JPG
--- @type AI_CARGO_DISPATCHER_AIRPLANE
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER
--- 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 is derived from the AI_CARGO_DISPATCHER module.
--
-- ## Note! In order to fully understand the mechanisms of the AI_CARGO_DISPATCHER_AIRPLANE class, it is recommended that you first consult and READ the documentation of the @{AI.AI_Cargo_Dispatcher} module!!!**
--
-- Especially to learn how to **Tailor the different cargo handling events**, this will be very useful!
--
-- On top, the AI_CARGO_DISPATCHER_AIRPLANE class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
-- Also ensure that you fully understand how to declare and setup Cargo objects within the MOOSE framework before using this class.
-- CARGO derived objects must be declared within the mission to make the AI_CARGO_DISPATCHER_HELICOPTER object recognize the cargo.
--
-- # 1) AI_CARGO_DISPATCHER_AIRPLANE constructor.
--
-- * @{#AI_CARGO_DISPATCHER_AIRPLANE.New}(): Creates a new AI_CARGO_DISPATCHER_AIRPLANE object.
--
-- ---
--
-- # 2) AI_CARGO_DISPATCHER_AIRPLANE is a Finite State Machine.
--
-- This section must be read as follows. Each of the rows indicate a state transition, triggered through an event, and with an ending state of the event was executed.
-- The first column is the **From** state, the second column the **Event**, and the third column the **To** state.
--
-- So, each of the rows have the following structure.
--
-- * **From** => **Event** => **To**
--
-- Important to know is that an event can only be executed if the **current state** is the **From** state.
-- This, when an **Event** that is being triggered has a **From** state that is equal to the **Current** state of the state machine, the event will be executed,
-- and the resulting state will be the **To** state.
--
-- These are the different possible state transitions of this state machine implementation:
--
-- * Idle => Start => Monitoring
-- * Monitoring => Monitor => Monitoring
-- * Monitoring => Stop => Idle
--
-- * Monitoring => Pickup => Monitoring
-- * Monitoring => Load => Monitoring
-- * Monitoring => Loading => Monitoring
-- * Monitoring => Loaded => Monitoring
-- * Monitoring => PickedUp => Monitoring
-- * Monitoring => Deploy => Monitoring
-- * Monitoring => Unload => Monitoring
-- * Monitoring => Unloaded => Monitoring
-- * Monitoring => Deployed => Monitoring
-- * Monitoring => Home => Monitoring
--
--
-- ## 2.1) AI_CARGO_DISPATCHER States.
--
-- * **Monitoring**: The process is dispatching.
-- * **Idle**: The process is idle.
--
-- ## 2.2) AI_CARGO_DISPATCHER Events.
--
-- * **Start**: Start the transport process.
-- * **Stop**: Stop the transport process.
-- * **Monitor**: Monitor and take action.
--
-- * **Pickup**: Pickup cargo.
-- * **Load**: Load the cargo.
-- * **Loading**: The dispatcher is coordinating the loading of a cargo.
-- * **Loaded**: Flag that the cargo is loaded.
-- * **PickedUp**: The dispatcher has loaded all requested cargo into the CarrierGroup.
-- * **Deploy**: Deploy cargo to a location.
-- * **Unload**: Unload the cargo.
-- * **Unloaded**: Flag that the cargo is unloaded.
-- * **Deployed**: All cargo is unloaded from the carriers in the group.
-- * **Home**: A Carrier is going home.
--
-- ## 2.3) Enhance your mission scripts with **Tailored** Event Handling!
--
-- Within your mission, you can capture these events when triggered, and tailor the events with your own code!
-- Check out the @{AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER} class at chapter 3 for details on the different event handlers that are available and how to use them.
--
-- **There are a lot of templates available that allows you to quickly setup an event handler for a specific event type!**
--
--
--
-- @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 AirplaneSet The set of @{Wrapper.Group#GROUP} objects of airplanes that will transport the cargo.
-- @param Core.Set#SET_CARGO CargoSet The set of @{Cargo.Cargo#CARGO} objects, which can be CARGO_GROUP, CARGO_CRATE, CARGO_SLINGLOAD objects.
-- @param Core.Zone#SET_ZONE PickupZoneSet The set of zone airbases where the cargo has to be picked up.
-- @param Core.Zone#SET_ZONE DeployZoneSet The set of zone airbases where the cargo is deployed. Choice for each cargo is random.
-- @return #AI_CARGO_DISPATCHER_AIRPLANE self
-- @usage
--
-- -- An AI dispatcher object for an airplane squadron, moving infantry and vehicles from pickup airbases to deploy airbases.
--
-- local CargoInfantrySet = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
-- local AirplanesSet = SET_GROUP:New():FilterPrefixes( "Airplane" ):FilterStart()
-- local PickupZoneSet = SET_ZONE:New()
-- local DeployZoneSet = SET_ZONE:New()
--
-- PickupZoneSet:AddZone( ZONE_AIRBASE:New( AIRBASE.Caucasus.Gudauta ) )
-- DeployZoneSet:AddZone( ZONE_AIRBASE:New( AIRBASE.Caucasus.Sochi_Adler ) )
-- DeployZoneSet:AddZone( ZONE_AIRBASE:New( AIRBASE.Caucasus.Maykop_Khanskaya ) )
-- DeployZoneSet:AddZone( ZONE_AIRBASE:New( AIRBASE.Caucasus.Mineralnye_Vody ) )
-- DeployZoneSet:AddZone( ZONE_AIRBASE:New( AIRBASE.Caucasus.Vaziani ) )
--
-- AICargoDispatcherAirplanes = AI_CARGO_DISPATCHER_AIRPLANE:New( AirplanesSet, CargoInfantrySet, PickupZoneSet, DeployZoneSet )
-- AICargoDispatcherAirplanes:Start()
--
function AI_CARGO_DISPATCHER_AIRPLANE:New( AirplaneSet, CargoSet, PickupZoneSet, DeployZoneSet )
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( AirplaneSet, CargoSet, PickupZoneSet, DeployZoneSet ) ) -- #AI_CARGO_DISPATCHER_AIRPLANE
self:SetPickupSpeed( 1200, 600 )
self:SetDeploySpeed( 1200, 600 )
self:SetPickupRadius( 0, 0 )
self:SetDeployRadius( 0, 0 )
self:SetPickupHeight( 8000, 6000 )
self:SetDeployHeight( 8000, 6000 )
self:SetMonitorTimeInterval( 600 )
return self
end
function AI_CARGO_DISPATCHER_AIRPLANE:AICargo( Airplane, CargoSet )
return AI_CARGO_AIRPLANE:New( Airplane, CargoSet )
end

View File

@@ -0,0 +1,191 @@
--- **AI** -- (2.4) - Models the intelligent transportation of infantry and other cargo using Helicopters.
--
-- ## Features:
--
-- * The helicopters will fly towards the pickup locations to pickup the cargo.
-- * The helicopters will fly towards the deploy zones to deploy the cargo.
-- * Precision deployment as well as randomized deployment within the deploy zones are possible.
-- * Helicopters will orbit the deploy zones when there is no space for landing until the deploy zone is free.
--
-- ===
--
-- ## Test Missions:
--
-- Test missions can be located on the main GITHUB site.
--
-- [FlightControl-Master/MOOSE_MISSIONS/AID - AI Dispatching/AID-CGO - AI Cargo Dispatching/]
-- (https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/AID%20-%20AI%20Dispatching/AID-CGO%20-%20AI%20Cargo%20Dispatching)
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_Cargo_Dispatcher_Helicopter
-- @image AI_Cargo_Dispatching_For_Helicopters.JPG
--- @type AI_CARGO_DISPATCHER_HELICOPTER
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER
--- A dynamic cargo handling capability for AI helicopter groups.
--
-- Helicopters can be mobilized to intelligently transport infantry and other cargo within the simulation.
--
--
-- The AI_CARGO_DISPATCHER_HELICOPTER module is derived from the AI_CARGO_DISPATCHER module.
--
-- ## Note! In order to fully understand the mechanisms of the AI_CARGO_DISPATCHER_HELICOPTER class, it is recommended that you first consult and READ the documentation of the @{AI.AI_Cargo_Dispatcher} module!!!**
--
-- Especially to learn how to **Tailor the different cargo handling events**, this will be very useful!
--
-- On top, the AI_CARGO_DISPATCHER_HELICOPTER class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
-- Also ensure that you fully understand how to declare and setup Cargo objects within the MOOSE framework before using this class.
-- CARGO derived objects must be declared within the mission to make the AI_CARGO_DISPATCHER_HELICOPTER object recognize the cargo.
--
-- ---
--
-- # 1. AI\_CARGO\_DISPATCHER\_HELICOPTER constructor.
--
-- * @{#AI_CARGO_DISPATCHER\_HELICOPTER.New}(): Creates a new AI\_CARGO\_DISPATCHER\_HELICOPTER object.
--
-- ---
--
-- # 2. AI\_CARGO\_DISPATCHER\_HELICOPTER is a Finite State Machine.
--
-- This section must be read as follows. Each of the rows indicate a state transition, triggered through an event, and with an ending state of the event was executed.
-- The first column is the **From** state, the second column the **Event**, and the third column the **To** state.
--
-- So, each of the rows have the following structure.
--
-- * **From** => **Event** => **To**
--
-- Important to know is that an event can only be executed if the **current state** is the **From** state.
-- This, when an **Event** that is being triggered has a **From** state that is equal to the **Current** state of the state machine, the event will be executed,
-- and the resulting state will be the **To** state.
--
-- These are the different possible state transitions of this state machine implementation:
--
-- * Idle => Start => Monitoring
-- * Monitoring => Monitor => Monitoring
-- * Monitoring => Stop => Idle
--
-- * Monitoring => Pickup => Monitoring
-- * Monitoring => Load => Monitoring
-- * Monitoring => Loading => Monitoring
-- * Monitoring => Loaded => Monitoring
-- * Monitoring => PickedUp => Monitoring
-- * Monitoring => Deploy => Monitoring
-- * Monitoring => Unload => Monitoring
-- * Monitoring => Unloaded => Monitoring
-- * Monitoring => Deployed => Monitoring
-- * Monitoring => Home => Monitoring
--
--
-- ## 2.1) AI_CARGO_DISPATCHER States.
--
-- * **Monitoring**: The process is dispatching.
-- * **Idle**: The process is idle.
--
-- ## 2.2) AI_CARGO_DISPATCHER Events.
--
-- * **Start**: Start the transport process.
-- * **Stop**: Stop the transport process.
-- * **Monitor**: Monitor and take action.
--
-- * **Pickup**: Pickup cargo.
-- * **Load**: Load the cargo.
-- * **Loading**: The dispatcher is coordinating the loading of a cargo.
-- * **Loaded**: Flag that the cargo is loaded.
-- * **PickedUp**: The dispatcher has loaded all requested cargo into the CarrierGroup.
-- * **Deploy**: Deploy cargo to a location.
-- * **Unload**: Unload the cargo.
-- * **Unloaded**: Flag that the cargo is unloaded.
-- * **Deployed**: All cargo is unloaded from the carriers in the group.
-- * **Home**: A Carrier is going home.
--
-- ## 2.3) Enhance your mission scripts with **Tailored** Event Handling!
--
-- Within your mission, you can capture these events when triggered, and tailor the events with your own code!
-- Check out the @{AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER} class at chapter 3 for details on the different event handlers that are available and how to use them.
--
-- **There are a lot of templates available that allows you to quickly setup an event handler for a specific event type!**
--
-- ---
--
-- ## 3. Set the pickup parameters.
--
-- Several parameters can be set to pickup cargo:
--
-- * @{#AI_CARGO_DISPATCHER_HELICOPTER.SetPickupRadius}(): Sets or randomizes the pickup location for the helicopter around the cargo coordinate in a radius defined an outer and optional inner radius.
-- * @{#AI_CARGO_DISPATCHER_HELICOPTER.SetPickupSpeed}(): Set the speed or randomizes the speed in km/h to pickup the cargo.
-- * @{#AI_CARGO_DISPATCHER_HELICOPTER.SetPickupHeight}(): Set the height or randomizes the height in meters to pickup the cargo.
--
-- ---
--
-- ## 4. Set the deploy parameters.
--
-- Several parameters can be set to deploy cargo:
--
-- * @{#AI_CARGO_DISPATCHER_HELICOPTER.SetDeployRadius}(): Sets or randomizes the deploy location for the helicopter around the cargo coordinate in a radius defined an outer and an optional inner radius.
-- * @{#AI_CARGO_DISPATCHER_HELICOPTER.SetDeploySpeed}(): Set the speed or randomizes the speed in km/h to deploy the cargo.
-- * @{#AI_CARGO_DISPATCHER_HELICOPTER.SetDeployHeight}(): Set the height or randomizes the height in meters to deploy the cargo.
--
-- ---
--
-- ## 5. Set the home zone when there isn't any more cargo to pickup.
--
-- A home zone can be specified to where the Helicopters will move when there isn't any cargo left for pickup.
-- Use @{#AI_CARGO_DISPATCHER_HELICOPTER.SetHomeZone}() to specify the home zone.
--
-- If no home zone is specified, the helicopters will wait near the deploy zone for a new pickup command.
--
-- ===
--
-- @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 HelicopterSet The set of @{Wrapper.Group#GROUP} objects of helicopters that will transport the cargo.
-- @param Core.Set#SET_CARGO CargoSet The set of @{Cargo.Cargo#CARGO} objects, which can be CARGO_GROUP, CARGO_CRATE, CARGO_SLINGLOAD objects.
-- @param Core.Set#SET_ZONE PickupZoneSet (optional) The set of pickup zones, which are used to where the cargo can be picked up by the APCs. If nil, then cargo can be picked up everywhere.
-- @param Core.Set#SET_ZONE DeployZoneSet The set of deploy zones, which are used to where the cargo will be deployed by the Helicopters.
-- @return #AI_CARGO_DISPATCHER_HELICOPTER
-- @usage
--
-- -- An AI dispatcher object for a helicopter squadron, moving infantry from pickup zones to deploy zones.
--
-- local SetCargoInfantry = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
-- local SetHelicopter = SET_GROUP:New():FilterPrefixes( "Helicopter" ):FilterStart()
-- local SetPickupZones = SET_ZONE:New():FilterPrefixes( "Pickup" ):FilterStart()
-- local SetDeployZones = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
--
-- AICargoDispatcherHelicopter = AI_CARGO_DISPATCHER_HELICOPTER:New( SetHelicopter, SetCargoInfantry, SetPickupZones, SetDeployZones )
-- AICargoDispatcherHelicopter:Start()
--
function AI_CARGO_DISPATCHER_HELICOPTER:New( HelicopterSet, CargoSet, PickupZoneSet, DeployZoneSet )
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( HelicopterSet, CargoSet, PickupZoneSet, DeployZoneSet ) ) -- #AI_CARGO_DISPATCHER_HELICOPTER
self:SetPickupSpeed( 350, 150 )
self:SetDeploySpeed( 350, 150 )
self:SetPickupRadius( 0, 0 )
self:SetDeployRadius( 0, 0 )
self:SetPickupHeight( 500, 200 )
self:SetDeployHeight( 500, 200 )
return self
end
function AI_CARGO_DISPATCHER_HELICOPTER:AICargo( Helicopter, CargoSet )
return AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
end

View File

@@ -0,0 +1,625 @@
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry (cargo).
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_Cargo_Helicopter
-- @image AI_Cargo_Dispatching_For_Helicopters.JPG
--- @type AI_CARGO_HELICOPTER
-- @extends Core.Fsm#FSM_CONTROLLABLE
--- Brings a dynamic cargo handling capability for an AI helicopter group.
--
-- Helicopter carriers can be mobilized to intelligently transport infantry and other cargo within the simulation.
--
-- The AI_CARGO_HELICOPTER class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
-- @{Cargo.Cargo} must be declared within the mission to make the AI_CARGO_HELICOPTER object recognize the cargo.
-- Please consult the @{Cargo.Cargo} module for more information.
--
-- ## Cargo pickup.
--
-- Using the @{#AI_CARGO_HELICOPTER.Pickup}() method, you are able to direct the helicopters towards a point on the battlefield to board/load the cargo at the specific coordinate.
-- Ensure that the landing zone is horizontally flat, and that trees cannot be found in the landing vicinity, or the helicopters won't land or will even crash!
--
-- ## Cargo deployment.
--
-- Using the @{#AI_CARGO_HELICOPTER.Deploy}() method, you are able to direct the helicopters towards a point on the battlefield to unboard/unload the cargo at the specific coordinate.
-- Ensure that the landing zone is horizontally flat, and that trees cannot be found in the landing vicinity, or the helicopters won't land or will even crash!
--
-- ## 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, 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 ...
--
--
-- ===
--
-- @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
-- @return #AI_CARGO_HELICOPTER
function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
local self = BASE:Inherit( self, AI_CARGO:New( Helicopter, CargoSet ) ) -- #AI_CARGO_HELICOPTER
self.Zone = ZONE_GROUP:New( Helicopter:GetName(), Helicopter, 300 )
self:SetStartState( "Unloaded" )
self:AddTransition( "Unloaded", "Pickup", "*" )
self:AddTransition( "Loaded", "Deploy", "*" )
self:AddTransition( { "Unloaded", "Loading" }, "Load", "Boarding" )
self:AddTransition( "Boarding", "Board", "Boarding" )
self:AddTransition( "Boarding", "Loaded", "Boarding" )
self:AddTransition( "Boarding", "PickedUp", "Loaded" )
self:AddTransition( "Loaded", "Unload", "Unboarding" )
self:AddTransition( "Unboarding", "Unboard", "Unboarding" )
self:AddTransition( "Unboarding", "Unloaded", "Unboarding" )
self:AddTransition( "Unboarding", "Deployed", "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
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
--- Pickup Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] Pickup
-- @param #AI_CARGO_HELICOPTER self
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
--- Pickup Asynchronous Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] __Pickup
-- @param #AI_CARGO_HELICOPTER self
-- @param #number Delay Delay in seconds.
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h to go to the pickup coordinate. Default is 50% of max possible speed the unit can go.
--- 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 Place at which cargo is deployed.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
-- @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
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
--- Deploy Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] Deploy
-- @param #AI_CARGO_HELICOPTER self
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
--- Deploy Asynchronous Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] __Deploy
-- @param #number Delay Delay in seconds.
-- @param #AI_CARGO_HELICOPTER self
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
-- We need to capture the Crash events for the helicopters.
-- The helicopter reference is used in the semaphore AI_CARGO_QUEUE.
-- So, we need to unlock this when the helo is not anymore ...
Helicopter:HandleEvent( EVENTS.Crash,
function( Helicopter, EventData )
AI_CARGO_QUEUE[Helicopter] = nil
end
)
-- We need to capture the Land events for the helicopters.
-- The helicopter reference is used in the semaphore AI_CARGO_QUEUE.
-- So, we need to unlock this when the helo has landed, which can be anywhere ...
-- But only free the landing coordinate after 1 minute, to ensure that all helos have left.
Helicopter:HandleEvent( EVENTS.Land,
function( Helicopter, EventData )
self:ScheduleOnce( 60,
function( Helicopter )
AI_CARGO_QUEUE[Helicopter] = nil
end, Helicopter
)
end
)
self:SetCarrier( Helicopter )
return self
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: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
function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To )
Helicopter:F( { Name = Helicopter:GetName() } )
if Helicopter and Helicopter:IsAlive() then
-- S_EVENT_LAND is directly called in two situations:
-- 1 - When the helo lands normally on the ground.
-- 2 - when the helo is hit and goes RTB or even when it is destroyed.
-- For point 2, this is an issue, the infantry may not unload in this case!
-- So we check if the helo is on the ground, and velocity< 5.
-- Only then the infantry can unload (and load too, for consistency)!
self:F( { Helicopter:GetName(), Height = Helicopter:GetHeight( true ), Velocity = Helicopter:GetVelocityKMH() } )
if self.RoutePickup == true then
if Helicopter:GetHeight( true ) <= 5 and Helicopter:GetVelocityKMH() < 10 then
--self:Load( Helicopter:GetPointVec2() )
self:Load( self.PickupZone )
self.RoutePickup = false
end
end
if self.RouteDeploy == true then
if Helicopter:GetHeight( true ) <= 5 and Helicopter:GetVelocityKMH() < 10 then
self:Unload( self.DeployZone )
self.RouteDeploy = false
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:onafterQueue( Helicopter, From, Event, To, Coordinate, Speed, DeployZone )
local HelicopterInZone = false
if Helicopter and Helicopter:IsAlive() == true then
local Distance = Coordinate:DistanceFromPointVec2( Helicopter:GetCoordinate() )
if Distance > 2000 then
self:__Queue( -10, Coordinate, Speed, DeployZone )
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 )
-- Keep the DeployZone, because when the helo has landed, we want to provide the DeployZone to the mission designer as part of the Unloaded event.
self.DeployZone = DeployZone
else
self:__Queue( -10, Coordinate, Speed, DeployZone )
end
end
else
AI_CARGO_QUEUE[Helicopter] = nil
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
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 ), 150, CoordinateTo:GetRandomCoordinateInRadius( 800, 500 ) )
Route[#Route].task = Helicopter:TaskCombo( Tasks )
Route[#Route+1] = WaypointTo
-- Now route the helicopter
Helicopter:Route( Route, 0 )
end
end
--- On after Deployed event.
-- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Cargo.Cargo#CARGO Cargo Cargo object.
-- @param #boolean Deployed Cargo is deployed.
-- @return #boolean True if all cargo has been unloaded.
function AI_CARGO_HELICOPTER:onafterDeployed( Helicopter, From, Event, To, DeployZone )
self:F( { Helicopter, From, Event, To, DeployZone = DeployZone } )
self:Orbit( Helicopter:GetCoordinate(), 50 )
-- Free the coordinate zone after 30 seconds, so that the original helicopter can fly away first.
self:ScheduleOnce( 30,
function( Helicopter )
AI_CARGO_QUEUE[Helicopter] = nil
end, Helicopter
)
self:GetParent( self, AI_CARGO_HELICOPTER ).onafterDeployed( self, Helicopter, From, Event, To, DeployZone )
end
--- On after Pickup event.
-- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate Pickup place.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
-- @param #number Height Height in meters to move to the pickup coordinate. This parameter is ignored for APCs.
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordinate, Speed, Height, PickupZone )
if Helicopter and Helicopter:IsAlive() ~= nil then
Helicopter:Activate()
self.RoutePickup = true
Coordinate.y = Height
local _speed=Speed or Helicopter:GetSpeedMax()*0.5
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,
_speed,
true
)
--- Create a route point of type air.
local WaypointTo = CoordinateTo:WaypointAir(
"RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
_speed,
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.PickupZone = PickupZone
self:GetParent( self, AI_CARGO_HELICOPTER ).onafterPickup( self, Helicopter, From, Event, To, Coordinate, Speed, Height, PickupZone )
end
end
--- Depoloy function and queue.
-- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP AICargoHelicopter
-- @param Core.Point#COORDINATE Coordinate Coordinate
function AI_CARGO_HELICOPTER:_Deploy( AICargoHelicopter, Coordinate, DeployZone )
AICargoHelicopter:__Queue( -10, Coordinate, 100, DeployZone )
end
--- On after Deploy event.
-- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter Transport helicopter.
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
-- @param #number Height Height in meters to move to the deploy coordinate.
function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordinate, Speed, Height, DeployZone )
if Helicopter and Helicopter:IsAlive() ~= nil then
self.RouteDeploy = true
local Route = {}
--- Calculate the target route point.
Coordinate.y = Height
local _speed=Speed or Helicopter:GetSpeedMax()*0.5
--- Create a route point of type air.
local CoordinateFrom = Helicopter:GetCoordinate()
local WaypointFrom = CoordinateFrom:WaypointAir(
"RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
_speed,
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,
_speed,
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, DeployZone )
Tasks[#Tasks+1] = Helicopter:TaskOrbitCircle( math.random( 30, 100 ), _speed, 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, 0 )
self:GetParent( self, AI_CARGO_HELICOPTER ).onafterDeploy( self, Helicopter, From, Event, To, Coordinate, Speed, Height, DeployZone )
end
end
--- On after Home event.
-- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate Home place.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
-- @param #number Height Height in meters to move to the home coordinate.
-- @param Core.Zone#ZONE HomeZone The zone wherein the carrier will return when all cargo has been transported. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinate, Speed, Height, HomeZone )
if Helicopter and Helicopter:IsAlive() ~= nil then
self.RouteHome = true
local Route = {}
--- Calculate the target route point.
Coordinate.y = Height
Speed = Speed or Helicopter:GetSpeedMax()*0.5
--- Create a route point of type air.
local CoordinateFrom = Helicopter:GetCoordinate()
local WaypointFrom = CoordinateFrom:WaypointAir(
"RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
Speed ,
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,
Speed ,
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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,185 @@
--- **AI** -- (R2.5) - Models the automatic assignment of AI escorts to player flights.
--
-- ## Features:
-- --
-- * Provides the facilities to trigger escorts when players join flight slots.
-- *
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_Escort_Dispatcher
-- @image AI_Escort_Dispatcher.JPG
--- @type AI_ESCORT_DISPATCHER
-- @extends Core.Fsm#FSM
--- Models the automatic assignment of AI escorts to player flights.
--
-- ===
--
-- @field #AI_ESCORT_DISPATCHER
AI_ESCORT_DISPATCHER = {
ClassName = "AI_ESCORT_DISPATCHER",
}
--- @field #list
AI_ESCORT_DISPATCHER.AI_Escorts = {}
--- Creates a new AI_ESCORT_DISPATCHER object.
-- @param #AI_ESCORT_DISPATCHER self
-- @param Core.Set#SET_GROUP CarrierSet The set of @{Wrapper.Group#GROUP} objects of carriers for which escorts are spawned in.
-- @param Core.Spawn#SPAWN EscortSpawn The spawn object that will spawn in the Escorts.
-- @param Wrapper.Airbase#AIRBASE EscortAirbase The airbase where the escorts are spawned.
-- @param #string EscortName Name of the escort, which will also be the name of the escort menu.
-- @param #string EscortBriefing A text showing the briefing to the player. Note that if no EscortBriefing is provided, the default briefing will be shown.
-- @return #AI_ESCORT_DISPATCHER
-- @usage
--
-- -- Create a new escort when a player joins an SU-25T plane.
-- Create a carrier set, which contains the player slots that can be joined by the players, for which escorts will be defined.
-- local Red_SU25T_CarrierSet = SET_GROUP:New():FilterPrefixes( "Red A2G Player Su-25T" ):FilterStart()
--
-- -- Create a spawn object that will spawn in the escorts, once the player has joined the player slot.
-- local Red_SU25T_EscortSpawn = SPAWN:NewWithAlias( "Red A2G Su-25 Escort", "Red AI A2G SU-25 Escort" ):InitLimit( 10, 10 )
--
-- -- Create an airbase object, where the escorts will be spawned.
-- local Red_SU25T_Airbase = AIRBASE:FindByName( AIRBASE.Caucasus.Maykop_Khanskaya )
--
-- -- Park the airplanes at the airbase, visible before start.
-- Red_SU25T_EscortSpawn:ParkAtAirbase( Red_SU25T_Airbase, AIRBASE.TerminalType.OpenMedOrBig )
--
-- -- New create the escort dispatcher, using the carrier set, the escort spawn object at the escort airbase.
-- -- Provide a name of the escort, which will be also the name appearing on the radio menu for the group.
-- -- And a briefing to appear when the player joins the player slot.
-- Red_SU25T_EscortDispatcher = AI_ESCORT_DISPATCHER:New( Red_SU25T_CarrierSet, Red_SU25T_EscortSpawn, Red_SU25T_Airbase, "Escort Su-25", "You Su-25T is escorted by one Su-25. Use the radio menu to control the escorts." )
--
-- -- The dispatcher needs to be started using the :Start() method.
-- Red_SU25T_EscortDispatcher:Start()
function AI_ESCORT_DISPATCHER:New( CarrierSet, EscortSpawn, EscortAirbase, EscortName, EscortBriefing )
local self = BASE:Inherit( self, FSM:New() ) -- #AI_ESCORT_DISPATCHER
self.CarrierSet = CarrierSet
self.EscortSpawn = EscortSpawn
self.EscortAirbase = EscortAirbase
self.EscortName = EscortName
self.EscortBriefing = EscortBriefing
self:SetStartState( "Idle" )
self:AddTransition( "Monitoring", "Monitor", "Monitoring" )
self:AddTransition( "Idle", "Start", "Monitoring" )
self:AddTransition( "Monitoring", "Stop", "Idle" )
-- Put a Dead event handler on CarrierSet, to ensure that when a carrier is destroyed, that all internal parameters are reset.
function self.CarrierSet.OnAfterRemoved( CarrierSet, From, Event, To, CarrierName, Carrier )
self:F( { Carrier = Carrier:GetName() } )
end
return self
end
function AI_ESCORT_DISPATCHER:onafterStart( From, Event, To )
self:HandleEvent( EVENTS.Birth )
self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventExit )
self:HandleEvent( EVENTS.Crash, self.OnEventExit )
self:HandleEvent( EVENTS.Dead, self.OnEventExit )
end
--- @param #AI_ESCORT_DISPATCHER self
-- @param Core.Event#EVENTDATA EventData
function AI_ESCORT_DISPATCHER:OnEventExit( EventData )
local PlayerGroupName = EventData.IniGroupName
local PlayerGroup = EventData.IniGroup
local PlayerUnit = EventData.IniUnit
self:I({EscortAirbase= self.EscortAirbase } )
self:I({PlayerGroupName = PlayerGroupName } )
self:I({PlayerGroup = PlayerGroup})
self:I({FirstGroup = self.CarrierSet:GetFirst()})
self:I({FindGroup = self.CarrierSet:FindGroup( PlayerGroupName )})
if self.CarrierSet:FindGroup( PlayerGroupName ) then
if self.AI_Escorts[PlayerGroupName] then
self.AI_Escorts[PlayerGroupName]:Stop()
self.AI_Escorts[PlayerGroupName] = nil
end
end
end
--- @param #AI_ESCORT_DISPATCHER self
-- @param Core.Event#EVENTDATA EventData
function AI_ESCORT_DISPATCHER:OnEventBirth( EventData )
local PlayerGroupName = EventData.IniGroupName
local PlayerGroup = EventData.IniGroup
local PlayerUnit = EventData.IniUnit
self:I({EscortAirbase= self.EscortAirbase } )
self:I({PlayerGroupName = PlayerGroupName } )
self:I({PlayerGroup = PlayerGroup})
self:I({FirstGroup = self.CarrierSet:GetFirst()})
self:I({FindGroup = self.CarrierSet:FindGroup( PlayerGroupName )})
if self.CarrierSet:FindGroup( PlayerGroupName ) then
if not self.AI_Escorts[PlayerGroupName] then
local LeaderUnit = PlayerUnit
local EscortGroup = self.EscortSpawn:SpawnAtAirbase( self.EscortAirbase, SPAWN.Takeoff.Hot )
self:I({EscortGroup = EscortGroup})
self:ScheduleOnce( 1,
function( EscortGroup )
local EscortSet = SET_GROUP:New()
EscortSet:AddGroup( EscortGroup )
self.AI_Escorts[PlayerGroupName] = AI_ESCORT:New( LeaderUnit, EscortSet, self.EscortName, self.EscortBriefing )
self.AI_Escorts[PlayerGroupName]:FormationTrail( 0, 100, 0 )
if EscortGroup:IsHelicopter() then
self.AI_Escorts[PlayerGroupName]:MenusHelicopters()
else
self.AI_Escorts[PlayerGroupName]:MenusAirplanes()
end
self.AI_Escorts[PlayerGroupName]:__Start( 0.1 )
end, EscortGroup
)
end
end
end
--- Start Trigger for AI_ESCORT_DISPATCHER
-- @function [parent=#AI_ESCORT_DISPATCHER] Start
-- @param #AI_ESCORT_DISPATCHER self
--- Start Asynchronous Trigger for AI_ESCORT_DISPATCHER
-- @function [parent=#AI_ESCORT_DISPATCHER] __Start
-- @param #AI_ESCORT_DISPATCHER self
-- @param #number Delay
--- Stop Trigger for AI_ESCORT_DISPATCHER
-- @function [parent=#AI_ESCORT_DISPATCHER] Stop
-- @param #AI_ESCORT_DISPATCHER self
--- Stop Asynchronous Trigger for AI_ESCORT_DISPATCHER
-- @function [parent=#AI_ESCORT_DISPATCHER] __Stop
-- @param #AI_ESCORT_DISPATCHER self
-- @param #number Delay

View File

@@ -0,0 +1,146 @@
--- **AI** -- (R2.5) - Models the assignment of AI escorts to player flights upon request using the radio menu.
--
-- ## Features:
--
-- * Provides the facilities to trigger escorts when players join flight units.
-- * Provide a menu for which escorts can be requested.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module AI.AI_ESCORT_DISPATCHER_REQUEST
-- @image AI_ESCORT_DISPATCHER_REQUEST.JPG
--- @type AI_ESCORT_DISPATCHER_REQUEST
-- @extends Core.Fsm#FSM
--- Models the assignment of AI escorts to player flights upon request using the radio menu.
--
-- ===
--
-- @field #AI_ESCORT_DISPATCHER_REQUEST
AI_ESCORT_DISPATCHER_REQUEST = {
ClassName = "AI_ESCORT_DISPATCHER_REQUEST",
}
--- @field #list
AI_ESCORT_DISPATCHER_REQUEST.AI_Escorts = {}
--- Creates a new AI_ESCORT_DISPATCHER_REQUEST object.
-- @param #AI_ESCORT_DISPATCHER_REQUEST self
-- @param Core.Set#SET_GROUP CarrierSet The set of @{Wrapper.Group#GROUP} objects of carriers for which escorts are requested.
-- @param Core.Spawn#SPAWN EscortSpawn The spawn object that will spawn in the Escorts.
-- @param Wrapper.Airbase#AIRBASE EscortAirbase The airbase where the escorts are spawned.
-- @param #string EscortName Name of the escort, which will also be the name of the escort menu.
-- @param #string EscortBriefing A text showing the briefing to the player. Note that if no EscortBriefing is provided, the default briefing will be shown.
-- @return #AI_ESCORT_DISPATCHER_REQUEST
function AI_ESCORT_DISPATCHER_REQUEST:New( CarrierSet, EscortSpawn, EscortAirbase, EscortName, EscortBriefing )
local self = BASE:Inherit( self, FSM:New() ) -- #AI_ESCORT_DISPATCHER_REQUEST
self.CarrierSet = CarrierSet
self.EscortSpawn = EscortSpawn
self.EscortAirbase = EscortAirbase
self.EscortName = EscortName
self.EscortBriefing = EscortBriefing
self:SetStartState( "Idle" )
self:AddTransition( "Monitoring", "Monitor", "Monitoring" )
self:AddTransition( "Idle", "Start", "Monitoring" )
self:AddTransition( "Monitoring", "Stop", "Idle" )
-- Put a Dead event handler on CarrierSet, to ensure that when a carrier is destroyed, that all internal parameters are reset.
function self.CarrierSet.OnAfterRemoved( CarrierSet, From, Event, To, CarrierName, Carrier )
self:F( { Carrier = Carrier:GetName() } )
end
return self
end
function AI_ESCORT_DISPATCHER_REQUEST:onafterStart( From, Event, To )
self:HandleEvent( EVENTS.Birth )
self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventExit )
self:HandleEvent( EVENTS.Crash, self.OnEventExit )
self:HandleEvent( EVENTS.Dead, self.OnEventExit )
end
--- @param #AI_ESCORT_DISPATCHER_REQUEST self
-- @param Core.Event#EVENTDATA EventData
function AI_ESCORT_DISPATCHER_REQUEST:OnEventExit( EventData )
local PlayerGroupName = EventData.IniGroupName
local PlayerGroup = EventData.IniGroup
local PlayerUnit = EventData.IniUnit
if self.CarrierSet:FindGroup( PlayerGroupName ) then
if self.AI_Escorts[PlayerGroupName] then
self.AI_Escorts[PlayerGroupName]:Stop()
self.AI_Escorts[PlayerGroupName] = nil
end
end
end
--- @param #AI_ESCORT_DISPATCHER_REQUEST self
-- @param Core.Event#EVENTDATA EventData
function AI_ESCORT_DISPATCHER_REQUEST:OnEventBirth( EventData )
local PlayerGroupName = EventData.IniGroupName
local PlayerGroup = EventData.IniGroup
local PlayerUnit = EventData.IniUnit
if self.CarrierSet:FindGroup( PlayerGroupName ) then
if not self.AI_Escorts[PlayerGroupName] then
local LeaderUnit = PlayerUnit
self:ScheduleOnce( 0.1,
function()
self.AI_Escorts[PlayerGroupName] = AI_ESCORT_REQUEST:New( LeaderUnit, self.EscortSpawn, self.EscortAirbase, self.EscortName, self.EscortBriefing )
self.AI_Escorts[PlayerGroupName]:FormationTrail( 0, 100, 0 )
if PlayerGroup:IsHelicopter() then
self.AI_Escorts[PlayerGroupName]:MenusHelicopters()
else
self.AI_Escorts[PlayerGroupName]:MenusAirplanes()
end
self.AI_Escorts[PlayerGroupName]:__Start( 0.1 )
end
)
end
end
end
--- Start Trigger for AI_ESCORT_DISPATCHER_REQUEST
-- @function [parent=#AI_ESCORT_DISPATCHER_REQUEST] Start
-- @param #AI_ESCORT_DISPATCHER_REQUEST self
--- Start Asynchronous Trigger for AI_ESCORT_DISPATCHER_REQUEST
-- @function [parent=#AI_ESCORT_DISPATCHER_REQUEST] __Start
-- @param #AI_ESCORT_DISPATCHER_REQUEST self
-- @param #number Delay
--- Stop Trigger for AI_ESCORT_DISPATCHER_REQUEST
-- @function [parent=#AI_ESCORT_DISPATCHER_REQUEST] Stop
-- @param #AI_ESCORT_DISPATCHER_REQUEST self
--- Stop Asynchronous Trigger for AI_ESCORT_DISPATCHER_REQUEST
-- @function [parent=#AI_ESCORT_DISPATCHER_REQUEST] __Stop
-- @param #AI_ESCORT_DISPATCHER_REQUEST self
-- @param #number Delay

View File

@@ -0,0 +1,316 @@
--- **Functional** -- Taking the lead of AI escorting your flight or of other AI, upon request using the menu.
--
-- ===
--
-- ## Features:
--
-- * Escort navigation commands.
-- * Escort hold at position commands.
-- * Escorts reporting detected targets.
-- * Escorts scanning targets in advance.
-- * Escorts attacking specific targets.
-- * Request assistance from other groups for attack.
-- * Manage rule of engagement of escorts.
-- * Manage the allowed evasion techniques of escorts.
-- * Make escort to execute a defined mission or path.
-- * Escort tactical situation reporting.
--
-- ===
--
-- ## Missions:
--
-- [ESC - Escorting](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/ESC%20-%20Escorting)
--
-- ===
--
-- Allows you to interact with escorting AI on your flight and take the lead.
--
-- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10).
--
-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes.
-- 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.
--
-- Escorts detect targets using a built-in detection mechanism. The detected targets are reported at a specified time interval.
-- Once targets are reported, each escort has these targets as menu options to command the attack of these targets.
-- Targets are by default grouped per area of 5000 meters, but the kind of detection and the grouping range can be altered.
--
-- Different formations can be selected in the Flight menu: Trail, Stack, Left Line, Right Line, Left Wing, Right Wing, Central Wing and Boxed formations are available.
-- The Flight menu also allows for a mass attack, where all of the escorts are commanded to attack a target.
--
-- Escorts can emit flares to reports their location. They can be commanded to hold at a location, which can be their current or the leader location.
-- In this way, you can spread out the escorts over the battle field before a coordinated attack.
--
-- But basically, the escort class provides 4 modes of operation, and depending on the mode, you are either leading the flight, or following the flight.
--
-- ## Leading the flight
--
-- When leading the flight, you are expected to guide the escorts towards the target areas,
-- and carefully coordinate the attack based on the threat levels reported, and the available weapons
-- carried by the escorts. Ground ships or ground troops can execute A-assisted attacks, when they have long-range ground precision weapons for attack.
--
-- ## Following the flight
--
-- Escorts can be commanded to execute a specific mission path. In this mode, the escorts are in the lead.
-- You as a player, are following the escorts, and are commanding them to progress the mission while
-- ensuring that the escorts survive. You are joining the escorts in the battlefield. They will detect and report targets
-- and you will ensure that the attacks are well coordinated, assigning the correct escort type for the detected target
-- type. Once the attack is finished, the escort will resume the mission it was assigned.
-- In other words, you can use the escorts for reconnaissance, and for guiding the attack.
-- Imagine you as a mi-8 pilot, assigned to pickup cargo. Two ka-50s are guiding the way, and you are
-- following. You are in control. The ka-50s detect targets, report them, and you command how the attack
-- will commence and from where. You can control where the escorts are holding position and which targets
-- are attacked first. You are in control how the ka-50s will follow their mission path.
--
-- Escorts can act as part of a AI A2G dispatcher offensive. In this way, You was a player are in control.
-- The mission is defined by the A2G dispatcher, and you are responsible to join the flight and ensure that the
-- attack is well coordinated.
--
-- It is with great proud that I present you this class, and I hope you will enjoy the functionality and the dynamism
-- it brings in your DCS world simulations.
--
-- # RADIO MENUs that can be created:
--
-- Find a summary below of the current available commands:
--
-- ## Navigation ...:
--
-- Escort group navigation functions:
--
-- * **"Join-Up":** The escort group fill follow you in the assigned formation.
-- * **"Flare":** Provides menu commands to let the escort group shoot a flare in the air in a color.
-- * **"Smoke":** Provides menu commands to let the escort group smoke the air in a color. Note that smoking is only available for ground and naval troops.
--
-- ## Hold position ...:
--
-- Escort group navigation functions:
--
-- * **"At current location":** The escort group will hover above the ground at the position they were. The altitude can be specified as a parameter.
-- * **"At my location":** The escort group will hover or orbit at the position where you are. The escort will fly to your location and hold position. The altitude can be specified as a parameter.
--
-- ## Report targets ...:
--
-- Report targets will make the escort group to report any target that it identifies within detection range. Any detected target can be attacked using the "Attack Targets" menu function. (see below).
--
-- * **"Report now":** Will report the current detected targets.
-- * **"Report targets on":** Will make the escorts to report the detected targets and will fill the "Attack Targets" menu list.
-- * **"Report targets off":** Will stop detecting targets.
--
-- ## Attack targets ...:
--
-- This menu item will list all detected targets within a 15km range. Depending on the level of detection (known/unknown) and visuality, the targets type will also be listed.
-- This menu will be available in Flight menu or in each Escort menu.
--
-- ## Scan targets ...:
--
-- Menu items to pop-up the escort group for target scanning. After scanning, the escort group will resume with the mission or rejoin formation.
--
-- * **"Scan targets 30 seconds":** Scan 30 seconds for targets.
-- * **"Scan targets 60 seconds":** Scan 60 seconds for targets.
--
-- ## Request assistance from ...:
--
-- This menu item will list all detected targets within a 15km range, similar as with the menu item **Attack Targets**.
-- This menu item allows to request attack support from other ground based escorts supporting the current escort.
-- eg. the function allows a player to request support from the Ship escort to attack a target identified by the Plane escort with its Tomahawk missiles.
-- eg. the function allows a player to request support from other Planes escorting to bomb the unit with illumination missiles or bombs, so that the main plane escort can attack the area.
--
-- ## ROE ...:
--
-- Sets the Rules of Engagement (ROE) of the escort group when in flight.
--
-- * **"Hold Fire":** The escort group will hold fire.
-- * **"Return Fire":** The escort group will return fire.
-- * **"Open Fire":** The escort group will open fire on designated targets.
-- * **"Weapon Free":** The escort group will engage with any target.
--
-- ## Evasion ...:
--
-- Will define the evasion techniques that the escort group will perform during flight or combat.
--
-- * **"Fight until death":** The escort group will have no reaction to threats.
-- * **"Use flares, chaff and jammers":** The escort group will use passive defense using flares and jammers. No evasive manoeuvres are executed.
-- * **"Evade enemy fire":** The rescort group will evade enemy fire before firing.
-- * **"Go below radar and evade fire":** The escort group will perform evasive vertical manoeuvres.
--
-- ## Resume Mission ...:
--
-- Escort groups can have their own mission. This menu item will allow the escort group to resume their Mission from a given waypoint.
-- Note that this is really fantastic, as you now have the dynamic of taking control of the escort groups, and allowing them to resume their path or mission.
--
-- ===
--
-- ### Authors: **FlightControl**
--
-- ===
--
-- @module AI.AI_Escort
-- @image Escorting.JPG
--- @type AI_ESCORT_REQUEST
-- @extends AI.AI_Escort#AI_ESCORT
--- AI_ESCORT_REQUEST class
--
-- # AI_ESCORT_REQUEST construction methods.
--
-- Create a new AI_ESCORT_REQUEST object with the @{#AI_ESCORT_REQUEST.New} method:
--
-- * @{#AI_ESCORT_REQUEST.New}: Creates a new AI_ESCORT_REQUEST object from a @{Wrapper.Group#GROUP} for a @{Wrapper.Client#CLIENT}, with an optional briefing text.
--
-- @usage
-- -- Declare a new EscortPlanes object as follows:
--
-- -- First find the GROUP object and the CLIENT object.
-- local EscortUnit = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client.
--
-- -- Now use these 2 objects to construct the new EscortPlanes object.
-- EscortPlanes = AI_ESCORT_REQUEST:New( EscortUnit, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
--
-- @field #AI_ESCORT_REQUEST
AI_ESCORT_REQUEST = {
ClassName = "AI_ESCORT_REQUEST",
}
--- AI_ESCORT_REQUEST.Mode class
-- @type AI_ESCORT_REQUEST.MODE
-- @field #number FOLLOW
-- @field #number MISSION
--- MENUPARAM type
-- @type MENUPARAM
-- @field #AI_ESCORT_REQUEST ParamSelf
-- @field #Distance ParamDistance
-- @field #function ParamFunction
-- @field #string ParamMessage
--- AI_ESCORT_REQUEST class constructor for an AI group
-- @param #AI_ESCORT_REQUEST self
-- @param Wrapper.Client#CLIENT EscortUnit The client escorted by the EscortGroup.
-- @param Core.Spawn#SPAWN EscortSpawn The spawn object of AI, escorting the EscortUnit.
-- @param Wrapper.Airbase#AIRBASE EscortAirbase The airbase where escorts will be spawned once requested.
-- @param #string EscortName Name of the escort.
-- @param #string EscortBriefing A text showing the AI_ESCORT_REQUEST briefing to the player. Note that if no EscortBriefing is provided, the default briefing will be shown.
-- @return #AI_ESCORT_REQUEST
-- @usage
-- EscortSpawn = SPAWN:NewWithAlias( "Red A2G Escort Template", "Red A2G Escort AI" ):InitLimit( 10, 10 )
-- EscortSpawn:ParkAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Sochi_Adler ), AIRBASE.TerminalType.OpenBig )
--
-- local EscortUnit = UNIT:FindByName( "Red A2G Pilot" )
--
-- Escort = AI_ESCORT_REQUEST:New( EscortUnit, EscortSpawn, AIRBASE:FindByName(AIRBASE.Caucasus.Sochi_Adler), "A2G", "Briefing" )
-- Escort:FormationTrail( 50, 100, 100 )
-- Escort:Menus()
-- Escort:__Start( 5 )
function AI_ESCORT_REQUEST:New( EscortUnit, EscortSpawn, EscortAirbase, EscortName, EscortBriefing )
local EscortGroupSet = SET_GROUP:New():FilterDeads():FilterCrashes()
local self = BASE:Inherit( self, AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) ) -- #AI_ESCORT_REQUEST
self.EscortGroupSet = EscortGroupSet
self.EscortSpawn = EscortSpawn
self.EscortAirbase = EscortAirbase
self.LeaderGroup = self.PlayerUnit:GetGroup()
self.Detection = DETECTION_AREAS:New( self.EscortGroupSet, 5000 )
self.Detection:__Start( 30 )
self.SpawnMode = self.__Enum.Mode.Mission
return self
end
--- @param #AI_ESCORT_REQUEST self
function AI_ESCORT_REQUEST:SpawnEscort()
local EscortGroup = self.EscortSpawn:SpawnAtAirbase( self.EscortAirbase, SPAWN.Takeoff.Hot )
self:ScheduleOnce( 0.1,
function( EscortGroup )
EscortGroup:OptionROTVertical()
EscortGroup:OptionROEHoldFire()
self.EscortGroupSet:AddGroup( EscortGroup )
local LeaderEscort = self.EscortGroupSet:GetFirst() -- Wrapper.Group#GROUP
local Report = REPORT:New()
Report:Add( "Joining Up " .. self.EscortGroupSet:GetUnitTypeNames():Text( ", " ) .. " from " .. LeaderEscort:GetCoordinate():ToString( self.EscortUnit ) )
LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.PlayerUnit )
self:SetFlightModeFormation( EscortGroup )
self:FormationTrail()
self:_InitFlightMenus()
self:_InitEscortMenus( EscortGroup )
self:_InitEscortRoute( EscortGroup )
--- @param #AI_ESCORT self
-- @param Core.Event#EVENTDATA EventData
function EscortGroup:OnEventDeadOrCrash( EventData )
self:F( { "EventDead", EventData } )
self.EscortMenu:Remove()
end
EscortGroup:HandleEvent( EVENTS.Dead, EscortGroup.OnEventDeadOrCrash )
EscortGroup:HandleEvent( EVENTS.Crash, EscortGroup.OnEventDeadOrCrash )
end, EscortGroup
)
end
--- @param #AI_ESCORT_REQUEST self
-- @param Core.Set#SET_GROUP EscortGroupSet
function AI_ESCORT_REQUEST:onafterStart( EscortGroupSet )
self:F()
if not self.MenuRequestEscort then
self.MainMenu = MENU_GROUP:New( self.PlayerGroup, self.EscortName )
self.MenuRequestEscort = MENU_GROUP_COMMAND:New( self.LeaderGroup, "Request new escort ", self.MainMenu,
function()
self:SpawnEscort()
end
)
end
self:GetParent( self ).onafterStart( self, EscortGroupSet )
self:HandleEvent( EVENTS.Dead, self.OnEventDeadOrCrash )
self:HandleEvent( EVENTS.Crash, self.OnEventDeadOrCrash )
end
--- @param #AI_ESCORT_REQUEST self
-- @param Core.Set#SET_GROUP EscortGroupSet
function AI_ESCORT_REQUEST:onafterStop( EscortGroupSet )
self:F()
EscortGroupSet:ForEachGroup(
--- @param Core.Group#GROUP EscortGroup
function( EscortGroup )
EscortGroup:WayPointInitialize()
EscortGroup:OptionROTVertical()
EscortGroup:OptionROEOpenFire()
end
)
self.Detection:Stop()
self.MainMenu:Remove()
end
--- Set the spawn mode to be mission execution.
-- @param #AI_ESCORT_REQUEST self
function AI_ESCORT_REQUEST:SetEscortSpawnMission()
self.SpawnMode = self.__Enum.Mode.Mission
end

View File

@@ -1,66 +1,34 @@
--- **AI** -- (R2.1) Build large **formations** of AI @{Group}s flying together.
--- **AI** -- Build large airborne formations of aircraft.
--
-- ![Banner Image](..\Presentations\AI_FORMATION\Dia1.JPG)
-- **Features:**
--
-- * Build in-air formations consisting of more than 40 aircraft as one group.
-- * Build different formation types.
-- * Assign a group leader that will guide the large formation path.
--
-- ===
--
-- AI_FORMATION makes AI @{GROUP}s fly in formation of various compositions.
-- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!!
-- The purpose of the class is to:
--
-- * Make formation building a process that can be managed while in flight, rather than a task.
-- * Human players can guide formations, consisting of larget planes.
-- * Build large formations (like a large bomber field).
-- * Form formations that DCS does not support off the shelve.
--
-- A few remarks:
--
-- * Depending on the type of plane, the change in direction by the leader may result in the formation getting disentangled while in flight and needs to be rebuild.
-- * Formations are vulnerable to collissions, but is depending on the type of plane, the distance between the planes and the speed and angle executed by the leader.
-- * Formations may take a while to build up.
--
-- As a result, the AI_FORMATION is not perfect, but is very useful to:
--
-- * Model large formations when flying straight line.
-- * Make humans guide a large formation, when the planes are wide from each other.
--
-- There are the following types of classes defined:
--
-- * @{#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
-- @module AI.AI_Formation
-- @image AI_Large_Formations.JPG
--- AI_FORMATION class
-- @type AI_FORMATION
-- @extends Fsm#FSM_SET
-- @field Unit#UNIT FollowUnit
-- @field Set#SET_GROUP FollowGroupSet
-- @extends Core.Fsm#FSM_SET
-- @field Wrapper.Unit#UNIT FollowUnit
-- @field Core.Set#SET_GROUP FollowGroupSet
-- @field #string FollowName
-- @field #AI_FORMATION.MODE FollowMode The mode the escort is in.
-- @field Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class.
@@ -68,12 +36,10 @@
-- @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
-- @field #number dtFollow Time step between position updates.
--- # AI_FORMATION class, extends @{Fsm#FSM_SET}
--
-- The #AI_FORMATION class allows you to build large formations, make AI follow a @{Client#CLIENT} (player) leader or a @{Unit#UNIT} (AI) leader.
--- Build large formations, make AI follow a @{Wrapper.Client#CLIENT} (player) leader or a @{Wrapper.Unit#UNIT} (AI) leader.
--
-- AI_FORMATION makes AI @{GROUP}s fly in formation of various compositions.
-- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!!
@@ -99,25 +65,25 @@
--
-- Create a new SPAWN object with the @{#AI_FORMATION.New} method:
--
-- * @{Follow#AI_FORMATION.New}(): Creates a new AI_FORMATION object from a @{Group#GROUP} for a @{Client#CLIENT} or a @{Unit#UNIT}, with an optional briefing text.
-- * @{#AI_FORMATION.New}(): Creates a new AI_FORMATION object from a @{Wrapper.Group#GROUP} for a @{Wrapper.Client#CLIENT} or a @{Wrapper.Unit#UNIT}, with an optional briefing text.
--
-- ## Formation methods
--
-- The following methods can be used to set or change the formation:
--
-- * @{AI_Formation#AI_FORMATION.FormationLine}(): Form a line formation (core formation function).
-- * @{AI_Formation#AI_FORMATION.FormationTrail}(): Form a trail formation.
-- * @{AI_Formation#AI_FORMATION.FormationLeftLine}(): Form a left line formation.
-- * @{AI_Formation#AI_FORMATION.FormationRightLine}(): Form a right line formation.
-- * @{AI_Formation#AI_FORMATION.FormationRightWing}(): Form a right wing formation.
-- * @{AI_Formation#AI_FORMATION.FormationLeftWing}(): Form a left wing formation.
-- * @{AI_Formation#AI_FORMATION.FormationCenterWing}(): Form a center wing formation.
-- * @{AI_Formation#AI_FORMATION.FormationCenterVic}(): Form a Vic formation (same as CenterWing.
-- * @{AI_Formation#AI_FORMATION.FormationCenterBoxed}(): Form a center boxed formation.
-- * @{#AI_FORMATION.FormationLine}(): Form a line formation (core formation function).
-- * @{#AI_FORMATION.FormationTrail}(): Form a trail formation.
-- * @{#AI_FORMATION.FormationLeftLine}(): Form a left line formation.
-- * @{#AI_FORMATION.FormationRightLine}(): Form a right line formation.
-- * @{#AI_FORMATION.FormationRightWing}(): Form a right wing formation.
-- * @{#AI_FORMATION.FormationLeftWing}(): Form a left wing formation.
-- * @{#AI_FORMATION.FormationCenterWing}(): Form a center wing formation.
-- * @{#AI_FORMATION.FormationCenterVic}(): Form a Vic formation (same as CenterWing.
-- * @{#AI_FORMATION.FormationCenterBoxed}(): Form a center boxed formation.
--
-- ## Randomization
--
-- Use the method @{AI_Formation#AI_FORMATION.SetFlightRandomization}() to simulate the formation flying errors that pilots make while in formation. Is a range set in meters.
-- Use the method @{AI.AI_Formation#AI_FORMATION.SetFlightRandomization}() to simulate the formation flying errors that pilots make while in formation. Is a range set in meters.
--
-- @usage
-- local FollowGroupSet = SET_GROUP:New():FilterCategories("plane"):FilterCoalitions("blue"):FilterPrefixes("Follow"):FilterStart()
@@ -141,12 +107,59 @@ AI_FORMATION = {
FollowScheduler = nil,
OptionROE = AI.Option.Air.val.ROE.OPEN_FIRE,
OptionReactionOnThreat = AI.Option.Air.val.REACTION_ON_THREAT.ALLOW_ABORT_MISSION,
dtFollow = 0.5,
}
--- AI_FORMATION.Mode class
-- @type AI_FORMATION.MODE
-- @field #number FOLLOW
-- @field #number MISSION
AI_FORMATION.__Enum = {}
--- @type AI_FORMATION.__Enum.Formation
-- @field #number None
-- @field #number Line
-- @field #number Trail
-- @field #number Stack
-- @field #number LeftLine
-- @field #number RightLine
-- @field #number LeftWing
-- @field #number RightWing
-- @field #number Vic
-- @field #number Box
AI_FORMATION.__Enum.Formation = {
None = 0,
Mission = 1,
Line = 2,
Trail = 3,
Stack = 4,
LeftLine = 5,
RightLine = 6,
LeftWing = 7,
RightWing = 8,
Vic = 9,
Box = 10,
}
--- @type AI_FORMATION.__Enum.Mode
-- @field #number Mission
-- @field #number Formation
AI_FORMATION.__Enum.Mode = {
Mission = "M",
Formation = "F",
Attack = "A",
Reconnaissance = "R",
}
--- @type AI_FORMATION.__Enum.ReportType
-- @field #number All
-- @field #number Airborne
-- @field #number GroundRadar
-- @field #number Ground
AI_FORMATION.__Enum.ReportType = {
Airborne = "*",
Airborne = "A",
GroundRadar = "R",
Ground = "G",
}
--- MENUPARAM type
-- @type MENUPARAM
@@ -157,16 +170,24 @@ AI_FORMATION = {
--- AI_FORMATION class constructor for an AI group
-- @param #AI_FORMATION self
-- @param Unit#UNIT FollowUnit The UNIT leading the FolllowGroupSet.
-- @param Wrapper.Unit#UNIT FollowUnit The UNIT leading the FolllowGroupSet.
-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit.
-- @param #string FollowName Name of the escort.
-- @param #string FollowBriefing Briefing.
-- @return #AI_FORMATION self
function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefing ) --R2.1
local self = BASE:Inherit( self, FSM_SET:New( FollowGroupSet ) )
self:F( { FollowUnit, FollowGroupSet, FollowName } )
self.FollowUnit = FollowUnit -- Unit#UNIT
self.FollowGroupSet = FollowGroupSet -- Set#SET_GROUP
self.FollowUnit = FollowUnit -- Wrapper.Unit#UNIT
self.FollowGroupSet = FollowGroupSet -- Core.Set#SET_GROUP
self.FollowGroupSet:ForEachGroup(
function( FollowGroup )
self:E("Following")
FollowGroup:SetState( self, "Mode", self.__Enum.Mode.Formation )
end
)
self:SetFlightRandomization( 2 )
@@ -174,7 +195,7 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
self:AddTransition( "*", "Stop", "Stopped" )
self:AddTransition( "None", "Start", "Following" )
self:AddTransition( {"None", "Stopped"}, "Start", "Following" )
self:AddTransition( "*", "FormationLine", "*" )
--- FormationLine Handler OnBefore for AI_FORMATION
@@ -655,6 +676,16 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
return self
end
--- Set time interval between updates of the formation.
-- @param #AI_FORMATION self
-- @param #number dt Time step in seconds between formation updates. Default is every 0.5 seconds.
-- @return #AI_FORMATION
function AI_FORMATION:SetFollowTimeInterval(dt) --R2.1
self.dtFollow=dt or 0.5
return self
end
--- This function is for test, it will put on the frequency of the FollowScheduler a red smoke at the direction vector calculated for the escort to fly to.
-- This allows to visualize where the escort is flying to.
-- @param #AI_FORMATION self
@@ -678,14 +709,21 @@ end
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
-- @return #AI_FORMATION
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 } )
function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, Formation ) --R2.1
self:F( { FollowGroupSet, From , Event ,To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, Formation } )
FollowGroupSet:Flush()
XStart = XStart or self.XStart
XSpace = XSpace or self.XSpace
YStart = YStart or self.YStart
YSpace = YSpace or self.YSpace
ZStart = ZStart or self.ZStart
ZSpace = ZSpace or self.ZSpace
FollowGroupSet:Flush( self )
local FollowSet = FollowGroupSet:GetSet()
local i = 0
local i = 1 --FF i=0 caused first unit to have no XSpace! Probably needs further adjustments. This is just a quick work around.
for FollowID, FollowGroup in pairs( FollowSet ) do
@@ -697,6 +735,8 @@ function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, X
local Vec3 = PointVec3:GetVec3()
FollowGroup:SetState( self, "FormationVec3", Vec3 )
i = i + 1
FollowGroup:SetState( FollowGroup, "Formation", Formation )
end
return self
@@ -715,7 +755,7 @@ end
-- @return #AI_FORMATION
function AI_FORMATION:onafterFormationTrail( FollowGroupSet, From , Event , To, XStart, XSpace, YStart ) --R2.1
self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,0,0)
self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,0,0, self.__Enum.Formation.Trail )
return self
end
@@ -734,7 +774,7 @@ end
-- @return #AI_FORMATION
function AI_FORMATION:onafterFormationStack( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace ) --R2.1
self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,YSpace,0,0)
self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,YSpace,0,0, self.__Enum.Formation.Stack )
return self
end
@@ -755,7 +795,7 @@ end
-- @return #AI_FORMATION
function AI_FORMATION:onafterFormationLeftLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) --R2.1
self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,ZStart,ZSpace)
self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,-ZStart,-ZSpace, self.__Enum.Formation.LeftLine )
return self
end
@@ -774,7 +814,7 @@ end
-- @return #AI_FORMATION
function AI_FORMATION:onafterFormationRightLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) --R2.1
self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,-ZStart,-ZSpace)
self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,ZStart,ZSpace,self.__Enum.Formation.RightLine)
return self
end
@@ -793,7 +833,7 @@ end
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
function AI_FORMATION:onafterFormationLeftWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) --R2.1
self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,ZStart,ZSpace)
self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,-ZStart,-ZSpace,self.__Enum.Formation.LeftWing)
return self
end
@@ -813,7 +853,7 @@ end
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
function AI_FORMATION:onafterFormationRightWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) --R2.1
self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,-ZStart,-ZSpace)
self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,ZStart,ZSpace,self.__Enum.Formation.RightWing)
return self
end
@@ -851,6 +891,7 @@ function AI_FORMATION:onafterFormationCenterWing( FollowGroupSet, From , Event ,
local Vec3 = PointVec3:GetVec3()
FollowGroup:SetState( self, "FormationVec3", Vec3 )
i = i + 1
FollowGroup:SetState( FollowGroup, "Formation", self.__Enum.Formation.Vic )
end
return self
@@ -910,13 +951,14 @@ function AI_FORMATION:onafterFormationBox( FollowGroupSet, From , Event , To, XS
local Vec3 = PointVec3:GetVec3()
FollowGroup:SetState( self, "FormationVec3", Vec3 )
i = i + 1
FollowGroup:SetState( FollowGroup, "Formation", self.__Enum.Formation.Box )
end
return self
end
--- Use the method @{AI_Formation#AI_FORMATION.SetFlightRandomization}() to make the air units in your formation randomize their flight a bit while in formation.
--- Use the method @{AI.AI_Formation#AI_FORMATION.SetFlightRandomization}() to make the air units in your formation randomize their flight a bit while in formation.
-- @param #AI_FORMATION self
-- @param #number FlightRandomization The formation flying errors that pilots can make while in formation. Is a range set in meters.
-- @return #AI_FORMATION
@@ -928,17 +970,126 @@ function AI_FORMATION:SetFlightRandomization( FlightRandomization ) --R2.1
end
--- @param Follow#AI_FORMATION self
function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1
self:F( )
--- Gets your escorts to flight mode.
-- @param #AI_FORMATION self
-- @param Wrapper.Group#GROUP FollowGroup FollowGroup.
-- @return #AI_FORMATION
function AI_FORMATION:GetFlightMode( FollowGroup )
if FollowGroup then
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission )
end
return FollowGroup:GetState( FollowGroup, "Mode" )
end
--- This sets your escorts to fly a mission.
-- @param #AI_FORMATION self
-- @param Wrapper.Group#GROUP FollowGroup FollowGroup.
-- @return #AI_FORMATION
function AI_FORMATION:SetFlightModeMission( FollowGroup )
if FollowGroup then
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission )
else
self.EscortGroupSet:ForSomeGroupAlive(
--- @param Core.Group#GROUP EscortGroup
function( FollowGroup )
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission )
end
)
end
return self
end
--- This sets your escorts to execute an attack.
-- @param #AI_FORMATION self
-- @param Wrapper.Group#GROUP FollowGroup FollowGroup.
-- @return #AI_FORMATION
function AI_FORMATION:SetFlightModeAttack( FollowGroup )
if FollowGroup then
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Attack )
else
self.EscortGroupSet:ForSomeGroupAlive(
--- @param Core.Group#GROUP EscortGroup
function( FollowGroup )
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Attack )
end
)
end
return self
end
--- This sets your escorts to fly in a formation.
-- @param #AI_FORMATION self
-- @param Wrapper.Group#GROUP FollowGroup FollowGroup.
-- @return #AI_FORMATION
function AI_FORMATION:SetFlightModeFormation( FollowGroup )
if FollowGroup then
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation )
else
self.EscortGroupSet:ForSomeGroupAlive(
--- @param Core.Group#GROUP EscortGroup
function( FollowGroup )
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation )
end
)
end
return self
end
--- Stop function. Formation will not be updated any more.
-- @param #AI_FORMATION self
-- @param Core.Set#SET_GROUP FollowGroupSet The following set of groups.
-- @param #string From From state.
-- @param #string Event Event.
-- @pram #string To The to state.
function AI_FORMATION:onafterStop(FollowGroupSet, From, Event, To) --R2.1
self:E("Stopping formation.")
end
--- Follow event fuction. Check if coming from state "stopped". If so the transition is rejected.
-- @param #AI_FORMATION self
-- @param Core.Set#SET_GROUP FollowGroupSet The following set of groups.
-- @param #string From From state.
-- @param #string Event Event.
-- @pram #string To The to state.
function AI_FORMATION:onbeforeFollow( FollowGroupSet, From, Event, To ) --R2.1
if From=="Stopped" then
return false -- Deny transition.
end
return true
end
--- @param #AI_FORMATION self
function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1
self:T( { self.FollowUnit.UnitName, self.FollowUnit:IsAlive() } )
if self.FollowUnit:IsAlive() then
local ClientUnit = self.FollowUnit
self:T( {ClientUnit.UnitName } )
local CT1, CT2, CV1, CV2
CT1 = ClientUnit:GetState( self, "CT1" )
@@ -955,120 +1106,139 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1
ClientUnit:SetState( self, "CV1", CV2 )
end
FollowGroupSet:ForEachGroup(
FollowGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP FollowGroup
-- @param Wrapper.Unit#UNIT ClientUnit
function( FollowGroup, Formation, ClientUnit, CT1, CV1, CT2, CV2 )
if FollowGroup:GetState( FollowGroup, "Mode" ) == self.__Enum.Mode.Formation then
FollowGroup:OptionROTPassiveDefense()
FollowGroup:OptionROEReturnFire()
self:T({Mode=FollowGroup:GetState( FollowGroup, "Mode" )})
local GroupUnit = FollowGroup:GetUnit( 1 )
local FollowFormation = FollowGroup:GetState( self, "FormationVec3" )
if FollowFormation then
local FollowDistance = FollowFormation.x
local GT1 = GroupUnit:GetState( self, "GT1" )
if CT1 == nil or CT1 == 0 or GT1 == nil or GT1 == 0 then
GroupUnit:SetState( self, "GV1", GroupUnit:GetPointVec3() )
GroupUnit:SetState( self, "GT1", timer.getTime() )
else
local CD = ( ( CV2.x - CV1.x )^2 + ( CV2.y - CV1.y )^2 + ( CV2.z - CV1.z )^2 ) ^ 0.5
local CT = CT2 - CT1
local CS = ( 3600 / CT ) * ( CD / 1000 ) / 3.6
local CDv = { x = CV2.x - CV1.x, y = CV2.y - CV1.y, z = CV2.z - CV1.z }
local Ca = math.atan2( CDv.x, CDv.z )
FollowGroup:OptionROTEvadeFire()
FollowGroup:OptionROEReturnFire()
local GroupUnit = FollowGroup:GetUnit( 1 )
local FollowFormation = FollowGroup:GetState( self, "FormationVec3" )
if FollowFormation then
local FollowDistance = FollowFormation.x
local GT1 = GroupUnit:GetState( self, "GT1" )
local GT2 = timer.getTime()
local GV1 = GroupUnit:GetState( self, "GV1" )
local GV2 = GroupUnit:GetPointVec3()
GV2:AddX( math.random( -Formation.FlightRandomization / 2, Formation.FlightRandomization / 2 ) )
GV2:AddY( math.random( -Formation.FlightRandomization / 2, Formation.FlightRandomization / 2 ) )
GV2:AddZ( math.random( -Formation.FlightRandomization / 2, Formation.FlightRandomization / 2 ) )
GroupUnit:SetState( self, "GT1", GT2 )
GroupUnit:SetState( self, "GV1", GV2 )
local GD = ( ( GV2.x - GV1.x )^2 + ( GV2.y - GV1.y )^2 + ( GV2.z - GV1.z )^2 ) ^ 0.5
local GT = GT2 - GT1
if CT1 == nil or CT1 == 0 or GT1 == nil or GT1 == 0 then
GroupUnit:SetState( self, "GV1", GroupUnit:GetPointVec3() )
GroupUnit:SetState( self, "GT1", timer.getTime() )
else
local CD = ( ( CV2.x - CV1.x )^2 + ( CV2.y - CV1.y )^2 + ( CV2.z - CV1.z )^2 ) ^ 0.5
local CT = CT2 - CT1
local CS = ( 3600 / CT ) * ( CD / 1000 ) / 3.6
local CDv = { x = CV2.x - CV1.x, y = CV2.y - CV1.y, z = CV2.z - CV1.z }
local Ca = math.atan2( CDv.x, CDv.z )
local GT1 = GroupUnit:GetState( self, "GT1" )
local GT2 = timer.getTime()
local GV1 = GroupUnit:GetState( self, "GV1" )
local GV2 = GroupUnit:GetPointVec3()
GV2:AddX( math.random( -Formation.FlightRandomization / 2, Formation.FlightRandomization / 2 ) )
GV2:AddY( math.random( -Formation.FlightRandomization / 2, Formation.FlightRandomization / 2 ) )
GV2:AddZ( math.random( -Formation.FlightRandomization / 2, Formation.FlightRandomization / 2 ) )
GroupUnit:SetState( self, "GT1", GT2 )
GroupUnit:SetState( self, "GV1", GV2 )
local GD = ( ( GV2.x - GV1.x )^2 + ( GV2.y - GV1.y )^2 + ( GV2.z - GV1.z )^2 ) ^ 0.5
local GT = GT2 - GT1
-- Calculate the distance
local GDv = { x = GV2.x - CV1.x, y = GV2.y - CV1.y, z = GV2.z - CV1.z }
local Alpha_T = math.atan2( GDv.x, GDv.z ) - math.atan2( CDv.x, CDv.z )
local Alpha_R = ( Alpha_T < 0 ) and Alpha_T + 2 * math.pi or Alpha_T
local Position = math.cos( Alpha_R )
local GD = ( ( GDv.x )^2 + ( GDv.z )^2 ) ^ 0.5
local Distance = GD * Position + - CS * 0.5
-- Calculate the group direction vector
local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z }
-- Calculate GH2, GH2 with the same height as CV2.
local GH2 = { x = GV2.x, y = CV2.y + FollowFormation.y, z = GV2.z }
-- Calculate the angle of GV to the orthonormal plane
local alpha = math.atan2( GV.x, GV.z )
local GVx = FollowFormation.z * math.cos( Ca ) + FollowFormation.x * math.sin( Ca )
local GVz = FollowFormation.x * math.cos( Ca ) - FollowFormation.z * math.sin( Ca )
-- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2.
-- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2))
local Inclination = ( Distance + FollowFormation.x ) / 10
if Inclination < -30 then
Inclination = - 30
end
local CVI = { x = CV2.x + CS * 10 * math.sin(Ca),
y = GH2.y + Inclination, -- + FollowFormation.y,
y = GH2.y,
z = CV2.z + CS * 10 * math.cos(Ca),
}
-- Calculate the direction vector DV of the escort group. We use CVI as the base and CV2 as the direction.
local DV = { x = CV2.x - CVI.x, y = CV2.y - CVI.y, z = CV2.z - CVI.z }
-- We now calculate the unary direction vector DVu, so that we can multiply DVu with the speed, which is expressed in meters / s.
-- We need to calculate this vector to predict the point the escort group needs to fly to according its speed.
-- The distance of the destination point should be far enough not to have the aircraft starting to swipe left to right...
local DVu = { x = DV.x / FollowDistance, y = DV.y, z = DV.z / FollowDistance }
-- Now we can calculate the group destination vector GDV.
local GDV = { x = CVI.x, y = CVI.y, z = CVI.z }
local ADDx = FollowFormation.x * math.cos(alpha) - FollowFormation.z * math.sin(alpha)
local ADDz = FollowFormation.z * math.cos(alpha) + FollowFormation.x * math.sin(alpha)
local GDV_Formation = {
x = GDV.x - GVx,
y = GDV.y,
z = GDV.z - GVz
}
if self.SmokeDirectionVector == true then
trigger.action.smoke( GDV, trigger.smokeColor.Green )
trigger.action.smoke( GDV_Formation, trigger.smokeColor.White )
end
local Time = 120
local Speed = - ( Distance + FollowFormation.x ) / Time
-- Calculate the distance
local GDv = { x = GV2.x - CV1.x, y = GV2.y - CV1.y, z = GV2.z - CV1.z }
local Alpha_T = math.atan2( GDv.x, GDv.z ) - math.atan2( CDv.x, CDv.z )
local Alpha_R = ( Alpha_T < 0 ) and Alpha_T + 2 * math.pi or Alpha_T
local Position = math.cos( Alpha_R )
local GD = ( ( GDv.x )^2 + ( GDv.z )^2 ) ^ 0.5
local Distance = GD * Position + - CS * 0,5
-- Calculate the group direction vector
local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z }
-- Calculate GH2, GH2 with the same height as CV2.
local GH2 = { x = GV2.x, y = CV2.y + FollowFormation.y, z = GV2.z }
-- Calculate the angle of GV to the orthonormal plane
local alpha = math.atan2( GV.x, GV.z )
local GVx = FollowFormation.z * math.cos( Ca ) + FollowFormation.x * math.sin( Ca )
local GVz = FollowFormation.x * math.cos( Ca ) - FollowFormation.z * math.sin( Ca )
if Distance > -10000 then
Speed = - ( Distance + FollowFormation.x ) / 60
end
if Distance > -2500 then
Speed = - ( Distance + FollowFormation.x ) / 20
end
local GS = Speed + CS
-- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2.
-- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2))
local CVI = { x = CV2.x + CS * 10 * math.sin(Ca),
y = GH2.y - ( Distance + FollowFormation.x ) / 5, -- + FollowFormation.y,
z = CV2.z + CS * 10 * math.cos(Ca),
}
-- Calculate the direction vector DV of the escort group. We use CVI as the base and CV2 as the direction.
local DV = { x = CV2.x - CVI.x, y = CV2.y - CVI.y, z = CV2.z - CVI.z }
-- We now calculate the unary direction vector DVu, so that we can multiply DVu with the speed, which is expressed in meters / s.
-- We need to calculate this vector to predict the point the escort group needs to fly to according its speed.
-- The distance of the destination point should be far enough not to have the aircraft starting to swipe left to right...
local DVu = { x = DV.x / FollowDistance, y = DV.y, z = DV.z / FollowDistance }
-- Now we can calculate the group destination vector GDV.
local GDV = { x = CVI.x, y = CVI.y, z = CVI.z }
local ADDx = FollowFormation.x * math.cos(alpha) - FollowFormation.z * math.sin(alpha)
local ADDz = FollowFormation.z * math.cos(alpha) + FollowFormation.x * math.sin(alpha)
local GDV_Formation = {
x = GDV.x - GVx,
y = GDV.y,
z = GDV.z - GVz
}
if self.SmokeDirectionVector == true then
trigger.action.smoke( GDV, trigger.smokeColor.Green )
trigger.action.smoke( GDV_Formation, trigger.smokeColor.White )
self:F( { Distance = Distance, Speed = Speed, CS = CS, GS = GS } )
-- Now route the escort to the desired point with the desired speed.
FollowGroup:RouteToVec3( GDV_Formation, GS ) -- DCS models speed in Mps (Miles per second)
end
local Time = 60
local Speed = - ( Distance + FollowFormation.x ) / Time
local GS = Speed + CS
if Speed < 0 then
Speed = 0
end
-- Now route the escort to the desired point with the desired speed.
FollowGroup:RouteToVec3( GDV_Formation, GS ) -- DCS models speed in Mps (Miles per second)
end
end
end,
self, ClientUnit, CT1, CV1, CT2, CV2
)
self:__Follow( -0.5 )
self:__Follow( -self.dtFollow )
end
end

View File

@@ -1,6 +1,10 @@
--- **AI** -- **Air Patrolling or Staging.**
--- **AI** -- Perform Air Patrolling for airplanes.
--
-- ![Banner Image](..\Presentations\AI_PATROL\Dia1.JPG)
-- **Features:**
--
-- * Patrol AI airplanes within a given zone.
-- * Trigger detected events when enemy airplanes are detected.
-- * Manage a fuel treshold to RTB on time.
--
-- ===
--
@@ -10,83 +14,43 @@
--
-- * @{#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
-- @module AI.AI_Patrol
-- @image AI_Air_Patrolling.JPG
--- AI_PATROL_ZONE class
-- @type AI_PATROL_ZONE
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling.
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
-- @field Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @field Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @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 DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @field DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @field DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
-- @field DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h.
-- @field Core.Spawn#SPAWN CoordTest
-- @extends Core.Fsm#FSM_CONTROLLABLE
--- # AI_PATROL_ZONE class, extends @{Fsm#FSM_CONTROLLABLE}
--
-- The AI_PATROL_ZONE class implements the core functions to patrol a @{Zone} by an AI @{Controllable} or @{Group}.
--- Implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}.
--
-- ![Process](..\Presentations\AI_PATROL\Dia3.JPG)
--
-- The AI_PATROL_ZONE is assigned a @{Group} and this must be done before the AI_PATROL_ZONE process can be started using the **Start** event.
-- The AI_PATROL_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_PATROL_ZONE process can be started using the **Start** event.
--
-- ![Process](..\Presentations\AI_PATROL\Dia4.JPG)
--
@@ -158,8 +122,8 @@
-- * @{#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.
-- Use the method @{#AI_PATROL_ZONE.GetDetectedUnits}() to obtain a list of the @{Unit}s detected by the AI.
-- 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 @{Wrapper.Unit}s detected by the AI.
--
-- The detection can be filtered to potential targets in a specific zone.
-- Use the method @{#AI_PATROL_ZONE.SetDetectionZone}() to set the zone where targets need to be detected.
@@ -191,11 +155,11 @@ AI_PATROL_ZONE = {
--- Creates a new AI_PATROL_ZONE object
-- @param #AI_PATROL_ZONE self
-- @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 @{Controllable} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h.
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @return #AI_PATROL_ZONE self
-- @usage
-- -- Define a new AI_PATROL_ZONE Object. This PatrolArea will patrol an AIControllable within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h.
@@ -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
@@ -490,8 +454,8 @@ end
--- Sets (modifies) the minimum and maximum speed of the patrol.
-- @param #AI_PATROL_ZONE 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.
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h.
-- @return #AI_PATROL_ZONE self
function AI_PATROL_ZONE:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
@@ -504,8 +468,8 @@ end
--- Sets the floor and ceiling altitude of the patrol.
-- @param #AI_PATROL_ZONE 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.
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @return #AI_PATROL_ZONE self
function AI_PATROL_ZONE:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } )
@@ -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
@@ -598,18 +562,18 @@ function AI_PATROL_ZONE:SetDetectionZone( DetectionZone )
end
end
--- Gets a list of @{Unit#UNIT}s that were detected by the AI.
--- Gets a list of @{Wrapper.Unit#UNIT}s that were detected by the AI.
-- No filtering is applied, so, ANY detected UNIT can be in this list.
-- It is up to the mission designer to use the @{Unit} class and methods to filter the targets.
-- It is up to the mission designer to use the @{Wrapper.Unit} class and methods to filter the targets.
-- @param #AI_PATROL_ZONE self
-- @return #table The list of @{Unit#UNIT}s
-- @return #table The list of @{Wrapper.Unit#UNIT}s
function AI_PATROL_ZONE:GetDetectedUnits()
self:F2()
return self.DetectedUnits
end
--- Clears the list of @{Unit#UNIT}s that were detected by the AI.
--- Clears the list of @{Wrapper.Unit#UNIT}s that were detected by the AI.
-- @param #AI_PATROL_ZONE self
function AI_PATROL_ZONE:ClearDetectedUnits()
self:F2()
@@ -621,13 +585,12 @@ 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 +603,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 +741,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 +756,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 +782,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,
@@ -860,11 +823,10 @@ function AI_PATROL_ZONE:onafterStatus()
local RTB = false
local Fuel = self.Controllable:GetUnit(1):GetFuel()
if Fuel < self.PatrolFuelTresholdPercentage then
self:E( self.Controllable:GetName() .. " is out of fuel:" .. Fuel .. ", RTB!" )
local Fuel = self.Controllable:GetFuelMin()
if Fuel < self.PatrolFuelThresholdPercentage then
self:I( 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,8 +838,8 @@ function AI_PATROL_ZONE:onafterStatus()
-- TODO: Check GROUP damage function.
local Damage = self.Controllable:GetLife()
if Damage <= self.PatrolDamageTreshold then
self:E( self.Controllable:GetName() .. " is damaged:" .. Damage .. ", RTB!" )
if Damage <= self.PatrolDamageThreshold then
self:I( self.Controllable:GetName() .. " is damaged:" .. Damage .. ", RTB!" )
RTB = true
end
@@ -907,7 +869,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,
@@ -938,7 +900,6 @@ end
function AI_PATROL_ZONE: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

View File

@@ -1,15 +1,15 @@
--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occuring on @{Unit}s.
--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occuring on @{Wrapper.Unit}s.
--
-- ![Banner Image](..\Presentations\ACT_ACCOUNT\Dia1.JPG)
--
-- ===
--
-- @module Account
-- @module Actions.Account
-- @image MOOSE.JPG
do -- ACT_ACCOUNT
--- # @{#ACT_ACCOUNT} FSM class, extends @{Fsm#FSM_PROCESS}
--- # @{#ACT_ACCOUNT} FSM class, extends @{Core.Fsm#FSM_PROCESS}
--
-- ## ACT_ACCOUNT state machine:
--
@@ -55,7 +55,7 @@ do -- ACT_ACCOUNT
-- These state transition methods need to provide a return value, which is specified at the function description.
--
-- @type ACT_ACCOUNT
-- @field Set#SET_UNIT TargetSetUnit
-- @field Core.Set#SET_UNIT TargetSetUnit
-- @extends Core.Fsm#FSM_PROCESS
ACT_ACCOUNT = {
ClassName = "ACT_ACCOUNT",
@@ -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
@@ -135,7 +138,7 @@ end -- ACT_ACCOUNT
do -- ACT_ACCOUNT_DEADS
--- # @{#ACT_ACCOUNT_DEADS} FSM class, extends @{Fsm.Account#ACT_ACCOUNT}
--- # @{#ACT_ACCOUNT_DEADS} FSM class, extends @{Core.Fsm.Account#ACT_ACCOUNT}
--
-- The ACT_ACCOUNT_DEADS class accounts (detects, counts and reports) successful kills of DCS units.
-- The process is given a @{Set} of units that will be tracked upon successful destruction.
@@ -148,25 +151,21 @@ do -- ACT_ACCOUNT_DEADS
-- * @{#ACT_ACCOUNT_DEADS.New}(): Creates a new ACT_ACCOUNT_DEADS object.
--
-- @type ACT_ACCOUNT_DEADS
-- @field Set#SET_UNIT TargetSetUnit
-- @field Core.Set#SET_UNIT TargetSetUnit
-- @extends #ACT_ACCOUNT
ACT_ACCOUNT_DEADS = {
ClassName = "ACT_ACCOUNT_DEADS",
TargetSetUnit = nil,
}
--- Creates a new DESTROY process.
-- @param #ACT_ACCOUNT_DEADS self
-- @param Set#SET_UNIT TargetSetUnit
-- @param Core.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,67 +177,115 @@ 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 Event#EVENTDATA EventData
-- @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 Core.Event#EVENTDATA EventData
function ACT_ACCOUNT_DEADS:onfuncEventDead( EventData )
self:T( { "EventDead", EventData } )
@@ -247,4 +294,16 @@ do -- ACT_ACCOUNT_DEADS
end
end
--- DCS Events
--- @param #ACT_ACCOUNT_DEADS self
-- @param Core.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

@@ -2,7 +2,7 @@
--
-- ===
--
-- # @{#ACT_ASSIGN} FSM template class, extends @{Fsm#FSM_PROCESS}
-- # @{#ACT_ASSIGN} FSM template class, extends @{Core.Fsm#FSM_PROCESS}
--
-- ## ACT_ASSIGN state machine:
--
@@ -54,7 +54,7 @@
--
-- ===
--
-- # 1) @{#ACT_ASSIGN_ACCEPT} class, extends @{Fsm.Assign#ACT_ASSIGN}
-- # 1) @{#ACT_ASSIGN_ACCEPT} class, extends @{Core.Fsm.Assign#ACT_ASSIGN}
--
-- The ACT_ASSIGN_ACCEPT class accepts by default a task for a player. No player intervention is allowed to reject the task.
--
@@ -64,7 +64,7 @@
--
-- ===
--
-- # 2) @{#ACT_ASSIGN_MENU_ACCEPT} class, extends @{Fsm.Assign#ACT_ASSIGN}
-- # 2) @{#ACT_ASSIGN_MENU_ACCEPT} class, extends @{Core.Fsm.Assign#ACT_ASSIGN}
--
-- The ACT_ASSIGN_MENU_ACCEPT class accepts a task when the player accepts the task through an added menu option.
-- This assignment type is useful to conditionally allow the player to choose whether or not he would accept the task.
@@ -77,7 +77,8 @@
--
-- ===
--
-- @module Assign
-- @module Actions.Assign
-- @image MOOSE.JPG
do -- ACT_ASSIGN
@@ -155,8 +156,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 +167,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, TaskGroup )
local ProcessGroup = ProcessUnit:GetGroup()
self.Task:Assign( ProcessUnit, ProcessUnit:GetPlayerName() )
end
@@ -193,99 +189,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

@@ -1,9 +1,5 @@
--- (SP) (MP) (FSM) Route AI or players through waypoints or to zones.
--
-- ===
--
-- # @{#ACT_ASSIST} FSM class, extends @{Fsm#FSM_PROCESS}
--
-- ## ACT_ASSIST state machine:
--
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
@@ -52,7 +48,7 @@
--
-- ===
--
-- # 1) @{#ACT_ASSIST_SMOKE_TARGETS_ZONE} class, extends @{Fsm.Route#ACT_ASSIST}
-- # 1) @{#ACT_ASSIST_SMOKE_TARGETS_ZONE} class, extends @{Core.Fsm.Route#ACT_ASSIST}
--
-- The ACT_ASSIST_SMOKE_TARGETS_ZONE class implements the core functions to smoke targets in a @{Zone}.
-- The targets are smoked within a certain range around each target, simulating a realistic smoking behaviour.
@@ -64,7 +60,9 @@
--
-- ===
--
-- @module Smoke
-- @module Actions.Assist
-- @image MOOSE.JPG
do -- ACT_ASSIST
@@ -111,7 +109,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
@@ -143,7 +140,7 @@ do -- ACT_ASSIST_SMOKE_TARGETS_ZONE
--- ACT_ASSIST_SMOKE_TARGETS_ZONE class
-- @type ACT_ASSIST_SMOKE_TARGETS_ZONE
-- @field Set#SET_UNIT TargetSetUnit
-- @field Core.Set#SET_UNIT TargetSetUnit
-- @field Core.Zone#ZONE_BASE TargetZone
-- @extends #ACT_ASSIST
ACT_ASSIST_SMOKE_TARGETS_ZONE = {
@@ -159,7 +156,7 @@ do -- ACT_ASSIST_SMOKE_TARGETS_ZONE
--- Creates a new target smoking 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_ASSIST_SMOKE_TARGETS_ZONE self
-- @param Set#SET_UNIT TargetSetUnit
-- @param Core.Set#SET_UNIT TargetSetUnit
-- @param Core.Zone#ZONE_BASE TargetZone
function ACT_ASSIST_SMOKE_TARGETS_ZONE:New( TargetSetUnit, TargetZone )
local self = BASE:Inherit( self, ACT_ASSIST:New() ) -- #ACT_ASSIST
@@ -178,7 +175,7 @@ do -- ACT_ASSIST_SMOKE_TARGETS_ZONE
--- Creates a new target smoking 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_ASSIST_SMOKE_TARGETS_ZONE self
-- @param Set#SET_UNIT TargetSetUnit
-- @param Core.Set#SET_UNIT TargetSetUnit
-- @param Core.Zone#ZONE_BASE TargetZone
-- @return #ACT_ASSIST_SMOKE_TARGETS_ZONE self
function ACT_ASSIST_SMOKE_TARGETS_ZONE:Init( TargetSetUnit, TargetZone )

View File

@@ -1,198 +0,0 @@
--- @module Process_JTAC
--- PROCESS_JTAC class
-- @type PROCESS_JTAC
-- @field Wrapper.Unit#UNIT ProcessUnit
-- @field Core.Set#SET_UNIT TargetSetUnit
-- @extends Core.Fsm#FSM_PROCESS
PROCESS_JTAC = {
ClassName = "PROCESS_JTAC",
Fsm = {},
TargetSetUnit = nil,
}
--- Creates a new DESTROY process.
-- @param #PROCESS_JTAC self
-- @param Tasking.Task#TASK Task
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Core.Set#SET_UNIT TargetSetUnit
-- @param Wrapper.Unit#UNIT FACUnit
-- @return #PROCESS_JTAC self
function PROCESS_JTAC:New( Task, ProcessUnit, TargetSetUnit, FACUnit )
-- Inherits from BASE
local self = BASE:Inherit( self, PROCESS:New( "JTAC", Task, ProcessUnit ) ) -- #PROCESS_JTAC
self.TargetSetUnit = TargetSetUnit
self.FACUnit = FACUnit
self.DisplayInterval = 60
self.DisplayCount = 30
self.DisplayMessage = true
self.DisplayTime = 10 -- 10 seconds is the default
self.DisplayCategory = "HQ" -- Targets is the default display category
self.Fsm = FSM_PROCESS:New( self, {
initial = 'Assigned',
events = {
{ name = 'Start', from = 'Assigned', to = 'CreatedMenu' },
{ name = 'JTACMenuUpdate', from = 'CreatedMenu', to = 'AwaitingMenu' },
{ name = 'JTACMenuAwait', from = 'AwaitingMenu', to = 'AwaitingMenu' },
{ name = 'JTACMenuSpot', from = 'AwaitingMenu', to = 'AwaitingMenu' },
{ name = 'JTACMenuCancel', from = 'AwaitingMenu', to = 'AwaitingMenu' },
{ name = 'JTACStatus', from = 'AwaitingMenu', to = 'AwaitingMenu' },
{ name = 'Fail', from = 'AwaitingMenu', to = 'Failed' },
{ name = 'Fail', from = 'CreatedMenu', to = 'Failed' },
},
callbacks = {
onStart = self.OnStart,
onJTACMenuUpdate = self.OnJTACMenuUpdate,
onJTACMenuAwait = self.OnJTACMenuAwait,
onJTACMenuSpot = self.OnJTACMenuSpot,
onJTACMenuCancel = self.OnJTACMenuCancel,
},
endstates = { 'Failed' }
} )
self:HandleEvent( EVENTS.Dead, self.EventDead )
return self
end
--- Process Events
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_JTAC self
-- @param Core.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_JTAC:OnStart( Fsm, From, Event, To )
self:NextEvent( Fsm.JTACMenuUpdate )
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_JTAC self
-- @param Core.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_JTAC:OnJTACMenuUpdate( Fsm, From, Event, To )
local function JTACMenuSpot( MenuParam )
self:E( MenuParam.TargetUnit.UnitName )
local self = MenuParam.self
local TargetUnit = MenuParam.TargetUnit
self:NextEvent( self.Fsm.JTACMenuSpot, TargetUnit )
end
local function JTACMenuCancel( MenuParam )
self:E( MenuParam )
local self = MenuParam.self
local TargetUnit = MenuParam.TargetUnit
self:NextEvent( self.Fsm.JTACMenuCancel, TargetUnit )
end
-- Loop each unit in the target set, and determine the threat levels map table.
local UnitThreatLevels = self.TargetSetUnit:GetUnitThreatLevels()
self:E( {"UnitThreadLevels", UnitThreatLevels } )
local JTACMenu = self.ProcessGroup:GetState( self.ProcessGroup, "JTACMenu" )
if not JTACMenu then
JTACMenu = MENU_GROUP:New( self.ProcessGroup, "JTAC", self.MissionMenu )
for ThreatLevel, ThreatLevelTable in pairs( UnitThreatLevels ) do
local JTACMenuThreatLevel = MENU_GROUP:New( self.ProcessGroup, ThreatLevelTable.UnitThreatLevelText, JTACMenu )
for ThreatUnitName, ThreatUnit in pairs( ThreatLevelTable.Units ) do
local JTACMenuUnit = MENU_GROUP:New( self.ProcessGroup, ThreatUnit:GetTypeName(), JTACMenuThreatLevel )
MENU_GROUP_COMMAND:New( self.ProcessGroup, "Lase Target", JTACMenuUnit, JTACMenuSpot, { self = self, TargetUnit = ThreatUnit } )
MENU_GROUP_COMMAND:New( self.ProcessGroup, "Cancel Target", JTACMenuUnit, JTACMenuCancel, { self = self, TargetUnit = ThreatUnit } )
end
end
end
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_JTAC self
-- @param Core.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_JTAC:OnJTACMenuAwait( Fsm, From, Event, To )
if self.DisplayCount >= self.DisplayInterval then
local TaskJTAC = self.Task -- Tasking.Task#TASK_JTAC
TaskJTAC.Spots = TaskJTAC.Spots or {}
for TargetUnitName, SpotData in pairs( TaskJTAC.Spots) do
local TargetUnit = UNIT:FindByName( TargetUnitName )
self.FACUnit:MessageToGroup( "Lasing " .. TargetUnit:GetTypeName() .. " with laser code " .. SpotData:getCode(), 15, self.ProcessGroup )
end
self.DisplayCount = 1
else
self.DisplayCount = self.DisplayCount + 1
end
self:NextEvent( Fsm.JTACMenuAwait )
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_JTAC self
-- @param Core.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT TargetUnit
function PROCESS_JTAC:OnJTACMenuSpot( Fsm, From, Event, To, TargetUnit )
local TargetUnitName = TargetUnit:GetName()
local TaskJTAC = self.Task -- Tasking.Task#TASK_JTAC
TaskJTAC.Spots = TaskJTAC.Spots or {}
TaskJTAC.Spots[TargetUnitName] = TaskJTAC.Spots[TargetUnitName] or {}
local DCSFACObject = self.FACUnit:GetDCSObject()
local TargetVec3 = TargetUnit:GetVec3()
TaskJTAC.Spots[TargetUnitName] = Spot.createInfraRed( self.FACUnit:GetDCSObject(), { x = 0, y = 1, z = 0 }, TargetUnit:GetVec3(), math.random( 1000, 9999 ) )
local SpotData = TaskJTAC.Spots[TargetUnitName]
self.FACUnit:MessageToGroup( "Lasing " .. TargetUnit:GetTypeName() .. " with laser code " .. SpotData:getCode(), 15, self.ProcessGroup )
self:NextEvent( Fsm.JTACMenuAwait )
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_JTAC self
-- @param Core.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT TargetUnit
function PROCESS_JTAC:OnJTACMenuCancel( Fsm, From, Event, To, TargetUnit )
local TargetUnitName = TargetUnit:GetName()
local TaskJTAC = self.Task -- Tasking.Task#TASK_JTAC
TaskJTAC.Spots = TaskJTAC.Spots or {}
if TaskJTAC.Spots[TargetUnitName] then
TaskJTAC.Spots[TargetUnitName]:destroy() -- destroys the spot
TaskJTAC.Spots[TargetUnitName] = nil
end
self.FACUnit:MessageToGroup( "Stopped lasing " .. TargetUnit:GetTypeName(), 15, self.ProcessGroup )
self:NextEvent( Fsm.JTACMenuAwait )
end

View File

@@ -1,173 +0,0 @@
--- @module Process_Pickup
--- PROCESS_PICKUP class
-- @type PROCESS_PICKUP
-- @field Wrapper.Unit#UNIT ProcessUnit
-- @field Core.Set#SET_UNIT TargetSetUnit
-- @extends Core.Fsm#FSM_PROCESS
PROCESS_PICKUP = {
ClassName = "PROCESS_PICKUP",
Fsm = {},
TargetSetUnit = nil,
}
--- Creates a new DESTROY process.
-- @param #PROCESS_PICKUP self
-- @param Tasking.Task#TASK Task
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Core.Set#SET_UNIT TargetSetUnit
-- @return #PROCESS_PICKUP self
function PROCESS_PICKUP:New( Task, ProcessName, ProcessUnit )
-- Inherits from BASE
local self = BASE:Inherit( self, PROCESS:New( ProcessName, Task, ProcessUnit ) ) -- #PROCESS_PICKUP
self.DisplayInterval = 30
self.DisplayCount = 30
self.DisplayMessage = true
self.DisplayTime = 10 -- 10 seconds is the default
self.DisplayCategory = "HQ" -- Targets is the default display category
self.Fsm = FSM_PROCESS:New( self, {
initial = 'Assigned',
events = {
{ name = 'Start', from = 'Assigned', to = 'Navigating' },
{ name = 'Start', from = 'Navigating', to = 'Navigating' },
{ name = 'Nearby', from = 'Navigating', to = 'Preparing' },
{ name = 'Pickup', from = 'Preparing', to = 'Loading' },
{ name = 'Load', from = 'Loading', to = 'Success' },
{ name = 'Fail', from = 'Assigned', to = 'Failed' },
{ name = 'Fail', from = 'Navigating', to = 'Failed' },
{ name = 'Fail', from = 'Preparing', to = 'Failed' },
},
callbacks = {
onStart = self.OnStart,
onNearby = self.OnNearby,
onPickup = self.OnPickup,
onLoad = self.OnLoad,
},
endstates = { 'Success', 'Failed' }
} )
return self
end
--- Process Events
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_PICKUP self
-- @param Core.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_PICKUP:OnStart( Fsm, From, Event, To )
self:NextEvent( Fsm.Start )
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_PICKUP self
-- @param Core.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_PICKUP:OnNavigating( Fsm, From, Event, To )
local TaskGroup = self.ProcessUnit:GetGroup()
if self.DisplayCount >= self.DisplayInterval then
MESSAGE:New( "Your group with assigned " .. self.Task:GetName() .. " task has " .. self.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed.", 5, "HQ" ):ToGroup( TaskGroup )
self.DisplayCount = 1
else
self.DisplayCount = self.DisplayCount + 1
end
return true -- Process always the event.
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_PICKUP self
-- @param Core.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Event#EVENTDATA Event
function PROCESS_PICKUP:OnHitTarget( Fsm, From, Event, To, Event )
self.TargetSetUnit:Flush()
if self.TargetSetUnit:FindUnit( Event.IniUnitName ) then
self.TargetSetUnit:RemoveUnitsByName( Event.IniUnitName )
local TaskGroup = self.ProcessUnit:GetGroup()
MESSAGE:New( "You hit a target. Your group with assigned " .. self.Task:GetName() .. " task has " .. self.TargetSetUnit:Count() .. " targets ( " .. self.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed.", 15, "HQ" ):ToGroup( TaskGroup )
end
if self.TargetSetUnit:Count() > 0 then
self:NextEvent( Fsm.MoreTargets )
else
self:NextEvent( Fsm.Destroyed )
end
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_PICKUP self
-- @param Core.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_PICKUP:OnMoreTargets( Fsm, From, Event, To )
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_PICKUP self
-- @param Core.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Event#EVENTDATA DCSEvent
function PROCESS_PICKUP:OnKilled( Fsm, From, Event, To )
self:NextEvent( Fsm.Restart )
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_PICKUP self
-- @param Core.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_PICKUP:OnRestart( Fsm, From, Event, To )
self:NextEvent( Fsm.Menu )
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_PICKUP self
-- @param Core.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_PICKUP:OnDestroyed( Fsm, From, Event, To )
end
--- DCS Events
--- @param #PROCESS_PICKUP self
-- @param Core.Event#EVENTDATA Event
function PROCESS_PICKUP:EventDead( Event )
if Event.IniDCSUnit then
self:NextEvent( self.Fsm.HitTarget, Event )
end
end

View File

@@ -2,7 +2,7 @@
--
-- ===
--
-- # @{#ACT_ROUTE} FSM class, extends @{Fsm#FSM_PROCESS}
-- # @{#ACT_ROUTE} FSM class, extends @{Core.Fsm#FSM_PROCESS}
--
-- ## ACT_ROUTE state machine:
--
@@ -60,9 +60,9 @@
--
-- ===
--
-- # 1) @{#ACT_ROUTE_ZONE} class, extends @{Fsm.Route#ACT_ROUTE}
-- # 1) @{#ACT_ROUTE_ZONE} class, extends @{Core.Fsm.Route#ACT_ROUTE}
--
-- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Controllable} player @{Unit} to a @{Zone}.
-- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Wrapper.Controllable} player @{Wrapper.Unit} to a @{Zone}.
-- The player receives on perioding times messages with the coordinates of the route to follow.
-- Upon arrival at the zone, a confirmation of arrival is sent, and the process will be ended.
--
@@ -72,7 +72,8 @@
--
-- ===
--
-- @module Route
-- @module Actions.Route
-- @image MOOSE.JPG
do -- ACT_ROUTE
@@ -123,16 +124,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 +159,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 +232,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 +240,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 +258,6 @@ do -- ACT_ROUTE
self.DisplayCount = self.DisplayCount + 1
end
self:T( { DisplayCount = self.DisplayCount } )
if HasArrived then
self:__Arrive( 1 )
else
@@ -313,7 +340,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 +348,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 )
@@ -334,8 +362,8 @@ do -- ACT_ROUTE_POINT
local Distance = self.Coordinate:Get2DDistance( ProcessUnit:GetCoordinate() )
if Distance <= self.Range then
local RouteText = "You have arrived."
self:Message( RouteText )
local RouteText = "Task \"" .. self:GetTask():GetName() .. "\", you have arrived."
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
return true
end
end
@@ -347,15 +375,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 = "Task \"" .. self:GetTask():GetName() .. "\", " .. self:GetRouteText( ProcessUnit )
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Update )
end
end -- ACT_ROUTE_POINT
@@ -403,8 +431,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 +448,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 )
local RouteText = "Task \"" .. self:GetTask():GetName() .. "\", you have arrived within the zone."
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
end
return ProcessUnit:IsInZone( self.Zone )
@@ -432,18 +464,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 = "Task \"" .. self:GetTask():GetName() .. "\", " .. 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,332 @@
--- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object.
--
-- ===
--
-- ### [Demo Missions]()
--
-- ### [YouTube Playlist]()
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @module Cargo.CargoCrate
-- @image Cargo_Crates.JPG
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
--- 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.
--
-- The above cargo classes are used by the following 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} module.
-- * AI Helicopters to transport cargo, using the @{AI.AI_Cargo_Helicopter} module.
-- * AI Planes to transport cargo, using the @{AI.AI_Cargo_Airplane} module.
-- * 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.
--
-- ===
--
-- @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.RemoveUnit, self.OnEventCargoDead )
self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead )
self:SetEventPriority( 4 )
self.NearRadius = NearRadius or 25
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( false ) -- Do not generate a remove unit event, because we want to keep the template for later respawn in the database.
--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 the cargo can be sling loaded.
-- @param #CARGO_CRATE self
function CARGO_CRATE:CanSlingload()
return false
end
--- Check if Cargo Crate is in the radius for the Cargo to be reported.
-- @param #CARGO_CRATE 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_CRATE 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,760 @@
--- **Cargo** -- Management of grouped cargo logistics, which are based on a @{Wrapper.Group} object.
--
-- ===
--
-- ### [Demo Missions]()
--
-- ### [YouTube Playlist]()
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @module Cargo.CargoGroup
-- @image Cargo_Groups.JPG
do -- CARGO_GROUP
--- @type CARGO_GROUP
-- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects.
-- @field #string GroupName The name of the CargoGroup.
-- @extends Cargo.Cargo#CARGO_REPORTABLE
--- Defines a cargo that is represented by a @{Wrapper.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 following 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} module.
-- * AI Helicopters to transport cargo, using the @{AI.AI_Cargo_Helicopter} module.
-- * AI Planes to transport cargo, using the @{AI.AI_Cargo_Airplane} module.
-- * 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.
--
-- @field #CARGO_GROUP CARGO_GROUP
--
CARGO_GROUP = {
ClassName = "CARGO_GROUP",
}
--- CARGO_GROUP constructor.
-- This make a new CARGO_GROUP from a @{Wrapper.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 Group to be transported as cargo.
-- @param #string Type Cargo type, e.g. "Infantry". This is the type used in SET_CARGO:New():FilterTypes("Infantry") to define the valid cargo groups of the set.
-- @param #string Name A user defined name of the cargo group. This name CAN be the same as the group object but can also have a different name. This name MUST be unique!
-- @param #number LoadRadius (optional) Distance in meters until which a cargo is loaded into the carrier. Cargo outside this radius has to be routed by other means to within the radius to be loaded.
-- @param #number NearRadius (optional) Once the units are within this radius of the carrier, they are actually loaded, i.e. disappear from the scene.
-- @return #CARGO_GROUP Cargo group object.
function CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius, NearRadius )
local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_GROUP
self:F( { Type, Name, LoadRadius } )
self.CargoSet = SET_CARGO:New()
self.CargoGroup = CargoGroup
self.Grouped = true
self.CargoUnitTemplate = {}
self.NearRadius = NearRadius
self:SetDeployed( false )
local WeightGroup = 0
local VolumeGroup = 0
self.CargoGroup:Destroy() -- destroy and generate a unit removal event, so that the database gets cleaned, and the linked sets get properly cleaned.
local GroupName = CargoGroup:GetName()
self.CargoName = Name
self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ) )
self.GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
self.GroupTemplate.name = self.CargoName .. "#CARGO"
self.GroupTemplate.groupId = nil
self.GroupTemplate.units = {}
for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do
UnitTemplate.name = UnitTemplate.name .. "#CARGO"
local CargoUnitName = UnitTemplate.name
self.CargoUnitTemplate[CargoUnitName] = UnitTemplate
self.GroupTemplate.units[#self.GroupTemplate.units+1] = self.CargoUnitTemplate[CargoUnitName]
self.GroupTemplate.units[#self.GroupTemplate.units].unitId = nil
-- And we register the spawned unit as part of the CargoSet.
local Unit = UNIT:Register( CargoUnitName )
end
-- Then we register the new group in the database
self.CargoGroup = GROUP:NewTemplate( self.GroupTemplate, self.GroupTemplate.CoalitionID, self.GroupTemplate.CategoryID, self.GroupTemplate.CountryID )
-- Now we spawn the new group based on the template created.
self.CargoObject = _DATABASE:Spawn( self.GroupTemplate )
for CargoUnitID, CargoUnit in pairs( self.CargoObject:GetUnits() ) do
local CargoUnitName = CargoUnit:GetName()
local Cargo = CARGO_UNIT:New( CargoUnit, Type, CargoUnitName, LoadRadius, NearRadius )
self.CargoSet:Add( CargoUnitName, Cargo )
WeightGroup = WeightGroup + Cargo:GetWeight()
end
self:SetWeight( WeightGroup )
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.RemoveUnit, self.OnEventCargoDead )
self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead )
self:SetEventPriority( 4 )
return self
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#CARGO
Cargo:Destroy() -- Destroy the cargo and generate a remove unit event to update the sets.
Cargo:SetStartState( "UnLoaded" )
end
-- Now we spawn the new group based on the template created.
_DATABASE:Spawn( self.GroupTemplate )
for CargoUnitID, CargoUnit in pairs( self.CargoObject:GetUnits() ) do
local CargoUnitName = CargoUnit:GetName()
local Cargo = CARGO_UNIT:New( CargoUnit, self.Type, CargoUnitName, self.LoadRadius )
self.CargoSet:Add( CargoUnitName, Cargo )
end
self:SetDeployed( false )
self:SetStartState( "UnLoaded" )
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
self.CargoObject = nil
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.
self.CargoObject = _DATABASE:Spawn( GroupTemplate )
end
end
--- @param #CARGO_GROUP self
-- @param Core.Event#EVENTDATA EventData
function CARGO_GROUP:OnEventCargoDead( EventData )
self:E(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.Cargo#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
--- After Board Event.
-- @param #CARGO_GROUP self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { CargoCarrier.UnitName, From, Event, To, NearRadius = NearRadius } )
NearRadius = NearRadius or self.NearRadius
-- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2
self.CargoSet:ForEach(
function( Cargo, ... )
self:F( { "Board Unit", Cargo:GetName( ), Cargo:IsDestroyed(), Cargo.CargoObject:IsAlive() } )
local CargoGroup = Cargo.CargoObject --Wrapper.Group#GROUP
CargoGroup:OptionAlarmStateGreen()
Cargo:__Board( 1, CargoCarrier, NearRadius, ... )
end, ...
)
self:__Boarding( -1, CargoCarrier, NearRadius, ... )
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:onafterLoad( 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
if not Cargo:IsDestroyed() then
Cargo:Load( CargoCarrier )
end
end
end
--self.CargoObject:Destroy()
self.CargoCarrier = CargoCarrier
self.CargoCarrier:AddCargo( self )
end
--- Leave Boarding State.
-- @param #CARGO_GROUP self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
--self:F( { CargoCarrier.UnitName, From, Event, To } )
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( -5, 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 #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onafterUnBoard( 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
local ToVec=nil
if ToPointVec2==nil then
ToVec=self.CargoCarrier:GetPointVec2():GetRandomPointVec2InRadius(2*NearRadius, NearRadius)
else
ToVec=ToPointVec2
end
Cargo:__UnBoard( Timer, ToVec, NearRadius )
Timer = Timer + 1
end
end, { NearRadius }
)
self:__UnBoarding( 1, ToPointVec2, NearRadius, ... )
end
end
--- Leave UnBoarding State.
-- @param #CARGO_GROUP self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onafterUnBoarding( 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
self:__UnLoad( 1, ToPointVec2, ... )
else
self:__UnBoarding( 1, ToPointVec2, NearRadius, ... )
end
return false
end
end
--- Enter UnLoaded State.
-- @param #CARGO_GROUP self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2
function CARGO_GROUP:onafterUnLoad( 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(20, 10)
Cargo:UnBoard( 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()
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 or #nil if 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
local CargoCoordinate
if Cargo:IsLoaded() then
CargoCoordinate = Cargo.CargoCarrier:GetCoordinate()
else
CargoCoordinate = Cargo.CargoObject:GetCoordinate()
end
-- FF check if coordinate could be obtained. This was commented out for some (unknown) reason. But the check seems valid!
if CargoCoordinate then
Distance = Coordinate:Get2DDistance( CargoCoordinate )
else
return false
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
--- 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.Cargo#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.Cargo#CARGO
if Cargo then
Cargo:Smoke( SmokeColor, Radius )
end
end
--- Check if the first element of the CargoGroup is the given @{Zone}.
-- @param #CARGO_GROUP 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.Cargo#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,270 @@
--- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object. The cargo can only be slingloaded.
--
-- ===
--
-- ### [Demo Missions]()
--
-- ### [YouTube Playlist]()
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @module Cargo.CargoSlingload
-- @image Cargo_Slingload.JPG
do -- CARGO_SLINGLOAD
--- Models the behaviour of cargo crates, which can only be slingloaded.
-- @type CARGO_SLINGLOAD
-- @extends Cargo.Cargo#CARGO_REPRESENTABLE
--- Defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier.
--
-- 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.
--
-- ===
--
-- @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.RemoveUnit, self.OnEventCargoDead )
self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead )
self:SetEventPriority( 4 )
self.NearRadius = NearRadius or 25
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_SLINGLOAD self
function CARGO_SLINGLOAD: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,382 @@
--- **Cargo** -- Management of single cargo logistics, which are based on a @{Wrapper.Unit} object.
--
-- ===
--
-- ### [Demo Missions]()
--
-- ### [YouTube Playlist]()
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @module Cargo.CargoUnit
-- @image Cargo_Units.JPG
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
--- 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.
-- Note that ground forces behave in a group, and thus, act in formation, regardless if one unit is commanded to move.
--
-- This class is used in CARGO_GROUP, and is not meant to be used by mission designers individually.
--
-- ===
--
-- @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, LoadRadius, NearRadius )
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, LoadRadius, NearRadius ) ) -- #CARGO_UNIT
self:I( { Type, Name, LoadRadius, 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
-- @param #number NearRadius (optional) Defaut 25 m.
function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } )
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
-- @param #number NearRadius (optional) Defaut 100 m.
function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } )
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
-- @param #number NearRadius (optional) Defaut 100 m.
function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } )
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
-- @param Wrapper.Group#GROUP CargoCarrier
-- @param #number NearRadius
function CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { From, Event, To, CargoCarrier, NearRadius = NearRadius } )
self.CargoInAir = self.CargoObject:InAir()
local Desc = self.CargoObject:GetDesc()
local MaxSpeed = Desc.speedMaxOffRoad
local TypeName = Desc.typeName
--self:F({Unit=self.CargoObject:GetName()})
-- A cargo unit can only be boarded if it is not dead
-- 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 NearRadius is given, then use the given NearRadius, otherwise calculate the NearRadius
-- based upon the Carrier bounding radius, which is calculated from the bounding rectangle on the Y axis.
local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius() + 5
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 = 0
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( -5, 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 Default 25 m.
function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { From, Event, To, CargoCarrier:GetName(), NearRadius = NearRadius } )
self:F( { IsAlive=self.CargoObject:IsAlive() } )
if CargoCarrier and CargoCarrier:IsAlive() then -- and self.CargoObject and self.CargoObject:IsAlive() then
if (CargoCarrier:IsAir() and not CargoCarrier:InAir()) or true then
local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius( NearRadius ) + 5
if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
self:__Load( -1, CargoCarrier, ... )
else
if self:IsNear( CargoCarrier:GetPointVec2(), 20 ) then
self:__Boarding( -1, CargoCarrier, NearRadius, ... )
self.RunCount = self.RunCount + 1
else
self:__Boarding( -2, CargoCarrier, NearRadius, ... )
self.RunCount = self.RunCount + 2
end
if self.RunCount >= 40 then
self.RunCount = 0
local Speed = 90
local Angle = 180
local Distance = 0
--self:F({Unit=self.CargoObject:GetName()})
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
--- 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
--self:F({Unit=self.CargoObject:GetName()})
-- Only destroy the CargoObject if there is a CargoObject (packages don't have CargoObjects).
if self.CargoObject then
self.CargoObject:Destroy( false )
--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,38 +1,30 @@
--- **Core** - BASE forms **the basis of the MOOSE framework**. Each class within the MOOSE framework derives from BASE.
--
-- ![Banner Image](..\Presentations\BASE\Dia1.JPG)
--- **Core** - The base class within the framework.
--
-- ===
--
-- The @{#BASE} class is the core root class from where every other class in moose is derived.
-- ## Features:
--
-- * The construction and inheritance of MOOSE classes.
-- * The class naming and numbering system.
-- * The class hierarchy search system.
-- * The tracing of information or objects during mission execution for debuggin purposes.
-- * The subscription to DCS events for event handling in MOOSE objects.
-- * Object inspection.
--
-- ===
--
-- # **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:
-- All classes within the MOOSE framework are derived from the BASE class.
-- Note: The BASE class is an abstract class and is not meant to be used directly.
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- * None.
-- ===
--
-- ### Authors:
--
-- * **FlightControl**: Design & Programming
--
-- @module Base
-- @module Core.Base
-- @image Core_Base.JPG
@@ -49,26 +41,14 @@ local _ClassID = 0
-- @field ClassID The ID number of the class.
-- @field ClassNameAndID The name of the class concatenated with the ID number of the class.
--- # 1) #BASE class
--- BASE class
--
-- # 1. BASE constructor.
--
-- All classes within the MOOSE framework are derived from the BASE class.
--
-- BASE provides facilities for :
-- Any class derived from BASE, will use the @{Core.Base#BASE.New} constructor embedded in the @{Core.Base#BASE.Inherit} method.
-- See an example at the @{Core.Base#BASE.New} method how this is done.
--
-- * The construction and inheritance of MOOSE classes.
-- * The class naming and numbering system.
-- * The class hierarchy search system.
-- * The tracing of information or objects during mission execution for debuggin purposes.
-- * The subscription to DCS events for event handling in MOOSE objects.
--
-- Note: The BASE class is an abstract class and is not meant to be used directly.
--
-- ## 1.1) BASE constructor
--
-- Any class derived from BASE, will use the @{Base#BASE.New} constructor embedded in the @{Base#BASE.Inherit} method.
-- See an example at the @{Base#BASE.New} method how this is done.
--
-- ## 1.2) Trace information for debugging
-- # 2. Trace information for debugging.
--
-- The BASE class contains trace methods to trace progress within a mission execution of a certain object.
-- These trace methods are inherited by each MOOSE class interiting BASE, soeach object created from derived class from BASE can use the tracing methods to trace its execution.
@@ -99,7 +79,7 @@ local _ClassID = 0
--
-- Below a more detailed explanation of the different method types for tracing.
--
-- ### 1.2.1) Tracing methods categories
-- ## 2.1. Tracing methods categories.
--
-- There are basically 3 types of tracing methods available:
--
@@ -107,9 +87,9 @@ local _ClassID = 0
-- * @{#BASE.T}: Used to trace further logic within a function giving optional variables or parameters. A T is indicated at column 44 in the DCS.log file.
-- * @{#BASE.E}: Used to always trace information giving optional variables or parameters. An E is indicated at column 44 in the DCS.log file.
--
-- ### 1.2.2) Tracing levels
-- ## 2.2 Tracing levels.
--
-- There are 3 tracing levels within MOOSE.
-- There are 3 tracing levels within MOOSE.
-- These tracing levels were defined to avoid bulks of tracing to be generated by lots of objects.
--
-- As such, the F and T methods have additional variants to trace level 2 and 3 respectively:
@@ -119,7 +99,7 @@ local _ClassID = 0
-- * @{#BASE.T2}: Trace further logic within a function giving optional variables or parameters with tracing level 2.
-- * @{#BASE.T3}: Trace further logic within a function giving optional variables or parameters with tracing level 3.
--
-- ### 1.2.3) Trace activation.
-- ## 2.3. Trace activation.
--
-- Tracing can be activated in several ways:
--
@@ -129,16 +109,17 @@ local _ClassID = 0
-- * Activate only the tracing of a certain method of a certain class through the @{#BASE.TraceClassMethod}() method.
-- * Activate only the tracing of a certain level through the @{#BASE.TraceLevel}() method.
--
-- ### 1.2.4) Check if tracing is on.
-- ## 2.4. Check if tracing is on.
--
-- The method @{#BASE.IsTrace}() will validate if tracing is activated or not.
--
-- ## 1.3 DCS simulator Event Handling
--
-- # 3. DCS simulator Event Handling.
--
-- The BASE class provides methods to catch DCS Events. These are events that are triggered from within the DCS simulator,
-- and handled through lua scripting. MOOSE provides an encapsulation to handle these events more efficiently.
--
-- ### 1.3.1 Subscribe / Unsubscribe to DCS Events
-- ## 3.1. Subscribe / Unsubscribe to DCS Events.
--
-- At first, the mission designer will need to **Subscribe** to a specific DCS event for the class.
-- So, when the DCS event occurs, the class will be notified of that event.
@@ -147,10 +128,10 @@ local _ClassID = 0
-- * @{#BASE.HandleEvent}(): Subscribe to a DCS Event.
-- * @{#BASE.UnHandleEvent}(): Unsubscribe from a DCS Event.
--
-- ### 1.3.2 Event Handling of DCS Events
-- ## 3.2. Event Handling of DCS Events.
--
-- Once the class is subscribed to the event, an **Event Handling** method on the object or class needs to be written that will be called
-- when the DCS event occurs. The Event Handling method receives an @{Event#EVENTDATA} structure, which contains a lot of information
-- when the DCS event occurs. The Event Handling method receives an @{Core.Event#EVENTDATA} structure, which contains a lot of information
-- about the event that occurred.
--
-- Find below an example of the prototype how to write an event handling function for two units:
@@ -182,7 +163,7 @@ local _ClassID = 0
--
-- See the @{Event} module for more information about event handling.
--
-- ## 1.4) Class identification methods
-- # 4. Class identification methods.
--
-- BASE provides methods to get more information of each object:
--
@@ -190,7 +171,7 @@ local _ClassID = 0
-- * @{#BASE.GetClassName}(): Gets the name of the object, which is the name of the class the object was instantiated from.
-- * @{#BASE.GetClassNameAndID}(): Gets the name and ID of the object.
--
-- ## 1.5) All objects derived from BASE can have "States"
-- # 5. All objects derived from BASE can have "States".
--
-- A mechanism is in place in MOOSE, that allows to let the objects administer **states**.
-- States are essentially properties of objects, which are identified by a **Key** and a **Value**.
@@ -205,7 +186,7 @@ local _ClassID = 0
-- Thus, if the state is to be set for the same object as the object for which the method is used, then provide the same
-- object name to the method.
--
-- ## 1.10) Inheritance
-- # 6. Inheritance.
--
-- The following methods are available to implement inheritance
--
@@ -214,14 +195,23 @@ local _ClassID = 0
--
-- ===
--
-- @field #BASE BASE
--
-- @field #BASE
BASE = {
ClassName = "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 +237,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 +257,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 +300,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 +465,7 @@ do -- Event Handling
-- @return #BASE
function BASE:UnHandleEvent( Event )
self:EventDispatcher():Remove( self, Event )
self:EventDispatcher():RemoveEvent( self, Event )
return self
end
@@ -532,25 +595,43 @@ do -- Event Handling
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when any unit begins firing a weapon that has a high rate of fire. Most common with aircraft cannons (GAU-8), autocannons, and machine guns.
-- initiator : The unit that is doing the shooing.
-- initiator : The unit that is doing the shooting.
-- target: The unit that is being targeted.
-- @function [parent=#BASE] OnEventShootingStart
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when any unit stops firing its weapon. Event will always correspond with a shooting start event.
-- initiator : The unit that was doing the shooing.
-- initiator : The unit that was doing the shooting.
-- @function [parent=#BASE] OnEventShootingEnd
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a new mark was added.
-- MarkID: ID of the mark.
-- @function [parent=#BASE] OnEventMarkAdded
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a mark was removed.
-- MarkID: ID of the mark.
-- @function [parent=#BASE] OnEventMarkRemoved
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a mark text was changed.
-- MarkID: ID of the mark.
-- @function [parent=#BASE] OnEventMarkChange
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
end
--- Creation of a Birth 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.
-- @param DCS#Time EventTime The time stamp of the event.
-- @param DCS#Object Initiator The initiating object of the event.
-- @param #string IniUnitName The initiating unit name.
-- @param place
-- @param subplace
@@ -571,8 +652,8 @@ end
--- Creation of a Crash 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.
-- @param DCS#Time EventTime The time stamp of the event.
-- @param DCS#Object Initiator The initiating object of the event.
function BASE:CreateEventCrash( EventTime, Initiator )
self:F( { EventTime, Initiator } )
@@ -585,10 +666,58 @@ function BASE:CreateEventCrash( EventTime, Initiator )
world.onEvent( Event )
end
-- TODO: Complete Dcs.DCSTypes#Event structure.
--- Creation of a Dead Event.
-- @param #BASE self
-- @param DCS#Time EventTime The time stamp of the event.
-- @param DCS#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 Remove Unit Event.
-- @param #BASE self
-- @param DCS#Time EventTime The time stamp of the event.
-- @param DCS#Object Initiator The initiating object of the event.
function BASE:CreateEventRemoveUnit( EventTime, Initiator )
self:F( { EventTime, Initiator } )
local Event = {
id = EVENTS.RemoveUnit,
time = EventTime,
initiator = Initiator,
}
world.onEvent( Event )
end
--- Creation of a Takeoff Event.
-- @param #BASE self
-- @param DCS#Time EventTime The time stamp of the event.
-- @param DCS#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#Event structure.
--- The main event handling function... This function captures all events generated for the class.
-- @param #BASE self
-- @param Dcs.DCSTypes#Event event
-- @param DCS#Event event
function BASE:onEvent(event)
--self:F( { BaseEventCodes[event.id], event } )
@@ -615,21 +744,113 @@ 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
--self.MasterObject = self
local ScheduleID = self.Scheduler:Schedule(
self,
SchedulerFunction,
{ ... },
Start,
Repeat,
RandomizeFactor,
Stop,
4
)
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:" } )
if self.Scheduler then
_SCHEDULEDISPATCHER:Stop( self.Scheduler, self._.Schedules[SchedulerFunction] )
end
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
-- @param Object The object that will hold the Value set by the Key.
-- @param Key The key that is used as a reference of the value. Note that the key can be a #string, but it can also be any other type!
-- @param Value The value to is stored in the object.
-- @return The Value set.
-- @return #nil The Key was not found and thus the Value could not be retrieved.
-- @return The Value set.
function BASE:SetState( Object, Key, Value )
local ClassNameAndID = Object:GetClassNameAndID()
self.States[ClassNameAndID] = self.States[ClassNameAndID] or {}
self.States[ClassNameAndID][Key] = Value
self:T2( { ClassNameAndID, Key, Value } )
return self.States[ClassNameAndID][Key]
end
@@ -640,21 +861,23 @@ 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.
-- @return The Value retrieved or nil if the Key was not found and thus the Value could not be retrieved.
function BASE:GetState( Object, Key )
local ClassNameAndID = Object:GetClassNameAndID()
if self.States[ClassNameAndID] then
local Value = self.States[ClassNameAndID][Key] or false
self:T2( { ClassNameAndID, Key, Value } )
return Value
end
return nil
end
--- Clear the state of an object.
-- @param #BASE self
-- @param Object The object that holds the Value set by the Key.
-- @param StateName The key that is should be cleared.
function BASE:ClearState( Object, StateName )
local ClassNameAndID = Object:GetClassNameAndID()
@@ -668,8 +891,28 @@ end
-- Log a trace (only shown when trace is on)
-- TODO: Make trace function using variable parameters.
--- Set trace on.
-- @param #BASE self
-- @usage
-- -- Switch the tracing On
-- BASE:TraceOn()
function BASE:TraceOn()
self:TraceOnOff( true )
end
--- Set trace off.
-- @param #BASE self
-- @usage
-- -- Switch the tracing Off
-- BASE:TraceOff()
function BASE:TraceOff()
self:TraceOnOff( false )
end
--- 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.
@@ -682,7 +925,7 @@ end
-- -- Switch the tracing Off
-- BASE:TraceOnOff( false )
function BASE:TraceOnOff( TraceOnOff )
_TraceOnOff = TraceOnOff
_TraceOnOff = TraceOnOff or true
end
@@ -691,7 +934,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
@@ -702,8 +945,8 @@ end
-- @param #BASE self
-- @param #number Level
function BASE:TraceLevel( Level )
_TraceLevel = Level
self:E( "Tracing level " .. Level )
_TraceLevel = Level or 1
self:I( "Tracing level " .. _TraceLevel )
end
--- Trace all methods in MOOSE
@@ -711,12 +954,12 @@ end
-- @param #boolean TraceAll true = trace all methods in MOOSE.
function BASE:TraceAll( TraceAll )
_TraceAll = TraceAll
_TraceAll = TraceAll or true
if _TraceAll then
self:E( "Tracing all methods in MOOSE " )
self:I( "Tracing all methods in MOOSE " )
else
self:E( "Switched off tracing all methods in MOOSE" )
self:I( "Switched off tracing all methods in MOOSE" )
end
end
@@ -726,7 +969,7 @@ end
function BASE:TraceClass( Class )
_TraceClass[Class] = true
_TraceClassMethod[Class] = {}
self:E( "Tracing class " .. Class )
self:I( "Tracing class " .. Class )
end
--- Set tracing for a specific method of class
@@ -739,7 +982,7 @@ function BASE:TraceClassMethod( Class, Method )
_TraceClassMethod[Class].Method = {}
end
_TraceClassMethod[Class].Method[Method] = true
self:E( "Tracing method " .. Method .. " of class " .. Class )
self:I( "Tracing method " .. Method .. " of class " .. Class )
end
--- Trace a function call. This function is private.
@@ -747,10 +990,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
@@ -766,7 +1009,7 @@ function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
if DebugInfoFrom then
LineFrom = DebugInfoFrom.currentline
end
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)" , LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
end
end
end
@@ -776,9 +1019,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 +1035,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 +1050,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 +1065,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
@@ -841,7 +1084,7 @@ function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
if DebugInfoFrom then
LineFrom = DebugInfoFrom.currentline
end
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s" , LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s" , LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
end
end
end
@@ -851,9 +1094,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 +1110,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 +1125,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 +1140,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
@@ -912,10 +1155,72 @@ function BASE:E( Arguments )
LineFrom = DebugInfoFrom.currentline
end
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
else
env.info( string.format( "%1s:%30s%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:%30s%05d.%s(%s)" , LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
else
env.info( string.format( "%1s:%30s%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

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,15 @@
--- **Core R2.1** - EVENT models DCS **event dispatching** using a **publish-subscribe** model.
--
-- ![Banner Image](..\Presentations\EVENT\Dia1.JPG)
--- **Core** - Models DCS event dispatching using a publish-subscribe model.
--
-- ===
--
-- # 1) Event Handling Overview
-- ## Features:
--
-- * Capture DCS events and dispatch them to the subscribed objects.
-- * Generate DCS events to the subscribed objects from within the code.
--
-- ===
--
-- # Event Handling Overview
--
-- ![Objects](..\Presentations\EVENT\Dia2.JPG)
--
@@ -16,7 +21,7 @@
-- Objects can subscribe to different events. The Event dispatcher will publish the received DCS events to the subscribed MOOSE objects, in a specified order.
-- In this way, the subscribed MOOSE objects are kept in sync with your evolving running mission.
--
-- ## 1.1) Event Dispatching
-- ## 1. Event Dispatching
--
-- ![Objects](..\Presentations\EVENT\Dia4.JPG)
--
@@ -43,7 +48,7 @@
--
-- But for some DCS events, the publishing order is reversed. This is due to the fact that objects need to be **erased** instead of added.
--
-- ## 1.2) Event Handling
-- # 2. Event Handling
--
-- ![Objects](..\Presentations\EVENT\Dia8.JPG)
--
@@ -55,14 +60,14 @@
-- The BASE class provides methods to catch DCS Events. These are events that are triggered from within the DCS simulator,
-- and handled through lua scripting. MOOSE provides an encapsulation to handle these events more efficiently.
--
-- ### 1.2.1 Subscribe / Unsubscribe to DCS Events
-- ## 2.1. Subscribe to / Unsubscribe from DCS Events.
--
-- At first, the mission designer will need to **Subscribe** to a specific DCS event for the class.
-- So, when the DCS event occurs, the class will be notified of that event.
-- There are two functions which you use to subscribe to or unsubscribe from an event.
--
-- * @{Base#BASE.HandleEvent}(): Subscribe to a DCS Event.
-- * @{Base#BASE.UnHandleEvent}(): Unsubscribe from a DCS Event.
-- * @{Core.Base#BASE.HandleEvent}(): Subscribe to a DCS Event.
-- * @{Core.Base#BASE.UnHandleEvent}(): Unsubscribe from a DCS Event.
--
-- Note that for a UNIT, the event will be handled **for that UNIT only**!
-- Note that for a GROUP, the event will be handled **for all the UNITs in that GROUP only**!
@@ -71,10 +76,10 @@
-- So if a UNIT within the mission has the subscribed event for that object,
-- then the object event handler will receive the event for that UNIT!
--
-- ### 1.3.2 Event Handling of DCS Events
-- ## 2.2 Event Handling of DCS Events
--
-- Once the class is subscribed to the event, an **Event Handling** method on the object or class needs to be written that will be called
-- when the DCS event occurs. The Event Handling method receives an @{Event#EVENTDATA} structure, which contains a lot of information
-- when the DCS event occurs. The Event Handling method receives an @{Core.Event#EVENTDATA} structure, which contains a lot of information
-- about the event that occurred.
--
-- Find below an example of the prototype how to write an event handling function for two units:
@@ -102,21 +107,21 @@
-- self:SmokeBlue()
-- end
--
-- ### 1.3.3 Event Handling methods that are automatically called upon subscribed DCS events
-- ## 2.3 Event Handling methods that are automatically called upon subscribed DCS events.
--
-- ![Objects](..\Presentations\EVENT\Dia10.JPG)
--
-- The following list outlines which EVENTS item in the structure corresponds to which Event Handling method.
-- Always ensure that your event handling methods align with the events being subscribed to, or nothing will be executed.
--
-- # 2) EVENTS type
-- # 3. EVENTS type
--
-- The EVENTS structure contains names for all the different DCS events that objects can subscribe to using the
-- @{Base#BASE.HandleEvent}() method.
-- @{Core.Base#BASE.HandleEvent}() method.
--
-- # 3) EVENTDATA type
-- # 4. EVENTDATA type
--
-- The @{Event#EVENTDATA} structure contains all the fields that are populated with event information before
-- The @{Core.Event#EVENTDATA} structure contains all the fields that are populated with event information before
-- an Event Handler method is being called by the event dispatcher.
-- The Event Handler received the EVENTDATA object as a parameter, and can be used to investigate further the different events.
-- There are basically 4 main categories of information stored in the EVENTDATA structure:
@@ -157,51 +162,40 @@
--
-- 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
-- @module Core.Event
-- @image Core_Event.JPG
--- The EVENT structure
-- @type EVENT
--- @type EVENT
-- @field #EVENT.Events Events
-- @extends Core.Base#BASE
--- The EVENT class
-- @field #EVENT
EVENT = {
ClassName = "EVENT",
ClassID = 0,
MissionEnd = false,
}
world.event.S_EVENT_NEW_CARGO = world.event.S_EVENT_MAX + 1000
world.event.S_EVENT_DELETE_CARGO = world.event.S_EVENT_MAX + 1001
world.event.S_EVENT_NEW_ZONE = world.event.S_EVENT_MAX + 1002
world.event.S_EVENT_DELETE_ZONE = world.event.S_EVENT_MAX + 1003
world.event.S_EVENT_NEW_ZONE_GOAL = world.event.S_EVENT_MAX + 1004
world.event.S_EVENT_DELETE_ZONE_GOAL = world.event.S_EVENT_MAX + 1005
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1006
--- The different types of events supported by MOOSE.
-- Use this structure to subscribe to events using the @{Base#BASE.HandleEvent}() method.
-- Use this structure to subscribe to events using the @{Core.Base#BASE.HandleEvent}() method.
-- @type EVENTS
EVENTS = {
Shot = world.event.S_EVENT_SHOT,
@@ -227,8 +221,16 @@ EVENTS = {
PlayerComment = world.event.S_EVENT_PLAYER_COMMENT,
ShootingStart = world.event.S_EVENT_SHOOTING_START,
ShootingEnd = world.event.S_EVENT_SHOOTING_END,
MarkAdded = world.event.S_EVENT_MARK_ADDED,
MarkChange = world.event.S_EVENT_MARK_CHANGE,
MarkRemoved = world.event.S_EVENT_MARK_REMOVED,
NewCargo = world.event.S_EVENT_NEW_CARGO,
DeleteCargo = world.event.S_EVENT_DELETE_CARGO,
NewZone = world.event.S_EVENT_NEW_ZONE,
DeleteZone = world.event.S_EVENT_DELETE_ZONE,
NewZoneGoal = world.event.S_EVENT_NEW_ZONE_GOAL,
DeleteZoneGoal = world.event.S_EVENT_DELETE_ZONE_GOAL,
RemoveUnit = world.event.S_EVENT_REMOVE_UNIT,
}
--- The Event structure
@@ -240,40 +242,50 @@ EVENTS = {
-- @type EVENTDATA
-- @field #number id The identifier of the event.
--
-- @field Dcs.DCSUnit#Unit initiator (UNIT/STATIC/SCENERY) The initiating @{Dcs.DCSUnit#Unit} or @{Dcs.DCSStaticObject#StaticObject}.
-- @field Dcs.DCSObject#Object.Category IniObjectCategory (UNIT/STATIC/SCENERY) The initiator object category ( Object.Category.UNIT or Object.Category.STATIC ).
-- @field Dcs.DCSUnit#Unit IniDCSUnit (UNIT/STATIC) The initiating @{DCSUnit#Unit} or @{DCSStaticObject#StaticObject}.
-- @field DCS#Unit initiator (UNIT/STATIC/SCENERY) The initiating @{DCS#Unit} or @{DCS#StaticObject}.
-- @field DCS#Object.Category IniObjectCategory (UNIT/STATIC/SCENERY) The initiator object category ( Object.Category.UNIT or Object.Category.STATIC ).
-- @field DCS#Unit IniDCSUnit (UNIT/STATIC) The initiating @{DCS#Unit} or @{DCS#StaticObject}.
-- @field #string IniDCSUnitName (UNIT/STATIC) The initiating Unit name.
-- @field Wrapper.Unit#UNIT IniUnit (UNIT/STATIC) The initiating MOOSE wrapper @{Unit#UNIT} of the initiator Unit object.
-- @field Wrapper.Unit#UNIT IniUnit (UNIT/STATIC) The initiating MOOSE wrapper @{Wrapper.Unit#UNIT} of the initiator Unit object.
-- @field #string IniUnitName (UNIT/STATIC) The initiating UNIT name (same as IniDCSUnitName).
-- @field Dcs.DCSGroup#Group IniDCSGroup (UNIT) The initiating {DCSGroup#Group}.
-- @field DCS#Group IniDCSGroup (UNIT) The initiating {DCSGroup#Group}.
-- @field #string IniDCSGroupName (UNIT) The initiating Group name.
-- @field Wrapper.Group#GROUP IniGroup (UNIT) The initiating MOOSE wrapper @{Group#GROUP} of the initiator Group object.
-- @field Wrapper.Group#GROUP IniGroup (UNIT) The initiating MOOSE wrapper @{Wrapper.Group#GROUP} of the initiator Group object.
-- @field #string IniGroupName UNIT) The initiating GROUP name (same as IniDCSGroupName).
-- @field #string IniPlayerName (UNIT) The name of the initiating player in case the Unit is a client or player slot.
-- @field Dcs.DCScoalition#coalition.side IniCoalition (UNIT) The coalition of the initiator.
-- @field Dcs.DCSUnit#Unit.Category IniCategory (UNIT) The category of the initiator.
-- @field DCS#coalition.side IniCoalition (UNIT) The coalition of the initiator.
-- @field DCS#Unit.Category IniCategory (UNIT) The category of the initiator.
-- @field #string IniTypeName (UNIT) The type name of the initiator.
--
-- @field Dcs.DCSUnit#Unit target (UNIT/STATIC) The target @{Dcs.DCSUnit#Unit} or @{DCSStaticObject#StaticObject}.
-- @field Dcs.DCSObject#Object.Category TgtObjectCategory (UNIT/STATIC) The target object category ( Object.Category.UNIT or Object.Category.STATIC ).
-- @field Dcs.DCSUnit#Unit TgtDCSUnit (UNIT/STATIC) The target @{DCSUnit#Unit} or @{DCSStaticObject#StaticObject}.
-- @field DCS#Unit target (UNIT/STATIC) The target @{DCS#Unit} or @{DCS#StaticObject}.
-- @field DCS#Object.Category TgtObjectCategory (UNIT/STATIC) The target object category ( Object.Category.UNIT or Object.Category.STATIC ).
-- @field DCS#Unit TgtDCSUnit (UNIT/STATIC) The target @{DCS#Unit} or @{DCS#StaticObject}.
-- @field #string TgtDCSUnitName (UNIT/STATIC) The target Unit name.
-- @field Wrapper.Unit#UNIT TgtUnit (UNIT/STATIC) The target MOOSE wrapper @{Unit#UNIT} of the target Unit object.
-- @field Wrapper.Unit#UNIT TgtUnit (UNIT/STATIC) The target MOOSE wrapper @{Wrapper.Unit#UNIT} of the target Unit object.
-- @field #string TgtUnitName (UNIT/STATIC) The target UNIT name (same as TgtDCSUnitName).
-- @field Dcs.DCSGroup#Group TgtDCSGroup (UNIT) The target {DCSGroup#Group}.
-- @field DCS#Group TgtDCSGroup (UNIT) The target {DCSGroup#Group}.
-- @field #string TgtDCSGroupName (UNIT) The target Group name.
-- @field Wrapper.Group#GROUP TgtGroup (UNIT) The target MOOSE wrapper @{Group#GROUP} of the target Group object.
-- @field Wrapper.Group#GROUP TgtGroup (UNIT) The target MOOSE wrapper @{Wrapper.Group#GROUP} of the target Group object.
-- @field #string TgtGroupName (UNIT) The target GROUP name (same as TgtDCSGroupName).
-- @field #string TgtPlayerName (UNIT) The name of the target player in case the Unit is a client or player slot.
-- @field Dcs.DCScoalition#coalition.side TgtCoalition (UNIT) The coalition of the target.
-- @field Dcs.DCSUnit#Unit.Category TgtCategory (UNIT) The category of the target.
-- @field DCS#coalition.side TgtCoalition (UNIT) The coalition of the target.
-- @field DCS#Unit.Category TgtCategory (UNIT) The category of the target.
-- @field #string TgtTypeName (UNIT) The type name of the target.
--
-- @field weapon The weapon used during the event.
-- @field Weapon
-- @field WeaponName
-- @field WeaponTgtDCSUnit
-- @field DCS#Airbase place The @{DCS#Airbase}
-- @field Wrapper.Airbase#AIRBASE Place The MOOSE airbase object.
-- @field #string PlaceName The name of the airbase.
--
-- @field #table weapon The weapon used during the event.
-- @field #table Weapon
-- @field #string WeaponName Name of the weapon.
-- @field DCS#Unit WeaponTgtDCSUnit Target DCS unit of the weapon.
--
-- @field Cargo.Cargo#CARGO Cargo The cargo object.
-- @field #string CargoName The name of the cargo object.
--
-- @field Core.ZONE#ZONE Zone The zone object.
-- @field #string ZoneName The name of the zone.
@@ -416,6 +428,24 @@ local _EVENTMETA = {
Event = "OnEventShootingEnd",
Text = "S_EVENT_SHOOTING_END"
},
[world.event.S_EVENT_MARK_ADDED] = {
Order = 1,
Side = "I",
Event = "OnEventMarkAdded",
Text = "S_EVENT_MARK_ADDED"
},
[world.event.S_EVENT_MARK_CHANGE] = {
Order = 1,
Side = "I",
Event = "OnEventMarkChange",
Text = "S_EVENT_MARK_CHANGE"
},
[world.event.S_EVENT_MARK_REMOVED] = {
Order = 1,
Side = "I",
Event = "OnEventMarkRemoved",
Text = "S_EVENT_MARK_REMOVED"
},
[EVENTS.NewCargo] = {
Order = 1,
Event = "OnEventNewCargo",
@@ -426,6 +456,31 @@ local _EVENTMETA = {
Event = "OnEventDeleteCargo",
Text = "S_EVENT_DELETE_CARGO"
},
[EVENTS.NewZone] = {
Order = 1,
Event = "OnEventNewZone",
Text = "S_EVENT_NEW_ZONE"
},
[EVENTS.DeleteZone] = {
Order = 1,
Event = "OnEventDeleteZone",
Text = "S_EVENT_DELETE_ZONE"
},
[EVENTS.NewZoneGoal] = {
Order = 1,
Event = "OnEventNewZoneGoal",
Text = "S_EVENT_NEW_ZONE_GOAL"
},
[EVENTS.DeleteZoneGoal] = {
Order = 1,
Event = "OnEventDeleteZoneGoal",
Text = "S_EVENT_DELETE_ZONE_GOAL"
},
[EVENTS.RemoveUnit] = {
Order = -1,
Event = "OnEventRemoveUnit",
Text = "S_EVENT_REMOVE_UNIT"
},
}
@@ -443,7 +498,7 @@ end
--- Initializes the Events structure for the event
-- @param #EVENT self
-- @param Dcs.DCSWorld#world.event EventID
-- @param DCS#world.event EventID
-- @param Core.Base#BASE EventClass
-- @return #EVENT.Events
function EVENT:Init( EventID, EventClass )
@@ -469,18 +524,17 @@ end
--- Removes a subscription
-- @param #EVENT self
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
-- @param Dcs.DCSWorld#world.event EventID
-- @param DCS#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] = nil
@@ -489,11 +543,11 @@ end
--- Resets subscriptions
-- @param #EVENT self
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
-- @param Dcs.DCSWorld#world.event EventID
-- @param DCS#world.event EventID
-- @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
@@ -512,7 +566,7 @@ end
--- Clears all event subscriptions for a @{Base#BASE} derived object.
--- Clears all event subscriptions for a @{Core.Base#BASE} derived object.
-- @param #EVENT self
-- @param Core.Base#BASE EventObject
function EVENT:RemoveAll( EventObject )
@@ -582,12 +636,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
@@ -704,7 +758,7 @@ do -- Event Creation
-- @param #EVENT self
-- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created.
function EVENT:CreateEventNewCargo( Cargo )
self:F( { Cargo } )
self:I( { Cargo } )
local Event = {
id = EVENTS.NewCargo,
@@ -730,6 +784,68 @@ do -- Event Creation
world.onEvent( Event )
end
--- Creation of a New Zone Event.
-- @param #EVENT self
-- @param Core.Zone#ZONE_BASE Zone The Zone created.
function EVENT:CreateEventNewZone( Zone )
self:F( { Zone } )
local Event = {
id = EVENTS.NewZone,
time = timer.getTime(),
zone = Zone,
}
world.onEvent( Event )
end
--- Creation of a Zone Deletion Event.
-- @param #EVENT self
-- @param Core.Zone#ZONE_BASE Zone The Zone created.
function EVENT:CreateEventDeleteZone( Zone )
self:F( { Zone } )
local Event = {
id = EVENTS.DeleteZone,
time = timer.getTime(),
zone = Zone,
}
world.onEvent( Event )
end
--- Creation of a New ZoneGoal Event.
-- @param #EVENT self
-- @param Core.Functional#ZONE_GOAL ZoneGoal The ZoneGoal created.
function EVENT:CreateEventNewZoneGoal( ZoneGoal )
self:F( { ZoneGoal } )
local Event = {
id = EVENTS.NewZoneGoal,
time = timer.getTime(),
ZoneGoal = ZoneGoal,
}
world.onEvent( Event )
end
--- Creation of a ZoneGoal Deletion Event.
-- @param #EVENT self
-- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created.
function EVENT:CreateEventDeleteZoneGoal( ZoneGoal )
self:F( { ZoneGoal } )
local Event = {
id = EVENTS.DeleteZoneGoal,
time = timer.getTime(),
ZoneGoal = ZoneGoal,
}
world.onEvent( Event )
end
--- Creation of a S_EVENT_PLAYER_ENTER_UNIT Event.
-- @param #EVENT self
-- @param Wrapper.Unit#UNIT PlayerUnit.
@@ -754,7 +870,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 +880,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
@@ -784,9 +910,9 @@ function EVENT:onEvent( Event )
if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
Event.IniDCSGroupName = Event.IniDCSGroup:getName()
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
if Event.IniGroup then
--if Event.IniGroup then
Event.IniGroupName = Event.IniDCSGroupName
end
--end
end
Event.IniPlayerName = Event.IniDCSUnit:getPlayerName()
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
@@ -804,6 +930,16 @@ 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()
@@ -828,9 +964,9 @@ function EVENT:onEvent( Event )
if Event.TgtDCSGroup and Event.TgtDCSGroup:isExist() then
Event.TgtDCSGroupName = Event.TgtDCSGroup:getName()
Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName )
if Event.TgtGroup then
--if Event.TgtGroup then
Event.TgtGroupName = Event.TgtDCSGroupName
end
--end
end
Event.TgtPlayerName = Event.TgtDCSUnit:getPlayerName()
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
@@ -842,7 +978,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()
@@ -869,17 +1005,38 @@ function EVENT:onEvent( Event )
--Event.WeaponTgtDCSUnit = Event.Weapon:getTarget()
end
-- Place should be given for takeoff and landing events as well as base captured. It should be a DCS airbase.
if Event.place then
Event.Place=AIRBASE:Find(Event.place)
Event.PlaceName=Event.Place:GetName()
end
-- Mark points.
if Event.idx then
Event.MarkID=Event.idx
Event.MarkVec3=Event.pos
Event.MarkCoordinate=COORDINATE:NewFromVec3(Event.pos)
Event.MarkText=Event.text
Event.MarkCoalition=Event.coalition
Event.MarkGroupID = Event.groupID
end
if Event.cargo then
Event.Cargo = Event.cargo
Event.CargoName = Event.cargo.Name
end
if Event.zone then
Event.Zone = Event.zone
Event.ZoneName = Event.zone.ZoneName
end
local PriorityOrder = EventMeta.Order
local PriorityBegin = PriorityOrder == -1 and 5 or 1
local PriorityEnd = PriorityOrder == -1 and 1 or 5
if Event.IniObjectCategory ~= Object.Category.STATIC then
self:E( { EventMeta.Text, Event, Event.IniDCSUnitName, Event.TgtDCSUnitName, PriorityOrder } )
self:F( { EventMeta.Text, Event, Event.IniDCSUnitName, Event.TgtDCSUnitName, PriorityOrder } )
end
for EventPriority = PriorityBegin, PriorityEnd, PriorityOrder do
@@ -888,10 +1045,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,8 +1058,10 @@ 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
Event.id == EVENTS.Dead or
Event.id == EVENTS.RemoveUnit then
local UnitName = EventClass:GetName()
@@ -913,7 +1072,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 +1088,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 +1100,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,8 +1109,10 @@ 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
Event.id == EVENTS.Dead or
Event.id == EVENTS.RemoveUnit then
-- We can get the name of the EventClass, which is now always a GROUP object.
local GroupName = EventClass:GetName()
@@ -963,12 +1124,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 +1140,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 +1165,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 +1179,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 +1196,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,7 +1,18 @@
--- **Core** - The **FSM** (**F**inite **S**tate **M**achine) class and derived **FSM\_** classes
-- are design patterns allowing efficient (long-lasting) processes and workflows.
--- **Core** - FSM (Finite State Machine) are objects that model and control long lasting business processes and workflow.
--
-- ![Banner Image](..\Presentations\FSM\Dia1.JPG)
-- ===
--
-- ## Features:
--
-- * Provide a base class to model your own state machines.
-- * Trigger events synchronously.
-- * Trigger events asynchronously.
-- * Handle events before or after the event was triggered.
-- * Handle state transitions as a result of event before and after the state change.
-- * For internal moose purposes, further state machines have been designed:
-- - to handle controllables (groups and units).
-- - to handle tasks.
-- - to handle processes.
--
-- ===
--
@@ -52,39 +63,20 @@
--
-- * @{#FSM_TASK}: Models Finite State Machines for @{Task}s.
-- * @{#FSM_PROCESS}: Models Finite State Machines for @{Task} actions, which control @{Client}s.
-- * @{#FSM_CONTROLLABLE}: Models Finite State Machines for @{Controllable}s, which are @{Group}s, @{Unit}s, @{Client}s.
-- * @{#FSM_CONTROLLABLE}: Models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Client}s.
-- * @{#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
-- @module Core.Fsm
-- @image Core_Finite_State_Machine.JPG
do -- FSM
@@ -92,9 +84,7 @@ do -- FSM
-- @extends Core.Base#BASE
--- # FSM class, extends @{Base#BASE}
--
-- A Finite State Machine (FSM) models a process flow that transitions between various **States** through triggered **Events**.
--- A Finite State Machine (FSM) models a process flow that transitions between various **States** through triggered **Events**.
--
-- A FSM can only be in one of a finite number of states.
-- The machine is in only one state at a time; the state it is in at any given time is called the **current state**.
@@ -348,7 +338,7 @@ do -- FSM
--
-- ===
--
-- @field #FSM FSM
-- @field #FSM
--
FSM = {
ClassName = "FSM",
@@ -357,7 +347,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 +406,7 @@ do -- FSM
Transition.Event = Event
Transition.To = To
self:T( Transition )
self:T2( Transition )
self._Transitions[Transition] = Transition
self:_eventmap( self.Events, Transition )
@@ -430,7 +420,7 @@ do -- FSM
return self._Transitions or {}
end
--- Set the default @{Process} template with key ProcessName providing the ProcessClass and the process object when it is assigned to a @{Controllable} by the task.
--- Set the default @{Process} template with key ProcessName providing the ProcessClass and the process object when it is assigned to a @{Wrapper.Controllable} by the task.
-- @param #FSM self
-- @param #table From Can contain a string indicating the From state or a table of strings containing multiple From states.
-- @param #string Event The Event name.
@@ -438,7 +428,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 +451,8 @@ do -- FSM
-- @return #table
function FSM:GetProcesses()
self:F( { Processes = self._Processes } )
return self._Processes or {}
end
@@ -475,6 +467,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 +558,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 +581,140 @@ 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 )
if step == "onafter" or step == "OnAfter" then
self:T( ":::>" .. step .. params[2] .. " : " .. params[1] .. " >> " .. params[2] .. ">" .. step .. params[2] .. "()" .. " >> " .. params[3] )
elseif step == "onbefore" or step == "OnBefore" then
self:T( ":::>" .. step .. params[2] .. " : " .. params[1] .. " >> " .. step .. params[2] .. "()" .. ">" .. params[2] .. " >> " .. params[3] )
elseif step == "onenter" or step == "OnEnter" then
self:T( ":::>" .. step .. params[3] .. " : " .. params[1] .. " >> " .. params[2] .. " >> " .. step .. params[3] .. "()" .. ">" .. params[3] )
elseif step == "onleave" or step == "OnLeave" then
self:T( ":::>" .. step .. params[1] .. " : " .. params[1] .. ">" .. step .. params[1] .. "()" .. " >> " .. params[2] .. " >> " .. params[3] )
else
self:T( ":::>" .. step .. " : " .. params[1] .. " >> " .. params[2] .. " >> " .. params[3] )
end
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
@@ -679,13 +728,13 @@ do -- FSM
if DelaySeconds < 0 then -- Only call the event ONCE!
DelaySeconds = math.abs( DelaySeconds )
if not self._EventSchedules[EventName] then
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1 )
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
self._EventSchedules[EventName] = CallID
else
-- reschedule
end
else
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1 )
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
end
else
error( "FSM: An asynchronous event trigger requires a DelaySeconds parameter!!! This can be positive or negative! Sorry, but will not process this." )
@@ -711,17 +760,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 +792,10 @@ do -- FSM
return self.current
end
function FSM:GetCurrentState()
return self.current
end
function FSM:Is( State )
return self.current == State
@@ -772,14 +824,11 @@ do -- FSM_CONTROLLABLE
-- @field Wrapper.Controllable#CONTROLLABLE Controllable
-- @extends Core.Fsm#FSM
--- # FSM_CONTROLLABLE, extends @{#FSM}
--
-- FSM_CONTROLLABLE class models Finite State Machines for @{Controllable}s, which are @{Group}s, @{Unit}s, @{Client}s.
--- Models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Client}s.
--
-- ===
--
-- @field #FSM_CONTROLLABLE FSM_CONTROLLABLE
--
-- @field #FSM_CONTROLLABLE
FSM_CONTROLLABLE = {
ClassName = "FSM_CONTROLLABLE",
}
@@ -789,10 +838,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 +913,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 +924,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
@@ -905,9 +956,7 @@ do -- FSM_PROCESS
-- @extends Core.Fsm#FSM_CONTROLLABLE
--- # FSM_PROCESS, extends @{#FSM}
--
-- FSM_PROCESS class models Finite State Machines for @{Task} actions, which control @{Client}s.
--- FSM_PROCESS class models Finite State Machines for @{Task} actions, which control @{Client}s.
--
-- ===
--
@@ -924,10 +973,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 +984,29 @@ 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 )
local Result, Value
if self.Controllable and self.Controllable:IsAlive() == true then
Result, Value = xpcall( function() return self[handler]( self, self.Controllable, self.Task, unpack( params ) ) end, ErrorHandler )
end
return Value
--return self[handler]( self, self.Controllable, unpack( params ) )
end
@@ -966,7 +1022,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 +1036,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 +1066,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,32 +1113,32 @@ 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
--- Assign the process to a @{Unit} and activate the process.
--- Assign the process to a @{Wrapper.Unit} and activate the process.
-- @param #FSM_PROCESS self
-- @param Task.Tasking#TASK Task
-- @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 +1148,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 +1169,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
@@ -1145,9 +1200,7 @@ do -- FSM_TASK
-- @field Tasking.Task#TASK Task
-- @extends #FSM
--- # FSM_TASK, extends @{#FSM}
--
-- FSM_TASK class models Finite State Machines for @{Task}s.
--- Models Finite State Machines for @{Tasking.Task}s.
--
-- ===
--
@@ -1159,24 +1212,37 @@ 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
local ErrorHandler = function( errmsg )
env.info( "Error in SCHEDULER function:" .. errmsg )
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] .. " *** Task: " .. self.TaskName )
self._EventSchedules[EventName] = nil
return self[handler]( self, unpack( params ) )
--return self[handler]( self, unpack( params ) )
local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler )
return Value
end
end
@@ -1190,9 +1256,7 @@ do -- FSM_SET
-- @extends Core.Fsm#FSM
--- # FSM_SET, extends @{#FSM}
--
-- FSM_SET class models Finite State Machines for @{Set}s. Note that these FSMs control multiple objects!!! So State concerns here
--- FSM_SET class models Finite State Machines for @{Set}s. Note that these FSMs control multiple objects!!! So State concerns here
-- for multiple objects or the position of the state machine in the process.
--
-- ===
@@ -1236,9 +1300,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,185 @@
--- **Core** - Models the process to achieve goal(s).
--
-- ===
--
-- ## Features:
--
-- * Define the goal.
-- * Monitor the goal achievement.
-- * Manage goal contribution by players.
--
-- ===
--
-- Classes that implement a goal achievement, will derive from GOAL to implement the ways how the achievements can be realized.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module Core.Goal
-- @image Core_Goal.JPG
do -- Goal
--- @type GOAL
-- @extends Core.Fsm#FSM
--- Models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized.
--
-- # 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.
--
-- # 3. Player contributions.
--
-- Goals are most of the time achieved by players. These player achievements can be registered as part of the goal achievement.
-- Use @{#GOAL.AddPlayerContribution}() to add a player contribution to the goal.
-- The player contributions are based on a points system, an internal counter per player.
-- So once the goal has been achieved, the player contributions can be queried using @{#GOAL.GetPlayerContributions}(),
-- that retrieves all contributions done by the players. For one player, the contribution can be queried using @{#GOAL.GetPlayerContribution}().
-- The total amount of player contributions can be queried using @{#GOAL.GetTotalContributions}().
--
-- # 4. Goal achievement.
--
-- Once the goal is achieved, the mission designer will need to trigger the goal achievement using the **Achieved** event.
-- The underlying 2 examples will achieve the goals for the `Goal` object:
--
-- Goal:Achieved() -- Achieve the goal immediately.
-- Goal:__Achieved( 30 ) -- Achieve the goal within 30 seconds.
--
-- # 5. Check goal achievement.
--
-- The method @{#GOAL.IsAchieved}() will return true if the goal is achieved (the trigger **Achieved** was executed).
-- You can use this method to check asynchronously if a goal has been achieved, for example using a scheduler.
--
-- @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
--- Add a new contribution by a player.
-- @param #GOAL self
-- @param #string PlayerName The name of the player.
function GOAL:AddPlayerContribution( PlayerName )
self:F({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
--- Get the players who contributed to achieve the goal.
-- The result is a list of players, sorted by the name of the players.
-- @param #GOAL self
-- @return #list The list of players, indexed by the player name.
function GOAL:GetPlayerContributions()
return self.Players or {}
end
--- Gets the total contributions that happened to achieve the goal.
-- The result is a number.
-- @param #GOAL self
-- @return #number The total number of contributions. 0 is returned if there were no contributions (yet).
function GOAL:GetTotalContributions()
return self.TotalContributions or 0
end
--- Validates if the goal is achieved.
-- @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,43 +1,58 @@
--- **Core** - MESSAGE class takes are of the **real-time notifications** and **messages to players** during a simulation.
--
-- ![Banner Image](..\Presentations\MESSAGE\Dia1.JPG)
--- **Core** - Informs the players using messages during a simulation.
--
-- ===
--
-- @module Message
-- ## Features:
--
-- * A more advanced messaging system using the DCS message system.
-- * Time messages.
-- * Send messages based on a message type, which has a pre-defined duration that can be tweaked in SETTINGS.
-- * Send message to all players.
-- * Send messages to a coalition.
-- * Send messages to a specific group.
--
-- ===
--
-- @module Core.Message
-- @image Core_Message.JPG
--- The MESSAGE class
-- @type MESSAGE
-- @extends Core.Base#BASE
--- # MESSAGE class, extends @{Base#BASE}
--
-- Message System to display Messages to Clients, Coalitions or All.
--- Message System to display Messages to Clients, Coalitions or All.
-- Messages are shown on the display panel for an amount of seconds, and will then disappear.
-- Messages can contain a category which is indicating the category of the message.
--
-- ## MESSAGE construction
--
-- Messages are created with @{Message#MESSAGE.New}. Note that when the MESSAGE object is created, no message is sent yet.
-- Messages are created with @{#MESSAGE.New}. Note that when the MESSAGE object is created, no message is sent yet.
-- To send messages, you need to use the To functions.
--
-- ## Send messages to an audience
--
-- Messages are sent:
--
-- * To a @{Client} using @{Message#MESSAGE.ToClient}().
-- * To a @{Group} using @{Message#MESSAGE.ToGroup}()
-- * To a coalition using @{Message#MESSAGE.ToCoalition}().
-- * To the red coalition using @{Message#MESSAGE.ToRed}().
-- * To the blue coalition using @{Message#MESSAGE.ToBlue}().
-- * To all Players using @{Message#MESSAGE.ToAll}().
-- * To a @{Client} using @{#MESSAGE.ToClient}().
-- * To a @{Wrapper.Group} using @{#MESSAGE.ToGroup}()
-- * To a coalition using @{#MESSAGE.ToCoalition}().
-- * To the red coalition using @{#MESSAGE.ToRed}().
-- * To the blue coalition using @{#MESSAGE.ToBlue}().
-- * To all Players using @{#MESSAGE.ToAll}().
--
-- ## Send conditionally to an audience
--
-- Messages can be sent conditionally to an audience (when a condition is true):
--
-- * To all players using @{Message#MESSAGE.ToAllIf}().
-- * To a coalition using @{Message#MESSAGE.ToCoalitionIf}().
-- * To all players using @{#MESSAGE.ToAllIf}().
-- * To a coalition using @{#MESSAGE.ToCoalitionIf}().
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @field #MESSAGE
MESSAGE = {
@@ -46,12 +61,23 @@ 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
-- @param #string MessageText is the text of the Message.
-- @param #number MessageDuration is a number in seconds of how long the MESSAGE should be shown on the display panel.
-- @param #string MessageCategory (optional) is a string expressing the "category" of the Message. The category will be shown as the first text in the message followed by a ": ".
-- @param #boolean ClearScreen (optional) Clear all previous messages if true.
-- @return #MESSAGE
-- @usage
-- -- Create a series of new Messages.
@@ -63,10 +89,13 @@ MESSAGE = {
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" )
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" )
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score")
function MESSAGE:New( MessageText, MessageDuration, MessageCategory )
function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen )
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
@@ -77,10 +106,15 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory )
else
self.MessageCategory = ""
end
self.ClearScreen=false
if ClearScreen~=nil then
self.ClearScreen=ClearScreen
end
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,9 +123,56 @@ 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.
-- @param #boolean ClearScreen (optional) Clear all previous messages.
-- @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, ClearScreen )
local self = BASE:Inherit( self, BASE:New() )
self:F( { MessageText } )
self.MessageType = MessageType
self.ClearScreen=false
if ClearScreen~=nil then
self.ClearScreen=ClearScreen
end
self.MessageTime = timer.getTime()
self.MessageText = MessageText:gsub("^\n","",1):gsub("\n$","",1)
return self
end
--- Clears all previous messages from the screen before the new message is displayed. Not that this must come before all functions starting with ToX(), e.g. ToAll(), ToGroup() etc.
-- @param #MESSAGE self
-- @return #MESSAGE
function MESSAGE:Clear()
self:F()
self.ClearScreen=true
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.
-- @param Core.Settings#SETTINGS Settings Settings used to display the message.
-- @return #MESSAGE
-- @usage
-- -- Send the 2 messages created with the @{New} method to the Client Group.
@@ -108,14 +189,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 , self.ClearScreen)
end
end
return self
@@ -123,15 +212,23 @@ end
--- Sends a MESSAGE to a Group.
-- @param #MESSAGE self
-- @param Wrapper.Group#GROUP Group is the Group.
-- @return #MESSAGE
function MESSAGE:ToGroup( Group )
-- @param Wrapper.Group#GROUP Group to which the message is displayed.
-- @return #MESSAGE Message object.
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, self.ClearScreen )
end
end
return self
@@ -176,8 +273,9 @@ end
--- Sends a MESSAGE to a Coalition.
-- @param #MESSAGE self
-- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{coalition.side}.
-- @return #MESSAGE
-- @param #DCS.coalition.side CoalitionSide @{#DCS.coalition.side} to which the message is displayed.
-- @param Core.Settings#SETTINGS Settings (Optional) Settings for message display.
-- @return #MESSAGE Message object.
-- @usage
-- -- Send a message created with the @{New} method to the RED coalition.
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED )
@@ -186,12 +284,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, self.ClearScreen )
end
end
return self
@@ -199,8 +305,9 @@ end
--- Sends a MESSAGE to a Coalition if the given Condition is true.
-- @param #MESSAGE self
-- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{coalition.side}.
-- @return #MESSAGE
-- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{coalition.side}.
-- @param #boolean Condition Sends the message only if the condition is true.
-- @return #MESSAGE self
function MESSAGE:ToCoalitionIf( CoalitionSide, Condition )
self:F( CoalitionSide )
@@ -213,6 +320,7 @@ end
--- Sends a MESSAGE to all players.
-- @param #MESSAGE self
-- @param Core.Settings#Settings Settings (Optional) Settings for message display.
-- @return #MESSAGE
-- @usage
-- -- Send a message created to all players.
@@ -222,11 +330,19 @@ end
-- or
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" )
-- MessageAll:ToAll()
function MESSAGE:ToAll()
function MESSAGE:ToAll(Settings)
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, self.ClearScreen )
end
return self
end
@@ -238,8 +354,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,85 +1,90 @@
--- **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)
--- **Core** - Is responsible for everything that is related to radio transmission and you can hear in DCS, be it TACAN beacons, Radio transmissions.
--
-- ===
--
-- ## Features:
--
-- * Provide radio functionality to broadcast radio transmissions.
-- * Provide beacon functionality to assist pilots.
--
-- The Radio contains 2 classes : RADIO and BEACON
--
-- What are radio communications in DCS ?
-- What are radio communications in DCS?
--
-- * Radio transmissions consist of **sound files** that are broadcasted on a specific **frequency** (e.g. 115MHz) and **modulation** (e.g. AM),
-- * They can be **subtitled** for a specific **duration**, the **power** in Watts of the transmiter's antenna can be set, and the transmission can be **looped**.
--
-- How to supply DCS my own Sound Files ?
-- How to supply DCS my own Sound Files?
--
-- * Your sound files need to be encoded in **.ogg** or .wav,
-- * Your sound files should be **as tiny as possible**. It is suggested you encode in .ogg with low bitrate and sampling settings,
-- * They need to be added in .\l10n\DEFAULT\ in you .miz file (wich can be decompressed like a .zip file),
-- * For simplicty sake, you can **let DCS' Mission Editor add the file** itself, by creating a new Trigger with the action "Sound to Country", and choosing your sound file and a country you don't use in your mission.
-- * For simplicity sake, you can **let DCS' Mission Editor add the file** itself, by creating a new Trigger with the action "Sound to Country", and choosing your sound file and a country you don't use in your mission.
--
-- Due to weird DCS quirks, **radio communications behave differently** if sent by a @{Unit#UNIT} or a @{Group#GROUP} or by any other @{Positionable#POSITIONABLE}
-- Due to weird DCS quirks, **radio communications behave differently** if sent by a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or by any other @{Wrapper.Positionable#POSITIONABLE}
--
-- * If the transmitter is a @{Unit#UNIT} or a @{Group#GROUP}, DCS will set the power of the transmission automatically,
-- * If the transmitter is any other @{Positionable#POSITIONABLE}, the transmisison can't be subtitled or looped.
-- * If the transmitter is a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}, DCS will set the power of the transmission automatically,
-- * If the transmitter is any other @{Wrapper.Positionable#POSITIONABLE}, the transmisison can't be subtitled or looped.
--
-- Note that obviously, the **frequency** and the **modulation** of the transmission are important only if the players are piloting an **Advanced System Modelling** enabled aircraft,
-- like the A10C or the Mirage 2000C. They will **hear the transmission** if they are tuned on the **right frequency and modulation** (and if they are close enough - more on that below).
-- If a FC3 airacraft is used, it will **hear every communication, whatever the frequency and the modulation** is set to. The same is true for TACAN beacons. If your aircaft isn't compatible,
-- If an FC3 aircraft is used, it will **hear every communication, whatever the frequency and the modulation** is set to. The same is true for TACAN beacons. If your aircraft isn't compatible,
-- you won't hear/be able to use the TACAN beacon informations.
--
-- ===
--
-- ### Author: Hugues "Grey_Echo" Bousquet
-- ### Authors: Hugues "Grey_Echo" Bousquet, funkyfranky
--
-- @module Radio
-- @module Core.Radio
-- @image Core_Radio.JPG
--- # RADIO class, extends @{Base#BASE}
--- Models the radio capability.
--
-- ## RADIO usage
--
-- There are 3 steps to a successful radio transmission.
--
-- * First, you need to **"add a @{#RADIO} object** to your @{Positionable#POSITIONABLE}. This is done using the @{Positionable#POSITIONABLE.GetRadio}() function,
-- * First, you need to **"add a @{#RADIO} object** to your @{Wrapper.Positionable#POSITIONABLE}. This is done using the @{Wrapper.Positionable#POSITIONABLE.GetRadio}() function,
-- * Then, you will **set the relevant parameters** to the transmission (see below),
-- * When done, you can actually **broadcast the transmission** (i.e. play the sound) with the @{RADIO.Broadcast}() function.
--
-- Methods to set relevant parameters for both a @{Unit#UNIT} or a @{Group#GROUP} or any other @{Positionable#POSITIONABLE}
-- Methods to set relevant parameters for both a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or any other @{Wrapper.Positionable#POSITIONABLE}
--
-- * @{#RADIO.SetFileName}() : Sets the file name of your sound file (e.g. "Noise.ogg"),
-- * @{#RADIO.SetFrequency}() : Sets the frequency of your transmission.
-- * @{#RADIO.SetModulation}() : Sets the modulation of your transmission.
-- * @{#RADIO.SetLoop}() : Choose if you want the transmission to be looped. If you need your transmission to be looped, you might need a @{#BEACON} instead...
--
-- Additional Methods to set relevant parameters if the transmiter is a @{Unit#UNIT} or a @{Group#GROUP}
-- Additional Methods to set relevant parameters if the transmitter is a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}
--
-- * @{#RADIO.SetSubtitle}() : Set both the subtitle and its duration,
-- * @{#RADIO.NewUnitTransmission}() : Shortcut to set all the relevant parameters in one method call
--
-- Additional Methods to set relevant parameters if the transmiter is any other @{Positionable#POSITIONABLE}
-- Additional Methods to set relevant parameters if the transmitter is any other @{Wrapper.Positionable#POSITIONABLE}
--
-- * @{#RADIO.SetPower}() : Sets the power of the antenna in Watts
-- * @{#RADIO.NewGenericTransmission}() : Shortcut to set all the relevant parameters in one method call
--
-- What is this power thing ?
-- What is this power thing?
--
-- * If your transmission is sent by a @{Positionable#POSITIONABLE} other than a @{Unit#UNIT} or a @{Group#GROUP}, you can set the power of the antenna,
-- * If your transmission is sent by a @{Wrapper.Positionable#POSITIONABLE} other than a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}, you can set the power of the antenna,
-- * Otherwise, DCS sets it automatically, depending on what's available on your Unit,
-- * If the player gets **too far** from the transmiter, or if the antenna is **too weak**, the transmission will **fade** and **become noisyer**,
-- * If the player gets **too far** from the transmitter, or if the antenna is **too weak**, the transmission will **fade** and **become noisyer**,
-- * This an automated DCS calculation you have no say on,
-- * For reference, a standard VOR station has a 100W antenna, a standard AA TACAN has a 120W antenna, and civilian ATC's antenna usually range between 300 and 500W,
-- * For reference, a standard VOR station has a 100 W antenna, a standard AA TACAN has a 120 W antenna, and civilian ATC's antenna usually range between 300 and 500 W,
-- * Note that if the transmission has a subtitle, it will be readable, regardless of the quality of the transmission.
--
-- @type RADIO
-- @field Positionable#POSITIONABLE Positionable The transmiter
-- @field #string FileName Name of the sound file
-- @field #number Frequency Frequency of the transmission in Hz
-- @field #number Modulation Modulation of the transmission (either radio.modulation.AM or radio.modulation.FM)
-- @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 Wrapper.Controllable#CONTROLLABLE Positionable The @{#CONTROLLABLE} that will transmit the radio calls.
-- @field #string FileName Name of the sound file played.
-- @field #number Frequency Frequency of the transmission in Hz.
-- @field #number Modulation Modulation of the transmission (either radio.modulation.AM or radio.modulation.FM).
-- @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 Transmission is repeated (default true).
-- @field #string alias Name of the radio transmitter.
-- @extends Core.Base#BASE
RADIO = {
ClassName = "RADIO",
@@ -89,18 +94,19 @@ RADIO = {
Subtitle = "",
SubtitleDuration = 0,
Power = 100,
Loop = 0,
Loop = false,
alias=nil,
}
--- Create a new RADIO Object. This doesn't broadcast a transmission, though, use @{#RADIO.Broadcast} to actually broadcast
-- If you want to create a RADIO, you probably should use @{Positionable#POSITIONABLE.GetRadio}() instead
--- Create a new RADIO Object. This doesn't broadcast a transmission, though, use @{#RADIO.Broadcast} to actually broadcast.
-- If you want to create a RADIO, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetRadio}() instead.
-- @param #RADIO self
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities.
-- @return #RADIO Radio
-- @return #nil If Positionable is invalid
-- @return #RADIO The RADIO object or #nil if Positionable is invalid.
function RADIO:New(Positionable)
-- Inherit base
local self = BASE:Inherit( self, BASE:New() ) -- Core.Radio#RADIO
self:F(Positionable)
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure positionable is valid
@@ -108,11 +114,27 @@ function RADIO:New(Positionable)
return self
end
self:E({"The passed positionable is invalid, no RADIO created", Positionable})
self:E({error="The passed positionable is invalid, no RADIO created!", positionable=Positionable})
return nil
end
--- Check validity of the filename passed and sets RADIO.FileName
--- Set alias of the transmitter.
-- @param #RADIO self
-- @param #string alias Name of the radio transmitter.
-- @return #RADIO self
function RADIO:SetAlias(alias)
self.alias=tostring(alias)
return self
end
--- Get alias of the transmitter.
-- @param #RADIO self
-- @return #string Name of the transmitter.
function RADIO:GetAlias()
return tostring(self.alias)
end
--- Set the file name for the radio transmission.
-- @param #RADIO self
-- @param #string FileName File name of the sound file (i.e. "Noise.ogg")
-- @return #RADIO self
@@ -120,49 +142,63 @@ function RADIO:SetFileName(FileName)
self:F2(FileName)
if type(FileName) == "string" then
if FileName:find(".ogg") or FileName:find(".wav") then
if not FileName:find("l10n/DEFAULT/") then
FileName = "l10n/DEFAULT/" .. FileName
end
self.FileName = FileName
return self
end
end
self:E({"File name invalid. Maybe something wrong with the extension ?", self.FileName})
self:E({"File name invalid. Maybe something wrong with the extension?", FileName})
return self
end
--- Check validity of the frequency passed and sets RADIO.Frequency
--- Set the frequency for the radio transmission.
-- If the transmitting positionable is a unit or group, this also set the command "SetFrequency" with the defined frequency and modulation.
-- @param #RADIO self
-- @param #number Frequency in MHz (Ranges allowed for radio transmissions in DCS : 30-88 / 108-152 / 225-400MHz)
-- @param #number Frequency Frequency in MHz. Ranges allowed for radio transmissions in DCS : 30-87.995 / 108-173.995 / 225-399.975MHz.
-- @return #RADIO self
function RADIO:SetFrequency(Frequency)
self:F2(Frequency)
if type(Frequency) == "number" then
-- If frequency is in range
if (Frequency >= 30 and Frequency < 88) or (Frequency >= 108 and Frequency < 152) or (Frequency >= 225 and Frequency < 400) then
self.Frequency = Frequency * 1000000 -- Conversion in Hz
if (Frequency >= 30 and Frequency <= 87.995) or (Frequency >= 108 and Frequency <= 173.995) or (Frequency >= 225 and Frequency <= 399.975) then
-- Convert frequency from MHz to Hz
self.Frequency = Frequency * 1000000
-- If the RADIO is attached to a UNIT or a GROUP, we need to send the DCS Command "SetFrequency" to change the UNIT or GROUP frequency
if self.Positionable.ClassName == "UNIT" or self.Positionable.ClassName == "GROUP" then
self.Positionable:SetCommand({
local commandSetFrequency={
id = "SetFrequency",
params = {
frequency = self.Frequency,
frequency = self.Frequency,
modulation = self.Modulation,
}
})
}
self:T2(commandSetFrequency)
self.Positionable:SetCommand(commandSetFrequency)
end
return self
end
end
self:E({"Frequency is outside of DCS Frequency ranges (30-80, 108-152, 225-400). Frequency unchanged.", self.Frequency})
self:E({"Frequency is outside of DCS Frequency ranges (30-80, 108-152, 225-400). Frequency unchanged.", Frequency})
return self
end
--- Check validity of the frequency passed and sets RADIO.Modulation
--- Set AM or FM modulation of the radio transmitter.
-- @param #RADIO self
-- @param #number Modulation either radio.modulation.AM or radio.modulation.FM
-- @param #number Modulation Modulation is either radio.modulation.AM or radio.modulation.FM.
-- @return #RADIO self
function RADIO:SetModulation(Modulation)
self:F2(Modulation)
@@ -178,23 +214,24 @@ end
--- Check validity of the power passed and sets RADIO.Power
-- @param #RADIO self
-- @param #number Power in W
-- @param #number Power Power in W.
-- @return #RADIO self
function RADIO:SetPower(Power)
self:F2(Power)
if type(Power) == "number" then
self.Power = math.floor(math.abs(Power)) --TODO Find what is the maximum power allowed by DCS and limit power to that
return self
else
self:E({"Power is invalid. Power unchanged.", self.Power})
end
self:E({"Power is invalid. Power unchanged.", self.Power})
return self
end
--- Check validity of the loop passed and sets RADIO.Loop
--- Set message looping on or off.
-- @param #RADIO self
-- @param #boolean Loop
-- @param #boolean Loop If true, message is repeated indefinitely.
-- @return #RADIO self
-- @usage
function RADIO:SetLoop(Loop)
self:F2(Loop)
if type(Loop) == "boolean" then
@@ -227,13 +264,12 @@ function RADIO:SetSubtitle(Subtitle, SubtitleDuration)
self:E({"Subtitle is invalid. Subtitle reset.", self.Subtitle})
end
if type(SubtitleDuration) == "number" then
if math.floor(math.abs(SubtitleDuration)) == SubtitleDuration then
self.SubtitleDuration = SubtitleDuration
return self
end
self.SubtitleDuration = SubtitleDuration
else
self.SubtitleDuration = 0
self:E({"SubtitleDuration is invalid. SubtitleDuration reset.", self.SubtitleDuration})
end
self.SubtitleDuration = 0
self:E({"SubtitleDuration is invalid. SubtitleDuration reset.", self.SubtitleDuration})
return self
end
--- Create a new transmission, that is to say, populate the RADIO with relevant data
@@ -241,10 +277,10 @@ end
-- but it will work with a UNIT or a GROUP anyway.
-- Only the #RADIO and the Filename are mandatory
-- @param #RADIO self
-- @param #string FileName
-- @param #number Frequency in MHz
-- @param #number Modulation either radio.modulation.AM or radio.modulation.FM
-- @param #number Power in W
-- @param #string FileName Name of the sound file that will be transmitted.
-- @param #number Frequency Frequency in MHz.
-- @param #number Modulation Modulation of frequency, which is either radio.modulation.AM or radio.modulation.FM.
-- @param #number Power Power in W.
-- @return #RADIO self
function RADIO:NewGenericTransmission(FileName, Frequency, Modulation, Power, Loop)
self:F({FileName, Frequency, Modulation, Power})
@@ -261,62 +297,86 @@ end
--- Create a new transmission, that is to say, populate the RADIO with relevant data
-- In this function the data is especially relevant if the broadcaster is a UNIT or a GROUP,
-- but it will work for any @{Positionable#POSITIONABLE}.
-- but it will work for any @{Wrapper.Positionable#POSITIONABLE}.
-- Only the RADIO and the Filename are mandatory.
-- @param #RADIO self
-- @param #string FileName
-- @param #string Subtitle
-- @param #number SubtitleDuration in s
-- @param #number Frequency in MHz
-- @param #number Modulation either radio.modulation.AM or radio.modulation.FM
-- @param #boolean Loop
-- @param #string FileName Name of sound file.
-- @param #string Subtitle Subtitle to be displayed with sound file.
-- @param #number SubtitleDuration Duration of subtitle display in seconds.
-- @param #number Frequency Frequency in MHz.
-- @param #number Modulation Modulation which can be either radio.modulation.AM or radio.modulation.FM
-- @param #boolean Loop If true, loop message.
-- @return #RADIO self
function RADIO:NewUnitTransmission(FileName, Subtitle, SubtitleDuration, Frequency, Modulation, Loop)
self:F({FileName, Subtitle, SubtitleDuration, Frequency, Modulation, Loop})
-- Set file name.
self:SetFileName(FileName)
if Subtitle then self:SetSubtitle(Subtitle) end
if SubtitleDuration then self:SetSubtitleDuration(SubtitleDuration) end
if Frequency then self:SetFrequency(Frequency) end
if Modulation then self:SetModulation(Modulation) end
if Loop then self:SetLoop(Loop) end
-- Set modulation AM/FM.
if Modulation then
self:SetModulation(Modulation)
end
-- Set frequency.
if Frequency then
self:SetFrequency(Frequency)
end
-- Set subtitle.
if Subtitle then
self:SetSubtitle(Subtitle, SubtitleDuration or 0)
end
-- Set Looping.
if Loop then
self:SetLoop(Loop)
end
return self
end
--- Actually Broadcast the transmission
--- Broadcast the transmission.
-- * The Radio has to be populated with the new transmission before broadcasting.
-- * Please use RADIO setters or either @{Radio#RADIO.NewGenericTransmission} or @{Radio#RADIO.NewUnitTransmission}
-- * Please use RADIO setters or either @{#RADIO.NewGenericTransmission} or @{#RADIO.NewUnitTransmission}
-- * This class is in fact pretty smart, it determines the right DCS function to use depending on the type of POSITIONABLE
-- * If the POSITIONABLE is not a UNIT or a GROUP, we use the generic (but limited) trigger.action.radioTransmission()
-- * If the POSITIONABLE is a UNIT or a GROUP, we use the "TransmitMessage" Command
-- * If your POSITIONABLE is a UNIT or a GROUP, the Power is ignored.
-- * If your POSITIONABLE is not a UNIT or a GROUP, the Subtitle, SubtitleDuration are ignored
-- @param #RADIO self
-- @param #boolean viatrigger Use trigger.action.radioTransmission() in any case, i.e. also for UNITS and GROUPS.
-- @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")
self.Positionable:SetCommand({
function RADIO:Broadcast(viatrigger)
self:F({viatrigger=viatrigger})
-- 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") and (not viatrigger) then
self:T("Broadcasting from a UNIT or a GROUP")
local commandTransmitMessage={
id = "TransmitMessage",
params = {
file = self.FileName,
duration = self.SubtitleDuration,
subtitle = self.Subtitle,
loop = self.Loop,
}
})
}}
self:T3(commandTransmitMessage)
self.Positionable:SetCommand(commandTransmitMessage)
else
-- If the POSITIONABLE is anything else, we revert to the general singleton function
-- I need to give it a unique name, so that the transmission can be stopped later. I use the class ID
self:T2("Broadcasting from a POSITIONABLE")
self:T("Broadcasting from a POSITIONABLE")
trigger.action.radioTransmission(self.FileName, self.Positionable:GetPositionVec3(), self.Modulation, self.Loop, self.Frequency, self.Power, tostring(self.ID))
end
return self
end
--- Stops a transmission
-- This function is especially usefull to stop the broadcast of looped transmissions
-- @param #RADIO self
@@ -325,10 +385,10 @@ function RADIO:StopBroadcast()
self:F()
-- If the POSITIONABLE is a UNIT or a GROUP, stop the transmission with the DCS "StopTransmission" command
if self.Positionable.ClassName == "UNIT" or self.Positionable.ClassName == "GROUP" then
self.Positionable:SetCommand({
id = "StopTransmission",
params = {}
})
local commandStopTransmission={id="StopTransmission", params={}}
self.Positionable:SetCommand(commandStopTransmission)
else
-- Else, we use the appropriate singleton funciton
trigger.action.stopRadioTransmission(tostring(self.ID))
@@ -337,43 +397,108 @@ function RADIO:StopBroadcast()
end
--- # BEACON class, extends @{Base#BASE}
--
-- After attaching a @{#BEACON} to your @{Positionable#POSITIONABLE}, you need to select the right function to activate the kind of beacon you want.
--- After attaching a @{#BEACON} to your @{Wrapper.Positionable#POSITIONABLE}, you need to select the right function to activate the kind of beacon you want.
-- There are two types of BEACONs available : the AA TACAN Beacon and the general purpose Radio Beacon.
-- Note that in both case, you can set an optional parameter : the `BeaconDuration`. This can be very usefull to simulate the battery time if your BEACON is
-- attach to a cargo crate, for exemple.
--
-- ## AA TACAN Beacon usage
--
-- This beacon only works with airborne @{Unit#UNIT} or a @{Group#GROUP}. Use @{#BEACON:AATACAN}() to set the beacon parameters and start the beacon.
-- This beacon only works with airborne @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}. Use @{#BEACON:AATACAN}() to set the beacon parameters and start the beacon.
-- Use @#BEACON:StopAATACAN}() to stop it.
--
-- ## General Purpose Radio Beacon usage
--
-- This beacon will work with any @{Positionable#POSITIONABLE}, but **it won't follow the @{Positionable#POSITIONABLE}** ! This means that you should only use it with
-- @{Positionable#POSITIONABLE} that don't move, or move very slowly. Use @{#BEACON:RadioBeacon}() to set the beacon parameters and start the beacon.
-- This beacon will work with any @{Wrapper.Positionable#POSITIONABLE}, but **it won't follow the @{Wrapper.Positionable#POSITIONABLE}** ! This means that you should only use it with
-- @{Wrapper.Positionable#POSITIONABLE} that don't move, or move very slowly. Use @{#BEACON:RadioBeacon}() to set the beacon parameters and start the beacon.
-- Use @{#BEACON:StopRadioBeacon}() to stop it.
--
-- @type BEACON
-- @field #string ClassName Name of the class "BEACON".
-- @field Wrapper.Controllable#CONTROLLABLE Positionable The @{#CONTROLLABLE} that will receive radio capabilities.
-- @extends Core.Base#BASE
BEACON = {
ClassName = "BEACON",
Positionable = nil,
name=nil,
}
--- Create a new BEACON Object. This doesn't activate the beacon, though, use @{#BEACON.AATACAN} or @{#BEACON.Generic}
-- If you want to create a BEACON, you probably should use @{Positionable#POSITIONABLE.GetBeacon}() instead.
--- Beacon types supported by DCS.
-- @type BEACON.Type
-- @field #number NULL
-- @field #number VOR
-- @field #number DME
-- @field #number VOR_DME
-- @field #number TACAN
-- @field #number VORTAC
-- @field #number RSBN
-- @field #number BROADCAST_STATION
-- @field #number HOMER
-- @field #number AIRPORT_HOMER
-- @field #number AIRPORT_HOMER_WITH_MARKER
-- @field #number ILS_FAR_HOMER
-- @field #number ILS_NEAR_HOMER
-- @field #number ILS_LOCALIZER
-- @field #number ILS_GLIDESLOPE
-- @field #number NAUTICAL_HOMER
-- @field #number ICLS
BEACON.Type={
NULL = 0,
VOR = 1,
DME = 2,
VOR_DME = 3,
TACAN = 4,
VORTAC = 5,
RSBN = 32,
BROADCAST_STATION = 1024,
HOMER = 8,
AIRPORT_HOMER = 4104,
AIRPORT_HOMER_WITH_MARKER = 4136,
ILS_FAR_HOMER = 16408,
ILS_NEAR_HOMER = 16456,
ILS_LOCALIZER = 16640,
ILS_GLIDESLOPE = 16896,
NAUTICAL_HOMER = 32776,
ICLS = 131584,
}
--- Beacon systems supported by DCS. https://wiki.hoggitworld.com/view/DCS_command_activateBeacon
-- @type BEACON.System
-- @field #number PAR_10
-- @field #number RSBN_5
-- @field #number TACAN
-- @field #number TACAN_TANKER
-- @field #number ILS_LOCALIZER (This is the one to be used for AA TACAN Tanker!)
-- @field #number ILS_GLIDESLOPE
-- @field #number BROADCAST_STATION
BEACON.System={
PAR_10 = 1,
RSBN_5 = 2,
TACAN = 3,
TACAN_TANKER = 4,
ILS_LOCALIZER = 5,
ILS_GLIDESLOPE = 6,
BROADCAST_STATION = 7,
}
--- Create a new BEACON Object. This doesn't activate the beacon, though, use @{#BEACON.ActivateTACAN} etc.
-- If you want to create a BEACON, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetBeacon}() instead.
-- @param #BEACON self
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities.
-- @return #BEACON Beacon
-- @return #nil If Positionable is invalid
-- @return #BEACON Beacon object or #nil if the positionable is invalid.
function BEACON:New(Positionable)
local self = BASE:Inherit(self, BASE:New())
-- Inherit BASE.
local self=BASE:Inherit(self, BASE:New()) --#BEACON
-- Debug.
self:F(Positionable)
-- Set positionable.
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure positionable is valid
self.Positionable = Positionable
self.name=Positionable:GetName()
self:I(string.format("New BEACON %s", tostring(self.name)))
return self
end
@@ -382,44 +507,95 @@ function BEACON:New(Positionable)
end
--- Converts a TACAN Channel/Mode couple into a frequency in Hz
--- Activates a TACAN BEACON.
-- @param #BEACON self
-- @param #number TACANChannel
-- @param #string TACANMode
-- @return #number Frequecy
-- @return #nil if parameters are invalid
function BEACON:_TACANToFrequency(TACANChannel, TACANMode)
self:F3({TACANChannel, TACANMode})
if type(TACANChannel) ~= "number" then
if TACANMode ~= "X" and TACANMode ~= "Y" then
return nil -- error in arguments
end
-- @param #number Channel TACAN channel, i.e. the "10" part in "10Y".
-- @param #string Mode TACAN mode, i.e. the "Y" part in "10Y".
-- @param #string Message The Message that is going to be coded in Morse and broadcasted by the beacon.
-- @param #boolean Bearing If true, beacon provides bearing information. If false (or nil), only distance information is available.
-- @param #number Duration How long will the beacon last in seconds. Omit for forever.
-- @return #BEACON self
-- @usage
-- -- Let's create a TACAN Beacon for a tanker
-- local myUnit = UNIT:FindByName("MyUnit")
-- local myBeacon = myUnit:GetBeacon() -- Creates the beacon
--
-- myBeacon:ActivateTACAN(20, "Y", "TEXACO", true) -- Activate the beacon
function BEACON:ActivateTACAN(Channel, Mode, Message, Bearing, Duration)
self:T({channel=Channel, mode=Mode, callsign=Message, bearing=Bearing, duration=Duration})
-- Get frequency.
local Frequency=UTILS.TACANToFrequency(Channel, Mode)
-- Check.
if not Frequency then
self:E({"The passed TACAN channel is invalid, the BEACON is not emitting"})
return self
end
-- This code is largely based on ED's code, in DCS World\Scripts\World\Radio\BeaconTypes.lua, line 137.
-- I have no idea what it does but it seems to work
local A = 1151 -- 'X', channel >= 64
local B = 64 -- channel >= 64
-- Beacon type.
local Type=BEACON.Type.TACAN
if TACANChannel < 64 then
B = 1
end
-- Beacon system.
local System=BEACON.System.TACAN
if TACANMode == 'Y' then
A = 1025
if TACANChannel < 64 then
A = 1088
end
else -- 'X'
if TACANChannel < 64 then
A = 962
-- Check if unit is an aircraft and set system accordingly.
local AA=self.Positionable:IsAir()
if AA then
System=5 --NOTE: 5 is how you cat the correct tanker behaviour! --BEACON.System.TACAN_TANKER
-- Check if "Y" mode is selected for aircraft.
if Mode~="Y" then
self:E({"WARNING: The POSITIONABLE you want to attach the AA Tacan Beacon is an aircraft: Mode should Y !The BEACON is not emitting.", self.Positionable})
end
end
return (A + TACANChannel - B) * 1000000
-- Attached unit.
local UnitID=self.Positionable:GetID()
-- Debug.
self:I({string.format("BEACON Activating TACAN %s: Channel=%d%s, Morse=%s, Bearing=%s, Duration=%s!", tostring(self.name), Channel, Mode, Message, tostring(Bearing), tostring(Duration))})
-- Start beacon.
self.Positionable:CommandActivateBeacon(Type, System, Frequency, UnitID, Channel, Mode, AA, Message, Bearing)
-- Stop sheduler.
if Duration then
self.Positionable:DeactivateBeacon(Duration)
end
return self
end
--- Activates an ICLS BEACON. The unit the BEACON is attached to should be an aircraft carrier supporting this system.
-- @param #BEACON self
-- @param #number Channel ICLS channel.
-- @param #string Callsign The Message that is going to be coded in Morse and broadcasted by the beacon.
-- @param #number Duration How long will the beacon last in seconds. Omit for forever.
-- @return #BEACON self
function BEACON:ActivateICLS(Channel, Callsign, Duration)
self:F({Channel=Channel, Callsign=Callsign, Duration=Duration})
-- Attached unit.
local UnitID=self.Positionable:GetID()
-- Debug
self:T2({"ICLS BEACON started!"})
-- Start beacon.
self.Positionable:CommandActivateICLS(Channel, UnitID, Callsign)
-- Stop sheduler
if Duration then -- Schedule the stop of the BEACON if asked by the MD
self.Positionable:DeactivateBeacon(Duration)
end
return self
end
--- Activates a TACAN BEACON on an Aircraft.
-- @param #BEACON self
@@ -472,7 +648,7 @@ function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
})
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
SCHEDULER:New( nil,
SCHEDULER:New(nil,
function()
self:StopAATACAN()
end, {}, BeaconDuration)
@@ -583,4 +759,45 @@ function BEACON:StopRadioBeacon()
self:F()
-- The unique name of the transmission is the class ID
trigger.action.stopRadioTransmission(tostring(self.ID))
end
return self
end
--- Converts a TACAN Channel/Mode couple into a frequency in Hz
-- @param #BEACON self
-- @param #number TACANChannel
-- @param #string TACANMode
-- @return #number Frequecy
-- @return #nil if parameters are invalid
function BEACON:_TACANToFrequency(TACANChannel, TACANMode)
self:F3({TACANChannel, TACANMode})
if type(TACANChannel) ~= "number" then
if TACANMode ~= "X" and TACANMode ~= "Y" then
return nil -- error in arguments
end
end
-- This code is largely based on ED's code, in DCS World\Scripts\World\Radio\BeaconTypes.lua, line 137.
-- I have no idea what it does but it seems to work
local A = 1151 -- 'X', channel >= 64
local B = 64 -- channel >= 64
if TACANChannel < 64 then
B = 1
end
if TACANMode == 'Y' then
A = 1025
if TACANChannel < 64 then
A = 1088
end
else -- 'X'
if TACANChannel < 64 then
A = 962
end
end
return (A + TACANChannel - B) * 1000000
end

View File

@@ -0,0 +1,567 @@
--- **Core** - Queues Radio Transmissions.
--
-- ===
--
-- ## Features:
--
-- * Managed Radio Transmissions.
--
-- ===
--
-- ### Authors: funkyfranky
--
-- @module Core.RadioQueue
-- @image Core_Radio.JPG
--- Manages radio transmissions.
--
-- @type RADIOQUEUE
-- @field #string ClassName Name of the class "RADIOQUEUE".
-- @field #boolean Debug Debug mode. More info.
-- @field #string lid ID for dcs.log.
-- @field #number frequency The radio frequency in Hz.
-- @field #number modulation The radio modulation. Either radio.modulation.AM or radio.modulation.FM.
-- @field Core.Scheduler#SCHEDULER scheduler The scheduler.
-- @field #string RQid The radio queue scheduler ID.
-- @field #table queue The queue of transmissions.
-- @field #string alias Name of the radio.
-- @field #number dt Time interval in seconds for checking the radio queue.
-- @field #number delay Time delay before starting the radio queue.
-- @field #number Tlast Time (abs) when the last transmission finished.
-- @field Core.Point#COORDINATE sendercoord Coordinate from where transmissions are broadcasted.
-- @field #number sendername Name of the sending unit or static.
-- @field #boolean senderinit Set frequency was initialized.
-- @field #number power Power of radio station in Watts. Default 100 W.
-- @field #table numbers Table of number transmission parameters.
-- @field #boolean checking Scheduler is checking the radio queue.
-- @field #boolean schedonce Call ScheduleOnce instead of normal scheduler.
-- @extends Core.Base#BASE
RADIOQUEUE = {
ClassName = "RADIOQUEUE",
Debug = nil,
lid = nil,
frequency = nil,
modulation = nil,
scheduler = nil,
RQid = nil,
queue = {},
alias = nil,
dt = nil,
delay = nil,
Tlast = nil,
sendercoord = nil,
sendername = nil,
senderinit = nil,
power = nil,
numbers = {},
checking = nil,
schedonce = nil,
}
--- Radio queue transmission data.
-- @type RADIOQUEUE.Transmission
-- @field #string filename Name of the file to be transmitted.
-- @field #string path Path in miz file where the file is located.
-- @field #number duration Duration in seconds.
-- @field #string subtitle Subtitle of the transmission.
-- @field #number subduration Duration of the subtitle being displayed.
-- @field #number Tstarted Mission time (abs) in seconds when the transmission started.
-- @field #boolean isplaying If true, transmission is currently playing.
-- @field #number Tplay Mission time (abs) in seconds when the transmission should be played.
-- @field #number interval Interval in seconds before next transmission.
--- Create a new RADIOQUEUE object for a given radio frequency/modulation.
-- @param #RADIOQUEUE self
-- @param #number frequency The radio frequency in MHz.
-- @param #number modulation (Optional) The radio modulation. Default radio.modulation.AM.
-- @param #string alias (Optional) Name of the radio queue.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:New(frequency, modulation, alias)
-- Inherit base
local self=BASE:Inherit(self, BASE:New()) -- #RADIOQUEUE
self.alias=alias or "My Radio"
self.lid=string.format("RADIOQUEUE %s | ", self.alias)
if frequency==nil then
self:E(self.lid.."ERROR: No frequency specified as first parameter!")
return nil
end
-- Frequency in Hz.
self.frequency=frequency*1000000
-- Modulation.
self.modulation=modulation or radio.modulation.AM
-- Set radio power.
self:SetRadioPower()
-- Scheduler.
self.scheduler=SCHEDULER:New()
self.scheduler:NoTrace()
return self
end
--- Start the radio queue.
-- @param #RADIOQUEUE self
-- @param #number delay (Optional) Delay in seconds, before the radio queue is started. Default 1 sec.
-- @param #number dt (Optional) Time step in seconds for checking the queue. Default 0.01 sec.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:Start(delay, dt)
self.delay=delay or 1
self.dt=dt or 0.01
self:I(self.lid..string.format("Starting RADIOQUEUE %s on Frequency %.2f MHz [modulation=%d] in %.1f seconds (dt=%.3f sec)", self.alias, self.frequency/1000000, self.modulation, delay, dt))
if self.schedonce then
self:_CheckRadioQueueDelayed(self.delta)
else
--self.RQid=self.scheduler:Schedule(self, self._CheckRadioQueue, {}, delay, dt)
self.RQid=self.scheduler:Schedule(nil, RADIOQUEUE._CheckRadioQueue, {self}, delay, dt)
end
return self
end
--- Stop the radio queue. Stop scheduler and delete queue.
-- @param #RADIOQUEUE self
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:Stop()
self:I(self.lid.."Stopping RADIOQUEUE.")
self.scheduler:Stop(self.RQid)
self.queue={}
return self
end
--- Set coordinate from where the transmission is broadcasted.
-- @param #RADIOQUEUE self
-- @param Core.Point#COORDINATE coordinate Coordinate of the sender.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:SetSenderCoordinate(coordinate)
self.sendercoord=coordinate
return self
end
--- Set name of unit or static from which transmissions are made.
-- @param #RADIOQUEUE self
-- @param #string name Name of the unit or static used for transmissions.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:SetSenderUnitName(name)
self.sendername=name
return self
end
--- Set radio power. Note that this only applies if no relay unit is used.
-- @param #RADIOQUEUE self
-- @param #number power Radio power in Watts. Default 100 W.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:SetRadioPower(power)
self.power=power or 100
return self
end
--- Set parameters of a digit.
-- @param #RADIOQUEUE self
-- @param #number digit The digit 0-9.
-- @param #string filename The name of the sound file.
-- @param #number duration The duration of the sound file in seconds.
-- @param #string path The directory within the miz file where the sound is located. Default "l10n/DEFAULT/".
-- @param #string subtitle Subtitle of the transmission.
-- @param #number subduration Duration [sec] of the subtitle being displayed. Default 5 sec.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:SetDigit(digit, filename, duration, path, subtitle, subduration)
local transmission={} --#RADIOQUEUE.Transmission
transmission.filename=filename
transmission.duration=duration
transmission.path=path or "l10n/DEFAULT/"
transmission.subtitle=nil
transmission.subduration=nil
-- Convert digit to string in case it is given as a number.
if type(digit)=="number" then
digit=tostring(digit)
end
-- Set transmission.
self.numbers[digit]=transmission
return self
end
--- Add a transmission to the radio queue.
-- @param #RADIOQUEUE self
-- @param #RADIOQUEUE.Transmission transmission The transmission data table.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:AddTransmission(transmission)
self:F({transmission=transmission})
-- Init.
transmission.isplaying=false
transmission.Tstarted=nil
-- Add to queue.
table.insert(self.queue, transmission)
-- Start checking.
if self.schedonce and not self.checking then
self:_CheckRadioQueueDelayed()
end
return self
end
--- Add a transmission to the radio queue.
-- @param #RADIOQUEUE self
-- @param #string filename Name of the sound file. Usually an ogg or wav file type.
-- @param #number duration Duration in seconds the file lasts.
-- @param #number path Directory path inside the miz file where the sound file is located. Default "l10n/DEFAULT/".
-- @param #number tstart Start time (abs) seconds. Default now.
-- @param #number interval Interval in seconds after the last transmission finished.
-- @param #string subtitle Subtitle of the transmission.
-- @param #number subduration Duration [sec] of the subtitle being displayed. Default 5 sec.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:NewTransmission(filename, duration, path, tstart, interval, subtitle, subduration)
-- Sanity checks.
if not filename then
self:E(self.lid.."ERROR: No filename specified.")
return nil
end
if type(filename)~="string" then
self:E(self.lid.."ERROR: Filename specified is NOT a string.")
return nil
end
if not duration then
self:E(self.lid.."ERROR: No duration of transmission specified.")
return nil
end
if type(duration)~="number" then
self:E(self.lid.."ERROR: Duration specified is NOT a number.")
return nil
end
local transmission={} --#RADIOQUEUE.Transmission
transmission.filename=filename
transmission.duration=duration
transmission.path=path or "l10n/DEFAULT/"
transmission.Tplay=tstart or timer.getAbsTime()
transmission.subtitle=subtitle
transmission.interval=interval or 0
if transmission.subtitle then
transmission.subduration=subduration or 5
else
transmission.subduration=nil
end
-- Add transmission to queue.
self:AddTransmission(transmission)
return self
end
--- Convert a number (as string) into a radio transmission.
-- E.g. for board number or headings.
-- @param #RADIOQUEUE self
-- @param #string number Number string, e.g. "032" or "183".
-- @param #number delay Delay before transmission in seconds.
-- @param #number interval Interval between the next call.
-- @return #number Duration of the call in seconds.
function RADIOQUEUE:Number2Transmission(number, delay, interval)
--- Split string into characters.
local function _split(str)
local chars={}
for i=1,#str do
local c=str:sub(i,i)
table.insert(chars, c)
end
return chars
end
-- Split string into characters.
local numbers=_split(number)
local wait=0
for i=1,#numbers do
-- Current number
local n=numbers[i]
-- Radio call.
local transmission=UTILS.DeepCopy(self.numbers[n]) --#RADIOQUEUE.Transmission
transmission.Tplay=timer.getAbsTime()+(delay or 0)
if interval and i==1 then
transmission.interval=interval
end
self:AddTransmission(transmission)
-- Add up duration of the number.
wait=wait+transmission.duration
end
-- Return the total duration of the call.
return wait
end
--- Broadcast radio message.
-- @param #RADIOQUEUE self
-- @param #RADIOQUEUE.Transmission transmission The transmission.
function RADIOQUEUE:Broadcast(transmission)
-- Get unit sending the transmission.
local sender=self:_GetRadioSender()
-- Construct file name.
local filename=string.format("%s%s", transmission.path, transmission.filename)
if sender then
-- Broadcasting from aircraft. Only players tuned in to the right frequency will see the message.
self:T(self.lid..string.format("Broadcasting from aircraft %s", sender:GetName()))
if not self.senderinit then
-- Command to set the Frequency for the transmission.
local commandFrequency={
id="SetFrequency",
params={
frequency=self.frequency, -- Frequency in Hz.
modulation=self.modulation,
}}
-- Set commend for frequency
sender:SetCommand(commandFrequency)
self.senderinit=true
end
-- Command to tranmit the call.
local commandTransmit={
id = "TransmitMessage",
params = {
file=filename,
duration=transmission.subduration,
subtitle=transmission.subtitle or "",
loop=false,
}}
-- Set command for radio transmission.
sender:SetCommand(commandTransmit)
-- Debug message.
local text=string.format("file=%s, freq=%.2f MHz, duration=%.2f sec, subtitle=%s", filename, self.frequency/1000000, transmission.duration, transmission.subtitle or "")
MESSAGE:New(text, 2, "RADIOQUEUE "..self.alias):ToAllIf(self.Debug)
else
-- Broadcasting from carrier. No subtitle possible. Need to send messages to players.
self:T(self.lid..string.format("Broadcasting via trigger.action.radioTransmission()."))
-- Position from where to transmit.
local vec3=nil
-- Try to get positon from sender unit/static.
if self.sendername then
local coord=self:_GetRadioSenderCoord()
if coord then
vec3=coord:GetVec3()
end
end
-- Try to get fixed positon.
if self.sendercoord and not vec3 then
vec3=self.sendercoord:GetVec3()
end
-- Transmit via trigger.
if vec3 then
self:T("Sending")
self:T( { filename = filename, vec3 = vec3, modulation = self.modulation, frequency = self.frequency, power = self.power } )
-- Trigger transmission.
trigger.action.radioTransmission(filename, vec3, self.modulation, false, self.frequency, self.power)
-- Debug message.
local text=string.format("file=%s, freq=%.2f MHz, duration=%.2f sec, subtitle=%s", filename, self.frequency/1000000, transmission.duration, transmission.subtitle or "")
MESSAGE:New(string.format(text, filename, transmission.duration, transmission.subtitle or ""), 5, "RADIOQUEUE "..self.alias):ToAllIf(self.Debug)
end
end
end
--- Start checking the radio queue.
-- @param #RADIOQUEUE self
-- @param #number delay Delay in seconds before checking.
function RADIOQUEUE:_CheckRadioQueueDelayed(delay)
self.checking=true
self:ScheduleOnce(delay or self.dt, RADIOQUEUE._CheckRadioQueue, self)
end
--- Check radio queue for transmissions to be broadcasted.
-- @param #RADIOQUEUE self
function RADIOQUEUE:_CheckRadioQueue()
--env.info("FF check radio queue "..self.alias)
-- Check if queue is empty.
if #self.queue==0 then
-- Queue is now empty. Nothing to else to do.
self.checking=false
return
end
-- Get current abs time.
local time=timer.getAbsTime()
local playing=false
local next=nil --#RADIOQUEUE.Transmission
local remove=nil
for i,_transmission in ipairs(self.queue) do
local transmission=_transmission --#RADIOQUEUE.Transmission
-- Check if transmission time has passed.
if time>=transmission.Tplay then
-- Check if transmission is currently playing.
if transmission.isplaying then
-- Check if transmission is finished.
if time>=transmission.Tstarted+transmission.duration then
-- Transmission over.
transmission.isplaying=false
-- Remove ith element in queue.
remove=i
-- Store time last transmission finished.
self.Tlast=time
else -- still playing
-- Transmission is still playing.
playing=true
end
else -- not playing yet
local Tlast=self.Tlast
if transmission.interval==nil then
-- Not playing ==> this will be next.
if next==nil then
next=transmission
end
else
if Tlast==nil or time-Tlast>=transmission.interval then
next=transmission
else
end
end
-- We got a transmission or one with an interval that is not due yet. No need for anything else.
if next or Tlast then
break
end
end
else
-- Transmission not due yet.
end
end
-- Found a new transmission.
if next~=nil and not playing then
self:Broadcast(next)
next.isplaying=true
next.Tstarted=time
end
-- Remove completed calls from queue.
if remove then
table.remove(self.queue, remove)
end
-- Check queue.
if self.schedonce then
self:_CheckRadioQueueDelayed()
end
end
--- Get unit from which we want to transmit a radio message. This has to be an aircraft for subtitles to work.
-- @param #RADIOQUEUE self
-- @return Wrapper.Unit#UNIT Sending aircraft unit or nil if was not setup, is not an aircraft or is not alive.
function RADIOQUEUE:_GetRadioSender()
-- Check if we have a sending aircraft.
local sender=nil --Wrapper.Unit#UNIT
-- Try the general default.
if self.sendername then
-- First try to find a unit
sender=UNIT:FindByName(self.sendername)
-- Check that sender is alive and an aircraft.
if sender and sender:IsAlive() and sender:IsAir() then
return sender
end
end
return nil
end
--- Get unit from which we want to transmit a radio message. This has to be an aircraft for subtitles to work.
-- @param #RADIOQUEUE self
-- @return Core.Point#COORDINATE Coordinate of the sender unit.
function RADIOQUEUE:_GetRadioSenderCoord()
local vec3=nil
-- Try the general default.
if self.sendername then
-- First try to find a unit
local sender=UNIT:FindByName(self.sendername)
-- Check that sender is alive and an aircraft.
if sender and sender:IsAlive() then
return sender:GetCoordinate()
end
-- Now try a static.
local sender=STATIC:FindByName( self.sendername, false )
-- Check that sender is alive and an aircraft.
if sender then
return sender:GetCoordinate()
end
end
return nil
end

View File

@@ -0,0 +1,405 @@
--- **Core** - Makes the radio talk.
--
-- ===
--
-- ## Features:
--
-- * Send text strings using a vocabulary that is converted in spoken language.
-- * Possiblity to implement multiple language.
--
-- ===
--
-- ### Authors: FlightControl
--
-- @module Core.RadioSpeech
-- @image Core_Radio.JPG
--- Makes the radio speak.
--
-- # RADIOSPEECH usage
--
--
-- @type RADIOSPEECH
-- @extends Core.RadioQueue#RADIOQUEUE
RADIOSPEECH = {
ClassName = "RADIOSPEECH",
Vocabulary = {
EN = {},
DE = {},
RU = {},
}
}
RADIOSPEECH.Vocabulary.EN = {
["1"] = { "1", 0.25 },
["2"] = { "2", 0.25 },
["3"] = { "3", 0.30 },
["4"] = { "4", 0.35 },
["5"] = { "5", 0.35 },
["6"] = { "6", 0.42 },
["7"] = { "7", 0.38 },
["8"] = { "8", 0.20 },
["9"] = { "9", 0.32 },
["10"] = { "10", 0.35 },
["11"] = { "11", 0.40 },
["12"] = { "12", 0.42 },
["13"] = { "13", 0.38 },
["14"] = { "14", 0.42 },
["15"] = { "15", 0.42 },
["16"] = { "16", 0.52 },
["17"] = { "17", 0.59 },
["18"] = { "18", 0.40 },
["19"] = { "19", 0.47 },
["20"] = { "20", 0.38 },
["30"] = { "30", 0.29 },
["40"] = { "40", 0.35 },
["50"] = { "50", 0.32 },
["60"] = { "60", 0.44 },
["70"] = { "70", 0.48 },
["80"] = { "80", 0.26 },
["90"] = { "90", 0.36 },
["100"] = { "100", 0.55 },
["200"] = { "200", 0.55 },
["300"] = { "300", 0.61 },
["400"] = { "400", 0.60 },
["500"] = { "500", 0.61 },
["600"] = { "600", 0.65 },
["700"] = { "700", 0.70 },
["800"] = { "800", 0.54 },
["900"] = { "900", 0.60 },
["1000"] = { "1000", 0.60 },
["2000"] = { "2000", 0.61 },
["3000"] = { "3000", 0.64 },
["4000"] = { "4000", 0.62 },
["5000"] = { "5000", 0.69 },
["6000"] = { "6000", 0.69 },
["7000"] = { "7000", 0.75 },
["8000"] = { "8000", 0.59 },
["9000"] = { "9000", 0.65 },
["chevy"] = { "chevy", 0.35 },
["colt"] = { "colt", 0.35 },
["springfield"] = { "springfield", 0.65 },
["dodge"] = { "dodge", 0.35 },
["enfield"] = { "enfield", 0.5 },
["ford"] = { "ford", 0.32 },
["pontiac"] = { "pontiac", 0.55 },
["uzi"] = { "uzi", 0.28 },
["degrees"] = { "degrees", 0.5 },
["kilometers"] = { "kilometers", 0.65 },
["km"] = { "kilometers", 0.65 },
["miles"] = { "miles", 0.45 },
["meters"] = { "meters", 0.41 },
["mi"] = { "miles", 0.45 },
["feet"] = { "feet", 0.29 },
["br"] = { "br", 1.1 },
["bra"] = { "bra", 0.3 },
["returning to base"] = { "returning_to_base", 0.85 },
["on route to ground target"] = { "on_route_to_ground_target", 1.05 },
["intercepting bogeys"] = { "intercepting_bogeys", 1.00 },
["engaging ground target"] = { "engaging_ground_target", 1.20 },
["engaging bogeys"] = { "engaging_bogeys", 0.81 },
["wheels up"] = { "wheels_up", 0.42 },
["landing at base"] = { "landing at base", 0.8 },
["patrolling"] = { "patrolling", 0.55 },
["for"] = { "for", 0.31 },
["and"] = { "and", 0.31 },
["at"] = { "at", 0.3 },
["dot"] = { "dot", 0.26 },
["defender"] = { "defender", 0.45 },
}
RADIOSPEECH.Vocabulary.RU = {
["1"] = { "1", 0.34 },
["2"] = { "2", 0.30 },
["3"] = { "3", 0.23 },
["4"] = { "4", 0.51 },
["5"] = { "5", 0.31 },
["6"] = { "6", 0.44 },
["7"] = { "7", 0.25 },
["8"] = { "8", 0.43 },
["9"] = { "9", 0.45 },
["10"] = { "10", 0.53 },
["11"] = { "11", 0.66 },
["12"] = { "12", 0.70 },
["13"] = { "13", 0.66 },
["14"] = { "14", 0.80 },
["15"] = { "15", 0.65 },
["16"] = { "16", 0.75 },
["17"] = { "17", 0.74 },
["18"] = { "18", 0.85 },
["19"] = { "19", 0.80 },
["20"] = { "20", 0.58 },
["30"] = { "30", 0.51 },
["40"] = { "40", 0.51 },
["50"] = { "50", 0.67 },
["60"] = { "60", 0.76 },
["70"] = { "70", 0.68 },
["80"] = { "80", 0.84 },
["90"] = { "90", 0.71 },
["100"] = { "100", 0.35 },
["200"] = { "200", 0.59 },
["300"] = { "300", 0.53 },
["400"] = { "400", 0.70 },
["500"] = { "500", 0.50 },
["600"] = { "600", 0.58 },
["700"] = { "700", 0.64 },
["800"] = { "800", 0.77 },
["900"] = { "900", 0.75 },
["1000"] = { "1000", 0.87 },
["2000"] = { "2000", 0.83 },
["3000"] = { "3000", 0.84 },
["4000"] = { "4000", 1.00 },
["5000"] = { "5000", 0.77 },
["6000"] = { "6000", 0.90 },
["7000"] = { "7000", 0.77 },
["8000"] = { "8000", 0.92 },
["9000"] = { "9000", 0.87 },
["степени"] = { "degrees", 0.5 },
["километров"] = { "kilometers", 0.65 },
["km"] = { "kilometers", 0.65 },
["миль"] = { "miles", 0.45 },
["mi"] = { "miles", 0.45 },
["метры"] = { "meters", 0.41 },
["m"] = { "meters", 0.41 },
["ноги"] = { "feet", 0.37 },
["br"] = { "br", 1.1 },
["bra"] = { "bra", 0.3 },
["возвращаясь на базу"] = { "returning_to_base", 1.40 },
["на пути к наземной цели"] = { "on_route_to_ground_target", 1.45 },
["перехват самолетов"] = { "intercepting_bogeys", 1.22 },
["поражение наземной цели"] = { "engaging_ground_target", 1.53 },
["захватывающие самолеты"] = { "engaging_bogeys", 1.68 },
["колеса вверх"] = { "wheels_up", 0.92 },
["посадка на базу"] = { "landing at base", 1.04 },
["патрулирующий"] = { "patrolling", 0.96 },
["за"] = { "for", 0.27 },
["и"] = { "and", 0.17 },
["в"] = { "at", 0.19 },
["dot"] = { "dot", 0.51 },
["defender"] = { "defender", 0.45 },
}
--- Create a new RADIOSPEECH object for a given radio frequency/modulation.
-- @param #RADIOSPEECH self
-- @param #number frequency The radio frequency in MHz.
-- @param #number modulation (Optional) The radio modulation. Default radio.modulation.AM.
-- @return #RADIOSPEECH self The RADIOSPEECH object.
function RADIOSPEECH:New(frequency, modulation)
-- Inherit base
local self = BASE:Inherit( self, RADIOQUEUE:New( frequency, modulation ) ) -- #RADIOSPEECH
self.Language = "EN"
self:BuildTree()
return self
end
function RADIOSPEECH:SetLanguage( Langauge )
self.Language = Langauge
end
--- Add Sentence to the Speech collection.
-- @param #RADIOSPEECH self
-- @param #string RemainingSentence The remaining sentence during recursion.
-- @param #table Speech The speech node.
-- @param #string Sentence The full sentence.
-- @param #string Data The speech data.
-- @return #RADIOSPEECH self The RADIOSPEECH object.
function RADIOSPEECH:AddSentenceToSpeech( RemainingSentence, Speech, Sentence, Data )
self:I( { RemainingSentence, Speech, Sentence, Data } )
local Token, RemainingSentence = RemainingSentence:match( "^ *([^ ]+)(.*)" )
self:I( { Token = Token, RemainingSentence = RemainingSentence } )
-- Is there a Token?
if Token then
-- We check if the Token is already in the Speech collection.
if not Speech[Token] then
-- There is not yet a vocabulary registered for this.
Speech[Token] = {}
if RemainingSentence and RemainingSentence ~= "" then
-- We use recursion to iterate through the complete Sentence, and make a chain of Tokens.
-- The last Speech node in the collection contains the Sentence and the Data to be spoken.
-- This to ensure that during the actual speech:
-- - Complete sentences are being understood.
-- - Words without speech are ignored.
-- - Incorrect sequence of words are ignored.
Speech[Token].Next = {}
self:AddSentenceToSpeech( RemainingSentence, Speech[Token].Next, Sentence, Data )
else
-- There is no remaining sentence, so we add speech to the Sentence.
-- The recursion stops here.
Speech[Token].Sentence = Sentence
Speech[Token].Data = Data
end
end
end
end
--- Build the tree structure based on the language words, in order to find the correct sentences and to ignore incomprehensible words.
-- @param #RADIOSPEECH self
-- @return #RADIOSPEECH self The RADIOSPEECH object.
function RADIOSPEECH:BuildTree()
self.Speech = {}
for Language, Sentences in pairs( self.Vocabulary ) do
self:I( { Language = Language, Sentences = Sentences })
self.Speech[Language] = {}
for Sentence, Data in pairs( Sentences ) do
self:I( { Sentence = Sentence, Data = Data } )
self:AddSentenceToSpeech( Sentence, self.Speech[Language], Sentence, Data )
end
end
self:I( { Speech = self.Speech } )
return self
end
--- Speak a sentence.
-- @param #RADIOSPEECH self
-- @param #string Sentence The sentence to be spoken.
function RADIOSPEECH:SpeakWords( Sentence, Speech, Language )
local OriginalSentence = Sentence
-- lua does not parse UTF-8, so the match statement will fail on cyrillic using %a.
-- therefore, the only way to parse the statement is to use blank, comma or dot as a delimiter.
-- and then check if the character can be converted to a number or not.
local Word, RemainderSentence = Sentence:match( "^[., ]*([^ .,]+)(.*)" )
self:I( { Word = Word, Speech = Speech[Word], RemainderSentence = RemainderSentence } )
if Word then
if Word ~= "" and tonumber(Word) == nil then
-- Construct of words
Word = Word:lower()
if Speech[Word] then
-- The end of the sentence has been reached. Now Speech.Next should be nil, otherwise there is an error.
if Speech[Word].Next == nil then
self:I( { Sentence = Speech[Word].Sentence, Data = Speech[Word].Data } )
self:NewTransmission( Speech[Word].Data[1] .. ".wav", Speech[Word].Data[2], Language .. "/" )
else
if RemainderSentence and RemainderSentence ~= "" then
return self:SpeakWords( RemainderSentence, Speech[Word].Next, Language )
end
end
end
return RemainderSentence
end
return OriginalSentence
else
return ""
end
end
--- Speak a sentence.
-- @param #RADIOSPEECH self
-- @param #string Sentence The sentence to be spoken.
function RADIOSPEECH:SpeakDigits( Sentence, Speech, Langauge )
local OriginalSentence = Sentence
-- lua does not parse UTF-8, so the match statement will fail on cyrillic using %a.
-- therefore, the only way to parse the statement is to use blank, comma or dot as a delimiter.
-- and then check if the character can be converted to a number or not.
local Digits, RemainderSentence = Sentence:match( "^[., ]*([^ .,]+)(.*)" )
self:I( { Digits = Digits, Speech = Speech[Digits], RemainderSentence = RemainderSentence } )
if Digits then
if Digits ~= "" and tonumber( Digits ) ~= nil then
-- Construct numbers
local Number = tonumber( Digits )
local Multiple = nil
while Number >= 0 do
if Number > 1000 then
Multiple = math.floor( Number / 1000 ) * 1000
elseif Number > 100 then
Multiple = math.floor( Number / 100 ) * 100
elseif Number > 20 then
Multiple = math.floor( Number / 10 ) * 10
elseif Number >= 0 then
Multiple = Number
end
Sentence = tostring( Multiple )
if Speech[Sentence] then
self:I( { Speech = Speech[Sentence].Sentence, Data = Speech[Sentence].Data } )
self:NewTransmission( Speech[Sentence].Data[1] .. ".wav", Speech[Sentence].Data[2], Langauge .. "/" )
end
Number = Number - Multiple
Number = ( Number == 0 ) and -1 or Number
end
return RemainderSentence
end
return OriginalSentence
else
return ""
end
end
--- Speak a sentence.
-- @param #RADIOSPEECH self
-- @param #string Sentence The sentence to be spoken.
function RADIOSPEECH:Speak( Sentence, Language )
self:I( { Sentence, Language } )
local Language = Language or "EN"
self:I( { Language = Language } )
-- If there is no node for Speech, then we start at the first nodes of the language.
local Speech = self.Speech[Language]
self:I( { Speech = Speech, Language = Language } )
self:NewTransmission( "_In.wav", 0.52, Language .. "/" )
repeat
Sentence = self:SpeakWords( Sentence, Speech, Language )
self:I( { Sentence = Sentence } )
Sentence = self:SpeakDigits( Sentence, Speech, Language )
self:I( { Sentence = Sentence } )
-- Sentence = self:SpeakSymbols( Sentence, Speech )
--
-- self:I( { Sentence = Sentence } )
until not Sentence or Sentence == ""
self:NewTransmission( "_Out.wav", 0.28, Language .. "/" )
end

View File

@@ -0,0 +1,107 @@
--- **Core** - Provides a handy means to create messages and reports.
--
-- ===
--
-- ## Features:
--
-- * Create text blocks that are formatted.
-- * Create automatic indents.
-- * Variate the delimiters between reporting lines.
--
-- ===
--
-- ### Authors: FlightControl : Design & Programming
--
-- @module Core.Report
-- @image Core_Report.JPG
--- @type REPORT
-- @extends Core.Base#BASE
--- Provides a handy means to create messages and reports.
-- @field #REPORT
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, but indented. A separator character can be specified to separate the reported lines visually.
-- @param #REPORT self
-- @param #string Text The report text.
-- @param #string Separator (optional) The start of each report line can begin with an optional separator character. This can be a "-", or "#", or "*". You're free to choose what you find the best.
-- @return #REPORT
function REPORT:AddIndent( Text, Separator )
self.Report[#self.Report+1] = ( ( Separator and Separator .. string.rep( " ", self.Indent - 1 ) ) or string.rep(" ", self.Indent ) ) .. Text:gsub("\n","\n"..string.rep( " ", self.Indent ) )
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.
--
-- ===
--
@@ -22,17 +22,16 @@
--
-- The SCHEDULEDISPATCHER allows multiple scheduled functions to be planned and executed for one SCHEDULER object.
-- The SCHEDULER object therefore keeps a table of "CallID's", which are returned after each planning of a new scheduled function by the SCHEDULEDISPATCHER.
-- The SCHEDULER object plans new scheduled functions through the @{Scheduler#SCHEDULER.Schedule}() method.
-- The SCHEDULER object plans new scheduled functions through the @{Core.Scheduler#SCHEDULER.Schedule}() method.
-- The Schedule() method returns the CallID that is the reference ID for each planned schedule.
--
-- ===
--
-- ===
--
-- ### Contributions: -
-- ### Authors: FlightControl : Design & Programming
--
-- @module ScheduleDispatcher
-- @module Core.ScheduleDispatcher
-- @image Core_Schedule_Dispatcher.JPG
--- The SCHEDULEDISPATCHER structure
-- @type SCHEDULEDISPATCHER
@@ -53,10 +52,11 @@ end
-- Nothing of this code should be modified without testing it thoroughly.
-- @param #SCHEDULEDISPATCHER self
-- @param Core.Scheduler#SCHEDULER Scheduler
function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop )
self:F2( { Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop } )
function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop, TraceLevel, Fsm )
self:F2( { Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop, TraceLevel } )
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 +64,77 @@ 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
-- This section handles the tracing of the scheduled calls.
-- Because these calls will be executed with a delay, we inspect the place where these scheduled calls are initiated.
-- The Info structure contains the output of the debug.getinfo() calls, which inspects the call stack for the function name, line number and source name.
-- The call stack has many levels, and the correct semantical function call depends on where in the code AddSchedule was "used".
-- - Using SCHEDULER:New()
-- - Using Schedule:AddSchedule()
-- - Using Fsm:__Func()
-- - Using Class:ScheduleOnce()
-- - Using Class:ScheduleRepeat()
-- - ...
-- So for each of these scheduled call variations, AddSchedule is the workhorse which will schedule the call.
-- But the correct level with the correct semantical function location will differ depending on the above scheduled call invocation forms.
-- That's where the field TraceLevel contains optionally the level in the call stack where the call information is obtained.
-- The TraceLevel field indicates the correct level where the semantical scheduled call was invoked within the source, ensuring that function name, line number and source name are correct.
-- There is one quick ...
-- The FSM class models scheduled calls using the __Func syntax. However, these functions are "tailed".
-- There aren't defined anywhere within the source code, but rather implemented as triggers within the FSM logic,
-- and using the onbefore, onafter, onenter, onleave prefixes. (See the FSM for details).
-- Therefore, in the call stack, at the TraceLevel these functions are mentioned as "tail calls", and the Info.name field will be nil as a result.
-- To obtain the correct function name for FSM object calls, the function is mentioned in the call stack at a higher stack level.
-- So when function name stored in Info.name is nil, then I inspect the function name within the call stack one level higher.
-- So this little piece of code does its magic wonderfully, preformance overhead is neglectible, as scheduled calls don't happen that often.
self:T3( self.Schedule[Scheduler][self.CallID] )
local Info = {}
if debug then
TraceLevel = TraceLevel or 2
Info = debug.getinfo( TraceLevel, "nlS" )
local name_fsm = debug.getinfo( TraceLevel - 1, "n" ).name -- #string
if name_fsm then
Info.name = name_fsm
end
--env.info( debug.traceback() )
end
self.Schedule[Scheduler][self.CallID].CallHandler = function( CallID )
self:F2( CallID )
self:T3( self.Schedule[Scheduler][CallID] )
self.Schedule[Scheduler][CallID].CallHandler = function( Params )
local CallID = Params.CallID
local Info = Params.Info
local Source = Info.source or "?"
local Line = Info.currentline or "?"
local Name = Info.name or "?"
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 +143,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
@@ -120,25 +162,38 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
local Randomize = Schedule.Randomize or 0
local Stop = Schedule.Stop or 0
local ScheduleID = Schedule.ScheduleID
local ShowTrace = Scheduler.ShowTrace
local Prefix = ( Repeat == 0 ) and "--->" or "+++>"
local Status, Result
if ScheduleObject then
--self:E( { SchedulerObject = SchedulerObject } )
if SchedulerObject then
local function Timer()
return ScheduleFunction( ScheduleObject, unpack( ScheduleArguments ) )
if ShowTrace then
SchedulerObject:T( Prefix .. Name .. ":" .. Line .. " (" .. Source .. ")" )
end
return ScheduleFunction( SchedulerObject, unpack( ScheduleArguments ) )
end
Status, Result = xpcall( Timer, ErrorHandler )
else
local function Timer()
if ShowTrace then
self:T( Prefix .. Name .. ":" .. Line .. " (" .. Source .. ")" )
end
return ScheduleFunction( unpack( ScheduleArguments ) )
end
Status, Result = xpcall( Timer, ErrorHandler )
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 +202,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 +211,15 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
self:Stop( Scheduler, CallID )
end
else
self:E( "Scheduled obscolete call for CallID: " .. CallID )
self:I( "<<<>" .. Name .. ":" .. Line .. " (" .. Source .. ")" )
end
return nil
end
self:Start( Scheduler, self.CallID )
self:Start( Scheduler, CallID, Info )
return self.CallID
return CallID
end
function SCHEDULEDISPATCHER:RemoveSchedule( Scheduler, CallID )
@@ -176,7 +231,7 @@ function SCHEDULEDISPATCHER:RemoveSchedule( Scheduler, CallID )
end
end
function SCHEDULEDISPATCHER:Start( Scheduler, CallID )
function SCHEDULEDISPATCHER:Start( Scheduler, CallID, Info )
self:F2( { Start = CallID, Scheduler = Scheduler } )
if CallID then
@@ -184,15 +239,16 @@ 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
{ CallID = CallID, Info = Info },
timer.getTime() + Schedule[CallID].Start
)
end
else
for CallID, Schedule in pairs( self.Schedule[Scheduler] or {} ) do
self:Start( Scheduler, CallID ) -- Recursive
self:Start( Scheduler, CallID, Info ) -- Recursive
end
end
end
@@ -223,5 +279,9 @@ function SCHEDULEDISPATCHER:Clear( Scheduler )
end
end
function SCHEDULEDISPATCHER:NoTrace( Scheduler )
self:F2( { Scheduler = Scheduler } )
Scheduler.ShowTrace = nil
end

View File

@@ -1,15 +1,14 @@
--- **Core** - SCHEDULER prepares and handles the **execution of functions over scheduled time (intervals)**.
--- **Core** - Prepares and handles the execution of functions over scheduled time (intervals).
--
-- ![Banner Image](..\Presentations\SCHEDULER\Dia1.JPG)
--
-- ===
--
-- SCHEDULER manages the **scheduling of functions**:
-- ## Features:
--
-- * optionally in an optional specified time interval,
-- * optionally **repeating** with a specified time repeat interval,
-- * optionally **randomizing** with a specified time interval randomization factor,
-- * optionally **stop** the repeating after a specified time interval.
-- * Schedule functions over time,
-- * optionally in an optional specified time interval,
-- * optionally **repeating** with a specified time repeat interval,
-- * optionally **randomizing** with a specified time interval randomization factor,
-- * optionally **stop** the repeating after a specified time interval.
--
-- ===
--
@@ -21,13 +20,13 @@
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
-- ===
--
-- # YouTube Channel
--
-- ### [SCHEDULER YouTube Channel (none)]()
--
-- ====
-- ===
--
-- ### Contributions:
--
@@ -39,8 +38,8 @@
--
-- ===
--
-- @module Scheduler
-- @module Core.Scheduler
-- @image Core_Scheduler.JPG
--- The SCHEDULER class
-- @type SCHEDULER
@@ -48,9 +47,7 @@
-- @extends Core.Base#BASE
--- # SCHEDULER class, extends @{Base#BASE}
--
-- The SCHEDULER class creates schedule.
--- Creates and handles schedules over time, which allow to execute code at specific time intervals with randomization.
--
-- A SCHEDULER can manage **multiple** (repeating) schedules. Each planned or executing schedule has a unique **ScheduleID**.
-- The ScheduleID is returned when the method @{#SCHEDULER.Schedule}() is called.
@@ -210,15 +207,17 @@ 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
self.MasterObject = SchedulerObject
self.ShowTrace = true
if SchedulerFunction then
ScheduleID = self:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop )
ScheduleID = self:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop, 4 )
end
return self, ScheduleID
@@ -240,7 +239,7 @@ end
-- @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.
-- @return #number The ScheduleID of the planned schedule.
function SCHEDULER:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop )
function SCHEDULER:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop, TraceLevel, Fsm )
self:F2( { Start, Repeat, RandomizeFactor, Stop } )
self:T3( { SchedulerArguments } )
@@ -258,7 +257,9 @@ function SCHEDULER:Schedule( SchedulerObject, SchedulerFunction, SchedulerArgume
Start,
Repeat,
RandomizeFactor,
Stop
Stop,
TraceLevel or 3,
Fsm
)
self.Schedules[#self.Schedules+1] = ScheduleID
@@ -301,6 +302,14 @@ function SCHEDULER:Clear()
_SCHEDULEDISPATCHER:Clear( self )
end
--- No tracing for this scheduler.
-- @param #SCHEDULER self
-- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule.
function SCHEDULER:NoTrace()
_SCHEDULEDISPATCHER:NoTrace( self )
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,912 @@
--- **Core** - Manages various settings for running missions, consumed by moose classes and provides a menu system for players to tweak settings in running missions.
--
-- ===
--
-- ## Features:
--
-- * Provide a settings menu system to the players.
-- * Provide a player settings menu and an overall mission settings menu.
-- * Mission settings provide default settings, while player settings override mission settings.
-- * Provide a menu to select between different coordinate formats for A2G coordinates.
-- * Provide a menu to select between different coordinate formats for A2A coordinates.
-- * Provide a menu to select between different message time duration options.
-- * Provide a menu to select between different metric systems.
--
-- ===
--
-- The documentation of the SETTINGS class can be found further in this document.
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Contributions:
--
-- ### Authors:
--
-- * **FlightControl**: Design & Programming
--
-- @module Core.Settings
-- @image Core_Settings.JPG
--- @type SETTINGS
-- @extends Core.Base#BASE
--- Takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework.
--
-- ===
--
-- The SETTINGS class takes care of various settings that influence the 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.
--
-- ## 3.5) **Era** of the battle
--
-- The threat level metric is scaled according the era of the battle. A target that is AAA, will pose a much greather threat in WWII than on modern warfare.
-- Therefore, there are 4 era that are defined within the settings:
--
-- - **WWII** era: Use for warfare with equipment during the world war II time.
-- - **Korea** era: Use for warfare with equipment during the Korea war time.
-- - **Cold War** era: Use for warfare with equipment during the cold war time.
-- - **Modern** era: Use for warfare with modern equipment in the 2000s.
--
-- There are different API defined that you can use with the _SETTINGS object to configure your mission script to work in one of the 4 era:
-- @{#SETTINGS.SetEraWWII}(), @{#SETTINGS.SetEraKorea}(), @{#SETTINGS.SetEraCold}(), @{#SETTINGS.SetEraModern}()
--
-- ===
--
-- @field #SETTINGS
SETTINGS = {
ClassName = "SETTINGS",
ShowPlayerMenu = true,
}
SETTINGS.__Enum = {}
--- @type SETTINGS.__Enum.Era
-- @field #number WWII
-- @field #number Korea
-- @field #number Cold
-- @field #number Modern
SETTINGS.__Enum.Era = {
WWII = 1,
Korea = 2,
Cold = 3,
Modern = 4,
}
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 )
self:SetEraModern()
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()
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
--- Configures the era of the mission to be WWII.
-- @param #SETTINGS self
-- @return #SETTINGS self
function SETTINGS:SetEraWWII()
self.Era = SETTINGS.__Enum.Era.WWII
end
--- Configures the era of the mission to be Korea.
-- @param #SETTINGS self
-- @return #SETTINGS self
function SETTINGS:SetEraKorea()
self.Era = SETTINGS.__Enum.Era.Korea
end
--- Configures the era of the mission to be Cold war.
-- @param #SETTINGS self
-- @return #SETTINGS self
function SETTINGS:SetEraCold()
self.Era = SETTINGS.__Enum.Era.Cold
end
--- Configures the era of the mission to be Modern war.
-- @param #SETTINGS self
-- @return #SETTINGS self
function SETTINGS:SetEraModern()
self.Era = SETTINGS.__Enum.Era.Modern
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,16 @@
--- (R2.1) **Core** -- Spawn dynamically new STATICs in your missions.
--- **Core** - Spawn new statics in your running missions.
--
-- ![Banner Image](..\Presentations\SPAWNSTATIC\Dia1.JPG)
-- ===
--
-- ====
-- ## Features:
--
-- SPAWNSTATIC spawns static structures in your missions dynamically. See below the SPAWNSTATIC class documentation.
-- * Spawn new statics from a static already defined using the mission editor.
-- * Spawn new statics from a given template.
-- * Spawn new statics from a given type.
-- * Spawn with a custom heading and location.
-- * Spawn within a zone.
--
-- ====
-- ===
--
-- # Demo Missions
--
@@ -16,34 +20,21 @@
--
-- ### [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:
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Contributions:
--
-- ### Authors:
--
-- * **FlightControl**: Design & Programming
--
-- @module SpawnStatic
-- @module Core.SpawnStatic
-- @image Core_Spawnstatic.JPG
@@ -51,9 +42,7 @@
-- @extends Core.Base#BASE
--- # SPAWNSTATIC class, extends @{Base#BASE}
--
-- The SPAWNSTATIC class allows to spawn dynamically new @{Static}s.
--- Allows to spawn dynamically new @{Static}s.
-- Through creating a copy of an existing static object template as defined in the Mission Editor (ME),
-- SPAWNSTATIC can retireve the properties of the defined static object template (like type, category etc), and "copy"
-- these properties to create a new static object and place it at the desired coordinate.
@@ -94,18 +83,22 @@ SPAWNSTATIC = {
--- Creates the main object to spawn a @{Static} defined in the ME.
-- @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.
-- @param DCS#country.id SpawnCountryID The ID of the country.
-- @param DCS#coalition.side SpawnCoalitionID The ID of the coalition.
-- @return #SPAWNSTATIC
function SPAWNSTATIC:NewFromStatic( SpawnTemplatePrefix, CountryID ) --R2.1
function SPAWNSTATIC:NewFromStatic( SpawnTemplatePrefix, SpawnCountryID, SpawnCoalitionID )
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
self:F( { SpawnTemplatePrefix } )
local TemplateStatic = StaticObject.getByName( SpawnTemplatePrefix )
local TemplateStatic, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( SpawnTemplatePrefix )
if TemplateStatic then
self.SpawnTemplatePrefix = SpawnTemplatePrefix
self.CountryID = CountryID
self.CountryID = SpawnCountryID or CountryID
self.CategoryID = CategoryID
self.CoalitionID = SpawnCoalitionID or CoalitionID
self.SpawnIndex = 0
else
error( "SPAWNSTATIC:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" )
error( "SPAWNSTATIC:New: There is no static declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" )
end
self:SetEventPriority( 5 )
@@ -117,12 +110,13 @@ end
-- @param #SPAWNSTATIC self
-- @param #string SpawnTypeName is the name of the type.
-- @return #SPAWNSTATIC
function SPAWNSTATIC:NewFromType( SpawnTypeName, SpawnShapeName, SpawnCategory, CountryID ) --R2.1
function SPAWNSTATIC:NewFromType( SpawnTypeName, SpawnShapeName, SpawnCategory, SpawnCountryID, SpawnCoalitionID )
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
self:F( { SpawnTypeName } )
self.SpawnTypeName = SpawnTypeName
self.CountryID = CountryID
self.CountryID = SpawnCountryID
self.CoalitionID = SpawnCoalitionID
self.SpawnIndex = 0
self:SetEventPriority( 5 )
@@ -131,6 +125,36 @@ 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, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( self.SpawnTemplatePrefix )
if StaticTemplate then
local StaticUnitTemplate = StaticTemplate.units[1]
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
StaticTemplate.heading = ( Heading / 180 ) * math.pi
_DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID )
local Static = coalition.addStaticObject( self.CountryID or CountryID, StaticTemplate.units[1] )
self.SpawnIndex = self.SpawnIndex + 1
return _DATABASE:FindStatic(Static:getName())
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,32 +164,134 @@ end
function SPAWNSTATIC:SpawnFromPointVec2( PointVec2, Heading, NewName ) --R2.1
self:F( { PointVec2, Heading, NewName } )
local CountryName = _DATABASE.COUNTRY_NAME[self.CountryID]
local StaticTemplate, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( self.SpawnTemplatePrefix )
local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix )
if StaticTemplate then
StaticTemplate.x = PointVec2:GetLat()
StaticTemplate.y = PointVec2:GetLon()
local StaticUnitTemplate = StaticTemplate.units[1]
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
StaticTemplate.heading = ( Heading / 180 ) * math.pi
StaticUnitTemplate.x = PointVec2.x
StaticUnitTemplate.y = PointVec2.z
StaticTemplate.CountryID = nil
StaticTemplate.CoalitionID = nil
StaticTemplate.CategoryID = nil
local Static = coalition.addStaticObject( self.CountryID, StaticTemplate )
self.SpawnIndex = self.SpawnIndex + 1
StaticTemplate.route = nil
StaticTemplate.groupId = nil
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
StaticUnitTemplate.name = StaticTemplate.name
StaticUnitTemplate.heading = ( Heading / 180 ) * math.pi
_DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID)
self:F({StaticTemplate = StaticTemplate})
return Static
local Static = coalition.addStaticObject( self.CountryID or CountryID, StaticTemplate.units[1] )
self.SpawnIndex = self.SpawnIndex + 1
return _DATABASE:FindStatic(Static:getName())
end
return nil
end
--- Creates a new @{Static} from a COORDINATE.
-- @param #SPAWNSTATIC self
-- @param Core.Point#COORDINATE Coordinate The 3D coordinate where to spawn the static.
-- @param #number Heading (Optional) Heading The heading of the static, which is a number in degrees from 0 to 360. Default is 0 degrees.
-- @param #string NewName (Optional) The name of the new static.
-- @return #SPAWNSTATIC
function SPAWNSTATIC:SpawnFromCoordinate(Coordinate, Heading, NewName) --R2.4
self:F( { PointVec2, Heading, NewName } )
local StaticTemplate, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( self.SpawnTemplatePrefix )
if StaticTemplate then
Heading=Heading or 0
local StaticUnitTemplate = StaticTemplate.units[1]
StaticUnitTemplate.x = Coordinate.x
StaticUnitTemplate.y = Coordinate.z
StaticUnitTemplate.alt = Coordinate.y
StaticTemplate.route = nil
StaticTemplate.groupId = nil
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
StaticUnitTemplate.name = StaticTemplate.name
StaticUnitTemplate.heading = ( Heading / 180 ) * math.pi
_DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID)
self:F({StaticTemplate = StaticTemplate})
local Static = coalition.addStaticObject( self.CountryID or CountryID, StaticTemplate.units[1] )
self.SpawnIndex = self.SpawnIndex + 1
return _DATABASE:FindStatic(Static:getName())
end
return nil
end
--- Respawns the original @{Static}.
-- @param #SPAWNSTATIC self
-- @return #SPAWNSTATIC
function SPAWNSTATIC:ReSpawn()
local StaticTemplate, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( self.SpawnTemplatePrefix )
if StaticTemplate then
local StaticUnitTemplate = StaticTemplate.units[1]
StaticTemplate.route = nil
StaticTemplate.groupId = nil
local Static = coalition.addStaticObject( self.CountryID or CountryID, StaticTemplate.units[1] )
return _DATABASE:FindStatic(Static:getName())
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, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( self.SpawnTemplatePrefix )
if StaticTemplate then
local StaticUnitTemplate = StaticTemplate.units[1]
StaticUnitTemplate.x = Coordinate.x
StaticUnitTemplate.y = Coordinate.z
StaticUnitTemplate.heading = Heading and ( ( Heading / 180 ) * math.pi ) or StaticTemplate.heading
local Static = coalition.addStaticObject( self.CountryID or CountryID, StaticTemplate.units[1] )
return _DATABASE:FindStatic(Static:getName())
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.
-- @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.
-- @param #string NewName (optional) The name of the new static.
-- @return #SPAWNSTATIC
function SPAWNSTATIC:SpawnFromZone( Zone, Heading, NewName ) --R2.1
self:F( { Zone, Heading, NewName } )

View File

@@ -1,17 +1,16 @@
--- **Core 2.1** -- Management of SPOT logistics, that can be transported from and to transportation carriers.
--
-- ![Banner Image](..\Presentations\SPOT\Dia1.JPG)
--- **Core** - Management of spotting logistics, that can be activated and deactivated upon command.
--
-- ===
--
-- SPOT implements the DCS Spot class functionality, but adds additional luxury to be able to:
--
-- * Spot for a defined duration.
-- * wiggle the spot at the target.
-- * Provide a @{Unit} as a target, instead of a point.
-- * Updates of laer spot position every 0.2 seconds for moving targets.
-- * Wiggle the spot at the target.
-- * Provide a @{Wrapper.Unit} as a target, instead of a point.
-- * Implement a status machine, LaseOn, LaseOff.
--
-- ====
-- ===
--
-- # Demo Missions
--
@@ -21,7 +20,7 @@
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
-- ===
--
-- # YouTube Channel
--
@@ -29,20 +28,17 @@
--
-- ===
--
-- # **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
-- @module Core.Spot
-- @image Core_Spot.JPG
do
@@ -51,13 +47,12 @@ do
-- @extends Core.Fsm#FSM
--- # SPOT class, extends @{Fsm#FSM}
--
-- SPOT implements the DCS Spot class functionality, but adds additional luxury to be able to:
--- Implements the target spotting or marking functionality, but adds additional luxury to be able to:
--
-- * Mark targets for a defined duration.
-- * wiggle the spot at the target.
-- * Provide a @{Unit} as a target, instead of a point.
-- * Updates of laer spot position every 0.2 seconds for moving targets.
-- * Wiggle the spot at the target.
-- * Provide a @{Wrapper.Unit} as a target, instead of a point.
-- * Implement a status machine, LaseOn, LaseOff.
--
-- ## 1. SPOT constructor
@@ -92,9 +87,7 @@ do
--- SPOT Constructor.
-- @param #SPOT self
-- @param Wrapper.Unit#UNIT Recce
-- @param #number LaserCode
-- @param #number Duration
-- @param Wrapper.Unit#UNIT Recce Unit that is lasing
-- @return #SPOT
function SPOT:New( Recce )
@@ -122,12 +115,50 @@ do
--- LaseOn Trigger for SPOT
-- @function [parent=#SPOT] LaseOn
-- @param #SPOT self
-- @param Wrapper.Positionable#POSITIONABLE Target
-- @param #number LaserCode Laser code.
-- @param #number Duration Duration of lasing in seconds.
--- LaseOn Asynchronous Trigger for SPOT
-- @function [parent=#SPOT] __LaseOn
-- @param #SPOT self
-- @param #number Delay
-- @param Wrapper.Positionable#POSITIONABLE Target
-- @param #number LaserCode Laser code.
-- @param #number Duration Duration of lasing in seconds.
self:AddTransition( "Off", "LaseOnCoordinate", "On" )
--- LaseOnCoordinate Handler OnBefore for SPOT.
-- @function [parent=#SPOT] OnBeforeLaseOnCoordinate
-- @param #SPOT self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- LaseOnCoordinate Handler OnAfter for SPOT.
-- @function [parent=#SPOT] OnAfterLaseOnCoordinate
-- @param #SPOT self
-- @param #string From
-- @param #string Event
-- @param #string To
--- LaseOnCoordinate Trigger for SPOT.
-- @function [parent=#SPOT] LaseOnCoordinate
-- @param #SPOT self
-- @param Core.Point#COORDINATE Coordinate The coordinate to lase.
-- @param #number LaserCode Laser code.
-- @param #number Duration Duration of lasing in seconds.
--- LaseOn Asynchronous Trigger for SPOT
-- @function [parent=#SPOT] __LaseOn
-- @param #SPOT self
-- @param #number Delay
-- @param Wrapper.Positionable#POSITIONABLE Target
-- @param #number LaserCode Laser code.
-- @param #number Duration Duration of lasing in seconds.
self:AddTransition( "On", "Lasing", "On" )
@@ -196,15 +227,16 @@ do
return self
end
--- @param #SPOT self
--- On after LaseOn event. Activates the laser spot.
-- @param #SPOT self
-- @param From
-- @param Event
-- @param To
-- @param Wrapper.Positionable#POSITIONABLE Target
-- @param #number LaserCode
-- @param #number Duration
-- @param Wrapper.Positionable#POSITIONABLE Target Unit that is being lased.
-- @param #number LaserCode Laser code.
-- @param #number Duration Duration of lasing in seconds.
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 +258,50 @@ do
self:HandleEvent( EVENTS.Dead )
self:__Lasing( -0.2 )
self:__Lasing( -1 )
end
--- On after LaseOnCoordinate event. Activates the laser spot.
-- @param #SPOT self
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate The coordinate at which the laser is pointing.
-- @param #number LaserCode Laser code.
-- @param #number Duration Duration of lasing in seconds.
function SPOT:onafterLaseOnCoordinate(From, Event, To, Coordinate, LaserCode, Duration)
self:F( { "LaseOnCoordinate", Coordinate, LaserCode, Duration } )
local function StopLase( self )
self:LaseOff()
end
self.Target = nil
self.TargetCoord=Coordinate
self.LaserCode = LaserCode
self.Lasing = true
local RecceDcsUnit = self.Recce:GetDCSObject()
self.SpotIR = Spot.createInfraRed( RecceDcsUnit, { x = 0, y = 1, z = 0 }, Coordinate:GetVec3() )
self.SpotLaser = Spot.createLaser( RecceDcsUnit, { x = 0, y = 1, z = 0 }, Coordinate:GetVec3(), LaserCode )
if Duration then
self.ScheduleID = self.LaseScheduler:Schedule( self, StopLase, {self}, Duration )
end
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
@@ -248,12 +314,22 @@ do
-- @param To
function SPOT:onafterLasing( From, Event, To )
if self.Target:IsAlive() then
if self.Target and self.Target:IsAlive() then
self.SpotIR:setPoint( self.Target:GetPointVec3():AddY(1):AddY(math.random(-100,100)/100):AddX(math.random(-100,100)/100):GetVec3() )
self.SpotLaser:setPoint( self.Target:GetPointVec3():AddY(1):GetVec3() )
self:__Lasing( -0.2 )
elseif self.TargetCoord then
-- Wiggle the IR spot a bit.
local irvec3={x=self.TargetCoord.x+math.random(-100,100)/100, y=self.TargetCoord.y+math.random(-100,100)/100, z=self.TargetCoord.z} --#DCS.Vec3
local lsvec3={x=self.TargetCoord.x, y=self.TargetCoord.y, z=self.TargetCoord.z} --#DCS.Vec3
self.SpotIR:setPoint(irvec3)
self.SpotLaser:setPoint(lsvec3)
self:__Lasing(-0.25)
else
self:E( { "Target is not alive", self.Target:IsAlive() } )
self:F( { "Target is not alive", self.Target:IsAlive() } )
end
end
@@ -265,7 +341,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** - Manage user flags to interact with the mission editor trigger system and server side scripts.
--
-- ===
--
-- ## Features:
--
-- * Set or get DCS user flags within running missions.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module Core.UserFlag
-- @image Core_Userflag.JPG
--
do -- UserFlag
--- @type USERFLAG
-- @extends Core.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
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() --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,140 @@
--- **Core** - Manage user sound.
--
-- ===
--
-- ## Features:
--
-- * Play sounds wihtin running missions.
--
-- ===
--
-- Management of DCS User Sound.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module Core.UserSound
-- @image Core_Usersound.JPG
do -- UserSound
--- @type USERSOUND
-- @extends Core.Base#BASE
--- Management of DCS User Sound.
--
-- ## 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#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#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 @{Wrapper.Group}.
-- @param #USERSOUND self
-- @param Wrapper.Group#GROUP Group The @{Wrapper.Group} to play the usersound to.
-- @param #number Delay (Optional) Delay in seconds, before the sound is played. Default 0.
-- @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, Delay ) --R2.3
Delay=Delay or 0
if Delay>0 then
SCHEDULER:New(nil, USERSOUND.ToGroup,{self, Group}, Delay)
else
trigger.action.outSoundForGroup( Group:GetID(), self.UserSoundFileName )
end
return self
end
end

View File

@@ -0,0 +1,191 @@
--- **Core** - Models a velocity or speed, which can be expressed in various formats according the settings.
--
-- ===
--
-- ## Features:
--
-- * Convert velocity in various metric systems.
-- * Set the velocity.
-- * Create a text in a specific format of a velocity.
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @module Core.Velocity
-- @image MOOSE.JPG
do -- Velocity
--- @type VELOCITY
-- @extends Core.Base#BASE
--- VELOCITY models a speed, which can be expressed in various formats according the Settings.
--
-- ## 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 @{Core.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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,203 @@
--- The ZONE_DETECTION class, defined by a zone name, a detection object and a radius.
-- @type ZONE_DETECTION
-- @field DCS#Vec2 Vec2 The current location of the zone.
-- @field DCS#Distance Radius The radius of the zone.
-- @extends #ZONE_BASE
--- The ZONE_DETECTION class defined by a zone name, a location and a radius.
-- This class implements the inherited functions from Core.Zone#ZONE_BASE taking into account the own zone format and properties.
--
-- ## ZONE_DETECTION constructor
--
-- * @{#ZONE_DETECTION.New}(): Constructor.
--
-- @field #ZONE_DETECTION
ZONE_DETECTION = {
ClassName="ZONE_DETECTION",
}
--- Constructor of @{#ZONE_DETECTION}, taking the zone name, the zone location and a radius.
-- @param #ZONE_DETECTION self
-- @param #string ZoneName Name of the zone.
-- @param Functional.Detection#DETECTION_BASE Detection The detection object defining the locations of the central detections.
-- @param DCS#Distance Radius The radius around the detections defining the combined zone.
-- @return #ZONE_DETECTION self
function ZONE_DETECTION:New( ZoneName, Detection, Radius )
local self = BASE:Inherit( self, ZONE_BASE:New( ZoneName ) ) -- #ZONE_DETECTION
self:F( { ZoneName, Detection, Radius } )
self.Detection = Detection
self.Radius = Radius
return self
end
--- Bounds the zone with tires.
-- @param #ZONE_DETECTION self
-- @param #number Points (optional) The amount of points in the circle. Default 360.
-- @param DCS#country.id CountryID The country id of the tire objects, e.g. country.id.USA for blue or country.id.RUSSIA for red.
-- @param #boolean UnBound (Optional) If true the tyres will be destroyed.
-- @return #ZONE_DETECTION self
function ZONE_DETECTION:BoundZone( Points, CountryID, UnBound )
local Point = {}
local Vec2 = self:GetVec2()
Points = Points and Points or 360
local Angle
local RadialBase = math.pi*2
--
for Angle = 0, 360, (360 / Points ) do
local Radial = Angle * RadialBase / 360
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
local CountryName = _DATABASE.COUNTRY_NAME[CountryID]
local Tire = {
["country"] = CountryName,
["category"] = "Fortifications",
["canCargo"] = false,
["shape_name"] = "H-tyre_B_WF",
["type"] = "Black_Tyre_WF",
--["unitId"] = Angle + 10000,
["y"] = Point.y,
["x"] = Point.x,
["name"] = string.format( "%s-Tire #%0d", self:GetName(), Angle ),
["heading"] = 0,
} -- end of ["group"]
local Group = coalition.addStaticObject( CountryID, Tire )
if UnBound and UnBound == true then
Group:destroy()
end
end
return self
end
--- Smokes the zone boundaries in a color.
-- @param #ZONE_DETECTION 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_DETECTION self
function ZONE_DETECTION: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
local Angle
local RadialBase = math.pi*2
for Angle = 0, 360, 360 / Points do
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, AddHeight ):Smoke( SmokeColor )
end
return self
end
--- Flares the zone boundaries in a color.
-- @param #ZONE_DETECTION self
-- @param Utilities.Utils#FLARECOLOR FlareColor The flare color.
-- @param #number Points (optional) The amount of points in the circle.
-- @param DCS#Azimuth Azimuth (optional) Azimuth The azimuth of the flare.
-- @param #number AddHeight (optional) The height to be added for the smoke.
-- @return #ZONE_DETECTION self
function ZONE_DETECTION: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
local RadialBase = math.pi*2
for Angle = 0, 360, 360 / Points do
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, AddHeight ):Flare( FlareColor, Azimuth )
end
return self
end
--- Returns the radius around the detected locations defining the combine zone.
-- @param #ZONE_DETECTION self
-- @return DCS#Distance The radius.
function ZONE_DETECTION:GetRadius()
self:F2( self.ZoneName )
self:T2( { self.Radius } )
return self.Radius
end
--- Sets the radius around the detected locations defining the combine zone.
-- @param #ZONE_DETECTION self
-- @param DCS#Distance Radius The radius.
-- @return #ZONE_DETECTION self
function ZONE_DETECTION:SetRadius( Radius )
self:F2( self.ZoneName )
self.Radius = Radius
self:T2( { self.Radius } )
return self.Radius
end
--- Returns if a location is within the zone.
-- @param #ZONE_DETECTION self
-- @param DCS#Vec2 Vec2 The location to test.
-- @return #boolean true if the location is within the zone.
function ZONE_DETECTION:IsVec2InZone( Vec2 )
self:F2( Vec2 )
local Coordinates = self.Detection:GetDetectedItemCoordinates() -- This returns a list of coordinates that define the (central) locations of the detections.
for CoordinateID, Coordinate in pairs( Coordinates ) do
local ZoneVec2 = Coordinate:GetVec2()
if ZoneVec2 then
if (( Vec2.x - ZoneVec2.x )^2 + ( Vec2.y - ZoneVec2.y ) ^2 ) ^ 0.5 <= self:GetRadius() then
return true
end
end
end
return false
end
--- Returns if a point is within the zone.
-- @param #ZONE_DETECTION self
-- @param DCS#Vec3 Vec3 The point to test.
-- @return #boolean true if the point is within the zone.
function ZONE_DETECTION:IsVec3InZone( Vec3 )
self:F2( Vec3 )
local InZone = self:IsVec2InZone( { x = Vec3.x, y = Vec3.z } )
return InZone
end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,138 +1,271 @@
--- The CLEANUP class keeps an area clean of crashing or colliding airplanes. It also prevents airplanes from firing within this area.
-- @module CleanUp
-- @author Flightcontrol
--- **Functional** -- Keep airbases clean of crashing or colliding airplanes, and kill missiles when being fired at airbases.
--
-- ===
--
-- ## Features:
--
--
-- * Try to keep the airbase clean and operational.
-- * Prevent airplanes from crashing.
-- * Clean up obstructing airplanes from the runway that are standing still for a period of time.
-- * Prevent airplanes firing missiles within the airbase zone.
--
-- ===
--
-- ## Missions:
--
-- [CLA - CleanUp Airbase](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CLA%20-%20CleanUp%20Airbase)
--
-- ===
--
-- 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.
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @module Functional.CleanUp
-- @image CleanUp_Airbases.JPG
--- 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.__
--- Keeps airbases clean, and tries to guarantee continuous airbase operations, even under combat.
--
-- # 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 )
for UnitName, Unit in pairs( _DATABASE.UNITS ) do
local Unit = Unit -- Wrapper.Unit#UNIT
if Unit:IsAlive() ~= nil then
if self:IsInAirbase( Unit:GetVec2() ) then
self:F( { UnitName = UnitName } )
self.CleanUpList[UnitName] = {}
self.CleanUpList[UnitName].CleanUpUnit = Unit
self.CleanUpList[UnitName].CleanUpGroup = Unit:GetGroup()
self.CleanUpList[UnitName].CleanUpGroupName = Unit:GetGroup():GetName()
self.CleanUpList[UnitName].CleanUpUnitName = Unit:GetName()
end
end
end
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 @{Wrapper.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)
-- TODO Client bug in 1.5.3
if CleanUpGroup and CleanUpGroup:isExist() then
local CleanUpGroupUnits = CleanUpGroup:getUnits()
local CleanUpUnitName = CleanUpUnit:GetName()
local CleanUpGroup = CleanUpUnit:GetGroup()
-- TODO DCS BUG - Client bug in 1.5.3
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#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].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 )
if EventData.IniUnit:IsAlive() ~= nil then
if self:IsInAirbase( EventData.IniUnit:GetVec2() ) then
self.CleanUpList[EventData.IniDCSUnitName] = {}
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
end
end
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.
--TODO: DCS BUG - This stuff is not working due to a DCS bug. Burning units cannot be destroyed.
-- self:T("before getGroup")
-- local _grp = Unit.getGroup(event.initiator)-- Identify the group that fired
-- self:T("after getGroup")
@@ -140,171 +273,169 @@ 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 )
--- Add the @{DCS#Unit} to the CleanUpList for CleanUp.
-- @param #CLEANUP_AIRBASE self
-- @param DCS#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 } )
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
self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because below safe height and damaged." } )
self:_DestroyUnit(CleanUpUnit, CleanUpUnitName)
end
else
self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because on runway and damaged." } )
self:_DestroyUnit(CleanUpUnit, CleanUpUnitName)
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
self:T( { "CleanUp Scheduler", "Destroy due to not moving anymore " .. CleanUpUnitName } )
self:_DestroyUnit(CleanUpUnit, CleanUpUnitName)
end
end
else
UnitData.CleanUpTime = timer.getTime()
UnitData.CleanUpMoved = true
end
end
local CleanUpUnit = CleanUpListData.CleanUpUnit -- Wrapper.Unit#UNIT
local CleanUpGroupName = CleanUpListData.CleanUpGroupName
if CleanUpUnit:IsAlive() ~= nil then
if self:IsInAirbase( CleanUpUnit:GetVec2() ) then
if _DATABASE:GetStatusGroup( CleanUpGroupName ) ~= "ReSpawn" 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 )
end
else
self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because on runway and damaged." } )
self:DestroyUnit( CleanUpUnit )
end
end
end
-- Clean Units which are waiting for a very long time in the CleanUpZone.
if CleanUpUnit and not CleanUpUnit:GetPlayerName() 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 )
end
end
else
CleanUpListData.CleanUpTime = timer.getTime()
CleanUpListData.CleanUpMoved = true
end
end
else
-- not anymore in an airbase zone, remove from cleanup list.
self.CleanUpList[CleanUpUnitName] = nil
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

@@ -0,0 +1,416 @@
do -- DETECTION_ZONES
--- @type DETECTION_ZONES
-- @field DCS#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
-- @field #DETECTION_BASE.DetectedItems DetectedItems A list of areas containing the set of @{Wrapper.Unit}s, @{Zone}s, the center @{Wrapper.Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
-- @extends Functional.Detection#DETECTION_BASE
--- (old, to be revised ) Detect units within the battle zone for a list of @{Core.Zone}s detecting targets following (a) detection method(s),
-- and will build a list (table) of @{Core.Set#SET_UNIT}s containing the @{Wrapper.Unit#UNIT}s detected.
-- The class is group the detected units within zones given a DetectedZoneRange parameter.
-- A set with multiple detected zones will be created as there are groups of units detected.
--
-- ## 4.1) Retrieve the Detected Unit Sets and Detected Zones
--
-- The methods to manage the DetectedItems[].Set(s) are implemented in @{Functional.Detection#DECTECTION_BASE} and
-- the methods to manage the DetectedItems[].Zone(s) is implemented in @{Functional.Detection#DETECTION_ZONES}.
--
-- Retrieve the DetectedItems[].Set with the method @{Functional.Detection#DETECTION_BASE.GetDetectedSet}(). A @{Core.Set#SET_UNIT} object will be returned.
--
-- Retrieve the formed @{Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZones}().
-- To understand the amount of zones created, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZoneCount}().
-- If you want to obtain a specific zone from the DetectedZones, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZone}() with a given index.
--
-- ## 4.4) Flare or Smoke detected units
--
-- Use the methods @{Functional.Detection#DETECTION_ZONES.FlareDetectedUnits}() or @{Functional.Detection#DETECTION_ZONES.SmokeDetectedUnits}() to flare or smoke the detected units when a new detection has taken place.
--
-- ## 4.5) Flare or Smoke or Bound detected zones
--
-- Use the methods:
--
-- * @{Functional.Detection#DETECTION_ZONES.FlareDetectedZones}() to flare in a color
-- * @{Functional.Detection#DETECTION_ZONES.SmokeDetectedZones}() to smoke in a color
-- * @{Functional.Detection#DETECTION_ZONES.SmokeDetectedZones}() to bound with a tire with a white flag
--
-- the detected zones when a new detection has taken place.
--
-- @field #DETECTION_ZONES
DETECTION_ZONES = {
ClassName = "DETECTION_ZONES",
DetectionZoneRange = nil,
}
--- DETECTION_ZONES constructor.
-- @param #DETECTION_ZONES self
-- @param Core.Set#SET_ZONE DetectionSetZone The @{Set} of ZONE_RADIUS.
-- @param DCS#Coalition.side DetectionCoalition The coalition of the detection.
-- @return #DETECTION_ZONES
function DETECTION_ZONES:New( DetectionSetZone, DetectionCoalition )
-- Inherits from DETECTION_BASE
local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionSetZone ) ) -- #DETECTION_ZONES
self.DetectionSetZone = DetectionSetZone -- Core.Set#SET_ZONE
self.DetectionCoalition = DetectionCoalition
self._SmokeDetectedUnits = false
self._FlareDetectedUnits = false
self._SmokeDetectedZones = false
self._FlareDetectedZones = false
self._BoundDetectedZones = false
return self
end
--- @param #DETECTION_ZONES self
-- @param #number The amount of alive recce.
function DETECTION_ZONES:CountAliveRecce()
return self.DetectionSetZone:Count()
end
--- @param #DETECTION_ZONES self
function DETECTION_ZONES:ForEachAliveRecce( IteratorFunction, ... )
self:F2( arg )
self.DetectionSetZone:ForEachZone( IteratorFunction, arg )
return self
end
--- Report summary of a detected item using a given numeric index.
-- @param #DETECTION_ZONES self
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
-- @param Wrapper.Group#GROUP AttackGroup The group to get the settings for.
-- @param Core.Settings#SETTINGS Settings (Optional) Message formatting settings to use.
-- @return Core.Report#REPORT The report of the detection items.
function DETECTION_ZONES:DetectedItemReportSummary( DetectedItem, AttackGroup, Settings )
self:F( { DetectedItem = DetectedItem } )
local DetectedItemID = self:GetDetectedItemID( DetectedItem )
if DetectedItem then
local DetectedSet = self:GetDetectedItemSet( DetectedItem )
local ReportSummaryItem
local DetectedZone = self:GetDetectedItemZone( DetectedItem )
local DetectedItemCoordinate = DetectedZone:GetCoordinate()
local DetectedItemCoordText = DetectedItemCoordinate:ToString( AttackGroup, Settings )
local ThreatLevelA2G = self:GetDetectedItemThreatLevel( DetectedItem )
local DetectedItemsCount = DetectedSet:Count()
local DetectedItemsTypes = DetectedSet:GetTypeNames()
local Report = REPORT:New()
Report:Add(DetectedItemID .. ", " .. DetectedItemCoordText)
Report:Add( string.format( "Threat: [%s]", string.rep( "", ThreatLevelA2G ), string.rep( "", 10-ThreatLevelA2G ) ) )
Report:Add( string.format("Type: %2d of %s", DetectedItemsCount, DetectedItemsTypes ) )
Report:Add( string.format("Detected: %s", DetectedItem.IsDetected and "yes" or "no" ) )
return Report
end
return nil
end
--- Report detailed of a detection result.
-- @param #DETECTION_ZONES self
-- @param Wrapper.Group#GROUP AttackGroup The group to generate the report for.
-- @return #string
function DETECTION_ZONES:DetectedReportDetailed( AttackGroup ) --R2.1 Fixed missing report
self:F()
local Report = REPORT:New()
for DetectedItemIndex, DetectedItem in pairs( self.DetectedItems ) do
local DetectedItem = DetectedItem -- #DETECTION_BASE.DetectedItem
local ReportSummary = self:DetectedItemReportSummary( DetectedItem, AttackGroup )
Report:SetTitle( "Detected areas:" )
Report:Add( ReportSummary:Text() )
end
local ReportText = Report:Text()
return ReportText
end
--- Calculate the optimal intercept point of the DetectedItem.
-- @param #DETECTION_ZONES self
-- @param #DETECTION_BASE.DetectedItem DetectedItem
function DETECTION_ZONES:CalculateIntercept( DetectedItem )
local DetectedCoord = DetectedItem.Coordinate
-- local DetectedSpeed = DetectedCoord:GetVelocity()
-- local DetectedHeading = DetectedCoord:GetHeading()
--
-- if self.Intercept then
-- local DetectedSet = DetectedItem.Set
-- -- todo: speed
--
-- local TranslateDistance = DetectedSpeed * self.InterceptDelay
--
-- local InterceptCoord = DetectedCoord:Translate( TranslateDistance, DetectedHeading )
--
-- DetectedItem.InterceptCoord = InterceptCoord
-- else
-- DetectedItem.InterceptCoord = DetectedCoord
-- end
DetectedItem.InterceptCoord = DetectedCoord
end
--- Smoke the detected units
-- @param #DETECTION_ZONES self
-- @return #DETECTION_ZONES self
function DETECTION_ZONES:SmokeDetectedUnits()
self:F2()
self._SmokeDetectedUnits = true
return self
end
--- Flare the detected units
-- @param #DETECTION_ZONES self
-- @return #DETECTION_ZONES self
function DETECTION_ZONES:FlareDetectedUnits()
self:F2()
self._FlareDetectedUnits = true
return self
end
--- Smoke the detected zones
-- @param #DETECTION_ZONES self
-- @return #DETECTION_ZONES self
function DETECTION_ZONES:SmokeDetectedZones()
self:F2()
self._SmokeDetectedZones = true
return self
end
--- Flare the detected zones
-- @param #DETECTION_ZONES self
-- @return #DETECTION_ZONES self
function DETECTION_ZONES:FlareDetectedZones()
self:F2()
self._FlareDetectedZones = true
return self
end
--- Bound the detected zones
-- @param #DETECTION_ZONES self
-- @return #DETECTION_ZONES self
function DETECTION_ZONES:BoundDetectedZones()
self:F2()
self._BoundDetectedZones = true
return self
end
--- Make text documenting the changes of the detected zone.
-- @param #DETECTION_ZONES self
-- @param #DETECTION_BASE.DetectedItem DetectedItem
-- @return #string The Changes text
function DETECTION_ZONES:GetChangeText( DetectedItem )
self:F( DetectedItem )
local MT = {}
for ChangeCode, ChangeData in pairs( DetectedItem.Changes ) do
if ChangeCode == "AA" then
MT[#MT+1] = "Detected new area " .. ChangeData.ID .. ". The center target is a " .. ChangeData.ItemUnitType .. "."
end
if ChangeCode == "RAU" then
MT[#MT+1] = "Changed area " .. ChangeData.ID .. ". Removed the center target."
end
if ChangeCode == "AAU" then
MT[#MT+1] = "Changed area " .. ChangeData.ID .. ". The new center target is a " .. ChangeData.ItemUnitType .. "."
end
if ChangeCode == "RA" then
MT[#MT+1] = "Removed old area " .. ChangeData.ID .. ". No more targets in this area."
end
if ChangeCode == "AU" then
local MTUT = {}
for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do
if ChangeUnitType ~= "ID" then
MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType
end
end
MT[#MT+1] = "Detected for area " .. ChangeData.ID .. " new target(s) " .. table.concat( MTUT, ", " ) .. "."
end
if ChangeCode == "RU" then
local MTUT = {}
for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do
if ChangeUnitType ~= "ID" then
MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType
end
end
MT[#MT+1] = "Removed for area " .. ChangeData.ID .. " invisible or destroyed target(s) " .. table.concat( MTUT, ", " ) .. "."
end
end
return table.concat( MT, "\n" )
end
--- Make a DetectionSet table. This function will be overridden in the derived clsses.
-- @param #DETECTION_ZONES self
-- @return #DETECTION_ZONES self
function DETECTION_ZONES:CreateDetectionItems()
self:F( "Checking Detected Items for new Detected Units ..." )
local DetectedUnits = SET_UNIT:New()
-- First go through all zones, and check if there are new Zones.
-- New Zones become a new DetectedItem.
for ZoneName, DetectionZone in pairs( self.DetectionSetZone:GetSet() ) do
local DetectedItem = self:GetDetectedItemByKey( ZoneName )
if DetectedItem == nil then
DetectedItem = self:AddDetectedItemZone( "ZONE", ZoneName, nil, DetectionZone )
end
local DetectedItemSetUnit = self:GetDetectedItemSet( DetectedItem )
-- Scan the zone
DetectionZone:Scan( { Object.Category.UNIT }, { Unit.Category.GROUND_UNIT } )
-- For all the units in the zone,
-- check if they are of the same coalition to be included.
local ZoneUnits = DetectionZone:GetScannedUnits()
for DCSUnitID, DCSUnit in pairs( ZoneUnits ) do
local UnitName = DCSUnit:getName()
local ZoneUnit = UNIT:FindByName( UnitName )
local ZoneUnitCoalition = ZoneUnit:GetCoalition()
if ZoneUnitCoalition == self.DetectionCoalition then
if DetectedItemSetUnit:FindUnit( UnitName ) == nil and DetectedUnits:FindUnit( UnitName ) == nil then
self:F( "Adding " .. UnitName )
DetectedItemSetUnit:AddUnit( ZoneUnit )
DetectedUnits:AddUnit( ZoneUnit )
end
end
end
end
-- Now all the tests should have been build, now make some smoke and flares...
-- We also report here the friendlies within the detected areas.
for DetectedItemID, DetectedItemData in pairs( self.DetectedItems ) do
local DetectedItem = DetectedItemData -- #DETECTION_BASE.DetectedItem
local DetectedSet = self:GetDetectedItemSet( DetectedItem )
local DetectedFirstUnit = DetectedSet:GetFirst()
local DetectedZone = self:GetDetectedItemZone( DetectedItem )
-- Set the last known coordinate to the detection item.
local DetectedZoneCoord = DetectedZone:GetCoordinate()
self:SetDetectedItemCoordinate( DetectedItem, DetectedZoneCoord, DetectedFirstUnit )
self:CalculateIntercept( DetectedItem )
-- We search for friendlies nearby.
-- If there weren't any friendlies nearby, and now there are friendlies nearby, we flag the area as "changed".
-- If there were friendlies nearby, and now there aren't any friendlies nearby, we flag the area as "changed".
-- This is for the A2G dispatcher to detect if there is a change in the tactical situation.
local OldFriendliesNearbyGround = self:IsFriendliesNearBy( DetectedItem, Unit.Category.GROUND_UNIT )
self:ReportFriendliesNearBy( { DetectedItem = DetectedItem, ReportSetGroup = self.DetectionSetGroup } ) -- Fill the Friendlies table
local NewFriendliesNearbyGround = self:IsFriendliesNearBy( DetectedItem, Unit.Category.GROUND_UNIT )
if OldFriendliesNearbyGround ~= NewFriendliesNearbyGround then
DetectedItem.Changed = true
end
self:SetDetectedItemThreatLevel( DetectedItem ) -- Calculate A2G threat level
--self:NearestRecce( DetectedItem )
if DETECTION_ZONES._SmokeDetectedUnits or self._SmokeDetectedUnits then
DetectedZone:SmokeZone( SMOKECOLOR.Red, 30 )
end
--DetectedSet:Flush( self )
DetectedSet:ForEachUnit(
--- @param Wrapper.Unit#UNIT DetectedUnit
function( DetectedUnit )
if DetectedUnit:IsAlive() then
--self:T( "Detected Set #" .. DetectedItem.ID .. ":" .. DetectedUnit:GetName() )
if DETECTION_ZONES._FlareDetectedUnits or self._FlareDetectedUnits then
DetectedUnit:FlareGreen()
end
if DETECTION_ZONES._SmokeDetectedUnits or self._SmokeDetectedUnits then
DetectedUnit:SmokeGreen()
end
end
end
)
if DETECTION_ZONES._FlareDetectedZones or self._FlareDetectedZones then
DetectedZone:FlareZone( SMOKECOLOR.White, 30, math.random( 0,90 ) )
end
if DETECTION_ZONES._SmokeDetectedZones or self._SmokeDetectedZones then
DetectedZone:SmokeZone( SMOKECOLOR.White, 30 )
end
if DETECTION_ZONES._BoundDetectedZones or self._BoundDetectedZones then
self.CountryID = DetectedSet:GetFirst():GetCountry()
DetectedZone:BoundZone( 12, self.CountryID )
end
end
end
--- @param #DETECTION_ZONES self
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @param Detection The element on which the detection is based.
-- @param #number DetectionTimeStamp Time stamp of detection event.
function DETECTION_ZONES:onafterDetection( From, Event, To, Detection, DetectionTimeStamp )
self.DetectionRun = self.DetectionRun + 1
if self.DetectionCount > 0 and self.DetectionRun == self.DetectionCount then
self:CreateDetectionItems() -- Polymorphic call to Create/Update the DetectionItems list for the DETECTION_ class grouping method.
for DetectedItemID, DetectedItem in pairs( self.DetectedItems ) do
self:UpdateDetectedItemDetection( DetectedItem )
self:CleanDetectionItem( DetectedItem, DetectedItemID ) -- Any DetectionItem that has a Set with zero elements in it, must be removed from the DetectionItems list.
if DetectedItem then
self:__DetectedItem( 0.1, DetectedItem )
end
end
self:__Detect( -self.RefreshTimeInterval )
end
end
--- Set IsDetected flag for the DetectedItem, which can have more units.
-- @param #DETECTION_ZONES self
-- @return #DETECTION_ZONES.DetectedItem DetectedItem
-- @return #boolean true if at least one UNIT is detected from the DetectedSet, false if no UNIT was detected from the DetectedSet.
function DETECTION_ZONES:UpdateDetectedItemDetection( DetectedItem )
local IsDetected = true
DetectedItem.IsDetected = true
return IsDetected
end
end

View File

@@ -1,60 +1,82 @@
--- Taking the lead of AI escorting your flight.
--- **Functional** -- Taking the lead of AI escorting your flight.
--
-- ===
--
-- ## Features:
--
-- * Escort navigation commands.
-- * Escort hold at position commands.
-- * Escorts reporting detected targets.
-- * Escorts scanning targets in advance.
-- * Escorts attacking specific targets.
-- * Request assistance from other groups for attack.
-- * Manage rule of engagement of escorts.
-- * Manage the allowed evasion techniques of escorts.
-- * Make escort to execute a defined mission or path.
-- * Escort tactical situation reporting.
--
-- ===
--
-- ## Missions:
--
-- [ESC - Escorting](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/ESC%20-%20Escorting)
--
-- ===
--
-- Allows you to interact with escorting AI on your flight and take the lead.
--
-- @{#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).
--
-- The radio commands will vary according the category of the group. The richest set of commands are with Helicopters and AirPlanes.
-- 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:
-- ================================
-- # RADIO MENUs that can be created:
--
-- Find a summary below of the current available commands:
--
-- Navigation ...:
-- ---------------
-- ## Navigation ...:
--
-- Escort group navigation functions:
--
-- * **"Join-Up and Follow at x meters":** The escort group fill follow you at about x meters, and they will follow you.
-- * **"Flare":** Provides menu commands to let the escort group shoot a flare in the air in a color.
-- * **"Smoke":** Provides menu commands to let the escort group smoke the air in a color. Note that smoking is only available for ground and naval troops.
--
-- Hold position ...:
-- ------------------
-- ## Hold position ...:
--
-- Escort group navigation functions:
--
-- * **"At current location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped.
-- * **"At client location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped.
--
-- Report targets ...:
-- -------------------
-- ## Report targets ...:
--
-- Report targets will make the escort group to report any target that it identifies within a 8km range. Any detected target can be attacked using the 4. Attack nearby targets function. (see below).
--
-- * **"Report now":** Will report the current detected targets.
-- * **"Report targets on":** Will make the escort group to report detected targets and will fill the "Attack nearby targets" menu list.
-- * **"Report targets off":** Will stop detecting targets.
--
-- Scan targets ...:
-- -----------------
-- ## Scan targets ...:
--
-- Menu items to pop-up the escort group for target scanning. After scanning, the escort group will resume with the mission or defined task.
--
-- * **"Scan targets 30 seconds":** Scan 30 seconds for targets.
-- * **"Scan targets 60 seconds":** Scan 60 seconds for targets.
--
-- Attack targets ...:
-- -------------------
-- ## Attack targets ...:
--
-- This menu item will list all detected targets within a 15km range. Depending on the level of detection (known/unknown) and visuality, the targets type will also be listed.
--
-- Request assistance from ...:
-- ----------------------------
-- ## Request assistance from ...:
--
-- This menu item will list all detected targets within a 15km range, as with the menu item **Attack Targets**.
-- This menu item allows to request attack support from other escorts supporting the current client group.
-- eg. the function allows a player to request support from the Ship escort to attack a target identified by the Plane escort with its Tomahawk missiles.
-- eg. the function allows a player to request support from other Planes escorting to bomb the unit with illumination missiles or bombs, so that the main plane escort can attack the area.
--
-- ROE ...:
-- --------
-- ## ROE ...:
--
-- Sets the Rules of Engagement (ROE) of the escort group when in flight.
--
-- * **"Hold Fire":** The escort group will hold fire.
@@ -62,8 +84,8 @@
-- * **"Open Fire":** The escort group will open fire on designated targets.
-- * **"Weapon Free":** The escort group will engage with any target.
--
-- Evasion ...:
-- ------------
-- ## Evasion ...:
--
-- Will define the evasion techniques that the escort group will perform during flight or combat.
--
-- * **"Fight until death":** The escort group will have no reaction to threats.
@@ -71,35 +93,43 @@
-- * **"Evade enemy fire":** The rescort group will evade enemy fire before firing.
-- * **"Go below radar and evade fire":** The escort group will perform evasive vertical manoeuvres.
--
-- Resume Mission ...:
-- -------------------
-- ## Resume Mission ...:
--
-- Escort groups can have their own mission. This menu item will allow the escort group to resume their Mission from a given waypoint.
-- Note that this is really fantastic, as you now have the dynamic of taking control of the escort groups, and allowing them to resume their path or mission.
--
-- ESCORT construction methods.
-- ============================
-- ===
--
-- ### Authors: **FlightControl**
--
-- ===
--
-- @module Functional.Escort
-- @image Escorting.JPG
--- @type ESCORT
-- @extends Core.Base#BASE
-- @field Wrapper.Client#CLIENT EscortClient
-- @field Wrapper.Group#GROUP EscortGroup
-- @field #string EscortName
-- @field #ESCORT.MODE EscortMode The mode the escort is in.
-- @field Core.Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class.
-- @field #number FollowDistance The current follow distance.
-- @field #boolean ReportTargets If true, nearby targets are reported.
-- @Field DCS#AI.Option.Air.val.ROE OptionROE Which ROE is set to the EscortGroup.
-- @field DCS#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the EscortGroup.
-- @field FunctionalMENU_GROUPDETECTION_BASE Detection
--- ESCORT class
--
-- # 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.New}: Creates a new ESCORT object from a @{Wrapper.Group#GROUP} for a @{Wrapper.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.
-- * @{#ESCORT.MenuHoldAtEscortPosition}: Creates a menu to hold the escort at its current position.
-- * @{#ESCORT.MenuHoldAtLeaderPosition}: Creates a menu to hold the escort at the client position.
-- * @{#ESCORT.MenuScanForTargets}: Creates a menu so that the escort scans targets.
-- * @{#ESCORT.MenuFlare}: Creates a menu to disperse flares.
-- * @{#ESCORT.MenuSmoke}: Creates a menu to disparse smoke.
-- * @{#ESCORT.MenuReportTargets}: Creates a menu so that the escort reports targets.
-- * @{#ESCORT.MenuReportPosition}: Creates a menu so that the escort reports its current position from bullseye.
-- * @{#ESCORT.MenuAssistedAttack: Creates a menu so that the escort supportes assisted attack from other escorts with the client.
-- * @{#ESCORT.MenuROE: Creates a menu structure to set the rules of engagement of the escort.
-- * @{#ESCORT.MenuEvasion: Creates a menu structure to set the evasion techniques when the escort is under threat.
-- * @{#ESCORT.MenuResumeMission}: Creates a menu structure so that the escort can resume from a waypoint.
--
--
-- @usage
-- -- Declare a new EscortPlanes object as follows:
--
@@ -109,26 +139,8 @@
--
-- -- Now use these 2 objects to construct the new EscortPlanes object.
-- EscortPlanes = ESCORT:New( EscortClient, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
--
--
--
-- @module Escort
-- @author FlightControl
--- ESCORT class
-- @type ESCORT
-- @extends Core.Base#BASE
-- @field Wrapper.Client#CLIENT EscortClient
-- @field Wrapper.Group#GROUP EscortGroup
-- @field #string EscortName
-- @field #ESCORT.MODE EscortMode The mode the escort is in.
-- @field Core.Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class.
-- @field #number FollowDistance The current follow distance.
-- @field #boolean ReportTargets If true, nearby targets are reported.
-- @Field 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 #ESCORT
ESCORT = {
ClassName = "ESCORT",
EscortName = nil, -- The Escort Name
@@ -205,7 +217,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)
@@ -294,21 +306,21 @@ end
--- Defines a menu slot to let the escort Join and Follow you at a certain distance.
-- This menu will appear under **Navigation**.
-- @param #ESCORT self
-- @param Dcs.DCSTypes#Distance Distance The distance in meters that the escort needs to follow the client.
-- @param DCS#Distance Distance The distance in meters that the escort needs to follow the client.
-- @return #ESCORT
function ESCORT:MenuFollowAt( Distance )
self:F(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
@@ -319,8 +331,8 @@ end
--- Defines a menu slot to let the escort hold at their current position and stay low with a specified height during a specified time in seconds.
-- This menu will appear under **Hold position**.
-- @param #ESCORT self
-- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters.
-- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given.
-- @param DCS#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters.
-- @param DCS#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given.
-- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed.
-- @return #ESCORT
-- TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function.
@@ -330,7 +342,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 +372,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,
@@ -380,8 +392,8 @@ end
--- Defines a menu slot to let the escort hold at the client position and stay low with a specified height during a specified time in seconds.
-- This menu will appear under **Navigation**.
-- @param #ESCORT self
-- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters.
-- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given.
-- @param DCS#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters.
-- @param DCS#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given.
-- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed.
-- @return #ESCORT
-- TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function.
@@ -391,7 +403,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 +433,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,
@@ -441,8 +453,8 @@ end
--- Defines a menu slot to let the escort scan for targets at a certain height for a certain time in seconds.
-- This menu will appear under **Scan targets**.
-- @param #ESCORT self
-- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters.
-- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given.
-- @param DCS#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters.
-- @param DCS#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given.
-- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed.
-- @return #ESCORT
function ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat )
@@ -450,7 +462,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 +492,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 +518,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 +529,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 +551,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 +562,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
@@ -566,13 +578,13 @@ end
-- This menu will appear under **Report targets**.
-- Note that if a report targets menu is not specified, no targets will be detected by the escort, and the attack and assisted attack menus will not be displayed.
-- @param #ESCORT self
-- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort report their current detected targets after specified time interval in seconds. The default time is 30 seconds.
-- @param DCS#Time Seconds Optional parameter that lets the escort report their current detected targets after specified time interval in seconds. The default time is 30 seconds.
-- @return #ESCORT
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 +592,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 +615,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 +629,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 +658,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 +686,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
@@ -736,7 +748,7 @@ end
-- @param Functional.Escort#ESCORT self
-- @param Wrapper.Group#GROUP EscortGroup
-- @param Wrapper.Client#CLIENT EscortClient
-- @param Dcs.DCSTypes#Distance Distance
-- @param DCS#Distance Distance
function ESCORT:JoinUpAndFollow( EscortGroup, EscortClient, Distance )
self:F( { EscortGroup, EscortClient, Distance } )
@@ -845,11 +857,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 +872,7 @@ function ESCORT:_AttackTarget( DetectedItemID )
EscortGroup:OptionROTPassiveDefense()
EscortGroup:SetState( EscortGroup, "Escort", self )
local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID )
local DetectedSet = self.Detection:GetDetectedItemSet( DetectedItem )
local Tasks = {}
@@ -873,7 +885,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 +895,7 @@ function ESCORT:_AttackTarget( DetectedItemID )
else
local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID )
local DetectedSet = self.Detection:GetDetectedItemSet( DetectedItem )
local Tasks = {}
@@ -909,8 +921,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 +934,7 @@ function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItemID )
EscortGroupAttack:OptionROEOpenFire()
EscortGroupAttack:OptionROTVertical()
local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID )
local DetectedSet = self.Detection:GetDetectedItemSet( DetectedItem )
local Tasks = {}
@@ -943,7 +956,7 @@ function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItemID )
)
else
local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID )
local DetectedSet = self.Detection:GetDetectedItemSet( DetectedItem )
local Tasks = {}
@@ -1150,7 +1163,7 @@ function ESCORT:_ReportTargetsScheduler()
end
local DetectedItems = self.Detection:GetDetectedItems()
self:E( DetectedItems )
self:F( DetectedItems )
local DetectedTargets = false
@@ -1159,36 +1172,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 +1216,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 +1338,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 +1349,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 +1389,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
--

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,27 @@
--- This module contains the MISSILETRAINER class.
--- **Functional** -- Train missile defence and deflection.
--
-- ===
--
-- 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,
-- ## Features:
--
-- * Track the missiles fired at you and other players, providing bearing and range information of the missiles towards the airplanes.
-- * Provide alerts of missile launches, including detailed information of the units launching, including bearing, range <20>
-- * Provide alerts when a missile would have killed your aircraft.
-- * Provide alerts when the missile self destructs.
-- * Enable / Disable and Configure the Missile Trainer using the various menu options.
--
-- ===
--
-- ## Missions:
--
-- [MIT - Missile Trainer](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/MIT%20-%20Missile%20Trainer)
--
-- ===
--
-- Uses the MOOSE 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:
--
-- * Track the missiles fired at you and other players, providing bearing and range information of the missiles towards the airplanes.
-- * Provide alerts of missile launches, including detailed information of the units launching, including bearing, range <20>
-- * Provide alerts when a missile would have killed your aircraft.
-- * Provide alerts when the missile self destructs.
-- * Enable / Disable and Configure the Missile Trainer using the various menu options.
--
-- When running a mission where MISSILETRAINER is used, the following radio menu structure ( 'Radio Menu' -> 'Other (F10)' -> 'MissileTrainer' ) options are available for the players:
-- When running a mission where the missile trainer is used, the following radio menu structure ( 'Radio Menu' -> 'Other (F10)' -> 'MissileTrainer' ) options are available for the players:
--
-- * **Messages**: Menu to configure all messages.
-- * **Messages On**: Show all messages.
@@ -44,17 +51,40 @@
-- * **150 meter**: Destroys the missile when the distance to the aircraft is below or equal to 150 meter.
-- * **200 meter**: Destroys the missile when the distance to the aircraft is below or equal to 200 meter.
--
-- ===
--
-- ### Authors: **FlightControl**
--
-- ### Contributions:
--
-- * **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.
-- Together with the **476 virtual team**, we tested the MISSILETRAINER class, and got much positive feedback!
-- * **132nd Squadron**: Testing and optimizing the logic.
--
-- ===
--
-- 1.1) MISSILETRAINER construction methods:
-- -----------------------------------------
-- @module Functional.MissileTrainer
-- @image Missile_Trainer.JPG
--- @type MISSILETRAINER
-- @field Core.Set#SET_CLIENT DBClients
-- @extends Core.Base#BASE
---
--
-- # Constructor:
--
-- Create a new MISSILETRAINER object with the @{#MISSILETRAINER.New} method:
--
-- * @{#MISSILETRAINER.New}: Creates a new MISSILETRAINER object taking the maximum distance to your aircraft to evaluate when a missile needs to be destroyed.
--
-- MISSILETRAINER will collect each unit declared in the mission with a skill level "Client" and "Player", and will monitor the missiles shot at those.
--
-- 1.2) MISSILETRAINER initialization methods:
-- -------------------------------------------
-- # Initialization:
--
-- A MISSILETRAINER object will behave differently based on the usage of initialization methods:
--
-- * @{#MISSILETRAINER.InitMessagesOnOff}: Sets by default the display of any message to be ON or OFF.
@@ -67,24 +97,8 @@
-- * @{#MISSILETRAINER.InitRangeOnOff}: Sets by default the display of range information of missiles ON of OFF.
-- * @{#MISSILETRAINER.InitBearingOnOff}: Sets by default the display of bearing information of missiles ON of OFF.
-- * @{#MISSILETRAINER.InitMenusOnOff}: Allows to configure the options through the radio menu.
--
-- ===
--
-- 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.
-- Together with the **476 virtual team**, we tested the MISSILETRAINER class, and got much positive feedback!
--
-- @module MissileTrainer
-- @author FlightControl
--- The MISSILETRAINER class
-- @type MISSILETRAINER
-- @field Core.Set#SET_CLIENT DBClients
-- @extends Core.Base#BASE
-- @field #MISSILETRAINER
MISSILETRAINER = {
ClassName = "MISSILETRAINER",
TrackingMissiles = {},
@@ -99,39 +113,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 +191,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 +456,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 +584,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 +669,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 +679,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,13 +1,20 @@
--- 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
-- on defined intervals (currently every minute).
-- @module Movement
-- @module Functional.Movement
-- @image MOOSE.JPG
--- the MOVEMENT class
-- @type MOVEMENT
--- @type MOVEMENT
-- @extends Core.Base#BASE
---
--@field #MOVEMENT
MOVEMENT = {
ClassName = "MOVEMENT",
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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