Compare commits

...

154 Commits

Author SHA1 Message Date
Applevangelist
48721859fa #CTLD
* Added Subcategories for static cargo objects
2023-01-31 11:27:12 +01:00
Applevangelist
ee59d999f5 #POINT
* Added COORDINATE:SetAtLandheight()
2023-01-30 18:00:16 +01:00
Applevangelist
2f4f98cfe0 #CTLD - nobuildmenu option 2023-01-29 18:36:44 +01:00
Frank
ac1f202c19 Update Airboss.lua
- Added CJS Superhornet Mod
2023-01-29 12:53:50 +01:00
Frank
3f97ba3bd7 Database
- Polygon drawings are registered as polygon zones
2023-01-28 18:42:29 +01:00
grandpaSam
c0442fca68 Changed documentation for Marker.lua and MarkerOps_Base.lua (#1891) 2023-01-28 09:02:15 +01:00
Thomas
c20927b6d7 Update Marker.lua 2023-01-27 18:34:53 +01:00
Jason du Plessis
0d5b6d4c3e #CSAR - Add Persistence (#1889)
* Adds a modified version of ops.CTLD's Persistence to ops.CSAR
2023-01-26 21:11:15 +01:00
Applevangelist
bdc08a530d #AB 2023-01-25 17:54:13 +01:00
Applevangelist
6ab1632b4b #RANGE
* Set Google Key if given

#AIRBASE
* Added 3 Falklands AB to the enumerator
2023-01-25 17:53:29 +01:00
Thomas
cec865b9fb UTILS - exclude 243 MHz and 121.5 MHz 2023-01-25 13:37:56 +01:00
Thomas
d763e924a9 Update Utils.lua (#1886) 2023-01-24 20:16:46 +01:00
Applevangelist
57a30621e1 #CTLD added documentation 2023-01-24 15:26:32 +01:00
Applevangelist
f344084791 #1885
#PSEUDOATC - Menu shows Waypoint name if it has been set
2023-01-24 10:06:05 +01:00
Applevangelist
be68314c3a #CONTROLLABLE
* Added CommandActivateACLS()
* Added CommandDeactivateACLS()
2023-01-23 17:11:18 +01:00
Applevangelist
53cff8229b #CTLD
* Added option movecratesbeforebuild
* Added option surfacetypes for build-in reloads
* Inject function can optionally take surfacetypes
* Inject function can use the center of the zone instead of a random position

#EVENT
* Handle landing event if the place is a SCENERY object (helopad on a map, but not an airbase)

#ZONE
* docu corrections
2023-01-22 13:10:27 +01:00
Frank
1d52e27668 Update Controllable.lua
- Added enroute task SEAD
2023-01-19 19:10:56 +01:00
Applevangelist
6ec867196c #UTILS - make LoadSetOfGroups save(r) for groups spawned with SpawnScheduled 2023-01-19 14:59:54 +01:00
Applevangelist
80798f278c #Controllable - docu changes 2023-01-17 12:09:13 +01:00
Applevangelist
4e61bbb92e Merge remote-tracking branch 'origin/master' 2023-01-17 09:26:16 +01:00
Applevangelist
fabab9bfbb #ATIS docu fix 2023-01-17 09:25:01 +01:00
Applevangelist
4ae0089e4f #CSAR
* Docu corrections
2023-01-15 17:40:03 +01:00
Applevangelist
d82bce79c9 #CSAR
* Docu corrections
2023-01-15 17:38:54 +01:00
Applevangelist
55fcaf1c05 #CTLD - Adde Shark III typename 2023-01-12 13:20:12 +01:00
Applevangelist
e83df502ed #AIRBASE - docu fixes 2023-01-10 13:08:05 +01:00
Applevangelist
6501e89fa2 #PSEUDOATC
* Fix for debug messages
2023-01-10 07:47:56 +01:00
Applevangelist
91801d441f #GROUP
* Improve functionality of GetUnit(x)
* Added GetFirstUnit()
2023-01-09 17:07:21 +01:00
Frank
dd2a4ee7ff COORDINATE
- Added `GetMagneticDeclination` function
2023-01-08 19:32:38 +01:00
Applevangelist
8cedd88ce2 #SCENERY - explain destroy doesn't work 2023-01-05 10:58:40 +01:00
Applevangelist
c3fde2b698 Merge remote-tracking branch 'origin/master' 2023-01-05 10:48:55 +01:00
Applevangelist
59e8aed445 #CSAR fix for beacons 2023-01-05 10:48:50 +01:00
Applevangelist
e47b8f377c #CTLD/CSAR
* Small fix for
2023-01-05 10:45:37 +01:00
Applevangelist
793c0d988e Changes from dev 2023-01-03 10:22:10 +01:00
Applevangelist
b0eef34146 #CONTROLLABLE
* Docu fix

#WAREHOUSE
* Changes from dev

#ZONE
* Additions to ZONE_POLYGON
2023-01-03 10:15:16 +01:00
Applevangelist
3fbfb8b528 #UNIT
* Fix #1865
2023-01-02 17:27:01 +01:00
Thomas
cdd240abb7 PseudoATC - Option to display playername (#1870)
Use `myatc:SetReportPlayername()` to switch this on #1864
2023-01-02 14:28:35 +01:00
Applevangelist
5d802f0e16 #TIMER
* Added `StartIf()`
2023-01-01 12:34:02 +01:00
Applevangelist
8661d07e1e #ATIS
* Make SRS say TACAN and FARP and not spell the single characters
2022-12-29 16:33:13 +01:00
Thomas
41eec658e0 UTILS - Update Load/Save Groups and Statics (#1857)
Addresses #1855 and #1856 

Added options to save groups in a structrued manner, allowing to despawn specific unit-types on a reload. Optionally, cinematic effects like smoke and fires can be put in place of despawned units. For statics, an option to replace them with dead statics has been added, and also cinematic effects.
2022-12-28 15:40:40 +01:00
Thomas
9facf07955 ATIS - added basic FARP support (#1854)
ATIS - added basic FARP support, only works with SRS
2022-12-25 14:18:53 +01:00
Applevangelist
cd4844d26c #EVENT
* Small fix for hit event on coordinates
2022-12-24 12:03:04 +01:00
Applevangelist
9619b11c58 #CTLD
* add sound folder path option
2022-12-23 13:42:14 +01:00
Thomas
535060153a CTLD #1851 Add variable for a sound path (#1852)
CTLD #1851 Add variable for a sound path - defaults to  `self.RadioPath = "l10n/DEFAULT/"`
2022-12-23 13:39:00 +01:00
Applevangelist
f26ff52712 #UNIT
* Docu fix
2022-12-21 14:09:47 +01:00
Applevangelist
4a299ea53f #CTLD
* Added option to inject troops into helos
2022-12-21 14:05:58 +01:00
Applevangelist
6f0ba337c4 #SET_SCENERY
* Added GetAliveSet()
2022-12-21 12:55:01 +01:00
Applevangelist
8df6e2dd57 #UNIT
* Improve GetGroup() as after Dec/22 patch geGroup() might be nil
# SET_UNIT
* Improved Docu
2022-12-19 16:12:09 +01:00
Applevangelist
5010cdff71 #CTLD
* Fix to also save crates which have not been moved
2022-12-19 14:04:30 +01:00
Applevangelist
fea1839c06 #AIRBASE
* Added Rio Chico Airfield
2022-12-16 18:43:50 +01:00
Applevangelist
80e3b157ca #UTILS
* UTILS.LoadSetOfStatics(Path,Filename) ignore statics which do not exist
2022-12-15 18:28:06 +01:00
Applevangelist
d5028d86df #SET_CLIENT
* small addition
2022-12-15 11:49:28 +01:00
Applevangelist
1fac6b7c93 #SET_CLIENT
* Added `FilterCallsigns()` and `FilterPlayernames()`
2022-12-14 14:48:20 +01:00
Applevangelist
089467c15a #AI\_A2A\_GCICAP
* Fix demo mission link
2022-12-14 09:41:35 +01:00
Applevangelist
77e7f767d8 #AIRBASE
* docu correction
2022-12-12 16:23:47 +01:00
Applevangelist
324739aeb9 #SET
* Improve GetRandom() a bit
2022-12-11 15:49:50 +01:00
Applevangelist
84d301c676 #CTLD
* Added disallow building in loadzones: my_ctld.nobuildinloadzones = true
2022-12-09 12:37:39 +01:00
Applevangelist
dcfce8b619 #CTLD - enforce modulation on beacons 2022-12-07 18:50:26 +01:00
Frank
813d4edc97 CONDITION v0.3.0
- Added methods to remove condition functions
- Added option to define output if no condition functions at all were given
-
2022-12-07 18:35:12 +01:00
Applevangelist
9ea4a5dbd4 #CTLD less log noise 2022-12-06 12:49:27 +01:00
Applevangelist
508e36d327 #CTLD Fix for Beacon Zone disappearing too fast 2022-12-03 14:37:01 +01:00
Applevangelist
37b1e7366c *smaller fixes 2022-12-02 16:39:09 +01:00
Thomas
b29b9f1b2c Update README.md 2022-12-01 21:32:19 +01:00
Applevangelist
7865be43bb * Minor fixes 2022-12-01 13:27:58 +01:00
Frank
f17f688a20 Condition and Message 2022-11-30 18:37:14 +01:00
Applevangelist
df2a6a6902 #ATIS
* Added `ATIS:GetSRSText()`
2022-11-29 17:53:41 +01:00
Applevangelist
df0c0ec21e #CTLD
* Small fix for BEACON Zones
2022-11-29 15:39:58 +01:00
Thomas
53d71d9766 Update RAT.lua
Fix #1848
2022-11-28 17:42:09 +01:00
Applevangelist
eb5a72fc27 * less noise 2022-11-27 17:35:13 +01:00
Applevangelist
cec045045e * Less noise 2022-11-27 17:35:13 +01:00
Applevangelist
33f30101d9 Merge remote-tracking branch 'origin/master' 2022-11-23 09:55:50 +01:00
Applevangelist
1e139a6005 #SPAWN
* Fix callsign dupplication of numbers introduced with 2.8
2022-11-23 09:55:47 +01:00
Applevangelist
eacfbad729 #SPAWN
* Fix for unit callsign number duplication since 2.8 release (ED saving callsign.name now as "Texaco11" instead of "Texaco" for the F10 Map overview
2022-11-23 09:48:06 +01:00
Frank
6834a2e083 Spawning FARPS
**SPAWNSTATIC**
- Added event birth when static FARPS are spawned

**EVENT**
- Unknown airbases as inititiator are registered
2022-11-20 20:55:34 +01:00
Frank
2538d583ad Update Suppression.lua
- Fixed routing of group (passing waypoint function was triggered too early due to changed DCS behaviour)
2022-11-19 19:36:55 +01:00
Applevangelist
0f1ad9d811 # TaskRecoveryTanker 2022-11-18 11:28:52 +01:00
Applevangelist
93c986f00a #GROUP
* Added additional push of tanker task to GROUP:SetAsRecoveryTanker() for a working setup
2022-11-18 11:23:56 +01:00
Applevangelist
239e2ef86d #GROUP/CONTROLLABLE
* Added RecoveryTanker Task
2022-11-18 09:58:48 +01:00
Applevangelist
5a7a23552d #AIRBASE
* Added enumerators for
-- * AIRBASE.SouthAtlantic.Puerto_Santa_Cruz
-- * AIRBASE.SouthAtlantic.Comandante_Luis_Piedrabuena
-- * AIRBASE.SouthAtlantic.Aerodromo_De_Tolhuin
-- * AIRBASE.SouthAtlantic.Porvenir_Airfield
-- * AIRBASE.SouthAtlantic.Almirante_Schroeders
-- * AIRBASE.SouthAtlantic.Rio_Turbio
2022-11-17 17:13:33 +01:00
Applevangelist
4fb98cf72b #CSAR
* Make rescued pilot's weight configureable
2022-11-17 13:54:43 +01:00
Applevangelist
a125497fe7 #SPAWN
* Ensure we have a numbered table for InitRandomizeTemplate/Zone so math.random actually works
* Also, pre-shuffle tables
2022-11-16 11:12:47 +01:00
Applevangelist
ae2196585e #MESSAGE
* added to country
* added a couple of countries to country.id. enumerator
2022-11-16 09:39:54 +01:00
Applevangelist
fbad50973f # Bug fixes 2022-11-14 18:15:55 +01:00
Applevangelist
782cfd1fd0 #ATIS
* Added honor Stop() functionality
2022-11-14 17:36:34 +01:00
Applevangelist
d4a06089c9 #CTLD
* Change call order to move troops, vehicle on `onafter..` internally
* added pseudo-function for "OnBefore..."
2022-11-13 13:37:25 +01:00
Applevangelist
5c6efed995 Docu Headlines part II 2022-11-11 11:40:36 +01:00
Applevangelist
68a31b1eb7 Docu - Nicer Headlines 2022-11-11 09:35:54 +01:00
Applevangelist
f46f755327 #Docu fixes 2022-11-10 17:32:45 +01:00
Applevangelist
5d4f870a1d #Docu fixes 2022-11-10 17:29:40 +01:00
Applevangelist
08c5c38c7b Changes from last FF push 2022-11-09 16:09:05 +01:00
Applevangelist
0c9238651a * POINT
* Added option to get BR/BRA with add'l magnetic heading
2022-11-08 15:33:09 +01:00
Applevangelist
10a9b062b6 #MSRS
* Docu corrections
* Added `AddFrequencies()` and `AddModulations()`
2022-11-08 10:10:11 +01:00
Thomas
53c6a17ccb Fix CTLD Ship Zones
Fixes #1830
2022-11-07 19:11:08 +01:00
Applevangelist
c10617e1b0 #CTLD
* Fix for Bronco #1827
* Fix for Ship Zones
2022-11-07 17:37:02 +01:00
Thomas
be01567a1b CTLD - added Bronco (#1828)
Added data for the Bronco-OV-10A - needs further additions to ensure to work, as this is a plane, not a chopper #1827
2022-11-07 11:19:52 +01:00
TommyC81
88fc501c24 Update Range.lua (#1825)
Add meter text to RANGE bombing result.
2022-11-06 19:33:44 +01:00
Applevangelist
e93bb5ceba Merge remote-tracking branch 'origin/master' 2022-11-06 11:28:03 +01:00
Applevangelist
7983621f8e #SCORING
* Added option to switch AutoSave
2022-11-06 11:27:59 +01:00
Applevangelist
6c79d6b01f #SCORING
* Added option to switch AutoSave
2022-11-06 11:26:16 +01:00
Applevangelist
b2a351e67d UTILS 2022-11-05 14:03:38 +01:00
TommyC81
574fa8abf4 Documentation fixes. (#1820)
* Documentation fixes.

* Update Airboss.lua

Escape links.
2022-11-02 11:20:35 +01:00
Applevangelist
c4f4af5e5a #ZONE_POLYGON
* Scan for Scenery - changed scan strategy as box seems not to work properly all the time
2022-11-01 16:31:47 +01:00
Applevangelist
1da0792ed7 #CTLD
* added option for build time delay
2022-11-01 14:32:02 +01:00
Applevangelist
7d37acb1cd #CTLD_HERCULES
* Fix for `CTLD_HERCULES:Cargo_Track(cargo, initiator)` when flying very low
2022-10-31 16:06:30 +01:00
Applevangelist
fd230701e9 #EVENT
* Added events from 2.8
2022-10-31 15:43:13 +01:00
Applevangelist
91d492c579 #EVENT
* Added events from 2.8
2022-10-31 15:15:47 +01:00
Applevangelist
5eabe7e644 #GROUP
* Ensure also attribute "Tanks" is captured
2022-10-31 10:25:08 +01:00
TommyC81
368e720cab Documentation fixes. (#1816) 2022-10-29 10:07:50 +02:00
TommyC81
cba156b3dc Code formatting preparation. (#1817)
Use EmmyLuaCodeStyle that comes with "Lua" VS Code extension (https://marketplace.visualstudio.com/items?itemName=sumneko.lua). More features and configurability than LuaFormatter, and no need for additional extension (beyond "Lua").
Formatting file set up from default template with some tweaks to correspond to most common coding style observed in the code base. Further tweaks are likely required.
2022-10-29 10:07:01 +02:00
TommyC81
676bc0fef0 Documentation fixes. (#1815)
Minor documentation and code formatting fixes.
This is mostly intended to have something re-trigger the documentation generation to see if the filename capitalization is resolved.
2022-10-27 18:38:59 +02:00
TommyC81
7455c63716 Documentation fixes. (#1811)
Update documentation text and links.
Fix spelling errors.
Other minor adjustments where appropriate, such as remove whitespaces and format code.
2022-10-23 16:45:40 +02:00
TommyC81
81818705df Documentation fixes. (#1810)
Fix documentation references.
Correct spelling errors.
Remove empty whitespaces.
Correct a single mis-spelled ZONE_BASE variable, see 'Core/Zone.lua' (variable "Sureface" -> "Surface", no references to mis-spelled "Sureface" throughout the codebase).
Correct mis-spelling of "coaltion" in 'Functional/Mantis.lua', corrected to "coalition".
2022-10-22 11:07:58 +02:00
TommyC81
61ea484614 Documentation fixes. (#1809)
Fix incorrect references.
Simplify references within the same module.
Fix spelling errors and minor code formatting.
2022-10-21 13:52:09 +02:00
TommyC81
d5e8de4d74 Documentation fixes. (#1807)
Correct module links.
Replace references to missing images with MOOSE.JPG.
Add default MOOSE.JPG where no image was previously set.
Fix minor spelling error.
2022-10-21 06:10:34 +02:00
Applevangelist
b7d5144c91 #MANTIS
* Add systems from SMA mod
2022-10-20 11:39:51 +02:00
Applevangelist
7bba5ec69e #SCENERY, #SET_SCENERY
* Improvements
2022-10-19 12:37:24 +02:00
TommyC81
0441acf101 Documentation fixes. (#1803)
Improve the consistency of the module intros to the most commonly used version (single dash).

Add missing module information (abbreviated where none existed previously).

Fix broken documentation links

Make module names correspond to filenames (and fix links).

Fix typos.
2022-10-19 12:20:39 +02:00
Rolf Geuenich
89f0909a8f Fixed some errors in the documentation of Core MESSAGE (#1804)
Removed wrong forth parameter in most examples.
Removed duplicate of function ToUnit.
2022-10-19 06:32:57 +02:00
Applevangelist
ff0f1c4c24 #CTLD
* added a check for zones; not added when zone does not exist
2022-10-18 17:23:01 +02:00
Applevangelist
3a6c52ae73 #CSAR
* Added use of custom callsigns
* Added cargo weight for rescued pilots
* Improved o'clock calculation

#CTLD
* Docu additions
2022-10-18 16:59:19 +02:00
Applevangelist
7ec18ebf00 #SCENERY
* functional additions
#SET
* added SET_SCENERY
2022-10-17 18:06:29 +02:00
Thomas
66f52d41eb CTLD - No radius check (#1800)
Get rid of radius check in IsUnitInZone()
2022-10-17 12:33:17 +02:00
Applevangelist
1172cf0ae7 #GROUP
* Added function to obtain *average* Vec3 of the GROUP
* Added function to obtain *average* Coordinate of the GROUP
2022-10-16 13:36:21 +02:00
Applevangelist
1d296d1cf4 #CTLD
* Documentation additions
2022-10-14 16:50:31 +02:00
Applevangelist
a6bddc5aca #SET_UNIT - fix GetCoordinate() 2022-10-14 16:18:53 +02:00
Applevangelist
bdd40fdf7d #PLAYERTASK integration for CSAR and CTLD 2022-10-13 17:43:27 +02:00
Applevangelist
c84e153ff2 #SCENERY
* Improvements
2022-10-13 12:53:27 +02:00
Applevangelist
ab4c83d284 #SCENERY - Improvements 2022-10-13 10:49:17 +02:00
Applevangelist
cd99c053df #SCENERY
* Clarification in docu for :FindByName()
2022-10-12 16:21:55 +02:00
Applevangelist
3434ef47d9 #STATIC
* Add Life0 to STATIC Object
* Added functions for STATIC:GetLife() and STATIC:GetLife0()
2022-10-12 09:32:51 +02:00
Applevangelist
c5145a38e2 #Core.Point
* Cleanup GetClosestAirbase()
2022-10-10 17:42:02 +02:00
Applevangelist
38b9778e9a #SET
* minor enhancement
2022-10-09 12:53:45 +02:00
Jason du Plessis
2ca6168f47 #ZONE * Fixed ZONE_RADIUS Not being added to _Database (#1798)
* #ZONE * Fixed ZONE_RADIUS Not being added to _Database

Bugfix for #1797.

ZONE_RADIUS was not being registered within the _Database table, thus for CTLD, the Zone could not be found for moving units to ZONE_RADIUS zones. Because other Zone types inherit ZONE_RADIUS, I've added a RegisterZone parameter that is default to true, and modified the inheritance of the other Zone types to register the zone in the _Database depending if the zone does not get registered in that zone type.

* #ZONE * Updated ZONE_RADIUS RegisterZone to DoNotRegisterZone

Changed RegisterZone to DoNotRegisterZone and updated the different zone types values for RegisterZone.

Suggested by Applevangelist.

Co-authored-by: Jason du Plessis <jason.duplessis@ebtax.co.za>
2022-10-06 07:27:07 +02:00
Applevangelist
0da2299472 Docu changes 2022-10-05 07:32:17 +02:00
Frank
bf2ce3c4af AIRBOSS v1.3.0
- Copy from `develop` branch.
- Disabled AI handling as this is bugged (needs `FLIGHTGROUP` class)
2022-10-02 19:20:25 +02:00
Frank
c0f82eabb2 Server Name
**GLOBALS**
- Read out server name from `Config/serverSettings.lua`
**SOCKET**
- Added `server_name` to transmitted UDP data
2022-10-02 16:54:48 +02:00
Applevangelist
30aba1258d #POINT
* Added COORDINATE:ToStringFromRPShort
2022-10-02 13:14:57 +02:00
Applevangelist
f2ed920214 #SRSQUEUE, ATIS
* Added option to only transmit via SRS if there are active players
2022-10-01 11:57:22 +02:00
Applevangelist
2fc7139f6b #SET
* Added code to`SET:IsInSet(Object)` to be functional
2022-09-30 14:47:51 +02:00
Applevangelist
e8ace49e8b #SPOT - Set relative position to start lasing
#ZONE_POLYGON - Added `ZONE_POLYGON:NewFromPointsArray( ZoneName, PointsArray )`
2022-09-29 16:43:40 +02:00
Applevangelist
dddb9ff713 #ZONE_CAPTURE_COALITION - allow zone to be a ZONE_POLYGON 2022-09-28 11:49:06 +02:00
Applevangelist
f582f7df7c #ATIS
* Fixed SetILS report not working
* Use new AIRBASE additions to set takeoff/landing runway
* Fixed Visibility is reported twice
* Added SetReportmBar() to report for mBar/hpa QNH/QFE even if not metric
* Added option to output additional freetext information when using SRS SetAdditionalInformation()

#1792
2022-09-27 11:16:08 +02:00
Applevangelist
14c6d1be9b #1790 Fix for error in GetCustomCallsign if the player name contains a |-sign but no string at the end or just numbers 2022-09-27 09:27:59 +02:00
Applevangelist
0731e15385 #CSAR
* Added mycsar.ADFRadioPwr = 1000 for ADF beacon radio sending power
2022-09-26 17:01:18 +02:00
Applevangelist
9eb82060a5 SRS - corrected enumerator 2022-09-25 14:41:38 +02:00
Applevangelist
9f232ab5ec #ATIS - added Google TTS option 2022-09-25 14:41:19 +02:00
Applevangelist
ec0d164619 #MSRS - put "" around frequencies and modulations 2022-09-25 14:14:56 +02:00
Applevangelist
e804ab9254 Merge remote-tracking branch 'origin/master' 2022-09-24 10:10:06 +02:00
Applevangelist
25cb12a81a #FOX
* Added comfy function
2022-09-24 10:10:02 +02:00
Applevangelist
231acc7363 #RANGE
* added 2 more SRS outputs
2022-09-24 10:09:00 +02:00
Applevangelist
d8bdf6a8d3 #CSAR
* Added option to change top menu name
2022-09-23 10:28:35 +02:00
Applevangelist
d506067c72 #FOX
* Typo in Event Function fixed
2022-09-23 09:59:24 +02:00
Applevangelist
4483d3231a #CTLD
* Added: troop mass also checked when loading
2022-09-22 17:30:01 +02:00
Applevangelist
481ee186aa #AIRBOSS, #UTILS
* Alitude to Altitude
2022-09-22 15:49:31 +02:00
Thomas
8820b8a41c Nimitz deck height (#1787)
Corrected deck height of Nimitz class to 18.3m/60ft
2022-09-22 15:46:55 +02:00
124 changed files with 6585 additions and 2637 deletions

View File

@@ -0,0 +1,166 @@
# Repository: https://github.com/CppCXY/EmmyLuaCodeStyle
# English documentation: https://github.com/CppCXY/EmmyLuaCodeStyle/blob/master/README_EN.md
[*.lua]
# [basic]
# optional space/tab
indent_style = space
# if indent_style is space, this is valid
indent_size = 4
# if indent_style is tab, this is valid
tab_width = 4
# none/single/double
quote_style = none
# only support number
continuation_indent_size = 0
# optional crlf/lf/cr/auto, if it is 'auto', in windows it is crlf other platforms are lf
end_of_line = auto
detect_end_of_line = false
# this mean utf8 length , if this is 'unset' then the line width is no longer checked
# this option decides when to chopdown the code
max_line_length = 9999
# this will check text end with new line
insert_final_newline = true
# [function]
# function call expression's args will align to first arg
# optional true/false/only_after_more_indention_statement/only_not_exist_cross_row_expression
align_call_args = false
# if true, all function define params will align to first param
align_function_define_params = true
remove_expression_list_finish_comma = true
# keep/remove/remove_table_only/remove_string_only/unambiguous_remove_string_only
call_arg_parentheses = keep
# [table]
#optional none/comma/semicolon
table_separator_style = none
#optional keep/never/always/smart
trailing_table_separator = keep
# see document for detail
continuous_assign_table_field_align_to_equal_sign = true
# if true, format like this "local t = { 1, 2, 3 }"
keep_one_space_between_table_and_bracket = true
# if indent_style is tab, this option is invalid
align_table_field_to_first_field = true
# [statement]
align_chained_expression_statement = false
# continous line distance
max_continuous_line_distance = 1
# see document for detail
continuous_assign_statement_align_to_equal_sign = true
# if statement will align like switch case
if_condition_align_with_each_other = false
# if true, continuation_indent_size for local or assign statement is invalid
# however, if the expression list has cross row expression, it will not be aligned to the first expression
local_assign_continuation_align_to_first_expression = false
statement_inline_comment_space = 1
# [indentation]
# if true, the label loses its current indentation
label_no_indent = false
# if true, there will be no indentation in the do statement
do_statement_no_indent = false
# if true, the conditional expression of the if statement will not be a continuation line indent
if_condition_no_continuation_indent = false
if_branch_comments_after_block_no_indent = false
# [space]
# if true, t[#t+1] will not space wrapper '+'
table_append_expression_no_space = false
long_chain_expression_allow_one_space_after_colon = false
remove_empty_header_and_footer_lines_in_function = true
space_before_function_open_parenthesis = false
space_inside_function_call_parentheses = false
space_inside_function_param_list_parentheses = false
space_before_open_square_bracket = false
space_inside_square_brackets = false
# if true, ormat like this "local t <const> = 1"
keep_one_space_between_namedef_and_attribute = true
# [row_layout]
# The following configuration supports four expressions
# minLine:${n}
# keepLine
# keepLine:${n}
# maxLine:${n}
keep_line_after_if_statement = minLine:0
keep_line_after_do_statement = minLine:0
keep_line_after_while_statement = minLine:0
keep_line_after_repeat_statement = minLine:0
keep_line_after_for_statement = minLine:0
keep_line_after_local_or_assign_statement = keepLine
keep_line_after_function_define_statement = keepLine:1
keep_line_after_expression_statement = keepLine
# [diagnostic]
# the following is code diagnostic options
enable_check_codestyle = true
# [diagnostic.name_style]
enable_name_style_check = false
# the following is name style check rule
# base option off/camel_case/snake_case/upper_snake_case/pascal_case/same(filename/first_param/'<const string>', snake_case/pascal_case/camel_case)
# all option can use '|' represent or
# for example:
# snake_case | upper_snake_case
# same(first_param, snake_case)
# same('m')
local_name_define_style = snake_case
function_param_name_style = snake_case
function_name_define_style = snake_case
local_function_name_define_style = snake_case
table_field_name_define_style = snake_case
global_variable_name_define_style = snake_case|upper_snake_case
module_name_define_style = same('m')|same(filename, snake_case)
require_module_name_style = same(first_param, snake_case)
class_name_define_style = same(filename, snake_case)

View File

@@ -1,33 +0,0 @@
# See https://github.com/Koihik/LuaFormatter
# Use '-- LuaFormatter off' and '-- LuaFormatter on' around code blocks to inhibit formatting
column_limit: 500
indent_width: 2
use_tab: false
continuation_indent_width: 2
keep_simple_control_block_one_line: false
keep_simple_function_one_line: false
align_args: true
break_after_functioncall_lp: false
break_before_functioncall_rp: false
align_parameter: true
chop_down_parameter: true
break_after_functiondef_lp: false
break_before_functiondef_rp: false
align_table_field: true
break_after_table_lb: true
break_before_table_rb: true
chop_down_table: true
chop_down_kv_table: true
column_table_limit: 500
table_sep: ','
extra_sep_at_table_end: true
break_after_operator: true
single_quote_to_double_quote: false
double_quote_to_single_quote: false
spaces_before_call: 1
spaces_inside_functiondef_parens: true
spaces_inside_functioncall_parens: true
spaces_inside_table_braces: true
spaces_around_equals_in_field: true
line_breaks_after_function_body: 1

View File

@@ -1,4 +1,6 @@
--- **AI** -- (R2.2) - Models the process of Combat Air Patrol (CAP) for airplanes.
--- **AI** - Models the process of Combat Air Patrol (CAP) for airplanes.
--
-- This is a class used in the @{AI.AI_A2A_Dispatcher}.
--
-- ===
--
@@ -13,8 +15,7 @@
-- @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}
--- The AI_A2A_CAP class implements the core functions to patrol a @{Core.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)
@@ -81,15 +82,15 @@
-- 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.
-- Use the method @{#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,
-- An optional @{Core.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.
-- Use the method @{#AI_A2A_CAP.SetEngageZone}() to define that Zone.
--
-- ===
--
@@ -106,7 +107,7 @@ AI_A2A_CAP = {
-- @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 Core.Zone#ZONE_BASE PatrolZone The @{Core.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.
@@ -132,7 +133,7 @@ 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 Core.Zone#ZONE_BASE PatrolZone The @{Core.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.
@@ -191,7 +192,7 @@ 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 Wrapper.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 )

View File

@@ -1,4 +1,4 @@
--- **AI** - (R2.2) - Manages the process of an automatic A2A defense system based on an EWR network targets and coordinating CAP and GCI.
--- **AI** - Manages the process of an automatic A2A defense system based on an EWR network targets and coordinating CAP and GCI.
--
-- ===
--
@@ -57,8 +57,8 @@
--
-- ## 2. Which type of EWR will I setup? Grouping based per AREA, per TYPE or per UNIT? (Later others will follow).
--
-- The MOOSE framework leverages the @{Detection} classes to perform the EWR detection.
-- Several types of @{Detection} classes exist, and the most common characteristics of these classes is that they:
-- The MOOSE framework leverages the @{Functional.Detection} classes to perform the EWR detection.
-- Several types of @{Functional.Detection} classes exist, and the most common characteristics of these classes is that they:
--
-- * Perform detections from multiple FACs as one co-operating entity.
-- * Communicate with a Head Quarters, which consolidates each detection.
@@ -126,7 +126,7 @@
-- * polygon zones
-- * moving zones
--
-- Depending on the type of zone selected, a different @{Zone} object needs to be created from a ZONE_ class.
-- Depending on the type of zone selected, a different @{Core.Zone} object needs to be created from a ZONE_ class.
--
-- ## 14. For each Squadron doing CAP, what are the time intervals and CAP amounts to be performed?
--
@@ -356,7 +356,7 @@ do -- AI_A2A_DISPATCHER
--
-- ![Banner Image](..\Presentations\AI_A2A_DISPATCHER\Dia9.JPG)
--
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Core.Zone#ZONE_BASE}.
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE}.
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than
-- it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are.
-- In a hot war the borders are effectively defined by the ground based radar coverage of a coalition.
@@ -592,7 +592,7 @@ do -- AI_A2A_DISPATCHER
-- A2ADispatcher:SetSquadronCap( "Maykop", CAPZoneMiddle, 4000, 8000, 600, 800, 800, 1200, "RADIO" )
-- A2ADispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 )
--
-- Note the different @{Zone} MOOSE classes being used to create zones of different types. Please click the @{Zone} link for more information about the different zone types.
-- Note the different @{Core.Zone} MOOSE classes being used to create zones of different types. Please click the @{Core.Zone} link for more information about the different zone types.
-- Zones can be circles, can be setup in the mission editor using trigger zones, but can also be setup in the mission editor as polygons and in this case GROUP objects are being used!
--
-- ## 7.2. Set the squadron to execute CAP:
@@ -1148,7 +1148,7 @@ do -- AI_A2A_DISPATCHER
self:I( "Captured " .. AirbaseName )
-- Now search for all squadrons located at the airbase, and sanatize them.
-- Now search for all squadrons located at the airbase, and sanitize them.
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
if Squadron.AirbaseName == AirbaseName then
Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
@@ -1304,7 +1304,7 @@ do -- AI_A2A_DISPATCHER
--- Define a border area to simulate a **cold war** scenario.
-- A **cold war** is one where CAP aircraft patrol their territory but will not attack enemy aircraft or launch GCI aircraft unless enemy aircraft enter their territory. In other words the EWR may detect an enemy aircraft but will only send aircraft to attack it if it crosses the border.
-- A **hot war** is one where CAP aircraft will intercept any detected enemy aircraft and GCI aircraft will launch against detected enemy aircraft without regard for territory. In other words if the ground radar can detect the enemy aircraft then it will send CAP and GCI aircraft to attack it.
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are. In a hot war the borders are effectively defined by the ground based radar coverage of a coalition. Set the noborders parameter to 1
-- @param #AI_A2A_DISPATCHER self
-- @param Core.Zone#ZONE_BASE BorderZone An object derived from ZONE_BASE, or a list of objects derived from ZONE_BASE.
@@ -1713,7 +1713,7 @@ do -- AI_A2A_DISPATCHER
-- Get free parking for fighter aircraft.
local nfreeparking = DefenderSquadron.Airbase:GetFreeParkingSpotsNumber( AIRBASE.TerminalType.FighterAircraft, true )
-- Take number of free parking spots if no resource count was specifed.
-- Take number of free parking spots if no resource count was specified.
DefenderSquadron.ResourceCount = DefenderSquadron.ResourceCount or nfreeparking
-- Check that resource count is not larger than free parking spots.
@@ -1758,7 +1758,7 @@ do -- AI_A2A_DISPATCHER
-- @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 #number EngageAltType The altitude type to engage, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude.
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed.
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed.
-- @param #number PatrolMinSpeed The minimum speed at which the cap can be executed.
-- @param #number PatrolMaxSpeed The maximum speed at which the cap can be executed.
-- @param #number PatrolFloorAltitude The minimum altitude at which the cap can be executed.
@@ -1825,7 +1825,7 @@ do -- AI_A2A_DISPATCHER
--- Set a CAP for a Squadron.
-- @param #AI_A2A_DISPATCHER self
-- @param #string SquadronName The squadron name.
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed.
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed.
-- @param #number PatrolFloorAltitude The minimum altitude at which the cap can be executed.
-- @param #number PatrolCeilingAltitude the maximum altitude at which the cap can be executed.
-- @param #number PatrolMinSpeed The minimum speed at which the cap can be executed.
@@ -3940,11 +3940,7 @@ do
--
-- # Demo Missions
--
-- ### [AI\_A2A\_GCICAP for Caucasus](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-200%20-%20AI_A2A%20-%20GCICAP%20Demonstration)
-- ### [AI\_A2A\_GCICAP for NTTR](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-210%20-%20NTTR%20AI_A2A_GCICAP%20Demonstration)
-- ### [AI\_A2A\_GCICAP for Normandy](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-220%20-%20NORMANDY%20AI_A2A_GCICAP%20Demonstration)
--
-- ### [AI\_A2A\_GCICAP for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching)
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching)
--
-- ===
--

View File

@@ -1,6 +1,6 @@
--- **AI** -- (R2.2) - Models the process of Ground Controlled Interception (GCI) for airplanes.
--- **AI** - Models the process of Ground Controlled Interception (GCI) for airplanes.
--
-- This is a class used in the @{AI_A2A_Dispatcher}.
-- This is a class used in the @{AI.AI_A2A_Dispatcher}.
--
-- ===
--
@@ -8,7 +8,7 @@
--
-- ===
--
-- @module AI.AI_A2A_GCI
-- @module AI.AI_A2A_Gci
-- @image AI_Ground_Control_Intercept.JPG
@@ -89,9 +89,9 @@
--
-- ![Zone](..\Presentations\AI_GCI\Dia12.JPG)
--
-- An optional @{Zone} can be set,
-- An optional @{Core.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.
-- Use the method @{AI.AI_CAP#AI_CAP_ZONE.SetEngageZone}() to define that Zone.
--
-- ===
--
@@ -153,7 +153,7 @@ 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 Wrapper.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 )

View File

@@ -1,4 +1,4 @@
--- **AI** -- (R2.2) - Models the process of air patrol of airplanes.
--- **AI** - Models the process of air patrol of airplanes.
--
-- ===
--
@@ -13,7 +13,7 @@
--- @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}.
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}.
--
-- ![Process](..\Presentations\AI_PATROL\Dia3.JPG)
--
@@ -102,7 +102,7 @@
-- 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 threshold is calculated.
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit,
-- while a new AI is targetted to the AI_A2A_PATROL.
-- while a new AI is targeted 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.
--
@@ -122,7 +122,7 @@ AI_A2A_PATROL = {
--- Creates a new AI_A2A_PATROL object
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The patrol group object.
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.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.
@@ -264,7 +264,7 @@ function AI_A2A_PATROL:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
end
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
--- Defines a new patrol route using the @{AI.AI_Patrol#AI_PATROL_ZONE} 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.
@@ -287,7 +287,7 @@ function AI_A2A_PATROL:onafterPatrol( AIPatrol, From, Event, To )
end
--- This statis method is called from the route path within the last task at the last waaypoint of the AIPatrol.
--- This static method is called from the route path within the last task at the last waypoint of the AIPatrol.
-- Note that this method is required, as triggers the next route when patrolling for the AIPatrol.
-- @param Wrapper.Group#GROUP AIPatrol The AI group.
-- @param #AI_A2A_PATROL Fsm The FSM.
@@ -302,7 +302,7 @@ function AI_A2A_PATROL.PatrolRoute( AIPatrol, Fsm )
end
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
--- Defines a new patrol route using the @{AI.AI_Patrol#AI_PATROL_ZONE} 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.

View File

@@ -1,6 +1,6 @@
--- **AI** -- Models the process of air to ground BAI engagement for airplanes and helicopters.
--- **AI** - Models the process of air to ground BAI engagement for airplanes and helicopters.
--
-- This is a class used in the @{AI_A2G_Dispatcher}.
-- This is a class used in the @{AI.AI_A2G_Dispatcher}.
--
-- ===
--
@@ -11,11 +11,8 @@
-- @module AI.AI_A2G_BAI
-- @image AI_Air_To_Ground_Engage.JPG
--- @type AI_A2G_BAI
-- @extends AI.AI_A2A_Engage#AI_A2A_Engage
-- @extends AI.AI_A2A_Engage#AI_A2A_Engage -- TODO: Documentation. This class does not exist, unable to determine what it extends.
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
--
@@ -26,8 +23,6 @@ AI_A2G_BAI = {
ClassName = "AI_A2G_BAI",
}
--- Creates a new AI_A2G_BAI object
-- @param #AI_A2G_BAI self
-- @param Wrapper.Group#GROUP AIGroup
@@ -36,7 +31,7 @@ AI_A2G_BAI = {
-- @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 Core.Zone#ZONE_BASE PatrolZone The @{Core.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.
@@ -53,7 +48,6 @@ function AI_A2G_BAI:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAl
return self
end
--- Creates a new AI_A2G_BAI object
-- @param #AI_A2G_BAI self
-- @param Wrapper.Group#GROUP AIGroup
@@ -61,7 +55,7 @@ end
-- @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 Core.Zone#ZONE_BASE PatrolZone The @{Core.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.
@@ -76,7 +70,7 @@ 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 Wrapper.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 )
@@ -92,8 +86,6 @@ function AI_A2G_BAI:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageA
end
end
end
return AttackUnitTasks
end

View File

@@ -1,6 +1,6 @@
--- **AI** -- Models the process of air to ground engagement for airplanes and helicopters.
--- **AI** - Models the process of air to ground engagement for airplanes and helicopters.
--
-- This is a class used in the @{AI_A2G_Dispatcher}.
-- This is a class used in the @{AI.AI_A2G_Dispatcher}.
--
-- ===
--
@@ -11,11 +11,8 @@
-- @module AI.AI_A2G_CAS
-- @image AI_Air_To_Ground_Engage.JPG
--- @type AI_A2G_CAS
-- @extends AI.AI_A2G_Patrol#AI_AIR_PATROL
-- @extends AI.AI_A2G_Patrol#AI_AIR_PATROL TODO: Documentation. This class does not exist, unable to determine what it extends.
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
--
@@ -26,8 +23,6 @@ AI_A2G_CAS = {
ClassName = "AI_A2G_CAS",
}
--- Creates a new AI_A2G_CAS object
-- @param #AI_A2G_CAS self
-- @param Wrapper.Group#GROUP AIGroup
@@ -36,7 +31,7 @@ AI_A2G_CAS = {
-- @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 Core.Zone#ZONE_BASE PatrolZone The @{Core.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.
@@ -53,7 +48,6 @@ function AI_A2G_CAS:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAl
return self
end
--- Creates a new AI_A2G_CAS object
-- @param #AI_A2G_CAS self
-- @param Wrapper.Group#GROUP AIGroup
@@ -61,7 +55,7 @@ end
-- @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 Core.Zone#ZONE_BASE PatrolZone The @{Core.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.
@@ -76,7 +70,7 @@ 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 Wrapper.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 )
@@ -92,9 +86,6 @@ function AI_A2G_CAS:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageA
end
end
end
return AttackUnitTasks
end

View File

@@ -175,7 +175,7 @@
-- * polygon zones
-- * moving zones
--
-- Depending on the type of zone selected, a different @{Zone} object needs to be created from a ZONE_ class.
-- Depending on the type of zone selected, a different @{Core.Zone} object needs to be created from a ZONE_ class.
--
--
-- ## 12. Are moving defense coordinates possible?
@@ -1389,7 +1389,7 @@ do -- AI_A2G_DISPATCHER
--- Define a border area to simulate a **cold war** scenario.
-- A **cold war** is one where Patrol aircraft patrol their territory but will not attack enemy aircraft or launch GCI aircraft unless enemy aircraft enter their territory. In other words the EWR may detect an enemy aircraft but will only send aircraft to attack it if it crosses the border.
-- A **hot war** is one where Patrol aircraft will intercept any detected enemy aircraft and GCI aircraft will launch against detected enemy aircraft without regard for territory. In other words if the ground radar can detect the enemy aircraft then it will send Patrol and GCI aircraft to attack it.
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are. In a hot war the borders are effectively defined by the ground based radar coverage of a coalition. Set the noborders parameter to 1
-- @param #AI_A2G_DISPATCHER self
-- @param Core.Zone#ZONE_BASE BorderZone An object derived from ZONE_BASE, or a list of objects derived from ZONE_BASE.
@@ -2185,7 +2185,7 @@ do -- AI_A2G_DISPATCHER
-- The Sead patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
-- @param #AI_A2G_DISPATCHER self
-- @param #string SquadronName The squadron name.
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
-- @param #number PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the cap can be executed.
-- @param #number PatrolFloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
@@ -2234,7 +2234,7 @@ do -- AI_A2G_DISPATCHER
-- The Sead patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
-- @param #AI_A2G_DISPATCHER self
-- @param #string SquadronName The squadron name.
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
-- @param #number FloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
-- @param #number CeilingAltitude (optional, default = 1500m ) The maximum altitude at which the cap can be executed.
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
@@ -2336,7 +2336,7 @@ do -- AI_A2G_DISPATCHER
-- The Cas patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
-- @param #AI_A2G_DISPATCHER self
-- @param #string SquadronName The squadron name.
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
-- @param #number PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the cap can be executed.
-- @param #number PatrolFloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
@@ -2385,7 +2385,7 @@ do -- AI_A2G_DISPATCHER
-- The Cas patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
-- @param #AI_A2G_DISPATCHER self
-- @param #string SquadronName The squadron name.
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
-- @param #number FloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
-- @param #number CeilingAltitude (optional, default = 1500m ) The maximum altitude at which the cap can be executed.
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
@@ -2487,7 +2487,7 @@ do -- AI_A2G_DISPATCHER
-- The Bai patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
-- @param #AI_A2G_DISPATCHER self
-- @param #string SquadronName The squadron name.
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
-- @param #number PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the cap can be executed.
-- @param #number PatrolFloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
@@ -2536,7 +2536,7 @@ do -- AI_A2G_DISPATCHER
-- The Bai patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
-- @param #AI_A2G_DISPATCHER self
-- @param #string SquadronName The squadron name.
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
-- @param #number FloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
-- @param #number CeilingAltitude (optional, default = 1500m ) The maximum altitude at which the cap can be executed.
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.

View File

@@ -1,6 +1,6 @@
--- **AI** -- Models the process of air to ground SEAD engagement for airplanes and helicopters.
--- **AI** - Models the process of air to ground SEAD engagement for airplanes and helicopters.
--
-- This is a class used in the @{AI_A2G_Dispatcher}.
-- This is a class used in the @{AI.AI_A2G_Dispatcher}.
--
-- ===
--
@@ -65,9 +65,9 @@
--
-- ![Zone](..\Presentations\AI_GCI\Dia12.JPG)
--
-- An optional @{Zone} can be set,
-- An optional @{Core.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.
-- Use the method @{AI.AI_CAP#AI_CAP_ZONE.SetEngageZone}() to define that Zone. -- TODO: Documentation. Check that this is actually correct. The originally referenced class does not exist.
--
-- ===
--
@@ -76,8 +76,6 @@ AI_A2G_SEAD = {
ClassName = "AI_A2G_SEAD",
}
--- Creates a new AI_A2G_SEAD object
-- @param #AI_A2G_SEAD self
-- @param Wrapper.Group#GROUP AIGroup
@@ -86,7 +84,7 @@ AI_A2G_SEAD = {
-- @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 Core.Zone#ZONE_BASE PatrolZone The @{Core.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.
@@ -111,7 +109,7 @@ end
-- @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 Core.Zone#ZONE_BASE PatrolZone The @{Core.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.
@@ -127,7 +125,7 @@ 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 Wrapper.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 )

View File

@@ -374,7 +374,7 @@ 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 threshold is calculated.
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_AIR.
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targeted 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 threshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
@@ -409,7 +409,7 @@ end
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
--- Defines a new patrol route using the @{AI.AI_Patrol#AI_PATROL_ZONE} parameters and settings.
-- @param #AI_AIR self
-- @return #AI_AIR self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
@@ -473,27 +473,27 @@ function AI_AIR:onafterStatus()
-- 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 threshold 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()
RTB = true
end
@@ -504,11 +504,11 @@ function AI_AIR:onafterStatus()
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.
@@ -518,7 +518,7 @@ function AI_AIR:onafterStatus()
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
@@ -532,7 +532,7 @@ function AI_AIR:onafterStatus()
self:Damaged()
else
self:I( self.Controllable:GetName() .. " control lost! " )
self:LostControl()
end
else
@@ -550,7 +550,7 @@ function AI_AIR:onafterStatus()
if not self:Is("Home") then
self:__Status( 10 )
end
end
end
@@ -559,11 +559,11 @@ end
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
@@ -576,7 +576,7 @@ function AI_AIR.RTBHold( AIGroup, Fsm )
local Task = AIGroup:TaskOrbitCircle( 4000, 400 )
AIGroup:SetTask( Task )
end
end
--- Set the min and max factors on RTB speed. Use this, if your planes are heading back to base too fast. Default values are 0.5 and 0.6.
@@ -598,54 +598,53 @@ end
function AI_AIR:onafterRTB( AIGroup, From, Event, To )
self:F( { AIGroup, From, Event, To } )
if AIGroup and AIGroup:IsAlive() then
if AIGroup and AIGroup:IsAlive() then
self:T( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" )
self:ClearTargetDistance()
--AIGroup:ClearTasks()
AIGroup:OptionProhibitAfterburner(true)
local EngageRoute = {}
--- Calculate the target route point.
local FromCoord = AIGroup:GetCoordinate()
local ToTargetCoord = self.HomeAirbase:GetCoordinate() -- coordinate is on land height(!)
local ToTargetVec3 = ToTargetCoord:GetVec3()
ToTargetVec3.y = ToTargetCoord:GetLandHeight()+3000 -- let's set this 1000m/3000 feet above ground
local ToTargetCoord2 = COORDINATE:NewFromVec3( ToTargetVec3 )
if not self.RTBMinSpeed or not self.RTBMaxSpeed then
local RTBSpeedMax = AIGroup:GetSpeedMax()
local RTBSpeedMaxFactor = self.RTBSpeedMaxFactor or 0.6
local RTBSpeedMinFactor = self.RTBSpeedMinFactor or 0.5
self:SetRTBSpeed( RTBSpeedMax * RTBSpeedMinFactor, RTBSpeedMax * RTBSpeedMaxFactor)
end
local RTBSpeed = math.random( self.RTBMinSpeed, self.RTBMaxSpeed )
--local ToAirbaseAngle = FromCoord:GetAngleDegrees( FromCoord:GetDirectionVec3( ToTargetCoord2 ) )
local Distance = FromCoord:Get2DDistance( ToTargetCoord2 )
--local ToAirbaseCoord = FromCoord:Translate( 5000, ToAirbaseAngle )
local ToAirbaseCoord = ToTargetCoord2
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,
@@ -666,10 +665,10 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
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()
@@ -677,9 +676,9 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
--- NOW ROUTE THE GROUP!
AIGroup:Route( EngageRoute, self.TaskDelay )
end
end
--- @param #AI_AIR self

View File

@@ -1,4 +1,4 @@
--- **AI** - Create an automated AIR defense system based on a detection network of reconnaissance vehicles and air units, coordinating SEAD, BAI and CAP operations.
--- **AI** - Create an automated AIR defense system with reconnaissance units, coordinating SEAD, BAI and CAP operations.
--
-- ===
--
@@ -7,7 +7,7 @@
-- * Setup quickly an AIR defense system for a coalition.
-- * Setup multiple defense zones to defend specific coordinates in your battlefield.
-- * Setup (SEAD) Suppression of Air Defense squadrons, to gain control in the air of enemy grounds.
-- * Setup (CAS) Controlled Air Support squadrons, to attack closeby enemy ground units near friendly installations.
-- * Setup (CAS) Controlled Air Support squadrons, to attack close by enemy ground units near friendly installations.
-- * Setup (BAI) Battleground Air Interdiction squadrons to attack remote enemy ground units and targets.
-- * Define and use a detection network controlled by recce.
-- * Define AIR defense squadrons at airbases, FARPs and carriers.
@@ -24,7 +24,7 @@
--
-- ## Missions:
--
-- [AID-AIR - AI AIR Dispatching](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-AIR%20-%20AI%20AIR%20Dispatching)
-- [AID-AIR - AI AIR Dispatching](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching)
--
-- ===
--
@@ -88,7 +88,7 @@
--
-- ## 4. How do the defenses decide **when and where to engage** on approaching enemy units?
--
-- The AIR dispacher needs you to setup (various) defense coordinates, which are strategic positions in the battle field to be defended.
-- The AIR dispatcher needs you to setup (various) defense coordinates, which are strategic positions in the battle field to be defended.
-- Any ground based enemy approaching within the proximity of such a defense point, may trigger for a defensive action by friendly air units.
--
-- There are 2 important parameters that play a role in the defensive decision making: defensiveness and reactivity.
@@ -108,7 +108,7 @@
-- ## 5. Are defense coordinates and defense reactivity the only parameters?
--
-- No, depending on the target type, and the threat level of the target, the probability of defense will be higher.
-- In other words, when a SAM-10 radar emitter is detected, its probabilty for defense will be much higher than when a BMP-1 vehicle is
-- In other words, when a SAM-10 radar emitter is detected, its probability for defense will be much higher than when a BMP-1 vehicle is
-- detected, even when both enemies are at the same distance from a defense coordinate.
-- This will ensure optimal defenses, SEAD tasks will be launched much more quicker against engaging radar emitters, to ensure air superiority.
-- Approaching main battle tanks will be engaged much faster, than a group of approaching trucks.
@@ -117,12 +117,12 @@
-- ## 6. Which Squadrons will I create and which name will I give each Squadron?
--
-- The AIR defense system works with **Squadrons**. Each Squadron must be given a unique name, that forms the **key** to the squadron.
-- Several options and activities can be set per Squadron. A free format name can be given, but always ensure that the name is meaningfull
-- Several options and activities can be set per Squadron. A free format name can be given, but always ensure that the name is meaningful
-- for your mission, and remember that squadron names are used for communication to the players of your mission.
--
-- There are mainly 3 types of defenses: **SEAD**, **CAS** and **BAI**.
--
-- Suppression of Air Defenses (SEAD) are effective agains radar emitters. Close Air Support (CAS) is launched when the enemy is close near friendly units.
-- Suppression of Air Defenses (SEAD) are effective against radar emitters. Close Air Support (CAS) is launched when the enemy is close near friendly units.
-- Battleground Air Interdiction (BAI) tasks are launched when there are no friendlies around.
--
-- Depending on the defense type, different payloads will be needed. See further points on squadron definition.
@@ -174,13 +174,13 @@
-- * polygon zones
-- * moving zones
--
-- Depending on the type of zone selected, a different @{Zone} object needs to be created from a ZONE_ class.
-- Depending on the type of zone selected, a different @{Core.Zone} object needs to be created from a ZONE_ class.
--
--
-- ## 12. Are moving defense coordinates possible?
--
-- Yes, different COORDINATE types are possible to be used.
-- The COORDINATE_UNIT will help you to specify a defense coodinate that is attached to a moving unit.
-- The COORDINATE_UNIT will help you to specify a defense coordinate that is attached to a moving unit.
--
--
-- ## 13. How much defense coordinates do I need to create?
@@ -214,7 +214,7 @@
-- * From a parking spot with running engines
-- * From a parking spot with cold engines
--
-- **The default takeoff method is staight in the air.**
-- **The default takeoff method is straight in the air.**
-- This takeoff method is the most useful if you want to avoid airplane clutter at airbases!
-- But it is the least realistic one!
--
@@ -236,10 +236,10 @@
--
-- For each Squadron, depending on the helicopter or airplane type (modern, old) and payload, which overhead is required to provide any defense?
--
-- In other words, if **X** enemy ground units are detected, how many **Y** defense helicpters or airplanes need to engage (per squadron)?
-- In other words, if **X** enemy ground units are detected, how many **Y** defense helicopters or airplanes need to engage (per squadron)?
-- The **Y** is dependent on the type of airplane (era), payload, fuel levels, skills etc.
-- But the most important factor is the payload, which is the amount of AIR weapons the defense can carry to attack the enemy ground units.
-- For example, a Ka-50 can carry 16 vikrs, that means, that it potentially can destroy at least 8 ground units without a reload of ammunication.
-- For example, a Ka-50 can carry 16 vikrs, that means, that it potentially can destroy at least 8 ground units without a reload of ammunition.
-- That means, that one defender can destroy more enemy ground units.
-- Thus, the overhead is a **factor** that will calculate dynamically how many **Y** defenses will be required based on **X** attackers detected.
--
@@ -259,7 +259,7 @@
--
-- ### Author: **FlightControl** rework of GCICAP + introduction of new concepts (squadrons).
--
-- @module AI.AI_AIR_Dispatcher
-- @module AI.AI_Air_Dispatcher
-- @image AI_Air_To_Ground_Dispatching.JPG
@@ -279,7 +279,7 @@ do -- AI_AIR_DISPATCHER
-- Multiple defense coordinates can be setup. Defense coordinates can be strategic or tactical positions or references to strategic units or scenery.
-- The AIR dispatcher will evaluate every x seconds the tactical situation around each defense coordinate. When a defense coordinate
-- is under threat, it will communicate through the command center that defensive actions need to be taken and will launch groups of air units for defense.
-- The level of threat to the defense coordinate varyies upon the strength and types of the enemy units, the distance to the defense point, and the defensiveness parameters.
-- The level of threat to the defense coordinate varies upon the strength and types of the enemy units, the distance to the defense point, and the defensiveness parameters.
-- Defensive actions are taken through probability, but the closer and the more threat the enemy poses to the defense coordinate, the faster it will be attacked by friendly AIR units.
--
-- Please study carefully the underlying explanations how to setup and use this module, as it has many features.
@@ -328,7 +328,7 @@ do -- AI_AIR_DISPATCHER
-- By spawning in dynamically additional recce, you can ensure that there is sufficient reconnaissance coverage so the defense mechanism is continuously
-- alerted of new enemy ground targets.
--
-- The following example defens a new reconnaissance network using a @{Functional.Detection#DETECTION_AREAS} object.
-- The following example defense a new reconnaissance network using a @{Functional.Detection#DETECTION_AREAS} object.
--
-- -- Define a SET_GROUP object that builds a collection of groups that define the recce network.
-- -- Here we build the network with all the groups that have a name starting with CCCP Recce.
@@ -473,7 +473,7 @@ do -- AI_AIR_DISPATCHER
-- the mission designer can choose to increase or reduce the amount of planes spawned.
--
-- The method @{#AI_AIR_DISPATCHER.SetSquadron}() defines for you a new squadron.
-- The provided parameters are the squadron name, airbase name and a list of template prefixe, and a number that indicates the amount of resources.
-- The provided parameters are the squadron name, airbase name and a list of template prefixes, and a number that indicates the amount of resources.
--
-- For example, this defines 3 new squadrons:
--
@@ -619,7 +619,7 @@ do -- AI_AIR_DISPATCHER
-- Depending on the demand of requested takeoffs by the AIR dispatcher, an airfield can become overloaded. Too many aircraft need to be taken
-- off at the same time, which will result in clutter as described above. In order to better control this behaviour, a takeoff scheduler is implemented,
-- which can be used to control how many aircraft are ordered for takeoff between specific time intervals.
-- The takeff intervals can be specified per squadron, which make sense, as each squadron have a "home" airfield.
-- The takeoff intervals can be specified per squadron, which make sense, as each squadron have a "home" airfield.
--
-- For this purpose, the method @{#AI_AIR_DISPATCHER.SetSquadronTakeOffInterval}() can be used to specify the takeoff intervals of
-- aircraft groups per squadron to avoid cluttering of aircraft at airbases.
@@ -1021,7 +1021,7 @@ do -- AI_AIR_DISPATCHER
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @param Tasking.Task_AIR#AI_AIR Task
-- @param AI.AI_Air#AI_AIR Task
-- @param Wrapper.Unit#UNIT TaskUnit
-- @param #string PlayerName
@@ -1224,7 +1224,7 @@ do -- AI_AIR_DISPATCHER
self:I( "Captured " .. AirbaseName )
-- Now search for all squadrons located at the airbase, and sanatize them.
-- Now search for all squadrons located at the airbase, and sanitize them.
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
if Squadron.AirbaseName == AirbaseName then
Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
@@ -1376,7 +1376,7 @@ do -- AI_AIR_DISPATCHER
--- Define a border area to simulate a **cold war** scenario.
-- A **cold war** is one where Patrol aircraft patrol their territory but will not attack enemy aircraft or launch GCI aircraft unless enemy aircraft enter their territory. In other words the EWR may detect an enemy aircraft but will only send aircraft to attack it if it crosses the border.
-- A **hot war** is one where Patrol aircraft will intercept any detected enemy aircraft and GCI aircraft will launch against detected enemy aircraft without regard for territory. In other words if the ground radar can detect the enemy aircraft then it will send Patrol and GCI aircraft to attack it.
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are. In a hot war the borders are effectively defined by the ground based radar coverage of a coalition. Set the noborders parameter to 1
-- @param #AI_AIR_DISPATCHER self
-- @param Core.Zone#ZONE_BASE BorderZone An object derived from ZONE_BASE, or a list of objects derived from ZONE_BASE.
@@ -1796,12 +1796,12 @@ do -- AI_AIR_DISPATCHER
--
-- @return #AI_AIR_DISPATCHER
function AI_AIR_DISPATCHER:SetSquadron2( Squadron )
local SquadronName = Squadron:GetName() -- Retrieves the Squadron Name.
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
local DefenderSquadron = self.DefenderSquadrons[SquadronName]
return self
end
@@ -1812,15 +1812,15 @@ do -- AI_AIR_DISPATCHER
function AI_AIR_DISPATCHER:GetSquadron( SquadronName )
local DefenderSquadron = self.DefenderSquadrons[SquadronName]
if not DefenderSquadron then
error( "Unknown Squadron for Dispatcher:" .. SquadronName )
end
return DefenderSquadron
end
--- Set the Squadron visible before startup of the dispatcher.
-- All planes will be spawned as uncontrolled on the parking spot.
-- They will lock the parking spot.

View File

@@ -1,6 +1,6 @@
--- **AI** -- Models the process of air to ground engagement for airplanes and helicopters.
--- **AI** - Models the process of air to ground engagement for airplanes and helicopters.
--
-- This is a class used in the @{AI_A2G_Dispatcher}.
-- This is a class used in the @{AI.AI_A2G_Dispatcher}.
--
-- ===
--
@@ -65,9 +65,9 @@
--
-- ![Zone](..\Presentations\AI_GCI\Dia12.JPG)
--
-- An optional @{Zone} can be set,
-- An optional @{Core.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.
-- Use the method @{AI.AI_CAP#AI_AIR_ENGAGE.SetEngageZone}() to define that Zone.
--
-- ===
--

View File

@@ -1,4 +1,4 @@
--- **AI** -- Models the process of A2G patrolling and engaging ground targets for airplanes and helicopters.
--- **AI** - Models the process of A2G patrolling and engaging ground targets for airplanes and helicopters.
--
-- ===
--
@@ -12,8 +12,7 @@
--- @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}
--- The AI_AIR_PATROL class implements the core functions to patrol a @{Core.Zone} by an AI @{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)
@@ -86,9 +85,9 @@
--
-- ![Zone](..\Presentations\AI_CAP\Dia12.JPG)
--
-- An optional @{Zone} can be set,
-- An optional @{Core.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.
-- Use the method @{AI.AI_CAP#AI_AIR_PATROL.SetEngageZone}() to define that Zone.
--
-- ===
--
@@ -101,7 +100,7 @@ AI_AIR_PATROL = {
-- @param #AI_AIR_PATROL self
-- @param AI.AI_Air#AI_AIR AI_Air The AI_AIR FSM.
-- @param Wrapper.Group#GROUP AIGroup The AI group.
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.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.
@@ -114,17 +113,17 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
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.
@@ -135,7 +134,7 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
-- @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
@@ -143,16 +142,16 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
-- @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
@@ -161,7 +160,7 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
-- @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
@@ -169,9 +168,9 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
-- @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
@@ -180,7 +179,7 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
-- @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
@@ -188,23 +187,21 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
-- @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.
@@ -230,7 +227,7 @@ end
-- @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
@@ -238,18 +235,16 @@ function AI_AIR_PATROL:SetRaceTrackPattern(LegMin, LegMax, HeadingMin, HeadingMa
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.
--- Defines a new patrol route using the @{AI.AI_Patrol#AI_PATROL_ZONE} 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.
@@ -262,7 +257,7 @@ function AI_AIR_PATROL:onafterPatrol( AIPatrol, From, Event, To )
self:ClearTargetDistance()
self:__PatrolRoute( self.TaskDelay )
AIPatrol:OnReSpawn(
function( PatrolGroup )
self:__Reset( self.TaskDelay )
@@ -271,7 +266,7 @@ function AI_AIR_PATROL:onafterPatrol( AIPatrol, From, Event, To )
)
end
--- This statis method is called from the route path within the last task at the last waaypoint of the AIPatrol.
--- This static method is called from the route path within the last task at the last waypoint of the AIPatrol.
-- Note that this method is required, as triggers the next route when patrolling for the AIPatrol.
-- @param Wrapper.Group#GROUP AIPatrol The AI group.
-- @param #AI_AIR_PATROL Fsm The FSM.
@@ -282,10 +277,10 @@ function AI_AIR_PATROL.___PatrolRoute( AIPatrol, Fsm )
if AIPatrol and AIPatrol:IsAlive() then
Fsm:PatrolRoute()
end
end
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
--- Defines a new patrol route using the @{AI.AI_Patrol#AI_PATROL_ZONE} 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.
@@ -300,21 +295,20 @@ function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
return
end
if AIPatrol and 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
@@ -322,31 +316,31 @@ function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
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")
@@ -354,39 +348,41 @@ function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
-- 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_AIR_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
--- Resumes the AIPatrol
-- @param Wrapper.Group#GROUP AIPatrol
-- @param Core.Fsm#FSM Fsm
function AI_AIR_PATROL.Resume( AIPatrol, Fsm )
AIPatrol:F( { "AI_AIR_PATROL.Resume:", AIPatrol:GetName() } )
@@ -394,5 +390,5 @@ function AI_AIR_PATROL.Resume( AIPatrol, Fsm )
Fsm:__Reset( Fsm.TaskDelay )
Fsm:__PatrolRoute( Fsm.TaskDelay )
end
end

View File

@@ -1,6 +1,6 @@
--- **AI** - Models squadrons for airplanes and helicopters.
--
-- This is a class used in the @{AI_Air_Dispatcher} and derived dispatcher classes.
-- This is a class used in the @{AI.AI_Air_Dispatcher} and derived dispatcher classes.
--
-- ===
--

View File

@@ -1,4 +1,4 @@
--- **AI** -- Peform Battlefield Area Interdiction (BAI) within an engagement zone.
--- **AI** - Peform Battlefield Area Interdiction (BAI) within an engagement zone.
--
-- **Features:**
--
@@ -26,17 +26,17 @@
--
-- ===
--
-- @module AI.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 @{Wrapper.Controllable} patrolling.
-- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed.
-- @field Core.Zone#ZONE_BASE TargetZone The @{Core.Zone} where the patrol needs to be executed.
-- @extends AI.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}.
--- Implements the core functions to provide BattleGround Air Interdiction in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.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.
--
@@ -142,7 +142,7 @@ 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 Core.Zone#ZONE_BASE PatrolZone The @{Core.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.Controllable} in km/h.
@@ -566,7 +566,7 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
EngageRoute[#EngageRoute].task = Controllable:TaskCombo( AttackTasks )
--- Define a random point in the @{Zone}. The AI will fly to that point within the zone.
--- Define a random point in the @{Core.Zone}. The AI will fly to that point within the zone.
--- Find a random 2D point in EngageZone.
local ToTargetVec2 = self.EngageZone:GetRandomVec2()

View File

@@ -1,4 +1,4 @@
--- **AI** -- Balance player slots with AI to create an engaging simulation environment, independent of the amount of players.
--- **AI** - Balance player slots with AI to create an engaging simulation environment, independent of the amount of players.
--
-- **Features:**
--

View File

@@ -1,4 +1,4 @@
--- **AI** -- Perform Combat Air Patrolling (CAP) for airplanes.
--- **AI** - Perform Combat Air Patrolling (CAP) for airplanes.
--
-- **Features:**
--
@@ -6,7 +6,6 @@
-- * Trigger detected events when enemy airplanes are detected.
-- * Manage a fuel threshold to RTB on time.
-- * Engage the enemy when detected.
--
--
-- ===
--
@@ -19,27 +18,25 @@
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
-- ### 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.
-- * **[Delta99](https://forums.eagle.ru/member.php?u=125166): Testing.
--
-- ===
--
-- @module AI.AI_Cap
-- @module AI.AI_CAP
-- @image AI_Combat_Air_Patrol.JPG
--- @type AI_CAP_ZONE
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
-- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed.
-- @field Core.Zone#ZONE_BASE TargetZone The @{Core.Zone} where the patrol needs to be executed.
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
--- Implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}
--- Implements the core functions to patrol a @{Core.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)
@@ -106,15 +103,15 @@
-- 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_CAP_ZONE.SetEngageRange}() to define that range.
-- Use the method @{#AI_CAP_ZONE.SetEngageRange}() to define that range.
--
-- ## 4. Set the Zone of Engagement
--
-- ![Zone](..\Presentations\AI_CAP\Dia12.JPG)
--
-- An optional @{Zone} can be set,
-- An optional @{Core.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_CAP_ZONE.SetEngageZone}() to define that Zone.
-- Use the method @{#AI_CAP_ZONE.SetEngageZone}() to define that Zone.
--
-- ===
--
@@ -123,11 +120,9 @@ AI_CAP_ZONE = {
ClassName = "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 Core.Zone#ZONE_BASE PatrolZone The @{Core.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.Controllable} in km/h.
@@ -141,7 +136,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
self.Accomplished = false
self.Engaging = false
self:AddTransition( { "Patrolling", "Engaging" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE.
--- OnBefore Transition Handler for Event Engage.
@@ -152,7 +147,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
-- @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_CAP_ZONE] OnAfterEngage
-- @param #AI_CAP_ZONE self
@@ -160,11 +155,11 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
-- @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_CAP_ZONE] Engage
-- @param #AI_CAP_ZONE self
--- Asynchronous Event Trigger for Event Engage.
-- @function [parent=#AI_CAP_ZONE] __Engage
-- @param #AI_CAP_ZONE self
@@ -188,7 +183,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
-- @param #string To The To State string.
self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE.
--- OnBefore Transition Handler for Event Fired.
-- @function [parent=#AI_CAP_ZONE] OnBeforeFired
-- @param #AI_CAP_ZONE self
@@ -197,7 +192,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
-- @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_CAP_ZONE] OnAfterFired
-- @param #AI_CAP_ZONE self
@@ -205,11 +200,11 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
-- @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_CAP_ZONE] Fired
-- @param #AI_CAP_ZONE self
--- Asynchronous Event Trigger for Event Fired.
-- @function [parent=#AI_CAP_ZONE] __Fired
-- @param #AI_CAP_ZONE self
@@ -225,7 +220,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
-- @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_CAP_ZONE] OnAfterDestroy
-- @param #AI_CAP_ZONE self
@@ -233,17 +228,16 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
-- @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_CAP_ZONE] Destroy
-- @param #AI_CAP_ZONE self
--- Asynchronous Event Trigger for Event Destroy.
-- @function [parent=#AI_CAP_ZONE] __Destroy
-- @param #AI_CAP_ZONE self
-- @param #number Delay The delay in seconds.
self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE.
--- OnBefore Transition Handler for Event Abort.
@@ -254,7 +248,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
-- @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_CAP_ZONE] OnAfterAbort
-- @param #AI_CAP_ZONE self
@@ -262,11 +256,11 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
-- @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_CAP_ZONE] Abort
-- @param #AI_CAP_ZONE self
--- Asynchronous Event Trigger for Event Abort.
-- @function [parent=#AI_CAP_ZONE] __Abort
-- @param #AI_CAP_ZONE self
@@ -282,7 +276,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
-- @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_CAP_ZONE] OnAfterAccomplish
-- @param #AI_CAP_ZONE self
@@ -290,11 +284,11 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
-- @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_CAP_ZONE] Accomplish
-- @param #AI_CAP_ZONE self
--- Asynchronous Event Trigger for Event Accomplish.
-- @function [parent=#AI_CAP_ZONE] __Accomplish
-- @param #AI_CAP_ZONE self
@@ -303,7 +297,6 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
return self
end
--- Set the Engage Zone which defines where the AI will engage bogies.
-- @param #AI_CAP_ZONE self
-- @param Core.Zone#ZONE EngageZone The zone where the AI is performing CAP.
@@ -311,7 +304,7 @@ end
function AI_CAP_ZONE:SetEngageZone( EngageZone )
self:F2()
if EngageZone then
if EngageZone then
self.EngageZone = EngageZone
else
self.EngageZone = nil
@@ -346,7 +339,6 @@ function AI_CAP_ZONE:onafterStart( Controllable, From, Event, To )
end
--- @param AI.AI_CAP#AI_CAP_ZONE
-- @param Wrapper.Group#GROUP EngageGroup
function AI_CAP_ZONE.EngageRoute( EngageGroup, Fsm )
@@ -358,8 +350,6 @@ function AI_CAP_ZONE.EngageRoute( EngageGroup, Fsm )
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.
@@ -380,11 +370,11 @@ end
function AI_CAP_ZONE:onafterDetected( Controllable, From, Event, To )
if From ~= "Engaging" then
local Engage = false
for DetectedUnit, Detected in pairs( self.DetectedUnits ) do
local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT
self:T( DetectedUnit )
if DetectedUnit:IsAlive() and DetectedUnit:IsAir() then
@@ -392,7 +382,7 @@ function AI_CAP_ZONE:onafterDetected( Controllable, From, Event, To )
break
end
end
if Engage == true then
self:F( 'Detected -> Engaging' )
self:__Engage( 1 )
@@ -400,7 +390,6 @@ function AI_CAP_ZONE:onafterDetected( Controllable, From, Event, To )
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.
@@ -411,9 +400,6 @@ function AI_CAP_ZONE:onafterAbort( Controllable, From, Event, To )
self:__Route( 1 )
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.
@@ -427,24 +413,23 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
--- Calculate the current route point.
local CurrentVec2 = self.Controllable:GetVec2()
if not CurrentVec2 then return self end
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
local CurrentAltitude = self.Controllable:GetAltitude()
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToEngageZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToEngageZoneSpeed,
true
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToEngageZoneSpeed,
true
)
EngageRoute[#EngageRoute+1] = CurrentRoutePoint
--- Find a random 2D point in PatrolZone.
local ToTargetVec2 = self.PatrolZone:GetRandomVec2()
self:T2( ToTargetVec2 )
@@ -453,17 +438,17 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
local ToTargetAltitude = math.random( self.EngageFloorAltitude, self.EngageCeilingAltitude )
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } )
--- Obtain a 3D @{Point} from the 2D point + altitude.
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
--- Create a route point of type air.
local ToPatrolRoutePoint = ToTargetPointVec3:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToTargetSpeed,
true
local ToPatrolRoutePoint = ToTargetPointVec3:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToTargetSpeed,
true
)
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
@@ -482,7 +467,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
self:F( {"Within Zone and Engaging ", DetectedUnit } )
AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit )
end
else
else
if self.EngageRange then
if DetectedUnit:GetPointVec3():Get2DDistance(Controllable:GetPointVec3() ) <= self.EngageRange then
self:F( {"Within Range and Engaging", DetectedUnit } )
@@ -506,12 +491,12 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
AttackTasks[#AttackTasks+1] = Controllable:TaskFunction( "AI_CAP_ZONE.EngageRoute", self )
EngageRoute[1].task = Controllable:TaskCombo( AttackTasks )
self:SetDetectionDeactivated()
end
Controllable:Route( EngageRoute, 0.5 )
end
end

View File

@@ -1,4 +1,4 @@
--- **AI** -- Perform Close Air Support (CAS) near friendlies.
--- **AI** - Perform Close Air Support (CAS) near friendlies.
--
-- **Features:**
--
@@ -28,16 +28,16 @@
--
-- ===
--
-- @module AI.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 @{Wrapper.Controllable} patrolling.
-- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed.
-- @field Core.Zone#ZONE_BASE TargetZone The @{Core.Zone} where the patrol needs to be executed.
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
--- Implements the core functions to provide Close Air Support in an Engage @{Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
--- Implements the core functions to provide Close Air Support in an Engage @{Core.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)
@@ -130,7 +130,7 @@ 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 Core.Zone#ZONE_BASE PatrolZone The @{Core.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.Controllable} in km/h.
@@ -496,7 +496,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
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.
--- Define a random point in the @{Core.Zone}. The AI will fly to that point within the zone.
--- Find a random 2D point in EngageZone.
local ToTargetVec2 = self.EngageZone:GetRandomVec2()

View File

@@ -1,4 +1,4 @@
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo using Planes.
--- **AI** - Models the intelligent transportation of infantry and other cargo using Planes.
--
-- ## Features:
--

View File

@@ -1,4 +1,4 @@
--- **AI** -- (2.4) - Models the intelligent transportation of infantry and other cargo using Helicopters.
--- **AI** - Models the intelligent transportation of infantry and other cargo using Helicopters.
--
-- ## Features:
--

View File

@@ -1,4 +1,4 @@
--- **AI** -- (2.5.1) - Models the intelligent transportation of infantry and other cargo using Ships
--- **AI** - Models the intelligent transportation of infantry and other cargo using Ships.
--
-- ## Features:
--
@@ -37,14 +37,14 @@
--
-- This will be particularly helpful in order to determine how to **Tailor the different cargo handling events**.
--
-- The AI_CARGO_DISPATCHER_SHIP class uses the @{Cargo.Cargo} capabilities within the MOOSE framwork.
-- The AI_CARGO_DISPATCHER_SHIP 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 generally be declared within the mission to make the AI_CARGO_DISPATCHER_SHIP object recognize the cargo.
--
--
-- # 1) AI_CARGO_DISPATCHER_SHIP constructor.
--
-- * @{AI_CARGO_DISPATCHER_SHIP.New}(): Creates a new AI_CARGO_DISPATCHER_SHIP object.
-- * @{#AI_CARGO_DISPATCHER_SHIP.New}(): Creates a new AI_CARGO_DISPATCHER_SHIP object.
--
-- ---
--

View File

@@ -1,4 +1,4 @@
--- **AI** -- (R2.5.1) - Models the intelligent transportation of infantry and other cargo.
--- **AI** - Models the intelligent transportation of infantry and other cargo.
--
-- ===
--
@@ -46,12 +46,12 @@
--
-- ## Cargo deployment.
--
-- Using the @{AI_CARGO_SHIP.Deploy}() method, you are able to direct the Ship towards a Deploy zone to unboard/unload the cargo at the
-- Using the @{#AI_CARGO_SHIP.Deploy}() method, you are able to direct the Ship towards a Deploy zone to unboard/unload the cargo at the
-- specified coordinate. The Ship will follow the Shipping Lane to ensure consistent cargo transportation within the simulation environment.
--
-- ## Cargo pickup.
--
-- Using the @{AI_CARGO_SHIP.Pickup}() method, you are able to direct the Ship towards a Pickup zone to board/load the cargo at the specified
-- Using the @{#AI_CARGO_SHIP.Pickup}() method, you are able to direct the Ship towards a Pickup zone to board/load the cargo at the specified
-- coordinate. The Ship will follow the Shipping Lane to ensure consistent cargo transportation within the simulation environment.
--
--

View File

@@ -1,4 +1,4 @@
--- **Functional** -- Taking the lead of AI escorting your flight or of other AI.
--- **AI** - Taking the lead of AI escorting your flight or of other AI.
--
-- ===
--

View File

@@ -11,7 +11,7 @@
--
-- ===
--
-- @module AI.AI_ESCORT_DISPATCHER_REQUEST
-- @module AI.AI_Escort_Dispatcher_Request
-- @image MOOSE.JPG

View File

@@ -1,4 +1,4 @@
--- **Functional** -- Taking the lead of AI escorting your flight or of other AI, upon request using the menu.
--- **AI** - Taking the lead of AI escorting your flight or of other AI, upon request using the menu.
--
-- ===
--
@@ -143,7 +143,7 @@
--
-- ===
--
-- @module AI.AI_Escort
-- @module AI.AI_Escort_Request
-- @image Escorting.JPG

View File

@@ -1,4 +1,4 @@
--- **AI** -- Build large airborne formations of aircraft.
--- **AI** - Build large airborne formations of aircraft.
--
-- **Features:**
--
@@ -41,7 +41,7 @@
--- 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.
-- AI_FORMATION makes AI @{Wrapper.Group#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:
--

View File

@@ -1,4 +1,4 @@
--- **AI** -- Perform Air Patrolling for airplanes.
--- **AI** - Perform Air Patrolling for airplanes.
--
-- **Features:**
--
@@ -38,7 +38,7 @@
--- AI_PATROL_ZONE class
-- @type AI_PATROL_ZONE
-- @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 Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
-- @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.
@@ -46,7 +46,7 @@
-- @field Core.Spawn#SPAWN CoordTest
-- @extends Core.Fsm#FSM_CONTROLLABLE
--- Implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}.
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}.
--
-- ![Process](..\Presentations\AI_PATROL\Dia3.JPG)
--
@@ -135,15 +135,15 @@
-- 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 threshold is calculated.
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit,
-- while a new AI is targetted to the AI_PATROL_ZONE.
-- while a new AI is targeted to the AI_PATROL_ZONE.
-- Once the time is finished, the old AI will return to the base.
-- Use the method @{#AI_PATROL_ZONE.ManageFuel}() to have this proces in place.
-- Use the method @{#AI_PATROL_ZONE.ManageFuel}() to have this process in place.
--
-- ## 7. Manage "damage" behaviour of the AI in the AI_PATROL_ZONE
--
-- When the AI is damaged, it is required that a new AIControllable is started. However, damage cannon be foreseen early on.
-- Therefore, when the damage threshold is reached, the AI will return immediately to the home base (RTB).
-- Use the method @{#AI_PATROL_ZONE.ManageDamage}() to have this proces in place.
-- Use the method @{#AI_PATROL_ZONE.ManageDamage}() to have this process in place.
--
-- ===
--
@@ -154,7 +154,7 @@ 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 Core.Zone#ZONE_BASE PatrolZone The @{Core.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.Controllable} in km/h.
@@ -170,27 +170,27 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
-- Inherits from BASE
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_PATROL_ZONE
self.PatrolZone = PatrolZone
self.PatrolFloorAltitude = PatrolFloorAltitude
self.PatrolCeilingAltitude = PatrolCeilingAltitude
self.PatrolMinSpeed = PatrolMinSpeed
self.PatrolMaxSpeed = PatrolMaxSpeed
-- defafult PatrolAltType to "BARO" if not specified
self.PatrolAltType = PatrolAltType or "BARO"
self:SetRefreshTimeInterval( 30 )
self.CheckStatus = true
self:ManageFuel( .2, 60 )
self:ManageDamage( 1 )
self.DetectedUnits = {} -- This table contains the targets detected during patrol.
self:SetStartState( "None" )
self:AddTransition( "*", "Stop", "Stopped" )
@@ -228,7 +228,7 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
-- @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_PATROL_ZONE] Stop
-- @param #AI_PATROL_ZONE self
@@ -256,7 +256,7 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
-- @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 Start.
-- @function [parent=#AI_PATROL_ZONE] Start
-- @param #AI_PATROL_ZONE self
@@ -329,7 +329,7 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
-- @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_PATROL_ZONE] Status
-- @param #AI_PATROL_ZONE self
@@ -413,7 +413,7 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
-- @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_PATROL_ZONE] RTB
-- @param #AI_PATROL_ZONE self
@@ -441,11 +441,11 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
-- @param #string To The To State string.
self:AddTransition( "*", "Reset", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROL_ZONE.
self:AddTransition( "*", "Eject", "*" )
self:AddTransition( "*", "Crash", "Crashed" )
self:AddTransition( "*", "PilotDead", "*" )
return self
end
@@ -459,7 +459,7 @@ end
-- @return #AI_PATROL_ZONE self
function AI_PATROL_ZONE:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
self.PatrolMinSpeed = PatrolMinSpeed
self.PatrolMaxSpeed = PatrolMaxSpeed
end
@@ -473,7 +473,7 @@ end
-- @return #AI_PATROL_ZONE self
function AI_PATROL_ZONE:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } )
self.PatrolFloorAltitude = PatrolFloorAltitude
self.PatrolCeilingAltitude = PatrolCeilingAltitude
end
@@ -582,7 +582,7 @@ 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 threshold is calculated.
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_PATROL_ZONE.
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targeted 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 PatrolFuelThresholdPercentage The threshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
@@ -592,7 +592,7 @@ function AI_PATROL_ZONE:ManageFuel( PatrolFuelThresholdPercentage, PatrolOutOfFu
self.PatrolFuelThresholdPercentage = PatrolFuelThresholdPercentage
self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime
return self
end
@@ -609,28 +609,28 @@ function AI_PATROL_ZONE:ManageDamage( PatrolDamageThreshold )
self.PatrolManageDamage = true
self.PatrolDamageThreshold = PatrolDamageThreshold
return self
end
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
--- Defines a new patrol route using the @{#AI_PATROL_ZONE} parameters and settings.
-- @param #AI_PATROL_ZONE self
-- @return #AI_PATROL_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @return #AI_PATROL_ZONE self
function AI_PATROL_ZONE:onafterStart( Controllable, From, Event, To )
self:F2()
self:__Route( 1 ) -- Route to the patrol point. The asynchronous trigger is important, because a spawned group and units takes at least one second to come live.
self:__Status( 60 ) -- Check status status every 30 seconds.
self:SetDetectionActivated()
self:HandleEvent( EVENTS.PilotDead, self.OnPilotDead )
self:HandleEvent( EVENTS.Crash, self.OnCrash )
self:HandleEvent( EVENTS.Ejection, self.OnEjection )
Controllable:OptionROEHoldFire()
Controllable:OptionROTVertical()
@@ -667,12 +667,12 @@ function AI_PATROL_ZONE:onafterDetect( Controllable, From, Event, To )
if TargetObject and TargetObject:isExist() and TargetObject.id_ < 50000000 then
local TargetUnit = UNIT:Find( TargetObject )
-- Check that target is alive due to issue https://github.com/FlightControl-Master/MOOSE/issues/1234
if TargetUnit and TargetUnit:IsAlive() then
local TargetUnitName = TargetUnit:GetName()
if self.DetectionZone then
if TargetUnit:IsInZone( self.DetectionZone ) then
self:T( {"Detected ", TargetUnit } )
@@ -687,13 +687,13 @@ function AI_PATROL_ZONE:onafterDetect( Controllable, From, Event, To )
end
Detected = true
end
end
end
end
self:__Detect( -self.DetectInterval )
if Detected == true then
self:__Detected( 1.5 )
end
@@ -701,7 +701,7 @@ function AI_PATROL_ZONE:onafterDetect( Controllable, From, Event, To )
end
--- @param Wrapper.Controllable#CONTROLLABLE AIControllable
-- This statis method is called from the route path within the last task at the last waaypoint of the Controllable.
-- This static method is called from the route path within the last task at the last waypoint of the Controllable.
-- Note that this method is required, as triggers the next route when patrolling for the Controllable.
function AI_PATROL_ZONE:_NewPatrolRoute( AIControllable )
@@ -710,7 +710,7 @@ function AI_PATROL_ZONE:_NewPatrolRoute( AIControllable )
end
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
--- Defines a new patrol route using the @{#AI_PATROL_ZONE} parameters and settings.
-- @param #AI_PATROL_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
@@ -729,7 +729,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
if self.Controllable:IsAlive() and life > 1 then
-- Determine if the AIControllable is within the PatrolZone.
-- If not, make a waypoint within the to that the AIControllable will fly at maximum speed to that point.
local PatrolRoute = {}
-- Calculate the current route point of the controllable as the start point of the route.
@@ -775,7 +775,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
end
--- Define a random point in the @{Zone}. The AI will fly to that point within the zone.
--- Define a random point in the @{Core.Zone}. The AI will fly to that point within the zone.
--- Find a random 2D point in PatrolZone.
local ToTargetVec2 = self.PatrolZone:GetRandomVec2()

View File

@@ -1,10 +1,10 @@
--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occuring on @{Wrapper.Unit}s.
--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occurring on UNITs.
--
-- ![Banner Image](..\Presentations\ACT_ACCOUNT\Dia1.JPG)
--
-- ===
--
-- @module Actions.Account
-- @module Actions.Act_Account
-- @image MOOSE.JPG
do -- ACT_ACCOUNT
@@ -20,7 +20,7 @@ do -- ACT_ACCOUNT
--
-- ### ACT_ACCOUNT States
--
-- * **Asigned**: The player is assigned.
-- * **Assigned**: The player is assigned.
-- * **Waiting**: Waiting for an event.
-- * **Report**: Reporting.
-- * **Account**: Account for an event.
@@ -104,7 +104,6 @@ do -- ACT_ACCOUNT
self:__Wait( 1 )
end
--- StateMachine callback function
-- @param #ACT_ACCOUNT self
-- @param Wrapper.Unit#UNIT ProcessUnit
@@ -141,7 +140,7 @@ do -- ACT_ACCOUNT_DEADS
--- # @{#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.
-- The process is given a @{Core.Set} of units that will be tracked upon successful destruction.
-- The process will end after each target has been successfully destroyed.
-- Each successful dead will trigger an Account state transition that can be scored, modified or administered.
--
@@ -157,7 +156,6 @@ do -- ACT_ACCOUNT_DEADS
ClassName = "ACT_ACCOUNT_DEADS",
}
--- Creates a new DESTROY process.
-- @param #ACT_ACCOUNT_DEADS self
-- @param Core.Set#SET_UNIT TargetSetUnit
@@ -195,7 +193,6 @@ do -- ACT_ACCOUNT_DEADS
self:GetCommandCenter():MessageTypeToGroup( MessageText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
end
--- StateMachine callback function
-- @param #ACT_ACCOUNT_DEADS self
-- @param Wrapper.Unit#UNIT ProcessUnit
@@ -270,7 +267,6 @@ do -- ACT_ACCOUNT_DEADS
end
end
--- DCS Events
--- @param #ACT_ACCOUNT_DEADS self

View File

@@ -77,7 +77,7 @@
--
-- ===
--
-- @module Actions.Assign
-- @module Actions.Act_Assign
-- @image MOOSE.JPG

View File

@@ -50,7 +50,7 @@
--
-- # 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 ACT_ASSIST_SMOKE_TARGETS_ZONE class implements the core functions to smoke targets in a @{Core.Zone}.
-- The targets are smoked within a certain range around each target, simulating a realistic smoking behaviour.
-- At random intervals, a new target is smoked.
--
@@ -60,7 +60,7 @@
--
-- ===
--
-- @module Actions.Assist
-- @module Actions.Act_Assist
-- @image MOOSE.JPG

View File

@@ -62,7 +62,7 @@
--
-- # 1) @{#ACT_ROUTE_ZONE} class, extends @{Core.Fsm.Route#ACT_ROUTE}
--
-- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Wrapper.Controllable} player @{Wrapper.Unit} to a @{Zone}.
-- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Wrapper.Controllable} player @{Wrapper.Unit} to a @{Core.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,7 @@
--
-- ===
--
-- @module Actions.Route
-- @module Actions.Act_Route
-- @image MOOSE.JPG

View File

@@ -66,7 +66,7 @@
-- you can board the cargo into the carrier `CargoCarrier`.
-- Simple, isn't it? Told you, and this is only the beginning.
--
-- The boarding, unboarding, loading, unloading of cargo is however something that is not meant to be coded manualy by mission designers.
-- The boarding, unboarding, loading, unloading of cargo is however something that is not meant to be coded manually by mission designers.
-- It would be too low-level and not end-user friendly to deal with cargo handling complexity.
-- Things can become really complex if you want to make cargo being handled and behave in multiple scenarios.
--
@@ -77,8 +77,8 @@
--
-- ## 3.1) AI Cargo handlers.
--
-- - @{AI.AI_Cargo_APC} will create for you the capatility to make an APC group handle cargo.
-- - @{AI.AI_Cargo_Helicopter} will create for you the capatility to make a Helicopter group handle cargo.
-- - @{AI.AI_Cargo_APC} will create for you the capability to make an APC group handle cargo.
-- - @{AI.AI_Cargo_Helicopter} will create for you the capability to make a Helicopter group handle cargo.
--
--
-- ## 3.2) AI Cargo transportation dispatchers.
@@ -86,7 +86,7 @@
-- There are also dispatchers that make AI work together to transport cargo automatically!!!
--
-- - @{AI.AI_Cargo_Dispatcher_APC} derived classes will create for your dynamic cargo handlers controlled by AI ground vehicle groups (APCs) to transport cargo between sites.
-- - @{AI.AI_Cargo_Dispatcher_Helicopters} derived classes will create for your dynamic cargo handlers controlled by AI helicpter groups to transport cargo between sites.
-- - @{AI.AI_Cargo_Dispatcher_Helicopters} derived classes will create for your dynamic cargo handlers controlled by AI helicopter groups to transport cargo between sites.
--
-- ## 3.3) Cargo transportation tasking.
--
@@ -94,7 +94,7 @@
--
-- - @{Tasking.Task_CARGO} derived classes will create for you cargo transportation tasks, that allow human players to interact with MOOSE cargo objects to complete tasks.
--
-- Please refer to the documentation reflected within these modules to understand the detailed capabilties.
-- Please refer to the documentation reflected within these modules to understand the detailed capabilities.
--
-- # 4) Cargo SETs.
--
@@ -228,7 +228,7 @@
-- `StaticName #CARGO(T=CargoTypeName,C=Category,RR=Range,NR=Range)`
--
-- * **T=** Provide a text that contains the type name of the cargo object. This type name can be used to filter cargo within a SET_CARGO object.
-- * **C=** Provide either `CRATE` or `SLING` to have this static created as a CARGO_CRATE or CARGO_SLINGLOAD respectivly.
-- * **C=** Provide either `CRATE` or `SLING` to have this static created as a CARGO_CRATE or CARGO_SLINGLOAD respectively.
-- * **RR=** Provide the minimal range in meters when the report to the carrier, and board to the carrier.
-- Note that this option is optional, so can be omitted. The default value of the RR is 250 meters.
-- * **NR=** Provide the maximum range in meters when the cargo units will be boarded within the carrier during boarding.
@@ -377,7 +377,7 @@ do -- CARGO
-- @field #boolean Moveable This flag defines if the cargo is moveable.
-- @field #boolean Representable This flag defines if the cargo can be represented by a DCS Unit.
-- @field #boolean Containable This flag defines if the cargo can be contained within a DCS Unit.
--- Defines the core functions that defines a cargo object within MOOSE.
--
-- A cargo is a **logical object** defined that is available for transport, and has a life status within a simulation.
@@ -430,8 +430,7 @@ do -- CARGO
--- @type CARGO.CargoObjects
-- @map < #string, Wrapper.Positionable#POSITIONABLE > The alive POSITIONABLE objects representing the the cargo.
--- CARGO Constructor. This class is an abstract class and should not be instantiated.
-- @param #CARGO self
-- @param #string Type
@@ -441,10 +440,10 @@ do -- CARGO
-- @param #number NearRadius (optional)
-- @return #CARGO
function CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) --R2.1
local self = BASE:Inherit( self, FSM:New() ) -- #CARGO
self:F( { Type, Name, Weight, LoadRadius, NearRadius } )
self:SetStartState( "UnLoaded" )
self:AddTransition( { "UnLoaded", "Boarding" }, "Board", "Boarding" )
self:AddTransition( "Boarding" , "Boarding", "Boarding" )
@@ -459,7 +458,7 @@ do -- CARGO
self:AddTransition( "*", "Destroyed", "Destroyed" )
self:AddTransition( "*", "Respawn", "UnLoaded" )
self:AddTransition( "*", "Reset", "UnLoaded" )
self.Type = Type
self.Name = Name
self.Weight = Weight or 0
@@ -471,31 +470,29 @@ do -- CARGO
self.Containable = false
self.CargoLimit = 0
self.LoadRadius = LoadRadius or 500
--self.NearRadius = NearRadius or 25
self:SetDeployed( false )
self.CargoScheduler = SCHEDULER:New()
CARGOS[self.Name] = self
return self
end
--- Find a CARGO in the _DATABASE.
-- @param #CARGO self
-- @param #string CargoName The Cargo Name.
-- @return #CARGO self
function CARGO:FindByName( CargoName )
local CargoFound = _DATABASE:FindCargo( CargoName )
return CargoFound
end
--- Get the x position of the cargo.
-- @param #CARGO self
-- @return #number
@@ -504,9 +501,9 @@ do -- CARGO
return self.CargoCarrier:GetCoordinate().x
else
return self.CargoObject:GetCoordinate().x
end
end
end
--- Get the y position of the cargo.
-- @param #CARGO self
-- @return #number
@@ -515,9 +512,9 @@ do -- CARGO
return self.CargoCarrier:GetCoordinate().z
else
return self.CargoObject:GetCoordinate().z
end
end
end
--- Get the heading of the cargo.
-- @param #CARGO self
-- @return #number
@@ -526,22 +523,21 @@ do -- CARGO
return self.CargoCarrier:GetHeading()
else
return self.CargoObject:GetHeading()
end
end
end
--- Check if the cargo can be Slingloaded.
-- @param #CARGO self
function CARGO:CanSlingload()
return false
end
--- Check if the cargo can be Boarded.
-- @param #CARGO self
function CARGO:CanBoard()
return true
end
--- Check if the cargo can be Unboarded.
-- @param #CARGO self
function CARGO:CanUnboard()
@@ -553,14 +549,13 @@ do -- CARGO
function CARGO:CanLoad()
return true
end
--- Check if the cargo can be Unloaded.
-- @param #CARGO self
function CARGO:CanUnload()
return true
end
--- Destroy the cargo.
-- @param #CARGO self
function CARGO:Destroy()
@@ -569,14 +564,14 @@ do -- CARGO
end
self:Destroyed()
end
--- Get the name of the Cargo.
-- @param #CARGO self
-- @return #string The name of the Cargo.
function CARGO:GetName() --R2.1
return self.Name
end
--- Get the current active object representing or being the Cargo.
-- @param #CARGO self
-- @return Wrapper.Positionable#POSITIONABLE The object representing or being the Cargo.
@@ -585,9 +580,9 @@ do -- CARGO
return self.CargoCarrier
else
return self.CargoObject
end
end
end
--- Get the object name of the Cargo.
-- @param #CARGO self
-- @return #string The object name of the Cargo.
@@ -596,9 +591,9 @@ do -- CARGO
return self.CargoCarrier:GetName()
else
return self.CargoObject:GetName()
end
end
end
--- Get the amount of Cargo.
-- @param #CARGO self
-- @return #number The amount of Cargo.
@@ -613,7 +608,6 @@ do -- CARGO
return self.Type
end
--- Get the transportation method of the Cargo.
-- @param #CARGO self
-- @return #string The transportation method of the Cargo.
@@ -621,7 +615,6 @@ do -- CARGO
return self.TransportationMethod
end
--- Get the coalition of the Cargo.
-- @param #CARGO self
-- @return Coalition
@@ -630,32 +623,30 @@ do -- CARGO
return self.CargoCarrier:GetCoalition()
else
return self.CargoObject:GetCoalition()
end
end
end
--- Get the current coordinates of the Cargo.
-- @param #CARGO self
-- @return Core.Point#COORDINATE The coordinates of the Cargo.
function CARGO:GetCoordinate()
return self.CargoObject:GetCoordinate()
end
--- Check if cargo is destroyed.
-- @param #CARGO self
-- @return #boolean true if destroyed
function CARGO:IsDestroyed()
return self:Is( "Destroyed" )
end
--- Check if cargo is loaded.
-- @param #CARGO self
-- @return #boolean true if loaded
function CARGO:IsLoaded()
return self:Is( "Loaded" )
end
--- Check if cargo is loaded.
-- @param #CARGO self
-- @param Wrapper.Unit#UNIT Carrier
@@ -663,14 +654,14 @@ do -- CARGO
function CARGO:IsLoadedInCarrier( Carrier )
return self.CargoCarrier and self.CargoCarrier:GetName() == Carrier:GetName()
end
--- Check if cargo is unloaded.
-- @param #CARGO self
-- @return #boolean true if unloaded
function CARGO:IsUnLoaded()
return self:Is( "UnLoaded" )
end
--- Check if cargo is boarding.
-- @param #CARGO self
-- @return #boolean true if boarding
@@ -678,52 +669,47 @@ do -- CARGO
return self:Is( "Boarding" )
end
--- Check if cargo is unboarding.
-- @param #CARGO self
-- @return #boolean true if unboarding
function CARGO:IsUnboarding()
return self:Is( "UnBoarding" )
end
--- Check if cargo is alive.
-- @param #CARGO self
-- @return #boolean true if unloaded
function CARGO:IsAlive()
if self:IsLoaded() then
return self.CargoCarrier:IsAlive()
else
return self.CargoObject:IsAlive()
end
end
end
--- Set the cargo as deployed.
-- @param #CARGO self
-- @param #boolean Deployed true if the cargo is to be deployed. false or nil otherwise.
function CARGO:SetDeployed( Deployed )
self.Deployed = Deployed
end
--- Is the cargo deployed
-- @param #CARGO self
-- @return #boolean
function CARGO:IsDeployed()
return self.Deployed
end
--- Template method to spawn a new representation of the CARGO in the simulator.
-- @param #CARGO self
-- @return #CARGO
function CARGO:Spawn( PointVec2 )
self:F()
end
--- Signal a flare at the position of the CARGO.
-- @param #CARGO self
-- @param Utilities.Utils#FLARECOLOR FlareColor
@@ -732,31 +718,31 @@ do -- CARGO
trigger.action.signalFlare( self.CargoObject:GetVec3(), FlareColor , 0 )
end
end
--- Signal a white flare at the position of the CARGO.
-- @param #CARGO self
function CARGO:FlareWhite()
self:Flare( trigger.flareColor.White )
end
--- Signal a yellow flare at the position of the CARGO.
-- @param #CARGO self
function CARGO:FlareYellow()
self:Flare( trigger.flareColor.Yellow )
end
--- Signal a green flare at the position of the CARGO.
-- @param #CARGO self
function CARGO:FlareGreen()
self:Flare( trigger.flareColor.Green )
end
--- Signal a red flare at the position of the CARGO.
-- @param #CARGO self
function CARGO:FlareRed()
self:Flare( trigger.flareColor.Red )
end
--- Smoke the CARGO.
-- @param #CARGO self
-- @param Utilities.Utils#SMOKECOLOR SmokeColor The color of the smoke.
@@ -770,38 +756,37 @@ do -- CARGO
end
end
end
--- Smoke the CARGO Green.
-- @param #CARGO self
function CARGO:SmokeGreen()
self:Smoke( trigger.smokeColor.Green, Range )
end
--- Smoke the CARGO Red.
-- @param #CARGO self
function CARGO:SmokeRed()
self:Smoke( trigger.smokeColor.Red, Range )
end
--- Smoke the CARGO White.
-- @param #CARGO self
function CARGO:SmokeWhite()
self:Smoke( trigger.smokeColor.White, Range )
end
--- Smoke the CARGO Orange.
-- @param #CARGO self
function CARGO:SmokeOrange()
self:Smoke( trigger.smokeColor.Orange, Range )
end
--- Smoke the CARGO Blue.
-- @param #CARGO self
function CARGO:SmokeBlue()
self:Smoke( trigger.smokeColor.Blue, Range )
end
--- Set the Load radius, which is the radius till when the Cargo can be loaded.
-- @param #CARGO self
-- @param #number LoadRadius The radius till Cargo can be loaded.
@@ -809,23 +794,21 @@ do -- CARGO
function CARGO:SetLoadRadius( LoadRadius )
self.LoadRadius = LoadRadius or 150
end
--- Get the Load radius, which is the radius till when the Cargo can be loaded.
-- @param #CARGO self
-- @return #number The radius till Cargo can be loaded.
function CARGO:GetLoadRadius()
return self.LoadRadius
end
--- Check if Cargo is in the LoadRadius for the Cargo to be Boarded or Loaded.
-- @param #CARGO self
-- @param Core.Point#COORDINATE Coordinate
-- @return #boolean true if the CargoGroup is within the loading radius.
function CARGO:IsInLoadRadius( Coordinate )
self:F( { Coordinate, LoadRadius = self.LoadRadius } )
local Distance = 0
if self:IsUnLoaded() then
local CargoCoordinate = self.CargoObject:GetCoordinate()
@@ -835,18 +818,17 @@ do -- CARGO
return true
end
end
return false
end
--- Check if the Cargo can report itself to be Boarded or Loaded.
-- @param #CARGO self
-- @param Core.Point#COORDINATE Coordinate
-- @return #boolean true if the Cargo can report itself.
function CARGO:IsInReportRadius( Coordinate )
self:F( { Coordinate } )
local Distance = 0
if self:IsUnLoaded() then
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
@@ -855,7 +837,7 @@ do -- CARGO
return true
end
end
return false
end
@@ -867,7 +849,7 @@ do -- CARGO
-- @return #boolean
function CARGO:IsNear( Coordinate, NearRadius )
--self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } )
if self.CargoObject:IsAlive() then
--local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() )
--self:F( { CargoObjectName = self.CargoObject:GetName() } )
@@ -875,26 +857,24 @@ do -- CARGO
--self:F( { PointVec2 = PointVec2:GetVec2() } )
local Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
--self:F( { Distance = Distance, NearRadius = NearRadius or "nil" } )
if Distance <= NearRadius then
--self:F( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = true } )
return true
end
end
--self:F( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = false } )
return false
end
--- Check if Cargo is the given @{Zone}.
--- Check if Cargo is the given @{Core.Zone}.
-- @param #CARGO self
-- @param Core.Zone#ZONE_BASE Zone
-- @return #boolean **true** if cargo is in the Zone, **false** if cargo is not in the Zone.
function CARGO:IsInZone( Zone )
--self:F( { Zone } )
if self:IsLoaded() then
return Zone:IsPointVec2InZone( self.CargoCarrier:GetPointVec2() )
else
@@ -904,34 +884,33 @@ do -- CARGO
else
return false
end
end
end
return nil
end
--- Get the current PointVec2 of the cargo.
-- @param #CARGO self
-- @return Core.Point#POINT_VEC2
function CARGO:GetPointVec2()
return self.CargoObject:GetPointVec2()
end
--- Get the current Coordinate of the cargo.
-- @param #CARGO self
-- @return Core.Point#COORDINATE
function CARGO:GetCoordinate()
return self.CargoObject:GetCoordinate()
end
--- Get the weight of the cargo.
-- @param #CARGO self
-- @return #number Weight The weight in kg.
function CARGO:GetWeight()
return self.Weight
end
--- Set the weight of the cargo.
-- @param #CARGO self
-- @param #number Weight The weight in kg.
@@ -940,14 +919,14 @@ do -- CARGO
self.Weight = Weight
return self
end
--- Get the volume of the cargo.
-- @param #CARGO self
-- @return #number Volume The volume in kg.
function CARGO:GetVolume()
return self.Volume
end
--- Set the volume of the cargo.
-- @param #CARGO self
-- @param #number Volume The volume in kg.
@@ -956,18 +935,18 @@ do -- CARGO
self.Volume = Volume
return self
end
--- Send a CC message to a @{Wrapper.Group}.
-- @param #CARGO self
-- @param #string Message
-- @param Wrapper.Group#GROUP CarrierGroup The Carrier Group.
-- @param #string Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown.
function CARGO:MessageToGroup( Message, CarrierGroup, Name )
MESSAGE:New( Message, 20, "Cargo " .. self:GetName() ):ToGroup( CarrierGroup )
end
--- Report to a Carrier Group.
-- @param #CARGO self
-- @param #string Action The string describing the action for the cargo.
@@ -993,8 +972,7 @@ do -- CARGO
end
end
end
--- Report to a Carrier Group with a Flaring signal.
-- @param #CARGO self
-- @param Utils#UTILS.FlareColor FlareColor the color of the flare.
@@ -1003,8 +981,7 @@ do -- CARGO
self.ReportFlareColor = FlareColor
end
--- Report to a Carrier Group with a Smoking signal.
-- @param #CARGO self
-- @param Utils#UTILS.SmokeColor SmokeColor the color of the smoke.
@@ -1013,8 +990,7 @@ do -- CARGO
self.ReportSmokeColor = SmokeColor
end
--- Reset the reporting for a Carrier Group.
-- @param #CARGO self
-- @param #string Action The string describing the action for the cargo.
@@ -1024,7 +1000,7 @@ do -- CARGO
self.Reported[CarrierGroup][Action] = nil
end
--- Reset all the reporting for a Carrier Group.
-- @param #CARGO self
-- @param Wrapper.Group#GROUP CarrierGroup The Carrier Group to send the report to.
@@ -1033,7 +1009,7 @@ do -- CARGO
self.Reported[CarrierGroup] = nil
end
--- Respawn the cargo when destroyed
-- @param #CARGO self
-- @param #boolean RespawnDestroyed
@@ -1046,11 +1022,8 @@ do -- CARGO
else
self.onenterDestroyed = nil
end
end
end
end -- CARGO
@@ -1075,7 +1048,7 @@ do -- CARGO_REPRESENTABLE
-- @param #number NearRadius (optional) Radius in meters when the cargo is loaded into the carrier.
-- @return #CARGO_REPRESENTABLE
function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, LoadRadius, NearRadius )
-- Inherit CARGO.
local self = BASE:Inherit( self, CARGO:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE
self:F( { Type, Name, LoadRadius, NearRadius } )
@@ -1083,10 +1056,10 @@ do -- CARGO_REPRESENTABLE
-- Descriptors.
local Desc=CargoObject:GetDesc()
self:T({Desc=Desc})
-- Weight.
local Weight = math.random( 80, 120 )
-- Adjust weight..
if Desc then
if Desc.typeName == "2B11 mortar" then
@@ -1097,8 +1070,8 @@ do -- CARGO_REPRESENTABLE
end
-- Set weight.
self:SetWeight( Weight )
self:SetWeight( Weight )
return self
end
@@ -1106,14 +1079,14 @@ do -- CARGO_REPRESENTABLE
-- @param #CARGO_REPRESENTABLE self
-- @return #CARGO_REPRESENTABLE
function CARGO_REPRESENTABLE:Destroy()
-- Cargo objects are deleted from the _DATABASE and SET_CARGO objects.
self:F( { CargoName = self:GetName() } )
--_EVENTDISPATCHER:CreateEventDeleteCargo( self )
return self
end
--- Route a cargo unit to a PointVec2.
-- @param #CARGO_REPRESENTABLE self
-- @param Core.Point#POINT_VEC2 ToPointVec2
@@ -1121,19 +1094,19 @@ do -- CARGO_REPRESENTABLE
-- @return #CARGO_REPRESENTABLE
function CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed )
self:F2( ToPointVec2 )
local Points = {}
local PointStartVec2 = self.CargoObject:GetPointVec2()
Points[#Points+1] = PointStartVec2:WaypointGround( Speed )
Points[#Points+1] = ToPointVec2:WaypointGround( Speed )
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 2 )
return self
return self
end
--- Send a message to a @{Wrapper.Group} through a communication channel near the cargo.
-- @param #CARGO_REPRESENTABLE self
-- @param #string Message
@@ -1157,20 +1130,19 @@ do -- CARGO_REPRESENTABLE
end
end
end
end
end -- CARGO_REPRESENTABLE
do -- CARGO_REPORTABLE
--- @type CARGO_REPORTABLE
-- @extends #CARGO
CARGO_REPORTABLE = {
ClassName = "CARGO_REPORTABLE"
}
--- CARGO_REPORTABLE Constructor.
-- @param #CARGO_REPORTABLE self
-- @param #string Type
@@ -1182,31 +1154,23 @@ do -- CARGO_REPORTABLE
function CARGO_REPORTABLE:New( Type, Name, Weight, LoadRadius, NearRadius )
local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) ) -- #CARGO_REPORTABLE
self:F( { Type, Name, Weight, LoadRadius, NearRadius } )
return self
end
--- Send a CC message to a @{Wrapper.Group}.
-- @param #CARGO_REPORTABLE self
-- @param #string Message
-- @param Wrapper.Group#GROUP TaskGroup
-- @param #string Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown.
function CARGO_REPORTABLE:MessageToGroup( Message, TaskGroup, Name )
MESSAGE:New( Message, 20, "Cargo " .. self:GetName() .. " reporting" ):ToGroup( TaskGroup )
end
end
do -- CARGO_PACKAGE
--- @type CARGO_PACKAGE
@@ -1280,10 +1244,10 @@ function CARGO_PACKAGE:IsNear( CargoCarrier )
self:F()
local CargoCarrierPoint = CargoCarrier:GetCoordinate()
local Distance = CargoCarrierPoint:Get2DDistance( self.CargoCarrier:GetCoordinate() )
self:T( Distance )
if Distance <= self.NearRadius then
return true
else
@@ -1334,7 +1298,7 @@ function CARGO_PACKAGE:onafterUnBoard( From, Event, To, CargoCarrier, Speed, UnL
if not self.CargoInAir then
self:_Next( self.FsmP.UnLoad, UnLoadDistance, Angle )
local Points = {}
local StartPointVec2 = CargoCarrier:GetPointVec2()
@@ -1389,7 +1353,7 @@ function CARGO_PACKAGE:onafterLoad( From, Event, To, CargoCarrier, Speed, LoadDi
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployPointVec2 = StartPointVec2:Translate( LoadDistance, CargoDeployHeading )
local Points = {}
Points[#Points+1] = StartPointVec2:WaypointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed )
@@ -1410,12 +1374,12 @@ end
-- @param #number Angle
function CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Distance, Angle )
self:F()
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 CargoDeployPointVec2 = StartPointVec2:Translate( Distance, CargoDeployHeading )
self.CargoCarrier = CargoCarrier
local Points = {}
@@ -1427,5 +1391,4 @@ function CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Dist
end
end

View File

@@ -1,4 +1,4 @@
--- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object.
--- **Cargo** - Management of single cargo crates, which are based on a STATIC object.
--
-- ===
--

View File

@@ -1,4 +1,4 @@
--- **Cargo** - Management of grouped cargo logistics, which are based on a @{Wrapper.Group} object.
--- **Cargo** - Management of grouped cargo logistics, which are based on a GROUP object.
--
-- ===
--
@@ -47,7 +47,7 @@ do -- 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.
-- It will "ungroup" the group object within the sim, and will create a @{Core.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.
@@ -727,7 +727,7 @@ do -- CARGO_GROUP
end
end
--- Check if the first element of the CargoGroup is the given @{Zone}.
--- Check if the first element of the CargoGroup is the given @{Core.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

View File

@@ -1,4 +1,4 @@
--- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object. The cargo can only be slingloaded.
--- **Cargo** - Management of single cargo crates, which are based on a STATIC object. The cargo can only be slingloaded.
--
-- ===
--

View File

@@ -1,4 +1,4 @@
--- **Cargo** - Management of single cargo logistics, which are based on a @{Wrapper.Unit} object.
--- **Cargo** - Management of single cargo logistics, which are based on a UNIT object.
--
-- ===
--

View File

@@ -157,7 +157,7 @@ local _ClassID = 0
-- self:SmokeBlue()
-- end
--
-- See the @{Event} module for more information about event handling.
-- See the @{Core.Event} module for more information about event handling.
--
-- # 4. Class identification methods.
--
@@ -412,20 +412,20 @@ do -- Event Handling
return _EVENTDISPATCHER
end
--- Get the Class @{Event} processing Priority.
--- Get the Class @{Core.Event} processing Priority.
-- The Event processing Priority is a number from 1 to 10,
-- reflecting the order of the classes subscribed to the Event to be processed.
-- @param #BASE self
-- @return #number The @{Event} processing Priority.
-- @return #number The @{Core.Event} processing Priority.
function BASE:GetEventPriority()
return self._.EventPriority or 5
end
--- Set the Class @{Event} processing Priority.
--- Set the Class @{Core.Event} processing Priority.
-- The Event processing Priority is a number from 1 to 10,
-- reflecting the order of the classes subscribed to the Event to be processed.
-- @param #BASE self
-- @param #number EventPriority The @{Event} processing Priority.
-- @param #number EventPriority The @{Core.Event} processing Priority.
-- @return #BASE self
function BASE:SetEventPriority( EventPriority )
self._.EventPriority = EventPriority
@@ -464,16 +464,16 @@ do -- Event Handling
return self
end
-- Event handling function prototypes - Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Event handling function prototypes - Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
--- Occurs whenever any unit in a mission fires a weapon. But not any machine gun or autocannon based weapon, those are handled by EVENT.ShootingStart.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- @function [parent=#BASE] OnEventShot
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs whenever an object is hit by a weapon.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit object the fired the weapon
-- weapon: Weapon object that hit the target
-- target: The Object that was hit.
@@ -482,7 +482,7 @@ do -- Event Handling
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when an aircraft takes off from an airbase, farp, or ship.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that tookoff
-- place: Object from where the AI took-off from. Can be an Airbase Object, FARP, or Ships
-- @function [parent=#BASE] OnEventTakeoff
@@ -490,7 +490,7 @@ do -- Event Handling
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when an aircraft lands at an airbase, farp or ship
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that has landed
-- place: Object that the unit landed on. Can be an Airbase Object, FARP, or Ships
-- @function [parent=#BASE] OnEventLand
@@ -498,49 +498,49 @@ do -- Event Handling
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when any aircraft crashes into the ground and is completely destroyed.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that has crashed
-- @function [parent=#BASE] OnEventCrash
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a pilot ejects from an aircraft
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that has ejected
-- @function [parent=#BASE] OnEventEjection
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when an aircraft connects with a tanker and begins taking on fuel.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that is receiving fuel.
-- @function [parent=#BASE] OnEventRefueling
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when an object is dead.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that is dead.
-- @function [parent=#BASE] OnEventDead
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when an Event for an object is triggered.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that triggered the event.
-- @function [parent=#BASE] OnEvent
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when the pilot of an aircraft is killed. Can occur either if the player is alive and crashes or if a weapon kills the pilot without completely destroying the plane.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that the pilot has died in.
-- @function [parent=#BASE] OnEventPilotDead
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a ground unit captures either an airbase or a farp.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that captured the base
-- place: The airbase that was captured, can be a FARP or Airbase. When calling place:getCoalition() the faction will already be the new owning faction.
-- @function [parent=#BASE] OnEventBaseCaptured
@@ -548,68 +548,68 @@ do -- Event Handling
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a mission starts
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- @function [parent=#BASE] OnEventMissionStart
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a mission ends
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- @function [parent=#BASE] OnEventMissionEnd
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when an aircraft is finished taking fuel.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that was receiving fuel.
-- @function [parent=#BASE] OnEventRefuelingStop
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when any object is spawned into the mission.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that was spawned
-- @function [parent=#BASE] OnEventBirth
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when any system fails on a human controlled aircraft.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that had the failure
-- @function [parent=#BASE] OnEventHumanFailure
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when any aircraft starts its engines.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that is starting its engines.
-- @function [parent=#BASE] OnEventEngineStartup
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when any aircraft shuts down its engines.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that is stopping its engines.
-- @function [parent=#BASE] OnEventEngineShutdown
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when any player assumes direct control of a unit. Note - not Mulitplayer safe. Use PlayerEnterAircraft.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that is being taken control of.
-- @function [parent=#BASE] OnEventPlayerEnterUnit
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when any player relieves control of a unit to the AI.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that the player left.
-- @function [parent=#BASE] OnEventPlayerLeaveUnit
-- @param #BASE self
-- @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.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- initiator : The unit that is doing the shooting.
-- target: The unit that is being targeted.
-- @function [parent=#BASE] OnEventShootingStart
@@ -617,28 +617,28 @@ do -- Event Handling
-- @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.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- 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.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- 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.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- 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.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- MarkID: ID of the mark.
-- @function [parent=#BASE] OnEventMarkChange
-- @param #BASE self
@@ -654,13 +654,13 @@ do -- Event Handling
--- Occurs when any modification to the "Score" as seen on the debrief menu would occur.
-- There is no information on what values the score was changed to. Event is likely similar to player_comment in this regard.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- @function [parent=#BASE] OnEventScore
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs on the death of a unit. Contains more and different information. Similar to unit_lost it will occur for aircraft before the aircraft crash event occurs.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
--
-- * initiator: The unit that killed the target
-- * target: Target Object
@@ -672,13 +672,13 @@ do -- Event Handling
--- Occurs when any modification to the "Score" as seen on the debrief menu would occur.
-- There is no information on what values the score was changed to. Event is likely similar to player_comment in this regard.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- @function [parent=#BASE] OnEventScore
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when the game thinks an object is destroyed.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
--
-- * initiator: The unit that is was destroyed.
--
@@ -687,7 +687,7 @@ do -- Event Handling
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs shortly after the landing animation of an ejected pilot touching the ground and standing up. Event does not occur if the pilot lands in the water and sub combs to Davey Jones Locker.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
--
-- * initiator: Static object representing the ejected pilot. Place : Aircraft that the pilot ejected from.
-- * place: may not return as a valid object if the aircraft has crashed into the ground and no longer exists.
@@ -698,43 +698,43 @@ do -- Event Handling
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Paratrooper landing.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- @function [parent=#BASE] OnEventParatrooperLanding
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Discard chair after ejection.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- @function [parent=#BASE] OnEventDiscardChairAfterEjection
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Weapon add. Fires when entering a mission per pylon with the name of the weapon (double pylons not counted, infinite wep reload not counted.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- @function [parent=#BASE] OnEventParatrooperLanding
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Trigger zone.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- @function [parent=#BASE] OnEventTriggerZone
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Landing quality mark.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- @function [parent=#BASE] OnEventLandingQualityMark
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- BDA.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- @function [parent=#BASE] OnEventBDA
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a player enters a slot and takes control of an aircraft.
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
-- **NOTE**: This is a workaround of a long standing DCS bug with the PLAYER_ENTER_UNIT event.
-- initiator : The unit that is being taken control of.
-- @function [parent=#BASE] OnEventPlayerEnterAircraft

View File

@@ -17,8 +17,8 @@
--
-- 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 (aircraft) 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.
-- Note that in both case, you can set an optional parameter : the `BeaconDuration`. This can be very useful to simulate the battery time if your BEACON is
-- attach to a cargo crate, for example.
--
-- ## Aircraft TACAN Beacon usage
--
@@ -33,7 +33,7 @@
--
-- @type BEACON
-- @field #string ClassName Name of the class "BEACON".
-- @field Wrapper.Controllable#CONTROLLABLE Positionable The @{#CONTROLLABLE} that will receive radio capabilities.
-- @field Wrapper.Controllable#CONTROLLABLE Positionable The @{Wrapper.Controllable#CONTROLLABLE} that will receive radio capabilities.
-- @extends Core.Base#BASE
BEACON = {
ClassName = "BEACON",
@@ -72,12 +72,12 @@ BEACON.Type={
TACAN = 4,
VORTAC = 5,
RSBN = 128,
BROADCAST_STATION = 1024,
BROADCAST_STATION = 1024,
HOMER = 8,
AIRPORT_HOMER = 4104,
AIRPORT_HOMER_WITH_MARKER = 4136,
AIRPORT_HOMER = 4104,
AIRPORT_HOMER_WITH_MARKER = 4136,
ILS_FAR_HOMER = 16408,
ILS_NEAR_HOMER = 16424,
ILS_NEAR_HOMER = 16424,
ILS_LOCALIZER = 16640,
ILS_GLIDESLOPE = 16896,
PRMG_LOCALIZER = 33024,
@@ -108,13 +108,13 @@ BEACON.Type={
-- @field #number ICLS_LOCALIZER Carrier landing system.
-- @field #number ICLS_GLIDESLOPE Carrier landing system.
BEACON.System={
PAR_10 = 1,
RSBN_5 = 2,
TACAN = 3,
PAR_10 = 1,
RSBN_5 = 2,
TACAN = 3,
TACAN_TANKER_X = 4,
TACAN_TANKER_Y = 5,
VOR = 6,
ILS_LOCALIZER = 7,
VOR = 6,
ILS_LOCALIZER = 7,
ILS_GLIDESLOPE = 8,
PRMG_LOCALIZER = 9,
PRMG_GLIDESLOPE = 10,
@@ -130,16 +130,16 @@ BEACON.System={
--- 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.
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Wrapper.Positionable} that will receive radio capabilities.
-- @return #BEACON Beacon object or #nil if the positionable is invalid.
function BEACON:New(Positionable)
-- 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
@@ -147,12 +147,11 @@ function BEACON:New(Positionable)
self:I(string.format("New BEACON %s", tostring(self.name)))
return self
end
self:E({"The passed positionable is invalid, no BEACON created", Positionable})
return nil
end
--- Activates a TACAN BEACON.
-- @param #BEACON self
-- @param #number Channel TACAN channel, i.e. the "10" part in "10Y".
@@ -169,28 +168,28 @@ end
-- 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})
Mode=Mode or "Y"
-- 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
-- Beacon type.
local Type=BEACON.Type.TACAN
-- Beacon system.
local System=BEACON.System.TACAN
-- 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.
@@ -201,21 +200,21 @@ function BEACON:ActivateTACAN(Channel, Mode, Message, Bearing, Duration)
System=BEACON.System.TACAN_TANKER_Y
end
end
-- 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 scheduler.
if Duration then
self.Positionable:DeactivateBeacon(Duration)
end
return self
end
@@ -227,21 +226,21 @@ end
-- @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 scheduler
if Duration then -- Schedule the stop of the BEACON if asked by the MD
self.Positionable:DeactivateBeacon(Duration)
end
return self
end
@@ -253,25 +252,25 @@ end
-- @return #BEACON self
function BEACON:ActivateLink4(Frequency, Morse, Duration)
self:F({Frequency=Frequency, Morse=Morse, Duration=Duration})
-- Attached unit.
local UnitID=self.Positionable:GetID()
-- Debug
self:T2({"LINK4 BEACON started!"})
-- Start beacon.
self.Positionable:CommandActivateLink4(Frequency,UnitID,Morse)
-- Stop sheduler
if Duration then -- Schedule the stop of the BEACON if asked by the MD
self.Positionable:CommandDeactivateLink4(Duration)
end
return self
end
--- DEPRECATED: Please use @{BEACON:ActivateTACAN}() instead.
--- DEPRECATED: Please use @{#BEACON.ActivateTACAN}() instead.
-- Activates a TACAN BEACON on an Aircraft.
-- @param #BEACON self
-- @param #number TACANChannel (the "10" part in "10Y"). Note that AA TACAN are only available on Y Channels
@@ -287,20 +286,20 @@ end
-- myBeacon:AATACAN(20, "TEXACO", true) -- Activate the beacon
function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
self:F({TACANChannel, Message, Bearing, BeaconDuration})
local IsValid = true
if not self.Positionable:IsAir() then
self:E({"The POSITIONABLE you want to attach the AA Tacan Beacon is not an aircraft ! The BEACON is not emitting", self.Positionable})
IsValid = false
end
local Frequency = self:_TACANToFrequency(TACANChannel, "Y")
if not Frequency then
self:E({"The passed TACAN channel is invalid, the BEACON is not emitting"})
IsValid = false
end
-- I'm using the beacon type 4 (BEACON_TYPE_TACAN). For System, I'm using 5 (TACAN_TANKER_MODE_Y) if the bearing shows its bearing or 14 (TACAN_AA_MODE_Y) if it does not
local System
if Bearing then
@@ -308,7 +307,7 @@ function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
else
System = BEACON.System.TACAN_AA_MODE_Y
end
if IsValid then -- Starts the BEACON
self:T2({"AA TACAN BEACON started !"})
self.Positionable:SetCommand({
@@ -323,7 +322,7 @@ function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
modeChannel = "Y",
}
})
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
SCHEDULER:New(nil,
function()
@@ -331,7 +330,7 @@ function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
end, {}, BeaconDuration)
end
end
return self
end
@@ -351,7 +350,6 @@ function BEACON:StopAATACAN()
end
end
--- Activates a general purpose Radio Beacon
-- This uses the very generic singleton function "trigger.action.radioTransmission()" provided by DCS to broadcast a sound file on a specific frequency.
-- Although any frequency could be used, only a few DCS Modules can home on radio beacons at the time of writing, i.e. the Mi-8, Huey, Gazelle etc.
@@ -381,7 +379,7 @@ end
function BEACON:RadioBeacon(FileName, Frequency, Modulation, Power, BeaconDuration)
self:F({FileName, Frequency, Modulation, Power, BeaconDuration})
local IsValid = false
-- Check the filename
if type(FileName) == "string" then
if FileName:find(".ogg") or FileName:find(".wav") then
@@ -394,32 +392,32 @@ function BEACON:RadioBeacon(FileName, Frequency, Modulation, Power, BeaconDurati
if not IsValid then
self:E({"File name invalid. Maybe something wrong with the extension ? ", FileName})
end
-- Check the Frequency
if type(Frequency) ~= "number" and IsValid then
self:E({"Frequency invalid. ", Frequency})
IsValid = false
end
Frequency = Frequency * 1000000 -- Conversion to Hz
-- Check the modulation
if Modulation ~= radio.modulation.AM and Modulation ~= radio.modulation.FM and IsValid then --TODO Maybe make this future proof if ED decides to add an other modulation ?
self:E({"Modulation is invalid. Use DCS's enum radio.modulation.", Modulation})
IsValid = false
end
-- Check the Power
if type(Power) ~= "number" and IsValid then
self:E({"Power is invalid. ", Power})
IsValid = false
end
Power = math.floor(math.abs(Power)) --TODO Find what is the maximum power allowed by DCS and limit power to that
if IsValid then
self:T2({"Activating Beacon on ", Frequency, Modulation})
-- Note that this is looped. I have to give this transmission a unique name, I use the class ID
trigger.action.radioTransmission(FileName, self.Positionable:GetPositionVec3(), Modulation, true, Frequency, Power, tostring(self.ID))
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
SCHEDULER:New( nil,
function()
@@ -453,16 +451,16 @@ function BEACON:_TACANToFrequency(TACANChannel, TACANMode)
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
@@ -473,6 +471,6 @@ function BEACON:_TACANToFrequency(TACANChannel, TACANMode)
A = 962
end
end
return (A + TACANChannel - B) * 1000000
end

View File

@@ -17,17 +17,21 @@
--
-- ===
-- @module Core.Condition
-- @image Core_Conditon.png
-- @image MOOSE.JPG
--- CONDITON class.
-- @type CONDITION
-- @field #string ClassName Name of the class.
-- @field #string lid Class id string for output to DCS log file.
-- @field #string name Name of the condition.
-- @field #boolean isAny General functions are evaluated as any condition.
-- @field #boolean negateResult Negeate result of evaluation.
-- @field #boolean negateResult Negate result of evaluation.
-- @field #boolean noneResult Boolean that is returned if no condition functions at all were specified.
-- @field #table functionsGen General condition functions.
-- @field #table functionsAny Any condition functions.
-- @field #table functionsAll All condition functions.
-- @field #number functionCounter Running number to determine the unique ID of condition functions.
-- @field #boolean defaultPersist Default persistence of condition functions.
--
-- @extends Core.Base#BASE
@@ -41,27 +45,34 @@
--
-- @field #CONDITION
CONDITION = {
ClassName = "CONDITION",
lid = nil,
functionsGen = {},
functionsAny = {},
functionsAll = {},
ClassName = "CONDITION",
lid = nil,
functionsGen = {},
functionsAny = {},
functionsAll = {},
functionCounter = 0,
defaultPersist = false,
}
--- Condition function.
-- @type CONDITION.Function
-- @field #function func Callback function to check for a condition. Should return a `#boolean`.
-- @field #number uid Unique ID of the condition function.
-- @field #string type Type of the condition function: "gen", "any", "all".
-- @field #boolean persistence If `true`, this is persistent.
-- @field #function func Callback function to check for a condition. Must return a `#boolean`.
-- @field #table arg (Optional) Arguments passed to the condition callback function if any.
--- CONDITION class version.
-- @field #string version
CONDITION.version="0.1.0"
CONDITION.version="0.3.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Make FSM.
-- TODO: Make FSM. No sure if really necessary.
-- DONE: Option to remove condition functions.
-- DONE: Persistence option for condition functions.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
@@ -78,6 +89,8 @@ function CONDITION:New(Name)
self.name=Name or "Condition X"
self:SetNoneResult(false)
self.lid=string.format("%s | ", self.name)
return self
@@ -101,6 +114,28 @@ function CONDITION:SetNegateResult(Negate)
return self
end
--- Set whether `true` or `false` is returned, if no conditions at all were specified. By default `false` is returned.
-- @param #CONDITION self
-- @param #boolean ReturnValue Returns this boolean.
-- @return #CONDITION self
function CONDITION:SetNoneResult(ReturnValue)
if not ReturnValue then
self.noneResult=false
else
self.noneResult=true
end
return self
end
--- Set whether condition functions are persistent, *i.e.* are removed.
-- @param #CONDITION self
-- @param #boolean IsPersistent If `true`, condition functions are persistent.
-- @return #CONDITION self
function CONDITION:SetDefaultPersistence(IsPersistent)
self.defaultPersist=IsPersistent
return self
end
--- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`).
-- @param #CONDITION self
-- @param #function Function The function to call.
@@ -113,47 +148,109 @@ end
--
-- myCondition:AddFunction(isAequalB, a, b)
--
-- @return #CONDITION self
-- @return #CONDITION.Function Condition function table.
function CONDITION:AddFunction(Function, ...)
-- Condition function.
local condition=self:_CreateCondition(Function, ...)
local condition=self:_CreateCondition(0, Function, ...)
-- Add to table.
table.insert(self.functionsGen, condition)
return self
return condition
end
--- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`).
-- @param #CONDITION self
-- @param #function Function The function to call.
-- @param ... (Optional) Parameters passed to the function (if any).
-- @return #CONDITION self
-- @return #CONDITION.Function Condition function table.
function CONDITION:AddFunctionAny(Function, ...)
-- Condition function.
local condition=self:_CreateCondition(Function, ...)
local condition=self:_CreateCondition(1, Function, ...)
-- Add to table.
table.insert(self.functionsAny, condition)
return self
return condition
end
--- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`).
-- @param #CONDITION self
-- @param #function Function The function to call.
-- @param ... (Optional) Parameters passed to the function (if any).
-- @return #CONDITION self
-- @return #CONDITION.Function Condition function table.
function CONDITION:AddFunctionAll(Function, ...)
-- Condition function.
local condition=self:_CreateCondition(Function, ...)
local condition=self:_CreateCondition(2, Function, ...)
-- Add to table.
table.insert(self.functionsAll, condition)
return condition
end
--- Remove a condition function.
-- @param #CONDITION self
-- @param #CONDITION.Function ConditionFunction The condition function to be removed.
-- @return #CONDITION self
function CONDITION:RemoveFunction(ConditionFunction)
if ConditionFunction then
local data=nil
if ConditionFunction.type==0 then
data=self.functionsGen
elseif ConditionFunction.type==1 then
data=self.functionsAny
elseif ConditionFunction.type==2 then
data=self.functionsAll
end
if data then
for i=#data,1,-1 do
local cf=data[i] --#CONDITION.Function
if cf.uid==ConditionFunction.uid then
self:T(self.lid..string.format("Removed ConditionFunction UID=%d", cf.uid))
table.remove(data, i)
return self
end
end
end
end
return self
end
--- Remove all non-persistant condition functions.
-- @param #CONDITION self
-- @return #CONDITION self
function CONDITION:RemoveNonPersistant()
for i=#self.functionsGen,1,-1 do
local cf=self.functionsGen[i] --#CONDITION.Function
if not cf.persistence then
table.remove(self.functionsGen, i)
end
end
for i=#self.functionsAll,1,-1 do
local cf=self.functionsAll[i] --#CONDITION.Function
if not cf.persistence then
table.remove(self.functionsAll, i)
end
end
for i=#self.functionsAny,1,-1 do
local cf=self.functionsAny[i] --#CONDITION.Function
if not cf.persistence then
table.remove(self.functionsAny, i)
end
end
return self
end
@@ -166,11 +263,7 @@ function CONDITION:Evaluate(AnyTrue)
-- Check if at least one function was given.
if #self.functionsAll + #self.functionsAny + #self.functionsAll == 0 then
if self.negateResult then
return true
else
return false
end
return self.noneResult
end
-- Any condition for gen.
@@ -206,6 +299,10 @@ function CONDITION:Evaluate(AnyTrue)
return result
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Private Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Check if all given condition are true.
-- @param #CONDITION self
-- @param #table functions Functions to evaluate.
@@ -275,13 +372,20 @@ end
--- Create conditon function object.
-- @param #CONDITION self
-- @param #number Ftype Function type: 0=Gen, 1=All, 2=Any.
-- @param #function Function The function to call.
-- @param ... (Optional) Parameters passed to the function (if any).
-- @return #CONDITION.Function Condition function.
function CONDITION:_CreateCondition(Function, ...)
function CONDITION:_CreateCondition(Ftype, Function, ...)
-- Increase counter.
self.functionCounter=self.functionCounter+1
local condition={} --#CONDITION.Function
condition.uid=self.functionCounter
condition.type=Ftype or 0
condition.persistence=self.defaultPersist
condition.func=Function
condition.arg={}
if arg then
@@ -290,6 +394,71 @@ function CONDITION:_CreateCondition(Function, ...)
return condition
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Global Condition Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Condition to check if time is greater than a given threshold time.
-- @param #number Time Time in seconds.
-- @param #boolean Absolute If `true`, abs. mission time from `timer.getAbsTime()` is checked. Default is relative mission time from `timer.getTime()`.
-- @return #boolean Returns `true` if time is greater than give the time.
function CONDITION.IsTimeGreater(Time, Absolute)
local Tnow=nil
if Absolute then
Tnow=timer.getAbsTime()
else
Tnow=timer.getTime()
end
if Tnow>Time then
return true
else
return false
end
return nil
end
--- Function that returns `true` (success) with a certain probability. For example, if you specify `Probability=80` there is an 80% chance that `true` is returned.
-- Technically, a random number between 0 and 100 is created. If the given success probability is less then this number, `true` is returned.
-- @param #number Probability Success probability in percent. Default 50 %.
-- @return #boolean Returns `true` for success and `false` otherwise.
function CONDITION.IsRandomSuccess(Probability)
Probability=Probability or 50
-- Create some randomness.
math.random()
math.random()
math.random()
-- Number between 0 and 100.
local N=math.random()*100
if N<Probability then
return true
else
return false
end
end
--- Function that returns always `true`
-- @return #boolean Returns `true` unconditionally.
function CONDITION.ReturnTrue()
return true
end
--- Function that returns always `false`
-- @return #boolean Returns `false` unconditionally.
function CONDITION.ReturnFalse()
return false
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@@ -51,7 +51,7 @@
-- * PLAYERS
-- * CARGOS
--
-- On top, for internal MOOSE administration purposes, the DATBASE administers the Unit and Group TEMPLATES as defined within the Mission Editor.
-- On top, for internal MOOSE administration purposes, the DATABASE administers the Unit and Group TEMPLATES as defined within the Mission Editor.
--
-- The singleton object **_DATABASE** is automatically created by MOOSE, that administers all objects within the mission.
-- Moose refers to **_DATABASE** within the framework extensively, but you can also refer to the _DATABASE object within your missions if required.
@@ -246,7 +246,7 @@ end
do -- Zones
--- Finds a @{Zone} based on the zone name.
--- Finds a @{Core.Zone} based on the zone name.
-- @param #DATABASE self
-- @param #string ZoneName The name of the zone.
-- @return Core.Zone#ZONE_BASE The found ZONE.
@@ -256,7 +256,7 @@ do -- Zones
return ZoneFound
end
--- Adds a @{Zone} based on the zone name in the DATABASE.
--- Adds a @{Core.Zone} based on the zone name in the DATABASE.
-- @param #DATABASE self
-- @param #string ZoneName The name of the zone.
-- @param Core.Zone#ZONE_BASE Zone The zone.
@@ -268,7 +268,7 @@ do -- Zones
end
--- Deletes a @{Zone} from the DATABASE based on the zone name.
--- Deletes a @{Core.Zone} from the DATABASE based on the zone name.
-- @param #DATABASE self
-- @param #string ZoneName The name of the zone.
function DATABASE:DeleteZone( ZoneName )
@@ -309,7 +309,7 @@ do -- Zones
self:I(string.format("Register ZONE: %s (Polygon, Quad)", ZoneName))
Zone=ZONE_POLYGON_BASE:New(ZoneName, ZoneData.verticies)
Zone=ZONE_POLYGON:NewFromPointsArray(ZoneName, ZoneData.verticies)
--for i,vec2 in pairs(ZoneData.verticies) do
-- local coord=COORDINATE:NewFromVec2(vec2)
@@ -322,7 +322,7 @@ do -- Zones
-- Store color of zone.
Zone.Color=color
-- Store zone ID.
Zone.ZoneID=ZoneData.zoneId
@@ -372,14 +372,63 @@ do -- Zones
end
end
-- Drawings as zones
if env.mission.drawings and env.mission.drawings.layers then
-- Loop over layers.
for layerID, layerData in pairs(env.mission.drawings.layers or {}) do
-- Loop over objects in layers.
for objectID, objectData in pairs(layerData.objects or {}) do
-- Check for polygon which has at least 4 points (we would need 3 but the origin seems to be there twice)
if objectData.polygonMode=="free" and objectData.points and #objectData.points>=4 then
-- Name of the zone.
local ZoneName=objectData.name or "Unknown Drawing Zone"
-- Reference point. All other points need to be translated by this.
local vec2={x=objectData.mapX, y=objectData.mapY}
-- Copy points array.
local points=UTILS.DeepCopy(objectData.points)
-- Translate points.
for i,_point in pairs(points) do
local point=_point --DCS#Vec2
points[i]=UTILS.Vec2Add(point, vec2)
end
-- Remove last point.
table.remove(points, #points)
-- Debug output
self:I(string.format("Register ZONE: %s (Polygon drawing with %d verticies)", ZoneName, #points))
-- Create new polygon zone.
local Zone=ZONE_POLYGON:NewFromPointsArray(ZoneName, points)
-- Set color.
Zone:SetColor({1, 0, 0}, 0.15)
-- Store in DB.
self.ZONENAMES[ZoneName] = ZoneName
-- Add zone.
self:AddZone(ZoneName, Zone)
end
end
end
end
end
end -- zone
do -- Zone_Goal
--- Finds a @{Zone} based on the zone name.
--- Finds a @{Core.Zone} based on the zone name.
-- @param #DATABASE self
-- @param #string ZoneName The name of the zone.
-- @return Core.Zone#ZONE_BASE The found ZONE.
@@ -389,7 +438,7 @@ do -- Zone_Goal
return ZoneFound
end
--- Adds a @{Zone} based on the zone name in the DATABASE.
--- Adds a @{Core.Zone} based on the zone name in the DATABASE.
-- @param #DATABASE self
-- @param #string ZoneName The name of the zone.
-- @param Core.Zone#ZONE_BASE Zone The zone.
@@ -401,7 +450,7 @@ do -- Zone_Goal
end
--- Deletes a @{Zone} from the DATABASE based on the zone name.
--- Deletes a @{Core.Zone} from the DATABASE based on the zone name.
-- @param #DATABASE self
-- @param #string ZoneName The name of the zone.
function DATABASE:DeleteZoneGoal( ZoneName )
@@ -777,7 +826,7 @@ function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, Category
local StaticTemplate = UTILS.DeepCopy( StaticTemplate )
local StaticTemplateGroupName = env.getValueDictByKey(StaticTemplate.name)
local StaticTemplateName=StaticTemplate.units[1].name
self.Templates.Statics[StaticTemplateName] = self.Templates.Statics[StaticTemplateName] or {}
@@ -1027,11 +1076,26 @@ function DATABASE:_RegisterAirbases()
for DCSAirbaseId, DCSAirbase in pairs(world.getAirbases()) do
self:_RegisterAirbase(DCSAirbase)
end
return self
end
--- Register a DCS airbase.
-- @param #DATABASE self
-- @param DCS#Airbase airbase Airbase.
-- @return #DATABASE self
function DATABASE:_RegisterAirbase(airbase)
if airbase then
-- Get the airbase name.
local DCSAirbaseName = DCSAirbase:getName()
local DCSAirbaseName = airbase:getName()
-- This gave the incorrect value to be inserted into the airdromeID for DCS 2.5.6. Is fixed now.
local airbaseID=DCSAirbase:getID()
local airbaseID=airbase:getID()
-- Add and register airbase.
local airbase=self:AddAirbase( DCSAirbaseName )
@@ -1065,20 +1129,23 @@ function DATABASE:_EventOnBirth( Event )
if Event.IniDCSUnit then
if Event.IniObjectCategory == 3 then
if Event.IniObjectCategory == Object.Category.STATIC then
-- Add static object to DB.
self:AddStatic( Event.IniDCSUnitName )
else
if Event.IniObjectCategory == 1 then
if Event.IniObjectCategory == Object.Category.UNIT then
-- Add unit and group to DB.
self:AddUnit( Event.IniDCSUnitName )
self:AddGroup( Event.IniDCSGroupName )
-- Add airbase if it was spawned later in the mission.
-- A unit can also be an airbase (e.g. ships).
local DCSAirbase = Airbase.getByName(Event.IniDCSUnitName)
if DCSAirbase then
-- Add airbase if it was spawned later in the mission.
self:I(string.format("Adding airbase %s", tostring(Event.IniDCSUnitName)))
self:AddAirbase(Event.IniDCSUnitName)
end
@@ -1086,7 +1153,7 @@ function DATABASE:_EventOnBirth( Event )
end
end
if Event.IniObjectCategory == 1 then
if Event.IniObjectCategory == Object.Category.UNIT then
Event.IniUnit = self:FindUnit( Event.IniDCSUnitName )
Event.IniGroup = self:FindGroup( Event.IniDCSGroupName )
@@ -1153,11 +1220,11 @@ function DATABASE:_EventOnDeadOrCrash( Event )
if self.STATICS[Event.IniDCSUnitName] then
self:DeleteStatic( Event.IniDCSUnitName )
end
---
-- Maybe a UNIT?
---
-- Delete unit.
if self.UNITS[Event.IniDCSUnitName] then
self:T("STATIC Event for UNIT "..tostring(Event.IniDCSUnitName))
@@ -1556,11 +1623,11 @@ function DATABASE:FindOpsGroupFromUnit(unitname)
else
unit=unitname
end
if unit then
groupname=unit:GetGroup():GetName()
end
if groupname then
return self.FLIGHTGROUPS[groupname]
else

View File

@@ -35,7 +35,7 @@
-- There are 5 types/levels of objects that the _EVENTDISPATCHER services:
--
-- * _DATABASE object: The core of the MOOSE objects. Any object that is created, deleted or updated, is done in this database.
-- * SET_ derived classes: These are subsets of the _DATABASE object. These subsets are updated by the _EVENTDISPATCHER as the second priority.
-- * SET_ derived classes: These are subsets of the global _DATABASE object (an instance of @{Core.Database#DATABASE}). These subsets are updated by the _EVENTDISPATCHER as the second priority.
-- * UNIT objects: UNIT objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed UNIT object.
-- * GROUP objects: GROUP objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed GROUP object.
-- * Any other object: Various other objects can subscribe to DCS events. Each DCS event triggered will be published to each subscribed object.
@@ -52,7 +52,7 @@
--
-- ![Objects](..\Presentations\EVENT\Dia8.JPG)
--
-- The actual event subscribing and handling is not facilitated through the _EVENTDISPATCHER, but it is done through the @{BASE} class, @{UNIT} class and @{GROUP} class.
-- The actual event subscribing and handling is not facilitated through the _EVENTDISPATCHER, but it is done through the @{Core.Base#BASE} class, @{Wrapper.Unit#UNIT} class and @{Wrapper.Group#GROUP} class.
-- The _EVENTDISPATCHER is a component that is quietly working in the background of MOOSE.
--
-- ![Objects](..\Presentations\EVENT\Dia9.JPG)
@@ -248,6 +248,18 @@ EVENTS = {
TriggerZone = world.event.S_EVENT_TRIGGER_ZONE or -1,
LandingQualityMark = world.event.S_EVENT_LANDING_QUALITY_MARK or -1,
BDA = world.event.S_EVENT_BDA or -1,
-- Added with DCS 2.8.0
AIAbortMission = world.event.S_EVENT_AI_ABORT_MISSION or -1,
DayNight = world.event.S_EVENT_DAYNIGHT or -1,
FlightTime = world.event.S_EVENT_FLIGHT_TIME or -1,
SelfKillPilot = world.event.S_EVENT_PLAYER_SELF_KILL_PILOT or -1,
PlayerCaptureAirfield = world.event.S_EVENT_PLAYER_CAPTURE_AIRFIELD or -1,
EmergencyLanding = world.event.S_EVENT_EMERGENCY_LANDING or -1,
UnitCreateTask = world.event.S_EVENT_UNIT_CREATE_TASK or -1,
UnitDeleteTask = world.event.S_EVENT_UNIT_DELETE_TASK or -1,
SimulationStart = world.event.S_EVENT_SIMULATION_START or -1,
WeaponRearm = world.event.S_EVENT_WEAPON_REARM or -1,
WeaponDrop = world.event.S_EVENT_WEAPON_DROP or -1,
}
--- The Event structure
@@ -560,9 +572,69 @@ local _EVENTMETA = {
Event = "OnEventBDA",
Text = "S_EVENT_BDA"
},
-- Added with DCS 2.8
[EVENTS.AIAbortMission] = {
Order = 1,
Side = "I",
Event = "OnEventAIAbortMission",
Text = "S_EVENT_AI_ABORT_MISSION"
},
[EVENTS.DayNight] = {
Order = 1,
Event = "OnEventDayNight",
Text = "S_EVENT_DAYNIGHT"
},
[EVENTS.FlightTime] = {
Order = 1,
Event = "OnEventFlightTime",
Text = "S_EVENT_FLIGHT_TIME"
},
[EVENTS.SelfKillPilot] = {
Order = 1,
Side = "I",
Event = "OnEventSelfKillPilot",
Text = "S_EVENT_PLAYER_SELF_KILL_PILOT"
},
[EVENTS.PlayerCaptureAirfield] = {
Order = 1,
Event = "OnEventPlayerCaptureAirfield",
Text = "S_EVENT_PLAYER_CAPTURE_AIRFIELD"
},
[EVENTS.EmergencyLanding] = {
Order = 1,
Side = "I",
Event = "OnEventEmergencyLanding",
Text = "S_EVENT_EMERGENCY_LANDING"
},
[EVENTS.UnitCreateTask] = {
Order = 1,
Event = "OnEventUnitCreateTask",
Text = "S_EVENT_UNIT_CREATE_TASK"
},
[EVENTS.UnitDeleteTask] = {
Order = 1,
Event = "OnEventUnitDeleteTask",
Text = "S_EVENT_UNIT_DELETE_TASK"
},
[EVENTS.SimulationStart] = {
Order = 1,
Event = "OnEventSimulationStart",
Text = "S_EVENT_SIMULATION_START"
},
[EVENTS.WeaponRearm] = {
Order = 1,
Side = "I",
Event = "OnEventWeaponRearm",
Text = "S_EVENT_WEAPON_REARM"
},
[EVENTS.WeaponDrop] = {
Order = 1,
Side = "I",
Event = "OnEventWeaponDrop",
Text = "S_EVENT_WEAPON_DROP"
},
}
--- The Events structure
-- @type EVENT.Events
-- @field #number IniUnit
@@ -932,7 +1004,7 @@ do -- Event Creation
--- Creation of a ZoneGoal Deletion Event.
-- @param #EVENT self
-- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created.
-- @param Functional.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created.
function EVENT:CreateEventDeleteZoneGoal( ZoneGoal )
self:F( { ZoneGoal } )
@@ -1058,7 +1130,7 @@ function EVENT:onEvent( Event )
Event.IniUnitName = Event.IniDCSUnitName
Event.IniDCSGroup = Event.IniDCSUnit:getGroup()
Event.IniUnit = UNIT:FindByName( Event.IniDCSUnitName )
if not Event.IniUnit then
-- Unit can be a CLIENT. Most likely this will be the case ...
Event.IniUnit = CLIENT:FindByName( Event.IniDCSUnitName, '', true )
@@ -1093,8 +1165,7 @@ function EVENT:onEvent( Event )
if Event.IniObjectCategory == Object.Category.SCENERY then
---
-- Scenery
---
---
Event.IniDCSUnit = Event.initiator
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
Event.IniUnitName = Event.IniDCSUnitName
@@ -1114,6 +1185,12 @@ function EVENT:onEvent( Event )
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
Event.IniCategory = Event.IniDCSUnit:getDesc().category
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
-- If the airbase does not exist in the DB, we add it (e.g. when FARPS are spawned).
if not Event.IniUnit then
_DATABASE:_RegisterAirbase(Event.initiator)
Event.IniUnit = AIRBASE:FindByName(Event.IniDCSUnitName)
end
end
end
@@ -1147,7 +1224,7 @@ function EVENT:onEvent( Event )
if Event.TgtObjectCategory == Object.Category.STATIC then
-- get base data
Event.TgtDCSUnit = Event.target
if Event.target:isExist() and Event.id ~= 33 then -- leave out ejected seat object
if Event.target:isExist() and Event.id ~= 33 and not Event.TgtObjectCategory == Object.Category.COORDINATE then -- leave out ejected seat object
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
Event.TgtUnitName = Event.TgtDCSUnitName
Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false )
@@ -1203,9 +1280,11 @@ function EVENT:onEvent( Event )
--local name=Event.place:getName() -- This returns a DCS error "Airbase doesn't exit" :(
-- However, this is not a big thing, as the aircraft the pilot ejected from is usually long crashed before the ejected pilot touches the ground.
--Event.Place=UNIT:Find(Event.place)
else
Event.Place=AIRBASE:Find(Event.place)
Event.PlaceName=Event.Place:GetName()
else
if Event.place:isExist() and Event.place:getCategory() ~= Object.Category.SCENERY then
Event.Place=AIRBASE:Find(Event.place)
Event.PlaceName=Event.Place:GetName()
end
end
end

View File

@@ -47,9 +47,9 @@
-- and tailored** by mission designers through **the implementation of Transition Handlers**.
-- Each of these FSM implementation classes start either with:
--
-- * an acronym **AI\_**, which indicates a FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class.
-- * an acronym **TASK\_**, which indicates a FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class.
-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class.
-- * an acronym **AI\_**, which indicates a FSM implementation directing **AI controlled** @{Wrapper.Group#GROUP} and/or @{Wrapper.Unit#UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class.
-- * an acronym **TASK\_**, which indicates a FSM implementation executing a @{Tasking.Task#TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class.
-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{Tasking.Task#TASK}, seated in a @{Wrapper.Client#CLIENT} (slot) or a @{Wrapper.Unit#UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class.
--
-- Detailed explanations and API specifics are further below clarified and FSM derived class specifics are described in those class documentation sections.
--
@@ -61,10 +61,10 @@
--
-- The following derived classes are available in the MOOSE framework, that implement a specialized form of a FSM:
--
-- * @{#FSM_TASK}: Models Finite State Machines for @{Task}s.
-- * @{#FSM_PROCESS}: Models Finite State Machines for @{Task} actions, which control @{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
-- * @{#FSM_TASK}: Models Finite State Machines for @{Tasking.Task}s.
-- * @{#FSM_PROCESS}: Models Finite State Machines for @{Tasking.Task} actions, which control @{Wrapper.Client}s.
-- * @{#FSM_CONTROLLABLE}: Models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Wrapper.Client}s.
-- * @{#FSM_SET}: Models Finite State Machines for @{Core.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.
--
-- ===
@@ -119,9 +119,9 @@ do -- FSM
-- and tailored** by mission designers through **the implementation of Transition Handlers**.
-- Each of these FSM implementation classes start either with:
--
-- * an acronym **AI\_**, which indicates an FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class.
-- * an acronym **TASK\_**, which indicates an FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class.
-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class.
-- * an acronym **AI\_**, which indicates an FSM implementation directing **AI controlled** @{Wrapper.Group#GROUP} and/or @{Wrapper.Unit#UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class.
-- * an acronym **TASK\_**, which indicates an FSM implementation executing a @{Tasking.Task#TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class.
-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{Tasking.Task#TASK}, seated in a @{Wrapper.Client#CLIENT} (slot) or a @{Wrapper.Unit#UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class.
--
-- ![Transition Rules and Transition Handlers and Event Triggers](..\Presentations\FSM\Dia3.JPG)
--
@@ -418,7 +418,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 @{Wrapper.Controllable} by the task.
--- Set the default @{#FSM_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.
@@ -953,7 +953,7 @@ do -- FSM_CONTROLLABLE
-- @field Wrapper.Controllable#CONTROLLABLE Controllable
-- @extends Core.Fsm#FSM
--- Models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Client}s.
--- Models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Wrapper.Client}s.
--
-- ===
--
@@ -1086,7 +1086,7 @@ do -- FSM_PROCESS
-- @field Tasking.Task#TASK Task
-- @extends Core.Fsm#FSM_CONTROLLABLE
--- FSM_PROCESS class models Finite State Machines for @{Task} actions, which control @{Client}s.
--- FSM_PROCESS class models Finite State Machines for @{Tasking.Task} actions, which control @{Wrapper.Client}s.
--
-- ===
--
@@ -1241,7 +1241,7 @@ 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.
--- Send a message of the @{Tasking.Task} to the Group of the Unit.
-- @param #FSM_PROCESS self
function FSM_PROCESS:Message( Message )
self:F( { Message = Message } )
@@ -1382,7 +1382,7 @@ do -- FSM_SET
-- @field Core.Set#SET_BASE Set
-- @extends Core.Fsm#FSM
--- FSM_SET class models Finite State Machines for @{Set}s. Note that these FSMs control multiple objects!!! So State concerns here
--- FSM_SET class models Finite State Machines for @{Core.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.
--
-- ===

View File

@@ -1,10 +1,16 @@
--- **Core** - MarkerOps_Base.
--- **Core** - Tap into markers added to the F10 map by users.
--
-- **Main Features:**
--
-- * Create an easy way to tap into markers added to the F10 map by users.
-- * Recognize own tag and list of keywords.
-- * Matched keywords are handed down to functions.
-- ##Listen for your tag
-- myMarker = MARKEROPS_BASE:New("tag", {}, false)
-- function myMarker:OnAfterMarkChanged(From, Event, To, Text, Keywords, Coord, idx)
--
-- end
-- Make sure to use the "MarkChanged" event as "MarkAdded" comes in right after the user places a blank marker and your callback will never be called.
--
-- ===
--

View File

@@ -34,7 +34,7 @@
--
-- Messages are sent:
--
-- * To a @{Client} using @{#MESSAGE.ToClient}().
-- * To a @{Wrapper.Client} using @{#MESSAGE.ToClient}().
-- * To a @{Wrapper.Group} using @{#MESSAGE.ToGroup}()
-- * To a @{Wrapper.Unit} using @{#MESSAGE.ToUnit}()
-- * To a coalition using @{#MESSAGE.ToCoalition}().
@@ -98,7 +98,7 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen
self.MessageType = nil
-- When no MessageCategory is given, we don't show it as a title...
-- When no MessageCategory is given, we don't show it as a title...
if MessageCategory and MessageCategory ~= "" then
if MessageCategory:sub( -1 ) ~= "\n" then
self.MessageCategory = MessageCategory .. ": "
@@ -128,7 +128,7 @@ 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.
-- The message display times are automatically defined based on the timing settings in the @{Core.Settings} menu.
-- @param self
-- @param #string MessageText is the text of the Message.
-- @param #MESSAGE.Type MessageType The type of the message.
@@ -171,7 +171,7 @@ 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.
-- @param Core.Settings#SETTINGS Settings used to display the message.
-- @return #MESSAGE
-- @usage
--
@@ -182,11 +182,11 @@ end
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
-- or
-- MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
-- MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
-- MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25 ):ToClient( ClientGroup )
-- MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25 ):ToClient( ClientGroup )
-- or
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" )
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" )
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25 )
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25 )
-- MessageClient1:ToClient( ClientGroup )
-- MessageClient2:ToClient( ClientGroup )
--
@@ -204,19 +204,20 @@ function MESSAGE:ToClient( Client, Settings )
local Unit = Client:GetClient()
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)
trigger.action.outTextForUnit( Unit:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
end
end
return self
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)
trigger.action.outTextForUnit( Unit:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
end
end
return self
end
--- Sends a MESSAGE to a Group.
-- @param #MESSAGE self
-- @param Wrapper.Group#GROUP Group to which the message is displayed.
-- @param Core.Settings#Settings Settings (Optional) Settings for message display.
-- @return #MESSAGE Message object.
function MESSAGE:ToGroup( Group, Settings )
self:F( Group.GroupName )
@@ -241,6 +242,7 @@ end
--- Sends a MESSAGE to a Unit.
-- @param #MESSAGE self
-- @param Wrapper.Unit#UNIT Unit to which the message is displayed.
-- @param Core.Settings#Settings Settings (Optional) Settings for message display.
-- @return #MESSAGE Message object.
function MESSAGE:ToUnit( Unit, Settings )
self:F( Unit.IdentifiableName )
@@ -262,27 +264,38 @@ function MESSAGE:ToUnit( Unit, Settings )
return self
end
--- Sends a MESSAGE to a Unit.
--- Sends a MESSAGE to a Country.
-- @param #MESSAGE self
-- @param Wrapper.Unit#UNIT Unit to which the message is displayed.
-- @param #number Country to which the message is displayed, e.g. country.id.GERMANY. For all country numbers see here: [Hoggit Wiki](https://wiki.hoggitworld.com/view/DCS_enum_country)
-- @param Core.Settings#Settings Settings (Optional) Settings for message display.
-- @return #MESSAGE Message object.
function MESSAGE:ToUnit( Unit, Settings )
self:F( Unit.IdentifiableName )
if Unit then
function MESSAGE:ToCountry( Country, Settings )
self:F(Country )
if Country then
if self.MessageType then
local Settings = Settings or ( Unit and _DATABASE:GetPlayerSettings( Unit:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
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.outTextForUnit( Unit:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
trigger.action.outTextForCountry( Country, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
end
end
return self
end
--- Sends a MESSAGE to a Country.
-- @param #MESSAGE self
-- @param #number Country to which the message is displayed, , e.g. country.id.GERMANY. For all country numbers see here: [Hoggit Wiki](https://wiki.hoggitworld.com/view/DCS_enum_country)
-- @param #boolean Condition Sends the message only if the condition is true.
-- @param Core.Settings#Settings Settings (Optional) Settings for message display.
-- @return #MESSAGE Message object.
function MESSAGE:ToCountryIf( Country, Condition, Settings )
self:F(Country )
if Country and Condition == true then
self:ToCountry( Country, Settings )
end
return self
end
@@ -292,11 +305,11 @@ end
-- @usage
--
-- -- Send a message created with the @{New} method to the BLUE coalition.
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue()
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25):ToBlue()
-- or
-- MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue()
-- MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25 ):ToBlue()
-- or
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25 )
-- MessageBLUE:ToBlue()
--
function MESSAGE:ToBlue()
@@ -313,11 +326,11 @@ end
-- @usage
--
-- -- Send a message created with the @{New} method to the RED coalition.
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed()
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25 ):ToRed()
-- or
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed()
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25 ):ToRed()
-- 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 = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25 )
-- MessageRED:ToRed()
--
function MESSAGE:ToRed()
@@ -336,11 +349,11 @@ end
-- @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 )
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25 ):ToCoalition( coalition.side.RED )
-- or
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED )
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25 ):ToCoalition( coalition.side.RED )
-- 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 = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25 )
-- MessageRED:ToCoalition( coalition.side.RED )
--
function MESSAGE:ToCoalition( CoalitionSide, Settings )
@@ -384,11 +397,11 @@ end
-- @usage
--
-- -- Send a message created to all players.
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll()
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25 ):ToAll()
-- or
-- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll()
-- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25 ):ToAll()
-- or
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" )
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25 )
-- MessageAll:ToAll()
--
function MESSAGE:ToAll( Settings )
@@ -410,6 +423,7 @@ end
--- Sends a MESSAGE to all players if the given Condition is true.
-- @param #MESSAGE self
-- @param #boolean Condition
-- @return #MESSAGE
function MESSAGE:ToAllIf( Condition )
@@ -419,3 +433,24 @@ function MESSAGE:ToAllIf( Condition )
return self
end
--- Sends a MESSAGE to DCS log file.
-- @param #MESSAGE self
-- @return #MESSAGE self
function MESSAGE:ToLog()
env.info(self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ))
return self
end
--- Sends a MESSAGE to DCS log file if the given Condition is true.
-- @param #MESSAGE self
-- @return #MESSAGE self
function MESSAGE:ToLogIf( Condition )
if Condition and Condition == true then
env.info(self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ))
end
return self
end

View File

@@ -138,7 +138,7 @@ do -- COORDINATE
--
-- Calculate if the coordinate has Line of Sight (LOS) with the other given coordinate.
-- Mountains, trees and other objects can be positioned between the two 3D points, preventing visibilty in a straight continuous line.
-- The method @{#COORDINATE.IsLOS}() returns if the two coodinates have LOS.
-- The method @{#COORDINATE.IsLOS}() returns if the two coordinates have LOS.
--
-- ## 4.7) Check the coordinate position.
--
@@ -406,6 +406,42 @@ do -- COORDINATE
return self
end
--- Returns the magnetic declination at the given coordinate.
-- NOTE that this needs `require` to be available so you need to desanitize the `MissionScripting.lua` file in your DCS/Scrips folder.
-- If `require` is not available, a constant value for the whole map.
-- @param #COORDINATE self
-- @param #number Month (Optional) The month at which the declination is calculated. Default is the mission month.
-- @param #number Year (Optional) The year at which the declination is calculated. Default is the mission year.
-- @return #number Magnetic declination in degrees.
function COORDINATE:GetMagneticDeclination(Month, Year)
local decl=UTILS.GetMagneticDeclination()
if require then
local magvar = require('magvar')
if magvar then
local date, year, month, day=UTILS.GetDCSMissionDate()
magvar.init(Month or month, Year or year)
local lat, lon=self:GetLLDDM()
decl=magvar.get_mag_decl(lat, lon)
if decl then
decl=math.deg(decl)
end
end
else
self:T("The require package is not available. Using constant value for magnetic declination")
end
return decl
end
--- Returns the coordinate from the latitude and longitude given in decimal degrees.
-- @param #COORDINATE self
@@ -504,7 +540,7 @@ do -- COORDINATE
local gotscenery=false
local function EvaluateZone(ZoneObject)
BASE:T({ZoneObject})
if ZoneObject then
-- Get category of scanned object.
@@ -594,7 +630,7 @@ do -- COORDINATE
--- Scan/find SCENERY objects within a certain radius around the coordinate using the world.searchObjects() DCS API function.
-- @param #COORDINATE self
-- @param #number radius (Optional) Scan radius in meters. Default 100 m.
-- @return table Set of scenery objects.
-- @return table Table of SCENERY objects.
function COORDINATE:ScanScenery(radius)
local _,_,_,_,_,scenerys=self:ScanObjects(radius, false, false, true)
@@ -654,7 +690,7 @@ do -- COORDINATE
-- @param DCS#Distance Distance The Distance to be added in meters.
-- @param DCS#Angle Angle The Angle in degrees. Defaults to 0 if not specified (nil).
-- @param #boolean Keepalt If true, keep altitude of original coordinate. Default is that the new coordinate is created at the translated land height.
-- @param #boolean Overwrite If true, overwrite the original COORDINATE with the translated one. Otherwise, create a new COODINATE.
-- @param #boolean Overwrite If true, overwrite the original COORDINATE with the translated one. Otherwise, create a new COORDINATE.
-- @return #COORDINATE The new calculated COORDINATE.
function COORDINATE:Translate( Distance, Angle, Keepalt, Overwrite )
@@ -923,7 +959,7 @@ do -- COORDINATE
return T-273.15
end
--- Returns a text of the temperature according the measurement system @{Settings}.
--- Returns a text of the temperature according the measurement system @{Core.Settings}.
-- The text will reflect the temperature like this:
--
-- - For Russian and European aircraft using the metric system - Degrees Celcius (°C)
@@ -936,7 +972,7 @@ do -- COORDINATE
--
-- @param #COORDINATE self
-- @param height (Optional) parameter specifying the height ASL.
-- @return #string Temperature according the measurement system @{Settings}.
-- @return #string Temperature according the measurement system @{Core.Settings}.
function COORDINATE:GetTemperatureText( height, Settings )
local DegreesCelcius = self:GetTemperature( height )
@@ -969,7 +1005,7 @@ do -- COORDINATE
return P/100
end
--- Returns a text of the pressure according the measurement system @{Settings}.
--- Returns a text of the pressure according the measurement system @{Core.Settings}.
-- The text will contain always the pressure in hPa and:
--
-- - For Russian and European aircraft using the metric system - hPa and mmHg
@@ -982,7 +1018,7 @@ do -- COORDINATE
--
-- @param #COORDINATE self
-- @param height (Optional) parameter specifying the height ASL. E.g. set height=0 for QNH.
-- @return #string Pressure in hPa and mmHg or inHg depending on the measurement system @{Settings}.
-- @return #string Pressure in hPa and mmHg or inHg depending on the measurement system @{Core.Settings}.
function COORDINATE:GetPressureText( height, Settings )
local Pressure_hPa = self:GetPressure( height )
@@ -1062,7 +1098,7 @@ do -- COORDINATE
end
--- Returns a text documenting the wind direction (from) and strength according the measurement system @{Settings}.
--- Returns a text documenting the wind direction (from) and strength according the measurement system @{Core.Settings}.
-- The text will reflect the wind like this:
--
-- - For Russian and European aircraft using the metric system - Wind direction in degrees (°) and wind speed in meters per second (mps).
@@ -1075,7 +1111,7 @@ do -- COORDINATE
--
-- @param #COORDINATE self
-- @param height (Optional) parameter specifying the height ASL. The minimum height will be always be the land height since the wind is zero below the ground.
-- @return #string Wind direction and strength according the measurement system @{Settings}.
-- @return #string Wind direction and strength according the measurement system @{Core.Settings}.
function COORDINATE:GetWindText( height, Settings )
local Direction, Strength = self:GetWind( height )
@@ -1111,15 +1147,25 @@ do -- COORDINATE
-- @param #number AngleRadians The angle in randians.
-- @param #number Precision The precision.
-- @param Core.Settings#SETTINGS Settings
-- @param #boolean MagVar If true, include magentic degrees
-- @return #string The bearing text in degrees.
function COORDINATE:GetBearingText( AngleRadians, Precision, Settings, Language )
function COORDINATE:GetBearingText( AngleRadians, Precision, Settings, MagVar )
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
local AngleDegrees = UTILS.Round( UTILS.ToDegree( AngleRadians ), Precision )
local s = string.format( '%03d°', AngleDegrees )
if MagVar then
local variation = UTILS.GetMagneticDeclination() or 0
local AngleMagnetic = AngleDegrees - variation
if AngleMagnetic < 0 then AngleMagnetic = 360-AngleMagnetic end
s = string.format( '%03d°M|%03d°', AngleMagnetic,AngleDegrees )
end
return s
end
@@ -1133,21 +1179,22 @@ do -- COORDINATE
function COORDINATE:GetDistanceText( Distance, Settings, Language, Precision )
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
local Language = Language or "EN"
local Language = Language or Settings.Locale or _SETTINGS.Locale or "EN"
Language = string.lower(Language)
local Precision = Precision or 0
local DistanceText
if Settings:IsMetric() then
if Language == "EN" then
if Language == "en" then
DistanceText = " for " .. UTILS.Round( Distance / 1000, Precision ) .. " km"
elseif Language == "RU" then
elseif Language == "ru" then
DistanceText = " за " .. UTILS.Round( Distance / 1000, Precision ) .. " километров"
end
else
if Language == "EN" then
if Language == "en" then
DistanceText = " for " .. UTILS.Round( UTILS.MetersToNM( Distance ), Precision ) .. " miles"
elseif Language == "RU" then
elseif Language == "ru" then
DistanceText = " за " .. UTILS.Round( UTILS.MetersToNM( Distance ), Precision ) .. " миль"
end
end
@@ -1161,19 +1208,21 @@ do -- COORDINATE
function COORDINATE:GetAltitudeText( Settings, Language )
local Altitude = self.y
local Settings = Settings or _SETTINGS
local Language = Language or "EN"
local Language = Language or Settings.Locale or _SETTINGS.Locale or "EN"
Language = string.lower(Language)
if Altitude ~= 0 then
if Settings:IsMetric() then
if Language == "EN" then
if Language == "en" then
return " at " .. UTILS.Round( self.y, -3 ) .. " meters"
elseif Language == "RU" then
elseif Language == "ru" then
return " в " .. UTILS.Round( self.y, -3 ) .. " метры"
end
else
if Language == "EN" then
if Language == "en" then
return " at " .. UTILS.Round( UTILS.MetersToFeet( self.y ), -3 ) .. " feet"
elseif Language == "RU" then
elseif Language == "ru" then
return " в " .. UTILS.Round( self.y, -3 ) .. " ноги"
end
end
@@ -1220,12 +1269,14 @@ do -- COORDINATE
-- @param #number AngleRadians The angle in randians
-- @param #number Distance The distance
-- @param Core.Settings#SETTINGS Settings
-- @param #string Language (Optional) Language "en" or "ru"
-- @param #boolean MagVar If true, also state angle in magnetic
-- @return #string The BR Text
function COORDINATE:GetBRText( AngleRadians, Distance, Settings, Language )
function COORDINATE:GetBRText( AngleRadians, Distance, Settings, Language, MagVar )
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
local BearingText = self:GetBearingText( AngleRadians, 0, Settings, Language )
local BearingText = self:GetBearingText( AngleRadians, 0, Settings, MagVar )
local DistanceText = self:GetDistanceText( Distance, Settings, Language, 0 )
local BRText = BearingText .. DistanceText
@@ -1238,12 +1289,14 @@ do -- COORDINATE
-- @param #number AngleRadians The angle in randians
-- @param #number Distance The distance
-- @param Core.Settings#SETTINGS Settings
-- @param #string Language (Optional) Language "en" or "ru"
-- @param #boolean MagVar If true, also state angle in magnetic
-- @return #string The BRA Text
function COORDINATE:GetBRAText( AngleRadians, Distance, Settings, Language )
function COORDINATE:GetBRAText( AngleRadians, Distance, Settings, Language, MagVar )
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
local BearingText = self:GetBearingText( AngleRadians, 0, Settings, Language )
local BearingText = self:GetBearingText( AngleRadians, 0, Settings, MagVar )
local DistanceText = self:GetDistanceText( Distance, Settings, Language, 0 )
local AltitudeText = self:GetAltitudeText( Settings, Language )
@@ -1268,7 +1321,15 @@ do -- COORDINATE
self.y=alt
return self
end
--- Set altitude to be at land height (i.e. on the ground!)
-- @param #COORDINATE self
function COORDINATE:SetAtLandheight()
local alt=self:GetLandHeight()
self.y=alt
return self
end
--- Build an air type route point.
-- @param #COORDINATE self
-- @param #COORDINATE.WaypointAltType AltType The altitude type.
@@ -1519,7 +1580,7 @@ do -- COORDINATE
-- @param #number Coalition (Optional) Coalition of the airbase.
-- @return Wrapper.Airbase#AIRBASE Closest Airbase to the given coordinate.
-- @return #number Distance to the closest airbase in meters.
function COORDINATE:GetClosestAirbase2(Category, Coalition)
function COORDINATE:GetClosestAirbase(Category, Coalition)
-- Get all airbases of the map.
local airbases=AIRBASE.GetAllAirbases(Coalition)
@@ -1553,34 +1614,15 @@ do -- COORDINATE
return closest,distmin
end
--- Gets the nearest airbase with respect to the current coordinates.
--- [kept for downwards compatibility only] Gets the nearest airbase with respect to the current coordinates.
-- @param #COORDINATE self
-- @param #number Category (Optional) Category of the airbase. Enumerator of @{Wrapper.Airbase#AIRBASE.Category}.
-- @param #number Coalition (Optional) Coalition of the airbase.
-- @return Wrapper.Airbase#AIRBASE Closest Airbase to the given coordinate.
-- @return #number Distance to the closest airbase in meters.
function COORDINATE:GetClosestAirbase(Category, Coalition)
local a=self:GetVec3()
local distmin=math.huge
local airbase=nil
for DCSairbaseID, DCSairbase in pairs(world.getAirbases(Coalition)) do
local b=DCSairbase:getPoint()
local c=UTILS.VecSubstract(a,b)
local dist=UTILS.VecNorm(c)
--env.info(string.format("Airbase %s dist=%d category=%d", DCSairbase:getName(), dist, DCSairbase:getCategory()))
if dist<distmin and (Category==nil or Category==DCSairbase:getDesc().category) then
distmin=dist
airbase=DCSairbase
end
end
return AIRBASE:Find(airbase)
function COORDINATE:GetClosestAirbase2(Category, Coalition)
local closest, distmin = self:GetClosestAirbase(Category, Coalition)
return closest, distmin
end
--- Gets the nearest parking spot.
@@ -1913,7 +1955,6 @@ do -- COORDINATE
-- @param #COORDINATE self
-- @param #string name (Optional) Name of the fire to stop it, if not using the same COORDINATE object.
function COORDINATE:StopBigSmokeAndFire( name )
self:F2( { name = name } )
name = name or self.firename
trigger.action.effectSmokeStop( name )
end
@@ -2774,25 +2815,27 @@ do -- COORDINATE
-- @param #COORDINATE self
-- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from.
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
-- @param #boolean MagVar If true, also get angle in MagVar for BR/BRA
-- @return #string The BR text.
function COORDINATE:ToStringBR( FromCoordinate, Settings )
function COORDINATE:ToStringBR( FromCoordinate, Settings, MagVar )
local DirectionVec3 = FromCoordinate:GetDirectionVec3( self )
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
local Distance = self:Get2DDistance( FromCoordinate )
return "BR, " .. self:GetBRText( AngleRadians, Distance, Settings )
return "BR, " .. self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar )
end
--- Return a BRA string from a COORDINATE to the COORDINATE.
-- @param #COORDINATE self
-- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from.
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
-- @param #boolean MagVar If true, also get angle in MagVar for BR/BRA
-- @return #string The BR text.
function COORDINATE:ToStringBRA( FromCoordinate, Settings, Language )
function COORDINATE:ToStringBRA( FromCoordinate, Settings, MagVar )
local DirectionVec3 = FromCoordinate:GetDirectionVec3( self )
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
local Distance = FromCoordinate:Get2DDistance( self )
local Altitude = self:GetAltitudeText()
return "BRA, " .. self:GetBRAText( AngleRadians, Distance, Settings, Language )
return "BRA, " .. self:GetBRAText( AngleRadians, Distance, Settings, nil, MagVar )
end
--- Create a BRAA NATO call string to this COORDINATE from the FromCOORDINATE. Note - BRA delivered if no aspect can be obtained and "Merged" if range < 3nm
@@ -2887,14 +2930,15 @@ do -- COORDINATE
-- @param #COORDINATE self
-- @param DCS#coalition.side Coalition The coalition.
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
-- @param #boolean MagVar If true, als get angle in magnetic
-- @return #string The BR text.
function COORDINATE:ToStringBULLS( Coalition, Settings )
function COORDINATE:ToStringBULLS( Coalition, Settings, MagVar )
local BullsCoordinate = COORDINATE:NewFromVec3( coalition.getMainRefPoint( Coalition ) )
local DirectionVec3 = BullsCoordinate:GetDirectionVec3( self )
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
local Distance = self:Get2DDistance( BullsCoordinate )
local Altitude = self:GetAltitudeText()
return "BULLS, " .. self:GetBRText( AngleRadians, Distance, Settings )
return "BULLS, " .. self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar )
end
--- Return an aspect string from a COORDINATE to the Angle of the object.
@@ -2958,7 +3002,7 @@ do -- COORDINATE
-- @param #COORDINATE self
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
-- @return #string The MGRS Text
function COORDINATE:ToStringMGRS( Settings ) --R2.1 Fixes issue #424.
function COORDINATE:ToStringMGRS( Settings )
local MGRS_Accuracy = Settings and Settings.MGRS_Accuracy or _SETTINGS.MGRS_Accuracy
local lat, lon = coord.LOtoLL( self:GetVec3() )
@@ -2970,12 +3014,13 @@ do -- COORDINATE
-- * Uses default settings in COORDINATE.
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
-- @param #COORDINATE self
-- @param #COORDINATE ReferenceCoord The refrence coordinate.
-- @param #string ReferenceName The refrence name.
-- @param #COORDINATE ReferenceCoord The reference coordinate.
-- @param #string ReferenceName The reference name.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
-- @param #boolean MagVar If true also show angle in magnetic
-- @return #string The coordinate Text in the configured coordinate system.
function COORDINATE:ToStringFromRP( ReferenceCoord, ReferenceName, Controllable, Settings )
function COORDINATE:ToStringFromRP( ReferenceCoord, ReferenceName, Controllable, Settings, MagVar )
self:F2( { ReferenceCoord = ReferenceCoord, ReferenceName = ReferenceName } )
@@ -2987,24 +3032,59 @@ do -- COORDINATE
local DirectionVec3 = ReferenceCoord:GetDirectionVec3( self )
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
local Distance = self:Get2DDistance( ReferenceCoord )
return "Targets are the last seen " .. self:GetBRText( AngleRadians, Distance, Settings ) .. " from " .. ReferenceName
return "Targets are the last seen " .. self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar ) .. " from " .. ReferenceName
else
local DirectionVec3 = ReferenceCoord:GetDirectionVec3( self )
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
local Distance = self:Get2DDistance( ReferenceCoord )
return "Target are located " .. self:GetBRText( AngleRadians, Distance, Settings ) .. " from " .. ReferenceName
return "Target are located " .. self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar ) .. " from " .. ReferenceName
end
return nil
end
--- Provides a coordinate string of the point, based on a coordinate format system:
-- * Uses default settings in COORDINATE.
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
-- @param #COORDINATE self
-- @param #COORDINATE ReferenceCoord The reference coordinate.
-- @param #string ReferenceName The reference name.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
-- @param #boolean MagVar If true also get the angle as magnetic
-- @return #string The coordinate Text in the configured coordinate system.
function COORDINATE:ToStringFromRPShort( ReferenceCoord, ReferenceName, Controllable, Settings, MagVar )
self:F2( { ReferenceCoord = ReferenceCoord, ReferenceName = ReferenceName } )
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
local IsAir = Controllable and Controllable:IsAirPlane() or false
if IsAir then
local DirectionVec3 = ReferenceCoord:GetDirectionVec3( self )
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
local Distance = self:Get2DDistance( ReferenceCoord )
return self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar ) .. " from " .. ReferenceName
else
local DirectionVec3 = ReferenceCoord:GetDirectionVec3( self )
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
local Distance = self:Get2DDistance( ReferenceCoord )
return self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar ) .. " from " .. ReferenceName
end
return nil
end
--- Provides a coordinate string of the point, based on the A2G coordinate format system.
-- @param #COORDINATE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
-- @param #boolean MagVar If true, also get angle in MagVar for BR/BRA
-- @return #string The coordinate Text in the configured coordinate system.
function COORDINATE:ToStringA2G( Controllable, Settings )
function COORDINATE:ToStringA2G( Controllable, Settings, MagVar )
self:F2( { Controllable = Controllable and Controllable:GetName() } )
@@ -3014,7 +3094,7 @@ do -- COORDINATE
-- If no Controllable is given to calculate the BR from, then MGRS will be used!!!
if Controllable then
local Coordinate = Controllable:GetCoordinate()
return Controllable and self:ToStringBR( Coordinate, Settings ) or self:ToStringMGRS( Settings )
return Controllable and self:ToStringBR( Coordinate, Settings, MagVar ) or self:ToStringMGRS( Settings )
else
return self:ToStringMGRS( Settings )
end
@@ -3038,33 +3118,34 @@ do -- COORDINATE
-- @param #COORDINATE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
-- @param #boolean MagVar If true, also get angle in MagVar for BR/BRA
-- @return #string The coordinate Text in the configured coordinate system.
function COORDINATE:ToStringA2A( Controllable, Settings, Language ) -- R2.2
function COORDINATE:ToStringA2A( Controllable, Settings, MagVar )
self:F2( { Controllable = Controllable and Controllable:GetName() } )
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
if Settings:IsA2A_BRAA() then
if Settings:IsA2A_BRAA() then
if Controllable then
local Coordinate = Controllable:GetCoordinate()
return self:ToStringBRA( Coordinate, Settings, Language )
return self:ToStringBRA( Coordinate, Settings, MagVar )
else
return self:ToStringMGRS( Settings, Language )
return self:ToStringMGRS( Settings )
end
end
if Settings:IsA2A_BULLS() then
local Coalition = Controllable:GetCoalition()
return self:ToStringBULLS( Coalition, Settings, Language )
return self:ToStringBULLS( Coalition, Settings, MagVar )
end
if Settings:IsA2A_LL_DMS() then
return self:ToStringLLDMS( Settings, Language )
return self:ToStringLLDMS( Settings )
end
if Settings:IsA2A_LL_DDM() then
return self:ToStringLLDDM( Settings, Language )
return self:ToStringLLDDM( Settings )
end
if Settings:IsA2A_MGRS() then
return self:ToStringMGRS( Settings, Language )
return self:ToStringMGRS( Settings )
end
return nil
@@ -3132,7 +3213,7 @@ do -- COORDINATE
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
-- @return #string The pressure text in the configured measurement system.
function COORDINATE:ToStringPressure( Controllable, Settings ) -- R2.3
function COORDINATE:ToStringPressure( Controllable, Settings )
self:F2( { Controllable = Controllable and Controllable:GetName() } )
@@ -3309,21 +3390,21 @@ do -- POINT_VEC3
--- Return the x coordinate of the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @return #number The x coodinate.
-- @return #number The x coordinate.
function POINT_VEC3:GetX()
return self.x
end
--- Return the y coordinate of the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @return #number The y coodinate.
-- @return #number The y coordinate.
function POINT_VEC3:GetY()
return self.y
end
--- Return the z coordinate of the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @return #number The z coodinate.
-- @return #number The z coordinate.
function POINT_VEC3:GetZ()
return self.z
end
@@ -3357,7 +3438,7 @@ do -- POINT_VEC3
--- Add to the x coordinate of the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @param #number x The x coordinate value to add to the current x coodinate.
-- @param #number x The x coordinate value to add to the current x coordinate.
-- @return #POINT_VEC3
function POINT_VEC3:AddX( x )
self.x = self.x + x
@@ -3366,7 +3447,7 @@ do -- POINT_VEC3
--- Add to the y coordinate of the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @param #number y The y coordinate value to add to the current y coodinate.
-- @param #number y The y coordinate value to add to the current y coordinate.
-- @return #POINT_VEC3
function POINT_VEC3:AddY( y )
self.y = self.y + y
@@ -3375,7 +3456,7 @@ do -- POINT_VEC3
--- Add to the z coordinate of the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @param #number z The z coordinate value to add to the current z coodinate.
-- @param #number z The z coordinate value to add to the current z coordinate.
-- @return #POINT_VEC3
function POINT_VEC3:AddZ( z )
self.z = self.z +z
@@ -3481,14 +3562,14 @@ do -- POINT_VEC2
--- Return the x coordinate of the POINT_VEC2.
-- @param #POINT_VEC2 self
-- @return #number The x coodinate.
-- @return #number The x coordinate.
function POINT_VEC2:GetX()
return self.x
end
--- Return the y coordinate of the POINT_VEC2.
-- @param #POINT_VEC2 self
-- @return #number The y coodinate.
-- @return #number The y coordinate.
function POINT_VEC2:GetY()
return self.z
end
@@ -3513,7 +3594,7 @@ do -- POINT_VEC2
--- Return Return the Lat(itude) coordinate of the POINT_VEC2 (ie: (parent)POINT_VEC3.x).
-- @param #POINT_VEC2 self
-- @return #number The x coodinate.
-- @return #number The x coordinate.
function POINT_VEC2:GetLat()
return self.x
end
@@ -3529,7 +3610,7 @@ do -- POINT_VEC2
--- Return the Lon(gitude) coordinate of the POINT_VEC2 (ie: (parent)POINT_VEC3.z).
-- @param #POINT_VEC2 self
-- @return #number The y coodinate.
-- @return #number The y coordinate.
function POINT_VEC2:GetLon()
return self.z
end

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
--- **Core** - Manages various settings for running missions, consumed by moose classes and provides a menu system for players to tweak settings in running missions.
--- **Core** - Manages various settings for missions, providing a menu for players to tweak settings in running missions.
--
-- ===
--
@@ -335,7 +335,7 @@ do -- SETTINGS
--- Sets the SETTINGS MGRS accuracy.
-- @param #SETTINGS self
-- @param #number MGRS_Accuracy
-- @param #number MGRS_Accuracy 0 to 5
-- @return #SETTINGS
function SETTINGS:SetMGRS_Accuracy( MGRS_Accuracy )
self.MGRS_Accuracy = MGRS_Accuracy

View File

@@ -167,7 +167,7 @@
--
-- * @{#SPAWN.InitRandomizePosition}(): Randomizes the position of @{Wrapper.Group}s that are spawned within a **radius band**, given an Outer and Inner radius, from the point that the spawn happens.
-- * @{#SPAWN.InitRandomizeUnits}(): Randomizes the @{Wrapper.Unit}s in the @{Wrapper.Group} that is spawned within a **radius band**, given an Outer and Inner radius.
-- * @{#SPAWN.InitRandomizeZones}(): Randomizes the spawning between a predefined list of @{Zone}s that are declared using this function. Each zone can be given a probability factor.
-- * @{#SPAWN.InitRandomizeZones}(): Randomizes the spawning between a predefined list of @{Core.Zone}s that are declared using this function. Each zone can be given a probability factor.
--
-- ### Enable / Disable AI when spawning a new @{Wrapper.Group}
--
@@ -200,13 +200,13 @@
-- * @{#SPAWN.ReSpawn}(): Re-spawn a group based on a given index.
-- * @{#SPAWN.SpawnFromVec3}(): Spawn a new group from a Vec3 coordinate. (The group will can be spawned at a point in the air).
-- * @{#SPAWN.SpawnFromVec2}(): Spawn a new group from a Vec2 coordinate. (The group will be spawned at land height ).
-- * @{#SPAWN.SpawnFromStatic}(): Spawn a new group from a structure, taking the position of a @{Static}.
-- * @{#SPAWN.SpawnFromStatic}(): Spawn a new group from a structure, taking the position of a @{Wrapper.Static}.
-- * @{#SPAWN.SpawnFromUnit}(): Spawn a new group taking the position of a @{Wrapper.Unit}.
-- * @{#SPAWN.SpawnInZone}(): Spawn a new group in a @{Zone}.
-- * @{#SPAWN.SpawnInZone}(): Spawn a new group in a @{Core.Zone}.
-- * @{#SPAWN.SpawnAtAirbase}(): Spawn a new group at an @{Wrapper.Airbase}, which can be an airdrome, ship or helipad.
--
-- Note that @{#SPAWN.Spawn} and @{#SPAWN.ReSpawn} return a @{Wrapper.Group#GROUP.New} object, that contains a reference to the DCSGroup object.
-- You can use the @{GROUP} object to do further actions with the DCSGroup.
-- You can use the @{Wrapper.Group#GROUP} object to do further actions with the DCSGroup.
--
-- ### **Scheduled** spawning methods
--
@@ -389,7 +389,7 @@ end
-- @param #SPAWN self
-- @param #table SpawnTemplate is the Template of the Group. This must be a valid Group Template structure!
-- @param #string SpawnTemplatePrefix is the name of the Group that will be given at each spawn.
-- @param #string SpawnAliasPrefix (optional) is the name that will be given to the Group at runtime.
-- @param #string SpawnAliasPrefix is the name that will be given to the Group at runtime.
-- @return #SPAWN
-- @usage
-- -- Create a new SPAWN object based on a Group Template defined from scratch.
@@ -403,7 +403,7 @@ function SPAWN:NewFromTemplate( SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPr
local self = BASE:Inherit( self, BASE:New() )
self:F( { SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPrefix } )
if SpawnAliasPrefix == nil or SpawnAliasPrefix == "" then
BASE:I( "ERROR: in function NewFromTemplate, required paramter SpawnAliasPrefix is not set" )
BASE:I( "ERROR: in function NewFromTemplate, required parameter SpawnAliasPrefix is not set" )
return nil
end
@@ -765,7 +765,7 @@ end
--- Randomizes the UNITs that are spawned within a radius band given an Outer and Inner radius.
-- @param #SPAWN self
-- @param #boolean RandomizeUnits If true, SPAWN will perform the randomization of the @{UNIT}s position within the group between a given outer and inner radius.
-- @param #boolean RandomizeUnits If true, SPAWN will perform the randomization of the @{Wrapper.Unit#UNIT}s position within the group between a given outer and inner radius.
-- @param DCS#Distance OuterRadius (optional) The outer radius in meters where the new group will be spawned.
-- @param DCS#Distance InnerRadius (optional) The inner radius in meters where the new group will NOT be spawned.
-- @return #SPAWN
@@ -813,8 +813,13 @@ end
-- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):InitLimit( 12, 150 ):SpawnScheduled( 200, 0.4 ):InitRandomizeTemplate( Spawn_US_Platoon ):InitRandomizeRoute( 3, 3, 2000 )
function SPAWN:InitRandomizeTemplate( SpawnTemplatePrefixTable )
self:F( { self.SpawnTemplatePrefix, SpawnTemplatePrefixTable } )
self.SpawnTemplatePrefixTable = SpawnTemplatePrefixTable
local temptable = {}
for _,_temp in pairs(SpawnTemplatePrefixTable) do
temptable[#temptable+1] = _temp
end
self.SpawnTemplatePrefixTable = UTILS.ShuffleTable(temptable)
self.SpawnRandomizeTemplate = true
for SpawnGroupID = 1, self.SpawnMaxGroups do
@@ -848,16 +853,12 @@ end
-- Spawn_US_Platoon_Middle = SPAWN:New( 'US Tank Platoon Middle' ):InitLimit( 12, 150 ):SpawnScheduled( 200, 0.4 ):InitRandomizeTemplateSet( Spawn_US_PlatoonSet ):InitRandomizeRoute( 3, 3, 2000 )
-- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):InitLimit( 12, 150 ):SpawnScheduled( 200, 0.4 ):InitRandomizeTemplateSet( Spawn_US_PlatoonSet ):InitRandomizeRoute( 3, 3, 2000 )
--
function SPAWN:InitRandomizeTemplateSet( SpawnTemplateSet ) -- R2.3
function SPAWN:InitRandomizeTemplateSet( SpawnTemplateSet )
self:F( { self.SpawnTemplatePrefix } )
self.SpawnTemplatePrefixTable = SpawnTemplateSet:GetSetNames()
self.SpawnRandomizeTemplate = true
for SpawnGroupID = 1, self.SpawnMaxGroups do
self:_RandomizeTemplate( SpawnGroupID )
end
local setnames = SpawnTemplateSet:GetSetNames()
self:InitRandomizeTemplate(setnames)
return self
end
@@ -906,7 +907,7 @@ end
--- This method provides the functionality to randomize the spawning of the Groups at a given list of zones of different types.
-- @param #SPAWN self
-- @param #table SpawnZoneTable A table with @{Zone} objects. If this table is given, then each spawn will be executed within the given list of @{Zone}s objects.
-- @param #table SpawnZoneTable A table with @{Core.Zone} objects. If this table is given, then each spawn will be executed within the given list of @{Core.Zone}s objects.
-- @return #SPAWN
-- @usage
--
@@ -921,8 +922,13 @@ end
--
function SPAWN:InitRandomizeZones( SpawnZoneTable )
self:F( { self.SpawnTemplatePrefix, SpawnZoneTable } )
self.SpawnZoneTable = SpawnZoneTable
local temptable = {}
for _,_temp in pairs(SpawnZoneTable) do
temptable[#temptable+1] = _temp
end
self.SpawnZoneTable = UTILS.ShuffleTable(temptable)
self.SpawnRandomizeZones = true
for SpawnGroupID = 1, self.SpawnMaxGroups do
@@ -1159,7 +1165,7 @@ do -- Delay methods
end -- Delay methods
--- Will spawn a group based on the internal index.
-- Note: Uses @{DATABASE} module defined in MOOSE.
-- Note: This method uses the global _DATABASE object (an instance of @{Core.Database#DATABASE}), which contains ALL initial and new spawned objects in MOOSE.
-- @param #SPAWN self
-- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions.
function SPAWN:Spawn()
@@ -1174,7 +1180,7 @@ function SPAWN:Spawn()
end
--- Will re-spawn a group based on a given index.
-- Note: Uses @{DATABASE} module defined in MOOSE.
-- Note: This method uses the global _DATABASE object (an instance of @{Core.Database#DATABASE}), which contains ALL initial and new spawned objects in MOOSE.
-- @param #SPAWN self
-- @param #string SpawnIndex The index of the group to be spawned.
-- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions.
@@ -1222,7 +1228,7 @@ function SPAWN:SetSpawnIndex( SpawnIndex )
end
--- Will spawn a group with a specified index number.
-- Uses @{DATABASE} global object defined in MOOSE.
-- Note: This method uses the global _DATABASE object (an instance of @{Core.Database#DATABASE}), which contains ALL initial and new spawned objects in MOOSE.
-- @param #SPAWN self
-- @param #string SpawnIndex The index of the group to be spawned.
-- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions.
@@ -2615,8 +2621,8 @@ function SPAWN:SpawnFromStatic( HostStatic, MinHeight, MaxHeight, SpawnIndex )
return nil
end
--- Will spawn a Group within a given @{Zone}.
-- The @{Zone} can be of any type derived from @{Core.Zone#ZONE_BASE}.
--- Will spawn a Group within a given @{Core.Zone}.
-- The @{Core.Zone} can be of any type derived from @{Core.Zone#ZONE_BASE}.
-- Once the @{Wrapper.Group} is spawned within the zone, the @{Wrapper.Group} will continue on its route.
-- The **first waypoint** (where the group is spawned) is replaced with the zone location coordinates.
-- @param #SPAWN self
@@ -2937,7 +2943,7 @@ function SPAWN:_GetGroupCountryID( SpawnPrefix )
end
--- Gets the Group Template from the ME environment definition.
-- This method used the @{DATABASE} object, which contains ALL initial and new spawned object in MOOSE.
-- Note: This method uses the global _DATABASE object (an instance of @{Core.Database#DATABASE}), which contains ALL initial and new spawned objects in MOOSE.
-- @param #SPAWN self
-- @param #string SpawnTemplatePrefix
-- @return @SPAWN self
@@ -3032,6 +3038,7 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2
if type( Callsign ) ~= "number" then -- blue callsign
Callsign[2] = ((SpawnIndex - 1) % 10) + 1
local CallsignName = SpawnTemplate.units[UnitID].callsign["name"] -- #string
CallsignName = string.match(CallsignName,"^(%a+)") -- 2.8 - only the part w/o numbers
local CallsignLen = CallsignName:len()
SpawnTemplate.units[UnitID].callsign["name"] = CallsignName:sub( 1, CallsignLen ) .. SpawnTemplate.units[UnitID].callsign[2] .. SpawnTemplate.units[UnitID].callsign[3]
else
@@ -3108,7 +3115,7 @@ function SPAWN:_RandomizeTemplate( SpawnIndex )
return self
end
--- Private method that randomizes the @{Zone}s where the Group will be spawned.
--- Private method that randomizes the @{Core.Zone}s where the Group will be spawned.
-- @param #SPAWN self
-- @param #number SpawnIndex
-- @return #SPAWN self

View File

@@ -57,15 +57,15 @@
-- @extends Core.Base#BASE
--- Allows to spawn dynamically new @{Static}s into your mission.
--- Allows to spawn dynamically new @{Wrapper.Static}s into your mission.
--
-- 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.
--
-- New spawned @{Static}s get **the same name** as the name of the template Static, or gets the given name when a new name is provided at the Spawn method.
-- By default, spawned @{Static}s will follow a naming convention at run-time:
-- New spawned @{Wrapper.Static}s get **the same name** as the name of the template Static, or gets the given name when a new name is provided at the Spawn method.
-- By default, spawned @{Wrapper.Static}s will follow a naming convention at run-time:
--
-- * Spawned @{Static}s will have the name _StaticName_#_nnn_, where _StaticName_ is the name of the **Template Static**, and _nnn_ is a **counter from 0 to 99999**.
-- * Spawned @{Wrapper.Static}s will have the name _StaticName_#_nnn_, where _StaticName_ is the name of the **Template Static**, and _nnn_ is a **counter from 0 to 99999**.
--
-- # SPAWNSTATIC Constructors
--
@@ -106,7 +106,7 @@
-- * @{#SPAWNSTATIC.Spawn}(Heading, NewName) spawns the static with the set parameters. Optionally, heading and name can be given. The name **must be unique**!
-- * @{#SPAWNSTATIC.SpawnFromCoordinate}(Coordinate, Heading, NewName) spawn the static at the given coordinate. Optionally, heading and name can be given. The name **must be unique**!
-- * @{#SPAWNSTATIC.SpawnFromPointVec2}(PointVec2, Heading, NewName) spawns the static at a POINT_VEC2 coordinate. Optionally, heading and name can be given. The name **must be unique**!
-- * @{#SPAWNSTATIC.SpawnFromZone}(Zone, Heading, NewName) spawns the static at the center of a @{Zone}. Optionally, heading and name can be given. The name **must be unique**!
-- * @{#SPAWNSTATIC.SpawnFromZone}(Zone, Heading, NewName) spawns the static at the center of a @{Core.Zone}. Optionally, heading and name can be given. The name **must be unique**!
--
-- @field #SPAWNSTATIC SPAWNSTATIC
--
@@ -131,7 +131,7 @@ SPAWNSTATIC = {
-- @field #number mass Cargo mass in kg.
-- @field #boolean canCargo Static can be a cargo.
--- Creates the main object to spawn a @{Static} defined in the mission editor (ME).
--- Creates the main object to spawn a @{Wrapper.Static} defined in the mission editor (ME).
-- @param #SPAWNSTATIC self
-- @param #string SpawnTemplateName Name of the static object in the ME. Each new static will have the name starting with this prefix.
-- @param DCS#country.id SpawnCountryID (Optional) The ID of the country.
@@ -158,7 +158,7 @@ function SPAWNSTATIC:NewFromStatic(SpawnTemplateName, SpawnCountryID)
return self
end
--- Creates the main object to spawn a @{Static} given a template table.
--- Creates the main object to spawn a @{Wrapper.Static} given a template table.
-- @param #SPAWNSTATIC self
-- @param #table SpawnTemplate Template used for spawning.
-- @param DCS#country.id CountryID The ID of the country. Default `country.id.USA`.
@@ -174,7 +174,7 @@ function SPAWNSTATIC:NewFromTemplate(SpawnTemplate, CountryID)
return self
end
--- Creates the main object to spawn a @{Static} from a given type.
--- Creates the main object to spawn a @{Wrapper.Static} from a given type.
-- NOTE that you have to init many other parameters as spawn coordinate etc.
-- @param #SPAWNSTATIC self
-- @param #string StaticType Type of the static.
@@ -275,7 +275,7 @@ end
--- Initialize as dead.
-- @param #SPAWNSTATIC self
-- @param #boolean IsCargo If true, this static is dead.
-- @param #boolean IsDead If true, this static is dead.
-- @return #SPAWNSTATIC self
function SPAWNSTATIC:InitDead(IsDead)
self.InitStaticDead=IsDead
@@ -336,7 +336,7 @@ function SPAWNSTATIC:Spawn(Heading, NewName)
end
--- Creates a new @{Static} from a POINT_VEC2.
--- Creates a new @{Wrapper.Static} from a POINT_VEC2.
-- @param #SPAWNSTATIC self
-- @param Core.Point#POINT_VEC2 PointVec2 The 2D coordinate where to spawn the static.
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
@@ -352,7 +352,7 @@ function SPAWNSTATIC:SpawnFromPointVec2(PointVec2, Heading, NewName)
end
--- Creates a new @{Static} from a COORDINATE.
--- Creates a new @{Wrapper.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 in degrees. Default is 0 degrees.
@@ -375,7 +375,7 @@ function SPAWNSTATIC:SpawnFromCoordinate(Coordinate, Heading, NewName)
end
--- Creates a new @{Static} from a @{Zone}.
--- Creates a new @{Wrapper.Static} from a @{Core.Zone}.
-- @param #SPAWNSTATIC self
-- @param Core.Zone#ZONE_BASE Zone The Zone where to spawn the static.
-- @param #number Heading (Optional)The heading of the static in degrees. Default is the heading of the template.
@@ -467,7 +467,7 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
self:T(Template)
-- Add static to the game.
local Static=nil
local Static=nil --DCS#StaticObject
if self.InitFarp then
@@ -487,6 +487,17 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
-- ED's dirty way to spawn FARPS.
Static=coalition.addGroup(CountryID, -1, TemplateGroup)
-- Currently DCS 2.8 does not trigger birth events if FAPRS are spawned!
-- We create such an event. The airbase is registered in Core.Event
local Event = {
id = EVENTS.Birth,
time = timer.getTime(),
initiator = Static
}
-- Create BIRTH event.
world.onEvent(Event)
else
self:T("Spawning Static")
self:T2({Template=Template})

View File

@@ -249,8 +249,10 @@ do
local RecceDcsUnit = self.Recce:GetDCSObject()
self.SpotIR = Spot.createInfraRed( RecceDcsUnit, { x = 0, y = 2, z = 0 }, Target:GetPointVec3():AddY(1):GetVec3() )
self.SpotLaser = Spot.createLaser( RecceDcsUnit, { x = 0, y = 2, z = 0 }, Target:GetPointVec3():AddY(1):GetVec3(), LaserCode )
local relativespot = self.relstartpos or { x = 0, y = 2, z = 0 }
self.SpotIR = Spot.createInfraRed( RecceDcsUnit, relativespot, Target:GetPointVec3():AddY(1):GetVec3() )
self.SpotLaser = Spot.createLaser( RecceDcsUnit, relativespot, Target:GetPointVec3():AddY(1):GetVec3(), LaserCode )
if Duration then
self.ScheduleID = self.LaseScheduler:Schedule( self, StopLase, {self}, Duration )
@@ -368,4 +370,16 @@ do
return self.Lasing
end
end
--- Set laser start position relative to the lasing unit.
-- @param #SPOT self
-- @param #table position Start position of the laser relative to the lasing unit. Default is { x = 0, y = 2, z = 0 }
-- @return #SPOT self
-- @usage
-- -- Set lasing position to be the position of the optics of the Gazelle M:
-- myspot:SetRelativeStartPosition({ x = 1.7, y = 1.2, z = 0 })
function SPOT:SetRelativeStartPosition(position)
self.relstartpos = position or { x = 0, y = 2, z = 0 }
return self
end
end

View File

@@ -1,4 +1,4 @@
--- **Core** - TEXTANDSOUND (MOOSE gettext) system
--- **Core** - A Moose GetText system.
--
-- ===
--

View File

@@ -155,7 +155,7 @@ function TIMER:New(Function, ...)
return self
end
--- Create a new TIMER object.
--- Start TIMER object.
-- @param #TIMER self
-- @param #number Tstart Relative start time in seconds.
-- @param #number dT Interval between function calls in seconds. If not specified `nil`, the function is called only once.
@@ -192,6 +192,20 @@ function TIMER:Start(Tstart, dT, Duration)
return self
end
--- Start TIMER object if a condition is met. Useful for e.g. debugging.
-- @param #TIMER self
-- @param #boolean Condition Must be true for the TIMER to start
-- @param #number Tstart Relative start time in seconds.
-- @param #number dT Interval between function calls in seconds. If not specified `nil`, the function is called only once.
-- @param #number Duration Time in seconds for how long the timer is running. If not specified `nil`, the timer runs forever or until stopped manually by the `TIMER:Stop()` function.
-- @return #TIMER self
function TIMER:StartIf(Condition,Tstart, dT, Duration)
if Condition then
self:Start(Tstart, dT, Duration)
end
return self
end
--- Stop the timer by removing the timer function.
-- @param #TIMER self
-- @param #number Delay (Optional) Delay in seconds, before the timer is stopped.

View File

@@ -35,13 +35,13 @@ do -- UserFlag
ClassName = "USERFLAG",
UserFlagName = nil,
}
--- 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
@@ -52,7 +52,7 @@ do -- UserFlag
--- Get the userflag name.
-- @param #USERFLAG self
-- @return #string Name of the user flag.
function USERFLAG:GetName()
function USERFLAG:GetName()
return self.UserFlagName
end
@@ -66,18 +66,17 @@ do -- UserFlag
-- BlueVictory:Set( 100 ) -- Set the UserFlag VictoryBlue to 100.
--
function USERFLAG:Set( Number, Delay ) --R2.3
if Delay and Delay>0 then
self:ScheduleOnce(Delay, USERFLAG.Set, self, Number)
else
--env.info(string.format("Setting flag \"%s\" to %d at T=%.1f", self.UserFlagName, Number, timer.getTime()))
trigger.action.setUserFlag( self.UserFlagName, Number )
end
return self
end
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.
@@ -86,12 +85,10 @@ do -- UserFlag
-- local BlueVictoryValue = BlueVictory:Get() -- Get the UserFlag VictoryBlue value.
--
function USERFLAG:Get() --R2.3
return trigger.misc.getUserFlag( self.UserFlagName )
end
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.
@@ -102,9 +99,9 @@ do -- UserFlag
-- return "Blue has won"
-- end
function USERFLAG:Is( Number ) --R2.3
return trigger.misc.getUserFlag( self.UserFlagName ) == Number
end
end
end

View File

@@ -54,7 +54,7 @@ do -- Velocity
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.
@@ -70,12 +70,12 @@ do -- Velocity
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
@@ -87,7 +87,7 @@ do -- Velocity
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.
@@ -95,8 +95,7 @@ do -- Velocity
return UTILS.MpsToMiph( self.Velocity )
end
--- Get the velocity in text, according the player @{Settings}.
--- Get the velocity in text, according the player @{Core.Settings}.
-- @param #VELOCITY self
-- @param Core.Settings#SETTINGS Settings
-- @return #string The velocity in text.
@@ -113,11 +112,11 @@ do -- Velocity
end
end
--- Get the velocity in text, according the player or default @{Settings}.
--- Get the velocity in text, according the player or default @{Core.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}
-- @return #string The velocity in text according the player or default @{Core.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
@@ -134,7 +133,7 @@ do -- VELOCITY_POSITIONABLE
--- # 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.
-- @{#VELOCITY_POSITIONABLE} monitors the speed of a @{Wrapper.Positionable#POSITIONABLE} in the simulation, which can be expressed in various formats according the Settings.
--
-- ## 1. VELOCITY_POSITIONABLE constructor
--
@@ -167,7 +166,7 @@ do -- VELOCITY_POSITIONABLE
-- @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
@@ -178,9 +177,9 @@ do -- VELOCITY_POSITIONABLE
return UTILS.MpsToMiph( self.Positionable:GetVelocityMPS() or 0 )
end
--- Get the velocity in text, according the player or default @{Settings}.
--- Get the velocity in text, according the player or default @{Core.Settings}.
-- @param #VELOCITY_POSITIONABLE self
-- @return #string The velocity in text according the player or default @{Settings}
-- @return #string The velocity in text according the player or default @{Core.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

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,8 @@
--- **Core** - The ZONE_DETECTION class, defined by a zone name, a detection object and a radius.
-- @module Core.Zone_Detection
-- @image MOOSE.JPG
--- The ZONE_DETECTION class, defined by a zone name, a detection object and a radius.
-- @type ZONE_DETECTION
--- @type ZONE_DETECTION
-- @field DCS#Vec2 Vec2 The current location of the zone.
-- @field DCS#Distance Radius The radius of the zone.
-- @extends #ZONE_BASE
@@ -29,7 +31,7 @@ function ZONE_DETECTION:New( ZoneName, Detection, Radius )
self.Detection = Detection
self.Radius = Radius
return self
end
@@ -48,15 +50,14 @@ function ZONE_DETECTION:BoundZone( Points, CountryID, UnBound )
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",

View File

@@ -1,4 +1,6 @@
--- **DCS API** Prototypes
--- **DCS API** Prototypes.
--
-- ===
--
-- See the [Simulator Scripting Engine Documentation](https://wiki.hoggitworld.com/view/Simulator_Scripting_Engine_Documentation) on Hoggit for further explanation and examples.
--
@@ -306,6 +308,11 @@ do -- country
-- @field Argentinia
-- @field Cyprus
-- @field Slovenia
-- @field BOLIVIA
-- @field GHANA
-- @field NIGERIA
-- @field PERU
-- @field ECUADOR
country = {} --#country
@@ -334,9 +341,23 @@ do -- coalition
-- @field RED
-- @field BLUE
--- @function [parent=#coalition] getCountryCoalition
-- @param #number countryId
-- @return #number coalitionId
--- Get country coalition.
-- @function [parent=#coalition] getCountryCoalition
-- @param #number countryId Country ID.
-- @return #number coalitionId Coalition ID.
--- Dynamically spawns a group. See [hoggit](https://wiki.hoggitworld.com/view/DCS_func_addGroup)
-- @function [parent=#coalition] addGroup
-- @param #number countryId Id of the country.
-- @param #number groupCategory Group category. Set -1 for spawning FARPS.
-- @param #table groupData Group data table.
-- @return DCS#Group The spawned Group object.
--- Dynamically spawns a static object. See [hoggit](https://wiki.hoggitworld.com/view/DCS_func_addGroup)
-- @function [parent=#coalition] addStaticObject
-- @param #number countryId Id of the country.
-- @param #table groupData Group data table.
-- @return DCS#Static The spawned static object.
coalition = {} -- #coalition
@@ -1287,6 +1308,42 @@ do -- Group
end -- Group
do -- StaticObject
--- Represents a static object.
-- @type StaticObject
-- @extends DCS#Object
--- Returns the static object.
-- @function [parent=#StaticObject] getByName
-- @param #string name Name of the static object.
-- @return #StaticObject
StaticObject = {} --#StaticObject
end
do --Event
--- Event structure. Note that present fields depend on type of event.
-- @type Event
-- @field #number id Event ID.
-- @field #number time Mission time in seconds.
-- @field DCS#Unit initiator Unit initiating the event.
-- @field DCS#Unit target Target unit.
-- @field DCS#Airbase place Airbase.
-- @field number subPlace Subplace. Unknown and often just 0.
-- @field #string weapon_name Weapoin name.
-- @field #number idx Mark ID.
-- @field #number coalition Coalition ID.
-- @field #number groupID Group ID, *e.g.* of group that added mark point.
-- @field #string text Text, *e.g.* of mark point.
-- @field DCS#Vec3 pos Position vector, *e.g.* of mark point.
-- @field #string comment Comment, *e.g.* LSO score.
Event={} --#Event
end
do -- AI

View File

@@ -1,4 +1,4 @@
--- **Functional** -- Monitor airbase traffic and regulate speed while taxiing.
--- **Functional** - Monitor airbase traffic and regulate speed while taxiing.
--
-- ===
--

View File

@@ -30,7 +30,7 @@
-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536)
--
-- ====
-- @module Functional.Arty
-- @module Functional.Artillery
-- @image Artillery.JPG
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -108,7 +108,7 @@
--- Enables mission designers easily to assign targets for artillery units. Since the implementation is based on a Finite State Model (FSM), the mission designer can
-- interact with the process at certain events or states.
--
-- A new ARTY object can be created with the @{#ARTY.New}(*group*) contructor.
-- A new ARTY object can be created with the @{#ARTY.New}(*group*) constructor.
-- The parameter *group* has to be a MOOSE Group object and defines ARTY group.
--
-- The ARTY FSM process can be started by the @{#ARTY.Start}() command.
@@ -146,7 +146,7 @@
-- When a new target is assigned via the @{#ARTY.AssignTargetCoord}() function (see below), the **NewTarget** event is triggered.
--
-- ## Assigning Targets
-- Assigning targets is a central point of the ARTY class. Multiple targets can be assigned simultanioulsly and are put into a queue.
-- Assigning targets is a central point of the ARTY class. Multiple targets can be assigned simultaneously and are put into a queue.
-- Of course, targets can be added at any time during the mission. For example, once they are detected by a reconnaissance unit.
--
-- In order to add a target, the function @{#ARTY.AssignTargetCoord}(*coord*, *prio*, *radius*, *nshells*, *maxengage*, *time*, *weapontype*, *name*) has to be used.
@@ -161,7 +161,7 @@
-- * *maxengage*: Number of times a target is engaged.
-- * *time*: Time of day the engagement is schedule in the format "hh:mm:ss" for hh=hours, mm=minutes, ss=seconds.
-- For example "10:15:35". In the case the attack will be executed at a quarter past ten in the morning at the day the mission started.
-- If the engagement should start on the following day the format can be specified as "10:15:35+1", where the +1 denots the following day.
-- If the engagement should start on the following day the format can be specified as "10:15:35+1", where the +1 denotes the following day.
-- This is useful for longer running missions or if the mission starts at 23:00 hours and the attack should be scheduled at 01:00 hours on the following day.
-- Of course, later days are also possible by appending "+2", "+3", etc.
-- **Note** that the time has to be given as a string. So the enclosing quotation marks "" are important.
@@ -179,7 +179,7 @@
-- Let's first consider the case that none of the targets is scheduled to be executed at a certain time (*time*=nil).
-- The ARTY group will first engage the target with higher priority (*prio*=10). After the engagement is finished, the target with lower priority is attacked.
-- This is because the target with lower prio has been attacked one time less. After the attack on the lower priority task is finished and both targets
-- have been engaged equally often, the target with the higher priority is engaged again. This coninues until a target has engaged three times.
-- have been engaged equally often, the target with the higher priority is engaged again. This continues until a target has engaged three times.
-- Once the maximum number of engagements is reached, the target is deleted from the queue.
--
-- In other words, the queue is first sorted with respect to the number of engagements and targets with the same number of engagements are sorted with
@@ -190,7 +190,7 @@
-- As mentioned above, targets can be engaged at a specific time of the day via the *time* parameter.
--
-- If the *time* parameter is specified for a target, the first engagement of that target will happen at that time of the day and not before.
-- This also applies when multiple engagements are requested via the *maxengage* parameter. The first attack will not happen before the specifed time.
-- This also applies when multiple engagements are requested via the *maxengage* parameter. The first attack will not happen before the specified time.
-- When that timed attack is finished, the *time* parameter is deleted and the remaining engagements are carried out in the same manner as for untimed targets (described above).
--
-- Of course, it can happen that a scheduled task should be executed at a time, when another target is already under attack.
@@ -201,7 +201,7 @@
--
-- ## Determining the Amount of Ammo
--
-- In order to determin when a unit is out of ammo and possible initiate the rearming process it is necessary to know which types of weapons have to be counted.
-- In order to determine when a unit is out of ammo and possible initiate the rearming process it is necessary to know which types of weapons have to be counted.
-- For most artillery unit types, this is simple because they only have one type of weapon and hence ammunition.
--
-- However, there are more complex scenarios. For example, naval units carry a big arsenal of different ammunition types ranging from various cannon shell types
@@ -217,7 +217,7 @@
-- **Note** that the default parameters "weapons.shells", "weapons.nurs", "weapons.missiles" **should in priciple** capture all the corresponding ammo types.
-- However, the logic searches for the string "weapon.missies" in the ammo type. Especially for missiles, this string is often not contained in the ammo type descriptor.
--
-- One way to determin which types of ammo the unit carries, one can use the debug mode of the arty class via @{#ARTY.SetDebugON}().
-- One way to determine which types of ammo the unit carries, one can use the debug mode of the arty class via @{#ARTY.SetDebugON}().
-- In debug mode, the all ammo types of the group are printed to the monitor as message and can be found in the DCS.log file.
--
-- ## Employing Selected Weapons
@@ -274,7 +274,7 @@
--
-- ## Simulated Weapons
--
-- In addtion to the standard weapons a group has available some special weapon types that are not possible to use in the native DCS environment are simulated.
-- In addition to the standard weapons a group has available some special weapon types that are not possible to use in the native DCS environment are simulated.
--
-- ### Tactical Nukes
--
@@ -283,9 +283,9 @@
--
-- By default, they group does not have any nukes available. To give the group the ability the function @{#ARTY.SetTacNukeShells}(*n*) can be used.
-- This supplies the group with *n* nuclear shells, where *n* is restricted to the number of conventional shells the group can carry.
-- Note that the group must always have convenctional shells left in order to fire a nuclear shell.
-- Note that the group must always have conventional shells left in order to fire a nuclear shell.
--
-- The default explostion strength is 0.075 kilo tons TNT. The can be changed with the @{#ARTY.SetTacNukeWarhead}(*strength*), where *strength* is given in kilo tons TNT.
-- The default explosion strength is 0.075 kilo tons TNT. The can be changed with the @{#ARTY.SetTacNukeWarhead}(*strength*), where *strength* is given in kilo tons TNT.
--
-- ### Illumination Shells
--
@@ -301,12 +301,12 @@
--
-- ### Smoke Shells
--
-- In a similar way to illumination shells, ARTY groups can also employ smoke shells. The numer of smoke shells the group has available is set by the function
-- In a similar way to illumination shells, ARTY groups can also employ smoke shells. The number of smoke shells the group has available is set by the function
-- @{#ARTY.SetSmokeShells}(*n*, *color*), where *n* is the number of shells and *color* defines the smoke color. Default is SMOKECOLOR.Red.
--
-- The weapon type to be used in the @{#ARTY.AssignTargetCoord}() function is *ARTY.WeaponType.SmokeShells*.
--
-- The explosive shell the group fired is destroyed shortly before its impact on the ground and smoke of the speficied color is triggered at that position.
-- The explosive shell the group fired is destroyed shortly before its impact on the ground and smoke of the specified color is triggered at that position.
--
--
-- ## Assignments via Markers on F10 Map
@@ -320,15 +320,15 @@
-- ### Target Assignments
-- A new target can be assigned by writing **arty engage** in the marker text.
-- This is followed by a **comma separated list** of (optional) keywords and parameters.
-- First, it is important to address the ARTY group or groups that should engage. This can be done in numrous ways. The keywords are *battery*, *alias*, *cluster*.
-- First, it is important to address the ARTY group or groups that should engage. This can be done in numerous ways. The keywords are *battery*, *alias*, *cluster*.
-- It is also possible to address all ARTY groups by the keyword *everyone* or *allbatteries*. These two can be used synonymously.
-- **Note that**, if no battery is assigned nothing will happen.
--
-- * *everyone* or *allbatteries* The target is assigned to all batteries.
-- * *battery* Name of the ARTY group that the target is assigned to. Note that **the name is case sensitive** and has to be given in quotation marks. Default is all ARTY groups of the right coalition.
-- * *alias* Alias of the ARTY group that the target is assigned to. The alias is **case sensitive** and needs to be in quotation marks.
-- * *cluster* The cluster of ARTY groups that is addessed. Clusters can be defined by the function @{#ARTY.AddToCluster}(*clusters*). Names are **case sensitive** and need to be in quotation marks.
-- * *key* A number to authorize the target assignment. Only specifing the correct number will trigger an engagement.
-- * *cluster* The cluster of ARTY groups that is addressed. Clusters can be defined by the function @{#ARTY.AddToCluster}(*clusters*). Names are **case sensitive** and need to be in quotation marks.
-- * *key* A number to authorize the target assignment. Only specifying the correct number will trigger an engagement.
-- * *time* Time for which which the engagement is schedules, e.g. 08:42. Default is as soon as possible.
-- * *prio* Priority of the engagement as number between 1 (high prio) and 100 (low prio). Default is 50, i.e. medium priority.
-- * *shots* Number of shots (shells, rockets or missiles) fired at each engagement. Default is 5.
@@ -353,8 +353,8 @@
-- arty engage, battery "Paladin Alpha", weapon nukes, shots 1, time 20:15
-- arty engage, battery "Horwitzer 1", lldms 41:51:00N 41:47:58E
--
-- Note that the keywords and parameters are *case insensitve*. Only exception are the battery, alias and cluster names.
-- These must be exactly the same as the names of the goups defined in the mission editor or the aliases and cluster names defined in the script.
-- Note that the keywords and parameters are *case insensitive*. Only exception are the battery, alias and cluster names.
-- These must be exactly the same as the names of the groups defined in the mission editor or the aliases and cluster names defined in the script.
--
-- ### Relocation Assignments
--
@@ -363,11 +363,11 @@
-- * *time* Time for which which the relocation/move is schedules, e.g. 08:42. Default is as soon as possible.
-- * *speed* The speed in km/h the group will drive at. Default is 70% of its max possible speed.
-- * *on road* Group will use mainly roads. Default is off, i.e. it will go in a straight line from its current position to the assigned coordinate.
-- * *canceltarget* Group will cancel all running firing engagements and immidiately start to move. Default is that group will wait until is current assignment is over.
-- * *canceltarget* Group will cancel all running firing engagements and immediately start to move. Default is that group will wait until is current assignment is over.
-- * *battery* Name of the ARTY group that the relocation is assigned to.
-- * *alias* Alias of the ARTY group that the target is assigned to. The alias is **case sensitive** and needs to be in quotation marks.
-- * *cluster* The cluster of ARTY groups that is addessed. Clusters can be defined by the function @{#ARTY.AddToCluster}(*clusters*). Names are **case sensitive** and need to be in quotation marks.
-- * *key* A number to authorize the target assignment. Only specifing the correct number will trigger an engagement.
-- * *cluster* The cluster of ARTY groups that is addressed. Clusters can be defined by the function @{#ARTY.AddToCluster}(*clusters*). Names are **case sensitive** and need to be in quotation marks.
-- * *key* A number to authorize the target assignment. Only specifying the correct number will trigger an engagement.
-- * *lldms* Specify the coordinates in Lat/Long degrees, minutes and seconds format. The actual location of the marker is unimportant. The group will move to the coordinates given in the lldms keyword.
-- Format is DD:MM:SS[N,S] DD:MM:SS[W,E]. See example below.
-- * *readonly* Marker cannot be deleted by users any more. Hence, assignment cannot be cancelled by removing the marker.
@@ -410,12 +410,12 @@
--
-- A few options can be set by marks. The corresponding keyword is **arty set**. This can be used to define the rearming place and group for a battery.
--
-- To set the reamring place of a group at the marker position type
-- To set the rearming place of a group at the marker position type
-- arty set, battery "Paladin Alpha", rearming place
--
-- Setting the rearming group is independent of the position of the mark. Just create one anywhere on the map and type
-- arty set, battery "Mortar Bravo", rearming group "Ammo Truck M818"
-- Note that the name of the rearming group has to be given in quotation marks and spellt exactly as the group name defined in the mission editor.
-- Note that the name of the rearming group has to be given in quotation marks and spelt exactly as the group name defined in the mission editor.
--
-- ## Transporting
--
@@ -3422,7 +3422,7 @@ function ARTY:onafterMove(Controllable, From, Event, To, move)
-- Set current move.
self.currentMove=move
-- Route group to coodinate.
-- Route group to coordinate.
self:_Move(self.Controllable, move.coord, move.speed, move.onroad)
end

View File

@@ -1,4 +1,4 @@
--- **Functional** -- Keep airbases clean of crashing or colliding airplanes, and kill missiles when being fired at airbases.
--- **Functional** - Keep airbases clean of crashing or colliding airplanes, and kill missiles when being fired at airbases.
--
-- ===
--

View File

@@ -1,4 +1,4 @@
--- **Functional** -- Management of target **Designation**. Lase, smoke and illuminate targets.
--- **Functional** - Management of target **Designation**. Lase, smoke and illuminate targets.
--
-- ===
--
@@ -48,7 +48,7 @@
--
-- ![Banner Image](..\Presentations\DESIGNATE\Dia3.JPG)
--
-- A typical mission setup would require Recce (a @{Set} of Recce) to be detecting potential targets.
-- A typical mission setup would require Recce (a @{Core.Set} of Recce) to be detecting potential targets.
-- The DetectionObject will group the detected targets based on the detection method being used.
-- Possible detection methods could be by Area, by Type or by Unit.
-- Each grouping will result in a **TargetGroup**, for terminology and clarity we will use this term throughout the document.
@@ -276,7 +276,7 @@ do -- DESIGNATE
-- # 7. Designate Menu Location for a Mission
--
-- You can make DESIGNATE work for a @{Tasking.Mission#MISSION} object. In this way, the designate menu will not appear in the root of the radio menu, but in the menu of the Mission.
-- Use the method @{#DESIGNATE.SetMission}() to set the @{Mission} object for the designate function.
-- Use the method @{#DESIGNATE.SetMission}() to set the @{Tasking.Mission} object for the designate function.
--
-- # 8. Status Report
--

View File

@@ -1,4 +1,4 @@
--- **Functional** -- Models the detection of enemy units by FACs or RECCEs and group them according various methods.
--- **Functional** - Models the detection of enemy units by FACs or RECCEs and group them according various methods.
--
-- ===
--
@@ -40,7 +40,7 @@
do -- DETECTION_BASE
--- @type DETECTION_BASE
-- @field Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role.
-- @field Core.Set#SET_GROUP DetectionSetGroup The @{Core.Set} of GROUPs in the Forward Air Controller role.
-- @field DCS#Distance DetectionRange The range till which targets are accepted to be detected.
-- @field #DETECTION_BASE.DetectedObjects DetectedObjects The list of detected objects.
-- @field #table DetectedObjectsIdentified Map of the DetectedObjects identified.
@@ -318,7 +318,7 @@ do -- DETECTION_BASE
--- DETECTION constructor.
-- @param #DETECTION_BASE self
-- @param Core.Set#SET_GROUP DetectionSet The @{Set} of @{Group}s that is used to detect the units.
-- @param Core.Set#SET_GROUP DetectionSet The @{Core.Set} of @{Wrapper.Group}s that is used to detect the units.
-- @return #DETECTION_BASE self
function DETECTION_BASE:New( DetectionSet )
@@ -1982,7 +1982,7 @@ do -- DETECTION_UNITS
--- Will detect units within the battle zone.
--
-- It will build a DetectedItems list filled with DetectedItems. Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{UNIT} object reference.
-- It will build a DetectedItems list filled with DetectedItems. Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{Wrapper.Unit#UNIT} object reference.
-- Beware that when the amount of units detected is large, the DetectedItems list will be large also.
--
-- @field #DETECTION_UNITS
@@ -1993,7 +1993,7 @@ do -- DETECTION_UNITS
--- DETECTION_UNITS constructor.
-- @param Functional.Detection#DETECTION_UNITS self
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role.
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Core.Set} of GROUPs in the Forward Air Controller role.
-- @return Functional.Detection#DETECTION_UNITS self
function DETECTION_UNITS:New( DetectionSetGroup )
@@ -2237,7 +2237,7 @@ do -- DETECTION_TYPES
--- Will detect units within the battle zone.
-- It will build a DetectedItems[] list filled with DetectedItems, grouped by the type of units detected.
-- Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{UNIT} object reference.
-- Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{Wrapper.Unit#UNIT} object reference.
-- Beware that when the amount of different types detected is large, the DetectedItems[] list will be large also.
--
-- @field #DETECTION_TYPES
@@ -2248,7 +2248,7 @@ do -- DETECTION_TYPES
--- DETECTION_TYPES constructor.
-- @param Functional.Detection#DETECTION_TYPES self
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Recce role.
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Core.Set} of GROUPs in the Recce role.
-- @return Functional.Detection#DETECTION_TYPES self
function DETECTION_TYPES:New( DetectionSetGroup )
@@ -2436,7 +2436,7 @@ do -- DETECTION_AREAS
--- @type DETECTION_AREAS
-- @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.
-- @field #DETECTION_BASE.DetectedItems DetectedItems A list of areas containing the set of @{Wrapper.Unit}s, @{Core.Zone}s, the center @{Wrapper.Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
-- @extends Functional.Detection#DETECTION_BASE
--- Detect units within the battle zone for a list of @{Wrapper.Group}s detecting targets following (a) detection method(s),
@@ -2477,7 +2477,7 @@ do -- DETECTION_AREAS
--- DETECTION_AREAS constructor.
-- @param #DETECTION_AREAS self
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role.
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Core.Set} of GROUPs in the Forward Air Controller role.
-- @param DCS#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
-- @return #DETECTION_AREAS
function DETECTION_AREAS:New( DetectionSetGroup, DetectionZoneRange )
@@ -2498,7 +2498,7 @@ do -- DETECTION_AREAS
--- Retrieve set of detected zones.
-- @param #DETECTION_AREAS self
-- @return Core.Set#SET_ZONE The @{Set} of ZONE_UNIT objects detected.
-- @return Core.Set#SET_ZONE The @{Core.Set} of ZONE_UNIT objects detected.
function DETECTION_AREAS:GetDetectionZones()
local zoneset = SET_ZONE:New()
for _ID,_Item in pairs (self.DetectedItems) do

View File

@@ -1,8 +1,12 @@
--- **Functional** - Captures the class DETECTION_ZONES.
-- @module Functional.DetectionZones
-- @image MOOSE.JPG
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.
-- @field #DETECTION_BASE.DetectedItems DetectedItems A list of areas containing the set of @{Wrapper.Unit}s, @{Core.Zone}s, the center @{Wrapper.Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
-- @extends Functional.Detection#DETECTION_BASE
--- (old, to be revised ) Detect units within the battle zone for a list of @{Core.Zone}s detecting targets following (a) detection method(s),
@@ -40,27 +44,27 @@ do -- 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 Core.Set#SET_ZONE DetectionSetZone The @{Core.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

View File

@@ -1,4 +1,4 @@
--- **Functional** -- Taking the lead of AI escorting your flight.
--- **Functional** - Taking the lead of AI escorting your flight.
--
-- ===
--

View File

@@ -1,4 +1,4 @@
--- **Functional** - (R2.5) - Yet Another Missile Trainer.
--- **Functional** - Yet Another Missile Trainer.
--
--
-- Practice to evade missiles without being destroyed.
@@ -20,7 +20,7 @@
-- ===
--
-- ### Author: **funkyfranky**
-- @module Functional.FOX
-- @module Functional.Fox
-- @image Functional_FOX.png
--- FOX class.
@@ -492,7 +492,6 @@ end
--- Disable F10 menu for all players.
-- @param #FOX self
-- @param #boolean switch If true debug mode on. If false/nil debug mode off
-- @return #FOX self
function FOX:SetDisableF10Menu()
@@ -501,6 +500,16 @@ function FOX:SetDisableF10Menu()
return self
end
--- Enable F10 menu for all players.
-- @param #FOX self
-- @return #FOX self
function FOX:SetEnableF10Menu()
self.menudisabled=false
return self
end
--- Set default player setting for missile destruction.
-- @param #FOX self
-- @param #boolean switch If true missiles are destroyed. If false/nil missiles are not destroyed.
@@ -1162,7 +1171,7 @@ function FOX:OnEventBirth(EventData)
-- Add F10 radio menu for player.
if not self.menudisabled then
self:ScheduleOnce(0.1, FOX._AddF10Commands, self, _unitname)
self:ScheduleOnce(0.1, self._AddF10Commands, self, _unitName)
end
-- Player data.
@@ -1429,10 +1438,10 @@ function FOX:_AddF10Commands(_unitName)
end
else
self:E(self.lid..string.format("ERROR: Could not find group or group ID in AddF10Menu() function. Unit name: %s.", _unitName))
self:E(self.lid..string.format("ERROR: Could not find group or group ID in AddF10Menu() function. Unit name: %s.", _unitName or "unknown"))
end
else
self:E(self.lid..string.format("ERROR: Player unit does not exist in AddF10Menu() function. Unit name: %s.", _unitName))
self:E(self.lid..string.format("ERROR: Player unit does not exist in AddF10Menu() function. Unit name: %s.", _unitName or "unknown"))
end
end

View File

@@ -1,11 +1,13 @@
--- **Functional** -- Modular, Automatic and Network capable Targeting and Interception System for Air Defenses
--- **Functional** - Modular, Automatic and Network capable Targeting and Interception System for Air Defenses.
--
-- ===
--
-- **MANTIS** - Moose derived Modular, Automatic and Network capable Targeting and Interception System
-- Controls a network of SAM sites. Uses detection to switch on the AA site closest to the enemy.
-- Automatic mode (default since 0.8) can set-up your SAM site network automatically for you.
-- Leverage evasiveness from SEAD, leverage attack range setting.
-- ## Features:
--
-- * Moose derived Modular, Automatic and Network capable Targeting and Interception System.
-- * Controls a network of SAM sites. Uses detection to switch on the AA site closest to the enemy.
-- * Automatic mode (default since 0.8) can set-up your SAM site network automatically for you.
-- * Leverage evasiveness from SEAD, leverage attack range setting.
--
-- ===
--
@@ -20,7 +22,7 @@
-- @module Functional.Mantis
-- @image Functional.Mantis.jpg
--
-- Date: Dec 2021
-- Last Update: Oct 2022
-------------------------------------------------------------------------
--- **MANTIS** class, extends Core.Base#BASE
@@ -61,10 +63,11 @@
--- *The worst thing that can happen to a good cause is, not to be skillfully attacked, but to be ineptly defended.* - Frédéric Bastiat
--
-- Simple Class for a more intelligent Air Defense System
-- Moose class for a more intelligent Air Defense System
--
-- #MANTIS
-- Moose derived Modular, Automatic and Network capable Targeting and Interception System.
-- # MANTIS
--
-- * Moose derived Modular, Automatic and Network capable Targeting and Interception System.
-- * Controls a network of SAM sites. Uses detection to switch on the SAM site closest to the enemy.
-- * **Automatic mode** (default since 0.8) can set-up your SAM site network automatically for you
-- * **Classic mode** behaves like before
@@ -100,9 +103,11 @@
-- * Roland
-- * Silkworm (though strictly speaking this is a surface to ship missile)
-- * SA-2, SA-3, SA-5, SA-6, SA-7, SA-8, SA-9, SA-10, SA-11, SA-13, SA-15, SA-19
-- * and from HDS (see note below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2
-- * From HDS (see note on HDS below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2
-- * From SMA: RBS98M, RBS70, RBS90, RBS90M, RBS103A, RBS103B, RBS103AM, RBS103BM, Lvkv9040M
-- **NOTE** If you are using the Swedish Military Assets (SMA), please note that the **group name** for RBS-SAM types also needs to contain the keyword "SMA"
--
-- Following the example started above, an SA-6 site group name should start with "Red SAM SA-6" then, or a blue Patriot installation with e.g. "Blue SAM Patriot".
-- Following the example started above, an SA-6 site group name should start with "Red SAM SA-6" then, or a blue Patriot installation with e.g. "Blue SAM Patriot".
-- **NOTE** If you are using the High-Digit-Sam Mod, please note that the **group name** for the following SAM types also needs to contain the keyword "HDS":
--
-- * SA-2 (with V759 missile, e.g. "Red SAM SA-2 HDS")
@@ -211,7 +216,7 @@
-- * grouping = 5000 (meters) - Detection (EWR) will group enemy flights to areas of 5km for tracking - `MANTIS:SetEWRGrouping(radius)`
-- * detectinterval = 30 (seconds) - MANTIS will decide every 30 seconds which SAM to activate - `MANTIS:SetDetectInterval(interval)`
-- * engagerange = 95 (percent) - SAMs will only fire if flights are inside of a 95% radius of their max firerange - `MANTIS:SetSAMRange(range)`
-- * dynamic = false - Group filtering is set to once, i.e. newly added groups will not be part of the setup by default - `MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic)`
-- * dynamic = false - Group filtering is set to once, i.e. newly added groups will not be part of the setup by default - `MANTIS:New(name,samprefix,ewrprefix,hq,coalition,dynamic)`
-- * autorelocate = false - HQ and (mobile) EWR system will not relocate in random intervals between 30mins and 1 hour - `MANTIS:SetAutoRelocate(hq, ewr)`
-- * debug = false - Debugging reports on screen are set to off - `MANTIS:Debug(onoff)`
--
@@ -387,6 +392,29 @@ MANTIS.SamDataHDS = {
["HQ-2 HDS"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" },
}
--- SAM data SMA
-- @type MANTIS.SamDataSMA
-- @field #number Range Max firing range in km
-- @field #number Blindspot no-firing range (green circle)
-- @field #number Height Max firing height in km
-- @field #string Type #MANTIS.SamType of SAM, i.e. SHORT, MEDIUM or LONG (range)
-- @field #string Radar Radar typename on unit level (used as key)
MANTIS.SamDataSMA = {
-- units from SMA Mod (Sweedish Military Assets)
-- https://forum.dcs.world/topic/295202-swedish-military-assets-for-dcs-by-currenthill/
-- group name MUST contain SMA to ID launcher type correctly!
["RBS98M SMA"] = { Range=20, Blindspot=0, Height=8, Type="Short", Radar="RBS-98" },
["RBS70 SMA"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="RBS-70" },
["RBS70M SMA"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="BV410_RBS70" },
["RBS90 SMA"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="RBS-90" },
["RBS90M SMA"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="BV410_RBS90" },
["RBS103A SMA"] = { Range=150, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_Rb103A" },
["RBS103B SMA"] = { Range=35, Blindspot=0, Height=36, Type="Medium", Radar="LvS-103_Lavett103_Rb103B" },
["RBS103AM SMA"] = { Range=150, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_HX_Rb103A" },
["RBS103BM SMA"] = { Range=35, Blindspot=0, Height=36, Type="Medium", Radar="LvS-103_Lavett103_HX_Rb103B" },
["Lvkv9040M SMA"] = { Range=4, Blindspot=0, Height=2.5, Type="Short", Radar="LvKv9040" },
}
-----------------------------------------------------------------------
-- MANTIS System
-----------------------------------------------------------------------
@@ -398,7 +426,7 @@ do
--@param #string samprefix Prefixes for the SAM groups from the ME, e.g. all groups starting with "Red Sam..."
--@param #string ewrprefix Prefixes for the EWR groups from the ME, e.g. all groups starting with "Red EWR..."
--@param #string hq Group name of your HQ (optional)
--@param #string coaltion Coalition side of your setup, e.g. "blue", "red" or "neutral"
--@param #string coalition Coalition side of your setup, e.g. "blue", "red" or "neutral"
--@param #boolean dynamic Use constant (true) filtering or just filter once (false, default) (optional)
--@param #string awacs Group name of your Awacs (optional)
--@param #boolean EmOnOff Make MANTIS switch Emissions on and off instead of changing the alarm state between RED and GREEN (optional)
@@ -421,7 +449,7 @@ do
-- mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
-- mybluemantis:Start()
--
function MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic,awacs, EmOnOff, Padding)
function MANTIS:New(name,samprefix,ewrprefix,hq,coalition,dynamic,awacs, EmOnOff, Padding)
-- DONE: Create some user functions for these
-- DONE: Make HQ useful
@@ -434,7 +462,7 @@ do
self.SAM_Templates_Prefix = samprefix or "Red SAM"
self.EWR_Templates_Prefix = ewrprefix or "Red EWR"
self.HQ_Template_CC = hq or nil
self.Coalition = coaltion or "red"
self.Coalition = coalition or "red"
self.SAM_Table = {}
self.SAM_Table_Long = {}
self.SAM_Table_Medium = {}
@@ -550,7 +578,7 @@ do
-- TODO Version
-- @field #string version
self.version="0.8.8"
self.version="0.8.9"
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
--- FSM Functions ---
@@ -1270,11 +1298,12 @@ do
-- @param #MANTIS self
-- @param #string grpname Name of the group
-- @param #boolean mod HDS mod flag
-- @param #boolean sma SMA mod flag
-- @return #number range Max firing range
-- @return #number height Max firing height
-- @return #string type Long, medium or short range
-- @return #number blind "blind" spot
function MANTIS:_GetSAMDataFromUnits(grpname,mod)
function MANTIS:_GetSAMDataFromUnits(grpname,mod,sma)
self:T(self.lid.."_GetSAMRangeFromUnits")
local found = false
local range = self.checkradius
@@ -1287,6 +1316,8 @@ do
local SAMData = self.SamData
if mod then
SAMData = self.SamDataHDS
elseif sma then
SAMData = self.SamDataSMA
end
--self:I("Looking to auto-match for "..grpname)
for _,_unit in pairs(units) do
@@ -1332,8 +1363,11 @@ do
local blind = 0
local found = false
local HDSmod = false
local SMAMod = false
if string.find(grpname,"HDS",1,true) then
HDSmod = true
elseif string.find(grpname,"SMA",1,true) then
SMAMod = true
end
if self.automode then
for idx,entry in pairs(self.SamData) do
@@ -1352,8 +1386,8 @@ do
end
end
-- secondary filter if not found
if (not found and self.automode) or HDSmod then
range, height, type = self:_GetSAMDataFromUnits(grpname,HDSmod)
if (not found and self.automode) or HDSmod or SMAMod then
range, height, type = self:_GetSAMDataFromUnits(grpname,HDSmod,SMAMod)
elseif not found then
self:E(self.lid .. string.format("*****Could not match radar data for %s! Will default to midrange values!",grpname))
end

View File

@@ -1,4 +1,4 @@
--- **Functional** -- Train missile defence and deflection.
--- **Functional** - Train missile defence and deflection.
--
-- ===
--
@@ -28,14 +28,14 @@
-- * **Messages Off**: Disable all messages.
-- * **Tracking**: Menu to configure missile tracking messages.
-- * **To All**: Shows missile tracking messages to all players.
-- * **To Target**: Shows missile tracking messages only to the player where the missile is targetted at.
-- * **To Target**: Shows missile tracking messages only to the player where the missile is targeted at.
-- * **Tracking On**: Show missile tracking messages.
-- * **Tracking Off**: Disable missile tracking messages.
-- * **Frequency Increase**: Increases the missile tracking message frequency with one second.
-- * **Frequency Decrease**: Decreases the missile tracking message frequency with one second.
-- * **Alerts**: Menu to configure alert messages.
-- * **To All**: Shows alert messages to all players.
-- * **To Target**: Shows alert messages only to the player where the missile is (was) targetted at.
-- * **To Target**: Shows alert messages only to the player where the missile is (was) targeted at.
-- * **Hits On**: Show missile hit alert messages.
-- * **Hits Off**: Disable missile hit alert messages.
-- * **Launches On**: Show missile launch messages.
@@ -88,7 +88,7 @@
-- 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.
-- * @{#MISSILETRAINER.InitTrackingToAll}: Sets by default the missile tracking report for all players or only for those missiles targetted to you.
-- * @{#MISSILETRAINER.InitTrackingToAll}: Sets by default the missile tracking report for all players or only for those missiles targeted to you.
-- * @{#MISSILETRAINER.InitTrackingOnOff}: Sets by default the display of missile tracking report to be ON or OFF.
-- * @{#MISSILETRAINER.InitTrackingFrequency}: Increases, decreases the missile tracking message display frequency with the provided time interval in seconds.
-- * @{#MISSILETRAINER.InitAlertsToAll}: Sets by default the display of alerts to be shown to all players or only to you.
@@ -256,7 +256,7 @@ function MISSILETRAINER:InitMessagesOnOff( MessagesOnOff )
return self
end
--- Sets by default the missile tracking report for all players or only for those missiles targetted to you.
--- Sets by default the missile tracking report for all players or only for those missiles targeted to you.
-- @param #MISSILETRAINER self
-- @param #boolean TrackingToAll true or false
-- @return #MISSILETRAINER self

View File

@@ -1,4 +1,4 @@
--- **Functional** -- Limit the movement of simulaneous moving ground vehicles.
--- **Functional** - Limit the movement of simulaneous moving ground vehicles.
--
-- ===
--
@@ -30,23 +30,23 @@ MOVEMENT = {
function MOVEMENT:New( MovePrefixes, MoveMaximum )
local self = BASE:Inherit( self, BASE:New() ) -- #MOVEMENT
self:F( { MovePrefixes, MoveMaximum } )
if type( MovePrefixes ) == 'table' then
self.MovePrefixes = MovePrefixes
else
self.MovePrefixes = { MovePrefixes }
end
self.MoveCount = 0 -- The internal counter of the amount of Moveing the has happened since MoveStart.
self.MoveMaximum = MoveMaximum -- Contains the Maximum amount of units that are allowed to move...
self.AliveUnits = 0 -- Contains the counter how many units are currently alive
self.MoveUnits = {} -- Reflects if the Moving for this MovePrefixes is going to be scheduled or not.
self.MoveCount = 0 -- The internal counter of the amount of Moving the has happened since MoveStart.
self.MoveMaximum = MoveMaximum -- Contains the Maximum amount of units that are allowed to move.
self.AliveUnits = 0 -- Contains the counter how many units are currently alive.
self.MoveUnits = {} -- Reflects if the Moving for this MovePrefixes is going to be scheduled or not.
self:HandleEvent( EVENTS.Birth )
-- self:AddEvent( world.event.S_EVENT_BIRTH, self.OnBirth )
--
-- self:EnableEvents()
self:ScheduleStart()
return self
@@ -67,7 +67,7 @@ function MOVEMENT:ScheduleStop()
end
--- Captures the birth events when new Units were spawned.
-- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration.
-- @todo This method should become obsolete. The global _DATABASE object (an instance of @{Core.Database#DATABASE}) will handle the collection administration.
-- @param #MOVEMENT self
-- @param Core.Event#EVENTDATA self
function MOVEMENT:OnEventBirth( EventData )
@@ -86,14 +86,14 @@ function MOVEMENT:OnEventBirth( EventData )
end
end
end
EventData.IniUnit:HandleEvent( EVENTS.DEAD, self.OnDeadOrCrash )
end
end
--- Captures the Dead or Crash events when Units crash or are destroyed.
-- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration.
-- @todo This method should become obsolete. The global _DATABASE object (an instance of @{Core.Database#DATABASE}) will handle the collection administration.
function MOVEMENT:OnDeadOrCrash( Event )
self:F( { Event } )

View File

@@ -1,4 +1,4 @@
--- **Functional** - Rudimentary ATC.
--- **Functional** - Basic ATC.
--
-- ![Banner Image](..\Presentations\PSEUDOATC\PSEUDOATC_Main.jpg)
--
@@ -45,6 +45,7 @@
-- @field #number talt Interval in seconds between reporting altitude until touchdown. Default 3 sec.
-- @field #boolean chatty Display some messages on events like take-off and touchdown.
-- @field #boolean eventsmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler.
-- @field #boolean reportplayername If true, use playername not callsign on callouts
-- @extends Core.Base#BASE
--- Adds some rudimentary ATC functionality via the radio menu.
@@ -88,6 +89,7 @@ PSEUDOATC={
talt=3,
chatty=true,
eventsmoose=true,
reportplayername = false,
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -98,7 +100,7 @@ PSEUDOATC.id="PseudoATC | "
--- PSEUDOATC version.
-- @field #number version
PSEUDOATC.version="0.9.2"
PSEUDOATC.version="0.9.5"
-----------------------------------------------------------------------------------------------------------------------------------------
@@ -183,6 +185,13 @@ function PSEUDOATC:SetMessageDuration(duration)
self.mdur=duration or 30
end
--- Use player name, not call sign, in callouts
-- @param #PSEUDOATC self
function PSEUDOATC:SetReportPlayername()
self.reportplayername = true
return self
end
--- Set time interval after which the F10 radio menu is refreshed.
-- @param #PSEUDOATC self
-- @param #number interval Interval in seconds. Default is every 120 sec.
@@ -441,14 +450,18 @@ function PSEUDOATC:PlayerLanded(unit, place)
local group=unit:GetGroup()
local GID=group:GetID()
local UID=unit:GetDCSObject():getID()
local PlayerName=self.group[GID].player[UID].playername
local UnitName=self.group[GID].player[UID].unitname
local GroupName=self.group[GID].player[UID].groupname
-- Debug message.
local text=string.format("Player %s in unit %s of group %s (id=%d) landed at %s.", PlayerName, UnitName, GroupName, GID, place)
self:T(PSEUDOATC.id..text)
MESSAGE:New(text, 30):ToAllIf(self.Debug)
--local PlayerName=self.group[GID].player[UID].playername
--local UnitName=self.group[GID].player[UID].unitname
--local GroupName=self.group[GID].player[UID].groupname
local PlayerName = unit:GetPlayerName() or "Ghost"
local UnitName = unit:GetName() or "Ghostplane"
local GroupName = group:GetName() or "Ghostgroup"
if self.Debug then
-- Debug message.
local text=string.format("Player %s in unit %s of group %s landed at %s.", PlayerName, UnitName, GroupName, place)
self:T(PSEUDOATC.id..text)
MESSAGE:New(text, 30):ToAllIf(self.Debug)
end
-- Stop altitude reporting timer if its activated.
self:AltitudeTimerStop(GID,UID)
@@ -470,21 +483,28 @@ function PSEUDOATC:PlayerTakeOff(unit, place)
-- Gather some information.
local group=unit:GetGroup()
local GID=group:GetID()
local UID=unit:GetDCSObject():getID()
local PlayerName=self.group[GID].player[UID].playername
local CallSign=self.group[GID].player[UID].callsign
local UnitName=self.group[GID].player[UID].unitname
local GroupName=self.group[GID].player[UID].groupname
-- Debug message.
local text=string.format("Player %s in unit %s of group %s (id=%d) took off at %s.", PlayerName, UnitName, GroupName, GID, place)
self:T(PSEUDOATC.id..text)
MESSAGE:New(text, 30):ToAllIf(self.Debug)
--local GID=group:GetID()
--local UID=unit:GetDCSObject():getID()
--local PlayerName=self.group[GID].player[UID].playername
--local CallSign=self.group[GID].player[UID].callsign
--local UnitName=self.group[GID].player[UID].unitname
--local GroupName=self.group[GID].player[UID].groupname
local PlayerName = unit:GetPlayerName() or "Ghost"
local UnitName = unit:GetName() or "Ghostplane"
local GroupName = group:GetName() or "Ghostgroup"
local CallSign = unit:GetCallsign() or "Ghost11"
if self.Debug then
-- Debug message.
local text=string.format("Player %s in unit %s of group %s took off at %s.", PlayerName, UnitName, GroupName, place)
self:T(PSEUDOATC.id..text)
MESSAGE:New(text, 30):ToAllIf(self.Debug)
end
-- Bye-Bye message.
if place and self.chatty then
local text=string.format("%s, %s, you are airborne. Have a safe trip!", place, CallSign)
if self.reportplayername then
text=string.format("%s, %s, you are airborne. Have a safe trip!", place, PlayerName)
end
MESSAGE:New(text, self.mdur):ToGroup(group)
end
@@ -501,7 +521,7 @@ function PSEUDOATC:PlayerLeft(unit)
local GID=group:GetID()
local UID=unit:GetDCSObject():getID()
if self.group[GID].player[UID] then
if self.group[GID] and self.group[GID].player and self.group[GID].player[UID] then
local PlayerName=self.group[GID].player[UID].playername
local CallSign=self.group[GID].player[UID].callsign
local UnitName=self.group[GID].player[UID].unitname
@@ -687,7 +707,9 @@ function PSEUDOATC:MenuWaypoints(GID, UID)
-- Position of Waypoint
local pos=COORDINATE:New(wp.x, wp.alt, wp.y)
local name=string.format("Waypoint %d", i-1)
if wp.name and wp.name ~= "" then
name = string.format("Waypoint %s",wp.name)
end
-- "F10/PseudoATC/Waypoints/Waypoint X"
local submenu=missionCommands.addSubMenuForGroup(GID, name, self.group[GID].player[UID].menu_waypoints)
@@ -844,7 +866,8 @@ function PSEUDOATC:ReportHeight(GID, UID, dt, _clear)
local position=unit:GetCoordinate()
local height=get_AGL(position)
local callsign=unit:GetCallsign()
local PlayerName=self.group[GID].player[UID].playername
-- Settings.
local settings=_DATABASE:GetPlayerSettings(self.group[GID].player[UID].playername) or _SETTINGS --Core.Settings#SETTINGS
@@ -856,7 +879,9 @@ function PSEUDOATC:ReportHeight(GID, UID, dt, _clear)
-- Message text.
local _text=string.format("%s, your altitude is %s AGL.", callsign, Hs)
if self.reportplayername then
_text=string.format("%s, your altitude is %s AGL.", PlayerName, Hs)
end
-- Append flight level.
if _clear==false then
_text=_text..string.format(" FL%03d.", position.y/30.48)

View File

@@ -51,7 +51,7 @@
-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536)
--
-- ===
-- @module Functional.Rat
-- @module Functional.RAT
-- @image RAT.JPG
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -3492,7 +3492,7 @@ function RAT:Status(message, forID)
local fuel=group:GetFuel()*100.0
local airborne=group:InAir()
local coords=group:GetCoordinate()
local alt=coords.y
local alt=coords.y or 1000
--local vel=group:GetVelocityKMH()
local departure=ratcraft.departure:GetName()
local destination=ratcraft.destination:GetName()
@@ -5443,7 +5443,7 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take
SpawnTemplate.units[UnitID]["onboard_num"] = string.format("%s%d%02d", self.onboardnum, (self.SpawnIndex-1)%10, (self.onboardnum0-1)+UnitID)
end
-- Modify coaltion and country of template.
-- Modify coalition and country of template.
SpawnTemplate.CoalitionID=self.coalition
if self.country then
SpawnTemplate.CountryID=self.country
@@ -5671,6 +5671,9 @@ function RAT:_ATCClearForLanding(airport, flight)
-- Debug message.
local text1=string.format("ATC %s: Flight %s cleared for landing (flag=%d).", airport, flight, flagvalue)
if string.find(flight,"#") then
flight = string.match(flight,"^(.+)#")
end
local text2=string.format("ATC %s: Flight %s you are cleared for landing.", airport, flight)
BASE:T( RAT.id..text1)
MESSAGE:New(text2, 10):ToAllIf(RAT.ATC.messages)
@@ -5713,6 +5716,9 @@ function RAT:_ATCFlightLanded(name)
local text1=string.format("ATC %s: Flight %s landed. Tholding = %i:%02d, Tfinal = %i:%02d.", dest, name, Thold/60, Thold%60, Tfinal/60, Tfinal%60)
local text2=string.format("ATC %s: Number of flights still on final %d.", dest, RAT.ATC.airport[dest].Nonfinal)
local text3=string.format("ATC %s: Traffic report: Number of planes landed in total %d. Flights/hour = %3.2f.", dest, RAT.ATC.airport[dest].traffic, TrafficPerHour)
if string.find(name,"#") then
name = string.match(name,"^(.+)#")
end
local text4=string.format("ATC %s: Flight %s landed. Welcome to %s.", dest, name, dest)
BASE:T(RAT.id..text1)
BASE:T(RAT.id..text2)

View File

@@ -138,7 +138,7 @@
--
-- A strafe pit can be added to the range by the @{#RANGE.AddStrafePit}(*targetnames, boxlength, boxwidth, heading, inverseheading, goodpass, foulline*) function.
--
-- * The first parameter *targetnames* defines the target or targets. This can be a single item or a Table with the name(s) of @{Wrapper.Unit} or @{Static} objects defined in the mission editor.
-- * The first parameter *targetnames* defines the target or targets. This can be a single item or a Table with the name(s) of @{Wrapper.Unit} or @{Wrapper.Static} objects defined in the mission editor.
-- * In order to perform a valid pass on the strafe pit, the pilot has to begin his run from the correct direction. Therefore, an "approach box" is defined in front
-- of the strafe targets. The parameters *boxlength* and *boxwidth* define the size of the box in meters, while the *heading* parameter defines the heading of the box FROM the target.
-- For example, if heading 120 is set, the approach box will start FROM the target and extend outwards on heading 120. A strafe run approach must then be flown apx. heading 300 TOWARDS the target.
@@ -157,7 +157,7 @@
--
-- One ore multiple bombing targets can be added to the range by the @{#RANGE.AddBombingTargets}(targetnames, goodhitrange, randommove) function.
--
-- * The first parameter *targetnames* defines the target or targets. This can be a single item or a Table with the name(s) of @{Wrapper.Unit} or @{Static} objects defined in the mission editor.
-- * The first parameter *targetnames* defines the target or targets. This can be a single item or a Table with the name(s) of @{Wrapper.Unit} or @{Wrapper.Static} objects defined in the mission editor.
-- * The (optional) parameter *goodhitrange* specifies the radius in metres around the target within which a bomb/rocket hit is considered to be "good".
-- * If final (optional) parameter "*randommove*" can be enabled to create moving targets. If this parameter is set to true, the units of this bombing target will randomly move within the range zone.
-- Note that there might be quirks since DCS units can get stuck in buildings etc. So it might be safer to manually define a route for the units in the mission editor if moving targets are desired.
@@ -301,7 +301,7 @@
-- BASE:TraceLevel(1)
-- BASE:TraceClass("RANGE")
--
-- To get even more output you can increase the trace level to 2 or even 3, c.f. @{BASE} for more details.
-- To get even more output you can increase the trace level to 2 or even 3, c.f. @{Core.Base#BASE} for more details.
--
-- The function @{#RANGE.DebugON}() can be used to send messages on screen. It also smokes all defined strafe and bombing targets, the strafe pit approach boxes and the range zone.
--
@@ -578,7 +578,7 @@ RANGE.MenuF10Root = nil
--- Range script version.
-- @field #string version
RANGE.version = "2.5.0"
RANGE.version = "2.5.1"
-- TODO list:
-- TODO: Verbosity level for messages.
@@ -1207,13 +1207,18 @@ function RANGE:SetSRS(PathToSRS, Port, Coalition, Frequency, Modulation, Volume,
self.controlmsrs:SetCoalition(Coalition or coalition.side.BLUE)
self.controlmsrs:SetLabel("RANGEC")
self.controlsrsQ = MSRSQUEUE:New("CONTROL")
self.instructmsrs=MSRS:New(PathToSRS, Frequency or 305, Modulation or radio.modulation.AM, Volume or 1.0)
self.instructmsrs:SetPort(Port)
self.instructmsrs:SetCoalition(Coalition or coalition.side.BLUE)
self.instructmsrs:SetLabel("RANGEI")
self.instructsrsQ = MSRSQUEUE:New("INSTRUCT")
if PathToGoogleKey then
self.instructmsrs:SetGoogle(PathToGoogleKey)
self.instructmsrs:SetGoogle(PathToGoogleKey)
end
else
self:E(self.lid..string.format("ERROR: No SRS path specified!"))
end
@@ -1849,7 +1854,12 @@ function RANGE:OnEventHit( EventData )
-- Too close to the target.
if _currentTarget.pastfoulline == false and _unit and _playername then
local _d = _currentTarget.zone.foulline
-- DONE - SRS output
local text = string.format( "%s, Invalid hit!\nYou already passed foul line distance of %d m for target %s.", self:_myname( _unitName ), _d, targetname )
if self.useSRS then
local ttstext = string.format( "%s, Invalid hit! You already passed foul line distance of %d meters for target %s.", self:_myname( _unitName ), _d, targetname )
self.controlsrsQ:NewTransmission(ttstext,nil,self.controlmsrs,nil,2)
end
self:_DisplayMessageToGroup( _unit, text )
self:T2( self.id .. text )
_currentTarget.pastfoulline = true
@@ -2096,7 +2106,12 @@ function RANGE:OnEventShot( EventData )
elseif insidezone then
-- Send message.
-- DONE SRS message
local _message = string.format( "%s, weapon impacted too far from nearest range target (>%.1f km). No score!", _callsign, self.scorebombdistance / 1000 )
if self.useSRS then
local ttstext = string.format( "%s, weapon impacted too far from nearest range target, mor than %.1f kilometer. No score!", _callsign, self.scorebombdistance / 1000 )
self.controlsrsQ:NewTransmission(ttstext,nil,self.controlmsrs,nil,2)
end
self:_DisplayMessageToGroup( _unit, _message, nil, false )
if self.rangecontrol then
@@ -2249,7 +2264,7 @@ function RANGE:onafterImpact( From, Event, To, result, player )
end
-- Send message to player.
local text = string.format( "%s, impact %03d° for %d ft", player.playername, result.radial, UTILS.MetersToFeet( result.distance ) )
local text = string.format( "%s, impact %03d° for %d ft (%d m)", player.playername, result.radial, UTILS.MetersToFeet( result.distance ), result.distance )
if targetname then
text = text .. string.format( " from bulls of target %s.", targetname )
else
@@ -2560,7 +2575,7 @@ function RANGE:_DisplayMyStrafePitResults( _unitName )
self:F( _unitName )
-- Get player unit and name
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName )
local _unit, _playername, _multiplayer = self:_GetPlayerUnitAndName( _unitName )
if _unit and _playername then
@@ -2612,7 +2627,7 @@ function RANGE:_DisplayMyStrafePitResults( _unitName )
end
-- Send message to group.
self:_DisplayMessageToGroup( _unit, _message, nil, true, true )
self:_DisplayMessageToGroup( _unit, _message, nil, true, true, _multiplayer )
end
end
@@ -2623,7 +2638,7 @@ function RANGE:_DisplayStrafePitResults( _unitName )
self:F( _unitName )
-- Get player unit and name.
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName )
local _unit, _playername, _multiplayer = self:_GetPlayerUnitAndName( _unitName )
-- Check if we have a unit which is a player.
if _unit and _playername then
@@ -2670,7 +2685,7 @@ function RANGE:_DisplayStrafePitResults( _unitName )
end
-- Send message.
self:_DisplayMessageToGroup( _unit, _message, nil, true, true )
self:_DisplayMessageToGroup( _unit, _message, nil, true, true, _multiplayer )
end
end
@@ -2681,7 +2696,7 @@ function RANGE:_DisplayMyBombingResults( _unitName )
self:F( _unitName )
-- Get player unit and name.
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName )
local _unit, _playername, _multiplayer = self:_GetPlayerUnitAndName( _unitName )
if _unit and _playername then
@@ -2727,7 +2742,7 @@ function RANGE:_DisplayMyBombingResults( _unitName )
end
-- Send message.
self:_DisplayMessageToGroup( _unit, _message, nil, true, true )
self:_DisplayMessageToGroup( _unit, _message, nil, true, true, _multiplayer )
end
end
@@ -2741,7 +2756,7 @@ function RANGE:_DisplayBombingResults( _unitName )
local _playerResults = {}
-- Get player unit and name.
local _unit, _player = self:_GetPlayerUnitAndName( _unitName )
local _unit, _player, _multiplayer = self:_GetPlayerUnitAndName( _unitName )
-- Check if we have a unit with a player.
if _unit and _player then
@@ -2785,7 +2800,7 @@ function RANGE:_DisplayBombingResults( _unitName )
end
-- Send message.
self:_DisplayMessageToGroup( _unit, _message, nil, true, true )
self:_DisplayMessageToGroup( _unit, _message, nil, true, true, _multiplayer )
end
end
@@ -2796,7 +2811,7 @@ function RANGE:_DisplayRangeInfo( _unitname )
self:F( _unitname )
-- Get player unit and player name.
local unit, playername = self:_GetPlayerUnitAndName( _unitname )
local unit, playername, _multiplayer = self:_GetPlayerUnitAndName( _unitname )
-- Check if we have a player.
if unit and playername then
@@ -2891,7 +2906,7 @@ function RANGE:_DisplayRangeInfo( _unitname )
text = text .. textdelay
-- Send message to player group.
self:_DisplayMessageToGroup( unit, text, nil, true, true )
self:_DisplayMessageToGroup( unit, text, nil, true, true, _multiplayer )
-- Debug output.
self:T2( self.id .. text )
@@ -2906,7 +2921,7 @@ function RANGE:_DisplayBombTargets( _unitname )
self:F( _unitname )
-- Get player unit and player name.
local _unit, _playername = self:_GetPlayerUnitAndName( _unitname )
local _unit, _playername, _multiplayer = self:_GetPlayerUnitAndName( _unitname )
-- Check if we have a player.
if _unit and _playername then
@@ -2938,7 +2953,7 @@ function RANGE:_DisplayBombTargets( _unitname )
end
end
self:_DisplayMessageToGroup( _unit, _text, 120, true, true )
self:_DisplayMessageToGroup( _unit, _text, 120, true, true, _multiplayer )
end
end
@@ -2949,7 +2964,7 @@ function RANGE:_DisplayStrafePits( _unitname )
self:F( _unitname )
-- Get player unit and player name.
local _unit, _playername = self:_GetPlayerUnitAndName( _unitname )
local _unit, _playername, _multiplayer = self:_GetPlayerUnitAndName( _unitname )
-- Check if we have a player.
if _unit and _playername then
@@ -2978,7 +2993,7 @@ function RANGE:_DisplayStrafePits( _unitname )
_text = _text .. string.format( "\n- %s: heading %03d°\n%s", _strafepit.name, heading, mycoord )
end
self:_DisplayMessageToGroup( _unit, _text, nil, true, true )
self:_DisplayMessageToGroup( _unit, _text, nil, true, true, _multiplayer )
end
end
@@ -2989,7 +3004,7 @@ function RANGE:_DisplayRangeWeather( _unitname )
self:F( _unitname )
-- Get player unit and player name.
local unit, playername = self:_GetPlayerUnitAndName( _unitname )
local unit, playername, _multiplayer = self:_GetPlayerUnitAndName( _unitname )
-- Check if we have a player.
if unit and playername then
@@ -3038,7 +3053,7 @@ function RANGE:_DisplayRangeWeather( _unitname )
end
-- Send message to player group.
self:_DisplayMessageToGroup( unit, text, nil, true, true )
self:_DisplayMessageToGroup( unit, text, nil, true, true, _multiplayer )
-- Debug output.
self:T2( self.id .. text )
@@ -3188,23 +3203,6 @@ function RANGE:_CheckInZone( _unitName )
local _sound = nil -- #RANGE.Soundfile
--[[ --RangeBoss commented out in order to implement strafe quality based on accuracy percentage, not the number of rounds on target
-- Judge this pass. Text is displayed on summary.
if _result.hits >= _result.zone.goodPass*2 then
_result.text = "EXCELLENT PASS"
_sound=RANGE.Sound.RCExcellentPass
elseif _result.hits >= _result.zone.goodPass then
_result.text = "GOOD PASS"
_sound=RANGE.Sound.RCGoodPass
elseif _result.hits >= _result.zone.goodPass/2 then
_result.text = "INEFFECTIVE PASS"
_sound=RANGE.Sound.RCIneffectivePass
else
_result.text = "POOR PASS"
_sound=RANGE.Sound.RCPoorPass
end
]]
-- Calculate accuracy of run. Number of hits wrt number of rounds fired.
local shots = _result.ammo - _ammo
local accur = 0
@@ -3455,10 +3453,10 @@ function RANGE:_AddF10Commands( _unitName )
local _StrPits = MENU_GROUP_COMMAND:New( group, "Strafe Pits", _infoPath, self._DisplayStrafePits, self, _unitName ):Refresh()
end
else
self:E( self.id .. "Could not find group or group ID in AddF10Menu() function. Unit name: " .. _unitName )
self:E( self.id .. "Could not find group or group ID in AddF10Menu() function. Unit name: " .. _unitName or "N/A")
end
else
self:E( self.id .. "Player unit does not exist in AddF10Menu() function. Unit name: " .. _unitName )
self:E( self.id .. "Player unit does not exist in AddF10Menu() function. Unit name: " .. _unitName or "N/A")
end
end
@@ -3673,7 +3671,8 @@ end
-- @param #number _time Duration how long the message is displayed.
-- @param #boolean _clear Clear up old messages.
-- @param #boolean display If true, display message regardless of player setting "Messages Off".
function RANGE:_DisplayMessageToGroup( _unit, _text, _time, _clear, display )
-- @param #boolean _togroup If true, display the message to the group in any case
function RANGE:_DisplayMessageToGroup( _unit, _text, _time, _clear, display, _togroup )
self:F( { unit = _unit, text = _text, time = _time, clear = _clear } )
-- Defaults
@@ -3701,8 +3700,13 @@ function RANGE:_DisplayMessageToGroup( _unit, _text, _time, _clear, display )
local playermessage = self.PlayerSettings[playername].messages
-- Send message to player if messages enabled and not only for the examiner.
if _gid and (playermessage == true or display) and (not self.examinerexclusive) then
local m = MESSAGE:New(_text,_time,nil,_clear):ToUnit(_unit)
if _togroup and _grp then
local m = MESSAGE:New(_text,_time,nil,_clear):ToGroup(_grp)
else
local m = MESSAGE:New(_text,_time,nil,_clear):ToUnit(_unit)
end
end
-- Send message to examiner.
@@ -3722,7 +3726,7 @@ end
function RANGE:_SmokeBombImpactOnOff( unitname )
self:F( unitname )
local unit, playername = self:_GetPlayerUnitAndName( unitname )
local unit, playername, _multiplayer = self:_GetPlayerUnitAndName( unitname )
if unit and playername then
local text
if self.PlayerSettings[playername].smokebombimpact == true then
@@ -3743,7 +3747,7 @@ end
function RANGE:_SmokeBombDelayOnOff( unitname )
self:F( unitname )
local unit, playername = self:_GetPlayerUnitAndName( unitname )
local unit, playername, _multiplayer = self:_GetPlayerUnitAndName( unitname )
if unit and playername then
local text
if self.PlayerSettings[playername].delaysmoke == true then
@@ -3764,7 +3768,7 @@ end
function RANGE:_MessagesToPlayerOnOff( unitname )
self:F( unitname )
local unit, playername = self:_GetPlayerUnitAndName( unitname )
local unit, playername, _multiplayer = self:_GetPlayerUnitAndName( unitname )
if unit and playername then
local text
if self.PlayerSettings[playername].messages == true then
@@ -3785,7 +3789,7 @@ function RANGE:_TargetsheetOnOff( _unitname )
self:F2( _unitname )
-- Get player unit and player name.
local unit, playername = self:_GetPlayerUnitAndName( _unitname )
local unit, playername, _multiplayer = self:_GetPlayerUnitAndName( _unitname )
-- Check if we have a player.
if unit and playername then
@@ -3827,7 +3831,7 @@ end
function RANGE:_FlareDirectHitsOnOff( unitname )
self:F( unitname )
local unit, playername = self:_GetPlayerUnitAndName( unitname )
local unit, playername, _multiplayer = self:_GetPlayerUnitAndName( unitname )
if unit and playername then
local text
if self.PlayerSettings[playername].flaredirecthits == true then
@@ -4046,12 +4050,14 @@ end
-- @param #string _unitName Name of the player unit.
-- @return Wrapper.Unit#UNIT Unit of player.
-- @return #string Name of the player.
-- @return nil If player does not exist.
-- @return #boolean If true, group has > 1 player in it
function RANGE:_GetPlayerUnitAndName( _unitName )
self:F2( _unitName )
if _unitName ~= nil then
local multiplayer = false
-- Get DCS unit from its name.
local DCSunit = Unit.getByName( _unitName )
@@ -4063,7 +4069,11 @@ function RANGE:_GetPlayerUnitAndName( _unitName )
self:T2( { DCSunit = DCSunit, unit = unit, playername = playername } )
if DCSunit and unit and playername then
self:F2(playername)
return unit, playername
local grp = unit:GetGroup()
if grp and grp:CountAliveUnits() > 1 then
multiplayer = true
end
return unit, playername, multiplayer
end
end
@@ -4071,7 +4081,7 @@ function RANGE:_GetPlayerUnitAndName( _unitName )
end
-- Return nil if we could not find a player.
return nil, nil
return nil, nil, nil
end
--- Returns a string which consists of the player name.
@@ -4081,19 +4091,12 @@ function RANGE:_myname( unitname )
self:F2( unitname )
local pname = "Ghost 1 1"
local unit = UNIT:FindByName( unitname )
if unit then
if unit and unit:IsAlive() then
local grp = unit:GetGroup()
if grp then
if grp and grp:IsAlive() then
pname = grp:GetCustomCallSign(true,true)
end
end
--[[
local pname = unit:GetPlayerName()
-- local csign = unit:GetCallsign()
-- return string.format("%s (%s)", csign, pname)
return string.format( "%s", pname )
--]]
return pname
end

View File

@@ -1,4 +1,4 @@
--- **Functional** - Administer the scoring of player achievements, and create a CSV file logging the scoring events for use at team or squadron websites.
--- **Functional** - Administer the scoring of player achievements, file and log the scoring events for use at websites.
--
-- ===
--
@@ -12,7 +12,7 @@
-- * Score the hits and destroys of units.
-- * Score the hits and destroys of statics.
-- * Score the hits and destroys of scenery.
-- * Log scores into a CSV file.
-- * (optional) Log scores into a CSV file.
-- * Connect to a remote server using JSON and IP.
--
-- ===
@@ -59,7 +59,7 @@
--
-- ![Banner Image](..\Presentations\SCORING\Dia9.JPG)
--
-- Various @{Zone}s can be defined for which scores are also granted when objects in that @{Zone} are destroyed.
-- Various @{Core.Zone}s can be defined for which scores are also granted when objects in that @{Core.Zone} are destroyed.
-- This is **specifically useful** to designate **scenery targets on the map** that will generate points when destroyed.
--
-- With a small change in MissionScripting.lua, the scoring results can also be logged in a **CSV file**.
@@ -115,7 +115,7 @@
--
-- Special targets can be set that will give extra scores to the players when these are destroyed.
-- Use the methods @{#SCORING.AddUnitScore}() and @{#SCORING.RemoveUnitScore}() to specify a special additional score for a specific @{Wrapper.Unit}s.
-- Use the methods @{#SCORING.AddStaticScore}() and @{#SCORING.RemoveStaticScore}() to specify a special additional score for a specific @{Static}s.
-- Use the methods @{#SCORING.AddStaticScore}() and @{#SCORING.RemoveStaticScore}() to specify a special additional score for a specific @{Wrapper.Static}s.
-- Use the method @{#SCORING.SetGroupGroup}() to specify a special additional score for a specific @{Wrapper.Group}s.
--
-- local Scoring = SCORING:New( "Scoring File" )
@@ -131,11 +131,11 @@
-- # Define destruction zones that will give extra scores:
--
-- Define zones of destruction. Any object destroyed within the zone of the given category will give extra points.
-- Use the method @{#SCORING.AddZoneScore}() to add a @{Zone} for additional scoring.
-- Use the method @{#SCORING.RemoveZoneScore}() to remove a @{Zone} for additional scoring.
-- There are interesting variations that can be achieved with this functionality. For example, if the @{Zone} is a @{Core.Zone#ZONE_UNIT},
-- then the zone is a moving zone, and anything destroyed within that @{Zone} will generate points.
-- The other implementation could be to designate a scenery target (a building) in the mission editor surrounded by a @{Zone},
-- Use the method @{#SCORING.AddZoneScore}() to add a @{Core.Zone} for additional scoring.
-- Use the method @{#SCORING.RemoveZoneScore}() to remove a @{Core.Zone} for additional scoring.
-- There are interesting variations that can be achieved with this functionality. For example, if the @{Core.Zone} is a @{Core.Zone#ZONE_UNIT},
-- then the zone is a moving zone, and anything destroyed within that @{Core.Zone} will generate points.
-- The other implementation could be to designate a scenery target (a building) in the mission editor surrounded by a @{Core.Zone},
-- just large enough around that building.
--
-- # Add extra Goal scores upon an event or a condition:
@@ -225,6 +225,7 @@ SCORING = {
ClassName = "SCORING",
ClassID = 0,
Players = {},
AutoSave = true,
}
local _SCORINGCoalition = {
@@ -306,6 +307,7 @@ function SCORING:New( GameName )
end )
-- Create the CSV file.
self.AutoSave = true
self:OpenCSV( GameName )
return self
@@ -373,11 +375,11 @@ function SCORING:RemoveUnitScore( ScoreUnit )
return self
end
--- Add a @{Static} for additional scoring when the @{Static} is destroyed.
-- Note that if there was already a @{Static} declared within the scoring with the same name,
-- then the old @{Static} will be replaced with the new @{Static}.
--- Add a @{Wrapper.Static} for additional scoring when the @{Wrapper.Static} is destroyed.
-- Note that if there was already a @{Wrapper.Static} declared within the scoring with the same name,
-- then the old @{Wrapper.Static} will be replaced with the new @{Wrapper.Static}.
-- @param #SCORING self
-- @param Wrapper.Static#UNIT ScoreStatic The @{Static} for which the Score needs to be given.
-- @param Wrapper.Static#UNIT ScoreStatic The @{Wrapper.Static} for which the Score needs to be given.
-- @param #number Score The Score value.
-- @return #SCORING
function SCORING:AddStaticScore( ScoreStatic, Score )
@@ -389,9 +391,9 @@ function SCORING:AddStaticScore( ScoreStatic, Score )
return self
end
--- Removes a @{Static} for additional scoring when the @{Static} is destroyed.
--- Removes a @{Wrapper.Static} for additional scoring when the @{Wrapper.Static} is destroyed.
-- @param #SCORING self
-- @param Wrapper.Static#UNIT ScoreStatic The @{Static} for which the Score needs to be given.
-- @param Wrapper.Static#UNIT ScoreStatic The @{Wrapper.Static} for which the Score needs to be given.
-- @return #SCORING
function SCORING:RemoveStaticScore( ScoreStatic )
@@ -419,11 +421,11 @@ function SCORING:AddScoreGroup( ScoreGroup, Score )
return self
end
--- Add a @{Zone} to define additional scoring when any object is destroyed in that zone.
-- Note that if a @{Zone} with the same name is already within the scoring added, the @{Zone} (type) and Score will be replaced!
--- Add a @{Core.Zone} to define additional scoring when any object is destroyed in that zone.
-- Note that if a @{Core.Zone} with the same name is already within the scoring added, the @{Core.Zone} (type) and Score will be replaced!
-- This allows for a dynamic destruction zone evolution within your mission.
-- @param #SCORING self
-- @param Core.Zone#ZONE_BASE ScoreZone The @{Zone} which defines the destruction score perimeters.
-- @param Core.Zone#ZONE_BASE ScoreZone The @{Core.Zone} which defines the destruction score perimeters.
-- Note that a zone can be a polygon or a moving zone.
-- @param #number Score The Score value.
-- @return #SCORING
@@ -438,11 +440,11 @@ function SCORING:AddZoneScore( ScoreZone, Score )
return self
end
--- Remove a @{Zone} for additional scoring.
-- The scoring will search if any @{Zone} is added with the given name, and will remove that zone from the scoring.
--- Remove a @{Core.Zone} for additional scoring.
-- The scoring will search if any @{Core.Zone} is added with the given name, and will remove that zone from the scoring.
-- This allows for a dynamic destruction zone evolution within your mission.
-- @param #SCORING self
-- @param Core.Zone#ZONE_BASE ScoreZone The @{Zone} which defines the destruction score perimeters.
-- @param Core.Zone#ZONE_BASE ScoreZone The @{Core.Zone} which defines the destruction score perimeters.
-- Note that a zone can be a polygon or a moving zone.
-- @return #SCORING
function SCORING:RemoveZoneScore( ScoreZone )
@@ -1748,7 +1750,7 @@ end
function SCORING:OpenCSV( ScoringCSV )
self:F( ScoringCSV )
if lfs and io and os then
if lfs and io and os and self.AutoSave then
if ScoringCSV then
self.ScoringCSV = ScoringCSV
local fdir = lfs.writedir() .. [[Logs\]] .. self.ScoringCSV .. " " .. os.date( "%Y-%m-%d %H-%M-%S" ) .. ".csv"
@@ -1828,7 +1830,7 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes,
TargetUnitType = TargetUnitType or ""
TargetUnitName = TargetUnitName or ""
if lfs and io and os then
if lfs and io and os and self.AutoSave then
self.CSVFile:write(
'"' .. self.GameName .. '"' .. ',' ..
'"' .. self.RunTime .. '"' .. ',' ..
@@ -1852,9 +1854,20 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes,
end
end
--- Close CSV file
-- @param #SCORING self
-- @return #SCORING self
function SCORING:CloseCSV()
if lfs and io and os then
if lfs and io and os and self.AutoSave then
self.CSVFile:close()
end
end
--- Registers a score for a player.
-- @param #SCORING self
-- @param #boolean OnOff Switch saving to CSV on = true or off = false
-- @return #SCORING self
function SCORING:SwitchAutoSave(OnOff)
self.AutoSave = OnOff
return self
end

View File

@@ -1,4 +1,4 @@
--- **Functional** -- Make SAM sites execute evasive and defensive behaviour when being fired upon.
--- **Functional** - Make SAM sites execute evasive and defensive behaviour when being fired upon.
--
-- ===
--

View File

@@ -1,9 +1,11 @@
--- **Functional** -- Short Range Air Defense System
--- **Functional** - Short Range Air Defense System.
--
-- ===
--
-- ## Features:
--
-- **SHORAD** - Short Range Air Defense System
-- Controls a network of short range air/missile defense groups.
-- * Short Range Air Defense System
-- * Controls a network of short range air/missile defense groups.
--
-- ===
--

View File

@@ -85,6 +85,7 @@
-- @field #boolean eventmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler. Default true.
-- @field Core.Zone#ZONE BattleZone
-- @field #boolean AutoEngage
-- @field #table waypoints Waypoints of the group as defined in the ME.
-- @extends Core.Fsm#FSM_CONTROLLABLE
--
@@ -265,6 +266,7 @@ SUPPRESSION={
DefaultAlarmState = "Auto",
DefaultROE = "Weapon Free",
eventmoose = true,
waypoints = {},
}
--- Enumerator of possible rules of engagement.
@@ -295,7 +297,7 @@ SUPPRESSION.MenuF10=nil
--- PSEUDOATC version.
-- @field #number version
SUPPRESSION.version="0.9.3"
SUPPRESSION.version="0.9.4"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -309,7 +311,7 @@ SUPPRESSION.version="0.9.3"
--- Creates a new AI_suppression object.
-- @param #SUPPRESSION self
-- @param Wrapper.Group#GROUP group The GROUP object for which suppression should be applied.
-- @return #SUPPRESSION SUPPRESSION object or *nil* if group does not exist or is not a ground group.
-- @return #SUPPRESSION self
function SUPPRESSION:New(group)
-- Inherits from FSM_CONTROLLABLE
@@ -320,7 +322,7 @@ function SUPPRESSION:New(group)
self.lid=string.format("SUPPRESSION %s | ", tostring(group:GetName()))
self:T(self.lid..string.format("SUPPRESSION version %s. Activating suppressive fire for group %s", SUPPRESSION.version, group:GetName()))
else
self:E(self.lid.."SUPPRESSION | Requested group does not exist! (Has to be a MOOSE group.)")
self:E("SUPPRESSION | Requested group does not exist! (Has to be a MOOSE group)")
return nil
end
@@ -1186,6 +1188,16 @@ function SUPPRESSION:onafterFightBack(Controllable, From, Event, To)
-- Set ROE and alarm state back to default.
self:_SetROE()
self:_SetAlarmState()
local group=Controllable --Wrapper.Group#GROUP
local Waypoints = group:GetTemplateRoutePoints()
-- env.info("FF waypoints",showMessageBox)
-- self:I(Waypoints)
group:Route(Waypoints, 5)
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -1251,7 +1263,7 @@ function SUPPRESSION:onafterFallBack(Controllable, From, Event, To, AttackUnit)
self:_SetROE(SUPPRESSION.ROE.Hold)
-- Set alarm state to GREEN and let the unit run away.
self:_SetAlarmState(SUPPRESSION.AlarmState.Green)
self:_SetAlarmState(SUPPRESSION.AlarmState.Auto)
-- Make the group run away.
self:_Run(Coord, self.Speed, self.Formation, self.FallbackWait)
@@ -1537,7 +1549,7 @@ end
-- @param #SUPPRESSION self
-- @param Core.Event#EVENTDATA EventData
function SUPPRESSION:_OnEventHit(EventData)
self:F(EventData)
self:F3(EventData)
local GroupNameSelf=self.Controllable:GetName()
local GroupNameTgt=EventData.TgtGroupName
@@ -1676,15 +1688,15 @@ end
function SUPPRESSION:_Run(fin, speed, formation, wait)
speed=speed or 20
formation=formation or "Off road"
formation=formation or ENUMS.Formation.Vehicle.OffRoad
wait=wait or 30
local group=self.Controllable -- Wrapper.Controllable#CONTROLLABLE
local group=self.Controllable -- Wrapper.Group#GROUP
if group and group:IsAlive() then
-- Clear all tasks.
group:ClearTasks()
--group:ClearTasks()
-- Current coordinates of group.
local ini=group:GetCoordinate()
@@ -1694,57 +1706,18 @@ function SUPPRESSION:_Run(fin, speed, formation, wait)
-- Heading from ini to fin.
local heading=self:_Heading(ini, fin)
-- Number of waypoints.
local nx
if dist <= 50 then
nx=2
elseif dist <= 100 then
nx=3
elseif dist <= 500 then
nx=4
else
nx=5
end
-- Number of intermediate waypoints.
local dx=dist/(nx-1)
-- Waypoint and task arrays.
local wp={}
local tasks={}
-- First waypoint is the current position of the group.
wp[1]=ini:WaypointGround(speed, formation)
tasks[1]=group:TaskFunction("SUPPRESSION._Passing_Waypoint", self, 1, false)
if self.Debug then
local MarkerID=ini:MarkToAll(string.format("Waypoing %d of group %s (initial)", #wp, self.Controllable:GetName()))
end
self:T2(self.lid..string.format("Number of waypoints %d", nx))
for i=1,nx-2 do
local x=dx*i
local coord=ini:Translate(x, heading)
wp[#wp+1]=coord:WaypointGround(speed, formation)
tasks[#tasks+1]=group:TaskFunction("SUPPRESSION._Passing_Waypoint", self, #wp, false)
self:T2(self.lid..string.format("%d x = %4.1f", i, x))
if self.Debug then
local MarkerID=coord:MarkToAll(string.format("Waypoing %d of group %s", #wp, self.Controllable:GetName()))
end
end
self:T2(self.lid..string.format("Total distance: %4.1f", dist))
-- Final waypoint.
wp[#wp+1]=fin:WaypointGround(speed, formation)
if self.Debug then
local MarkerID=fin:MarkToAll(string.format("Waypoing %d of group %s (final)", #wp, self.Controllable:GetName()))
end
-- Task to hold.
local ConditionWait=group:TaskCondition(nil, nil, nil, nil, wait, nil)
local TaskHold = group:TaskHold()
@@ -1753,25 +1726,15 @@ function SUPPRESSION:_Run(fin, speed, formation, wait)
local TaskComboFin = {}
TaskComboFin[#TaskComboFin+1] = group:TaskFunction("SUPPRESSION._Passing_Waypoint", self, #wp, true)
TaskComboFin[#TaskComboFin+1] = group:TaskControlled(TaskHold, ConditionWait)
-- Add final task.
tasks[#tasks+1]=group:TaskCombo(TaskComboFin)
-- Original waypoints of the group.
local Waypoints = group:GetTemplateRoutePoints()
-- New points are added to the default route.
for i,p in ipairs(wp) do
table.insert(Waypoints, i, wp[i])
end
-- Set task for all waypoints.
for i,wp in ipairs(Waypoints) do
group:SetTaskWaypoint(Waypoints[i], tasks[i])
end
-- Final waypoint.
wp[#wp+1]=fin:WaypointGround(speed, formation, TaskComboFin)
if self.Debug then
local MarkerID=fin:MarkToAll(string.format("Waypoing %d of group %s (final)", #wp, self.Controllable:GetName()))
end
-- Submit task and route group along waypoints.
group:Route(Waypoints)
group:Route(wp)
else
self:E(self.lid..string.format("ERROR: Group is not alive!"))
@@ -1790,7 +1753,7 @@ function SUPPRESSION._Passing_Waypoint(group, Fsm, i, final)
local text=string.format("Group %s passing waypoint %d (final=%s)", group:GetName(), i, tostring(final))
MESSAGE:New(text,10):ToAllIf(Fsm.Debug)
if Fsm.Debug then
env.info(self.lid..text)
env.info(Fsm.lid..text)
end
if final then
@@ -1891,7 +1854,7 @@ function SUPPRESSION:_GetLife()
local groupstrength=#units/self.IniGroupStrength*100
self.T2(self.lid..string.format("Group %s _GetLife nunits = %d", self.Controllable:GetName(), #units))
self:T2(self.lid..string.format("Group %s _GetLife nunits = %d", self.Controllable:GetName(), #units))
for _,unit in pairs(units) do

View File

@@ -302,8 +302,8 @@
--
-- Initial Spawn states is as follows:
-- GROUND: ROE, "Return Fire" Alarm, "Green"
-- AIR: ROE, "Return Fire" Reaction to Threat, "Passive Defense"
-- NAVAL ROE, "Return Fire" Alarm,"N/A"
-- AIR: ROE, "Return Fire" Reaction to Threat, "Passive Defense"
-- NAVAL ROE, "Return Fire" Alarm,"N/A"
--
-- A request can be added by the @{#WAREHOUSE.AddRequest}(*warehouse*, *AssetDescriptor*, *AssetDescriptorValue*, *nAsset*, *TransportType*, *nTransport*, *Prio*, *Assignment*) function.
-- The parameters are
@@ -1274,7 +1274,7 @@
--
-- ## Example 13: Battlefield Air Interdiction
--
-- This example show how to couple the WAREHOUSE class with the @{AI.AI_Bai} class.
-- This example show how to couple the WAREHOUSE class with the @{AI.AI_BAI} class.
-- Four enemy targets have been located at the famous Kobuleti X. All three available Viggen 2-ship flights are assigned to kill at least one of the BMPs to complete their mission.
--
-- -- Start Warehouse at Kobuleti.
@@ -2647,6 +2647,13 @@ function WAREHOUSE:SetWarehouseZone(zone)
return self
end
--- Get the warehouse zone.
-- @param #WAREHOUSE self
-- @return Core.Zone#ZONE The warehouse zone.
function WAREHOUSE:GetWarehouseZone()
return self.zone
end
--- Set auto defence on. When the warehouse is under attack, all ground assets are spawned automatically and will defend the warehouse zone.
-- @param #WAREHOUSE self
-- @return #WAREHOUSE self
@@ -5810,6 +5817,7 @@ function WAREHOUSE:_SpawnAssetRequest(Request)
-- Now we try to find all parking spots for all cargo groups in advance. Due to the for loop, the parking spots do not get updated while spawning.
local Parking={}
if Request.cargocategory==Group.Category.AIRPLANE or Request.cargocategory==Group.Category.HELICOPTER then
--TODO: Check for airstart. Should be a request property.
Parking=self:_FindParkingForAssets(self.airbase, cargoassets) or {}
end
@@ -6069,7 +6077,9 @@ function WAREHOUSE:_SpawnAssetAircraft(alias, asset, request, parking, uncontrol
end
if self.Debug then
coord:MarkToAll(string.format("Spawnplace unit %s terminal %d.", unit.name, terminal))
local text=string.format("Spawnplace unit %s terminal %d.", unit.name, terminal)
coord:MarkToAll(text)
env.info(text)
end
unit.x=coord.x
@@ -6814,7 +6824,7 @@ function WAREHOUSE:_OnEventBaseCaptured(EventData)
self:AirbaseRecaptured(NewCoalitionAirbase)
end
else
-- Captured airbase belongs to this warehouse but was captured by other coaltion.
-- Captured airbase belongs to this warehouse but was captured by other coalition.
if NewCoalitionAirbase ~= self:GetCoalition() then
self:AirbaseCaptured(NewCoalitionAirbase)
end
@@ -7007,7 +7017,7 @@ function WAREHOUSE:_CheckRequestConsistancy(queue)
-- Request from enemy coalition?
if self:GetCoalition()~=request.warehouse:GetCoalition() then
self:E(self.lid..string.format("ERROR: INVALID request. Requesting warehouse is of wrong coaltion! Own coalition %s != %s of requesting warehouse.", self:GetCoalitionName(), request.warehouse:GetCoalitionName()))
self:E(self.lid..string.format("ERROR: INVALID request. Requesting warehouse is of wrong coalition! Own coalition %s != %s of requesting warehouse.", self:GetCoalitionName(), request.warehouse:GetCoalitionName()))
valid=false
end
@@ -7374,6 +7384,7 @@ function WAREHOUSE:_CheckRequestNow(request)
local _transports
local _assetattribute
local _assetcategory
local _assetairstart=false
-- Check if at least one (cargo) asset is available.
if _nassets>0 then
@@ -7381,21 +7392,28 @@ function WAREHOUSE:_CheckRequestNow(request)
-- Get the attibute of the requested asset.
_assetattribute=_assets[1].attribute
_assetcategory=_assets[1].category
_assetairstart=_assets[1].takeoffType and _assets[1].takeoffType==COORDINATE.WaypointType.TurningPoint or false
-- Check available parking for air asset units.
if _assetcategory==Group.Category.AIRPLANE or _assetcategory==Group.Category.HELICOPTER then
if self.airbase and self.airbase:GetCoalition()==self:GetCoalition() then
if self:IsRunwayOperational() then
if self:IsRunwayOperational() or _assetairstart then
local Parking=self:_FindParkingForAssets(self.airbase,_assets)
--if Parking==nil and not (self.category==Airbase.Category.HELIPAD) then
if Parking==nil then
local text=string.format("Warehouse %s: Request denied! Not enough free parking spots for all requested assets at the moment.", self.alias)
self:_InfoMessage(text, 5)
return false
if _assetairstart then
-- Airstart no need to check parking
else
-- Check parking.
local Parking=self:_FindParkingForAssets(self.airbase,_assets)
-- No parking?
if Parking==nil then
local text=string.format("Warehouse %s: Request denied! Not enough free parking spots for all requested assets at the moment.", self.alias)
self:_InfoMessage(text, 5)
return false
end
end
else
@@ -7969,93 +7987,123 @@ function WAREHOUSE:_FindParkingForAssets(airbase, assets)
-- Loop over all assets that need a parking psot.
for _,asset in pairs(assets) do
local _asset=asset --#WAREHOUSE.Assetitem
-- Get terminal type of this asset
local terminaltype=asset.terminalType or self:_GetTerminal(asset.attribute, self:GetAirbaseCategory())
-- Asset specific parking.
parking[_asset.uid]={}
-- Loop over all units - each one needs a spot.
for i=1,_asset.nunits do
-- Asset name
local assetname=_asset.spawngroupname.."-"..tostring(i)
-- Loop over all parking spots.
local gotit=false
for _,_parkingspot in pairs(parkingdata) do
local parkingspot=_parkingspot --Wrapper.Airbase#AIRBASE.ParkingSpot
-- Check correct terminal type for asset. We don't want helos in shelters etc.
if AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype) and self:_CheckParkingValid(parkingspot) and self:_CheckParkingAsset(parkingspot, asset) and airbase:_CheckParkingLists(parkingspot.TerminalID) then
-- Coordinate of the parking spot.
local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE
local _termid=parkingspot.TerminalID
local free=true
local problem=nil
-- Loop over all obstacles.
for _,obstacle in pairs(obstacles) do
-- Check if aircraft overlaps with any obstacle.
local dist=_spot:Get2DDistance(obstacle.coord)
local safe=_overlap(_asset.size, obstacle.size, dist)
-- Spot is blocked.
if not safe then
self:T3(self.lid..string.format("FF asset=%s (id=%d): spot id=%d dist=%.1fm is NOT SAFE", assetname, _asset.uid, _termid, dist))
free=false
problem=obstacle
problem.dist=dist
break
else
--env.info(string.format("FF asset=%s (id=%d): spot id=%d dist=%.1fm is SAFE", assetname, _asset.uid, _termid, dist))
end
end
-- Check if spot is free
if free then
-- Add parkingspot for this asset unit.
table.insert(parking[_asset.uid], parkingspot)
-- Debug
self:T(self.lid..string.format("Parking spot %d is free for asset %s [id=%d]!", _termid, assetname, _asset.uid))
-- Add the unit as obstacle so that this spot will not be available for the next unit.
table.insert(obstacles, {coord=_spot, size=_asset.size, name=assetname, type="asset"})
gotit=true
break
if not _asset.spawned then
-- Get terminal type of this asset
local terminaltype=asset.terminalType or self:_GetTerminal(asset.attribute, self:GetAirbaseCategory())
-- Asset specific parking.
parking[_asset.uid]={}
-- Loop over all units - each one needs a spot.
for i=1,_asset.nunits do
-- Asset name
local assetname=_asset.spawngroupname.."-"..tostring(i)
-- Loop over all parking spots.
local gotit=false
for _,_parkingspot in pairs(parkingdata) do
local parkingspot=_parkingspot --Wrapper.Airbase#AIRBASE.ParkingSpot
-- Parking valid?
local valid=true
if asset.parkingIDs then
-- If asset has assigned parking spots, we take these no matter what.
valid=self:_CheckParkingAsset(parkingspot, asset)
else
-- Debug output for occupied spots.
if self.Debug then
local coord=problem.coord --Core.Point#COORDINATE
local text=string.format("Obstacle %s [type=%s] blocking spot=%d! Size=%.1f m and distance=%.1f m.", problem.name, problem.type, _termid, problem.size, problem.dist)
self:I(self.lid..text)
coord:MarkToAll(string.format(text))
else
self:T(self.lid..string.format("Parking spot %d is occupied or not big enough!", _termid))
end
-- Valid terminal type depending on attribute.
local validTerminal=AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype)
-- Valid parking list.
local validParking=self:_CheckParkingValid(parkingspot)
-- Black and white list.
local validBWlist=airbase:_CheckParkingLists(parkingspot.TerminalID)
-- Debug info.
--env.info(string.format("FF validTerminal = %s", tostring(validTerminal)))
--env.info(string.format("FF validParking = %s", tostring(validParking)))
--env.info(string.format("FF validBWlist = %s", tostring(validBWlist)))
-- Check if all are true
valid=validTerminal and validParking and validBWlist
end
else
self:T2(self.lid..string.format("Terminal ID=%d: type=%s not supported", parkingspot.TerminalID, parkingspot.TerminalType))
end -- check terminal type
end -- loop over parking spots
-- No parking spot for at least one asset :(
if not gotit then
self:I(self.lid..string.format("WARNING: No free parking spot for asset %s [id=%d]", assetname, _asset.uid))
return nil
end
end -- loop over asset units
-- Check correct terminal type for asset. We don't want helos in shelters etc.
if valid then
-- Coordinate of the parking spot.
local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE
local _termid=parkingspot.TerminalID
local free=true
local problem=nil
-- Loop over all obstacles.
for _,obstacle in pairs(obstacles) do
-- Check if aircraft overlaps with any obstacle.
local dist=_spot:Get2DDistance(obstacle.coord)
local safe=_overlap(_asset.size, obstacle.size, dist)
-- Spot is blocked.
if not safe then
self:T3(self.lid..string.format("FF asset=%s (id=%d): spot id=%d dist=%.1fm is NOT SAFE", assetname, _asset.uid, _termid, dist))
free=false
problem=obstacle
problem.dist=dist
break
else
--env.info(string.format("FF asset=%s (id=%d): spot id=%d dist=%.1fm is SAFE", assetname, _asset.uid, _termid, dist))
end
end
-- Check if spot is free
if free then
-- Add parkingspot for this asset unit.
table.insert(parking[_asset.uid], parkingspot)
-- Debug
self:T(self.lid..string.format("Parking spot %d is free for asset %s [id=%d]!", _termid, assetname, _asset.uid))
-- Add the unit as obstacle so that this spot will not be available for the next unit.
table.insert(obstacles, {coord=_spot, size=_asset.size, name=assetname, type="asset"})
gotit=true
break
else
-- Debug output for occupied spots.
if self.Debug then
local coord=problem.coord --Core.Point#COORDINATE
local text=string.format("Obstacle %s [type=%s] blocking spot=%d! Size=%.1f m and distance=%.1f m.", problem.name, problem.type, _termid, problem.size, problem.dist)
self:I(self.lid..text)
coord:MarkToAll(string.format(text))
else
self:T(self.lid..string.format("Parking spot %d is occupied or not big enough!", _termid))
end
end
else
self:T2(self.lid..string.format("Terminal ID=%d: type=%s not supported", parkingspot.TerminalID, parkingspot.TerminalType))
end -- check terminal type
end -- loop over parking spots
-- No parking spot for at least one asset :(
if not gotit then
self:I(self.lid..string.format("WARNING: No free parking spot for asset %s [id=%d]", assetname, _asset.uid))
return nil
end
end -- loop over asset units
end -- Asset spawned check
end -- loop over asset groups
return parking

View File

@@ -1,4 +1,4 @@
--- **Functional** -- Models the process to zone guarding and capturing.
--- **Functional** - Models the process to zone guarding and capturing.
--
-- ===
--
@@ -68,9 +68,9 @@ do -- ZONE_CAPTURE_COALITION
--
-- In order to use ZONE_CAPTURE_COALITION, you need to:
--
-- * Create a @{Zone} object from one of the ZONE_ classes.
-- Note that ZONE_POLYGON_ classes are not yet functional.
-- The only functional ZONE_ classses are those derived from a ZONE_RADIUS.
-- * Create a @{Core.Zone} object from one of the ZONE_ classes.
-- The functional ZONE_ classses are those derived from a ZONE_RADIUS.
-- In order to use a ZONE_POLYGON, hand over the **GROUP name** of a late activated group forming a polygon with it's waypoints.
-- * Set the state of the zone. Most of the time, Guarded would be the initial state.
-- * Start the zone capturing **monitoring process**.
-- This will check the presence of friendly and/or enemy units within the zone and will transition the state of the zone when the tactical situation changed.
@@ -363,7 +363,7 @@ do -- ZONE_CAPTURE_COALITION
--- ZONE_CAPTURE_COALITION Constructor.
-- @param #ZONE_CAPTURE_COALITION self
-- @param Core.Zone#ZONE Zone A @{Zone} object with the goal to be achieved.
-- @param Core.Zone#ZONE Zone A @{Core.Zone} object with the goal to be achieved. Alternatively, can be handed as the name of late activated group describing a @{ZONE_POLYGON} with its waypoints.
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
-- @param #table UnitCategories Table of unit categories. See [DCS Class Unit](https://wiki.hoggitworld.com/view/DCS_Class_Unit). Default {Unit.Category.GROUND_UNIT}.
-- @param #table ObjectCategories Table of unit categories. See [DCS Class Object](https://wiki.hoggitworld.com/view/DCS_Class_Object). Default {Object.Category.UNIT, Object.Category.STATIC}, i.e. all UNITS and STATICS.

View File

@@ -1,4 +1,4 @@
--- **Functional (WIP)** -- Base class that models processes to achieve goals involving a Zone.
--- **Functional** - Base class that models processes to achieve goals involving a Zone.
--
-- ===
--
@@ -8,7 +8,7 @@
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions: **funkyfranky**
-- ### Contributions: **funkyfranky**, **Applevangelist**
--
-- ===
--
@@ -26,7 +26,6 @@ do -- Zone
-- @field #boolean SmokeZone If true, smoke zone.
-- @extends Core.Zone#ZONE_RADIUS
--- Models processes that have a Goal with a defined achievement involving a Zone.
-- Derived classes implement the ways how the achievements can be realized.
--
@@ -53,21 +52,26 @@ do -- Zone
SmokeColor = nil,
SmokeZone = nil,
}
--- ZONE_GOAL Constructor.
-- @param #ZONE_GOAL self
-- @param Core.Zone#ZONE_RADIUS Zone A @{Zone} object with the goal to be achieved.
-- @param Core.Zone#ZONE_RADIUS Zone A @{Core.Zone} object with the goal to be achieved. Alternatively, can be handed as the name of late activated group describing a ZONE_POLYGON with its waypoints.
-- @return #ZONE_GOAL
function ZONE_GOAL:New( Zone )
local self = BASE:Inherit( self, ZONE_RADIUS:New( Zone:GetName(), Zone:GetVec2(), Zone:GetRadius() ) ) -- #ZONE_GOAL
self:F( { Zone = Zone } )
BASE:I({Zone=Zone})
local self = BASE:Inherit( self, BASE:New())
if type(Zone) == "string" then
self = BASE:Inherit( self, ZONE_POLYGON:NewFromGroupName(Zone) )
else
self = BASE:Inherit( self, ZONE_RADIUS:New( Zone:GetName(), Zone:GetVec2(), Zone:GetRadius() ) ) -- #ZONE_GOAL
self:F( { Zone = Zone } )
end
-- Goal object.
self.Goal = GOAL:New()
self.SmokeTime = nil
-- Set smoke ON.
self:SetSmokeZone(true)
@@ -81,7 +85,7 @@ do -- Zone
-- @function [parent=#ZONE_GOAL] __DestroyedUnit
-- @param #ZONE_GOAL self
-- @param #number delay Delay in seconds.
--- DestroyedUnit Handler OnAfter for ZONE_GOAL
-- @function [parent=#ZONE_GOAL] OnAfterDestroyedUnit
-- @param #ZONE_GOAL self
@@ -93,15 +97,15 @@ do -- Zone
return self
end
--- Get the Zone.
-- @param #ZONE_GOAL self
-- @return #ZONE_GOAL
function ZONE_GOAL:GetZone()
return self
end
--- Get the name of the Zone.
-- @param #ZONE_GOAL self
-- @return #string
@@ -109,7 +113,6 @@ do -- Zone
return self:GetName()
end
--- Activate smoking of zone with the color or the current owner.
-- @param #ZONE_GOAL self
-- @param #boolean switch If *true* or *nil* activate smoke. If *false* or *nil*, no smoke.
@@ -131,11 +134,10 @@ do -- Zone
-- @param DCS#SMOKECOLOR.Color SmokeColor
function ZONE_GOAL:Smoke( SmokeColor )
self:F( { SmokeColor = SmokeColor} )
self.SmokeColor = SmokeColor
end
--- Flare the zone boundary.
-- @param #ZONE_GOAL self
-- @param DCS#SMOKECOLOR.Color FlareColor
@@ -143,7 +145,6 @@ do -- Zone
self:FlareZone( FlareColor, 30)
end
--- When started, check the Smoke and the Zone status.
-- @param #ZONE_GOAL self
function ZONE_GOAL:onafterGuard()
@@ -155,17 +156,16 @@ do -- Zone
end
end
--- Check status Smoke.
-- @param #ZONE_GOAL self
function ZONE_GOAL:StatusSmoke()
self:F({self.SmokeTime, self.SmokeColor})
if self.SmokeZone then
-- Current time.
local CurrentTime = timer.getTime()
-- Restart smoke every 5 min.
if self.SmokeTime == nil or self.SmokeTime + 300 <= CurrentTime then
if self.SmokeColor then
@@ -173,11 +173,10 @@ do -- Zone
self.SmokeTime = CurrentTime
end
end
end
end
end
end
--- @param #ZONE_GOAL self
-- @param Core.Event#EVENTDATA EventData Event data table.
@@ -185,38 +184,37 @@ do -- Zone
self:F( { "EventDead", EventData } )
self:F( { EventData.IniUnit } )
if EventData.IniDCSUnit then
local Vec3 = EventData.IniDCSUnit:getPosition().p
self:F( { Vec3 = Vec3 } )
if Vec3 and self:IsVec3InZone(Vec3) then
local PlayerHits = _DATABASE.HITS[EventData.IniUnitName]
if PlayerHits then
for PlayerName, PlayerHit in pairs( PlayerHits.Players or {} ) do
self.Goal:AddPlayerContribution( PlayerName )
self:DestroyedUnit( EventData.IniUnitName, PlayerName )
end
end
end
end
end
--- Activate the event UnitDestroyed to be fired when a unit is destroyed in the zone.
-- @param #ZONE_GOAL self
function ZONE_GOAL:MonitorDestroyedUnits()
self:HandleEvent( EVENTS.Dead, self.__Destroyed )
self:HandleEvent( EVENTS.Crash, self.__Destroyed )
end
end

View File

@@ -1,4 +1,4 @@
--- **Functional (WIP)** -- Base class that models processes to achieve goals involving a Zone and Cargo.
--- **Functional** - Base class that models processes to achieve goals involving a Zone and Cargo.
--
-- ===
--
@@ -55,7 +55,7 @@ do -- ZoneGoal
--- ZONE_GOAL_CARGO Constructor.
-- @param #ZONE_GOAL_CARGO self
-- @param Core.Zone#ZONE Zone A @{Zone} object with the goal to be achieved.
-- @param Core.Zone#ZONE Zone A @{Core.Zone} object with the goal to be achieved.
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
-- @return #ZONE_GOAL_CARGO
function ZONE_GOAL_CARGO:New( Zone, Coalition )

View File

@@ -1,4 +1,4 @@
--- **Functional (WIP)** -- Base class that models processes to achieve goals involving a Zone for a Coalition.
--- **Functional** - Base class that models processes to achieve goals involving a Zone for a Coalition.
--
-- ===
--
@@ -53,7 +53,7 @@ do -- ZoneGoal
--- ZONE_GOAL_COALITION Constructor.
-- @param #ZONE_GOAL_COALITION self
-- @param Core.Zone#ZONE Zone A @{Zone} object with the goal to be achieved.
-- @param Core.Zone#ZONE Zone A @{Core.Zone} object with the goal to be achieved.
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone. Default coalition.side.NEUTRAL.
-- @param #table UnitCategories Table of unit categories. See [DCS Class Unit](https://wiki.hoggitworld.com/view/DCS_Class_Unit). Default {Unit.Category.GROUND_UNIT}.
-- @return #ZONE_GOAL_COALITION

View File

@@ -22,25 +22,37 @@ _DATABASE:_RegisterAirbases()
--- Check if os etc is available.
BASE:I("Checking de-sanitization of os, io and lfs:")
local __na=false
local __na = false
if os then
BASE:I("- os available")
else
BASE:I("- os NOT available! Some functions may not work.")
__na=true
__na = true
end
if io then
BASE:I("- io available")
else
BASE:I("- io NOT available! Some functions may not work.")
__na=true
__na = true
end
if lfs then
BASE:I("- lfs available")
else
BASE:I("- lfs NOT available! Some functions may not work.")
__na=true
__na = true
end
if __na then
BASE:I("Check <DCS install folder>/Scripts/MissionScripting.lua and comment out the lines with sanitizeModule(''). Use at your own risk!)")
end
BASE.ServerName = "Unknown"
if lfs and loadfile then
local serverfile = lfs.writedir() .. 'Config/serverSettings.lua'
if UTILS.FileExists(serverfile) then
loadfile(serverfile)()
if cfg and cfg.name then
BASE.ServerName = cfg.name
end
end
BASE.ServerName = BASE.ServerName or "Unknown"
BASE:I("Server Name: " .. tostring(BASE.ServerName))
end

View File

@@ -46,7 +46,7 @@
--
-- ### Author: **funkyfranky**
--
-- @module Ops.Atis
-- @module Ops.ATIS
-- @image OPS_ATIS.png
--- ATIS class.
@@ -91,6 +91,10 @@
-- @field #boolean useSRS If true, use SRS for transmission.
-- @field Sound.SRS#MSRS msrs Moose SRS object.
-- @field #number dTQueueCheck Time interval to check the radio queue. Default 5 sec or 90 sec if SRS is used.
-- @field #boolean ReportmBar Report mBar/hpa even if not metric, i.e. for Mirage flights
-- @field #boolean TransmitOnlyWithPlayers For SRS - If true, only transmit if there are alive Players.
-- @field #string SRSText Text of the complete SRS message (if done at least once, else nil)
-- @field #boolean ATISforFARPs Will be set to true if the base given is a FARP/Helipad
-- @extends Core.Fsm#FSM
--- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde
@@ -120,7 +124,7 @@
-- The @{#ATIS.New}(*airbasename*, *frequency*) creates a new ATIS object. The parameter *airbasename* is the name of the airbase or airport. Note that this has to be spelled exactly as in the DCS mission editor.
-- The parameter *frequency* is the frequency the ATIS broadcasts in MHz.
--
-- Broadcasting is started via the @{#ATIS.Start}() function. The start can be delayed by useing @{#ATIS.__Start}(*delay*), where *delay* is the delay in seconds.
-- Broadcasting is started via the @{#ATIS.Start}() function. The start can be delayed by using @{#ATIS.__Start}(*delay*), where *delay* is the delay in seconds.
--
-- ## Subtitles
--
@@ -266,6 +270,8 @@
-- Unfortunately, it is not possible to determine the duration of the complete transmission. So once the transmission is finished, there might be some radio silence before
-- the next iteration begins. You can fine tune the time interval between transmissions with the @{#ATIS.SetQueueUpdateTime}() function. The default interval is 90 seconds.
--
-- An SRS Setup-Guide can be found here: [Moose TTS Setup Guide](https://github.com/FlightControl-Master/MOOSE_GUIDES/blob/master/documents/Moose%20TTS%20Setup%20Guide.pdf)
--
-- # Examples
--
-- ## Caucasus: Batumi
@@ -304,6 +310,19 @@
-- atis:Start()
--
-- This uses a male voice with US accent. It requires SRS to be installed in the `D:\DCS\_SRS\` directory. Not that backslashes need to be escaped or simply use slashes (as in linux).
--
-- ## FARPS
--
-- ATIS is working with FARPS, but this requires the usage of SRS. The airbase name for the `New()-method` is the UNIT name of the FARP:
--
-- atis = ATIS:New("FARP Gold",119,radio.modulation.AM)
-- atis:SetMetricUnits()
-- atis:SetTransmitOnlyWithPlayers(true)
-- atis:SetReportmBar(true)
-- atis:SetTowerFrequencies(127.50)
-- atis:SetSRS("D:\\DCS\\_SRS\\", "male", "en-US",nil,5002)
-- atis:SetAdditionalInformation("Welcome to the Jungle!")
-- atis:__Start(3)
--
-- @field #ATIS
ATIS = {
@@ -344,6 +363,9 @@ ATIS = {
usemarker = nil,
markerid = nil,
relHumidity = nil,
ReportmBar = false,
TransmitOnlyWithPlayers = false,
ATISforFARPs = false,
}
--- NATO alphabet.
@@ -586,15 +608,18 @@ _ATIS = {}
--- ATIS class version.
-- @field #string version
ATIS.version = "0.9.8"
ATIS.version = "0.9.14"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Add new Normany airfields.
-- TODO: Add new Normandy airfields.
-- TODO: Zulu time --> Zulu in output.
-- TODO: Correct fog for elevation.
-- DONE: Use new AIRBASE system to set start/landing runway
-- DONE: SetILS doesn't work
-- DONE: Visibility reported twice over SRS
-- DONE: Add text report for output.
-- DONE: Add stop FMS functions.
-- NOGO: Use local time. Not realisitc!
@@ -609,7 +634,7 @@ ATIS.version = "0.9.8"
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new ATIS class object for a specific aircraft carrier unit.
--- Create a new ATIS class object for a specific airbase.
-- @param #ATIS self
-- @param #string AirbaseName Name of the airbase.
-- @param #number Frequency Radio frequency in MHz. Default 143.00 MHz.
@@ -651,6 +676,7 @@ function ATIS:New(AirbaseName, Frequency, Modulation)
self:SetMapMarks( false )
self:SetRelativeHumidity()
self:SetQueueUpdateTime()
self:SetReportmBar(false)
-- Start State.
self:SetStartState( "Stopped" )
@@ -774,13 +800,52 @@ function ATIS:SetTowerFrequencies( freqs )
return self
end
--- Set active runway. This can be used if the automatic runway determination via the wind direction gives incorrect results.
--- For SRS - Switch to only transmit if there are players on the server.
-- @param #ATIS self
-- @param #boolean Switch If true, only send SRS if there are alive Players.
-- @return #ATIS self
function ATIS:SetTransmitOnlyWithPlayers(Switch)
self.TransmitOnlyWithPlayers = Switch
if self.msrsQ then
self.msrsQ:SetTransmitOnlyWithPlayers(Switch)
end
return self
end
--- Set active runway for **landing** operations. This can be used if the automatic runway determination via the wind direction gives incorrect results.
-- For example, use this if there are two runways with the same directions.
-- @param #ATIS self
-- @param #string runway Active runway, *e.g.* "31L".
-- @return #ATIS self
function ATIS:SetActiveRunway( runway )
self.activerunway = tostring( runway )
local prefer = nil
if string.find(string.lower(runway),"l") then
prefer = true
elseif string.find(string.lower(runway),"r") then
prefer = false
end
self.airbase:SetActiveRunway(runway,prefer)
return self
end
--- Set the active runway for landing.
-- @param #ATIS self
-- @param #string runway : Name of the runway, e.g. "31" or "02L" or "90R". If not given, the runway is determined from the wind direction.
-- @param #boolean preferleft : If true, perfer the left runway. If false, prefer the right runway. If nil (default), do not care about left or right.
-- @return #ATIS self
function ATIS:SetActiveRunwayLanding(runway, preferleft)
self.airbase:SetActiveRunwayLanding(runway,preferleft)
return self
end
--- Set the active runway for take-off.
-- @param #ATIS self
-- @param #string runway : Name of the runway, e.g. "31" or "02L" or "90R". If not given, the runway is determined from the wind direction.
-- @param #boolean preferleft : If true, perfer the left runway. If false, prefer the right runway. If nil (default), do not care about left or right.
-- @return #ATIS self
function ATIS:SetActiveRunwayTakeoff(runway,preferleft)
self.airbase:SetActiveRunwayTakeoff(runway,preferleft)
return self
end
@@ -831,6 +896,13 @@ function ATIS:SetMapMarks( switch )
return self
end
--- Return the complete SRS Text block, if at least generated once. Else nil.
-- @param #ATIS self
-- @return #string SRSText
function ATIS:GetSRSText()
return self.SRSText
end
--- Set magnetic runway headings as depicted on the runway, *e.g.* "13" for 130° or "25L" for the left runway with magnetic heading 250°.
-- @param #ATIS self
-- @param #table headings Magnetic headings. Inverse (-180°) headings are added automatically. You only need to specify one heading per runway direction. "L"eft and "R" right can also be appended.
@@ -947,6 +1019,28 @@ function ATIS:SetAltimeterQNH( switch )
return self
end
--- Additionally report altimeter QNH/QFE in hPa, even if not set to metric.
-- @param #ATIS self
-- @param #boolean switch If true or nil, report mBar/hPa in addition.
-- @return #ATIS self
function ATIS:SetReportmBar(switch)
if switch == true or switch == nil then
self.ReportmBar = true
else
self.ReportmBar = false
end
return self
end
--- Additionally report free text, only working with SRS(!)
-- @param #ATIS self
-- @param #string text The text to report at the end of the ATIS message, e.g. runway closure, warnings, etc.
-- @return #ATIS self
function ATIS:SetAdditionalInformation(text)
self.AdditionalInformation = text
return self
end
--- Suppresses QFE readout. Default is to report both QNH and QFE.
-- @param #ATIS self
-- @return #ATIS self
@@ -970,7 +1064,7 @@ end
--
-- * 186° on the Caucaus map
-- * 192° on the Nevada map
-- * 170° on the Normany map
-- * 170° on the Normandy map
-- * 182° on the Persian Gulf map
--
-- Likewise, to convert *true* into *magnetic* heading, one has to substract easterly and add westerly variation.
@@ -978,7 +1072,7 @@ end
-- Or you make your life simple and just include the sign so you don't have to bother about East/West.
--
-- @param #ATIS self
-- @param #number magvar Magnetic variation in degrees. Positive for easterly and negative for westerly variation. Default is magnatic declinaton of the used map, c.f. @{Utilities.UTils#UTILS.GetMagneticDeclination}.
-- @param #number magvar Magnetic variation in degrees. Positive for easterly and negative for westerly variation. Default is magnatic declinaton of the used map, c.f. @{Utilities.Utils#UTILS.GetMagneticDeclination}.
-- @return #ATIS self
function ATIS:SetMagneticDeclination( magvar )
self.magvar = magvar or UTILS.GetMagneticDeclination()
@@ -1126,8 +1220,9 @@ end
-- @param #string Culture Culture, e.g. "en-GB" (default).
-- @param #string Voice Specific voice. Overrides `Gender` and `Culture`.
-- @param #number Port SRS port. Default 5002.
-- @param #string GoogleKey Path to Google JSON-Key.
-- @return #ATIS self
function ATIS:SetSRS(PathToSRS, Gender, Culture, Voice, Port)
function ATIS:SetSRS(PathToSRS, Gender, Culture, Voice, Port, GoogleKey)
if PathToSRS then
self.useSRS=true
self.msrs=MSRS:New(PathToSRS, self.frequency, self.modulation)
@@ -1137,7 +1232,9 @@ function ATIS:SetSRS(PathToSRS, Gender, Culture, Voice, Port)
self.msrs:SetPort(Port)
self.msrs:SetCoalition(self:GetCoalition())
self.msrs:SetLabel("ATIS")
self.msrs:SetGoogle(GoogleKey)
self.msrsQ = MSRSQUEUE:New("ATIS")
self.msrsQ:SetTransmitOnlyWithPlayers(self.TransmitOnlyWithPlayers)
if self.dTQueueCheck<=10 then
self:SetQueueUpdateTime(90)
end
@@ -1175,27 +1272,34 @@ end
function ATIS:onafterStart( From, Event, To )
-- Check that this is an airdrome.
if self.airbase:GetAirbaseCategory() ~= Airbase.Category.AIRDROME then
self:E( self.lid .. string.format( "ERROR: Cannot start ATIS for airbase %s! Only AIRDROMES are supported but NOT FARPS or SHIPS.", self.airbasename ) )
if self.airbase:GetAirbaseCategory() == Airbase.Category.SHIP then
self:E( self.lid .. string.format( "ERROR: Cannot start ATIS for airbase %s! Only AIRDROMES are supported but NOT SHIPS.", self.airbasename ) )
return
end
-- Check that if is a Helipad.
if self.airbase:GetAirbaseCategory() == Airbase.Category.HELIPAD then
self:E( self.lid .. string.format( "EXPERIMENTAL: Starting ATIS for Helipad %s! SRS must be ON", self.airbasename ) )
self.ATISforFARPs = true
self.useSRS = true
end
-- Info.
self:I( self.lid .. string.format( "Starting ATIS v%s for airbase %s on %.3f MHz Modulation=%d", ATIS.version, self.airbasename, self.frequency, self.modulation ) )
-- Start radio queue.
if not self.useSRS then
self.radioqueue = RADIOQUEUE:New( self.frequency, self.modulation, string.format( "ATIS %s", self.airbasename ) )
-- Send coordinate is airbase coord.
self.radioqueue:SetSenderCoordinate( self.airbase:GetCoordinate() )
-- Set relay unit if we have one.
self.radioqueue:SetSenderUnitName( self.relayunitname )
-- Set radio power.
self.radioqueue:SetRadioPower( self.power )
-- Init numbers.
self.radioqueue:SetDigit( 0, ATIS.Sound.N0.filename, ATIS.Sound.N0.duration, self.soundpath )
self.radioqueue:SetDigit( 1, ATIS.Sound.N1.filename, ATIS.Sound.N1.duration, self.soundpath )
@@ -1207,11 +1311,11 @@ function ATIS:onafterStart( From, Event, To )
self.radioqueue:SetDigit( 7, ATIS.Sound.N7.filename, ATIS.Sound.N7.duration, self.soundpath )
self.radioqueue:SetDigit( 8, ATIS.Sound.N8.filename, ATIS.Sound.N8.duration, self.soundpath )
self.radioqueue:SetDigit( 9, ATIS.Sound.N9.filename, ATIS.Sound.N9.duration, self.soundpath )
-- Start radio queue.
self.radioqueue:Start( 1, 0.1 )
end
-- Handle airbase capture
-- Handle events.
self:HandleEvent( EVENTS.BaseCaptured )
@@ -1247,8 +1351,10 @@ function ATIS:onafterStatus( From, Event, To )
text = text .. string.format( ", Relay unit=%s (alive=%s)", tostring( self.relayunitname ), relayunitstatus )
end
self:T( self.lid .. text )
self:__Status( -60 )
if not self:Is("Stopped") then
self:__Status( -60 )
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -1276,9 +1382,11 @@ function ATIS:onafterCheckQueue( From, Event, To )
end
end
-- Check back in 5 seconds.
self:__CheckQueue( -math.abs( self.dTQueueCheck ) )
if not self:Is("Stopped") then
-- Check back in 5 seconds.
self:__CheckQueue( -math.abs( self.dTQueueCheck ) )
end
end
--- Broadcast ATIS radio message.
@@ -1326,6 +1434,9 @@ function ATIS:onafterBroadcast( From, Event, To )
end
local mBarqnh = qnh
local mBarqfe = qfe
-- Convert to inHg.
if self.PmmHg then
qfe = UTILS.hPa2mmHg( qfe )
@@ -1384,10 +1495,19 @@ function ATIS:onafterBroadcast( From, Event, To )
--------------
--- Runway ---
--------------
local runwayLanding, rwyLandingLeft=self:GetActiveRunway()
local runwayTakeoff, rwyTakeoffLeft=self:GetActiveRunway(true)
local runwayLanding, rwyLandingLeft
local runwayTakeoff, rwyTakeoffLeft
if self.airbase:GetAirbaseCategory() == Airbase.Category.HELIPAD then
runwayLanding, rwyLandingLeft="PAD 01",false
runwayTakeoff, rwyTakeoffLeft="PAD 02",false
else
runwayLanding, rwyLandingLeft=self:GetActiveRunway()
runwayTakeoff, rwyTakeoffLeft=self:GetActiveRunway(true)
end
------------
--- Time ---
------------
@@ -1701,7 +1821,7 @@ function ATIS:onafterBroadcast( From, Event, To )
-- Airbase name
subtitle = string.format( "%s", self.airbasename )
if self.airbasename:find( "AFB" ) == nil and self.airbasename:find( "Airport" ) == nil and self.airbasename:find( "Airstrip" ) == nil and self.airbasename:find( "airfield" ) == nil and self.airbasename:find( "AB" ) == nil then
if (not self.ATISforFARPs) and self.airbasename:find( "AFB" ) == nil and self.airbasename:find( "Airport" ) == nil and self.airbasename:find( "Airstrip" ) == nil and self.airbasename:find( "airfield" ) == nil and self.airbasename:find( "AB" ) == nil then
subtitle = subtitle .. " Airport"
end
if not self.useSRS then
@@ -1776,7 +1896,7 @@ function ATIS:onafterBroadcast( From, Event, To )
end
end
alltext = alltext .. ";\n" .. subtitle
-- Visibility
if self.metric then
subtitle = string.format( "Visibility %s km", VISIBILITY )
@@ -1793,7 +1913,8 @@ function ATIS:onafterBroadcast( From, Event, To )
end
end
alltext = alltext .. ";\n" .. subtitle
subtitle = ""
-- Weather phenomena
local wp = false
local wpsub = ""
@@ -1893,8 +2014,9 @@ function ATIS:onafterBroadcast( From, Event, To )
end
end
end
alltext = alltext .. ";\n" .. subtitle
alltext = alltext .. ";\n" .. subtitle
subtitle = ""
-- Temperature
if self.TDegF then
if temperature < 0 then
@@ -1923,7 +2045,7 @@ function ATIS:onafterBroadcast( From, Event, To )
end
end
alltext = alltext .. ";\n" .. subtitle
-- Dew point
if self.TDegF then
if dewpoint < 0 then
@@ -1975,6 +2097,15 @@ function ATIS:onafterBroadcast( From, Event, To )
end
end
end
if self.ReportmBar and not self.metric then
if self.qnhonly then
subtitle = string.format( "%s;\nAltimeter %d hPa", subtitle, mBarqnh )
else
subtitle = string.format( "%s;\nAltimeter: QNH %d, QFE %d hPa", subtitle, mBarqnh, mBarqfe)
end
end
local _ALTIMETER = subtitle
if not self.useSRS then
self:Transmission( ATIS.Sound.Altimeter, 1.0, subtitle )
@@ -2009,65 +2140,66 @@ function ATIS:onafterBroadcast( From, Event, To )
end
alltext = alltext .. ";\n" .. subtitle
-- Active runway.
local subtitle=string.format("Active runway %s", runwayLanding)
if rwyLandingLeft==true then
subtitle=subtitle.." Left"
elseif rwyLandingLeft==false then
subtitle=subtitle.." Right"
end
local _RUNACT = subtitle
if not self.useSRS then
self:Transmission(ATIS.Sound.ActiveRunway, 1.0, subtitle)
self.radioqueue:Number2Transmission(runwayLanding)
if not self.ATISforFARPs then
-- Active runway.
local subtitle=string.format("Active runway %s", runwayLanding)
if rwyLandingLeft==true then
self:Transmission(ATIS.Sound.Left, 0.2)
subtitle=subtitle.." Left"
elseif rwyLandingLeft==false then
self:Transmission(ATIS.Sound.Right, 0.2)
subtitle=subtitle.." Right"
end
end
alltext = alltext .. ";\n" .. subtitle
-- Runway length.
if self.rwylength then
local runact = self.airbase:GetActiveRunway( self.runwaym2t )
local length = runact.length
if not self.metric then
length = UTILS.MetersToFeet( length )
end
-- Length in thousands and hundrets of ft/meters.
local L1000, L0100 = self:_GetThousandsAndHundreds( length )
-- Subtitle.
local subtitle = string.format( "Runway length %d", length )
if self.metric then
subtitle = subtitle .. " meters"
else
subtitle = subtitle .. " feet"
end
-- Transmit.
local _RUNACT = subtitle
if not self.useSRS then
self:Transmission( ATIS.Sound.RunwayLength, 1.0, subtitle )
if tonumber( L1000 ) > 0 then
self.radioqueue:Number2Transmission( L1000 )
self:Transmission( ATIS.Sound.Thousand, 0.1 )
end
if tonumber( L0100 ) > 0 then
self.radioqueue:Number2Transmission( L0100 )
self:Transmission( ATIS.Sound.Hundred, 0.1 )
end
if self.metric then
self:Transmission( ATIS.Sound.Meters, 0.1 )
else
self:Transmission( ATIS.Sound.Feet, 0.1 )
self:Transmission(ATIS.Sound.ActiveRunway, 1.0, subtitle)
self.radioqueue:Number2Transmission(runwayLanding)
if rwyLandingLeft==true then
self:Transmission(ATIS.Sound.Left, 0.2)
elseif rwyLandingLeft==false then
self:Transmission(ATIS.Sound.Right, 0.2)
end
end
alltext = alltext .. ";\n" .. subtitle
-- Runway length.
if self.rwylength then
local runact = self.airbase:GetActiveRunway( self.runwaym2t )
local length = runact.length
if not self.metric then
length = UTILS.MetersToFeet( length )
end
-- Length in thousands and hundrets of ft/meters.
local L1000, L0100 = self:_GetThousandsAndHundreds( length )
-- Subtitle.
local subtitle = string.format( "Runway length %d", length )
if self.metric then
subtitle = subtitle .. " meters"
else
subtitle = subtitle .. " feet"
end
-- Transmit.
if not self.useSRS then
self:Transmission( ATIS.Sound.RunwayLength, 1.0, subtitle )
if tonumber( L1000 ) > 0 then
self.radioqueue:Number2Transmission( L1000 )
self:Transmission( ATIS.Sound.Thousand, 0.1 )
end
if tonumber( L0100 ) > 0 then
self.radioqueue:Number2Transmission( L0100 )
self:Transmission( ATIS.Sound.Hundred, 0.1 )
end
if self.metric then
self:Transmission( ATIS.Sound.Meters, 0.1 )
else
self:Transmission( ATIS.Sound.Feet, 0.1 )
end
end
alltext = alltext .. ";\n" .. subtitle
end
end
-- Airfield elevation
if self.elevation then
@@ -2238,7 +2370,12 @@ function ATIS:onafterBroadcast( From, Event, To )
end
alltext = alltext .. ";\n" .. subtitle
end
-- additional info, if any
if self.useSRS and self.AdditionalInformation then
alltext = alltext .. ";\n"..self.AdditionalInformation
end
-- Advice on initial...
subtitle = string.format( "Advise on initial contact, you have information %s", NATO )
if not self.useSRS then
@@ -2279,6 +2416,8 @@ function ATIS:onafterReport( From, Event, To, Text )
local text = string.gsub( text, "mmHg", "millimeters of Mercury" )
local text = string.gsub( text, "hPa", "hectopascals" )
local text = string.gsub( text, "m/s", "meters per second" )
local text = string.gsub( text, "TACAN", "tackan" )
local text = string.gsub( text, "FARP", "farp" )
-- Replace ";" by "."
local text = string.gsub( text, ";", " . " )
@@ -2290,7 +2429,8 @@ function ATIS:onafterReport( From, Event, To, Text )
local duration = STTS.getSpeechTime(text,0.95)
self.msrsQ:NewTransmission(text,duration,self.msrs,nil,2)
--self.msrs:PlayText( text )
self.SRSText = text
end
end

View File

@@ -27,25 +27,26 @@
-- **Supported Carriers:**
--
-- * [USS John C. Stennis](https://en.wikipedia.org/wiki/USS_John_C._Stennis) (CVN-74)
-- * [USS Theodore Roosevelt](https://en.wikipedia.org/wiki/USS_Theodore_Roosevelt_(CVN-71)) (CVN-71) [Super Carrier Module]
-- * [USS Abraham Lincoln](https://en.wikipedia.org/wiki/USS_Abraham_Lincoln_(CVN-72)) (CVN-72) [Super Carrier Module]
-- * [USS George Washington](https://en.wikipedia.org/wiki/USS_George_Washington_(CVN-73)) (CVN-73) [Super Carrier Module]
-- * [USS Theodore Roosevelt](https://en.wikipedia.org/wiki/USS_Theodore_Roosevelt_(CVN-71\)) (CVN-71) [Super Carrier Module]
-- * [USS Abraham Lincoln](https://en.wikipedia.org/wiki/USS_Abraham_Lincoln_(CVN-72\)) (CVN-72) [Super Carrier Module]
-- * [USS George Washington](https://en.wikipedia.org/wiki/USS_George_Washington_(CVN-73\)) (CVN-73) [Super Carrier Module]
-- * [USS Harry S. Truman](https://en.wikipedia.org/wiki/USS_Harry_S._Truman) (CVN-75) [Super Carrier Module]
-- * [USS Forrestal](https://en.wikipedia.org/wiki/USS_Forrestal_(CV-59)) (CV-59) [Heatblur Carrier Module]
-- * [HMS Hermes](https://en.wikipedia.org/wiki/HMS_Hermes_(R12)) (R12) [**WIP**]
-- * [HMS Invincible](https://en.wikipedia.org/wiki/HMS_Invincible_(R05) (R05) [**WIP**]
-- * [USS Tarawa](https://en.wikipedia.org/wiki/USS_Tarawa_(LHA-1)) (LHA-1) [**WIP**]
-- * [USS America](https://en.wikipedia.org/wiki/USS_America_(LHA-6)) (LHA-6) [**WIP**]
-- * [Juan Carlos I](https://en.wikipedia.org/wiki/Spanish_amphibious_assault_ship_Juan_Carlos_I) (L61) [**WIP**]
-- * [HMAS Canberra](https://en.wikipedia.org/wiki/HMAS_Canberra_(L02)) (L02) [**WIP**]
-- * [USS Forrestal](https://en.wikipedia.org/wiki/USS_Forrestal_(CV-59\)) (CV-59) [Heatblur Carrier Module]
-- * [HMS Hermes](https://en.wikipedia.org/wiki/HMS_Hermes_(R12\)) (R12)
-- * [HMS Invincible](https://en.wikipedia.org/wiki/HMS_Invincible_(R05\)) (R05)
-- * [USS Tarawa](https://en.wikipedia.org/wiki/USS_Tarawa_(LHA-1\)) (LHA-1)
-- * [USS America](https://en.wikipedia.org/wiki/USS_America_(LHA-6\)) (LHA-6)
-- * [Juan Carlos I](https://en.wikipedia.org/wiki/Spanish_amphibious_assault_ship_Juan_Carlos_I) (L61)
-- * [HMAS Canberra](https://en.wikipedia.org/wiki/HMAS_Canberra_(L02\)) (L02)
--
-- **Supported Aircraft:**
--
-- * [F/A-18C Hornet Lot 20](https://forums.eagle.ru/forumdisplay.php?f=557) (Player & AI)
-- * [F-14A/B Tomcat](https://forums.eagle.ru/forumdisplay.php?f=395) (Player & AI)
-- * [A-4E Skyhawk Community Mod](https://forums.eagle.ru/showthread.php?t=224989) (Player & AI)
-- * [AV-8B N/A Harrier](https://forums.eagle.ru/forumdisplay.php?f=555) (Player & AI) [**WIP**]
-- * [T-45C Goshawk](https://www.vnao-cvw-7.com/t-45-goshawk) (VNAO)(Player & AI) [**WIP**]
-- * [AV-8B N/A Harrier](https://forums.eagle.ru/forumdisplay.php?f=555) (Player & AI)
-- * [T-45C Goshawk](https://www.vnao-cvw-7.com/t-45-goshawk) (VNAO mod) (Player & AI)
-- * [FE/A-18E/F/G Superhornet](https://forum.dcs.world/topic/316971-cjs-super-hornet-community-mod-v20-official-thread/) (CJS mod) (Player & AI)
-- * F/A-18C Hornet (AI)
-- * F-14A Tomcat (AI)
-- * E-2D Hawkeye (AI)
@@ -117,6 +118,7 @@
-- * [Updated Airboss V/STOL Features USS Tarawa](https://youtu.be/K7I4pU6j718)
-- * [Harrier Practice pattern USS America](https://youtu.be/99NigITYmcI)
-- * [Harrier CASE III TACAN Approach USS Tarawa](https://www.youtube.com/watch?v=bTgJXZ9Mhdc&t=1s)
-- * [Harrier CASE III TACAN Approach USS Tarawa](https://www.youtube.com/watch?v=wWHag5WpNZ0)
--
-- ===
--
@@ -142,7 +144,7 @@
-- @field Wrapper.Airbase#AIRBASE airbase Carrier airbase object.
-- @field #table waypoints Waypoint coordinates of carrier.
-- @field #number currentwp Current waypoint, i.e. the one that has been passed last.
-- @field Core.Radio#BEACON beacon Carrier beacon for TACAN and ICLS.
-- @field Core.Beacon#BEACON beacon Carrier beacon for TACAN and ICLS.
-- @field #boolean TACANon Automatic TACAN is activated.
-- @field #number TACANchannel TACAN channel.
-- @field #string TACANmode TACAN mode, i.e. "X" or "Y".
@@ -296,7 +298,7 @@
--
-- The flight that transitions form the holding pattern to the landing approach, it should leave the Marshal stack at the 3 position and make a left hand turn to the *Initial*
-- position, which is 3 NM astern of the boat. Note that you need to be below 1300 feet to be registered in the initial zone.
-- The altitude can be set via the function @{AIRBOSS.SetInitialMaxAlt}(*altitude*) function.
-- The altitude can be set via the function @{#AIRBOSS.SetInitialMaxAlt}(*altitude*) function.
-- As described below, the initial zone can be smoked or flared via the AIRBOSS F10 Help radio menu.
--
-- ### Landing Pattern
@@ -761,7 +763,7 @@
--
-- ## Save Results
--
-- Saving asset data to file is achieved by the @{AIRBOSS.Save}(*path*, *filename*) function.
-- Saving asset data to file is achieved by the @{#AIRBOSS.Save}(*path*, *filename*) function.
--
-- The parameter *path* specifies the path on the file system where the
-- player grades are saved. If you do not specify a path, the file is saved your the DCS installation root directory if the **lfs** module is *not* desanizied or
@@ -782,7 +784,7 @@
--
-- ### Automatic Saving
--
-- The player grades can be saved automatically after each graded player pass via the @{AIRBOSS.SetAutoSave}(*path*, *filename*) function. Again the parameters *path* and *filename* are optional.
-- The player grades can be saved automatically after each graded player pass via the @{#AIRBOSS.SetAutoSave}(*path*, *filename*) function. Again the parameters *path* and *filename* are optional.
-- In the simplest case, you desanitize the **lfs** module and just add
--
-- airbossStennis:SetAutoSave()
@@ -820,7 +822,7 @@
--
-- ## Load Results
--
-- Loading player grades from file is achieved by the @{AIRBOSS.Load}(*path*, *filename*) function. The parameter *path* specifies the path on the file system where the
-- Loading player grades from file is achieved by the @{#AIRBOSS.Load}(*path*, *filename*) function. The parameter *path* specifies the path on the file system where the
-- data is loaded from. If you do not specify a path, the file is loaded from your the DCS installation root directory or, if **lfs** was desanitized from you "Saved Games\DCS" directory.
-- The parameter *filename* is optional and defines the name of the file to load. By default this is automatically generated from the AIBOSS carrier name/alias, for example
-- "Airboss-USS Stennis_LSOgrades.csv".
@@ -1040,7 +1042,7 @@
--
-- AI groups that enter the CCA are usually guided to Marshal stack. However, due to DCS limitations they might not obey the landing task if they have another airfield as departure and/or destination in
-- their mission task. Therefore, AI groups can be respawned when detected in the CCA. This should clear all other airfields and allow the aircraft to land on the carrier.
-- This is achieved by the @{AIRBOSS.SetRespawnAI}() function.
-- This is achieved by the @{#AIRBOSS.SetRespawnAI}() function.
--
-- ## Known Issues
--
@@ -1202,6 +1204,8 @@ AIRBOSS = {
NmaxSection = nil,
NmaxStack = nil,
handleai = nil,
xtVoiceOvers = nil,
xtVoiceOversAI = nil,
tanker = nil,
Corientation = nil,
Corientlast = nil,
@@ -1275,7 +1279,10 @@ AIRBOSS = {
-- @field #string S3BTANKER Lockheed S-3B Viking tanker.
-- @field #string E2D Grumman E-2D Hawkeye AWACS.
-- @field #string C2A Grumman C-2A Greyhound from Military Aircraft Mod.
-- @field #string T45C T-45C by VNAO
-- @field #string T45C T-45C by VNAO.
-- @field #string RHINOE F/A-18E Superhornet (mod).
-- @field #string RHINOF F/A-18F Superhornet (mod).
-- @field #string GROWLER FEA-18G Superhornet (mod).
AIRBOSS.AircraftCarrier={
AV8B="AV8BNA",
HORNET="FA-18C_hornet",
@@ -1289,6 +1296,9 @@ AIRBOSS.AircraftCarrier={
S3BTANKER="S-3B Tanker",
E2D="E-2C",
C2A="C2A_Greyhound",
RHINOE="FA-18E",
RHINOF="FA-18F",
GROWLER="EA-18G",
}
--- Carrier types.
@@ -1299,7 +1309,7 @@ AIRBOSS.AircraftCarrier={
-- @field #string STENNIS USS John C. Stennis (CVN-74)
-- @field #string TRUMAN USS Harry S. Truman (CVN-75) [Super Carrier Module]
-- @field #string FORRESTAL USS Forrestal (CV-59) [Heatblur Carrier Module]
-- @field #string VINSON USS Carl Vinson (CVN-70) [Obsolete]
-- @field #string VINSON USS Carl Vinson (CVN-70) [Deprecated!]
-- @field #string HERMES HMS Hermes (R12) [V/STOL Carrier]
-- @field #string INVINCIBLE HMS Invincible (R05) [V/STOL Carrier]
-- @field #string TARAWA USS Tarawa (LHA-1) [V/STOL Carrier]
@@ -1333,6 +1343,7 @@ AIRBOSS.CarrierType = {
-- @field #number wire2 Distance in meters from carrier position to second wire.
-- @field #number wire3 Distance in meters from carrier position to third wire.
-- @field #number wire4 Distance in meters from carrier position to fourth wire.
-- @field #number landingdist Distance in meeters to the landing position.
-- @field #number rwylength Length of the landing runway in meters.
-- @field #number rwywidth Width of the landing runway in meters.
-- @field #number totlength Total length of carrier.
@@ -1732,8 +1743,7 @@ AIRBOSS.MenuF10Root = nil
--- Airboss class version.
-- @field #string version
AIRBOSS.version = "1.2.1"
AIRBOSS.version = "1.3.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -1903,6 +1913,12 @@ function AIRBOSS:New( carriername, alias )
-- Set AI handling On.
self:SetHandleAION()
-- No extra voiceover/calls from player by default
self:SetExtraVoiceOvers(false)
-- No extra voiceover/calls from AI by default
self:SetExtraVoiceOversAI(false)
-- Airboss is a nice guy.
self:SetAirbossNiceGuy()
@@ -1974,7 +1990,8 @@ function AIRBOSS:New( carriername, alias )
-- Init carrier parameters.
if self.carriertype == AIRBOSS.CarrierType.STENNIS then
self:_InitStennis()
-- Stennis parameters were updated to match the other Super Carriers.
self:_InitNimitz()
elseif self.carriertype == AIRBOSS.CarrierType.ROOSEVELT then
self:_InitNimitz()
elseif self.carriertype == AIRBOSS.CarrierType.LINCOLN then
@@ -1986,7 +2003,7 @@ function AIRBOSS:New( carriername, alias )
elseif self.carriertype == AIRBOSS.CarrierType.FORRESTAL then
self:_InitForrestal()
elseif self.carriertype == AIRBOSS.CarrierType.VINSON then
-- TODO: Carl Vinson parameters.
-- Carl Vinson is legacy now.
self:_InitStennis()
elseif self.carriertype == AIRBOSS.CarrierType.HERMES then
-- Hermes parameters.
@@ -2004,8 +2021,8 @@ function AIRBOSS:New( carriername, alias )
-- Use Juan Carlos parameters.
self:_InitJcarlos()
elseif self.carriertype == AIRBOSS.CarrierType.CANBERRA then
-- Use Juan Carlos parameters at this stage --TODO Check primary Landing spot.
self:_InitJcarlos()
-- Use Juan Carlos parameters at this stage.
self:_InitCanberra()
elseif self.carriertype == AIRBOSS.CarrierType.KUZNETSOV then
-- Kusnetsov parameters - maybe...
self:_InitStennis()
@@ -2764,9 +2781,9 @@ function AIRBOSS:SetRefuelAI( LowFuelThreshold )
return self
end
--- Set max alitude to register flights in the initial zone. Aircraft above this altitude will not be registerered.
--- Set max altitude to register flights in the initial zone. Aircraft above this altitude will not be registerered.
-- @param #AIRBOSS self
-- @param #number MaxAltitude Max alitude in feet. Default 1300 ft.
-- @param #number MaxAltitude Max altitude in feet. Default 1300 ft.
-- @return #AIRBOSS self
function AIRBOSS:SetInitialMaxAlt( MaxAltitude )
self.initialmaxalt = UTILS.FeetToMeters( MaxAltitude or 1300 )
@@ -3234,6 +3251,24 @@ function AIRBOSS:SetHandleAION()
return self
end
--- Will play the inbound calls, commencing, initial, etc. from the player when requesteing marshal
-- @param #AIRBOSS self
-- @param #AIRBOSS status Boolean to activate (true) / deactivate (false) the radio inbound calls (default is ON)
-- @return #AIRBOSS self
function AIRBOSS:SetExtraVoiceOvers(status)
self.xtVoiceOvers=status
return self
end
--- Will simulate the inbound call, commencing, initial, etc from the AI when requested by Airboss
-- @param #AIRBOSS self
-- @param #AIRBOSS status Boolean to activate (true) / deactivate (false) the radio inbound calls (default is ON)
-- @return #AIRBOSS self
function AIRBOSS:SetExtraVoiceOversAI(status)
self.xtVoiceOversAI=status
return self
end
--- Do not handle AI aircraft.
-- @param #AIRBOSS self
-- @return #AIRBOSS self
@@ -3340,6 +3375,20 @@ function AIRBOSS:SetDebugModeOFF()
return self
end
--- Set FunkMan socket. LSO grades and trap sheets will be send to your Discord bot.
-- **Requires running FunkMan program**.
-- @param #AIRBOSS self
-- @param #number Port Port. Default `10042`.
-- @param #string Host Host. Default `"127.0.0.1"`.
-- @return #AIRBOSS self
function AIRBOSS:SetFunkManOn(Port, Host)
self.funkmanSocket=SOCKET:New(Port, Host)
return self
end
--- Get next time the carrier will start recovering aircraft.
-- @param #AIRBOSS self
-- @param #boolean InSeconds If true, abs. mission time seconds is returned. Default is a clock #string.
@@ -4233,7 +4282,7 @@ function AIRBOSS:_InitStennis()
-- Carrier Parameters.
self.carrierparam.sterndist = -153
self.carrierparam.deckheight = 19.06
self.carrierparam.deckheight = 18.30
-- Total size of the carrier (approx as rectangle).
self.carrierparam.totlength = 310 -- Wiki says 332.8 meters overall length.
@@ -4251,6 +4300,9 @@ function AIRBOSS:_InitStennis()
self.carrierparam.wire3 = 46 + 24
self.carrierparam.wire4 = 46 + 35 -- Last wire is strangely one meter closer.
-- Landing distance.
self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.wire3
-- Platform at 5k. Reduce descent rate to 2000 ft/min to 1200 dirty up level flight.
self.Platform.name = "Platform 5k"
self.Platform.Xmin = -UTILS.NMToMeters( 22 ) -- Not more than 22 NM behind the boat. Last check was at 21 NM.
@@ -4401,6 +4453,9 @@ function AIRBOSS:_InitNimitz()
self.carrierparam.wire3 = 79
self.carrierparam.wire4 = 92
-- Landing distance.
self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.wire3
end
--- Init parameters for Forrestal class super carriers.
@@ -4430,6 +4485,9 @@ function AIRBOSS:_InitForrestal()
self.carrierparam.wire3 = 64 -- 62
self.carrierparam.wire4 = 74 -- 72.5
-- Landing distance.
self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.wire3
end
--- Init parameters for R12 HMS Hermes carrier.
@@ -4459,6 +4517,12 @@ function AIRBOSS:_InitHermes()
self.carrierparam.wire3 = nil
self.carrierparam.wire4 = nil
-- Distance to landing spot.
self.carrierparam.landingspot=69
-- Landing distance.
self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.landingspot
-- Late break.
self.BreakLate.name = "Late Break"
self.BreakLate.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0.
@@ -4499,6 +4563,12 @@ function AIRBOSS:_InitInvincible()
self.carrierparam.wire3 = nil
self.carrierparam.wire4 = nil
-- Distance to landing spot.
self.carrierparam.landingspot=69
-- Landing distance.
self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.landingspot
-- Late break.
self.BreakLate.name = "Late Break"
self.BreakLate.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0.
@@ -4539,6 +4609,12 @@ function AIRBOSS:_InitTarawa()
self.carrierparam.wire3 = nil
self.carrierparam.wire4 = nil
-- Distance to landing spot.
self.carrierparam.landingspot=57
-- Landing distance.
self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.landingspot
-- Late break.
self.BreakLate.name = "Late Break"
self.BreakLate.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0.
@@ -4579,6 +4655,12 @@ function AIRBOSS:_InitAmerica()
self.carrierparam.wire3 = nil
self.carrierparam.wire4 = nil
-- Distance to landing spot.
self.carrierparam.landingspot=59
-- Landing distance.
self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.landingspot
-- Late break.
self.BreakLate.name = "Late Break"
self.BreakLate.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0.
@@ -4619,6 +4701,12 @@ function AIRBOSS:_InitJcarlos()
self.carrierparam.wire3 = nil
self.carrierparam.wire4 = nil
-- Distance to landing spot.
self.carrierparam.landingspot=89
-- Landing distance.
self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.landingspot
-- Late break.
self.BreakLate.name = "Late Break"
self.BreakLate.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0.
@@ -4631,6 +4719,16 @@ function AIRBOSS:_InitJcarlos()
self.BreakLate.LimitZmax = nil
end
--- Init parameters for L02 Canberra carrier.
-- @param #AIRBOSS self
function AIRBOSS:_InitCanberra()
-- Init Juan Carlos as default.
self:_InitJcarlos()
end
--- Init parameters for Marshal Voice overs *Gabriella* by HighwaymanEd.
-- @param #AIRBOSS self
-- @param #string mizfolder (Optional) Folder within miz file where the sound files are located.
@@ -5086,7 +5184,10 @@ end
function AIRBOSS:_GetAircraftAoA( playerData )
-- Get AC type.
local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET
local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOE
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF
or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER
local goshawk = playerData.actype == AIRBOSS.AircraftCarrier.T45C
local skyhawk = playerData.actype == AIRBOSS.AircraftCarrier.A4EC
local harrier = playerData.actype == AIRBOSS.AircraftCarrier.AV8B
@@ -5249,7 +5350,10 @@ function AIRBOSS:_GetAircraftParameters( playerData, step )
step = step or playerData.step
-- Get AC type.
local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET
local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOE
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF
or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER
local skyhawk = playerData.actype == AIRBOSS.AircraftCarrier.A4EC
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B
local harrier = playerData.actype == AIRBOSS.AircraftCarrier.AV8B
@@ -5353,16 +5457,12 @@ function AIRBOSS:_GetAircraftParameters( playerData, step )
aoa = aoaac.OnSpeed
if harrier then
-- 0.8 to 1.0 NM
dist = UTILS.NMToMeters( 0.9 )
else
dist = UTILS.NMToMeters( 1.2 )
end
if goshawk then
-- 0.9 to 1.1 NM per natops ch.4 page 48
dist = UTILS.NMToMeters( 0.9 )
elseif harrier then
-- 0.8 to 1.0 NM
dist = UTILS.NMToMeters( 0.9 )
else
dist = UTILS.NMToMeters( 1.1 )
end
@@ -5404,7 +5504,6 @@ function AIRBOSS:_GetAircraftParameters( playerData, step )
alt = UTILS.FeetToMeters( 300 ) -- ?
elseif harrier then
alt=UTILS.FeetToMeters(312)-- 300-325 ft
end
aoa = aoaac.OnSpeed
@@ -5622,6 +5721,12 @@ function AIRBOSS:_ClearForLanding( flight )
-- Cleared for Case X recovery.
self:_MarshalCallClearedForRecovery( flight.onboard, flight.case )
-- Voice over of the commencing simulated call from AI
if self.xtVoiceOversAI then
local leader = flight.group:GetUnits()[1]
self:_CommencingCall(leader, flight.onboard)
end
else
-- Cleared for Case X recovery.
@@ -5721,12 +5826,12 @@ function AIRBOSS:_ScanCarrierZone()
if knownflight then
-- Check if flight is AI and if we want to handle it at all.
if knownflight.ai and knownflight.flag == -100 and self.handleai then
if knownflight.ai and knownflight.flag == -100 and self.handleai and false then --Disabled AI handling because of incorrect OPSGROUP reference!
local putintomarshal = false
-- Get flight group.
local flight = _DATABASE:GetFlightGroup( groupname )
local flight = _DATABASE:GetOpsGroup( groupname )
if flight and flight:IsInbound() and flight.destbase:GetName() == self.carrier:GetName() then
if flight.ishelo then
@@ -5772,7 +5877,6 @@ function AIRBOSS:_ScanCarrierZone()
if not self:_IsHuman( group ) then
self:_CreateFlightGroup( group )
end
end
end
@@ -5916,7 +6020,7 @@ function AIRBOSS:_WaitAI( flight, respawn )
-- Heading from carrier to flight group
local hdgto = cv:HeadingTo( fc )
-- Holding alitude between angels 6 and 10 (random).
-- Holding altitude between angels 6 and 10 (random).
local angels = math.random( 6, 10 )
local altitude = UTILS.FeetToMeters( angels * 1000 )
@@ -5986,7 +6090,12 @@ function AIRBOSS:_MarshalAI( flight, nstack, respawn )
end
-- Check if flight is already in Marshal queue.
if not self:_InQueue( self.Qmarshal, flight.group ) then
if not self:_InQueue(self.Qmarshal,flight.group) then
-- Simulate inbound call
if self.xtVoiceOversAI then
local leader = flight.group:GetUnits()[1]
self:_MarshallInboundCall(leader, flight.onboard)
end
-- Add group to marshal stack queue.
self:_AddMarshalGroup( flight, nstack )
end
@@ -6068,7 +6177,7 @@ function AIRBOSS:_MarshalAI( flight, nstack, respawn )
local radial = self:GetRadial( case, false, true )
-- Point in the middle of the race track and a 5 NM more port perpendicular.
p0 = p2:Translate( UTILS.NMToMeters( 5 ), radial + 90 ):Translate( UTILS.NMToMeters( 5 ), radial, true )
p0 = p2:Translate( UTILS.NMToMeters( 5 ), radial + 90, true ):Translate( UTILS.NMToMeters( 5 ), radial, true )
-- Entering Case II/III marshal pattern waypoint.
wp[#wp + 1] = p0:WaypointAirTurningPoint( nil, speedTransit, { TaskArrivedHolding }, "Entering Case II/III Marshal Pattern" )
@@ -6155,6 +6264,9 @@ function AIRBOSS:_RefuelAI( flight )
actype==AIRBOSS.AircraftCarrier.F14B or
actype==AIRBOSS.AircraftCarrier.F14A_AI or
actype==AIRBOSS.AircraftCarrier.HORNET or
actype==AIRBOSS.AircraftCarrier.RHINOE or
actype==AIRBOSS.AircraftCarrier.RHINOF or
actype==AIRBOSS.AircraftCarrier.GROWLER or
actype==AIRBOSS.AircraftCarrier.FA18C or
actype==AIRBOSS.AircraftCarrier.S3B or
actype==AIRBOSS.AircraftCarrier.S3BTANKER then
@@ -6252,7 +6364,11 @@ function AIRBOSS:_LandAI( flight )
-- Aircraft speed when flying the pattern.
local Speed = UTILS.KnotsToKmph( 200 )
if flight.actype == AIRBOSS.AircraftCarrier.HORNET or flight.actype == AIRBOSS.AircraftCarrier.FA18C then
if flight.actype == AIRBOSS.AircraftCarrier.HORNET
or flight.actype == AIRBOSS.AircraftCarrier.FA18C
or flight.actype == AIRBOSS.AircraftCarrier.RHINOE
or flight.actype == AIRBOSS.AircraftCarrier.RHINOF
or flight.actype == AIRBOSS.AircraftCarrier.GROWLER then
Speed = UTILS.KnotsToKmph( 200 )
elseif flight.actype == AIRBOSS.AircraftCarrier.E2D then
Speed = UTILS.KnotsToKmph( 150 )
@@ -8910,7 +9026,7 @@ function AIRBOSS:_Initial( playerData )
-- Relative heading to carrier direction.
local relheading = self:_GetRelativeHeading( playerData.unit, false )
-- Alitude of player in feet.
-- altitude of player in feet.
local altitude = playerData.unit:GetAltitude()
-- Check if player is in zone and flying roughly in the right direction.
@@ -9076,7 +9192,13 @@ function AIRBOSS:_DirtyUp( playerData )
self:_PlayerHint( playerData )
-- Radio call "Say/Fly needles". Delayed by 10/15 seconds.
if playerData.actype == AIRBOSS.AircraftCarrier.HORNET or playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B then
if playerData.actype == AIRBOSS.AircraftCarrier.HORNET
or playerData.actype == AIRBOSS.AircraftCarrier.F14A
or playerData.actype == AIRBOSS.AircraftCarrier.F14B
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOE
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF
or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER
then
local callsay = self:_NewRadioCall( self.MarshalCall.SAYNEEDLES, nil, nil, 5, playerData.onboard )
local callfly = self:_NewRadioCall( self.MarshalCall.FLYNEEDLES, nil, nil, 5, playerData.onboard )
self:RadioTransmission( self.MarshalRadio, callsay, false, 55, nil, true )
@@ -10107,7 +10229,7 @@ function AIRBOSS:_GetWire( Lcoord, dc )
if self.Debug and false then
-- Wire position coodinates.
-- Wire position coordinates.
local wp1 = Scoord:Translate( w1, FB )
local wp2 = Scoord:Translate( w2, FB )
local wp3 = Scoord:Translate( w3, FB )
@@ -10167,7 +10289,10 @@ function AIRBOSS:_Trapped( playerData )
-- Get current wire (estimate). This now based on the position where the player comes to a standstill which should reflect the trapped wire better.
local dcorr = 100
if playerData.actype == AIRBOSS.AircraftCarrier.HORNET then
if playerData.actype == AIRBOSS.AircraftCarrier.HORNET
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOE
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF
or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER then
dcorr = 100
elseif playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B then
-- TODO: Check Tomcat.
@@ -10832,7 +10957,6 @@ function AIRBOSS:_GetZoneCommence( case, stack )
local Three = self:GetCoordinate():Translate( D, hdg + 275 )
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
local Dx = UTILS.NMToMeters( 2.25 )
local Dz = UTILS.NMToMeters( 2.25 )
@@ -11108,7 +11232,7 @@ function AIRBOSS:_Lineup( unit, runway )
return lineup
end
--- Get alitude of aircraft wrt carrier deck. Should give zero when the aircraft touched down.
--- Get altitude of aircraft wrt carrier deck. Should give zero when the aircraft touched down.
-- @param #AIRBOSS self
-- @param Wrapper.Unit#UNIT unit Aircraft unit.
-- @return #number Altitude in meters wrt carrier height.
@@ -11130,28 +11254,31 @@ function AIRBOSS:_GetOptLandingCoordinate()
-- Start with stern coordiante.
self.landingcoord:UpdateFromCoordinate( self:_GetSternCoord() )
-- Stern coordinate.
-- local stern=self:_GetSternCoord()
-- Final bearing.
local FB=self:GetFinalBearing(false)
-- Cse
local case=self.case
-- set Case III V/STOL abeam landing spot over deck -- Pene Testing
if self.carriertype==AIRBOSS.CarrierType.INVINCIBLE or self.carriertype==AIRBOSS.CarrierType.HERMES or self.carriertype==AIRBOSS.CarrierType.TARAWA or self.carriertype==AIRBOSS.CarrierType.AMERICA or self.carriertype==AIRBOSS.CarrierType.JCARLOS or self.carriertype==AIRBOSS.CarrierType.CANBERRA then
if case==3 then
self.landingcoord:UpdateFromCoordinate(self:_GetLandingSpotCoordinate())
-- Altitude 120ft -- is this corect for Case III?
self.landingcoord:SetAltitude(UTILS.FeetToMeters(120))
-- Landing coordinate.
self.landingcoord:UpdateFromCoordinate(self:_GetLandingSpotCoordinate())
-- Altitude 120ft -- is this corect for Case III?
self.landingcoord:SetAltitude(UTILS.FeetToMeters(120))
elseif case==2 or case==1 then
-- Landing 100 ft abeam, 120 ft alt.
self.landingcoord:UpdateFromCoordinate(self:_GetLandingSpotCoordinate()):Translate(35, FB-90, true, true)
--stern=self:_GetLandingSpotCoordinate():Translate(35, FB-90)
-- Landing 100 ft abeam, 120 ft alt.
self.landingcoord:UpdateFromCoordinate(self:_GetLandingSpotCoordinate()):Translate(35, FB-90, true, true)
-- Alitude 120 ft.
self.landingcoord:SetAltitude(UTILS.FeetToMeters(120))
-- Atlitude 120 ft.
self.landingcoord:SetAltitude(UTILS.FeetToMeters(120))
end
else
@@ -11159,8 +11286,7 @@ function AIRBOSS:_GetOptLandingCoordinate()
-- Ideally we want to land between 2nd and 3rd wire.
if self.carrierparam.wire3 then
-- We take the position of the 3rd wire to approximately account for the length of the aircraft.
local w3 = self.carrierparam.wire3
self.landingcoord:Translate( w3, FB, true, true )
self.landingcoord:Translate( self.carrierparam.wire3, FB, true, true )
end
-- Add 2 meters to account for aircraft height.
@@ -11171,61 +11297,19 @@ function AIRBOSS:_GetOptLandingCoordinate()
return self.landingcoord
end
--- Get landing spot on Tarawa.
--- Get landing spot on Tarawa and others.
-- @param #AIRBOSS self
-- @return Core.Point#COORDINATE Primary landing spot coordinate.
function AIRBOSS:_GetLandingSpotCoordinate()
-- Start at stern coordinate.
self.landingspotcoord:UpdateFromCoordinate( self:_GetSternCoord() )
-- Stern coordinate.
-- local stern=self:_GetSternCoord()
-- Landing 100 ft abeam, 100 alt.
local hdg = self:GetHeading()
if self.carriertype==AIRBOSS.CarrierType.HERMES then
-- Landing 100 ft abeam, 100 alt.
local hdg = self:GetHeading()
-- Primary landing spot 5
self.landingspotcoord:Translate( 69, hdg, true, true ):SetAltitude( self.carrierparam.deckheight )
elseif self.carriertype == AIRBOSS.CarrierType.INVINCIBLE then
-- Using spot 3 as the default
local hdg = self:GetHeading()
self.landingspotcoord:Translate( 69, hdg, true, true ):SetAltitude( self.carrierparam.deckheight )
-- This location looks good.
elseif self.carriertype == AIRBOSS.CarrierType.TARAWA then
-- Landing 100 ft abeam, 120 alt.
local hdg = self:GetHeading()
-- Primary landing spot 7.5
self.landingspotcoord:Translate( 57, hdg, true, true ):SetAltitude( self.carrierparam.deckheight )
elseif self.carriertype == AIRBOSS.CarrierType.AMERICA then
-- Landing 100 ft abeam, 120 alt.
local hdg = self:GetHeading()
-- Primary landing spot 7.5 a little further forwad on the America
self.landingspotcoord:Translate( 59, hdg, true, true ):SetAltitude( self.carrierparam.deckheight )
elseif self.carriertype == AIRBOSS.CarrierType.JCARLOS then
-- Landing 100 ft abeam, 120 alt.
local hdg = self:GetHeading()
-- Primary landing spot 5.0 -- Done voice for different landing Spots.
self.landingspotcoord:Translate( 89, hdg, true, true ):SetAltitude( self.carrierparam.deckheight )
elseif self.carriertype == AIRBOSS.CarrierType.CANBERRA then
-- Landing 100 ft abeam, 120 alt.
local hdg = self:GetHeading()
-- Primary landing spot 5.0 -- Done voice for different landing Spots.
self.landingspotcoord:Translate( 89, hdg, true, true ):SetAltitude( self.carrierparam.deckheight )
end
-- Primary landing spot. Different carriers handled via carrier parameter landingspot now.
self.landingspotcoord:Translate( self.carrierparam.landingspot, hdg, true, true ):SetAltitude( self.carrierparam.deckheight )
return self.landingspotcoord
end
@@ -11273,8 +11357,8 @@ function AIRBOSS:GetWind( alt, magnetic, coord )
-- Current position of the carrier or input.
local cv = coord or self:GetCoordinate()
-- Wind direction and speed. By default at 15 meters ASL.
local Wdir, Wspeed = cv:GetWind( alt or 15 )
-- Wind direction and speed. By default at 18 meters ASL.
local Wdir, Wspeed = cv:GetWind( alt or 18 )
-- Include magnetic declination.
if magnetic then
@@ -11290,7 +11374,7 @@ end
--- Get wind speed on carrier deck parallel and perpendicular to runway.
-- @param #AIRBOSS self
-- @param #number alt Altitude in meters. Default 15 m. (change made from 50m from Discord discussion from Sickdog)
-- @param #number alt Altitude in meters. Default 18 m.
-- @return #number Wind component parallel to runway im m/s.
-- @return #number Wind component perpendicular to runway in m/s.
-- @return #number Total wind strength in m/s.
@@ -11313,7 +11397,7 @@ function AIRBOSS:GetWindOnDeck( alt )
zc = UTILS.Rotate2D( zc, -self.carrierparam.rwyangle )
-- Wind (from) vector
local vw = cv:GetWindWithTurbulenceVec3( alt or 15 )
local vw = cv:GetWindWithTurbulenceVec3( alt or 18 ) --(change made from 50m to 15m from Discord discussion from Sickdog, next change to 18m due to SC higher deck discord)
-- Total wind velocity vector.
-- Carrier velocity has to be negative. If carrier drives in the direction the wind is blowing from, we have less wind in total.
@@ -11336,7 +11420,7 @@ end
--- Get true (or magnetic) heading of carrier into the wind. This accounts for the angled runway.
-- @param #AIRBOSS self
-- @param #boolean magnetic If true, calculate magnetic heading. By default true heading is returned.
-- @param Core.Point#COORDINATE coord (Optional) Coodinate from which heading is calculated. Default is current carrier position.
-- @param Core.Point#COORDINATE coord (Optional) Coordinate from which heading is calculated. Default is current carrier position.
-- @return #number Carrier heading in degrees.
function AIRBOSS:GetHeadingIntoWind( magnetic, coord )
@@ -11799,7 +11883,7 @@ function AIRBOSS:_LSOgrade( playerData )
local grade
local points
if N == 0 and (TgrooveUnicorn or TgrooveVstolUnicorn) then
if N == 0 and (TgrooveUnicorn or TgrooveVstolUnicorn or playerData.case==3) then
-- No deviations, should be REALLY RARE!
grade = "_OK_"
points = 5.0
@@ -12408,7 +12492,10 @@ function AIRBOSS:_PlayerHint( playerData, delay, soundoff )
if playerData.step == AIRBOSS.PatternStep.BULLSEYE then
-- Hint follow the needles.
if playerData.difficulty == AIRBOSS.Difficulty.EASY then
if playerData.actype == AIRBOSS.AircraftCarrier.HORNET then
if playerData.actype == AIRBOSS.AircraftCarrier.HORNET
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOE
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF
or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER then
hint = hint .. string.format( "\nIntercept glideslope and follow the needles." )
else
hint = hint .. string.format( "\nIntercept glideslope." )
@@ -12798,19 +12885,23 @@ function AIRBOSS:_Debrief( playerData )
end
mygrade.case = playerData.case
local windondeck = self:GetWindOnDeck()
mygrade.wind = tostring( UTILS.Round( UTILS.MpsToKnots( windondeck ), 1 ) )
mygrade.wind = UTILS.Round( UTILS.MpsToKnots( windondeck ), 1 )
mygrade.modex = playerData.onboard
mygrade.airframe = playerData.actype
mygrade.carriertype = self.carriertype
mygrade.carriername = self.alias
mygrade.carrierrwy = self.carrierparam.rwyangle
mygrade.theatre = self.theatre
mygrade.mitime = UTILS.SecondsToClock( timer.getAbsTime() )
mygrade.mitime = UTILS.SecondsToClock( timer.getAbsTime(), true )
mygrade.midate = UTILS.GetDCSMissionDate()
mygrade.osdate = "n/a"
if os then
mygrade.osdate = os.date() -- os.date("%d.%m.%Y")
end
-- Add last grade to playerdata for FunkMan.
playerData.grade=mygrade
-- Save trap sheet.
if playerData.trapon and self.trapsheet then
self:_SaveTrapSheet( playerData, mygrade )
@@ -13898,6 +13989,10 @@ function AIRBOSS:_GetACNickname( actype )
nickname = "Tomcat"
elseif actype == AIRBOSS.AircraftCarrier.FA18C or actype == AIRBOSS.AircraftCarrier.HORNET then
nickname = "Hornet"
elseif actype == AIRBOSS.AircraftCarrier.RHINOE or actype == AIRBOSS.AircraftCarrier.RHINOF then
nickname = "Rhino"
elseif actype == AIRBOSS.AircraftCarrier.GROWLER then
nickname = "Growler"
elseif actype == AIRBOSS.AircraftCarrier.S3B or actype == AIRBOSS.AircraftCarrier.S3BTANKER then
nickname = "Viking"
end
@@ -14102,7 +14197,7 @@ end
--- Convert altitude from meters to angels (thousands of feet).
-- @param #AIRBOSS self
-- @param alt Alitude in meters.
-- @param alt altitude in meters.
-- @return #number Altitude in Anglels = thousands of feet using math.floor().
function AIRBOSS:_GetAngels( alt )
@@ -15121,6 +15216,86 @@ function AIRBOSS:_Number2Radio( radio, number, delay, interval, pilotcall )
return wait
end
--- Aircraft request marshal (Inbound call both for players and AI).
-- @param #AIRBOSS self
-- @return Wrapper.Unit#UNIT Unit of player or nil.
-- @param #string modex Tail number.
function AIRBOSS:_MarshallInboundCall(unit, modex)
-- Calculate
local vectorCarrier = self:GetCoordinate():GetDirectionVec3(unit:GetCoordinate())
local bearing = UTILS.Round(unit:GetCoordinate():GetAngleDegrees( vectorCarrier ), 0)
local distance = UTILS.Round(UTILS.MetersToNM(unit:GetCoordinate():Get2DDistance(self:GetCoordinate())),0)
local angels = UTILS.Round(UTILS.MetersToFeet(unit:GetHeight()/1000),0)
local state = UTILS.Round(self:_GetFuelState(unit)/1000,1)
-- Pilot: "Marshall, [modex], marking mom's [bearing] for [distance], angels [XX], state [X.X]"
local text=string.format("Marshal, %s, marking mom's %d for %d, angels %d, state %.1f", modex, bearing, distance, angels, state)
-- Debug message.
self:T(self.lid..text)
-- Fuel state.
local FS=UTILS.Split(string.format("%.1f", state), ".")
-- Create new call to display complete subtitle.
local inboundcall=self:_NewRadioCall(self.MarshalCall.CLICK, unit.UnitName:upper() , text, self.Tmessage, nil, unit.UnitName:upper())
-- CLICK!
self:RadioTransmission(self.MarshalRadio, inboundcall)
-- Marshal ..
self:RadioTransmission(self.MarshalRadio, self.PilotCall.MARSHAL, nil, nil, nil, nil, true)
-- Modex..
self:_Number2Radio(self.MarshalRadio, modex, nil, nil, true)
-- Marking Mom's,
self:RadioTransmission(self.MarshalRadio, self.PilotCall.MARKINGMOMS, nil, nil, nil, nil, true)
-- Bearing ..
self:_Number2Radio(self.MarshalRadio, tostring(bearing), nil, nil, true)
-- For ..
self:RadioTransmission(self.MarshalRadio, self.PilotCall.FOR, nil, nil, nil, nil, true)
-- Distance ..
self:_Number2Radio(self.MarshalRadio, tostring(distance), nil, nil, true)
-- Angels ..
self:RadioTransmission(self.MarshalRadio, self.PilotCall.ANGELS, nil, nil, nil, nil, true)
-- Angels Number ..
self:_Number2Radio(self.MarshalRadio, tostring(angels), nil, nil, true)
-- State ..
self:RadioTransmission(self.MarshalRadio, self.PilotCall.STATE, nil, nil, nil, nil, true)
-- X..
self:_Number2Radio(self.MarshalRadio, FS[1], nil, nil, true)
-- Point..
self:RadioTransmission(self.MarshalRadio, self.PilotCall.POINT, nil, nil, nil, nil, true)
-- Y.
self:_Number2Radio(self.MarshalRadio, FS[2], nil, nil, true)
-- CLICK!
self:RadioTransmission(self.MarshalRadio, self.MarshalRadio.CLICK, nil, nil, nil, nil, true)
end
--- Aircraft commencing call (both for players and AI).
-- @param #AIRBOSS self
-- @return Wrapper.Unit#UNIT Unit of player or nil.
-- @param #string modex Tail number.
function AIRBOSS:_CommencingCall(unit, modex)
-- Pilot: "[modex], commencing"
local text=string.format("%s, commencing", modex)
-- Debug message.
self:T(self.lid..text)
-- Create new call to display complete subtitle.
local commencingCall=self:_NewRadioCall(self.MarshalCall.CLICK, unit.UnitName:upper() , text, self.Tmessage, nil, unit.UnitName:upper())
-- Click
self:RadioTransmission(self.MarshalRadio, commencingCall)
-- Modex..
self:_Number2Radio(self.MarshalRadio, modex, nil, nil, true)
-- Commencing
self:RadioTransmission(self.MarshalRadio, self.PilotCall.COMMENCING, nil, nil, nil, nil, true)
-- CLICK!
self:RadioTransmission(self.MarshalRadio, self.MarshalRadio.CLICK, nil, nil, nil, nil, true)
end
--- AI aircraft calls the ball.
-- @param #AIRBOSS self
-- @param #string modex Tail number.
@@ -15170,6 +15345,7 @@ function AIRBOSS:_MarshalCallGasAtTanker( modex )
-- Debug message.
self:I( self.lid .. text )
-- Create new call to display complete subtitle.
local call = self:_NewRadioCall( self.PilotCall.BINGOFUEL, modex, text, self.Tmessage, nil, modex )
@@ -15333,7 +15509,7 @@ function AIRBOSS:_MarshalCallNewFinalBearing( FB )
end
--- Compile a radio call when Marshal tells a flight the holding alitude.
--- Compile a radio call when Marshal tells a flight the holding altitude.
-- @param #AIRBOSS self
-- @param #number hdg Heading in degrees.
function AIRBOSS:_MarshalCallCarrierTurnTo( hdg )
@@ -15356,7 +15532,7 @@ function AIRBOSS:_MarshalCallCarrierTurnTo( hdg )
end
--- Compile a radio call when Marshal tells a flight the holding alitude.
--- Compile a radio call when Marshal tells a flight the holding altitude.
-- @param #AIRBOSS self
-- @param #string modex Tail number.
-- @param #number nwaiting Number of flights already waiting.
@@ -15382,7 +15558,7 @@ function AIRBOSS:_MarshalCallStackFull( modex, nwaiting )
self:RadioTransmission( self.MarshalRadio, call, nil, nil, nil, true )
end
--- Compile a radio call when Marshal tells a flight the holding alitude.
--- Compile a radio call when Marshal tells a flight the holding altitude.
-- @param #AIRBOSS self
function AIRBOSS:_MarshalCallRecoveryStart( case )
@@ -15422,12 +15598,12 @@ function AIRBOSS:_MarshalCallRecoveryStart( case )
end
--- Compile a radio call when Marshal tells a flight the holding alitude.
--- Compile a radio call when Marshal tells a flight the holding altitude.
-- @param #AIRBOSS self
-- @param #string modex Tail number.
-- @param #number case Recovery case.
-- @param #number brc Base recovery course.
-- @param #number altitude Holding alitude.
-- @param #number altitude Holding altitude.
-- @param #string charlie Charlie Time estimate.
-- @param #number qfe Alitmeter inHg.
function AIRBOSS:_MarshalCallArrived( modex, case, brc, altitude, charlie, qfe )
@@ -15876,6 +16052,11 @@ function AIRBOSS:_RequestMarshal( _unitName )
if playerData then
-- Voice over of inbound call (regardless of airboss rejecting it or not)
if self.xtVoiceOvers then
self:_MarshallInboundCall(_unit, playerData.onboard)
end
-- Check if player is in CCA
local inCCA = playerData.unit:IsInZone( self.zoneCCA )
@@ -16123,7 +16304,12 @@ function AIRBOSS:_RequestCommence( _unitName )
local playerData = self.players[_playername] -- #AIRBOSS.PlayerData
if playerData then
-- Voice over of Commencing call (regardless of Airboss will rejected or not)
if self.xtVoiceOvers then
self:_CommencingCall(_unit, playerData.onboard)
end
-- Check if unit is in CCA.
local text = ""
local cleared = false
@@ -17270,7 +17456,7 @@ function AIRBOSS:_MarkMarshalZone( _unitName, flare )
-- Get Case I commence zone at three position.
local zoneThree = self:_GetZoneCommence( case, stack )
-- Pattern alitude.
-- Pattern altitude.
local patternalt = self:_GetMarshalAltitude( stack, case )
-- Flare and smoke at the ground.
@@ -17835,6 +18021,59 @@ function AIRBOSS:onafterLoad( From, Event, To, path, filename )
end
--- On after "LSOGrade" event.
-- @param #AIRBOSS self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #AIRBOSS.PlayerData playerData Player Data.
-- @param #AIRBOSS.LSOgrade grade LSO grade.
function AIRBOSS:onafterLSOGrade(From, Event, To, playerData, grade)
if self.funkmanSocket then
-- Extract used info for FunkMan. We need to be careful with the amount of data send via UDP socket.
local trapsheet={} ; trapsheet.X={} ; trapsheet.Z={} ; trapsheet.AoA={} ; trapsheet.Alt={}
-- Loop over trapsheet and extract used values.
for i = 1, #playerData.trapsheet do
local ts=playerData.trapsheet[i] --#AIRBOSS.GrooveData
table.insert(trapsheet.X, UTILS.Round(ts.X, 1))
table.insert(trapsheet.Z, UTILS.Round(ts.Z, 1))
table.insert(trapsheet.AoA, UTILS.Round(ts.AoA, 2))
table.insert(trapsheet.Alt, UTILS.Round(ts.Alt, 1))
end
local result={}
result.command=SOCKET.DataType.LSOGRADE
result.name=playerData.name
result.trapsheet=trapsheet
result.airframe=grade.airframe
result.mitime=grade.mitime
result.midate=grade.midate
result.wind=grade.wind
result.carriertype=grade.carriertype
result.carriername=grade.carriername
result.carrierrwy=grade.carrierrwy
result.landingdist=self.carrierparam.landingdist
result.theatre=grade.theatre
result.case=playerData.case
result.Tgroove=grade.Tgroove
result.wire=grade.wire
result.grade=grade.grade
result.points=grade.points
result.details=grade.details
-- Debug info.
self:T(self.lid.."Result onafterLSOGrade")
self:T(result)
-- Send result.
self.funkmanSocket:SendTable(result)
end
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@@ -1,4 +1,4 @@
--- **Ops** -- Combat Search and Rescue.
--- **Ops** - Combat Search and Rescue.
--
-- ===
--
@@ -26,11 +26,11 @@
--
-- ===
--
-- ### Author: **Applevangelist** (Moose Version), ***Ciribob*** (original), Thanks to: Shadowze, Cammel (testing)
-- ### Author: **Applevangelist** (Moose Version), ***Ciribob*** (original), Thanks to: Shadowze, Cammel (testing), The Chosen One (Persistence)
-- @module Ops.CSAR
-- @image OPS_CSAR.jpg
-- Date: June 2022
-- Date: January 2023
-------------------------------------------------------------------------
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
@@ -98,23 +98,23 @@
-- mycsar.useprefix = true -- Requires CSAR helicopter #GROUP names to have the prefix(es) defined below.
-- mycsar.csarPrefix = { "helicargo", "MEDEVAC"} -- #GROUP name prefixes used for useprefix=true - DO NOT use # in helicopter names in the Mission Editor!
-- mycsar.verbose = 0 -- set to > 1 for stats output for debugging.
-- -- (added 0.1.4) limit amount of downed pilots spawned by **ejection** events
-- -- limit amount of downed pilots spawned by **ejection** events
-- mycsar.limitmaxdownedpilots = true
-- mycsar.maxdownedpilots = 10
-- -- (added 0.1.8) - allow to set far/near distance for approach and optionally pilot must open doors
-- -- allow to set far/near distance for approach and optionally pilot must open doors
-- mycsar.approachdist_far = 5000 -- switch do 10 sec interval approach mode, meters
-- mycsar.approachdist_near = 3000 -- switch to 5 sec interval approach mode, meters
-- mycsar.pilotmustopendoors = false -- switch to true to enable check of open doors
-- -- (added 0.1.9)
-- mycsar.suppressmessages = false -- switch off all messaging if you want to do your own
-- -- (added 0.1.11)
-- mycsar.rescuehoverheight = 20 -- max height for a hovering rescue in meters
-- mycsar.rescuehoverdistance = 10 -- max distance for a hovering rescue in meters
-- -- (added 0.1.12)
-- -- Country codes for spawned pilots
-- mycsar.countryblue= country.id.USA
-- mycsar.countryred = country.id.RUSSIA
-- mycsar.countryneutral = country.id.UN_PEACEKEEPERS
-- mycsar.topmenuname = "CSAR" -- set the menu entry name
-- mycsar.ADFRadioPwr = 1000 -- ADF Beacons sending with 1KW as default
-- mycsar.PilotWeight = 80 -- Loaded pilots weigh 80kgs each
--
-- ## 2.1 Experimental Features
--
@@ -197,6 +197,26 @@
--
-- --Create a casualty and CASEVAC request from a "Point" (VEC2) for the blue coalition --shagrat
-- my_csar:SpawnCASEVAC(Point, coalition.side.BLUE)
--
-- ## 6. Save and load downed pilots - Persistance
--
-- You can save and later load back downed pilots to make your mission persistent.
-- For this to work, you need to de-sanitize **io** and **lfs** in your MissionScripting.lua, which is located in your DCS installtion folder under Scripts.
-- There is a risk involved in doing that; if you do not know what that means, this is possibly not for you.
--
-- Use the following options to manage your saves:
--
-- mycsar.enableLoadSave = true -- allow auto-saving and loading of files
-- mycsar.saveinterval = 600 -- save every 10 minutes
-- mycsar.filename = "missionsave.csv" -- example filename
-- mycsar.filepath = "C:\\Users\\myname\\Saved Games\\DCS\Missions\\MyMission" -- example path
--
-- Then use an initial load at the beginning of your mission:
--
-- mycsar:__Load(10)
--
-- **Caveat:**
-- Dropped troop noMessage and forcedesc parameters aren't saved.
--
-- @field #CSAR
CSAR = {
@@ -218,7 +238,7 @@ CSAR = {
smokeMarkers = {}, -- tracks smoke markers for groups
heliVisibleMessage = {}, -- tracks if the first message has been sent of the heli being visible
heliCloseMessage = {}, -- tracks heli close message ie heli < 500m distance
max_units = 6, --number of pilots that can be carried
max_units = 6, -- number of pilots that can be carried
hoverStatus = {}, -- tracks status of a helis hover above a downed pilot
pilotDisabled = {}, -- tracks what aircraft a pilot is disabled for
pilotLives = {}, -- tracks how many lives a pilot has
@@ -232,6 +252,9 @@ CSAR = {
limitmaxdownedpilots = true,
maxdownedpilots = 10,
allheligroupset = nil,
topmenuname = "CSAR",
ADFRadioPwr = 1000,
PilotWeight = 80,
}
--- Downed pilots info.
@@ -269,7 +292,7 @@ CSAR.AircraftType["Bronco-OV-10A"] = 2
--- CSAR class version.
-- @field #string version
CSAR.version="1.0.9"
CSAR.version="1.0.17"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
@@ -277,7 +300,7 @@ CSAR.version="1.0.9"
-- DONE: SRS Integration (to be tested)
-- TODO: Maybe - add option to smoke/flare closest MASH
-- TODO: shagrat Add cargoWeight to helicopter when pilot boarded
-- DONE: shagrat Add cargoWeight to helicopter when pilot boarded
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -293,6 +316,8 @@ function CSAR:New(Coalition, Template, Alias)
-- Inherit everything from FSM class.
local self=BASE:Inherit(self, FSM:New()) -- #CSAR
BASE:T({Coalition, Prefixes, Alias})
--set Coalition
if Coalition and type(Coalition)=="string" then
if Coalition=="blue" then
@@ -343,6 +368,8 @@ function CSAR:New(Coalition, Template, Alias)
self:AddTransition("*", "Returning", "*") -- CSAR able to return to base.
self:AddTransition("*", "Rescued", "*") -- Pilot at MASH.
self:AddTransition("*", "KIA", "*") -- Pilot killed in action.
self:AddTransition("*", "Load", "*") -- CSAR load event.
self:AddTransition("*", "Save", "*") -- CSAR save event.
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
-- tables, mainly for tracking actions
@@ -417,8 +444,13 @@ function CSAR:New(Coalition, Template, Alias)
self.wetfeettemplate = nil
self.usewetfeet = false
-- added 0.1.8
-- added 1.0.15
self.allowbronco = false -- set to true to use the Bronco mod as a CSAR plane
self.ADFRadioPwr = 1000
-- added 1.0.16
self.PilotWeight = 80
-- WARNING - here\'ll be dragons
-- for this to work you need to de-sanitize your mission environment in <DCS root>\Scripts\MissionScripting.lua
@@ -434,6 +466,14 @@ function CSAR:New(Coalition, Template, Alias)
self.SRSVolume = 1.0 -- volume 0.0 to 1.0
self.SRSGender = "male" -- male or female
local AliaS = string.gsub(self.alias," ","_")
self.filename = string.format("CSAR_%s_Persist.csv",AliaS)
-- load and save downed pilots
self.enableLoadSave = false
self.filepath = nil
self.saveinterval = 600
------------------------
--- Pseudo Functions ---
------------------------
@@ -463,6 +503,24 @@ function CSAR:New(Coalition, Template, Alias)
-- @function [parent=#CSAR] __Status
-- @param #CSAR self
-- @param #number delay Delay in seconds.
--
-- --- Triggers the FSM event "Load".
-- @function [parent=#CSAR] Load
-- @param #CSAR self
--- Triggers the FSM event "Load" after a delay.
-- @function [parent=#CSAR] __Load
-- @param #CSAR self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "Save".
-- @function [parent=#CSAR] Load
-- @param #CSAR self
--- Triggers the FSM event "Save" after a delay.
-- @function [parent=#CSAR] __Save
-- @param #CSAR self
-- @param #number delay Delay in seconds.
--- On After "PilotDown" event. Downed Pilot detected.
-- @function [parent=#CSAR] OnAfterPilotDown
@@ -530,6 +588,24 @@ function CSAR:New(Coalition, Template, Alias)
-- @param #string To To state.
-- @param #string Pilotname Name of the pilot KIA.
--- FSM Function OnAfterLoad.
-- @function [parent=#CSAR] OnAfterLoad
-- @param #CSAR self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #string path (Optional) Path where the file is located. Default is the DCS root installation folder or your "Saved Games\\DCS" folder if the lfs module is desanitized.
-- @param #string filename (Optional) File name for loading. Default is "CSAR_<alias>_Persist.csv".
--- FSM Function OnAfterSave.
-- @function [parent=#CSAR] OnAfterSave
-- @param #CSAR self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #string path (Optional) Path where the file is saved. Default is the DCS root installation folder or your "Saved Games\\DCS" folder if the lfs module is desanitized.
-- @param #string filename (Optional) File name for saving. Default is "CSAR_<alias>_Persist.csv".
return self
end
@@ -610,6 +686,19 @@ function CSAR:_DoubleEjection(_unitname)
return false
end
--- (User) Add a PLAYERTASK - FSM events will check success
-- @param #CSAR self
-- @param Ops.PlayerTask#PLAYERTASK PlayerTask
-- @return #CSAR self
function CSAR:AddPlayerTask(PlayerTask)
self:T(self.lid .. " AddPlayerTask")
if not self.PlayerTaskQueue then
self.PlayerTaskQueue = FIFO:New()
end
self.PlayerTaskQueue:Push(PlayerTask,PlayerTask.PlayerTaskNr)
return self
end
--- (Internal) Spawn a downed pilot
-- @param #CSAR self
-- @param #number country Country for template.
@@ -829,7 +918,7 @@ end
--- (Internal) Function to add a CSAR object into the scene at a Point coordinate (VEC_2). For mission designers wanting to add e.g. casualties to the scene, that don't use beacons.
-- @param #CSAR self
-- @param #string _Point a POINT_VEC2.
-- @param Core.Point#COORDINATE _Point
-- @param #number _coalition Coalition.
-- @param #string _description (optional) Description.
-- @param #boolean _nomessage (optional) If true, don\'t send a message to SAR.
@@ -862,7 +951,7 @@ end
--- Function to add a CSAR object into the scene at a zone coordinate. For mission designers wanting to add e.g. PoWs to the scene.
-- @param #CSAR self
-- @param #string Point a POINT_VEC2.
-- @param Core.Point#COORDINATE Point
-- @param #number Coalition Coalition.
-- @param #string Description (optional) Description.
-- @param #boolean addBeacon (optional) yes or no.
@@ -872,8 +961,8 @@ end
-- @param #boolean Forcedesc (optional) Force to use the **description passed only** for the pilot track entry. Use to have fully custom names.
-- @usage If missions designers want to spawn downed pilots into the field, e.g. at mission begin, to give the helicopter guys work, they can do this like so:
--
-- -- Create casualty "CASEVAC" at Point #POINT_VEC2 for the blue coalition.
-- my_csar:SpawnCASEVAC( POINT_VEC2, coalition.side.BLUE )
-- -- Create casualty "CASEVAC" at coordinate Core.Point#COORDINATE for the blue coalition.
-- my_csar:SpawnCASEVAC( coordinate, coalition.side.BLUE )
function CSAR:SpawnCASEVAC(Point, Coalition, Description, Nomessage, Unitname, Typename, Forcedesc)
self:_SpawnCASEVAC(Point, Coalition, Description, Nomessage, Unitname, Typename, Forcedesc)
return self
@@ -1194,6 +1283,38 @@ function CSAR:_RemoveNameFromDownedPilots(name,force)
return found
end
--- [User] Set callsign options for TTS output. See @{Wrapper.Group#GROUP.GetCustomCallSign}() on how to set customized callsigns.
-- @param #CSAR self
-- @param #boolean ShortCallsign If true, only call out the major flight number
-- @param #boolean Keepnumber If true, keep the **customized callsign** in the #GROUP name for players as-is, no amendments or numbers.
-- @param #table CallsignTranslations (optional) Table to translate between DCS standard callsigns and bespoke ones. Does not apply if using customized
-- callsigns from playername or group name.
-- @return #CSAR self
function CSAR:SetCallSignOptions(ShortCallsign,Keepnumber,CallsignTranslations)
if not ShortCallsign or ShortCallsign == false then
self.ShortCallsign = false
else
self.ShortCallsign = true
end
self.Keepnumber = Keepnumber or false
self.CallsignTranslations = CallsignTranslations
return self
end
--- (Internal) Check if a name is in downed pilot table and remove it.
-- @param #CSAR self
-- @param #string UnitName
-- @return #string CallSign
function CSAR:_GetCustomCallSign(UnitName)
local callsign = Unitname
local unit = UNIT:FindByName(UnitName)
if unit and unit:IsAlive() then
local group = unit:GetGroup()
callsign = group:GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations)
end
return callsign
end
--- (Internal) Check state of wounded group.
-- @param #CSAR self
-- @param #string heliname heliname
@@ -1250,9 +1371,9 @@ function CSAR:_CheckWoundedGroupStatus(heliname,woundedgroupname)
local dist = UTILS.MetersToNM(self.autosmokedistance)
disttext = string.format("%.0fnm",dist)
end
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nI'll pop a smoke when you are %s away.\nLand or hover by the smoke.", _heliName, _pilotName, disttext), self.messageTime,false,true)
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nI'll pop a smoke when you are %s away.\nLand or hover by the smoke.", self:_GetCustomCallSign(_heliName), _pilotName, disttext), self.messageTime,false,true)
else
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nRequest a flare or smoke if you need.", _heliName, _pilotName), self.messageTime,false,true)
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nRequest a flare or smoke if you need.", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
end
--mark as shown for THIS heli and THIS group
self.heliVisibleMessage[_lookupKeyHeli] = true
@@ -1316,7 +1437,7 @@ function CSAR:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupNam
_maxUnits = self.max_units
end
if _unitsInHelicopter + 1 > _maxUnits then
self:_DisplayMessageToSAR(_heliUnit, string.format("%s, %s. We\'re already crammed with %d guys! Sorry!", _pilotName, _heliName, _unitsInHelicopter, _unitsInHelicopter), self.messageTime,false,false,true)
self:_DisplayMessageToSAR(_heliUnit, string.format("%s, %s. We\'re already crammed with %d guys! Sorry!", _pilotName, self:_GetCustomCallSign(_heliName), _unitsInHelicopter, _unitsInHelicopter), self.messageTime,false,false,true)
return self
end
@@ -1334,13 +1455,29 @@ function CSAR:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupNam
_woundedGroup:Destroy(false)
self:_RemoveNameFromDownedPilots(_woundedGroupName,true)
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s I\'m in! Get to the MASH ASAP! ", _heliName, _pilotName), self.messageTime,true,true)
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s I\'m in! Get to the MASH ASAP! ", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,true,true)
self:_UpdateUnitCargoMass(_heliName)
self:__Boarded(5,_heliName,_woundedGroupName,grouptable.desc)
return self
end
--- (Internal) Function to calculate and set Unit internal cargo mass
-- @param #CSAR self
-- @param #string _heliName Unit name
-- @return #CSAR self
function CSAR:_UpdateUnitCargoMass(_heliName)
self:T(self.lid .. " _UpdateUnitCargoMass")
local calculatedMass = self:_PilotsOnboard(_heliName)*(self.PilotWeight or 80)
local Unit = UNIT:FindByName(_heliName)
if Unit then
Unit:SetUnitInternalCargo(calculatedMass)
end
return self
end
--- (Internal) Move group to destination.
-- @param #CSAR self
-- @param Wrapper.Group#GROUP _leader
@@ -1355,7 +1492,6 @@ function CSAR:_OrderGroupToMoveToPoint(_leader, _destination)
return self
end
--- (internal) Function to check if the heli door(s) are open. Thanks to Shadowze.
-- @param #CSAR self
-- @param #string unit_name Name of unit.
@@ -1389,9 +1525,9 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
if self.heliCloseMessage[_lookupKeyHeli] == nil then
if self.autosmoke == true then
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land or hover at the smoke.", _heliName, _pilotName), self.messageTime,false,true)
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land or hover at the smoke.", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
else
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land in a safe place, I will go there ", _heliName, _pilotName), self.messageTime,false,true)
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land in a safe place, I will go there ", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
end
self.heliCloseMessage[_lookupKeyHeli] = true
end
@@ -1444,7 +1580,7 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
end
if _heliUnit:InAir() and _unitsInHelicopter + 1 <= _maxUnits then
-- TODO - make variable
-- DONE - make variable
if _distance < self.rescuehoverdistance then
--check height!
@@ -1452,7 +1588,7 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
if leaderheight < 0 then leaderheight = 0 end
local _height = _heliUnit:GetHeight() - leaderheight
-- TODO - make variable
-- DONE - make variable
if _height <= self.rescuehoverheight then
local _time = self.hoverStatus[_lookupKeyHeli]
@@ -1558,9 +1694,12 @@ function CSAR:_RescuePilots(_heliUnit)
self.inTransitGroups[_heliName] = nil
local _txt = string.format("%s: The %d pilot(s) have been taken to the\nmedical clinic. Good job!", _heliName, PilotsSaved)
local _txt = string.format("%s: The %d pilot(s) have been taken to the\nmedical clinic. Good job!", self:_GetCustomCallSign(_heliName), PilotsSaved)
self:_DisplayMessageToSAR(_heliUnit, _txt, self.messageTime)
self:_UpdateUnitCargoMass(_heliName)
-- trigger event
self:__Rescued(-1,_heliUnit,_heliName, PilotsSaved)
return self
@@ -1594,7 +1733,7 @@ function CSAR:_DisplayMessageToSAR(_unit, _text, _time, _clear, _speak, _overrid
local _clear = _clear or nil
local _time = _time or self.messageTime
if _override or not self.suppressmessages then
local m = MESSAGE:New(_text,_time,"Info",_clear):ToGroup(group)
local m = MESSAGE:New(_text,_time,"CSAR",_clear):ToGroup(group)
end
-- integrate SRS
if _speak and self.useSRS then
@@ -1743,7 +1882,7 @@ function CSAR:_SignalFlare(_unitName)
else
_distance = string.format("%.1fkm",_closest.distance)
end
local _msg = string.format("%s - Popping signal flare at your %s o\'clock. Distance %s", _unitName, _clockDir, _distance)
local _msg = string.format("%s - Popping signal flare at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance)
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
local _coord = _closest.pilot:GetCoordinate()
@@ -1797,7 +1936,7 @@ function CSAR:_Reqsmoke( _unitName )
else
_distance = string.format("%.1fkm",_closest.distance/1000)
end
local _msg = string.format("%s - Popping smoke at your %s o\'clock. Distance %s", _unitName, _clockDir, _distance)
local _msg = string.format("%s - Popping smoke at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance)
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
local _coord = _closest.pilot:GetCoordinate()
local color = self.smokecolor
@@ -1848,7 +1987,7 @@ function CSAR:_GetClosestMASH(_heli)
if self.allowFARPRescue then
local position = _heli:GetCoordinate()
local afb,distance = position:GetClosestAirbase2(nil,self.coalition)
local afb,distance = position:GetClosestAirbase(nil,self.coalition)
_shortestDistance = distance
end
@@ -1923,7 +2062,8 @@ function CSAR:_AddMedevacMenuItem()
local groupname = _group:GetName()
if self.addedTo[groupname] == nil then
self.addedTo[groupname] = true
local _rootPath = MENU_GROUP:New(_group,"CSAR")
local menuname = self.topmenuname or "CSAR"
local _rootPath = MENU_GROUP:New(_group,menuname)
local _rootMenu1 = MENU_GROUP_COMMAND:New(_group,"List Active CSAR",_rootPath, self._DisplayActiveSAR,self,_unitName)
local _rootMenu2 = MENU_GROUP_COMMAND:New(_group,"Check Onboard",_rootPath, self._CheckOnboard,self,_unitName)
local _rootMenu3 = MENU_GROUP_COMMAND:New(_group,"Request Signal Flare",_rootPath, self._SignalFlare,self,_unitName)
@@ -2000,13 +2140,17 @@ function CSAR:_GetClockDirection(_heli, _group)
local DirectionVec3 = _playerPosition:GetDirectionVec3( _targetpostions )
local Angle = _playerPosition:GetAngleDegrees( DirectionVec3 )
self:T(self.lid .. " _GetClockDirection"..tostring(Angle).." "..tostring(_heading))
local clock = 12
if _heading then
local Aspect = Angle - _heading
if Aspect == 0 then Aspect = 360 end
clock = math.abs(UTILS.Round((Aspect / 30),0))
if clock == 0 then clock = 12 end
end
local hours = 0
local clock = 12
if _heading and Angle then
clock = 12
--if angle == 0 then angle = 360 end
clock = _heading-Angle
hours = (clock/30)*-1
clock = 12+hours
clock = UTILS.Round(clock,0)
if clock > 12 then clock = clock-12 end
end
return clock
end
@@ -2032,9 +2176,10 @@ function CSAR:_AddBeaconToGroup(_group, _freq)
local _radioUnit = _group:GetUnit(1)
if _radioUnit then
local Frequency = _freq -- Freq in Hertz
local name = _radioUnit:GetName()
local Sound = "l10n/DEFAULT/"..self.radioSound
local vec3 = _radioUnit:GetVec3() or _radioUnit:GetPositionVec3() or {x=0,y=0,z=0}
trigger.action.radioTransmission(Sound, vec3, 0, false, Frequency, 1000) -- Beacon in MP only runs for exactly 30secs straight
trigger.action.radioTransmission(Sound, vec3, 0, false, Frequency, self.ADFRadioPwr or 1000,name..math.random(1,10000)) -- Beacon in MP only runs for exactly 30secs straight
end
end
return self
@@ -2142,7 +2287,16 @@ function CSAR:onafterStart(From, Event, To)
self.msrs:SetLabel("CSAR")
self.SRSQueue = MSRSQUEUE:New("CSAR")
end
self:__Status(-10)
if self.enableLoadSave then
local interval = self.saveinterval
local filename = self.filename
local filepath = self.filepath
self:__Save(interval,filepath,filename)
end
return self
end
@@ -2278,6 +2432,29 @@ end
function CSAR:onbeforeBoarded(From, Event, To, Heliname, Woundedgroupname)
self:T({From, Event, To, Heliname, Woundedgroupname})
self:_ScheduledSARFlight(Heliname,Woundedgroupname)
local Unit = UNIT:FindByName(Heliname)
if Unit and Unit:IsPlayer() and self.PlayerTaskQueue then
local playername = Unit:GetPlayerName()
local dropcoord = Unit:GetCoordinate() or COORDINATE:New(0,0,0)
local dropvec2 = dropcoord:GetVec2()
self.PlayerTaskQueue:ForEach(
function (Task)
local task = Task -- Ops.PlayerTask#PLAYERTASK
local subtype = task:GetSubType()
-- right subtype?
if Event == subtype and not task:IsDone() then
local targetzone = task.Target:GetObject() -- Core.Zone#ZONE should be a zone in this case ....
if (targetzone and targetzone.ClassName and string.match(targetzone.ClassName,"ZONE") and targetzone:IsVec2InZone(dropvec2))
or (string.find(task.CSARPilotName,Woundedgroupname)) then
if task.Clients:HasUniqueID(playername) then
-- success
task:__Success(-1)
end
end
end
end
)
end
return self
end
@@ -2307,6 +2484,23 @@ function CSAR:onbeforeRescued(From, Event, To, HeliUnit, HeliName, PilotsSaved)
self:T({From, Event, To, HeliName, HeliUnit})
self.rescues = self.rescues + 1
self.rescuedpilots = self.rescuedpilots + PilotsSaved
local Unit = HeliUnit or UNIT:FindByName(HeliName)
if Unit and Unit:IsPlayer() and self.PlayerTaskQueue then
local playername = Unit:GetPlayerName()
self.PlayerTaskQueue:ForEach(
function (Task)
local task = Task -- Ops.PlayerTask#PLAYERTASK
local subtype = task:GetSubType()
-- right subtype?
if Event == subtype and not task:IsDone() then
if task.Clients:HasUniqueID(playername) then
-- success
task:__Success(-1)
end
end
end
)
end
return self
end
@@ -2335,6 +2529,240 @@ function CSAR:onbeforeLanded(From, Event, To, HeliName, Airbase)
self:T({From, Event, To, HeliName, Airbase})
return self
end
--- On before "Save" event. Checks if io and lfs are available.
-- @param #CSAR self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #string path (Optional) Path where the file is saved. Default is the DCS root installation folder or your "Saved Games\\DCS" folder if the lfs module is desanitized.
-- @param #string filename (Optional) File name for saving. Default is "CSAR_<alias>_Persist.csv".
function CSAR:onbeforeSave(From, Event, To, path, filename)
self:T({From, Event, To, path, filename})
if not self.enableLoadSave then
return self
end
-- Thanks to @FunkyFranky
-- Check io module is available.
if not io then
self:E(self.lid.."ERROR: io not desanitized. Can't save current state.")
return false
end
-- Check default path.
if path==nil and not lfs then
self:E(self.lid.."WARNING: lfs not desanitized. State will be saved in DCS installation root directory rather than your \"Saved Games\\DCS\" folder.")
end
return true
end
--- On after "Save" event. Player data is saved to file.
-- @param #CSAR self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #string path Path where the file is saved. If nil, file is saved in the DCS root installtion directory or your "Saved Games" folder if lfs was desanitized.
-- @param #string filename (Optional) File name for saving. Default is Default is "CSAR_<alias>_Persist.csv".
function CSAR:onafterSave(From, Event, To, path, filename)
self:T({From, Event, To, path, filename})
-- Thanks to @FunkyFranky
if not self.enableLoadSave then
return self
end
--- Function that saves data to file
local function _savefile(filename, data)
local f = assert(io.open(filename, "wb"))
f:write(data)
f:close()
end
-- Set path or default.
if lfs then
path=self.filepath or lfs.writedir()
end
-- Set file name.
filename=filename or self.filename
-- Set path.
if path~=nil then
filename=path.."\\"..filename
end
local pilots = self.downedPilots
--local data = "LoadedData = {\n"
local data = "playerName,x,y,z,coalition,country,description,typeName,unitName,freq\n"
local n = 0
for _,_grp in pairs(pilots) do
local DownedPilot = _grp -- Wrapper.Group#GROUP
if DownedPilot and DownedPilot.alive then
-- get downed pilot data for saving
local playerName = DownedPilot.player
local group = DownedPilot.group
local coalition = group:GetCoalition()
local country = group:GetCountry()
local description = DownedPilot.desc
local typeName = DownedPilot.typename
local freq = DownedPilot.frequency
local location = group:GetVec3()
local unitName = DownedPilot.originalUnit
local txt = string.format("%s,%d,%d,%d,%s,%s,%s,%s,%s,%d\n",playerName,location.x,location.y,location.z,coalition,country,description,typeName,unitName,freq)
self:I(self.lid.."Saving to CSAR File: " .. txt)
data = data .. txt
end
end
_savefile(filename, data)
-- AutoSave
if self.enableLoadSave then
local interval = self.saveinterval
local filename = self.filename
local filepath = self.filepath
self:__Save(interval,filepath,filename)
end
return self
end
--- On before "Load" event. Checks if io and lfs and the file are available.
-- @param #CSAR self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #string path (Optional) Path where the file is located. Default is the DCS root installation folder or your "Saved Games\\DCS" folder if the lfs module is desanitized.
-- @param #string filename (Optional) File name for loading. Default is "CSAR_<alias>_Persist.csv".
function CSAR:onbeforeLoad(From, Event, To, path, filename)
self:T({From, Event, To, path, filename})
if not self.enableLoadSave then
return self
end
--- Function that check if a file exists.
local function _fileexists(name)
local f=io.open(name,"r")
if f~=nil then
io.close(f)
return true
else
return false
end
end
-- Set file name and path
filename=filename or self.filename
path = path or self.filepath
-- Check io module is available.
if not io then
self:E(self.lid.."WARNING: io not desanitized. Cannot load file.")
return false
end
-- Check default path.
if path==nil and not lfs then
self:E(self.lid.."WARNING: lfs not desanitized. State will be saved in DCS installation root directory rather than your \"Saved Games\\DCS\" folder.")
end
-- Set path or default.
if lfs then
path=path or lfs.writedir()
end
-- Set path.
if path~=nil then
filename=path.."\\"..filename
end
-- Check if file exists.
local exists=_fileexists(filename)
if exists then
return true
else
self:E(self.lid..string.format("WARNING: State file %s might not exist.", filename))
return false
--return self
end
end
--- On after "Load" event. Loads dropped units from file.
-- @param #CSAR self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #string path (Optional) Path where the file is located. Default is the DCS root installation folder or your "Saved Games\\DCS" folder if the lfs module is desanitized.
-- @param #string filename (Optional) File name for loading. Default is "CSAR_<alias>_Persist.csv".
function CSAR:onafterLoad(From, Event, To, path, filename)
self:T({From, Event, To, path, filename})
if not self.enableLoadSave then
return self
end
--- Function that loads data from a file.
local function _loadfile(filename)
local f=assert(io.open(filename, "rb"))
local data=f:read("*all")
f:close()
return data
end
-- Set file name and path
filename=filename or self.filename
path = path or self.filepath
-- Set path or default.
if lfs then
path=path or lfs.writedir()
end
-- Set path.
if path~=nil then
filename=path.."\\"..filename
end
-- Info message.
local text=string.format("Loading CSAR state from file %s", filename)
MESSAGE:New(text,10):ToAllIf(self.Debug)
self:I(self.lid..text)
local file=assert(io.open(filename, "rb"))
local loadeddata = {}
for line in file:lines() do
loadeddata[#loadeddata+1] = line
end
file:close()
-- remove header
table.remove(loadeddata, 1)
for _id,_entry in pairs (loadeddata) do
local dataset = UTILS.Split(_entry,",")
-- 1=playerName,2=x,3=y,4=z,5=coalition,6=country,7=description,8=typeName,9=unitName,10=freq\n
local playerName = dataset[1]
local vec3 = {}
vec3.x = tonumber(dataset[2])
vec3.y = tonumber(dataset[3])
vec3.z = tonumber(dataset[4])
local point = COORDINATE:NewFromVec3(vec3)
local coalition = dataset[5]
local country = dataset[6]
local description = dataset[7]
local typeName = dataset[8]
local unitName = dataset[9]
local freq = dataset[10]
self:_AddCsar(coalition, country, point, typeName, unitName, playerName, freq, nil, description, nil)
end
return self
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- End Ops.CSAR
--------------------------------------------------------------------------------------------------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@@ -9,13 +9,13 @@
-- 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**.
-- * They can be **subtitled** for a specific **duration**, the **power** in Watts of the transmitter's antenna can be set, and the transmission can be **looped**.
--
-- 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),
-- * They need to be added in .\l10n\DEFAULT\ in you .miz file (which can be decompressed like a .zip file),
-- * 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 @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or by any other @{Wrapper.Positionable#POSITIONABLE}
@@ -26,7 +26,7 @@
-- 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 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.
-- you won't hear/be able to use the TACAN beacon information.
--
-- ===
--
@@ -98,12 +98,12 @@ RADIO = {
--- 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.
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Wrapper.Positionable#POSITIONABLE} that will receive radio capabilities.
-- @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
local self = BASE:Inherit( self, BASE:New() ) -- Sound.Radio#RADIO
self:F(Positionable)
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure positionable is valid
@@ -375,7 +375,7 @@ end
--- Stops a transmission
-- This function is especially usefull to stop the broadcast of looped transmissions
-- This function is especially useful to stop the broadcast of looped transmissions
-- @param #RADIO self
-- @return #RADIO self
function RADIO:StopBroadcast()

View File

@@ -1,4 +1,4 @@
--- **Sound** - Simple Radio Standalone (SRS) Integration.
--- **Sound** - Simple Radio Standalone (SRS) Integration and Text-to-Speech.
--
-- ===
--
@@ -26,7 +26,7 @@
-- ===
--
-- ### Author: **funkyfranky**
-- @module Sound.MSRS
-- @module Sound.SRS
-- @image Sound_MSRS.png
--- MSRS class.
@@ -94,8 +94,6 @@
-- For more information on setting up a cloud account, visit: https://cloud.google.com/text-to-speech
-- Google's supported SSML reference: https://cloud.google.com/text-to-speech/docs/ssml
--
-- **NOTE on using GOOGLE TTS with SRS:** You need to have the C# library installed in your SRS folder for Google to work.
-- You can obtain it e.g. here: [NuGet](https://www.nuget.org/packages/Grpc.Core)
--
-- **Pro-Tipp** - use the command line with power shell to call DCS-SR-ExternalAudio.exe - it will tell you what is missing.
-- and also the Google Console error, in case you have missed a step in setting up your Google TTS.
@@ -104,10 +102,14 @@
--
-- ## Set Voice
--
-- Use a specifc voice with the @{#MSRS.SetVoice} function, e.g, `:SetVoice("Microsoft Hedda Desktop")`.
-- Use a specific voice with the @{#MSRS.SetVoice} function, e.g, `:SetVoice("Microsoft Hedda Desktop")`.
-- Note that this must be installed on your windows system.
-- If enabling SetGoogle(), you can use voices provided by Google
-- Google's supported voices: https://cloud.google.com/text-to-speech/docs/voices
-- For voices there are enumerators in this class to help you out on voice names:
--
-- MSRS.Voices.Microsoft -- e.g. MSRS.Voices.Microsoft.Hedda - the Microsoft enumerator contains all voices known to work with SRS
-- MSRS.Voices.Google -- e.g. MSRS.Voices.Google.Standard.en_AU_Standard_A or MSRS.Voices.Google.Wavenet.de_DE_Wavenet_C - The Google enumerator contains voices for EN, DE, IT, FR and ES.
--
-- ## Set Coordinate
--
@@ -141,7 +143,7 @@ MSRS = {
--- MSRS class version.
-- @field #string version
MSRS.version="0.1.0"
MSRS.version="0.1.1"
--- Voices
-- @type Voices
@@ -155,91 +157,91 @@ MSRS.Voices = {
},
Google = {
Standard = {
["en-AU-Standard-A"] = 'en-AU-Standard-A', -- [1] FEMALE
["en-AU-Standard-B"] = 'en-AU-Standard-B', -- [2] MALE
["en-AU-Standard-C"] = 'en-AU-Standard-C', -- [3] FEMALE
["en-AU-Standard-D"] = 'en-AU-Standard-D', -- [4] MALE
["en-IN-Standard-A"] = 'en-IN-Standard-A', -- [5] FEMALE
["en-IN-Standard-B"] = 'en-IN-Standard-B', -- [6] MALE
["en-IN-Standard-C"] = 'en-IN-Standard-C', -- [7] MALE
["en-IN-Standard-D"] = 'en-IN-Standard-D', -- [8] FEMALE
["en-GB-Standard-A"] = 'en-GB-Standard-A', -- [9] FEMALE
["en-GB-Standard-B"] = 'en-GB-Standard-B', -- [10] MALE
["en-GB-Standard-C"] = 'en-GB-Standard-C', -- [11] FEMALE
["en-GB-Standard-D"] = 'en-GB-Standard-D', -- [12] MALE
["en-GB-Standard-F"] = 'en-GB-Standard-F', -- [13] FEMALE
["en-US-Standard-A"] = 'en-US-Standard-A', -- [14] MALE
["en-US-Standard-B"] = 'en-US-Standard-B', -- [15] MALE
["en-US-Standard-C"] = 'en-US-Standard-C', -- [16] FEMALE
["en-US-Standard-D"] = 'en-US-Standard-D', -- [17] MALE
["en-US-Standard-E"] = 'en-US-Standard-E', -- [18] FEMALE
["en-US-Standard-F"] = 'en-US-Standard-F', -- [19] FEMALE
["en-US-Standard-G"] = 'en-US-Standard-G', -- [20] FEMALE
["en-US-Standard-H"] = 'en-US-Standard-H', -- [21] FEMALE
["en-US-Standard-I"] = 'en-US-Standard-I', -- [22] MALE
["en-US-Standard-J"] = 'en-US-Standard-J', -- [23] MALE
["fr-FR-Standard-A"] = "fr-FR-Standard-A", -- Female
["fr-FR-Standard-B"] = "fr-FR-Standard-B", -- Male
["fr-FR-Standard-C"] = "fr-FR-Standard-C", -- Female
["fr-FR-Standard-D"] = "fr-FR-Standard-D", -- Male
["fr-FR-Standard-E"] = "fr-FR-Standard-E", -- Female
["de-DE-Standard-A"] = "de-DE-Standard-A", -- Female
["de-DE-Standard-B"] = "de-DE-Standard-B", -- Male
["de-DE-Standard-C"] = "de-DE-Standard-C", -- Female
["de-DE-Standard-D"] = "de-DE-Standard-D", -- Male
["de-DE-Standard-E"] = "de-DE-Standard-E", -- Male
["de-DE-Standard-F"] = "de-DE-Standard-F", -- Female
["es-ES-Standard-A"] = "es-ES-Standard-A", -- Female
["es-ES-Standard-B"] = "es-ES-Standard-B", -- Male
["es-ES-Standard-C"] = "es-ES-Standard-C", -- Female
["es-ES-Standard-D"] = "es-ES-Standard-D", -- Female
["it-IT-Standard-A"] = "it-IT-Standard-A", -- Female
["it-IT-Standard-B"] = "it-IT-Standard-B", -- Female
["it-IT-Standard-C"] = "it-IT-Standard-C", -- Male
["it-IT-Standard-D"] = "it-IT-Standard-D", -- Male
["en_AU_Standard_A"] = 'en-AU-Standard-A', -- [1] FEMALE
["en_AU_Standard_B"] = 'en-AU-Standard-B', -- [2] MALE
["en_AU_Standard_C"] = 'en-AU-Standard-C', -- [3] FEMALE
["en_AU_Standard_D"] = 'en-AU-Standard-D', -- [4] MALE
["en_IN_Standard_A"] = 'en-IN-Standard-A', -- [5] FEMALE
["en_IN_Standard_B"] = 'en-IN-Standard-B', -- [6] MALE
["en_IN_Standard_C"] = 'en-IN-Standard-C', -- [7] MALE
["en_IN_Standard_D"] = 'en-IN-Standard-D', -- [8] FEMALE
["en_GB_Standard_A"] = 'en-GB-Standard-A', -- [9] FEMALE
["en_GB_Standard_B"] = 'en-GB-Standard-B', -- [10] MALE
["en_GB_Standard_C"] = 'en-GB-Standard-C', -- [11] FEMALE
["en_GB_Standard_D"] = 'en-GB-Standard-D', -- [12] MALE
["en_GB_Standard_F"] = 'en-GB-Standard-F', -- [13] FEMALE
["en_US_Standard_A"] = 'en-US-Standard-A', -- [14] MALE
["en_US_Standard_B"] = 'en-US-Standard-B', -- [15] MALE
["en_US_Standard_C"] = 'en-US-Standard-C', -- [16] FEMALE
["en_US_Standard_D"] = 'en-US-Standard-D', -- [17] MALE
["en_US_Standard_E"] = 'en-US-Standard-E', -- [18] FEMALE
["en_US_Standard_F"] = 'en-US-Standard-F', -- [19] FEMALE
["en_US_Standard_G"] = 'en-US-Standard-G', -- [20] FEMALE
["en_US_Standard_H"] = 'en-US-Standard-H', -- [21] FEMALE
["en_US_Standard_I"] = 'en-US-Standard-I', -- [22] MALE
["en_US_Standard_J"] = 'en-US-Standard-J', -- [23] MALE
["fr_FR_Standard_A"] = "fr-FR-Standard-A", -- Female
["fr_FR_Standard_B"] = "fr-FR-Standard-B", -- Male
["fr_FR_Standard_C"] = "fr-FR-Standard-C", -- Female
["fr_FR_Standard_D"] = "fr-FR-Standard-D", -- Male
["fr_FR_Standard_E"] = "fr-FR-Standard-E", -- Female
["de_DE_Standard_A"] = "de-DE-Standard-A", -- Female
["de_DE_Standard_B"] = "de-DE-Standard-B", -- Male
["de_DE_Standard_C"] = "de-DE-Standard-C", -- Female
["de_DE_Standard_D"] = "de-DE-Standard-D", -- Male
["de_DE_Standard_E"] = "de-DE-Standard-E", -- Male
["de_DE_Standard_F"] = "de-DE-Standard-F", -- Female
["es_ES_Standard_A"] = "es-ES-Standard-A", -- Female
["es_ES_Standard_B"] = "es-ES-Standard-B", -- Male
["es_ES_Standard_C"] = "es-ES-Standard-C", -- Female
["es_ES_Standard_D"] = "es-ES-Standard-D", -- Female
["it_IT_Standard_A"] = "it-IT-Standard-A", -- Female
["it_IT_Standard_B"] = "it-IT-Standard-B", -- Female
["it_IT_Standard_C"] = "it-IT-Standard-C", -- Male
["it_IT_Standard_D"] = "it-IT-Standard-D", -- Male
},
Wavenet = {
["en-AU-Wavenet-A"] = 'en-AU-Wavenet-A', -- [1] FEMALE
["en-AU-Wavenet-B"] = 'en-AU-Wavenet-B', -- [2] MALE
["en-AU-Wavenet-C"] = 'en-AU-Wavenet-C', -- [3] FEMALE
["en-AU-Wavenet-D"] = 'en-AU-Wavenet-D', -- [4] MALE
["en-IN-Wavenet-A"] = 'en-IN-Wavenet-A', -- [5] FEMALE
["en-IN-Wavenet-B"] = 'en-IN-Wavenet-B', -- [6] MALE
["en-IN-Wavenet-C"] = 'en-IN-Wavenet-C', -- [7] MALE
["en-IN-Wavenet-D"] = 'en-IN-Wavenet-D', -- [8] FEMALE
["en-GB-Wavenet-A"] = 'en-GB-Wavenet-A', -- [9] FEMALE
["en-GB-Wavenet-B"] = 'en-GB-Wavenet-B', -- [10] MALE
["en-GB-Wavenet-C"] = 'en-GB-Wavenet-C', -- [11] FEMALE
["en-GB-Wavenet-D"] = 'en-GB-Wavenet-D', -- [12] MALE
["en-GB-Wavenet-F"] = 'en-GB-Wavenet-F', -- [13] FEMALE
["en-US-Wavenet-A"] = 'en-US-Wavenet-A', -- [14] MALE
["en-US-Wavenet-B"] = 'en-US-Wavenet-B', -- [15] MALE
["en-US-Wavenet-C"] = 'en-US-Wavenet-C', -- [16] FEMALE
["en-US-Wavenet-D"] = 'en-US-Wavenet-D', -- [17] MALE
["en-US-Wavenet-E"] = 'en-US-Wavenet-E', -- [18] FEMALE
["en-US-Wavenet-F"] = 'en-US-Wavenet-F', -- [19] FEMALE
["en-US-Wavenet-G"] = 'en-US-Wavenet-G', -- [20] FEMALE
["en-US-Wavenet-H"] = 'en-US-Wavenet-H', -- [21] FEMALE
["en-US-Wavenet-I"] = 'en-US-Wavenet-I', -- [22] MALE
["en-US-Wavenet-J"] = 'en-US-Wavenet-J', -- [23] MALE
["fr-FR-Wavenet-A"] = "fr-FR-Wavenet-A", -- Female
["fr-FR-Wavenet-B"] = "fr-FR-Wavenet-B", -- Male
["fr-FR-Wavenet-C"] = "fr-FR-Wavenet-C", -- Female
["fr-FR-Wavenet-D"] = "fr-FR-Wavenet-D", -- Male
["fr-FR-Wavenet-E"] = "fr-FR-Wavenet-E", -- Female
["de-DE-Wavenet-A"] = "de-DE-Wavenet-A", -- Female
["de-DE-Wavenet-B"] = "de-DE-Wavenet-B", -- Male
["de-DE-Wavenet-C"] = "de-DE-Wavenet-C", -- Female
["de-DE-Wavenet-D"] = "de-DE-Wavenet-D", -- Male
["de-DE-Wavenet-E"] = "de-DE-Wavenet-E", -- Male
["de-DE-Wavenet-F"] = "de-DE-Wavenet-F", -- Female
["es-ES-Wavenet-B"] = "es-ES-Wavenet-B", -- Male
["es-ES-Wavenet-C"] = "es-ES-Wavenet-C", -- Female
["es-ES-Wavenet-D"] = "es-ES-Wavenet-D", -- Female
["it-IT-Wavenet-A"] = "it-IT-Wavenet-A", -- Female
["it-IT-Wavenet-B"] = "it-IT-Wavenet-B", -- Female
["it-IT-Wavenet-C"] = "it-IT-Wavenet-C", -- Male
["it-IT-Wavenet-D"] = "it-IT-Wavenet-D", -- Male
["en_AU_Wavenet_A"] = 'en-AU-Wavenet-A', -- [1] FEMALE
["en_AU_Wavenet_B"] = 'en-AU-Wavenet-B', -- [2] MALE
["en_AU_Wavenet_C"] = 'en-AU-Wavenet-C', -- [3] FEMALE
["en_AU_Wavenet_D"] = 'en-AU-Wavenet-D', -- [4] MALE
["en_IN_Wavenet_A"] = 'en-IN-Wavenet-A', -- [5] FEMALE
["en_IN_Wavenet_B"] = 'en-IN-Wavenet-B', -- [6] MALE
["en_IN_Wavenet_C"] = 'en-IN-Wavenet-C', -- [7] MALE
["en_IN_Wavenet_D"] = 'en-IN-Wavenet-D', -- [8] FEMALE
["en_GB_Wavenet_A"] = 'en-GB-Wavenet-A', -- [9] FEMALE
["en_GB_Wavenet_B"] = 'en-GB-Wavenet-B', -- [10] MALE
["en_GB_Wavenet_C"] = 'en-GB-Wavenet-C', -- [11] FEMALE
["en_GB_Wavenet_D"] = 'en-GB-Wavenet-D', -- [12] MALE
["en_GB_Wavenet_F"] = 'en-GB-Wavenet-F', -- [13] FEMALE
["en_US_Wavenet_A"] = 'en-US-Wavenet-A', -- [14] MALE
["en_US_Wavenet_B"] = 'en-US-Wavenet-B', -- [15] MALE
["en_US_Wavenet_C"] = 'en-US-Wavenet-C', -- [16] FEMALE
["en_US_Wavenet_D"] = 'en-US-Wavenet-D', -- [17] MALE
["en_US_Wavenet_E"] = 'en-US-Wavenet-E', -- [18] FEMALE
["en_US_Wavenet_F"] = 'en-US-Wavenet-F', -- [19] FEMALE
["en_US_Wavenet_G"] = 'en-US-Wavenet-G', -- [20] FEMALE
["en_US_Wavenet_H"] = 'en-US-Wavenet-H', -- [21] FEMALE
["en_US_Wavenet_I"] = 'en-US-Wavenet-I', -- [22] MALE
["en_US_Wavenet_J"] = 'en-US-Wavenet-J', -- [23] MALE
["fr_FR_Wavenet_A"] = "fr-FR-Wavenet-A", -- Female
["fr_FR_Wavenet_B"] = "fr-FR-Wavenet-B", -- Male
["fr_FR_Wavenet_C"] = "fr-FR-Wavenet-C", -- Female
["fr_FR_Wavenet_D"] = "fr-FR-Wavenet-D", -- Male
["fr_FR_Wavenet_E"] = "fr-FR-Wavenet-E", -- Female
["de_DE_Wavenet_A"] = "de-DE-Wavenet-A", -- Female
["de_DE_Wavenet_B"] = "de-DE-Wavenet-B", -- Male
["de_DE_Wavenet_C"] = "de-DE-Wavenet-C", -- Female
["de_DE_Wavenet_D"] = "de-DE-Wavenet-D", -- Male
["de_DE_Wavenet_E"] = "de-DE-Wavenet-E", -- Male
["de_DE_Wavenet_F"] = "de-DE-Wavenet-F", -- Female
["es_ES_Wavenet_B"] = "es-ES-Wavenet-B", -- Male
["es_ES_Wavenet_C"] = "es-ES-Wavenet-C", -- Female
["es_ES_Wavenet_D"] = "es-ES-Wavenet-D", -- Female
["it_IT_Wavenet_A"] = "it-IT-Wavenet-A", -- Female
["it_IT_Wavenet_B"] = "it-IT-Wavenet-B", -- Female
["it_IT_Wavenet_C"] = "it-IT-Wavenet-C", -- Male
["it_IT_Wavenet_D"] = "it-IT-Wavenet-D", -- Male
} ,
},
}
@@ -248,7 +250,7 @@ MSRS.Voices = {
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Add functions to add/remove freqs and modulations.
-- TODO: Add functions to remove freqs and modulations.
-- DONE: Add coordinate.
-- DONE: Add google.
@@ -410,6 +412,24 @@ function MSRS:SetFrequencies(Frequencies)
return self
end
--- Add frequencies.
-- @param #MSRS self
-- @param #table Frequencies Frequencies in MHz. Can also be given as a #number if only one frequency should be used.
-- @return #MSRS self
function MSRS:AddFrequencies(Frequencies)
-- Ensure table.
if type(Frequencies)~="table" then
Frequencies={Frequencies}
end
for _,_freq in pairs(Frequencies) do
table.insert(self.frequencies,_freq)
end
return self
end
--- Get frequencies.
-- @param #MSRS self
-- @param #table Frequencies in MHz.
@@ -434,6 +454,24 @@ function MSRS:SetModulations(Modulations)
return self
end
--- Add modulations.
-- @param #MSRS self
-- @param #table Modulations Modulations. Can also be given as a #number if only one modulation should be used.
-- @return #MSRS self
function MSRS:AddModulations(Modulations)
-- Ensure table.
if type(Modulations)~="table" then
Modulations={Modulations}
end
for _,_mod in pairs(Modulations) do
table.insert(self.modulations,_mod)
end
return self
end
--- Get modulations.
-- @param #MSRS self
-- @param #table Modulations.
@@ -806,16 +844,8 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
modus=modus:gsub("0", "AM")
modus=modus:gsub("1", "FM")
-- This did not work well. Stopped if the transmission was a bit longer with no apparent error.
--local command=string.format("%s --freqs=%s --modulations=%s --coalition=%d --port=%d --volume=%.2f --speed=%d", exe, freqs, modus, coal, port, volume, speed)
-- Command from orig STTS script. Works better for some unknown reason!
--local command=string.format("start /min \"\" /d \"%s\" /b \"%s\" -f %s -m %s -c %s -p %s -n \"%s\" -h", path, exe, freqs, modus, coal, port, "ROBOT")
--local command=string.format('start /b "" /d "%s" "%s" -f %s -m %s -c %s -p %s -n "%s" > bla.txt', path, exe, freqs, modus, coal, port, "ROBOT")
-- Command.
local command=string.format('"%s\\%s" -f %s -m %s -c %s -p %s -n "%s" -v "%.1f"', path, exe, freqs, modus, coal, port, label,volume)
local command=string.format('"%s\\%s" -f "%s" -m "%s" -c %s -p %s -n "%s" -v "%.1f"', path, exe, freqs, modus, coal, port, label,volume)
-- Set voice or gender/culture.
if voice then
@@ -890,6 +920,8 @@ MSRSQUEUE = {
-- @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.
-- @field #boolean TransmitOnlyWithPlayers If true, only transmit if there are alive Players.
-- @field Core.Set#SET_CLIENT PlayerSet PlayerSet created when TransmitOnlyWithPlayers == true
--- Create a new MSRSQUEUE object for a given radio frequency/modulation.
-- @param #MSRSQUEUE self
@@ -940,6 +972,23 @@ function MSRSQUEUE:AddTransmission(transmission)
return self
end
--- Switch to only transmit if there are players on the server.
-- @param #MSRSQUEUE self
-- @param #boolean Switch If true, only send SRS if there are alive Players.
-- @return #MSRSQUEUE self
function MSRSQUEUE:SetTransmitOnlyWithPlayers(Switch)
self.TransmitOnlyWithPlayers = Switch
if Switch == false or Switch==nil then
if self.PlayerSet then
self.PlayerSet:FilterStop()
end
self.PlayerSet = nil
else
self.PlayerSet = SET_CLIENT:New():FilterStart()
end
return self
end
--- Create a new transmission and add it to the radio queue.
-- @param #MSRSQUEUE self
-- @param #string text Text to play.
@@ -954,7 +1003,13 @@ end
-- @param #number modulation Radio modulation if other then MSRS default.
-- @return #MSRSQUEUE.Transmission Radio transmission table.
function MSRSQUEUE:NewTransmission(text, duration, msrs, tstart, interval, subgroups, subtitle, subduration, frequency, modulation)
if self.TransmitOnlyWithPlayers then
if self.PlayerSet and self.PlayerSet:CountAlive() == 0 then
return self
end
end
-- Sanity checks.
if not text then
self:E(self.lid.."ERROR: No text specified.")

View File

@@ -1,4 +1,4 @@
--- **Tasking** -- A command center governs multiple missions, and takes care of the reporting and communications.
--- **Tasking** - A command center governs multiple missions, and takes care of the reporting and communications.
--
-- **Features:**
--
@@ -512,7 +512,7 @@ function COMMANDCENTER:AssignTask( TaskGroup )
if Task then
self:I( "Assigning task " .. Task:GetName() .. " using auto assign method " .. self.AutoAssignMethod .. " to " .. TaskGroup:GetName() .. " with task priority " .. AssignPriority )
self:T( "Assigning task " .. Task:GetName() .. " using auto assign method " .. self.AutoAssignMethod .. " to " .. TaskGroup:GetName() .. " with task priority " .. AssignPriority )
if not self.AutoAcceptTasks == true then
Task:SetAutoAssignMethod( ACT_ASSIGN_MENU_ACCEPT:New( Task.TaskBriefing ) )

View File

@@ -342,7 +342,7 @@ do -- DETECTION_REPORTING
return self
end
--- Creates a string of the detected items in a @{Detection}.
--- Creates a string of the detected items in a @{Functional.Detection} object.
-- @param #DETECTION_MANAGER self
-- @param Core.Set#SET_UNIT DetectedSet The detected Set created by the @{Functional.Detection#DETECTION_BASE} object.
-- @return #DETECTION_MANAGER self

View File

@@ -1,4 +1,4 @@
--- **Tasking** -- A mission models a goal to be achieved through the execution and completion of tasks by human players.
--- **Tasking** - A mission models a goal to be achieved through the execution and completion of tasks by human players.
--
-- **Features:**
--
@@ -86,7 +86,7 @@
-- - @{#MISSION.GetTasks}(): Retrieves a list of the tasks controlled by the mission.
-- - @{#MISSION.GetTask}(): Retrieves a specific task controlled by the mission.
-- - @{#MISSION.GetTasksRemaining}(): Retrieve a list of the tasks that aren't finished or failed, and are governed by the mission.
-- - @{#MISSION.GetGroupTasks}(): Retrieve a list of the tasks that can be asigned to a @{Wrapper.Group}.
-- - @{#MISSION.GetGroupTasks}(): Retrieve a list of the tasks that can be assigned to a @{Wrapper.Group}.
-- - @{#MISSION.GetTaskTypes}(): Retrieve a list of the different task types governed by the mission.
--
-- ### 3.3. Get the command center.
@@ -131,7 +131,7 @@ MISSION = {
-- @param Tasking.CommandCenter#COMMANDCENTER CommandCenter
-- @param #string MissionName Name of the mission. This name will be used to reference the status of each mission by the players.
-- @param #string MissionPriority String indicating the "priority" of the Mission. e.g. "Primary", "Secondary". It is free format and up to the Mission designer to choose. There are no rules behind this field.
-- @param #string MissionBriefing String indicating the mission briefing to be shown when a player joins a @{CLIENT}.
-- @param #string MissionBriefing String indicating the mission briefing to be shown when a player joins a @{Wrapper.Client#CLIENT}.
-- @param DCS#coalition.side MissionCoalition Side of the coalition, i.e. and enumerator @{#DCS.coalition.side} corresponding to RED, BLUE or NEUTRAL.
-- @return #MISSION self
function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefing, MissionCoalition )
@@ -413,7 +413,7 @@ end
-- @param Wrapper.Group#GROUP PlayerGroup The GROUP of the player joining the Mission.
-- @return #boolean true if Unit is part of a Task in the Mission.
function MISSION:JoinUnit( PlayerUnit, PlayerGroup )
self:I( { Mission = self:GetName(), PlayerUnit = PlayerUnit, PlayerGroup = PlayerGroup } )
self:T( { Mission = self:GetName(), PlayerUnit = PlayerUnit, PlayerGroup = PlayerGroup } )
local PlayerUnitAdded = false
@@ -543,7 +543,7 @@ end
do -- Group Assignment
--- Returns if the @{Mission} is assigned to the Group.
--- Returns if the @{Tasking.Mission} is assigned to the Group.
-- @param #MISSION self
-- @param Wrapper.Group#GROUP MissionGroup
-- @return #boolean
@@ -561,7 +561,7 @@ do -- Group Assignment
end
--- Set @{Wrapper.Group} assigned to the @{Mission}.
--- Set @{Wrapper.Group} assigned to the @{Tasking.Mission}.
-- @param #MISSION self
-- @param Wrapper.Group#GROUP MissionGroup
-- @return #MISSION
@@ -571,12 +571,12 @@ do -- Group Assignment
local MissionGroupName = MissionGroup:GetName()
self.AssignedGroups[MissionGroupName] = MissionGroup
self:I( string.format( "Mission %s is assigned to %s", MissionName, MissionGroupName ) )
self:T( string.format( "Mission %s is assigned to %s", MissionName, MissionGroupName ) )
return self
end
--- Clear the @{Wrapper.Group} assignment from the @{Mission}.
--- Clear the @{Wrapper.Group} assignment from the @{Tasking.Mission}.
-- @param #MISSION self
-- @param Wrapper.Group#GROUP MissionGroup
-- @return #MISSION
@@ -667,7 +667,7 @@ end
--- Get the TASK identified by the TaskNumber from the Mission. This function is useful in GoalFunctions.
-- @param #string TaskName The Name of the @{Task} within the @{Mission}.
-- @param #string TaskName The Name of the @{Tasking.Task} within the @{Tasking.Mission}.
-- @return Tasking.Task#TASK The Task
-- @return #nil Returns nil if no task was found.
function MISSION:GetTask( TaskName )
@@ -677,9 +677,9 @@ function MISSION:GetTask( TaskName )
end
--- Return the next @{Task} ID to be completed within the @{Mission}.
--- Return the next @{Tasking.Task} ID to be completed within the @{Tasking.Mission}.
-- @param #MISSION self
-- @param Tasking.Task#TASK Task is the @{Task} object.
-- @param Tasking.Task#TASK Task is the @{Tasking.Task} object.
-- @return Tasking.Task#TASK The task added.
function MISSION:GetNextTaskID( Task )
@@ -689,16 +689,16 @@ function MISSION:GetNextTaskID( Task )
end
--- Register a @{Task} to be completed within the @{Mission}.
-- Note that there can be multiple @{Task}s registered to be completed.
--- Register a @{Tasking.Task} to be completed within the @{Tasking.Mission}.
-- Note that there can be multiple @{Tasking.Task}s registered to be completed.
-- Each Task can be set a certain Goals. The Mission will not be completed until all Goals are reached.
-- @param #MISSION self
-- @param Tasking.Task#TASK Task is the @{Task} object.
-- @param Tasking.Task#TASK Task is the @{Tasking.Task} object.
-- @return Tasking.Task#TASK The task added.
function MISSION:AddTask( Task )
local TaskName = Task:GetTaskName()
self:I( { "==> Adding TASK ", MissionName = self:GetName(), TaskName = TaskName } )
self:T( { "==> Adding TASK ", MissionName = self:GetName(), TaskName = TaskName } )
self.Tasks[TaskName] = Task
@@ -708,16 +708,16 @@ function MISSION:AddTask( Task )
end
--- Removes a @{Task} to be completed within the @{Mission}.
-- Note that there can be multiple @{Task}s registered to be completed.
--- Removes a @{Tasking.Task} to be completed within the @{Tasking.Mission}.
-- Note that there can be multiple @{Tasking.Task}s registered to be completed.
-- Each Task can be set a certain Goals. The Mission will not be completed until all Goals are reached.
-- @param #MISSION self
-- @param Tasking.Task#TASK Task is the @{Task} object.
-- @param Tasking.Task#TASK Task is the @{Tasking.Task} object.
-- @return #nil The cleaned Task reference.
function MISSION:RemoveTask( Task )
local TaskName = Task:GetTaskName()
self:I( { "<== Removing TASK ", MissionName = self:GetName(), TaskName = TaskName } )
self:T( { "<== Removing TASK ", MissionName = self:GetName(), TaskName = TaskName } )
self:F( TaskName )
self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 }
@@ -733,35 +733,35 @@ function MISSION:RemoveTask( Task )
return nil
end
--- Is the @{Mission} **COMPLETED**.
--- Is the @{Tasking.Mission} **COMPLETED**.
-- @param #MISSION self
-- @return #boolean
function MISSION:IsCOMPLETED()
return self:Is( "COMPLETED" )
end
--- Is the @{Mission} **IDLE**.
--- Is the @{Tasking.Mission} **IDLE**.
-- @param #MISSION self
-- @return #boolean
function MISSION:IsIDLE()
return self:Is( "IDLE" )
end
--- Is the @{Mission} **ENGAGED**.
--- Is the @{Tasking.Mission} **ENGAGED**.
-- @param #MISSION self
-- @return #boolean
function MISSION:IsENGAGED()
return self:Is( "ENGAGED" )
end
--- Is the @{Mission} **FAILED**.
--- Is the @{Tasking.Mission} **FAILED**.
-- @param #MISSION self
-- @return #boolean
function MISSION:IsFAILED()
return self:Is( "FAILED" )
end
--- Is the @{Mission} **HOLD**.
--- Is the @{Tasking.Mission} **HOLD**.
-- @param #MISSION self
-- @return #boolean
function MISSION:IsHOLD()
@@ -1105,7 +1105,7 @@ function MISSION:ReportDetails( ReportGroup )
end
--- Get all the TASKs from the Mission. This function is useful in GoalFunctions.
-- @return {TASK,...} Structure of TASKS with the @{TASK} number as the key.
-- @return {TASK,...} Structure of TASKS with the @{Tasking.Task#TASK} number as the key.
-- @usage
-- -- Get Tasks from the Mission.
-- Tasks = Mission:GetTasks()

View File

@@ -1,4 +1,4 @@
--- **Tasking** -- A task object governs the main engine to administer human taskings.
--- **Tasking** - A task object governs the main engine to administer human taskings.
--
-- **Features:**
--
@@ -38,7 +38,7 @@
--
-- A mission can be in a specific state during the simulation run. For more information about these states, please check the @{Tasking.Mission} section.
--
-- To achieve the mission goal, a mission administers @{Tasking.Task}s that are set to achieve the mission goal by the human players.
-- To achieve the mission goal, a mission administers @{#TASK}s that are set to achieve the mission goal by the human players.
-- Each of these tasks can be **dynamically created** using a task dispatcher, or **coded** by the mission designer.
-- Each mission has a separate **Mission Menu**, that focuses on the administration of these tasks.
--
@@ -143,7 +143,7 @@
--
-- ![Command Center](../Tasking/Menu_CommandCenter.JPG)
--
-- When we take back the command center menu, you see two addtional **Assign Task** menu items.
-- When we take back the command center menu, you see two additional **Assign Task** menu items.
-- The menu **Assign Task On** will automatically allocate a task to the player.
-- After the selection of this menu, the menu will change into **Assign Task Off**,
-- and will need to be selected again by the player to switch of the automatic task assignment.
@@ -190,7 +190,7 @@
--
-- The state completion is by default set to **Success**, if the goals of the task have been reached, but can be overruled by a goal method.
--
-- Depending on the tactical situation, a task can be **Cancelled** by the mission governer.
-- Depending on the tactical situation, a task can be **Cancelled** by the mission governor.
-- It is actually the mission designer who has the flexibility to decide at which conditions a task would be set to **Success**, **Failed** or **Cancelled**.
-- This decision all depends on the task goals, and the phase/evolution of the task conditions that would accomplish the goals.
--
@@ -199,16 +199,16 @@
-- However, it could very well be also acceptable that the task would be flagged as **Success**.
--
-- The tasking mechanism governs beside the progress also a scoring mechanism, and in case of goal completion without any active pilot involved
-- in the execution of the task, could result in a **Success** task completion status, but no score would be awared, as there were no players involved.
-- in the execution of the task, could result in a **Success** task completion status, but no score would be awarded, as there were no players involved.
--
-- These different completion states are important for the mission designer to reflect scoring to a player.
-- A success could mean a positive score to be given, while a failure could mean a negative score or penalties to be awarded.
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Author(s): **FlightControl**
--
-- ### Contributions:
-- ### Contribution(s):
--
-- ===
--
@@ -262,8 +262,8 @@
--
-- ## 1.3) Cargo Tasks
--
-- - @{Tasking.Task_Cargo#TASK_CARGO_TRANSPORT} - Models the transportation of cargo to deployment zones.
-- - @{Tasking.Task_Cargo#TASK_CARGO_CSAR} - Models the rescue of downed friendly pilots from behind enemy lines.
-- - @{Tasking.Task_CARGO#TASK_CARGO_TRANSPORT} - Models the transportation of cargo to deployment zones.
-- - @{Tasking.Task_CARGO#TASK_CARGO_CSAR} - Models the rescue of downed friendly pilots from behind enemy lines.
--
--
-- # 2) Task status events.
@@ -293,7 +293,7 @@
--
-- function Task:OnAfterGoal()
-- if condition == true then
-- self:Success() -- This will flag the task to Succcess when the condition is true.
-- self:Success() -- This will flag the task to Success when the condition is true.
-- else
-- if condition2 == true and condition3 == true then
-- self:Fail() -- This will flag the task to Failed, when condition2 and condition3 would be true.
@@ -732,7 +732,7 @@ end
do -- Group Assignment
--- Returns if the @{Task} is assigned to the Group.
--- Returns if the @{#TASK} is assigned to the Group.
-- @param #TASK self
-- @param Wrapper.Group#GROUP TaskGroup
-- @return #boolean
@@ -750,7 +750,7 @@ do -- Group Assignment
end
--- Set @{Wrapper.Group} assigned to the @{Task}.
--- Set @{Wrapper.Group} assigned to the @{#TASK}.
-- @param #TASK self
-- @param Wrapper.Group#GROUP TaskGroup
-- @return #TASK
@@ -780,7 +780,7 @@ do -- Group Assignment
return self
end
--- Clear the @{Wrapper.Group} assignment from the @{Task}.
--- Clear the @{Wrapper.Group} assignment from the @{#TASK}.
-- @param #TASK self
-- @param Wrapper.Group#GROUP TaskGroup
-- @return #TASK
@@ -824,7 +824,7 @@ do -- Group Assignment
end
--- Assign the @{Task} to a @{Wrapper.Group}.
--- Assign the @{#TASK} to a @{Wrapper.Group}.
-- @param #TASK self
-- @param Wrapper.Group#GROUP TaskGroup
-- @return #TASK
@@ -861,7 +861,7 @@ do -- Group Assignment
return self
end
--- UnAssign the @{Task} from a @{Wrapper.Group}.
--- UnAssign the @{#TASK} from a @{Wrapper.Group}.
-- @param #TASK self
-- @param Wrapper.Group#GROUP TaskGroup
function TASK:UnAssignFromGroup( TaskGroup )
@@ -899,7 +899,7 @@ function TASK:HasGroup( FindGroup )
end
--- Assign the @{Task} to an alive @{Wrapper.Unit}.
--- Assign the @{#TASK} to an alive @{Wrapper.Unit}.
-- @param #TASK self
-- @param Wrapper.Unit#UNIT TaskUnit
-- @return #TASK self
@@ -918,7 +918,7 @@ function TASK:AssignToUnit( TaskUnit )
return self
end
--- UnAssign the @{Task} from an alive @{Wrapper.Unit}.
--- UnAssign the @{#TASK} from an alive @{Wrapper.Unit}.
-- @param #TASK self
-- @param Wrapper.Unit#UNIT TaskUnit
-- @return #TASK self
@@ -932,7 +932,7 @@ function TASK:UnAssignFromUnit( TaskUnit )
return self
end
--- Sets the TimeOut for the @{Task}. If @{Task} stayed planned for longer than TimeOut, it gets into Cancelled status.
--- Sets the TimeOut for the @{#TASK}. If @{#TASK} stayed planned for longer than TimeOut, it gets into Cancelled status.
-- @param #TASK self
-- @param #integer Timer in seconds
-- @return #TASK self
@@ -943,7 +943,7 @@ function TASK:SetTimeOut ( Timer )
return self
end
--- Send a message of the @{Task} to the assigned @{Wrapper.Group}s.
--- Send a message of the @{#TASK} to the assigned @{Wrapper.Group}s.
-- @param #TASK self
function TASK:MessageToGroups( Message )
self:F( { Message = Message } )
@@ -960,7 +960,7 @@ function TASK:MessageToGroups( Message )
end
--- Send the briefng message of the @{Task} to the assigned @{Wrapper.Group}s.
--- Send the briefing message of the @{#TASK} to the assigned @{Wrapper.Group}s.
-- @param #TASK self
function TASK:SendBriefingToAssignedGroups()
self:F2()
@@ -975,7 +975,7 @@ function TASK:SendBriefingToAssignedGroups()
end
--- UnAssign the @{Task} from the @{Wrapper.Group}s.
--- UnAssign the @{#TASK} from the @{Wrapper.Group}s.
-- @param #TASK self
function TASK:UnAssignFromGroups()
self:F2()
@@ -991,7 +991,7 @@ end
--- Returns if the @{Task} has still alive and assigned Units.
--- Returns if the @{#TASK} has still alive and assigned Units.
-- @param #TASK self
-- @return #boolean
function TASK:HasAliveUnits()
@@ -1016,7 +1016,7 @@ function TASK:HasAliveUnits()
return false
end
--- Set the menu options of the @{Task} to all the groups in the SetGroup.
--- Set the menu options of the @{#TASK} to all the groups in the SetGroup.
-- @param #TASK self
-- @param #number MenuTime
-- @return #TASK
@@ -1057,7 +1057,7 @@ function TASK:SetMenuForGroup( TaskGroup, MenuTime )
end
--- Set the planned menu option of the @{Task}.
--- Set the planned menu option of the @{#TASK}.
-- @param #TASK self
-- @param Wrapper.Group#GROUP TaskGroup
-- @param #string MenuText The menu text.
@@ -1092,7 +1092,7 @@ function TASK:SetPlannedMenuForGroup( TaskGroup, MenuTime )
return self
end
--- Set the assigned menu options of the @{Task}.
--- Set the assigned menu options of the @{#TASK}.
-- @param #TASK self
-- @param Wrapper.Group#GROUP TaskGroup
-- @param #number MenuTime
@@ -1127,7 +1127,7 @@ function TASK:SetAssignedMenuForGroup( TaskGroup, MenuTime )
return self
end
--- Remove the menu options of the @{Task} to all the groups in the SetGroup.
--- Remove the menu options of the @{#TASK} to all the groups in the SetGroup.
-- @param #TASK self
-- @param #number MenuTime
-- @return #TASK
@@ -1145,7 +1145,7 @@ function TASK:RemoveMenu( MenuTime )
end
--- Remove the menu option of the @{Task} for a @{Wrapper.Group}.
--- Remove the menu option of the @{#TASK} for a @{Wrapper.Group}.
-- @param #TASK self
-- @param Wrapper.Group#GROUP TaskGroup
-- @param #number MenuTime
@@ -1176,7 +1176,7 @@ function TASK:RefreshMenus( TaskGroup, MenuTime )
end
--- Remove the assigned menu option of the @{Task} for a @{Wrapper.Group}.
--- Remove the assigned menu option of the @{#TASK} for a @{Wrapper.Group}.
-- @param #TASK self
-- @param Wrapper.Group#GROUP TaskGroup
-- @param #number MenuTime
@@ -1275,14 +1275,14 @@ end
--- Returns the @{Task} name.
--- Returns the @{#TASK} name.
-- @param #TASK self
-- @return #string TaskName
function TASK:GetTaskName()
return self.TaskName
end
--- Returns the @{Task} briefing.
--- Returns the @{#TASK} briefing.
-- @param #TASK self
-- @return #string Task briefing.
function TASK:GetTaskBriefing()
@@ -1292,7 +1292,7 @@ end
--- Get the default or currently assigned @{Process} template with key ProcessName.
--- Get the default or currently assigned @{Core.Fsm#FSM_PROCESS} template with key ProcessName.
-- @param #TASK self
-- @param #string ProcessName
-- @return Core.Fsm#FSM_PROCESS
@@ -1305,8 +1305,8 @@ end
-- TODO: Obscolete?
--- Fail processes from @{Task} with key @{Wrapper.Unit}
-- TODO: Obsolete?
--- Fail processes from @{#TASK} with key @{Wrapper.Unit}.
-- @param #TASK self
-- @param #string TaskUnitName
-- @return #TASK self
@@ -1318,7 +1318,7 @@ function TASK:FailProcesses( TaskUnitName )
end
end
--- Add a FiniteStateMachine to @{Task} with key Task@{Wrapper.Unit}
--- Add a FiniteStateMachine to @{#TASK} with key @{Wrapper.Unit}.
-- @param #TASK self
-- @param Wrapper.Unit#UNIT TaskUnit
-- @param Core.Fsm#FSM_PROCESS Fsm
@@ -1331,7 +1331,7 @@ function TASK:SetStateMachine( TaskUnit, Fsm )
return Fsm
end
--- Gets the FiniteStateMachine of @{Task} with key Task@{Wrapper.Unit}
--- Gets the FiniteStateMachine of @{#TASK} with key @{Wrapper.Unit}.
-- @param #TASK self
-- @param Wrapper.Unit#UNIT TaskUnit
-- @return Core.Fsm#FSM_PROCESS
@@ -1341,7 +1341,7 @@ function TASK:GetStateMachine( TaskUnit )
return self.Fsm[TaskUnit]
end
--- Remove FiniteStateMachines from @{Task} with key Task@{Wrapper.Unit}
--- Remove FiniteStateMachines from @{#TASK} with key @{Wrapper.Unit}.
-- @param #TASK self
-- @param Wrapper.Unit#UNIT TaskUnit
-- @return #TASK self
@@ -1365,7 +1365,7 @@ function TASK:RemoveStateMachine( TaskUnit )
end
--- Checks if there is a FiniteStateMachine assigned to Task@{Wrapper.Unit} for @{Task}
--- Checks if there is a FiniteStateMachine assigned to @{Wrapper.Unit} for @{#TASK}.
-- @param #TASK self
-- @param Wrapper.Unit#UNIT TaskUnit
-- @return #TASK self
@@ -1438,117 +1438,117 @@ function TASK:GetID()
end
--- Sets a @{Task} to status **Success**.
--- Sets a @{#TASK} to status **Success**.
-- @param #TASK self
function TASK:StateSuccess()
self:SetState( self, "State", "Success" )
return self
end
--- Is the @{Task} status **Success**.
--- Is the @{#TASK} status **Success**.
-- @param #TASK self
function TASK:IsStateSuccess()
return self:Is( "Success" )
end
--- Sets a @{Task} to status **Failed**.
--- Sets a @{#TASK} to status **Failed**.
-- @param #TASK self
function TASK:StateFailed()
self:SetState( self, "State", "Failed" )
return self
end
--- Is the @{Task} status **Failed**.
--- Is the @{#TASK} status **Failed**.
-- @param #TASK self
function TASK:IsStateFailed()
return self:Is( "Failed" )
end
--- Sets a @{Task} to status **Planned**.
--- Sets a @{#TASK} to status **Planned**.
-- @param #TASK self
function TASK:StatePlanned()
self:SetState( self, "State", "Planned" )
return self
end
--- Is the @{Task} status **Planned**.
--- Is the @{#TASK} status **Planned**.
-- @param #TASK self
function TASK:IsStatePlanned()
return self:Is( "Planned" )
end
--- Sets a @{Task} to status **Aborted**.
--- Sets a @{#TASK} to status **Aborted**.
-- @param #TASK self
function TASK:StateAborted()
self:SetState( self, "State", "Aborted" )
return self
end
--- Is the @{Task} status **Aborted**.
--- Is the @{#TASK} status **Aborted**.
-- @param #TASK self
function TASK:IsStateAborted()
return self:Is( "Aborted" )
end
--- Sets a @{Task} to status **Cancelled**.
--- Sets a @{#TASK} to status **Cancelled**.
-- @param #TASK self
function TASK:StateCancelled()
self:SetState( self, "State", "Cancelled" )
return self
end
--- Is the @{Task} status **Cancelled**.
--- Is the @{#TASK} status **Cancelled**.
-- @param #TASK self
function TASK:IsStateCancelled()
return self:Is( "Cancelled" )
end
--- Sets a @{Task} to status **Assigned**.
--- Sets a @{#TASK} to status **Assigned**.
-- @param #TASK self
function TASK:StateAssigned()
self:SetState( self, "State", "Assigned" )
return self
end
--- Is the @{Task} status **Assigned**.
--- Is the @{#TASK} status **Assigned**.
-- @param #TASK self
function TASK:IsStateAssigned()
return self:Is( "Assigned" )
end
--- Sets a @{Task} to status **Hold**.
--- Sets a @{#TASK} to status **Hold**.
-- @param #TASK self
function TASK:StateHold()
self:SetState( self, "State", "Hold" )
return self
end
--- Is the @{Task} status **Hold**.
--- Is the @{#TASK} status **Hold**.
-- @param #TASK self
function TASK:IsStateHold()
return self:Is( "Hold" )
end
--- Sets a @{Task} to status **Replanned**.
--- Sets a @{#TASK} to status **Replanned**.
-- @param #TASK self
function TASK:StateReplanned()
self:SetState( self, "State", "Replanned" )
return self
end
--- Is the @{Task} status **Replanned**.
--- Is the @{#TASK} status **Replanned**.
-- @param #TASK self
function TASK:IsStateReplanned()
return self:Is( "Replanned" )
end
--- Gets the @{Task} status.
--- Gets the @{#TASK} status.
-- @param #TASK self
function TASK:GetStateString()
return self:GetState( self, "State" )
end
--- Sets a @{Task} briefing.
--- Sets a @{#TASK} briefing.
-- @param #TASK self
-- @param #string TaskBriefing
-- @return #TASK self
@@ -1558,7 +1558,7 @@ function TASK:SetBriefing( TaskBriefing )
return self
end
--- Gets the @{Task} briefing.
--- Gets the @{#TASK} briefing.
-- @param #TASK self
-- @return #string The briefing text.
function TASK:GetBriefing()

View File

@@ -1,4 +1,4 @@
--- **Tasking** -- Controls the information of a Task.
--- **Tasking** - Controls the information of a Task.
--
-- ===
--

View File

@@ -18,7 +18,7 @@ do -- TASK_A2A
-- @field Core.Set#SET_UNIT TargetSetUnit
-- @extends Tasking.Task#TASK
--- Defines Air To Air tasks for a @{Set} of Target Units,
--- Defines Air To Air tasks for a @{Core.Set} of Target Units,
-- based on the tasking capabilities defined in @{Tasking.Task#TASK}.
-- The TASK_A2A is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses:
--

View File

@@ -29,11 +29,11 @@ do -- TASK_A2A_DISPATCHER
-- @type TASK_A2A_DISPATCHER
-- @extends Tasking.DetectionManager#DETECTION_MANAGER
--- Orchestrates the dynamic dispatching of tasks upon groups of detected units determined a @{Set} of EWR installation groups.
--- Orchestrates the dynamic dispatching of tasks upon groups of detected units determined a @{Core.Set} of EWR installation groups.
--
-- ![Banner Image](..\Presentations\TASK_A2A_DISPATCHER\Dia3.JPG)
--
-- The EWR will detect units, will group them, and will dispatch @{Task}s to groups. Depending on the type of target detected, different tasks will be dispatched.
-- The EWR will detect units, will group them, and will dispatch @{Tasking.Task}s to groups. Depending on the type of target detected, different tasks will be dispatched.
-- Find a summary below describing for which situation a task type is created:
--
-- ![Banner Image](..\Presentations\TASK_A2A_DISPATCHER\Dia9.JPG)
@@ -140,7 +140,7 @@ do -- TASK_A2A_DISPATCHER
--
-- ## 4. Set **Scoring** and **Messages**:
--
-- The TASK\_A2A\_DISPATCHER is a state machine. It triggers the event Assign when a new player joins a @{Task} dispatched by the TASK\_A2A\_DISPATCHER.
-- The TASK\_A2A\_DISPATCHER is a state machine. It triggers the event Assign when a new player joins a @{Tasking.Task} dispatched by the TASK\_A2A\_DISPATCHER.
-- An _event handler_ can be defined to catch the **Assign** event, and add **additional processing** to set _scoring_ and to _define messages_,
-- when the player reaches certain achievements in the task.
--

View File

@@ -18,7 +18,7 @@ do -- TASK_A2G
-- @field Core.Set#SET_UNIT TargetSetUnit
-- @extends Tasking.Task#TASK
--- The TASK_A2G class defines Air To Ground tasks for a @{Set} of Target Units,
--- The TASK_A2G class defines Air To Ground tasks for a @{Core.Set} of Target Units,
-- based on the tasking capabilities defined in @{Tasking.Task#TASK}.
-- The TASK_A2G is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses:
--

View File

@@ -1,4 +1,4 @@
--- **Tasking** -- Dynamically allocates A2G tasks to human players, based on detected ground targets through reconnaissance.
--- **Tasking** - Dynamically allocates A2G tasks to human players, based on detected ground targets through reconnaissance.
--
-- **Features:**
--
@@ -32,17 +32,17 @@ do -- TASK_A2G_DISPATCHER
-- @field Tasking.Mission#MISSION Mission
-- @extends Tasking.DetectionManager#DETECTION_MANAGER
--- Orchestrates dynamic **A2G Task Dispatching** based on the detection results of a linked @{Detection} object.
--- Orchestrates dynamic **A2G Task Dispatching** based on the detection results of a linked @{Functional.Detection} object.
--
-- It uses the Tasking System within the MOOSE framework, which is a multi-player Tasking Orchestration system.
-- It provides a truly dynamic battle environment for pilots and ground commanders to engage upon,
-- in a true co-operation environment wherein **Multiple Teams** will collaborate in Missions to **achieve a common Mission Goal**.
--
-- The A2G dispatcher will dispatch the A2G Tasks to a defined @{Set} of @{Wrapper.Group}s that will be manned by **Players**.
-- We call this the **AttackSet** of the A2G dispatcher. So, the Players are seated in the @{Client}s of the @{Wrapper.Group} @{Set}.
-- The A2G dispatcher will dispatch the A2G Tasks to a defined @{Core.Set} of @{Wrapper.Group}s that will be manned by **Players**.
-- We call this the **AttackSet** of the A2G dispatcher. So, the Players are seated in the @{Wrapper.Client}s of the @{Wrapper.Group} @{Core.Set}.
--
-- Depending on the actions of the enemy, preventive tasks are dispatched to the players to orchestrate the engagement in a true co-operation.
-- The detection object will group the detected targets by its grouping method, and integrates a @{Set} of @{Wrapper.Group}s that are Recce vehicles or air units.
-- The detection object will group the detected targets by its grouping method, and integrates a @{Core.Set} of @{Wrapper.Group}s that are Recce vehicles or air units.
-- We call this the **RecceSet** of the A2G dispatcher.
--
-- Depending on the current detected tactical situation, different task types will be dispatched to the Players seated in the AttackSet..
@@ -108,7 +108,7 @@ do -- TASK_A2G_DISPATCHER
--
-- # 1. Player Experience
--
-- The A2G dispatcher is residing under a @{CommandCenter}, which is orchestrating a @{Mission}.
-- The A2G dispatcher is residing under a @{Tasking.CommandCenter}, which is orchestrating a @{Tasking.Mission}.
-- As a result, you'll find for DCS World missions that implement the A2G dispatcher a **Command Center Menu** and under this one or more **Mission Menus**.
--
-- For example, if there are 2 Command Centers (CC).
@@ -367,7 +367,7 @@ do -- TASK_A2G_DISPATCHER
--
-- ![](..\Presentations\TASK_A2G_DISPATCHER\Dia7.JPG)
--
-- The @{Settings} menu provides additional options to control the timing of the messages.
-- The @{Core.Settings} menu provides additional options to control the timing of the messages.
-- There are:
--
-- - Status messages, which are quick status updates. The settings menu allows to switch off these messages.
@@ -384,12 +384,12 @@ do -- TASK_A2G_DISPATCHER
--
-- To use the TASK\_A2G\_DISPATCHER class, you need:
--
-- - A @{CommandCenter} object. The master communication channel.
-- - A @{Mission} object. Each task belongs to a Mission.
-- - A @{Detection} object. There are several detection grouping methods to choose from.
-- - A @{Task_A2G_Dispatcher} object. The master A2G task dispatcher.
-- - A @{Set} of @{Wrapper.Group} objects that will detect the enemy, the RecceSet. This is attached to the @{Detection} object.
-- - A @{Set} ob @{Wrapper.Group} objects that will attack the enemy, the AttackSet. This is attached to the @{Task_A2G_Dispatcher} object.
-- - A @{Tasking.CommandCenter} object. The master communication channel.
-- - A @{Tasking.Mission} object. Each task belongs to a Mission.
-- - A @{Functional.Detection} object. There are several detection grouping methods to choose from.
-- - A @{Tasking.Task_A2G_Dispatcher} object. The master A2G task dispatcher.
-- - A @{Core.Set} of @{Wrapper.Group} objects that will detect the enemy, the RecceSet. This is attached to the @{Functional.Detection} object.
-- - A @{Core.Set} of @{Wrapper.Group} objects that will attack the enemy, the AttackSet. This is attached to the @{Tasking.Task_A2G_Dispatcher} object.
--
-- Below an example mission declaration that is defines a Task A2G Dispatcher object.
--

View File

@@ -1,11 +1,11 @@
--- **Tasking** -- Base class to model tasks for players to transport cargo.
--- **Tasking** - Base class to model tasks for players to transport cargo.
--
-- ## Features:
--
-- * TASK_CARGO is the **base class** for:
--
-- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_TRANSPORT}
-- * @{Tasking.Task_Cargo_CSAR#TASK_CARGO_CSAR}
-- * @{Tasking.Task_CARGO_CSAR#TASK_CARGO_CSAR}
--
--
-- ===
@@ -34,7 +34,7 @@
-- The following TASK_CARGO_ classes are important, as they implement the CONCRETE tasks:
--
-- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_TRANSPORT}: Defines a task for a human player to transport a set of cargo between various zones.
-- * @{Tasking.Task_Cargo_CSAR#TASK_CARGO_CSAR}: Defines a task for a human player to Search and Rescue wounded pilots.
-- * @{Tasking.Task_CARGO_CSAR#TASK_CARGO_CSAR}: Defines a task for a human player to Search and Rescue wounded pilots.
--
-- However! The menu system and basic usage of the TASK_CARGO classes is explained in the @{#TASK_CARGO} class description.
-- So please browse further below to understand how to use it from a player perspective!
@@ -387,9 +387,9 @@
--
-- Please consult the documentation how to implement the derived classes of SET_CARGO in:
--
-- - @{Tasking.Task_Cargo#TASK_CARGO}: Documents the main methods how to handle the cargo tasking from a mission designer perspective.
-- - @{Tasking.Task_Cargo#TASK_CARGO_TRANSPORT}: Documents the specific methods how to handle the cargo transportation tasking from a mission designer perspective.
-- - @{Tasking.Task_Cargo#TASK_CARGO_CSAR}: Documents the specific methods how to handle the cargo CSAR tasking from a mission designer perspective.
-- - @{Tasking.Task_CARGO#TASK_CARGO}: Documents the main methods how to handle the cargo tasking from a mission designer perspective.
-- - @{Tasking.Task_CARGO#TASK_CARGO_TRANSPORT}: Documents the specific methods how to handle the cargo transportation tasking from a mission designer perspective.
-- - @{Tasking.Task_CARGO#TASK_CARGO_CSAR}: Documents the specific methods how to handle the cargo CSAR tasking from a mission designer perspective.
--
--
-- ===
@@ -400,7 +400,7 @@
--
-- ===
--
-- @module Tasking.Task_Cargo
-- @module Tasking.Task_CARGO
-- @image MOOSE.JPG
do -- TASK_CARGO
@@ -438,8 +438,8 @@ do -- TASK_CARGO
--
-- ### 2.1.1) Cargo Tasks
--
-- - @{Tasking.Task_Cargo#TASK_CARGO_TRANSPORT} - Models the transportation of cargo to deployment zones.
-- - @{Tasking.Task_Cargo#TASK_CARGO_CSAR} - Models the rescue of downed friendly pilots from behind enemy lines.
-- - @{Tasking.Task_CARGO#TASK_CARGO_TRANSPORT} - Models the transportation of cargo to deployment zones.
-- - @{Tasking.Task_CARGO#TASK_CARGO_CSAR} - Models the rescue of downed friendly pilots from behind enemy lines.
--
-- ## 2.2) Handle TASK_CARGO Events ...
--

View File

@@ -54,7 +54,7 @@
--
-- ===
--
-- @module Tasking.Task_Zone_Capture_Dispatcher
-- @module Tasking.Task_Capture_Dispatcher
-- @image MOOSE.JPG
do -- TASK_CAPTURE_DISPATCHER

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