Compare commits

...

84 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
33 changed files with 3061 additions and 727 deletions
@@ -3940,11 +3940,7 @@ do
-- --
-- # Demo Missions -- # 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) -- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching)
-- ### [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)
-- --
-- === -- ===
-- --
+187 -18
View File
@@ -23,11 +23,15 @@
-- @type CONDITION -- @type CONDITION
-- @field #string ClassName Name of the class. -- @field #string ClassName Name of the class.
-- @field #string lid Class id string for output to DCS log file. -- @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 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 functionsGen General condition functions.
-- @field #table functionsAny Any condition functions. -- @field #table functionsAny Any condition functions.
-- @field #table functionsAll All 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 -- @extends Core.Base#BASE
@@ -46,22 +50,29 @@ CONDITION = {
functionsGen = {}, functionsGen = {},
functionsAny = {}, functionsAny = {},
functionsAll = {}, functionsAll = {},
functionCounter = 0,
defaultPersist = false,
} }
--- Condition function. --- Condition function.
-- @type 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. -- @field #table arg (Optional) Arguments passed to the condition callback function if any.
--- CONDITION class version. --- CONDITION class version.
-- @field #string version -- @field #string version
CONDITION.version="0.1.0" CONDITION.version="0.3.0"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- 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 -- Constructor
@@ -78,6 +89,8 @@ function CONDITION:New(Name)
self.name=Name or "Condition X" self.name=Name or "Condition X"
self:SetNoneResult(false)
self.lid=string.format("%s | ", self.name) self.lid=string.format("%s | ", self.name)
return self return self
@@ -101,6 +114,28 @@ function CONDITION:SetNegateResult(Negate)
return self return self
end 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`). --- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`).
-- @param #CONDITION self -- @param #CONDITION self
-- @param #function Function The function to call. -- @param #function Function The function to call.
@@ -113,47 +148,109 @@ end
-- --
-- myCondition:AddFunction(isAequalB, a, b) -- myCondition:AddFunction(isAequalB, a, b)
-- --
-- @return #CONDITION self -- @return #CONDITION.Function Condition function table.
function CONDITION:AddFunction(Function, ...) function CONDITION:AddFunction(Function, ...)
-- Condition function. -- Condition function.
local condition=self:_CreateCondition(Function, ...) local condition=self:_CreateCondition(0, Function, ...)
-- Add to table. -- Add to table.
table.insert(self.functionsGen, condition) table.insert(self.functionsGen, condition)
return self return condition
end end
--- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`). --- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`).
-- @param #CONDITION self -- @param #CONDITION self
-- @param #function Function The function to call. -- @param #function Function The function to call.
-- @param ... (Optional) Parameters passed to the function (if any). -- @param ... (Optional) Parameters passed to the function (if any).
-- @return #CONDITION self -- @return #CONDITION.Function Condition function table.
function CONDITION:AddFunctionAny(Function, ...) function CONDITION:AddFunctionAny(Function, ...)
-- Condition function. -- Condition function.
local condition=self:_CreateCondition(Function, ...) local condition=self:_CreateCondition(1, Function, ...)
-- Add to table. -- Add to table.
table.insert(self.functionsAny, condition) table.insert(self.functionsAny, condition)
return self return condition
end end
--- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`). --- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`).
-- @param #CONDITION self -- @param #CONDITION self
-- @param #function Function The function to call. -- @param #function Function The function to call.
-- @param ... (Optional) Parameters passed to the function (if any). -- @param ... (Optional) Parameters passed to the function (if any).
-- @return #CONDITION self -- @return #CONDITION.Function Condition function table.
function CONDITION:AddFunctionAll(Function, ...) function CONDITION:AddFunctionAll(Function, ...)
-- Condition function. -- Condition function.
local condition=self:_CreateCondition(Function, ...) local condition=self:_CreateCondition(2, Function, ...)
-- Add to table. -- Add to table.
table.insert(self.functionsAll, condition) 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 return self
end end
@@ -166,11 +263,7 @@ function CONDITION:Evaluate(AnyTrue)
-- Check if at least one function was given. -- Check if at least one function was given.
if #self.functionsAll + #self.functionsAny + #self.functionsAll == 0 then if #self.functionsAll + #self.functionsAny + #self.functionsAll == 0 then
if self.negateResult then return self.noneResult
return true
else
return false
end
end end
-- Any condition for gen. -- Any condition for gen.
@@ -206,6 +299,10 @@ function CONDITION:Evaluate(AnyTrue)
return result return result
end end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Private Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Check if all given condition are true. --- Check if all given condition are true.
-- @param #CONDITION self -- @param #CONDITION self
-- @param #table functions Functions to evaluate. -- @param #table functions Functions to evaluate.
@@ -275,13 +372,20 @@ end
--- Create conditon function object. --- Create conditon function object.
-- @param #CONDITION self -- @param #CONDITION self
-- @param #number Ftype Function type: 0=Gen, 1=All, 2=Any.
-- @param #function Function The function to call. -- @param #function Function The function to call.
-- @param ... (Optional) Parameters passed to the function (if any). -- @param ... (Optional) Parameters passed to the function (if any).
-- @return #CONDITION.Function Condition function. -- @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 local condition={} --#CONDITION.Function
condition.uid=self.functionCounter
condition.type=Ftype or 0
condition.persistence=self.defaultPersist
condition.func=Function condition.func=Function
condition.arg={} condition.arg={}
if arg then if arg then
@@ -290,6 +394,71 @@ function CONDITION:_CreateCondition(Function, ...)
return condition return condition
end 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
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+73 -6
View File
@@ -372,9 +372,58 @@ do -- Zones
end end
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 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 end -- zone
do -- Zone_Goal do -- Zone_Goal
@@ -1027,11 +1076,26 @@ function DATABASE:_RegisterAirbases()
for DCSAirbaseId, DCSAirbase in pairs(world.getAirbases()) do 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. -- 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. -- 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. -- Add and register airbase.
local airbase=self:AddAirbase( DCSAirbaseName ) local airbase=self:AddAirbase( DCSAirbaseName )
@@ -1065,20 +1129,23 @@ function DATABASE:_EventOnBirth( Event )
if Event.IniDCSUnit then 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 ) self:AddStatic( Event.IniDCSUnitName )
else else
if Event.IniObjectCategory == 1 then if Event.IniObjectCategory == Object.Category.UNIT then
-- Add unit and group to DB.
self:AddUnit( Event.IniDCSUnitName ) self:AddUnit( Event.IniDCSUnitName )
self:AddGroup( Event.IniDCSGroupName ) 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) local DCSAirbase = Airbase.getByName(Event.IniDCSUnitName)
if DCSAirbase then if DCSAirbase then
-- Add airbase if it was spawned later in the mission.
self:I(string.format("Adding airbase %s", tostring(Event.IniDCSUnitName))) self:I(string.format("Adding airbase %s", tostring(Event.IniDCSUnitName)))
self:AddAirbase(Event.IniDCSUnitName) self:AddAirbase(Event.IniDCSUnitName)
end end
@@ -1086,7 +1153,7 @@ function DATABASE:_EventOnBirth( Event )
end end
end end
if Event.IniObjectCategory == 1 then if Event.IniObjectCategory == Object.Category.UNIT then
Event.IniUnit = self:FindUnit( Event.IniDCSUnitName ) Event.IniUnit = self:FindUnit( Event.IniDCSUnitName )
Event.IniGroup = self:FindGroup( Event.IniDCSGroupName ) Event.IniGroup = self:FindGroup( Event.IniDCSGroupName )
+9 -2
View File
@@ -1166,7 +1166,6 @@ function EVENT:onEvent( Event )
--- ---
-- Scenery -- Scenery
--- ---
Event.IniDCSUnit = Event.initiator Event.IniDCSUnit = Event.initiator
Event.IniDCSUnitName = Event.IniDCSUnit:getName() Event.IniDCSUnitName = Event.IniDCSUnit:getName()
Event.IniUnitName = Event.IniDCSUnitName Event.IniUnitName = Event.IniDCSUnitName
@@ -1186,6 +1185,12 @@ function EVENT:onEvent( Event )
Event.IniCoalition = Event.IniDCSUnit:getCoalition() Event.IniCoalition = Event.IniDCSUnit:getCoalition()
Event.IniCategory = Event.IniDCSUnit:getDesc().category Event.IniCategory = Event.IniDCSUnit:getDesc().category
Event.IniTypeName = Event.IniDCSUnit:getTypeName() Event.IniTypeName = Event.IniDCSUnit:getTypeName()
-- 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
end end
@@ -1219,7 +1224,7 @@ function EVENT:onEvent( Event )
if Event.TgtObjectCategory == Object.Category.STATIC then if Event.TgtObjectCategory == Object.Category.STATIC then
-- get base data -- get base data
Event.TgtDCSUnit = Event.target 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.TgtDCSUnitName = Event.TgtDCSUnit:getName()
Event.TgtUnitName = Event.TgtDCSUnitName Event.TgtUnitName = Event.TgtDCSUnitName
Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false ) Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false )
@@ -1276,10 +1281,12 @@ function EVENT:onEvent( Event )
-- However, this is not a big thing, as the aircraft the pilot ejected from is usually long crashed before the ejected pilot touches the ground. -- However, this is not a big thing, as the aircraft the pilot ejected from is usually long crashed before the ejected pilot touches the ground.
--Event.Place=UNIT:Find(Event.place) --Event.Place=UNIT:Find(Event.place)
else else
if Event.place:isExist() and Event.place:getCategory() ~= Object.Category.SCENERY then
Event.Place=AIRBASE:Find(Event.place) Event.Place=AIRBASE:Find(Event.place)
Event.PlaceName=Event.Place:GetName() Event.PlaceName=Event.Place:GetName()
end end
end end
end
-- Mark points. -- Mark points.
if Event.idx then if Event.idx then
@@ -5,6 +5,12 @@
-- * Create an easy way to tap into markers added to the F10 map by users. -- * Create an easy way to tap into markers added to the F10 map by users.
-- * Recognize own tag and list of keywords. -- * Recognize own tag and list of keywords.
-- * Matched keywords are handed down to functions. -- * 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.
-- --
-- === -- ===
-- --
+59
View File
@@ -217,6 +217,7 @@ end
--- Sends a MESSAGE to a Group. --- Sends a MESSAGE to a Group.
-- @param #MESSAGE self -- @param #MESSAGE self
-- @param Wrapper.Group#GROUP Group to which the message is displayed. -- @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. -- @return #MESSAGE Message object.
function MESSAGE:ToGroup( Group, Settings ) function MESSAGE:ToGroup( Group, Settings )
self:F( Group.GroupName ) self:F( Group.GroupName )
@@ -241,6 +242,7 @@ end
--- Sends a MESSAGE to a Unit. --- Sends a MESSAGE to a Unit.
-- @param #MESSAGE self -- @param #MESSAGE self
-- @param Wrapper.Unit#UNIT Unit to which the message is displayed. -- @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. -- @return #MESSAGE Message object.
function MESSAGE:ToUnit( Unit, Settings ) function MESSAGE:ToUnit( Unit, Settings )
self:F( Unit.IdentifiableName ) self:F( Unit.IdentifiableName )
@@ -262,6 +264,41 @@ function MESSAGE:ToUnit( Unit, Settings )
return self return self
end 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 Core.Settings#Settings Settings (Optional) Settings for message display.
-- @return #MESSAGE Message object.
function MESSAGE:ToCountry( Country, Settings )
self:F(Country )
if Country then
if self.MessageType then
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
self.MessageCategory = "" -- self.MessageType .. ": "
end
if self.MessageDuration ~= 0 then
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
trigger.action.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
--- Sends a MESSAGE to the Blue coalition. --- Sends a MESSAGE to the Blue coalition.
-- @param #MESSAGE self -- @param #MESSAGE self
-- @return #MESSAGE -- @return #MESSAGE
@@ -386,6 +423,7 @@ end
--- Sends a MESSAGE to all players if the given Condition is true. --- Sends a MESSAGE to all players if the given Condition is true.
-- @param #MESSAGE self -- @param #MESSAGE self
-- @param #boolean Condition
-- @return #MESSAGE -- @return #MESSAGE
function MESSAGE:ToAllIf( Condition ) function MESSAGE:ToAllIf( Condition )
@@ -395,3 +433,24 @@ function MESSAGE:ToAllIf( Condition )
return self return self
end 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
+45 -2
View File
@@ -406,6 +406,42 @@ do -- COORDINATE
return self return self
end 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. --- Returns the coordinate from the latitude and longitude given in decimal degrees.
-- @param #COORDINATE self -- @param #COORDINATE self
@@ -504,7 +540,7 @@ do -- COORDINATE
local gotscenery=false local gotscenery=false
local function EvaluateZone(ZoneObject) local function EvaluateZone(ZoneObject)
BASE:T({ZoneObject})
if ZoneObject then if ZoneObject then
-- Get category of scanned object. -- Get category of scanned object.
@@ -1286,6 +1322,14 @@ do -- COORDINATE
return self return self
end 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. --- Build an air type route point.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @param #COORDINATE.WaypointAltType AltType The altitude type. -- @param #COORDINATE.WaypointAltType AltType The altitude type.
@@ -1911,7 +1955,6 @@ do -- COORDINATE
-- @param #COORDINATE self -- @param #COORDINATE self
-- @param #string name (Optional) Name of the fire to stop it, if not using the same COORDINATE object. -- @param #string name (Optional) Name of the fire to stop it, if not using the same COORDINATE object.
function COORDINATE:StopBigSmokeAndFire( name ) function COORDINATE:StopBigSmokeAndFire( name )
self:F2( { name = name } )
name = name or self.firename name = name or self.firename
trigger.action.effectSmokeStop( name ) trigger.action.effectSmokeStop( name )
end end
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -335,7 +335,7 @@ do -- SETTINGS
--- Sets the SETTINGS MGRS accuracy. --- Sets the SETTINGS MGRS accuracy.
-- @param #SETTINGS self -- @param #SETTINGS self
-- @param #number MGRS_Accuracy -- @param #number MGRS_Accuracy 0 to 5
-- @return #SETTINGS -- @return #SETTINGS
function SETTINGS:SetMGRS_Accuracy( MGRS_Accuracy ) function SETTINGS:SetMGRS_Accuracy( MGRS_Accuracy )
self.MGRS_Accuracy = MGRS_Accuracy self.MGRS_Accuracy = MGRS_Accuracy
+18 -11
View File
@@ -389,7 +389,7 @@ end
-- @param #SPAWN self -- @param #SPAWN self
-- @param #table SpawnTemplate is the Template of the Group. This must be a valid Group Template structure! -- @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 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 -- @return #SPAWN
-- @usage -- @usage
-- -- Create a new SPAWN object based on a Group Template defined from scratch. -- -- 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() ) local self = BASE:Inherit( self, BASE:New() )
self:F( { SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPrefix } ) self:F( { SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPrefix } )
if SpawnAliasPrefix == nil or SpawnAliasPrefix == "" then 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 return nil
end end
@@ -814,7 +814,12 @@ end
function SPAWN:InitRandomizeTemplate( SpawnTemplatePrefixTable ) function SPAWN:InitRandomizeTemplate( SpawnTemplatePrefixTable )
self:F( { self.SpawnTemplatePrefix, 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 self.SpawnRandomizeTemplate = true
for SpawnGroupID = 1, self.SpawnMaxGroups do for SpawnGroupID = 1, self.SpawnMaxGroups do
@@ -848,15 +853,11 @@ 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_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 ) -- 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:F( { self.SpawnTemplatePrefix } )
self.SpawnTemplatePrefixTable = SpawnTemplateSet:GetSetNames() local setnames = SpawnTemplateSet:GetSetNames()
self.SpawnRandomizeTemplate = true self:InitRandomizeTemplate(setnames)
for SpawnGroupID = 1, self.SpawnMaxGroups do
self:_RandomizeTemplate( SpawnGroupID )
end
return self return self
end end
@@ -922,7 +923,12 @@ end
function SPAWN:InitRandomizeZones( SpawnZoneTable ) function SPAWN:InitRandomizeZones( SpawnZoneTable )
self:F( { self.SpawnTemplatePrefix, 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 self.SpawnRandomizeZones = true
for SpawnGroupID = 1, self.SpawnMaxGroups do for SpawnGroupID = 1, self.SpawnMaxGroups do
@@ -3032,6 +3038,7 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2
if type( Callsign ) ~= "number" then -- blue callsign if type( Callsign ) ~= "number" then -- blue callsign
Callsign[2] = ((SpawnIndex - 1) % 10) + 1 Callsign[2] = ((SpawnIndex - 1) % 10) + 1
local CallsignName = SpawnTemplate.units[UnitID].callsign["name"] -- #string 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() local CallsignLen = CallsignName:len()
SpawnTemplate.units[UnitID].callsign["name"] = CallsignName:sub( 1, CallsignLen ) .. SpawnTemplate.units[UnitID].callsign[2] .. SpawnTemplate.units[UnitID].callsign[3] SpawnTemplate.units[UnitID].callsign["name"] = CallsignName:sub( 1, CallsignLen ) .. SpawnTemplate.units[UnitID].callsign[2] .. SpawnTemplate.units[UnitID].callsign[3]
else else
+13 -2
View File
@@ -275,7 +275,7 @@ end
--- Initialize as dead. --- Initialize as dead.
-- @param #SPAWNSTATIC self -- @param #SPAWNSTATIC self
-- @param #boolean IsCargo If true, this static is dead. -- @param #boolean IsDead If true, this static is dead.
-- @return #SPAWNSTATIC self -- @return #SPAWNSTATIC self
function SPAWNSTATIC:InitDead(IsDead) function SPAWNSTATIC:InitDead(IsDead)
self.InitStaticDead=IsDead self.InitStaticDead=IsDead
@@ -467,7 +467,7 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
self:T(Template) self:T(Template)
-- Add static to the game. -- Add static to the game.
local Static=nil local Static=nil --DCS#StaticObject
if self.InitFarp then if self.InitFarp then
@@ -487,6 +487,17 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
-- ED's dirty way to spawn FARPS. -- ED's dirty way to spawn FARPS.
Static=coalition.addGroup(CountryID, -1, TemplateGroup) 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 else
self:T("Spawning Static") self:T("Spawning Static")
self:T2({Template=Template}) self:T2({Template=Template})
+15 -1
View File
@@ -155,7 +155,7 @@ function TIMER:New(Function, ...)
return self return self
end end
--- Create a new TIMER object. --- Start TIMER object.
-- @param #TIMER self -- @param #TIMER self
-- @param #number Tstart Relative start time in seconds. -- @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 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 return self
end 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. --- Stop the timer by removing the timer function.
-- @param #TIMER self -- @param #TIMER self
-- @param #number Delay (Optional) Delay in seconds, before the timer is stopped. -- @param #number Delay (Optional) Delay in seconds, before the timer is stopped.
+73 -1
View File
@@ -1387,7 +1387,7 @@ end
-- @param #ZONE_RADIUS self -- @param #ZONE_RADIUS self
-- @param #number inner (Optional) Minimal distance from the center of the zone in meters. Default is 0 m. -- @param #number inner (Optional) Minimal distance from the center of the zone in meters. Default is 0 m.
-- @param #number outer (Optional) Maximal distance from the outer edge of the zone in meters. Default is the radius of the zone. -- @param #number outer (Optional) Maximal distance from the outer edge of the zone in meters. Default is the radius of the zone.
-- @param #table surfacetypes (Optional) Table of surface types. Can also be a single surface type. We will try max 1000 times to find the right type! -- @param #table surfacetypes (Optional) Table of surface types. Can also be a single surface type. We will try max 100 times to find the right type!
-- @return Core.Point#COORDINATE The random coordinate. -- @return Core.Point#COORDINATE The random coordinate.
function ZONE_RADIUS:GetRandomCoordinate(inner, outer, surfacetypes) function ZONE_RADIUS:GetRandomCoordinate(inner, outer, surfacetypes)
@@ -2084,6 +2084,52 @@ function ZONE_POLYGON_BASE:DrawZone(Coalition, Color, Alpha, FillColor, FillAlph
return self return self
end end
--- Get the smallest circular zone encompassing all points points of the polygon zone.
-- @param #ZONE_POLYGON_BASE self
-- @param #string ZoneName (Optional) Name of the zone. Default is the name of the polygon zone.
-- @param #boolean DoNotRegisterZone (Optional) If `true`, zone is not registered.
-- @return #ZONE_RADIUS The circular zone.
function ZONE_POLYGON_BASE:GetZoneRadius(ZoneName, DoNotRegisterZone)
local center=self:GetVec2()
local radius=0
for _,_vec2 in pairs(self._.Polygon) do
local vec2=_vec2 --DCS#Vec2
local r=UTILS.VecDist2D(center, vec2)
if r>radius then
radius=r
end
end
local zone=ZONE_RADIUS:New(ZoneName or self.ZoneName, center, radius, DoNotRegisterZone)
return zone
end
--- Get the smallest rectangular zone encompassing all points points of the polygon zone.
-- @param #ZONE_POLYGON_BASE self
-- @param #string ZoneName (Optional) Name of the zone. Default is the name of the polygon zone.
-- @param #boolean DoNotRegisterZone (Optional) If `true`, zone is not registered.
-- @return #ZONE_POLYGON The rectangular zone.
function ZONE_POLYGON_BASE:GetZoneQuad(ZoneName, DoNotRegisterZone)
local vec1, vec3=self:GetBoundingVec2()
local vec2={x=vec1.x, y=vec3.y}
local vec4={x=vec3.x, y=vec1.y}
local zone=ZONE_POLYGON_BASE:New(ZoneName or self.ZoneName, {vec1, vec2, vec3, vec4})
return zone
end
--- Smokes the zone boundaries in a color. --- Smokes the zone boundaries in a color.
-- @param #ZONE_POLYGON_BASE self -- @param #ZONE_POLYGON_BASE self
-- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color. -- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color.
@@ -2286,6 +2332,32 @@ function ZONE_POLYGON_BASE:GetBoundingSquare()
return { x1 = x1, y1 = y1, x2 = x2, y2 = y2 } return { x1 = x1, y1 = y1, x2 = x2, y2 = y2 }
end end
--- Get the bounding 2D vectors of the polygon.
-- @param #ZONE_POLYGON_BASE self
-- @return DCS#Vec2 Coordinates of western-southern-lower vertex of the box.
-- @return DCS#Vec2 Coordinates of eastern-northern-upper vertex of the box.
function ZONE_POLYGON_BASE:GetBoundingVec2()
local x1 = self._.Polygon[1].x
local y1 = self._.Polygon[1].y
local x2 = self._.Polygon[1].x
local y2 = self._.Polygon[1].y
for i = 2, #self._.Polygon do
self:T2( { self._.Polygon[i], x1, y1, x2, y2 } )
x1 = ( x1 > self._.Polygon[i].x ) and self._.Polygon[i].x or x1
x2 = ( x2 < self._.Polygon[i].x ) and self._.Polygon[i].x or x2
y1 = ( y1 > self._.Polygon[i].y ) and self._.Polygon[i].y or y1
y2 = ( y2 < self._.Polygon[i].y ) and self._.Polygon[i].y or y2
end
local vec1={x=x1, y=y1}
local vec2={x=x2, y=y2}
return vec1, vec2
end
--- Draw a frontier on the F10 map with small filled circles. --- Draw a frontier on the F10 map with small filled circles.
-- @param #ZONE_POLYGON_BASE self -- @param #ZONE_POLYGON_BASE self
-- @param #number Coalition (Optional) Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1= All. -- @param #number Coalition (Optional) Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1= All.
+58 -3
View File
@@ -308,6 +308,11 @@ do -- country
-- @field Argentinia -- @field Argentinia
-- @field Cyprus -- @field Cyprus
-- @field Slovenia -- @field Slovenia
-- @field BOLIVIA
-- @field GHANA
-- @field NIGERIA
-- @field PERU
-- @field ECUADOR
country = {} --#country country = {} --#country
@@ -336,9 +341,23 @@ do -- coalition
-- @field RED -- @field RED
-- @field BLUE -- @field BLUE
--- @function [parent=#coalition] getCountryCoalition --- Get country coalition.
-- @param #number countryId -- @function [parent=#coalition] getCountryCoalition
-- @return #number coalitionId -- @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 coalition = {} -- #coalition
@@ -1289,6 +1308,42 @@ do -- Group
end -- 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 do -- AI
@@ -45,6 +45,7 @@
-- @field #number talt Interval in seconds between reporting altitude until touchdown. Default 3 sec. -- @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 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 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 -- @extends Core.Base#BASE
--- Adds some rudimentary ATC functionality via the radio menu. --- Adds some rudimentary ATC functionality via the radio menu.
@@ -88,6 +89,7 @@ PSEUDOATC={
talt=3, talt=3,
chatty=true, chatty=true,
eventsmoose=true, eventsmoose=true,
reportplayername = false,
} }
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -98,7 +100,7 @@ PSEUDOATC.id="PseudoATC | "
--- PSEUDOATC version. --- PSEUDOATC version.
-- @field #number 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 self.mdur=duration or 30
end 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. --- Set time interval after which the F10 radio menu is refreshed.
-- @param #PSEUDOATC self -- @param #PSEUDOATC self
-- @param #number interval Interval in seconds. Default is every 120 sec. -- @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 group=unit:GetGroup()
local GID=group:GetID() local GID=group:GetID()
local UID=unit:GetDCSObject():getID() local UID=unit:GetDCSObject():getID()
local PlayerName=self.group[GID].player[UID].playername --local PlayerName=self.group[GID].player[UID].playername
local UnitName=self.group[GID].player[UID].unitname --local UnitName=self.group[GID].player[UID].unitname
local GroupName=self.group[GID].player[UID].groupname --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. -- Debug message.
local text=string.format("Player %s in unit %s of group %s (id=%d) landed at %s.", PlayerName, UnitName, GroupName, GID, place) local text=string.format("Player %s in unit %s of group %s landed at %s.", PlayerName, UnitName, GroupName, place)
self:T(PSEUDOATC.id..text) self:T(PSEUDOATC.id..text)
MESSAGE:New(text, 30):ToAllIf(self.Debug) MESSAGE:New(text, 30):ToAllIf(self.Debug)
end
-- Stop altitude reporting timer if its activated. -- Stop altitude reporting timer if its activated.
self:AltitudeTimerStop(GID,UID) self:AltitudeTimerStop(GID,UID)
@@ -470,21 +483,28 @@ function PSEUDOATC:PlayerTakeOff(unit, place)
-- Gather some information. -- Gather some information.
local group=unit:GetGroup() local group=unit:GetGroup()
local GID=group:GetID() --local GID=group:GetID()
local UID=unit:GetDCSObject():getID() --local UID=unit:GetDCSObject():getID()
local PlayerName=self.group[GID].player[UID].playername --local PlayerName=self.group[GID].player[UID].playername
local CallSign=self.group[GID].player[UID].callsign --local CallSign=self.group[GID].player[UID].callsign
local UnitName=self.group[GID].player[UID].unitname --local UnitName=self.group[GID].player[UID].unitname
local GroupName=self.group[GID].player[UID].groupname --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. -- 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) 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) self:T(PSEUDOATC.id..text)
MESSAGE:New(text, 30):ToAllIf(self.Debug) MESSAGE:New(text, 30):ToAllIf(self.Debug)
end
-- Bye-Bye message. -- Bye-Bye message.
if place and self.chatty then if place and self.chatty then
local text=string.format("%s, %s, you are airborne. Have a safe trip!", place, CallSign) 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) MESSAGE:New(text, self.mdur):ToGroup(group)
end end
@@ -501,7 +521,7 @@ function PSEUDOATC:PlayerLeft(unit)
local GID=group:GetID() local GID=group:GetID()
local UID=unit:GetDCSObject():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 PlayerName=self.group[GID].player[UID].playername
local CallSign=self.group[GID].player[UID].callsign local CallSign=self.group[GID].player[UID].callsign
local UnitName=self.group[GID].player[UID].unitname local UnitName=self.group[GID].player[UID].unitname
@@ -687,7 +707,9 @@ function PSEUDOATC:MenuWaypoints(GID, UID)
-- Position of Waypoint -- Position of Waypoint
local pos=COORDINATE:New(wp.x, wp.alt, wp.y) local pos=COORDINATE:New(wp.x, wp.alt, wp.y)
local name=string.format("Waypoint %d", i-1) 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" -- "F10/PseudoATC/Waypoints/Waypoint X"
local submenu=missionCommands.addSubMenuForGroup(GID, name, self.group[GID].player[UID].menu_waypoints) local submenu=missionCommands.addSubMenuForGroup(GID, name, self.group[GID].player[UID].menu_waypoints)
@@ -844,6 +866,7 @@ function PSEUDOATC:ReportHeight(GID, UID, dt, _clear)
local position=unit:GetCoordinate() local position=unit:GetCoordinate()
local height=get_AGL(position) local height=get_AGL(position)
local callsign=unit:GetCallsign() local callsign=unit:GetCallsign()
local PlayerName=self.group[GID].player[UID].playername
-- Settings. -- Settings.
local settings=_DATABASE:GetPlayerSettings(self.group[GID].player[UID].playername) or _SETTINGS --Core.Settings#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. -- Message text.
local _text=string.format("%s, your altitude is %s AGL.", callsign, Hs) 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. -- Append flight level.
if _clear==false then if _clear==false then
_text=_text..string.format(" FL%03d.", position.y/30.48) _text=_text..string.format(" FL%03d.", position.y/30.48)
+7 -1
View File
@@ -3492,7 +3492,7 @@ function RAT:Status(message, forID)
local fuel=group:GetFuel()*100.0 local fuel=group:GetFuel()*100.0
local airborne=group:InAir() local airborne=group:InAir()
local coords=group:GetCoordinate() local coords=group:GetCoordinate()
local alt=coords.y local alt=coords.y or 1000
--local vel=group:GetVelocityKMH() --local vel=group:GetVelocityKMH()
local departure=ratcraft.departure:GetName() local departure=ratcraft.departure:GetName()
local destination=ratcraft.destination:GetName() local destination=ratcraft.destination:GetName()
@@ -5671,6 +5671,9 @@ function RAT:_ATCClearForLanding(airport, flight)
-- Debug message. -- Debug message.
local text1=string.format("ATC %s: Flight %s cleared for landing (flag=%d).", airport, flight, flagvalue) 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) local text2=string.format("ATC %s: Flight %s you are cleared for landing.", airport, flight)
BASE:T( RAT.id..text1) BASE:T( RAT.id..text1)
MESSAGE:New(text2, 10):ToAllIf(RAT.ATC.messages) 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 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 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) 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) local text4=string.format("ATC %s: Flight %s landed. Welcome to %s.", dest, name, dest)
BASE:T(RAT.id..text1) BASE:T(RAT.id..text1)
BASE:T(RAT.id..text2) BASE:T(RAT.id..text2)
+43 -26
View File
@@ -578,7 +578,7 @@ RANGE.MenuF10Root = nil
--- Range script version. --- Range script version.
-- @field #string version -- @field #string version
RANGE.version = "2.5.0" RANGE.version = "2.5.1"
-- TODO list: -- TODO list:
-- TODO: Verbosity level for messages. -- TODO: Verbosity level for messages.
@@ -1214,6 +1214,11 @@ function RANGE:SetSRS(PathToSRS, Port, Coalition, Frequency, Modulation, Volume,
self.instructmsrs:SetLabel("RANGEI") self.instructmsrs:SetLabel("RANGEI")
self.instructsrsQ = MSRSQUEUE:New("INSTRUCT") self.instructsrsQ = MSRSQUEUE:New("INSTRUCT")
if PathToGoogleKey then
self.instructmsrs:SetGoogle(PathToGoogleKey)
self.instructmsrs:SetGoogle(PathToGoogleKey)
end
else else
self:E(self.lid..string.format("ERROR: No SRS path specified!")) self:E(self.lid..string.format("ERROR: No SRS path specified!"))
end end
@@ -2570,7 +2575,7 @@ function RANGE:_DisplayMyStrafePitResults( _unitName )
self:F( _unitName ) self:F( _unitName )
-- Get player unit and name -- Get player unit and name
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) local _unit, _playername, _multiplayer = self:_GetPlayerUnitAndName( _unitName )
if _unit and _playername then if _unit and _playername then
@@ -2622,7 +2627,7 @@ function RANGE:_DisplayMyStrafePitResults( _unitName )
end end
-- Send message to group. -- Send message to group.
self:_DisplayMessageToGroup( _unit, _message, nil, true, true ) self:_DisplayMessageToGroup( _unit, _message, nil, true, true, _multiplayer )
end end
end end
@@ -2633,7 +2638,7 @@ function RANGE:_DisplayStrafePitResults( _unitName )
self:F( _unitName ) self:F( _unitName )
-- Get player unit and name. -- 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. -- Check if we have a unit which is a player.
if _unit and _playername then if _unit and _playername then
@@ -2680,7 +2685,7 @@ function RANGE:_DisplayStrafePitResults( _unitName )
end end
-- Send message. -- Send message.
self:_DisplayMessageToGroup( _unit, _message, nil, true, true ) self:_DisplayMessageToGroup( _unit, _message, nil, true, true, _multiplayer )
end end
end end
@@ -2691,7 +2696,7 @@ function RANGE:_DisplayMyBombingResults( _unitName )
self:F( _unitName ) self:F( _unitName )
-- Get player unit and name. -- Get player unit and name.
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) local _unit, _playername, _multiplayer = self:_GetPlayerUnitAndName( _unitName )
if _unit and _playername then if _unit and _playername then
@@ -2737,7 +2742,7 @@ function RANGE:_DisplayMyBombingResults( _unitName )
end end
-- Send message. -- Send message.
self:_DisplayMessageToGroup( _unit, _message, nil, true, true ) self:_DisplayMessageToGroup( _unit, _message, nil, true, true, _multiplayer )
end end
end end
@@ -2751,7 +2756,7 @@ function RANGE:_DisplayBombingResults( _unitName )
local _playerResults = {} local _playerResults = {}
-- Get player unit and name. -- 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. -- Check if we have a unit with a player.
if _unit and _player then if _unit and _player then
@@ -2795,7 +2800,7 @@ function RANGE:_DisplayBombingResults( _unitName )
end end
-- Send message. -- Send message.
self:_DisplayMessageToGroup( _unit, _message, nil, true, true ) self:_DisplayMessageToGroup( _unit, _message, nil, true, true, _multiplayer )
end end
end end
@@ -2806,7 +2811,7 @@ function RANGE:_DisplayRangeInfo( _unitname )
self:F( _unitname ) self:F( _unitname )
-- Get player unit and player name. -- 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. -- Check if we have a player.
if unit and playername then if unit and playername then
@@ -2901,7 +2906,7 @@ function RANGE:_DisplayRangeInfo( _unitname )
text = text .. textdelay text = text .. textdelay
-- Send message to player group. -- Send message to player group.
self:_DisplayMessageToGroup( unit, text, nil, true, true ) self:_DisplayMessageToGroup( unit, text, nil, true, true, _multiplayer )
-- Debug output. -- Debug output.
self:T2( self.id .. text ) self:T2( self.id .. text )
@@ -2916,7 +2921,7 @@ function RANGE:_DisplayBombTargets( _unitname )
self:F( _unitname ) self:F( _unitname )
-- Get player unit and player name. -- 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. -- Check if we have a player.
if _unit and _playername then if _unit and _playername then
@@ -2948,7 +2953,7 @@ function RANGE:_DisplayBombTargets( _unitname )
end end
end end
self:_DisplayMessageToGroup( _unit, _text, 120, true, true ) self:_DisplayMessageToGroup( _unit, _text, 120, true, true, _multiplayer )
end end
end end
@@ -2959,7 +2964,7 @@ function RANGE:_DisplayStrafePits( _unitname )
self:F( _unitname ) self:F( _unitname )
-- Get player unit and player name. -- 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. -- Check if we have a player.
if _unit and _playername then if _unit and _playername then
@@ -2988,7 +2993,7 @@ function RANGE:_DisplayStrafePits( _unitname )
_text = _text .. string.format( "\n- %s: heading %03d°\n%s", _strafepit.name, heading, mycoord ) _text = _text .. string.format( "\n- %s: heading %03d°\n%s", _strafepit.name, heading, mycoord )
end end
self:_DisplayMessageToGroup( _unit, _text, nil, true, true ) self:_DisplayMessageToGroup( _unit, _text, nil, true, true, _multiplayer )
end end
end end
@@ -2999,7 +3004,7 @@ function RANGE:_DisplayRangeWeather( _unitname )
self:F( _unitname ) self:F( _unitname )
-- Get player unit and player name. -- 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. -- Check if we have a player.
if unit and playername then if unit and playername then
@@ -3048,7 +3053,7 @@ function RANGE:_DisplayRangeWeather( _unitname )
end end
-- Send message to player group. -- Send message to player group.
self:_DisplayMessageToGroup( unit, text, nil, true, true ) self:_DisplayMessageToGroup( unit, text, nil, true, true, _multiplayer )
-- Debug output. -- Debug output.
self:T2( self.id .. text ) self:T2( self.id .. text )
@@ -3666,7 +3671,8 @@ end
-- @param #number _time Duration how long the message is displayed. -- @param #number _time Duration how long the message is displayed.
-- @param #boolean _clear Clear up old messages. -- @param #boolean _clear Clear up old messages.
-- @param #boolean display If true, display message regardless of player setting "Messages Off". -- @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 } ) self:F( { unit = _unit, text = _text, time = _time, clear = _clear } )
-- Defaults -- Defaults
@@ -3694,9 +3700,14 @@ function RANGE:_DisplayMessageToGroup( _unit, _text, _time, _clear, display )
local playermessage = self.PlayerSettings[playername].messages local playermessage = self.PlayerSettings[playername].messages
-- Send message to player if messages enabled and not only for the examiner. -- 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 if _gid and (playermessage == true or display) and (not self.examinerexclusive) then
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) local m = MESSAGE:New(_text,_time,nil,_clear):ToUnit(_unit)
end end
end
-- Send message to examiner. -- Send message to examiner.
if self.examinergroupname ~= nil then if self.examinergroupname ~= nil then
@@ -3715,7 +3726,7 @@ end
function RANGE:_SmokeBombImpactOnOff( unitname ) function RANGE:_SmokeBombImpactOnOff( unitname )
self:F( unitname ) self:F( unitname )
local unit, playername = self:_GetPlayerUnitAndName( unitname ) local unit, playername, _multiplayer = self:_GetPlayerUnitAndName( unitname )
if unit and playername then if unit and playername then
local text local text
if self.PlayerSettings[playername].smokebombimpact == true then if self.PlayerSettings[playername].smokebombimpact == true then
@@ -3736,7 +3747,7 @@ end
function RANGE:_SmokeBombDelayOnOff( unitname ) function RANGE:_SmokeBombDelayOnOff( unitname )
self:F( unitname ) self:F( unitname )
local unit, playername = self:_GetPlayerUnitAndName( unitname ) local unit, playername, _multiplayer = self:_GetPlayerUnitAndName( unitname )
if unit and playername then if unit and playername then
local text local text
if self.PlayerSettings[playername].delaysmoke == true then if self.PlayerSettings[playername].delaysmoke == true then
@@ -3757,7 +3768,7 @@ end
function RANGE:_MessagesToPlayerOnOff( unitname ) function RANGE:_MessagesToPlayerOnOff( unitname )
self:F( unitname ) self:F( unitname )
local unit, playername = self:_GetPlayerUnitAndName( unitname ) local unit, playername, _multiplayer = self:_GetPlayerUnitAndName( unitname )
if unit and playername then if unit and playername then
local text local text
if self.PlayerSettings[playername].messages == true then if self.PlayerSettings[playername].messages == true then
@@ -3778,7 +3789,7 @@ function RANGE:_TargetsheetOnOff( _unitname )
self:F2( _unitname ) self:F2( _unitname )
-- Get player unit and player name. -- 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. -- Check if we have a player.
if unit and playername then if unit and playername then
@@ -3820,7 +3831,7 @@ end
function RANGE:_FlareDirectHitsOnOff( unitname ) function RANGE:_FlareDirectHitsOnOff( unitname )
self:F( unitname ) self:F( unitname )
local unit, playername = self:_GetPlayerUnitAndName( unitname ) local unit, playername, _multiplayer = self:_GetPlayerUnitAndName( unitname )
if unit and playername then if unit and playername then
local text local text
if self.PlayerSettings[playername].flaredirecthits == true then if self.PlayerSettings[playername].flaredirecthits == true then
@@ -4039,12 +4050,14 @@ end
-- @param #string _unitName Name of the player unit. -- @param #string _unitName Name of the player unit.
-- @return Wrapper.Unit#UNIT Unit of player. -- @return Wrapper.Unit#UNIT Unit of player.
-- @return #string Name of the 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 ) function RANGE:_GetPlayerUnitAndName( _unitName )
self:F2( _unitName ) self:F2( _unitName )
if _unitName ~= nil then if _unitName ~= nil then
local multiplayer = false
-- Get DCS unit from its name. -- Get DCS unit from its name.
local DCSunit = Unit.getByName( _unitName ) local DCSunit = Unit.getByName( _unitName )
@@ -4056,7 +4069,11 @@ function RANGE:_GetPlayerUnitAndName( _unitName )
self:T2( { DCSunit = DCSunit, unit = unit, playername = playername } ) self:T2( { DCSunit = DCSunit, unit = unit, playername = playername } )
if DCSunit and unit and playername then if DCSunit and unit and playername then
self:F2(playername) 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
end end
@@ -4064,7 +4081,7 @@ function RANGE:_GetPlayerUnitAndName( _unitName )
end end
-- Return nil if we could not find a player. -- Return nil if we could not find a player.
return nil, nil return nil, nil, nil
end end
--- Returns a string which consists of the player name. --- Returns a string which consists of the player name.
@@ -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 #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 Core.Zone#ZONE BattleZone
-- @field #boolean AutoEngage -- @field #boolean AutoEngage
-- @field #table waypoints Waypoints of the group as defined in the ME.
-- @extends Core.Fsm#FSM_CONTROLLABLE -- @extends Core.Fsm#FSM_CONTROLLABLE
-- --
@@ -265,6 +266,7 @@ SUPPRESSION={
DefaultAlarmState = "Auto", DefaultAlarmState = "Auto",
DefaultROE = "Weapon Free", DefaultROE = "Weapon Free",
eventmoose = true, eventmoose = true,
waypoints = {},
} }
--- Enumerator of possible rules of engagement. --- Enumerator of possible rules of engagement.
@@ -295,7 +297,7 @@ SUPPRESSION.MenuF10=nil
--- PSEUDOATC version. --- PSEUDOATC version.
-- @field #number 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. --- Creates a new AI_suppression object.
-- @param #SUPPRESSION self -- @param #SUPPRESSION self
-- @param Wrapper.Group#GROUP group The GROUP object for which suppression should be applied. -- @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) function SUPPRESSION:New(group)
-- Inherits from FSM_CONTROLLABLE -- Inherits from FSM_CONTROLLABLE
@@ -320,7 +322,7 @@ function SUPPRESSION:New(group)
self.lid=string.format("SUPPRESSION %s | ", tostring(group:GetName())) 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())) self:T(self.lid..string.format("SUPPRESSION version %s. Activating suppressive fire for group %s", SUPPRESSION.version, group:GetName()))
else 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 return nil
end end
@@ -1186,6 +1188,16 @@ function SUPPRESSION:onafterFightBack(Controllable, From, Event, To)
-- Set ROE and alarm state back to default. -- Set ROE and alarm state back to default.
self:_SetROE() self:_SetROE()
self:_SetAlarmState() 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 end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -1251,7 +1263,7 @@ function SUPPRESSION:onafterFallBack(Controllable, From, Event, To, AttackUnit)
self:_SetROE(SUPPRESSION.ROE.Hold) self:_SetROE(SUPPRESSION.ROE.Hold)
-- Set alarm state to GREEN and let the unit run away. -- 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. -- Make the group run away.
self:_Run(Coord, self.Speed, self.Formation, self.FallbackWait) self:_Run(Coord, self.Speed, self.Formation, self.FallbackWait)
@@ -1537,7 +1549,7 @@ end
-- @param #SUPPRESSION self -- @param #SUPPRESSION self
-- @param Core.Event#EVENTDATA EventData -- @param Core.Event#EVENTDATA EventData
function SUPPRESSION:_OnEventHit(EventData) function SUPPRESSION:_OnEventHit(EventData)
self:F(EventData) self:F3(EventData)
local GroupNameSelf=self.Controllable:GetName() local GroupNameSelf=self.Controllable:GetName()
local GroupNameTgt=EventData.TgtGroupName local GroupNameTgt=EventData.TgtGroupName
@@ -1676,15 +1688,15 @@ end
function SUPPRESSION:_Run(fin, speed, formation, wait) function SUPPRESSION:_Run(fin, speed, formation, wait)
speed=speed or 20 speed=speed or 20
formation=formation or "Off road" formation=formation or ENUMS.Formation.Vehicle.OffRoad
wait=wait or 30 wait=wait or 30
local group=self.Controllable -- Wrapper.Controllable#CONTROLLABLE local group=self.Controllable -- Wrapper.Group#GROUP
if group and group:IsAlive() then if group and group:IsAlive() then
-- Clear all tasks. -- Clear all tasks.
group:ClearTasks() --group:ClearTasks()
-- Current coordinates of group. -- Current coordinates of group.
local ini=group:GetCoordinate() local ini=group:GetCoordinate()
@@ -1695,56 +1707,17 @@ function SUPPRESSION:_Run(fin, speed, formation, wait)
-- Heading from ini to fin. -- Heading from ini to fin.
local heading=self:_Heading(ini, 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. -- Waypoint and task arrays.
local wp={} local wp={}
local tasks={} local tasks={}
-- First waypoint is the current position of the group. -- First waypoint is the current position of the group.
wp[1]=ini:WaypointGround(speed, formation) wp[1]=ini:WaypointGround(speed, formation)
tasks[1]=group:TaskFunction("SUPPRESSION._Passing_Waypoint", self, 1, false)
if self.Debug then if self.Debug then
local MarkerID=ini:MarkToAll(string.format("Waypoing %d of group %s (initial)", #wp, self.Controllable:GetName())) local MarkerID=ini:MarkToAll(string.format("Waypoing %d of group %s (initial)", #wp, self.Controllable:GetName()))
end 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. -- Task to hold.
local ConditionWait=group:TaskCondition(nil, nil, nil, nil, wait, nil) local ConditionWait=group:TaskCondition(nil, nil, nil, nil, wait, nil)
local TaskHold = group:TaskHold() local TaskHold = group:TaskHold()
@@ -1754,24 +1727,14 @@ function SUPPRESSION:_Run(fin, speed, formation, wait)
TaskComboFin[#TaskComboFin+1] = group:TaskFunction("SUPPRESSION._Passing_Waypoint", self, #wp, true) TaskComboFin[#TaskComboFin+1] = group:TaskFunction("SUPPRESSION._Passing_Waypoint", self, #wp, true)
TaskComboFin[#TaskComboFin+1] = group:TaskControlled(TaskHold, ConditionWait) TaskComboFin[#TaskComboFin+1] = group:TaskControlled(TaskHold, ConditionWait)
-- Add final task. -- Final waypoint.
tasks[#tasks+1]=group:TaskCombo(TaskComboFin) wp[#wp+1]=fin:WaypointGround(speed, formation, TaskComboFin)
if self.Debug then
-- Original waypoints of the group. local MarkerID=fin:MarkToAll(string.format("Waypoing %d of group %s (final)", #wp, self.Controllable:GetName()))
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 end
-- Submit task and route group along waypoints. -- Submit task and route group along waypoints.
group:Route(Waypoints) group:Route(wp)
else else
self:E(self.lid..string.format("ERROR: Group is not alive!")) 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)) local text=string.format("Group %s passing waypoint %d (final=%s)", group:GetName(), i, tostring(final))
MESSAGE:New(text,10):ToAllIf(Fsm.Debug) MESSAGE:New(text,10):ToAllIf(Fsm.Debug)
if Fsm.Debug then if Fsm.Debug then
env.info(self.lid..text) env.info(Fsm.lid..text)
end end
if final then if final then
@@ -1891,7 +1854,7 @@ function SUPPRESSION:_GetLife()
local groupstrength=#units/self.IniGroupStrength*100 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 for _,unit in pairs(units) do
@@ -2647,6 +2647,13 @@ function WAREHOUSE:SetWarehouseZone(zone)
return self return self
end 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. --- 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 -- @param #WAREHOUSE self
-- @return #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. -- 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={} local Parking={}
if Request.cargocategory==Group.Category.AIRPLANE or Request.cargocategory==Group.Category.HELICOPTER then 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 {} Parking=self:_FindParkingForAssets(self.airbase, cargoassets) or {}
end end
@@ -6069,7 +6077,9 @@ function WAREHOUSE:_SpawnAssetAircraft(alias, asset, request, parking, uncontrol
end end
if self.Debug then 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 end
unit.x=coord.x unit.x=coord.x
@@ -7374,6 +7384,7 @@ function WAREHOUSE:_CheckRequestNow(request)
local _transports local _transports
local _assetattribute local _assetattribute
local _assetcategory local _assetcategory
local _assetairstart=false
-- Check if at least one (cargo) asset is available. -- Check if at least one (cargo) asset is available.
if _nassets>0 then if _nassets>0 then
@@ -7381,22 +7392,29 @@ function WAREHOUSE:_CheckRequestNow(request)
-- Get the attibute of the requested asset. -- Get the attibute of the requested asset.
_assetattribute=_assets[1].attribute _assetattribute=_assets[1].attribute
_assetcategory=_assets[1].category _assetcategory=_assets[1].category
_assetairstart=_assets[1].takeoffType and _assets[1].takeoffType==COORDINATE.WaypointType.TurningPoint or false
-- Check available parking for air asset units. -- Check available parking for air asset units.
if _assetcategory==Group.Category.AIRPLANE or _assetcategory==Group.Category.HELICOPTER then if _assetcategory==Group.Category.AIRPLANE or _assetcategory==Group.Category.HELICOPTER then
if self.airbase and self.airbase:GetCoalition()==self:GetCoalition() then if self.airbase and self.airbase:GetCoalition()==self:GetCoalition() then
if self:IsRunwayOperational() then if self:IsRunwayOperational() or _assetairstart then
if _assetairstart then
-- Airstart no need to check parking
else
-- Check parking.
local Parking=self:_FindParkingForAssets(self.airbase,_assets) local Parking=self:_FindParkingForAssets(self.airbase,_assets)
--if Parking==nil and not (self.category==Airbase.Category.HELIPAD) then -- No parking?
if Parking==nil 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) 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) self:_InfoMessage(text, 5)
return false return false
end end
end
else else
-- Runway destroyed. -- Runway destroyed.
@@ -7970,6 +7988,8 @@ function WAREHOUSE:_FindParkingForAssets(airbase, assets)
for _,asset in pairs(assets) do for _,asset in pairs(assets) do
local _asset=asset --#WAREHOUSE.Assetitem local _asset=asset --#WAREHOUSE.Assetitem
if not _asset.spawned then
-- Get terminal type of this asset -- Get terminal type of this asset
local terminaltype=asset.terminalType or self:_GetTerminal(asset.attribute, self:GetAirbaseCategory()) local terminaltype=asset.terminalType or self:_GetTerminal(asset.attribute, self:GetAirbaseCategory())
@@ -7987,8 +8007,35 @@ function WAREHOUSE:_FindParkingForAssets(airbase, assets)
for _,_parkingspot in pairs(parkingdata) do for _,_parkingspot in pairs(parkingdata) do
local parkingspot=_parkingspot --Wrapper.Airbase#AIRBASE.ParkingSpot 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
-- 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
-- Check correct terminal type for asset. We don't want helos in shelters etc. -- 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 if valid then
-- Coordinate of the parking spot. -- Coordinate of the parking spot.
local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE
@@ -8056,6 +8103,7 @@ function WAREHOUSE:_FindParkingForAssets(airbase, assets)
return nil return nil
end end
end -- loop over asset units end -- loop over asset units
end -- Asset spawned check
end -- loop over asset groups end -- loop over asset groups
return parking return parking
+58 -24
View File
@@ -93,6 +93,8 @@
-- @field #number dTQueueCheck Time interval to check the radio queue. Default 5 sec or 90 sec if SRS is used. -- @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 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 #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 -- @extends Core.Fsm#FSM
--- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde --- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde
@@ -268,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 -- 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. -- 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 -- # Examples
-- --
-- ## Caucasus: Batumi -- ## Caucasus: Batumi
@@ -307,6 +311,19 @@
-- --
-- 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). -- 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 -- @field #ATIS
ATIS = { ATIS = {
ClassName = "ATIS", ClassName = "ATIS",
@@ -348,6 +365,7 @@ ATIS = {
relHumidity = nil, relHumidity = nil,
ReportmBar = false, ReportmBar = false,
TransmitOnlyWithPlayers = false, TransmitOnlyWithPlayers = false,
ATISforFARPs = false,
} }
--- NATO alphabet. --- NATO alphabet.
@@ -590,7 +608,7 @@ _ATIS = {}
--- ATIS class version. --- ATIS class version.
-- @field #string version -- @field #string version
ATIS.version = "0.9.10" ATIS.version = "0.9.14"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@@ -616,7 +634,7 @@ ATIS.version = "0.9.10"
-- Constructor -- 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 #ATIS self
-- @param #string AirbaseName Name of the airbase. -- @param #string AirbaseName Name of the airbase.
-- @param #number Frequency Radio frequency in MHz. Default 143.00 MHz. -- @param #number Frequency Radio frequency in MHz. Default 143.00 MHz.
@@ -878,6 +896,13 @@ function ATIS:SetMapMarks( switch )
return self return self
end 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°. --- 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 #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. -- @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.
@@ -1039,7 +1064,7 @@ end
-- --
-- * 186° on the Caucaus map -- * 186° on the Caucaus map
-- * 192° on the Nevada map -- * 192° on the Nevada map
-- * 170° on the Normany map -- * 170° on the Normandy map
-- * 182° on the Persian Gulf map -- * 182° on the Persian Gulf map
-- --
-- Likewise, to convert *true* into *magnetic* heading, one has to substract easterly and add westerly variation. -- Likewise, to convert *true* into *magnetic* heading, one has to substract easterly and add westerly variation.
@@ -1247,11 +1272,18 @@ end
function ATIS:onafterStart( From, Event, To ) function ATIS:onafterStart( From, Event, To )
-- Check that this is an airdrome. -- Check that this is an airdrome.
if self.airbase:GetAirbaseCategory() ~= Airbase.Category.AIRDROME then 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 FARPS or SHIPS.", self.airbasename ) ) self:E( self.lid .. string.format( "ERROR: Cannot start ATIS for airbase %s! Only AIRDROMES are supported but NOT SHIPS.", self.airbasename ) )
return return
end 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. -- 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 ) ) 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 ) )
@@ -1320,7 +1352,9 @@ function ATIS:onafterStatus( From, Event, To )
end end
self:T( self.lid .. text ) self:T( self.lid .. text )
if not self:Is("Stopped") then
self:__Status( -60 ) self:__Status( -60 )
end
end end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -1349,8 +1383,10 @@ function ATIS:onafterCheckQueue( From, Event, To )
end end
if not self:Is("Stopped") then
-- Check back in 5 seconds. -- Check back in 5 seconds.
self:__CheckQueue( -math.abs( self.dTQueueCheck ) ) self:__CheckQueue( -math.abs( self.dTQueueCheck ) )
end
end end
--- Broadcast ATIS radio message. --- Broadcast ATIS radio message.
@@ -1460,8 +1496,17 @@ function ATIS:onafterBroadcast( From, Event, To )
--- Runway --- --- 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 --- --- Time ---
@@ -1776,7 +1821,7 @@ function ATIS:onafterBroadcast( From, Event, To )
-- Airbase name -- Airbase name
subtitle = string.format( "%s", self.airbasename ) 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" subtitle = subtitle .. " Airport"
end end
if not self.useSRS then if not self.useSRS then
@@ -1851,8 +1896,6 @@ function ATIS:onafterBroadcast( From, Event, To )
end end
end end
alltext = alltext .. ";\n" .. subtitle alltext = alltext .. ";\n" .. subtitle
--self:I("Line 1811")
--self:I(alltext)
-- Visibility -- Visibility
if self.metric then if self.metric then
@@ -1870,8 +1913,6 @@ function ATIS:onafterBroadcast( From, Event, To )
end end
end end
alltext = alltext .. ";\n" .. subtitle alltext = alltext .. ";\n" .. subtitle
--self:I("Line 1830")
--self:I(alltext)
subtitle = "" subtitle = ""
-- Weather phenomena -- Weather phenomena
@@ -1973,10 +2014,8 @@ function ATIS:onafterBroadcast( From, Event, To )
end end
end end
end end
--self:I("Line 1932")
alltext = alltext .. ";\n" .. subtitle alltext = alltext .. ";\n" .. subtitle
--self:I(alltext)
subtitle = "" subtitle = ""
-- Temperature -- Temperature
if self.TDegF then if self.TDegF then
@@ -2005,9 +2044,7 @@ function ATIS:onafterBroadcast( From, Event, To )
self:Transmission( ATIS.Sound.DegreesCelsius, 0.2 ) self:Transmission( ATIS.Sound.DegreesCelsius, 0.2 )
end end
end end
--self:I("Line 1962")
alltext = alltext .. ";\n" .. subtitle alltext = alltext .. ";\n" .. subtitle
--self:I(alltext)
-- Dew point -- Dew point
if self.TDegF then if self.TDegF then
@@ -2036,8 +2073,6 @@ function ATIS:onafterBroadcast( From, Event, To )
self:Transmission( ATIS.Sound.DegreesCelsius, 0.2 ) self:Transmission( ATIS.Sound.DegreesCelsius, 0.2 )
end end
end end
--self:I("Line 1992")
--self:I(alltext)
alltext = alltext .. ";\n" .. subtitle alltext = alltext .. ";\n" .. subtitle
-- Altimeter QNH/QFE. -- Altimeter QNH/QFE.
@@ -2103,10 +2138,9 @@ function ATIS:onafterBroadcast( From, Event, To )
end end
end end
end end
--self:I("Line 2049")
--self:I(alltext)
alltext = alltext .. ";\n" .. subtitle alltext = alltext .. ";\n" .. subtitle
if not self.ATISforFARPs then
-- Active runway. -- Active runway.
local subtitle=string.format("Active runway %s", runwayLanding) local subtitle=string.format("Active runway %s", runwayLanding)
if rwyLandingLeft==true then if rwyLandingLeft==true then
@@ -2165,7 +2199,7 @@ function ATIS:onafterBroadcast( From, Event, To )
end end
alltext = alltext .. ";\n" .. subtitle alltext = alltext .. ";\n" .. subtitle
end end
end
-- Airfield elevation -- Airfield elevation
if self.elevation then if self.elevation then
@@ -2232,9 +2266,7 @@ function ATIS:onafterBroadcast( From, Event, To )
end end
-- ILS -- ILS
--self:I({ils=self.ils})
local ils=self:GetNavPoint(self.ils, runwayLanding, rwyLandingLeft) local ils=self:GetNavPoint(self.ils, runwayLanding, rwyLandingLeft)
--self:I({ils=ils,runwayLanding=runwayLanding, rwyLandingLeft=rwyLandingLeft})
if ils then if ils then
subtitle = string.format( "ILS frequency %.2f MHz", ils.frequency ) subtitle = string.format( "ILS frequency %.2f MHz", ils.frequency )
if not self.useSRS then if not self.useSRS then
@@ -2249,7 +2281,6 @@ function ATIS:onafterBroadcast( From, Event, To )
self:Transmission( ATIS.Sound.MegaHertz, 0.2 ) self:Transmission( ATIS.Sound.MegaHertz, 0.2 )
end end
alltext = alltext .. ";\n" .. subtitle alltext = alltext .. ";\n" .. subtitle
--self:I(alltext)
end end
-- Outer NDB -- Outer NDB
@@ -2385,6 +2416,8 @@ function ATIS:onafterReport( From, Event, To, Text )
local text = string.gsub( text, "mmHg", "millimeters of Mercury" ) local text = string.gsub( text, "mmHg", "millimeters of Mercury" )
local text = string.gsub( text, "hPa", "hectopascals" ) local text = string.gsub( text, "hPa", "hectopascals" )
local text = string.gsub( text, "m/s", "meters per second" ) 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 "." -- Replace ";" by "."
local text = string.gsub( text, ";", " . " ) local text = string.gsub( text, ";", " . " )
@@ -2396,6 +2429,7 @@ function ATIS:onafterReport( From, Event, To, Text )
local duration = STTS.getSpeechTime(text,0.95) local duration = STTS.getSpeechTime(text,0.95)
self.msrsQ:NewTransmission(text,duration,self.msrs,nil,2) self.msrsQ:NewTransmission(text,duration,self.msrs,nil,2)
--self.msrs:PlayText( text ) --self.msrs:PlayText( text )
self.SRSText = text
end end
+50 -14
View File
@@ -32,20 +32,21 @@
-- * [USS George Washington](https://en.wikipedia.org/wiki/USS_George_Washington_(CVN-73\)) (CVN-73) [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 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] -- * [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 Hermes](https://en.wikipedia.org/wiki/HMS_Hermes_(R12\)) (R12)
-- * [HMS Invincible](https://en.wikipedia.org/wiki/HMS_Invincible_(R05\)) (R05) [**WIP**] -- * [HMS Invincible](https://en.wikipedia.org/wiki/HMS_Invincible_(R05\)) (R05)
-- * [USS Tarawa](https://en.wikipedia.org/wiki/USS_Tarawa_(LHA-1\)) (LHA-1) [**WIP**] -- * [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) [**WIP**] -- * [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) [**WIP**] -- * [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) [**WIP**] -- * [HMAS Canberra](https://en.wikipedia.org/wiki/HMAS_Canberra_(L02\)) (L02)
-- --
-- **Supported Aircraft:** -- **Supported Aircraft:**
-- --
-- * [F/A-18C Hornet Lot 20](https://forums.eagle.ru/forumdisplay.php?f=557) (Player & AI) -- * [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) -- * [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) -- * [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**] -- * [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)(Player & AI) [**WIP**] -- * [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/A-18C Hornet (AI)
-- * F-14A Tomcat (AI) -- * F-14A Tomcat (AI)
-- * E-2D Hawkeye (AI) -- * E-2D Hawkeye (AI)
@@ -1278,7 +1279,10 @@ AIRBOSS = {
-- @field #string S3BTANKER Lockheed S-3B Viking tanker. -- @field #string S3BTANKER Lockheed S-3B Viking tanker.
-- @field #string E2D Grumman E-2D Hawkeye AWACS. -- @field #string E2D Grumman E-2D Hawkeye AWACS.
-- @field #string C2A Grumman C-2A Greyhound from Military Aircraft Mod. -- @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={ AIRBOSS.AircraftCarrier={
AV8B="AV8BNA", AV8B="AV8BNA",
HORNET="FA-18C_hornet", HORNET="FA-18C_hornet",
@@ -1292,6 +1296,9 @@ AIRBOSS.AircraftCarrier={
S3BTANKER="S-3B Tanker", S3BTANKER="S-3B Tanker",
E2D="E-2C", E2D="E-2C",
C2A="C2A_Greyhound", C2A="C2A_Greyhound",
RHINOE="FA-18E",
RHINOF="FA-18F",
GROWLER="EA-18G",
} }
--- Carrier types. --- Carrier types.
@@ -1302,7 +1309,7 @@ AIRBOSS.AircraftCarrier={
-- @field #string STENNIS USS John C. Stennis (CVN-74) -- @field #string STENNIS USS John C. Stennis (CVN-74)
-- @field #string TRUMAN USS Harry S. Truman (CVN-75) [Super Carrier Module] -- @field #string TRUMAN USS Harry S. Truman (CVN-75) [Super Carrier Module]
-- @field #string FORRESTAL USS Forrestal (CV-59) [Heatblur 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 HERMES HMS Hermes (R12) [V/STOL Carrier]
-- @field #string INVINCIBLE HMS Invincible (R05) [V/STOL Carrier] -- @field #string INVINCIBLE HMS Invincible (R05) [V/STOL Carrier]
-- @field #string TARAWA USS Tarawa (LHA-1) [V/STOL Carrier] -- @field #string TARAWA USS Tarawa (LHA-1) [V/STOL Carrier]
@@ -5178,6 +5185,9 @@ function AIRBOSS:_GetAircraftAoA( playerData )
-- Get AC type. -- 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 goshawk = playerData.actype == AIRBOSS.AircraftCarrier.T45C
local skyhawk = playerData.actype == AIRBOSS.AircraftCarrier.A4EC local skyhawk = playerData.actype == AIRBOSS.AircraftCarrier.A4EC
local harrier = playerData.actype == AIRBOSS.AircraftCarrier.AV8B local harrier = playerData.actype == AIRBOSS.AircraftCarrier.AV8B
@@ -5341,6 +5351,9 @@ function AIRBOSS:_GetAircraftParameters( playerData, step )
-- Get AC type. -- 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 skyhawk = playerData.actype == AIRBOSS.AircraftCarrier.A4EC
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B
local harrier = playerData.actype == AIRBOSS.AircraftCarrier.AV8B local harrier = playerData.actype == AIRBOSS.AircraftCarrier.AV8B
@@ -6251,6 +6264,9 @@ function AIRBOSS:_RefuelAI( flight )
actype==AIRBOSS.AircraftCarrier.F14B or actype==AIRBOSS.AircraftCarrier.F14B or
actype==AIRBOSS.AircraftCarrier.F14A_AI or actype==AIRBOSS.AircraftCarrier.F14A_AI or
actype==AIRBOSS.AircraftCarrier.HORNET 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.FA18C or
actype==AIRBOSS.AircraftCarrier.S3B or actype==AIRBOSS.AircraftCarrier.S3B or
actype==AIRBOSS.AircraftCarrier.S3BTANKER then actype==AIRBOSS.AircraftCarrier.S3BTANKER then
@@ -6348,7 +6364,11 @@ function AIRBOSS:_LandAI( flight )
-- Aircraft speed when flying the pattern. -- Aircraft speed when flying the pattern.
local Speed = UTILS.KnotsToKmph( 200 ) 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 ) Speed = UTILS.KnotsToKmph( 200 )
elseif flight.actype == AIRBOSS.AircraftCarrier.E2D then elseif flight.actype == AIRBOSS.AircraftCarrier.E2D then
Speed = UTILS.KnotsToKmph( 150 ) Speed = UTILS.KnotsToKmph( 150 )
@@ -9172,7 +9192,13 @@ function AIRBOSS:_DirtyUp( playerData )
self:_PlayerHint( playerData ) self:_PlayerHint( playerData )
-- Radio call "Say/Fly needles". Delayed by 10/15 seconds. -- 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 callsay = self:_NewRadioCall( self.MarshalCall.SAYNEEDLES, nil, nil, 5, playerData.onboard )
local callfly = self:_NewRadioCall( self.MarshalCall.FLYNEEDLES, 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 ) self:RadioTransmission( self.MarshalRadio, callsay, false, 55, nil, true )
@@ -10263,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. -- 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 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 dcorr = 100
elseif playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B then elseif playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B then
-- TODO: Check Tomcat. -- TODO: Check Tomcat.
@@ -12463,7 +12492,10 @@ function AIRBOSS:_PlayerHint( playerData, delay, soundoff )
if playerData.step == AIRBOSS.PatternStep.BULLSEYE then if playerData.step == AIRBOSS.PatternStep.BULLSEYE then
-- Hint follow the needles. -- Hint follow the needles.
if playerData.difficulty == AIRBOSS.Difficulty.EASY then 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." ) hint = hint .. string.format( "\nIntercept glideslope and follow the needles." )
else else
hint = hint .. string.format( "\nIntercept glideslope." ) hint = hint .. string.format( "\nIntercept glideslope." )
@@ -13957,6 +13989,10 @@ function AIRBOSS:_GetACNickname( actype )
nickname = "Tomcat" nickname = "Tomcat"
elseif actype == AIRBOSS.AircraftCarrier.FA18C or actype == AIRBOSS.AircraftCarrier.HORNET then elseif actype == AIRBOSS.AircraftCarrier.FA18C or actype == AIRBOSS.AircraftCarrier.HORNET then
nickname = "Hornet" 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 elseif actype == AIRBOSS.AircraftCarrier.S3B or actype == AIRBOSS.AircraftCarrier.S3BTANKER then
nickname = "Viking" nickname = "Viking"
end end
+328 -11
View File
@@ -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 -- @module Ops.CSAR
-- @image OPS_CSAR.jpg -- @image OPS_CSAR.jpg
-- Date: October 2022 -- Date: January 2023
------------------------------------------------------------------------- -------------------------------------------------------------------------
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM --- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
@@ -114,6 +114,7 @@
-- mycsar.countryneutral = country.id.UN_PEACEKEEPERS -- mycsar.countryneutral = country.id.UN_PEACEKEEPERS
-- mycsar.topmenuname = "CSAR" -- set the menu entry name -- mycsar.topmenuname = "CSAR" -- set the menu entry name
-- mycsar.ADFRadioPwr = 1000 -- ADF Beacons sending with 1KW as default -- mycsar.ADFRadioPwr = 1000 -- ADF Beacons sending with 1KW as default
-- mycsar.PilotWeight = 80 -- Loaded pilots weigh 80kgs each
-- --
-- ## 2.1 Experimental Features -- ## 2.1 Experimental Features
-- --
@@ -197,6 +198,26 @@
-- --Create a casualty and CASEVAC request from a "Point" (VEC2) for the blue coalition --shagrat -- --Create a casualty and CASEVAC request from a "Point" (VEC2) for the blue coalition --shagrat
-- my_csar:SpawnCASEVAC(Point, coalition.side.BLUE) -- 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 -- @field #CSAR
CSAR = { CSAR = {
ClassName = "CSAR", ClassName = "CSAR",
@@ -233,6 +254,7 @@ CSAR = {
allheligroupset = nil, allheligroupset = nil,
topmenuname = "CSAR", topmenuname = "CSAR",
ADFRadioPwr = 1000, ADFRadioPwr = 1000,
PilotWeight = 80,
} }
--- Downed pilots info. --- Downed pilots info.
@@ -270,7 +292,7 @@ CSAR.AircraftType["Bronco-OV-10A"] = 2
--- CSAR class version. --- CSAR class version.
-- @field #string version -- @field #string version
CSAR.version="1.0.15" CSAR.version="1.0.17"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list -- ToDo list
@@ -278,7 +300,7 @@ CSAR.version="1.0.15"
-- DONE: SRS Integration (to be tested) -- DONE: SRS Integration (to be tested)
-- TODO: Maybe - add option to smoke/flare closest MASH -- TODO: Maybe - add option to smoke/flare closest MASH
-- TODO: shagrat Add cargoWeight to helicopter when pilot boarded -- DONE: shagrat Add cargoWeight to helicopter when pilot boarded
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor -- Constructor
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -294,6 +316,8 @@ function CSAR:New(Coalition, Template, Alias)
-- Inherit everything from FSM class. -- Inherit everything from FSM class.
local self=BASE:Inherit(self, FSM:New()) -- #CSAR local self=BASE:Inherit(self, FSM:New()) -- #CSAR
BASE:T({Coalition, Prefixes, Alias})
--set Coalition --set Coalition
if Coalition and type(Coalition)=="string" then if Coalition and type(Coalition)=="string" then
if Coalition=="blue" then if Coalition=="blue" then
@@ -344,6 +368,8 @@ function CSAR:New(Coalition, Template, Alias)
self:AddTransition("*", "Returning", "*") -- CSAR able to return to base. self:AddTransition("*", "Returning", "*") -- CSAR able to return to base.
self:AddTransition("*", "Rescued", "*") -- Pilot at MASH. self:AddTransition("*", "Rescued", "*") -- Pilot at MASH.
self:AddTransition("*", "KIA", "*") -- Pilot killed in action. 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. self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
-- tables, mainly for tracking actions -- tables, mainly for tracking actions
@@ -418,11 +444,14 @@ function CSAR:New(Coalition, Template, Alias)
self.wetfeettemplate = nil self.wetfeettemplate = nil
self.usewetfeet = false 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.allowbronco = false -- set to true to use the Bronco mod as a CSAR plane
self.ADFRadioPwr = 1000 self.ADFRadioPwr = 1000
-- added 1.0.16
self.PilotWeight = 80
-- WARNING - here\'ll be dragons -- WARNING - here\'ll be dragons
-- for this to work you need to de-sanitize your mission environment in <DCS root>\Scripts\MissionScripting.lua -- for this to work you need to de-sanitize your mission environment in <DCS root>\Scripts\MissionScripting.lua
-- needs SRS => 1.9.6 to work (works on the *server* side) -- needs SRS => 1.9.6 to work (works on the *server* side)
@@ -437,6 +466,14 @@ function CSAR:New(Coalition, Template, Alias)
self.SRSVolume = 1.0 -- volume 0.0 to 1.0 self.SRSVolume = 1.0 -- volume 0.0 to 1.0
self.SRSGender = "male" -- male or female 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 --- --- Pseudo Functions ---
------------------------ ------------------------
@@ -466,6 +503,24 @@ function CSAR:New(Coalition, Template, Alias)
-- @function [parent=#CSAR] __Status -- @function [parent=#CSAR] __Status
-- @param #CSAR self -- @param #CSAR self
-- @param #number delay Delay in seconds. -- @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. --- On After "PilotDown" event. Downed Pilot detected.
-- @function [parent=#CSAR] OnAfterPilotDown -- @function [parent=#CSAR] OnAfterPilotDown
@@ -533,6 +588,24 @@ function CSAR:New(Coalition, Template, Alias)
-- @param #string To To state. -- @param #string To To state.
-- @param #string Pilotname Name of the pilot KIA. -- @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 return self
end end
@@ -845,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. --- (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 #CSAR self
-- @param #string _Point a POINT_VEC2. -- @param Core.Point#COORDINATE _Point
-- @param #number _coalition Coalition. -- @param #number _coalition Coalition.
-- @param #string _description (optional) Description. -- @param #string _description (optional) Description.
-- @param #boolean _nomessage (optional) If true, don\'t send a message to SAR. -- @param #boolean _nomessage (optional) If true, don\'t send a message to SAR.
@@ -878,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. --- Function to add a CSAR object into the scene at a zone coordinate. For mission designers wanting to add e.g. PoWs to the scene.
-- @param #CSAR self -- @param #CSAR self
-- @param #string Point a POINT_VEC2. -- @param Core.Point#COORDINATE Point
-- @param #number Coalition Coalition. -- @param #number Coalition Coalition.
-- @param #string Description (optional) Description. -- @param #string Description (optional) Description.
-- @param #boolean addBeacon (optional) yes or no. -- @param #boolean addBeacon (optional) yes or no.
@@ -888,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. -- @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: -- @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. -- -- Create casualty "CASEVAC" at coordinate Core.Point#COORDINATE for the blue coalition.
-- my_csar:SpawnCASEVAC( POINT_VEC2, coalition.side.BLUE ) -- my_csar:SpawnCASEVAC( coordinate, coalition.side.BLUE )
function CSAR:SpawnCASEVAC(Point, Coalition, Description, Nomessage, Unitname, Typename, Forcedesc) function CSAR:SpawnCASEVAC(Point, Coalition, Description, Nomessage, Unitname, Typename, Forcedesc)
self:_SpawnCASEVAC(Point, Coalition, Description, Nomessage, Unitname, Typename, Forcedesc) self:_SpawnCASEVAC(Point, Coalition, Description, Nomessage, Unitname, Typename, Forcedesc)
return self return self
@@ -1397,7 +1470,7 @@ end
-- @return #CSAR self -- @return #CSAR self
function CSAR:_UpdateUnitCargoMass(_heliName) function CSAR:_UpdateUnitCargoMass(_heliName)
self:T(self.lid .. " _UpdateUnitCargoMass") self:T(self.lid .. " _UpdateUnitCargoMass")
local calculatedMass = self:_PilotsOnboard(_heliName)*80 local calculatedMass = self:_PilotsOnboard(_heliName)*(self.PilotWeight or 80)
local Unit = UNIT:FindByName(_heliName) local Unit = UNIT:FindByName(_heliName)
if Unit then if Unit then
Unit:SetUnitInternalCargo(calculatedMass) Unit:SetUnitInternalCargo(calculatedMass)
@@ -2103,9 +2176,10 @@ function CSAR:_AddBeaconToGroup(_group, _freq)
local _radioUnit = _group:GetUnit(1) local _radioUnit = _group:GetUnit(1)
if _radioUnit then if _radioUnit then
local Frequency = _freq -- Freq in Hertz local Frequency = _freq -- Freq in Hertz
local name = _radioUnit:GetName()
local Sound = "l10n/DEFAULT/"..self.radioSound local Sound = "l10n/DEFAULT/"..self.radioSound
local vec3 = _radioUnit:GetVec3() or _radioUnit:GetPositionVec3() or {x=0,y=0,z=0} local vec3 = _radioUnit:GetVec3() or _radioUnit:GetPositionVec3() or {x=0,y=0,z=0}
trigger.action.radioTransmission(Sound, vec3, 0, false, Frequency, self.ADFRadioPwr or 1000) -- 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
end end
return self return self
@@ -2213,7 +2287,16 @@ function CSAR:onafterStart(From, Event, To)
self.msrs:SetLabel("CSAR") self.msrs:SetLabel("CSAR")
self.SRSQueue = MSRSQUEUE:New("CSAR") self.SRSQueue = MSRSQUEUE:New("CSAR")
end end
self:__Status(-10) 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 return self
end end
@@ -2446,6 +2529,240 @@ function CSAR:onbeforeLanded(From, Event, To, HeliName, Airbase)
self:T({From, Event, To, HeliName, Airbase}) self:T({From, Event, To, HeliName, Airbase})
return self return self
end 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 -- End Ops.CSAR
-------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------
+401 -47
View File
@@ -22,7 +22,7 @@
-- @module Ops.CTLD -- @module Ops.CTLD
-- @image OPS_CTLD.jpg -- @image OPS_CTLD.jpg
-- Last Update October 2022 -- Last Update Jan 2023
do do
@@ -583,6 +583,7 @@ do
-- @field #number verbose Verbosity level. -- @field #number verbose Verbosity level.
-- @field #string lid Class id string for output to DCS log file. -- @field #string lid Class id string for output to DCS log file.
-- @field #number coalition Coalition side number, e.g. `coalition.side.RED`. -- @field #number coalition Coalition side number, e.g. `coalition.side.RED`.
-- @field #boolean debug
-- @extends Core.Fsm#FSM -- @extends Core.Fsm#FSM
--- *Combat Troop & Logistics Deployment (CTLD): Everyone wants to be a POG, until there\'s POG stuff to be done.* (Mil Saying) --- *Combat Troop & Logistics Deployment (CTLD): Everyone wants to be a POG, until there\'s POG stuff to be done.* (Mil Saying)
@@ -710,6 +711,10 @@ do
-- my_ctld.droppedbeacontimeout = 600 -- dropped beacon lasts 10 minutes -- my_ctld.droppedbeacontimeout = 600 -- dropped beacon lasts 10 minutes
-- my_ctld.usesubcats = false -- use sub-category names for crates, adds an extra menu layer in "Get Crates", useful if you have > 10 crate types. -- my_ctld.usesubcats = false -- use sub-category names for crates, adds an extra menu layer in "Get Crates", useful if you have > 10 crate types.
-- my_ctld.placeCratesAhead = false -- place crates straight ahead of the helicopter, in a random way. If true, crates are more neatly sorted. -- my_ctld.placeCratesAhead = false -- place crates straight ahead of the helicopter, in a random way. If true, crates are more neatly sorted.
-- my_ctld.nobuildinloadzones = true -- forbid players to build stuff in LOAD zones if set to `true`
-- my_ctld.movecratesbeforebuild = true -- crates must be moved once before they can be build. Set to false for direct builds.
-- my_ctld.surfacetypes = {land.SurfaceType.LAND,land.SurfaceType.ROAD,land.SurfaceType.RUNWAY,land.SurfaceType.SHALLOW_WATER} -- surfaces for loading back objects.
-- my_ctld.nobuildmenu = false -- if set to true effectively enforces to have engineers build/repair stuff for you.
-- --
-- ## 2.1 User functions -- ## 2.1 User functions
-- --
@@ -728,6 +733,7 @@ do
-- ["SA342Minigun"] = {type="SA342Minigun", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 12, cargoweightlimit = 400}, -- ["SA342Minigun"] = {type="SA342Minigun", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 12, cargoweightlimit = 400},
-- ["UH-1H"] = {type="UH-1H", crates=true, troops=true, cratelimit = 1, trooplimit = 8, length = 15, cargoweightlimit = 700}, -- ["UH-1H"] = {type="UH-1H", crates=true, troops=true, cratelimit = 1, trooplimit = 8, length = 15, cargoweightlimit = 700},
-- ["Mi-8MT"] = {type="Mi-8MT", crates=true, troops=true, cratelimit = 2, trooplimit = 12, length = 15, cargoweightlimit = 3000}, -- ["Mi-8MT"] = {type="Mi-8MT", crates=true, troops=true, cratelimit = 2, trooplimit = 12, length = 15, cargoweightlimit = 3000},
-- ["Mi-8MTV2"] = {type="Mi-8MTV2", crates=true, troops=true, cratelimit = 2, trooplimit = 12, length = 15, cargoweightlimit = 3000},
-- ["Ka-50"] = {type="Ka-50", crates=false, troops=false, cratelimit = 0, trooplimit = 0, length = 15, cargoweightlimit = 0}, -- ["Ka-50"] = {type="Ka-50", crates=false, troops=false, cratelimit = 0, trooplimit = 0, length = 15, cargoweightlimit = 0},
-- ["Mi-24P"] = {type="Mi-24P", crates=true, troops=true, cratelimit = 2, trooplimit = 8, length = 18, cargoweightlimit = 700}, -- ["Mi-24P"] = {type="Mi-24P", crates=true, troops=true, cratelimit = 2, trooplimit = 8, length = 18, cargoweightlimit = 700},
-- ["Mi-24V"] = {type="Mi-24V", crates=true, troops=true, cratelimit = 2, trooplimit = 8, length = 18, cargoweightlimit = 700}, -- ["Mi-24V"] = {type="Mi-24V", crates=true, troops=true, cratelimit = 2, trooplimit = 8, length = 18, cargoweightlimit = 700},
@@ -966,6 +972,109 @@ do
-- **Caveat:** -- **Caveat:**
-- If you use units build by multiple templates, they will effectively double on loading. Dropped crates are not saved. Current stock is not saved. -- If you use units build by multiple templates, they will effectively double on loading. Dropped crates are not saved. Current stock is not saved.
-- --
-- ## 7. Complex example - Build a complete FARP from a CTLD crate drop
--
-- Prerequisites - you need to add a cargo of type FOB to your CTLD instance, for simplification reasons we call it FOB:
--
-- my_ctld:AddCratesCargo("FARP",{"FOB"},CTLD_CARGO.Enum.FOB,2)
--
-- Also, you need to have **all statics with the fitting names** as per the script in your mission already, as we're going to copy them, and a template
-- for FARP vehicles, so -- services are goin to work (e.g. for the blue side: an unarmed humvee, two trucks and a fuel truck. Optionally add a fire fighter).
--
-- The following code will build a FARP at the coordinate the FOB was dropped and built:
--
-- -- FARP Radio. First one has 130AM, next 131 and for forth
-- local FARPFreq = 130
-- local FARPName = 1 -- numbers 1..10
--
-- local FARPClearnames = {
-- [1]="London",
-- [2]="Dallas",
-- [3]="Paris",
-- [4]="Moscow",
-- [5]="Berlin",
-- [6]="Rome",
-- [7]="Madrid",
-- [8]="Warsaw",
-- [9]="Dublin",
-- [10]="Perth",
-- }
--
-- function BuildAFARP(Coordinate)
-- local coord = Coordinate -- Core.Point#COORDINATE
--
-- local FarpName = ((FARPName-1)%10)+1
-- local FName = FARPClearnames[FarpName]
--
-- FARPFreq = FARPFreq + 1
-- FARPName = FARPName + 1
--
-- -- Create a SPAWNSTATIC object from a template static FARP object.
-- local SpawnStaticFarp=SPAWNSTATIC:NewFromStatic("Static Invisible FARP-1", country.id.USA)
--
-- -- Spawning FARPs is special in DCS. Therefore, we need to specify that this is a FARP. We also set the callsign and the frequency.
-- SpawnStaticFarp:InitFARP(FARPName, FARPFreq, 0)
-- SpawnStaticFarp:InitDead(false)
--
-- -- Spawn FARP
-- local ZoneSpawn = ZONE_RADIUS:New("FARP "..FName,Coordinate:GetVec2(),160,false)
-- local Heading = 0
-- local FarpBerlin=SpawnStaticFarp:SpawnFromZone(ZoneSpawn, Heading, "FARP "..FName)
--
-- -- ATC and services - put them 125m from the center of the zone towards North
-- local FarpVehicles = SPAWN:NewWithAlias("FARP Vehicles Template","FARP "..FName.." Technicals")
-- FarpVehicles:InitHeading(180)
-- local FarpVCoord = coord:Translate(125,0)
-- FarpVehicles:SpawnFromCoordinate(FarpVCoord)
--
-- -- We will put the rest of the statics in a nice circle around the center
-- local base = 330
-- local delta = 30
--
-- local windsock = SPAWNSTATIC:NewFromStatic("Static Windsock-1",country.id.USA)
-- local sockcoord = coord:Translate(125,base)
-- windsock:SpawnFromCoordinate(sockcoord,Heading,"Windsock "..FName)
-- base=base-delta
--
-- local fueldepot = SPAWNSTATIC:NewFromStatic("Static FARP Fuel Depot-1",country.id.USA)
-- local fuelcoord = coord:Translate(125,base)
-- fueldepot:SpawnFromCoordinate(fuelcoord,Heading,"Fueldepot "..FName)
-- base=base-delta
--
-- local ammodepot = SPAWNSTATIC:NewFromStatic("Static FARP Ammo Storage-2-1",country.id.USA)
-- local ammocoord = coord:Translate(125,base)
-- ammodepot:SpawnFromCoordinate(ammocoord,Heading,"Ammodepot "..FName)
-- base=base-delta
--
-- local CommandPost = SPAWNSTATIC:NewFromStatic("Static FARP Command Post-1",country.id.USA)
-- local CommandCoord = coord:Translate(125,base)
-- CommandPost:SpawnFromCoordinate(CommandCoord,Heading,"Command Post "..FName)
-- base=base-delta
--
-- local Tent1 = SPAWNSTATIC:NewFromStatic("Static FARP Tent-11",country.id.USA)
-- local Tent1Coord = coord:Translate(125,base)
-- Tent1:SpawnFromCoordinate(Tent1Coord,Heading,"Command Tent "..FName)
-- base=base-delta
--
-- local Tent2 = SPAWNSTATIC:NewFromStatic("Static FARP Tent-11",country.id.USA)
-- local Tent2Coord = coord:Translate(125,base)
-- Tent2:SpawnFromCoordinate(Tent2Coord,Heading,"Command Tent2 "..FName)
--
-- -- add a loadzone to CTLD
-- my_ctld:AddCTLDZone("FARP "..FName,CTLD.CargoZoneType.LOAD,SMOKECOLOR.Blue,true,true)
-- local m = MESSAGE:New(string.format("FARP %s in operation!",FName),15,"CTLD"):ToBlue()
-- end
--
-- function my_ctld:OnAfterCratesBuild(From,Event,To,Group,Unit,Vehicle)
-- local name = Vehicle:GetName()
-- if string.match(name,"FOB",1,true) then
-- local Coord = Vehicle:GetCoordinate()
-- Vehicle:Destroy(false)
-- BuildAFARP(Coord)
-- end
-- end
--
--
-- @field #CTLD -- @field #CTLD
CTLD = { CTLD = {
ClassName = "CTLD", ClassName = "CTLD",
@@ -1014,7 +1123,16 @@ CTLD = {
-- @type CTLD.ZoneBeacon -- @type CTLD.ZoneBeacon
-- @field #string name -- Name of zone for the coordinate -- @field #string name -- Name of zone for the coordinate
-- @field #number frequency -- in mHz -- @field #number frequency -- in mHz
-- @field #number modulation -- i.e.radio.modulation.FM or radio.modulation.AM -- @field #number modulation -- i.e.CTLD.RadioModulation.FM or CTLD.RadioModulation.AM
--- Radio Modulation
-- @type CTLD.RadioModulation
-- @field #number AM
-- @field #number FM
CTLD.RadioModulation = {
AM = 0,
FM = 1,
}
--- Zone Info. --- Zone Info.
-- @type CTLD.CargoZone -- @type CTLD.CargoZone
@@ -1064,8 +1182,9 @@ CTLD.UnitTypes = {
["SA342Minigun"] = {type="SA342Minigun", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 12, cargoweightlimit = 400}, ["SA342Minigun"] = {type="SA342Minigun", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 12, cargoweightlimit = 400},
["UH-1H"] = {type="UH-1H", crates=true, troops=true, cratelimit = 1, trooplimit = 8, length = 15, cargoweightlimit = 700}, ["UH-1H"] = {type="UH-1H", crates=true, troops=true, cratelimit = 1, trooplimit = 8, length = 15, cargoweightlimit = 700},
["Mi-8MTV2"] = {type="Mi-8MTV2", crates=true, troops=true, cratelimit = 2, trooplimit = 12, length = 15, cargoweightlimit = 3000}, ["Mi-8MTV2"] = {type="Mi-8MTV2", crates=true, troops=true, cratelimit = 2, trooplimit = 12, length = 15, cargoweightlimit = 3000},
["Mi-8MT"] = {type="Mi-8MTV2", crates=true, troops=true, cratelimit = 2, trooplimit = 12, length = 15, cargoweightlimit = 3000}, ["Mi-8MT"] = {type="Mi-8MT", crates=true, troops=true, cratelimit = 2, trooplimit = 12, length = 15, cargoweightlimit = 3000},
["Ka-50"] = {type="Ka-50", crates=false, troops=false, cratelimit = 0, trooplimit = 0, length = 15, cargoweightlimit = 0}, ["Ka-50"] = {type="Ka-50", crates=false, troops=false, cratelimit = 0, trooplimit = 0, length = 15, cargoweightlimit = 0},
["Ka-50_3"] = {type="Ka-50_3", crates=false, troops=false, cratelimit = 0, trooplimit = 0, length = 15, cargoweightlimit = 0},
["Mi-24P"] = {type="Mi-24P", crates=true, troops=true, cratelimit = 2, trooplimit = 8, length = 18, cargoweightlimit = 700}, ["Mi-24P"] = {type="Mi-24P", crates=true, troops=true, cratelimit = 2, trooplimit = 8, length = 18, cargoweightlimit = 700},
["Mi-24V"] = {type="Mi-24V", crates=true, troops=true, cratelimit = 2, trooplimit = 8, length = 18, cargoweightlimit = 700}, ["Mi-24V"] = {type="Mi-24V", crates=true, troops=true, cratelimit = 2, trooplimit = 8, length = 18, cargoweightlimit = 700},
["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64, length = 25, cargoweightlimit = 19000}, -- 19t cargo, 64 paratroopers. ["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64, length = 25, cargoweightlimit = 19000}, -- 19t cargo, 64 paratroopers.
@@ -1077,7 +1196,7 @@ CTLD.UnitTypes = {
--- CTLD class version. --- CTLD class version.
-- @field #string version -- @field #string version
CTLD.version="1.0.18" CTLD.version="1.0.29"
--- Instantiate a new CTLD. --- Instantiate a new CTLD.
-- @param #CTLD self -- @param #CTLD self
@@ -1160,6 +1279,7 @@ function CTLD:New(Coalition, Prefixes, Alias)
-- radio beacons -- radio beacons
self.RadioSound = "beacon.ogg" self.RadioSound = "beacon.ogg"
self.RadioPath = "l10n/DEFAULT/"
-- zones stuff -- zones stuff
self.pickupZones = {} self.pickupZones = {}
@@ -1188,6 +1308,7 @@ function CTLD:New(Coalition, Prefixes, Alias)
self.Engineers = 0 -- #number use as counter self.Engineers = 0 -- #number use as counter
self.EngineersInField = {} -- #table holds #CTLD_ENGINEERING objects self.EngineersInField = {} -- #table holds #CTLD_ENGINEERING objects
self.EngineerSearch = 2000 -- #number search distance for crates to build or repair self.EngineerSearch = 2000 -- #number search distance for crates to build or repair
self.nobuildmenu = false -- enfore engineer build only?
-- setup -- setup
self.CrateDistance = 35 -- list/load crates in this radius self.CrateDistance = 35 -- list/load crates in this radius
@@ -1242,6 +1363,11 @@ function CTLD:New(Coalition, Prefixes, Alias)
self.usesubcats = false self.usesubcats = false
self.subcats = {} self.subcats = {}
-- disallow building in loadzones
self.nobuildinloadzones = true
self.movecratesbeforebuild = true
self.surfacetypes = {land.SurfaceType.LAND,land.SurfaceType.ROAD,land.SurfaceType.RUNWAY,land.SurfaceType.SHALLOW_WATER}
local AliaS = string.gsub(self.alias," ","_") local AliaS = string.gsub(self.alias," ","_")
self.filename = string.format("CTLD_%s_Persist.csv",AliaS) self.filename = string.format("CTLD_%s_Persist.csv",AliaS)
@@ -1312,6 +1438,92 @@ function CTLD:New(Coalition, Prefixes, Alias)
-- @param #CTLD self -- @param #CTLD self
-- @param #number delay Delay in seconds. -- @param #number delay Delay in seconds.
--- FSM Function OnBeforeTroopsPickedUp.
-- @function [parent=#CTLD] OnBeforeTroopsPickedUp
-- @param #CTLD self
-- @param #string From State.
-- @param #string Event Trigger.
-- @param #string To State.
-- @param Wrapper.Group#GROUP Group Group Object.
-- @param Wrapper.Unit#UNIT Unit Unit Object.
-- @param #CTLD_CARGO Cargo Cargo troops.
-- @return #CTLD self
--- FSM Function OnBeforeTroopsExtracted.
-- @function [parent=#CTLD] OnBeforeTroopsExtracted
-- @param #CTLD self
-- @param #string From State.
-- @param #string Event Trigger.
-- @param #string To State.
-- @param Wrapper.Group#GROUP Group Group Object.
-- @param Wrapper.Unit#UNIT Unit Unit Object.
-- @param #CTLD_CARGO Cargo Cargo troops.
-- @return #CTLD self
--- FSM Function OnBeforeCratesPickedUp.
-- @function [parent=#CTLD] OnBeforeCratesPickedUp
-- @param #CTLD self
-- @param #string From State .
-- @param #string Event Trigger.
-- @param #string To State.
-- @param Wrapper.Group#GROUP Group Group Object.
-- @param Wrapper.Unit#UNIT Unit Unit Object.
-- @param #CTLD_CARGO Cargo Cargo crate.
-- @return #CTLD self
--- FSM Function OnBeforeTroopsDeployed.
-- @function [parent=#CTLD] OnBeforeTroopsDeployed
-- @param #CTLD self
-- @param #string From State.
-- @param #string Event Trigger.
-- @param #string To State.
-- @param Wrapper.Group#GROUP Group Group Object.
-- @param Wrapper.Unit#UNIT Unit Unit Object.
-- @param Wrapper.Group#GROUP Troops Troops #GROUP Object.
-- @return #CTLD self
--- FSM Function OnBeforeCratesDropped.
-- @function [parent=#CTLD] OnBeforeCratesDropped
-- @param #CTLD self
-- @param #string From State.
-- @param #string Event Trigger.
-- @param #string To State.
-- @param Wrapper.Group#GROUP Group Group Object.
-- @param Wrapper.Unit#UNIT Unit Unit Object.
-- @param #table Cargotable Table of #CTLD_CARGO objects dropped.
-- @return #CTLD self
--- FSM Function OnBeforeCratesBuild.
-- @function [parent=#CTLD] OnBeforeCratesBuild
-- @param #CTLD self
-- @param #string From State.
-- @param #string Event Trigger.
-- @param #string To State.
-- @param Wrapper.Group#GROUP Group Group Object.
-- @param Wrapper.Unit#UNIT Unit Unit Object.
-- @param Wrapper.Group#GROUP Vehicle The #GROUP object of the vehicle or FOB build.
-- @return #CTLD self
--- FSM Function OnBeforeCratesRepaired.
-- @function [parent=#CTLD] OnBeforeCratesRepaired
-- @param #CTLD self
-- @param #string From State.
-- @param #string Event Trigger.
-- @param #string To State.
-- @param Wrapper.Group#GROUP Group Group Object.
-- @param Wrapper.Unit#UNIT Unit Unit Object.
-- @param Wrapper.Group#GROUP Vehicle The #GROUP object of the vehicle or FOB repaired.
-- @return #CTLD self
--- FSM Function OnBeforeTroopsRTB.
-- @function [parent=#CTLD] OnBeforeTroopsRTB
-- @param #CTLD self
-- @param #string From State.
-- @param #string Event Trigger.
-- @param #string To State.
-- @param Wrapper.Group#GROUP Group Group Object.
-- @param Wrapper.Unit#UNIT Unit Unit Object.
--- FSM Function OnAfterTroopsPickedUp. --- FSM Function OnAfterTroopsPickedUp.
-- @function [parent=#CTLD] OnAfterTroopsPickedUp -- @function [parent=#CTLD] OnAfterTroopsPickedUp
-- @param #CTLD self -- @param #CTLD self
@@ -1548,12 +1760,54 @@ function CTLD:_SendMessage(Text, Time, Clearscreen, Group)
return self return self
end end
--- (Internal) Find a troops CTLD_CARGO object in stock
-- @param #CTLD self
-- @param #string Name of the object
-- @return #CTLD_CARGO Cargo object, nil if it cannot be found
function CTLD:_FindTroopsCargoObject(Name)
self:T(self.lid .. " _FindTroopsCargoObject")
local cargo = nil
for _,_cargo in pairs(self.Cargo_Troops)do
local cargo = _cargo -- #CTLD_CARGO
if cargo.Name == Name then
return cargo
end
end
return nil
end
--- (User) Pre-load troops into a helo, e.g. for airstart. Unit **must** be alive in-game, i.e. player has taken the slot!
-- @param #CTLD self
-- @param Wrapper.Unit#UNIT Unit The unit to load into, can be handed as Wrapper.Client#CLIENT object
-- @param #string Troopname The name of the Troops to be loaded. Must be created prior in the CTLD setup!
-- @return #CTLD self
-- @usage
-- local client = UNIT:FindByName("Helo-1-1")
-- if client and client:IsAlive() then
-- myctld:PreloadTroops(client,"Infantry")
-- end
function CTLD:PreloadTroops(Unit,Troopname)
self:T(self.lid .. " PreloadTroops")
local name = Troopname or "Unknown"
if Unit and Unit:IsAlive() then
local cargo = self:_FindTroopsCargoObject(name)
local group = Unit:GetGroup()
if cargo then
self:_LoadTroops(group,Unit,cargo,true)
else
self:E(self.lid.." Troops preload - Cargo Object "..name.." not found!")
end
end
return self
end
--- (Internal) Function to load troops into a heli. --- (Internal) Function to load troops into a heli.
-- @param #CTLD self -- @param #CTLD self
-- @param Wrapper.Group#GROUP Group -- @param Wrapper.Group#GROUP Group
-- @param Wrapper.Unit#UNIT Unit -- @param Wrapper.Unit#UNIT Unit
-- @param #CTLD_CARGO Cargotype -- @param #CTLD_CARGO Cargotype
function CTLD:_LoadTroops(Group, Unit, Cargotype) -- @param #boolean Inject
function CTLD:_LoadTroops(Group, Unit, Cargotype, Inject)
self:T(self.lid .. " _LoadTroops") self:T(self.lid .. " _LoadTroops")
-- check if we have stock -- check if we have stock
local instock = Cargotype:GetStock() local instock = Cargotype:GetStock()
@@ -1561,7 +1815,7 @@ function CTLD:_LoadTroops(Group, Unit, Cargotype)
local cgotype = Cargotype:GetType() local cgotype = Cargotype:GetType()
local cgonetmass = Cargotype:GetNetMass() local cgonetmass = Cargotype:GetNetMass()
local maxloadable = self:_GetMaxLoadableMass(Unit) local maxloadable = self:_GetMaxLoadableMass(Unit)
if type(instock) == "number" and tonumber(instock) <= 0 and tonumber(instock) ~= -1 then if type(instock) == "number" and tonumber(instock) <= 0 and tonumber(instock) ~= -1 and not Inject then
-- nothing left over -- nothing left over
self:_SendMessage(string.format("Sorry, all %s are gone!", cgoname), 10, false, Group) self:_SendMessage(string.format("Sorry, all %s are gone!", cgoname), 10, false, Group)
return self return self
@@ -1569,12 +1823,12 @@ function CTLD:_LoadTroops(Group, Unit, Cargotype)
-- landed or hovering over load zone? -- landed or hovering over load zone?
local grounded = not self:IsUnitInAir(Unit) local grounded = not self:IsUnitInAir(Unit)
local hoverload = self:CanHoverLoad(Unit) local hoverload = self:CanHoverLoad(Unit)
--local dooropen = UTILS.IsLoadingDoorOpen(Unit:GetName()) and self.pilotmustopendoors
-- check if we are in LOAD zone -- check if we are in LOAD zone
local inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD) local inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD)
if not inzone then if not inzone then
inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.SHIP) inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.SHIP)
end end
if not Inject then
if not inzone then if not inzone then
self:_SendMessage("You are not close enough to a logistics zone!", 10, false, Group) self:_SendMessage("You are not close enough to a logistics zone!", 10, false, Group)
if not self.debug then return self end if not self.debug then return self end
@@ -1585,6 +1839,7 @@ function CTLD:_LoadTroops(Group, Unit, Cargotype)
self:_SendMessage("You need to open the door(s) to load troops!", 10, false, Group) self:_SendMessage("You need to open the door(s) to load troops!", 10, false, Group)
if not self.debug then return self end if not self.debug then return self end
end end
end
-- load troops into heli -- load troops into heli
local group = Group -- Wrapper.Group#GROUP local group = Group -- Wrapper.Group#GROUP
local unit = Unit -- Wrapper.Unit#UNIT local unit = Unit -- Wrapper.Unit#UNIT
@@ -2006,10 +2261,11 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop)
self.CargoCounter = self.CargoCounter + 1 self.CargoCounter = self.CargoCounter + 1
local realcargo = nil local realcargo = nil
if drop then if drop then
realcargo = CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,true,false,cratesneeded,self.Spawned_Crates[self.CrateCounter],true,cargotype.PerCrateMass,subcat) --CTLD_CARGO:New(ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped, PerCrateMass, Stock, Subcategory)
realcargo = CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,true,false,cratesneeded,self.Spawned_Crates[self.CrateCounter],true,cargotype.PerCrateMass,nil,subcat)
table.insert(droppedcargo,realcargo) table.insert(droppedcargo,realcargo)
else else
realcargo = CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,false,false,cratesneeded,self.Spawned_Crates[self.CrateCounter],true,cargotype.PerCrateMass,subcat) realcargo = CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,false,false,cratesneeded,self.Spawned_Crates[self.CrateCounter],false,cargotype.PerCrateMass,nil,subcat)
Cargo:RemoveStock() Cargo:RemoveStock()
end end
table.insert(self.Spawned_Cargo, realcargo) table.insert(self.Spawned_Cargo, realcargo)
@@ -2590,9 +2846,7 @@ function CTLD:_UnloadTroops(Group, Unit)
:InitRandomizeUnits(true,20,2) :InitRandomizeUnits(true,20,2)
:InitDelayOff() :InitDelayOff()
:SpawnFromVec2(randomcoord) :SpawnFromVec2(randomcoord)
if self.movetroopstowpzone and type ~= CTLD_CARGO.Enum.ENGINEERS then self:__TroopsDeployed(1, Group, Unit, self.DroppedTroops[self.TroopCounter],type)
self:_MoveGroupToZone(self.DroppedTroops[self.TroopCounter])
end
end -- template loop end -- template loop
cargo:SetWasDropped(true) cargo:SetWasDropped(true)
-- engineering group? -- engineering group?
@@ -2604,7 +2858,6 @@ function CTLD:_UnloadTroops(Group, Unit)
else else
self:_SendMessage(string.format("Dropped Troops %s into action!",name), 10, false, Group) self:_SendMessage(string.format("Dropped Troops %s into action!",name), 10, false, Group)
end end
self:__TroopsDeployed(1, Group, Unit, self.DroppedTroops[self.TroopCounter])
end -- if type end end -- if type end
end -- cargotable loop end -- cargotable loop
else -- droppingatbase else -- droppingatbase
@@ -2740,6 +2993,14 @@ function CTLD:_BuildCrates(Group, Unit,Engineering)
return self return self
end end
end end
if not Engineering and self.nobuildinloadzones then
-- are we in a load zone?
local inloadzone = self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD)
if inloadzone then
self:_SendMessage("You cannot build in a loading area, Pilot!", 10, false, Group)
return self
end
end
-- get nearby crates -- get nearby crates
local finddist = self.CrateDistance or 35 local finddist = self.CrateDistance or 35
local crates,number = self:_FindCratesNearby(Group,Unit, finddist,true) -- #table local crates,number = self:_FindCratesNearby(Group,Unit, finddist,true) -- #table
@@ -2750,7 +3011,7 @@ function CTLD:_BuildCrates(Group, Unit,Engineering)
-- get dropped crates -- get dropped crates
for _,_crate in pairs(crates) do for _,_crate in pairs(crates) do
local Crate = _crate -- #CTLD_CARGO local Crate = _crate -- #CTLD_CARGO
if Crate:WasDropped() and not Crate:IsRepair() and not Crate:IsStatic() then if (Crate:WasDropped() or not self.movecratesbeforebuild) and not Crate:IsRepair() and not Crate:IsStatic() then
-- we can build these - maybe -- we can build these - maybe
local name = Crate:GetName() local name = Crate:GetName()
local required = Crate:GetCratesNeeded() local required = Crate:GetCratesNeeded()
@@ -2795,7 +3056,12 @@ function CTLD:_BuildCrates(Group, Unit,Engineering)
local text = string.format("Type: %s | Required %d | Found %d | Can Build %s", name, needed, found, txtok) local text = string.format("Type: %s | Required %d | Found %d | Can Build %s", name, needed, found, txtok)
report:Add(text) report:Add(text)
end -- end list buildables end -- end list buildables
if not foundbuilds then report:Add(" --- None Found ---") end if not foundbuilds then
report:Add(" --- None found! ---")
if self.movecratesbeforebuild then
report:Add("*** Crates need to be moved before building!")
end
end
report:Add("------------------------------------------------------------") report:Add("------------------------------------------------------------")
local text = report:Text() local text = report:Text()
if not Engineering then if not Engineering then
@@ -2958,9 +3224,6 @@ function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation)
:InitDelayOff() :InitDelayOff()
:SpawnFromVec2(randomcoord) :SpawnFromVec2(randomcoord)
end end
if self.movetroopstowpzone and canmove then
self:_MoveGroupToZone(self.DroppedTroops[self.TroopCounter])
end
if Repair then if Repair then
self:__CratesRepaired(1,Group,Unit,self.DroppedTroops[self.TroopCounter]) self:__CratesRepaired(1,Group,Unit,self.DroppedTroops[self.TroopCounter])
else else
@@ -3063,6 +3326,12 @@ function CTLD:_RefreshF10Menus()
self.subcats[entry.Subcategory] = entry.Subcategory self.subcats[entry.Subcategory] = entry.Subcategory
end end
end end
for _id,_cargo in pairs(self.Cargo_Statics) do
local entry = _cargo -- #CTLD_CARGO
if not self.subcats[entry.Subcategory] then
self.subcats[entry.Subcategory] = entry.Subcategory
end
end
end end
-- build unit menus -- build unit menus
@@ -3126,6 +3395,13 @@ function CTLD:_RefreshF10Menus()
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0) local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,subcatmenus[subcat],self._GetCrates, self, _group, _unit, entry) menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,subcatmenus[subcat],self._GetCrates, self, _group, _unit, entry)
end end
for _,_entry in pairs(self.Cargo_Statics) do
local entry = _entry -- #CTLD_CARGO
local subcat = entry.Subcategory
menucount = menucount + 1
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,subcatmenus[subcat],self._GetCrates, self, _group, _unit, entry)
end
else else
for _,_entry in pairs(self.Cargo_Crates) do for _,_entry in pairs(self.Cargo_Crates) do
local entry = _entry -- #CTLD_CARGO local entry = _entry -- #CTLD_CARGO
@@ -3133,17 +3409,21 @@ function CTLD:_RefreshF10Menus()
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0) local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrates, self, _group, _unit, entry) menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrates, self, _group, _unit, entry)
end end
end
for _,_entry in pairs(self.Cargo_Statics) do for _,_entry in pairs(self.Cargo_Statics) do
local entry = _entry -- #CTLD_CARGO local entry = _entry -- #CTLD_CARGO
menucount = menucount + 1 menucount = menucount + 1
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0) local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrates, self, _group, _unit, entry) menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrates, self, _group, _unit, entry)
end end
end
listmenu = MENU_GROUP_COMMAND:New(_group,"List crates nearby",topcrates, self._ListCratesNearby, self, _group, _unit) listmenu = MENU_GROUP_COMMAND:New(_group,"List crates nearby",topcrates, self._ListCratesNearby, self, _group, _unit)
local unloadmenu = MENU_GROUP_COMMAND:New(_group,"Drop crates",topcrates, self._UnloadCrates, self, _group, _unit) local unloadmenu = MENU_GROUP_COMMAND:New(_group,"Drop crates",topcrates, self._UnloadCrates, self, _group, _unit)
if not self.nobuildmenu then
local buildmenu = MENU_GROUP_COMMAND:New(_group,"Build crates",topcrates, self._BuildCrates, self, _group, _unit) local buildmenu = MENU_GROUP_COMMAND:New(_group,"Build crates",topcrates, self._BuildCrates, self, _group, _unit)
local repairmenu = MENU_GROUP_COMMAND:New(_group,"Repair",topcrates, self._RepairCrates, self, _group, _unit):Refresh() local repairmenu = MENU_GROUP_COMMAND:New(_group,"Repair",topcrates, self._RepairCrates, self, _group, _unit):Refresh()
else
unloadmenu:Refresh()
end
end end
if self:IsHercules(_unit) then if self:IsHercules(_unit) then
local hoverpars = MENU_GROUP_COMMAND:New(_group,"Show flight parameters",topmenu, self._ShowFlightParams, self, _group, _unit):Refresh() local hoverpars = MENU_GROUP_COMMAND:New(_group,"Show flight parameters",topmenu, self._ShowFlightParams, self, _group, _unit):Refresh()
@@ -3228,13 +3508,14 @@ end
-- @param #string Name Unique name of this type of cargo as set in the mission editor (note: UNIT name!), e.g. "Ammunition-1". -- @param #string Name Unique name of this type of cargo as set in the mission editor (note: UNIT name!), e.g. "Ammunition-1".
-- @param #number Mass Mass in kg of each static in kg, e.g. 100. -- @param #number Mass Mass in kg of each static in kg, e.g. 100.
-- @param #number Stock Number of groups in stock. Nil for unlimited. -- @param #number Stock Number of groups in stock. Nil for unlimited.
function CTLD:AddStaticsCargo(Name,Mass,Stock) -- @param #string SubCategory Name of sub-category (optional).
function CTLD:AddStaticsCargo(Name,Mass,Stock,SubCategory)
self:T(self.lid .. " AddStaticsCargo") self:T(self.lid .. " AddStaticsCargo")
self.CargoCounter = self.CargoCounter + 1 self.CargoCounter = self.CargoCounter + 1
local type = CTLD_CARGO.Enum.STATIC local type = CTLD_CARGO.Enum.STATIC
local template = STATIC:FindByName(Name,true):GetTypeName() local template = STATIC:FindByName(Name,true):GetTypeName()
-- Crates are not directly loadable -- Crates are not directly loadable
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,template,type,false,false,1,nil,nil,Mass,Stock) local cargo = CTLD_CARGO:New(self.CargoCounter,Name,template,type,false,false,1,nil,nil,Mass,Stock,SubCategory)
table.insert(self.Cargo_Statics,cargo) table.insert(self.Cargo_Statics,cargo)
return self return self
end end
@@ -3359,7 +3640,7 @@ function CTLD:_GetFMBeacon(Name)
table.insert(self.UsedFMFrequencies, FM) table.insert(self.UsedFMFrequencies, FM)
beacon.name = Name beacon.name = Name
beacon.frequency = FM / 1000000 beacon.frequency = FM / 1000000
beacon.modulation = radio.modulation.FM beacon.modulation = CTLD.RadioModulation.FM
return beacon return beacon
end end
@@ -3379,7 +3660,7 @@ function CTLD:_GetUHFBeacon(Name)
table.insert(self.UsedUHFFrequencies, UHF) table.insert(self.UsedUHFFrequencies, UHF)
beacon.name = Name beacon.name = Name
beacon.frequency = UHF / 1000000 beacon.frequency = UHF / 1000000
beacon.modulation = radio.modulation.AM beacon.modulation = CTLD.RadioModulation.AM
return beacon return beacon
end end
@@ -3400,7 +3681,7 @@ function CTLD:_GetVHFBeacon(Name)
table.insert(self.UsedVHFFrequencies, VHF) table.insert(self.UsedVHFFrequencies, VHF)
beacon.name = Name beacon.name = Name
beacon.frequency = VHF / 1000000 beacon.frequency = VHF / 1000000
beacon.modulation = radio.modulation.FM beacon.modulation = CTLD.RadioModulation.FM
return beacon return beacon
end end
@@ -3442,6 +3723,11 @@ function CTLD:AddCTLDZone(Name, Type, Color, Active, HasBeacon, Shiplength, Ship
ctldzone.type = Type or CTLD.CargoZoneType.MOVE -- #CTLD.CargoZoneType ctldzone.type = Type or CTLD.CargoZoneType.MOVE -- #CTLD.CargoZoneType
ctldzone.hasbeacon = HasBeacon or false ctldzone.hasbeacon = HasBeacon or false
if Type == CTLD.CargoZoneType.BEACON then
self.droppedbeaconref[ctldzone.name] = zone:GetCoordinate()
ctldzone.timestamp = timer.getTime()
end
if HasBeacon then if HasBeacon then
ctldzone.fmbeacon = self:_GetFMBeacon(Name) ctldzone.fmbeacon = self:_GetFMBeacon(Name)
ctldzone.uhfbeacon = self:_GetUHFBeacon(Name) ctldzone.uhfbeacon = self:_GetUHFBeacon(Name)
@@ -3530,6 +3816,7 @@ function CTLD:CheckDroppedBeacons()
for _,_beacon in pairs (self.droppedBeacons) do for _,_beacon in pairs (self.droppedBeacons) do
local beacon = _beacon -- #CTLD.CargoZone local beacon = _beacon -- #CTLD.CargoZone
if not beacon.timestamp then beacon.timestamp = timer.getTime() + timeout end
local T0 = beacon.timestamp local T0 = beacon.timestamp
if timer.getTime() - T0 > timeout then if timer.getTime() - T0 > timeout then
local name = beacon.name local name = beacon.name
@@ -3601,19 +3888,50 @@ function CTLD:_AddRadioBeacon(Name, Sound, Mhz, Modulation, IsShip, IsDropped)
end end
end end
local Sound = Sound or "beacon.ogg" local Sound = Sound or "beacon.ogg"
if IsDropped and Zone then if Zone then
if IsDropped then
local ZoneCoord = Zone local ZoneCoord = Zone
local ZoneVec3 = ZoneCoord:GetVec3() local ZoneVec3 = ZoneCoord:GetVec3() or {x=0,y=0,z=0}
local Frequency = Mhz * 1000000 -- Freq in Hertz local Frequency = Mhz * 1000000 -- Freq in Hertz
local Sound = "l10n/DEFAULT/"..Sound local Sound = self.RadioPath..Sound
trigger.action.radioTransmission(Sound, ZoneVec3, Modulation, false, Frequency, 1000) -- Beacon in MP only runs for 30secs straight trigger.action.radioTransmission(Sound, ZoneVec3, Modulation, false, Frequency, 1000, Name..math.random(1,10000)) -- Beacon in MP only runs for 30secs straight
elseif Zone then self:T2(string.format("Beacon added | Name = %s | Sound = %s | Vec3 = %d %d %d | Freq = %f | Modulation = %d (0=AM/1=FM)",Name,Sound,ZoneVec3.x,ZoneVec3.y,ZoneVec3.z,Mhz,Modulation))
else
local ZoneCoord = Zone:GetCoordinate() local ZoneCoord = Zone:GetCoordinate()
local ZoneVec3 = ZoneCoord:GetVec3() local ZoneVec3 = ZoneCoord:GetVec3() or {x=0,y=0,z=0}
local Frequency = Mhz * 1000000 -- Freq in Hertz local Frequency = Mhz * 1000000 -- Freq in Hert
local Sound = "l10n/DEFAULT/"..Sound local Sound = self.RadioPath..Sound
trigger.action.radioTransmission(Sound, ZoneVec3, Modulation, false, Frequency, 1000) -- Beacon in MP only runs for 30secs straight trigger.action.radioTransmission(Sound, ZoneVec3, Modulation, false, Frequency, 1000, Name..math.random(1,10000)) -- Beacon in MP only runs for 30secs straightt
self:T2(string.format("Beacon added | Name = %s | Sound = %s | Vec3 = {x=%d, y=%d, z=%d} | Freq = %f | Modulation = %d (0=AM/1=FM)",Name,Sound,ZoneVec3.x,ZoneVec3.y,ZoneVec3.z,Mhz,Modulation))
end end
else
self:E(self.lid.."***** _AddRadioBeacon: Zone does not exist: "..Name)
end
return self
end
--- Set folder path where the CTLD sound files are located **within you mission (miz) file**.
-- The default path is "l10n/DEFAULT/" but sound files simply copied there will be removed by DCS the next time you save the mission.
-- However, if you create a new folder inside the miz file, which contains the sounds, it will not be deleted and can be used.
-- @param #CTLD self
-- @param #string FolderPath The path to the sound files, e.g. "CTLD_Soundfiles/".
-- @return #CTLD self
function CTLD:SetSoundfilesFolder( FolderPath )
self:T(self.lid .. " SetSoundfilesFolder")
-- Check that it ends with /
if FolderPath then
local lastchar = string.sub( FolderPath, -1 )
if lastchar ~= "/" then
FolderPath = FolderPath .. "/"
end
end
-- Folderpath.
self.RadioPath = FolderPath
-- Info message.
self:I( self.lid .. string.format( "Setting sound files folder to: %s", self.RadioPath ) )
return self return self
end end
@@ -3640,9 +3958,9 @@ function CTLD:_RefreshRadioBeacons()
local FM = FMbeacon.frequency -- MHz local FM = FMbeacon.frequency -- MHz
local VHF = VHFbeacon.frequency -- KHz local VHF = VHFbeacon.frequency -- KHz
local UHF = UHFbeacon.frequency -- MHz local UHF = UHFbeacon.frequency -- MHz
self:_AddRadioBeacon(Name,Sound,FM,radio.modulation.FM, IsShip, IsDropped) self:_AddRadioBeacon(Name,Sound,FM, CTLD.RadioModulation.FM, IsShip, IsDropped)
self:_AddRadioBeacon(Name,Sound,VHF,radio.modulation.FM, IsShip, IsDropped) self:_AddRadioBeacon(Name,Sound,VHF,CTLD.RadioModulation.FM, IsShip, IsDropped)
self:_AddRadioBeacon(Name,Sound,UHF,radio.modulation.AM, IsShip, IsDropped) self:_AddRadioBeacon(Name,Sound,UHF,CTLD.RadioModulation.AM, IsShip, IsDropped)
end end
end end
end end
@@ -4154,6 +4472,8 @@ end
-- @param #CTLD self -- @param #CTLD self
-- @param Core.Zone#ZONE Zone The zone where to drop the troops. -- @param Core.Zone#ZONE Zone The zone where to drop the troops.
-- @param Ops.CTLD#CTLD_CARGO Cargo The #CTLD_CARGO object to spawn. -- @param Ops.CTLD#CTLD_CARGO Cargo The #CTLD_CARGO object to spawn.
-- @param #table Surfacetypes (Optional) Table of surface types. Can also be a single surface type. We will try max 1000 times to find the right type!
-- @param #boolean PreciseLocation (Optional) Don't try to get a random position in the zone but use the dead center. Caution not to stack up stuff on another!
-- @return #CTLD self -- @return #CTLD self
-- @usage Use this function to pre-populate the field with Troops or Engineers at a random coordinate in a zone: -- @usage Use this function to pre-populate the field with Troops or Engineers at a random coordinate in a zone:
-- -- create a matching #CTLD_CARGO type -- -- create a matching #CTLD_CARGO type
@@ -4161,8 +4481,8 @@ end
-- -- get a #ZONE object -- -- get a #ZONE object
-- local dropzone = ZONE:New("InjectZone") -- Core.Zone#ZONE -- local dropzone = ZONE:New("InjectZone") -- Core.Zone#ZONE
-- -- and go: -- -- and go:
-- my_ctld:InjectTroops(dropzone,InjectTroopsType) -- my_ctld:InjectTroops(dropzone,InjectTroopsType,{land.SurfaceType.LAND})
function CTLD:InjectTroops(Zone,Cargo) function CTLD:InjectTroops(Zone,Cargo,Surfacetypes,PreciseLocation)
self:T(self.lid.." InjectTroops") self:T(self.lid.." InjectTroops")
local cargo = Cargo -- #CTLD_CARGO local cargo = Cargo -- #CTLD_CARGO
@@ -4194,8 +4514,10 @@ end
local temptable = cargo:GetTemplates() or {} local temptable = cargo:GetTemplates() or {}
local factor = 1.5 local factor = 1.5
local zone = Zone local zone = Zone
local randomcoord = zone:GetRandomCoordinate(10,30*factor,Surfacetypes):GetVec2()
local randomcoord = zone:GetRandomCoordinate(10,30*factor):GetVec2() if PreciseLocation then
randomcoord = zone:GetCoordinate():GetVec2()
end
for _,_template in pairs(temptable) do for _,_template in pairs(temptable) do
self.TroopCounter = self.TroopCounter + 1 self.TroopCounter = self.TroopCounter + 1
local alias = string.format("%s-%d", _template, math.random(1,100000)) local alias = string.format("%s-%d", _template, math.random(1,100000))
@@ -4215,7 +4537,7 @@ end
self.EngineersInField[self.Engineers] = CTLD_ENGINEERING:New(name, grpname) self.EngineersInField[self.Engineers] = CTLD_ENGINEERING:New(name, grpname)
end end
if self.eventoninject then if self.eventoninject then
self:__TroopsDeployed(1,nil,nil,self.DroppedTroops[self.TroopCounter]) self:__TroopsDeployed(1,nil,nil,self.DroppedTroops[self.TroopCounter],type)
end end
end -- if type end end -- if type end
return self return self
@@ -4282,9 +4604,6 @@ end
:InitDelayOff() :InitDelayOff()
:SpawnFromVec2(randomcoord) :SpawnFromVec2(randomcoord)
end end
if self.movetroopstowpzone and canmove then
self:_MoveGroupToZone(self.DroppedTroops[self.TroopCounter])
end
if self.eventoninject then if self.eventoninject then
self:__CratesBuild(1,nil,nil,self.DroppedTroops[self.TroopCounter]) self:__CratesBuild(1,nil,nil,self.DroppedTroops[self.TroopCounter])
end end
@@ -4491,6 +4810,24 @@ end
return self return self
end end
--- (Internal) FSM Function onafterTroopsDeployed.
-- @param #CTLD self
-- @param #string From State.
-- @param #string Event Trigger.
-- @param #string To State.
-- @param Wrapper.Group#GROUP Group Group Object.
-- @param Wrapper.Unit#UNIT Unit Unit Object.
-- @param Wrapper.Group#GROUP Troops Troops #GROUP Object.
-- @param #CTLD.CargoZoneType Type Type of Cargo deployed
-- @return #CTLD self
function CTLD:onafterTroopsDeployed(From, Event, To, Group, Unit, Troops, Type)
self:T({From, Event, To})
if self.movetroopstowpzone and Type ~= CTLD_CARGO.Enum.ENGINEERS then
self:_MoveGroupToZone(Troops)
end
return self
end
--- (Internal) FSM Function onbeforeCratesDropped. --- (Internal) FSM Function onbeforeCratesDropped.
-- @param #CTLD self -- @param #CTLD self
-- @param #string From State. -- @param #string From State.
@@ -4515,7 +4852,7 @@ end
-- @param Wrapper.Group#GROUP Vehicle The #GROUP object of the vehicle or FOB build. -- @param Wrapper.Group#GROUP Vehicle The #GROUP object of the vehicle or FOB build.
-- @return #CTLD self -- @return #CTLD self
function CTLD:onbeforeCratesBuild(From, Event, To, Group, Unit, Vehicle) function CTLD:onbeforeCratesBuild(From, Event, To, Group, Unit, Vehicle)
self:I({From, Event, To}) self:T({From, Event, To})
if Unit and Unit:IsPlayer() and self.PlayerTaskQueue then if Unit and Unit:IsPlayer() and self.PlayerTaskQueue then
local playername = Unit:GetPlayerName() local playername = Unit:GetPlayerName()
local dropcoord = Vehicle:GetCoordinate() or COORDINATE:New(0,0,0) local dropcoord = Vehicle:GetCoordinate() or COORDINATE:New(0,0,0)
@@ -4540,6 +4877,23 @@ end
return self return self
end end
--- (Internal) FSM Function onafterCratesBuild.
-- @param #CTLD self
-- @param #string From State.
-- @param #string Event Trigger.
-- @param #string To State.
-- @param Wrapper.Group#GROUP Group Group Object.
-- @param Wrapper.Unit#UNIT Unit Unit Object.
-- @param Wrapper.Group#GROUP Vehicle The #GROUP object of the vehicle or FOB build.
-- @return #CTLD self
function CTLD:onafterCratesBuild(From, Event, To, Group, Unit, Vehicle)
self:T({From, Event, To})
if self.movetroopstowpzone then
self:_MoveGroupToZone(Vehicle)
end
return self
end
--- (Internal) FSM Function onbeforeTroopsRTB. --- (Internal) FSM Function onbeforeTroopsRTB.
-- @param #CTLD self -- @param #CTLD self
-- @param #string From State. -- @param #string From State.
@@ -4624,7 +4978,7 @@ end
for _,_cargo in pairs (stcstable) do for _,_cargo in pairs (stcstable) do
local cargo = _cargo -- #CTLD_CARGO local cargo = _cargo -- #CTLD_CARGO
local object = cargo:GetPositionable() -- Wrapper.Static#STATIC local object = cargo:GetPositionable() -- Wrapper.Static#STATIC
if object and object:IsAlive() and cargo:WasDropped() then if object and object:IsAlive() and (cargo:WasDropped() or not cargo:HasMoved()) then
statics[#statics+1] = cargo statics[#statics+1] = cargo
end end
end end
@@ -4865,7 +5219,7 @@ end
self:InjectVehicles(dropzone,injectvehicle) self:InjectVehicles(dropzone,injectvehicle)
elseif cargotype == CTLD_CARGO.Enum.TROOPS or cargotype == CTLD_CARGO.Enum.ENGINEERS then elseif cargotype == CTLD_CARGO.Enum.TROOPS or cargotype == CTLD_CARGO.Enum.ENGINEERS then
local injecttroops = CTLD_CARGO:New(nil,cargoname,cargotemplates,cargotype,true,true,size,nil,true,mass) local injecttroops = CTLD_CARGO:New(nil,cargoname,cargotemplates,cargotype,true,true,size,nil,true,mass)
self:InjectTroops(dropzone,injecttroops) self:InjectTroops(dropzone,injecttroops,self.surfacetypes)
end end
elseif (type(groupname) == "string" and groupname == "STATIC") or cargotype == CTLD_CARGO.Enum.REPAIR then elseif (type(groupname) == "string" and groupname == "STATIC") or cargotype == CTLD_CARGO.Enum.REPAIR then
local cargotemplates = dataset[6] local cargotemplates = dataset[6]
@@ -512,7 +512,7 @@ function COMMANDCENTER:AssignTask( TaskGroup )
if Task then 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 if not self.AutoAcceptTasks == true then
Task:SetAutoAssignMethod( ACT_ASSIGN_MENU_ACCEPT:New( Task.TaskBriefing ) ) Task:SetAutoAssignMethod( ACT_ASSIGN_MENU_ACCEPT:New( Task.TaskBriefing ) )
+4 -4
View File
@@ -413,7 +413,7 @@ end
-- @param Wrapper.Group#GROUP PlayerGroup The GROUP of the player joining the Mission. -- @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. -- @return #boolean true if Unit is part of a Task in the Mission.
function MISSION:JoinUnit( PlayerUnit, PlayerGroup ) 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 local PlayerUnitAdded = false
@@ -571,7 +571,7 @@ do -- Group Assignment
local MissionGroupName = MissionGroup:GetName() local MissionGroupName = MissionGroup:GetName()
self.AssignedGroups[MissionGroupName] = MissionGroup 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 return self
end end
@@ -698,7 +698,7 @@ end
function MISSION:AddTask( Task ) function MISSION:AddTask( Task )
local TaskName = Task:GetTaskName() 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 self.Tasks[TaskName] = Task
@@ -717,7 +717,7 @@ end
function MISSION:RemoveTask( Task ) function MISSION:RemoveTask( Task )
local TaskName = Task:GetTaskName() 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:F( TaskName )
self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 } self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 }
+339 -39
View File
@@ -606,10 +606,12 @@ end
-- acc- the accuracy of each easting/northing. 0, 1, 2, 3, 4, or 5. -- acc- the accuracy of each easting/northing. 0, 1, 2, 3, 4, or 5.
UTILS.tostringMGRS = function(MGRS, acc) --R2.1 UTILS.tostringMGRS = function(MGRS, acc) --R2.1
if acc == 0 then if acc <= 0 then
return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph
else else
if acc > 5 then acc = 5 end
-- Test if Easting/Northing have less than 4 digits. -- Test if Easting/Northing have less than 4 digits.
--MGRS.Easting=123 -- should be 00123 --MGRS.Easting=123 -- should be 00123
--MGRS.Northing=5432 -- should be 05432 --MGRS.Northing=5432 -- should be 05432
@@ -1059,8 +1061,8 @@ function UTILS.Vec2Norm(a)
end end
--- Calculate the distance between two 2D vectors. --- Calculate the distance between two 2D vectors.
-- @param DCS#Vec2 a Vector in 3D with x, y components. -- @param DCS#Vec2 a Vector in 2D with x, y components.
-- @param DCS#Vec2 b Vector in 3D with x, y components. -- @param DCS#Vec2 b Vector in 2D with x, y components.
-- @return #number Distance between the vectors. -- @return #number Distance between the vectors.
function UTILS.VecDist2D(a, b) function UTILS.VecDist2D(a, b)
@@ -1444,6 +1446,30 @@ function UTILS.GetCoalitionName(Coalition)
end end
--- Get the enemy coalition for a given coalition.
-- @param #number Coalition The coalition ID.
-- @param #boolean Neutral Include neutral as enemy.
-- @return #table Enemy coalition table.
function UTILS.GetCoalitionEnemy(Coalition, Neutral)
local Coalitions={}
if Coalition then
if Coalition==coalition.side.RED then
Coalitions={coalition.side.BLUE}
elseif Coalition==coalition.side.BLUE then
Coalitions={coalition.side.RED}
elseif Coalition==coalition.side.NEUTRAL then
Coalitions={coalition.side.RED, coalition.side.BLUE}
end
end
if Neutral then
table.insert(Coalitions, coalition.side.NEUTRAL)
end
return Coalitions
end
--- Get the modulation name from its numerical value. --- Get the modulation name from its numerical value.
-- @param #number Modulation The modulation enumerator number. Can be either 0 or 1. -- @param #number Modulation The modulation enumerator number. Can be either 0 or 1.
-- @return #string The modulation name, i.e. "AM"=0 or "FM"=1. Anything else will return "Unknown". -- @return #string The modulation name, i.e. "AM"=0 or "FM"=1. Anything else will return "Unknown".
@@ -1574,6 +1600,8 @@ function UTILS.GMTToLocalTimeDifference()
return 3 -- Damascus is UTC+3 hours return 3 -- Damascus is UTC+3 hours
elseif theatre==DCSMAP.MarianaIslands then elseif theatre==DCSMAP.MarianaIslands then
return 10 -- Guam is UTC+10 hours. return 10 -- Guam is UTC+10 hours.
elseif theatre==DCSMAP.Falklands then
return -3 -- Fireland is UTC-3 hours.
else else
BASE:E(string.format("ERROR: Unknown Map %s in UTILS.GMTToLocal function. Returning 0", tostring(theatre))) BASE:E(string.format("ERROR: Unknown Map %s in UTILS.GMTToLocal function. Returning 0", tostring(theatre)))
return 0 return 0
@@ -1905,7 +1933,7 @@ function UTILS.GenerateVHFrequencies()
705,720,722,730,735,740,745,750,770,795, 705,720,722,730,735,740,745,750,770,795,
822,830,862,866, 822,830,862,866,
905,907,920,935,942,950,995, 905,907,920,935,942,950,995,
1000,1025,1030,1050,1065,1116,1175,1182,1210 1000,1025,1030,1050,1065,1116,1175,1182,1210,1215
} }
local FreeVHFFrequencies = {} local FreeVHFFrequencies = {}
@@ -1973,7 +2001,9 @@ function UTILS.GenerateUHFrequencies()
local _start = 220000000 local _start = 220000000
while _start < 399000000 do while _start < 399000000 do
if _start ~= 243000000 then
table.insert(FreeUHFFrequencies, _start) table.insert(FreeUHFFrequencies, _start)
end
_start = _start + 500000 _start = _start + 500000
end end
@@ -2173,10 +2203,29 @@ function UTILS.CheckFileExists(Path,Filename)
end end
end end
--- Function to obtain a table of typenames from the group given with the number of units of the same type in the group.
-- @param Wrapper.Group#GROUP Group The group to list
-- @return #table Table of typnames and typename counts, e.g. `{["KAMAZ Truck"]=3,["ATZ-5"]=1}`
function UTILS.GetCountPerTypeName(Group)
local units = Group:GetUnits()
local TypeNameTable = {}
for _,_unt in pairs (units) do
local unit = _unt -- Wrapper.Unit#UNIT
local typen = unit:GetTypeName()
if not TypeNameTable[typen] then
TypeNameTable[typen] = 1
else
TypeNameTable[typen] = TypeNameTable[typen] + 1
end
end
return TypeNameTable
end
--- Function to save the state of a list of groups found by name --- Function to save the state of a list of groups found by name
-- @param #table List Table of strings with groupnames -- @param #table List Table of strings with groupnames
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems. -- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
-- @param #string Filename The name of the file. -- @param #string Filename The name of the file.
-- @param #boolean Structured Append the data with a list of typenames in the group plus their count.
-- @return #boolean outcome True if saving is successful, else false. -- @return #boolean outcome True if saving is successful, else false.
-- @usage -- @usage
-- We will go through the list and find the corresponding group and save the current group size (0 when dead). -- We will go through the list and find the corresponding group and save the current group size (0 when dead).
@@ -2184,7 +2233,7 @@ end
-- Position is still saved for your usage. -- Position is still saved for your usage.
-- The idea is to reduce the number of units when reloading the data again to restart the saved mission. -- The idea is to reduce the number of units when reloading the data again to restart the saved mission.
-- The data will be a simple comma separated list of groupname and size, with one header line. -- The data will be a simple comma separated list of groupname and size, with one header line.
function UTILS.SaveStationaryListOfGroups(List,Path,Filename) function UTILS.SaveStationaryListOfGroups(List,Path,Filename,Structured)
local filename = Filename or "StateListofGroups" local filename = Filename or "StateListofGroups"
local data = "--Save Stationary List of Groups: "..Filename .."\n" local data = "--Save Stationary List of Groups: "..Filename .."\n"
for _,_group in pairs (List) do for _,_group in pairs (List) do
@@ -2192,7 +2241,16 @@ function UTILS.SaveStationaryListOfGroups(List,Path,Filename)
if group and group:IsAlive() then if group and group:IsAlive() then
local units = group:CountAliveUnits() local units = group:CountAliveUnits()
local position = group:GetVec3() local position = group:GetVec3()
if Structured then
local structure = UTILS.GetCountPerTypeName(group)
local strucdata = ""
for typen,anzahl in pairs (structure) do
strucdata = strucdata .. typen .. "=="..anzahl..";"
end
data = string.format("%s%s,%d,%d,%d,%d,%s\n",data,_group,units,position.x,position.y,position.z,strucdata)
else
data = string.format("%s%s,%d,%d,%d,%d\n",data,_group,units,position.x,position.y,position.z) data = string.format("%s%s,%d,%d,%d,%d\n",data,_group,units,position.x,position.y,position.z)
end
else else
data = string.format("%s%s,0,0,0,0\n",data,_group) data = string.format("%s%s,0,0,0,0\n",data,_group)
end end
@@ -2206,6 +2264,7 @@ end
-- @param Core.Set#SET_BASE Set of objects to save -- @param Core.Set#SET_BASE Set of objects to save
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems. -- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
-- @param #string Filename The name of the file. -- @param #string Filename The name of the file.
-- @param #boolean Structured Append the data with a list of typenames in the group plus their count.
-- @return #boolean outcome True if saving is successful, else false. -- @return #boolean outcome True if saving is successful, else false.
-- @usage -- @usage
-- We will go through the set and find the corresponding group and save the current group size and current position. -- We will go through the set and find the corresponding group and save the current group size and current position.
@@ -2215,7 +2274,7 @@ end
-- **Note** Do NOT use dashes or hashes in group template names (-,#)! -- **Note** Do NOT use dashes or hashes in group template names (-,#)!
-- The data will be a simple comma separated list of groupname and size, with one header line. -- The data will be a simple comma separated list of groupname and size, with one header line.
-- The current task/waypoint/etc cannot be restored. -- The current task/waypoint/etc cannot be restored.
function UTILS.SaveSetOfGroups(Set,Path,Filename) function UTILS.SaveSetOfGroups(Set,Path,Filename,Structured)
local filename = Filename or "SetOfGroups" local filename = Filename or "SetOfGroups"
local data = "--Save SET of groups: "..Filename .."\n" local data = "--Save SET of groups: "..Filename .."\n"
local List = Set:GetSetObjects() local List = Set:GetSetObjects()
@@ -2229,9 +2288,18 @@ function UTILS.SaveSetOfGroups(Set,Path,Filename)
end end
local units = group:CountAliveUnits() local units = group:CountAliveUnits()
local position = group:GetVec3() local position = group:GetVec3()
if Structured then
local structure = UTILS.GetCountPerTypeName(group)
local strucdata = ""
for typen,anzahl in pairs (structure) do
strucdata = strucdata .. typen .. "=="..anzahl..";"
end
data = string.format("%s%s,%s,%d,%d,%d,%d,%s\n",data,name,template,units,position.x,position.y,position.z,strucdata)
else
data = string.format("%s%s,%s,%d,%d,%d,%d\n",data,name,template,units,position.x,position.y,position.z) data = string.format("%s%s,%s,%d,%d,%d,%d\n",data,name,template,units,position.x,position.y,position.z)
end end
end end
end
-- save the data -- save the data
local outcome = UTILS.SaveToFile(Path,Filename,data) local outcome = UTILS.SaveToFile(Path,Filename,data)
return outcome return outcome
@@ -2293,8 +2361,41 @@ end
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems. -- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
-- @param #string Filename The name of the file. -- @param #string Filename The name of the file.
-- @param #boolean Reduce If false, existing loaded groups will not be reduced to fit the saved number. -- @param #boolean Reduce If false, existing loaded groups will not be reduced to fit the saved number.
-- @param #boolean Structured (Optional, needs Reduce = true) If true, and the data has been saved as structure before, remove the correct unit types as per the saved list.
-- @param #boolean Cinematic (Optional, needs Structured = true) If true, place a fire/smoke effect on the dead static position.
-- @param #number Effect (Optional for Cinematic) What effect to use. Defaults to a random effect. Smoke presets are: 1=small smoke and fire, 2=medium smoke and fire, 3=large smoke and fire, 4=huge smoke and fire, 5=small smoke, 6=medium smoke, 7=large smoke, 8=huge smoke.
-- @param #number Density (Optional for Cinematic) What smoke density to use, can be 0 to 1. Defaults to 0.5.
-- @return #table Table of data objects (tables) containing groupname, coordinate and group object. Returns nil when file cannot be read. -- @return #table Table of data objects (tables) containing groupname, coordinate and group object. Returns nil when file cannot be read.
function UTILS.LoadStationaryListOfGroups(Path,Filename,Reduce) -- @return #table When using Cinematic: table of names of smoke and fire objects, so they can be extinguished with `COORDINATE.StopBigSmokeAndFire( name )`
function UTILS.LoadStationaryListOfGroups(Path,Filename,Reduce,Structured,Cinematic,Effect,Density)
local fires = {}
local function Smokers(name,coord,effect,density)
local eff = math.random(8)
if type(effect) == "number" then eff = effect end
coord:BigSmokeAndFire(eff,density,name)
table.insert(fires,name)
end
local function Cruncher(group,typename,anzahl)
local units = group:GetUnits()
local reduced = 0
for _,_unit in pairs (units) do
local typo = _unit:GetTypeName()
if typename == typo then
if Cinematic then
local coordinate = _unit:GetCoordinate()
local name = _unit:GetName()
Smokers(name,coordinate,Effect,Density)
end
_unit:Destroy(false)
reduced = reduced + 1
if reduced == anzahl then break end
end
end
end
local reduce = true local reduce = true
if Reduce == false then reduce = false end if Reduce == false then reduce = false end
local filename = Filename or "StateListofGroups" local filename = Filename or "StateListofGroups"
@@ -2311,13 +2412,42 @@ function UTILS.LoadStationaryListOfGroups(Path,Filename,Reduce)
local posx = tonumber(dataset[3]) local posx = tonumber(dataset[3])
local posy = tonumber(dataset[4]) local posy = tonumber(dataset[4])
local posz = tonumber(dataset[5]) local posz = tonumber(dataset[5])
local structure = dataset[6]
--BASE:I({structure})
local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz}) local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz})
local data = { groupname=groupname, size=size, coordinate=coordinate, group=GROUP:FindByName(groupname) } local data = { groupname=groupname, size=size, coordinate=coordinate, group=GROUP:FindByName(groupname) }
if reduce then if reduce then
local actualgroup = GROUP:FindByName(groupname) local actualgroup = GROUP:FindByName(groupname)
if actualgroup and actualgroup:IsAlive() and actualgroup:CountAliveUnits() > size then if actualgroup and actualgroup:IsAlive() and actualgroup:CountAliveUnits() > size then
if Structured and structure then
--BASE:I("Reducing group structure!")
local loadedstructure = {}
local strcset = UTILS.Split(structure,";")
for _,_data in pairs(strcset) do
local datasplit = UTILS.Split(_data,"==")
loadedstructure[datasplit[1]] = tonumber(datasplit[2])
end
--BASE:I({loadedstructure})
local originalstructure = UTILS.GetCountPerTypeName(actualgroup)
--BASE:I({originalstructure})
for _name,_number in pairs(originalstructure) do
local loadednumber = 0
if loadedstructure[_name] then
loadednumber = loadedstructure[_name]
end
local reduce = false
if loadednumber < _number then reduce = true end
--BASE:I(string.format("Looking at: %s | Original number: %d | Loaded number: %d | Reduce: %s",_name,_number,loadednumber,tostring(reduce)))
if reduce then
Cruncher(actualgroup,_name,_number-loadednumber)
end
end
else
local reduction = actualgroup:CountAliveUnits() - size local reduction = actualgroup:CountAliveUnits() - size
BASE:I("Reducing groupsize by ".. reduction .. " units!") --BASE:I("Reducing groupsize by ".. reduction .. " units!")
-- reduce existing group -- reduce existing group
local units = actualgroup:GetUnits() local units = actualgroup:GetUnits()
local units2 = UTILS.ShuffleTable(units) -- randomize table local units2 = UTILS.ShuffleTable(units) -- randomize table
@@ -2326,27 +2456,127 @@ function UTILS.LoadStationaryListOfGroups(Path,Filename,Reduce)
end end
end end
end end
end
table.insert(datatable,data) table.insert(datatable,data)
end end
else else
return nil return nil
end end
return datatable return datatable,fires
end end
--- Load back a SET of groups from file. --- Load back a SET of groups from file.
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems. -- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
-- @param #string Filename The name of the file. -- @param #string Filename The name of the file.
-- @param #boolean Spawn If set to false, do not re-spawn the groups loaded in location and reduce to size. -- @param #boolean Spawn If set to false, do not re-spawn the groups loaded in location and reduce to size.
-- @param #boolean Structured (Optional, needs Spawn=true)If true, and the data has been saved as structure before, remove the correct unit types as per the saved list.
-- @param #boolean Cinematic (Optional, needs Structured=true) If true, place a fire/smoke effect on the dead static position.
-- @param #number Effect (Optional for Cinematic) What effect to use. Defaults to a random effect. Smoke presets are: 1=small smoke and fire, 2=medium smoke and fire, 3=large smoke and fire, 4=huge smoke and fire, 5=small smoke, 6=medium smoke, 7=large smoke, 8=huge smoke.
-- @param #number Density (Optional for Cinematic) What smoke density to use, can be 0 to 1. Defaults to 0.5.
-- @return Core.Set#SET_GROUP Set of GROUP objects. -- @return Core.Set#SET_GROUP Set of GROUP objects.
-- Returns nil when file cannot be read. Returns a table of data entries if Spawn is false: `{ groupname=groupname, size=size, coordinate=coordinate, template=template }` -- Returns nil when file cannot be read. Returns a table of data entries if Spawn is false: `{ groupname=groupname, size=size, coordinate=coordinate, template=template }`
function UTILS.LoadSetOfGroups(Path,Filename,Spawn) -- @return #table When using Cinematic: table of names of smoke and fire objects, so they can be extinguished with `COORDINATE.StopBigSmokeAndFire( name )`
function UTILS.LoadSetOfGroups(Path,Filename,Spawn,Structured,Cinematic,Effect,Density)
local fires = {}
local usedtemplates = {}
local spawn = true local spawn = true
if Spawn == false then spawn = false end if Spawn == false then spawn = false end
BASE:I("Spawn = "..tostring(spawn))
local filename = Filename or "SetOfGroups" local filename = Filename or "SetOfGroups"
local setdata = SET_GROUP:New() local setdata = SET_GROUP:New()
local datatable = {} local datatable = {}
local function Smokers(name,coord,effect,density)
local eff = math.random(8)
if type(effect) == "number" then eff = effect end
coord:BigSmokeAndFire(eff,density,name)
table.insert(fires,name)
end
local function Cruncher(group,typename,anzahl)
local units = group:GetUnits()
local reduced = 0
for _,_unit in pairs (units) do
local typo = _unit:GetTypeName()
if typename == typo then
if Cinematic then
local coordinate = _unit:GetCoordinate()
local name = _unit:GetName()
Smokers(name,coordinate,Effect,Density)
end
_unit:Destroy(false)
reduced = reduced + 1
if reduced == anzahl then break end
end
end
end
local function PostSpawn(args)
local spwndgrp = args[1]
local size = args[2]
local structure = args[3]
setdata:AddObject(spwndgrp)
local actualsize = spwndgrp:CountAliveUnits()
if actualsize > size then
if Structured and structure then
local loadedstructure = {}
local strcset = UTILS.Split(structure,";")
for _,_data in pairs(strcset) do
local datasplit = UTILS.Split(_data,"==")
loadedstructure[datasplit[1]] = tonumber(datasplit[2])
end
local originalstructure = UTILS.GetCountPerTypeName(spwndgrp)
for _name,_number in pairs(originalstructure) do
local loadednumber = 0
if loadedstructure[_name] then
loadednumber = loadedstructure[_name]
end
local reduce = false
if loadednumber < _number then reduce = true end
if reduce then
Cruncher(spwndgrp,_name,_number-loadednumber)
end
end
else
local reduction = actualsize-size
-- reduce existing group
local units = spwndgrp:GetUnits()
local units2 = UTILS.ShuffleTable(units) -- randomize table
for i=1,reduction do
units2[i]:Destroy(false)
end
end
end
end
local function MultiUse(Data)
local template = Data.template
if template and usedtemplates[template] and usedtemplates[template].used and usedtemplates[template].used > 1 then
-- multispawn
if not usedtemplates[template].done then
local spwnd = 0
local spawngrp = SPAWN:New(template)
spawngrp:InitLimit(0,usedtemplates[template].used)
for _,_entry in pairs(usedtemplates[template].data) do
spwnd = spwnd + 1
local sgrp=spawngrp:SpawnFromCoordinate(_entry.coordinate,spwnd)
BASE:ScheduleOnce(0.5,PostSpawn,{sgrp,_entry.size,_entry.structure})
end
usedtemplates[template].done = true
end
return true
else
return false
end
end
--BASE:I("Spawn = "..tostring(spawn))
if UTILS.CheckFileExists(Path,filename) then if UTILS.CheckFileExists(Path,filename) then
local outcome,loadeddata = UTILS.LoadFromFile(Path,Filename) local outcome,loadeddata = UTILS.LoadFromFile(Path,Filename)
-- remove header -- remove header
@@ -2360,36 +2590,37 @@ function UTILS.LoadSetOfGroups(Path,Filename,Spawn)
local posx = tonumber(dataset[4]) local posx = tonumber(dataset[4])
local posy = tonumber(dataset[5]) local posy = tonumber(dataset[5])
local posz = tonumber(dataset[6]) local posz = tonumber(dataset[6])
local structure = dataset[7]
local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz}) local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz})
local group=nil local group=nil
local data = { groupname=groupname, size=size, coordinate=coordinate, template=template } if size > 0 then
local data = { groupname=groupname, size=size, coordinate=coordinate, template=template, structure=structure }
table.insert(datatable,data) table.insert(datatable,data)
if spawn then if usedtemplates[template] then
local group = SPAWN:New(template) usedtemplates[template].used = usedtemplates[template].used + 1
:InitDelayOff() table.insert(usedtemplates[template].data,data)
:OnSpawnGroup( else
function(spwndgrp) usedtemplates[template] = {
setdata:AddObject(spwndgrp) data = {},
local actualsize = spwndgrp:CountAliveUnits() used = 1,
if actualsize > size then done = false,
local reduction = actualsize-size }
-- reduce existing group table.insert(usedtemplates[template].data,data)
local units = spwndgrp:GetUnits()
local units2 = UTILS.ShuffleTable(units) -- randomize table
for i=1,reduction do
units2[i]:Destroy(false)
end end
end end
end end
) for _id,_entry in pairs (datatable) do
:SpawnFromCoordinate(coordinate) if spawn and not MultiUse(_entry) and _entry.size > 0 then
local group = SPAWN:New(_entry.template)
local sgrp=group:SpawnFromCoordinate(_entry.coordinate)
BASE:ScheduleOnce(0.5,PostSpawn,{sgrp,_entry.size,_entry.structure})
end end
end end
else else
return nil return nil
end end
if spawn then if spawn then
return setdata return setdata,fires
else else
return datatable return datatable
end end
@@ -2408,13 +2639,11 @@ function UTILS.LoadSetOfStatics(Path,Filename)
table.remove(loadeddata, 1) table.remove(loadeddata, 1)
for _id,_entry in pairs (loadeddata) do for _id,_entry in pairs (loadeddata) do
local dataset = UTILS.Split(_entry,",") local dataset = UTILS.Split(_entry,",")
-- staticname,position.x,position.y,position.z
local staticname = dataset[1] local staticname = dataset[1]
local posx = tonumber(dataset[2]) local StaticObject = STATIC:FindByName(staticname,false)
local posy = tonumber(dataset[3]) if StaticObject then
local posz = tonumber(dataset[4]) datatable:AddObject(StaticObject)
local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz}) end
datatable:AddObject(STATIC:FindByName(staticname,false))
end end
else else
return nil return nil
@@ -2426,9 +2655,15 @@ end
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems. -- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
-- @param #string Filename The name of the file. -- @param #string Filename The name of the file.
-- @param #boolean Reduce If false, do not destroy the units with size=0. -- @param #boolean Reduce If false, do not destroy the units with size=0.
-- @return #table Table of data objects (tables) containing staticname, size (0=dead else 1), coordinate and the static object. -- @param #boolean Dead (Optional, needs Reduce = true) If Dead is true, re-spawn the dead object as dead and do not just delete it.
-- @param #boolean Cinematic (Optional, needs Dead = true) If true, place a fire/smoke effect on the dead static position.
-- @param #number Effect (Optional for Cinematic) What effect to use. Defaults to a random effect. Smoke presets are: 1=small smoke and fire, 2=medium smoke and fire, 3=large smoke and fire, 4=huge smoke and fire, 5=small smoke, 6=medium smoke, 7=large smoke, 8=huge smoke.
-- @param #number Density (Optional for Cinematic) What smoke density to use, can be 0 to 1. Defaults to 0.5.
-- @return #table Table of data objects (tables) containing staticname, size (0=dead else 1), coordinate and the static object. Dead objects will have coordinate points `{x=0,y=0,z=0}`
-- @return #table When using Cinematic: table of names of smoke and fire objects, so they can be extinguished with `COORDINATE.StopBigSmokeAndFire( name )`
-- Returns nil when file cannot be read. -- Returns nil when file cannot be read.
function UTILS.LoadStationaryListOfStatics(Path,Filename,Reduce) function UTILS.LoadStationaryListOfStatics(Path,Filename,Reduce,Dead,Cinematic,Effect,Density)
local fires = {}
local reduce = true local reduce = true
if Reduce == false then reduce = false end if Reduce == false then reduce = false end
local filename = Filename or "StateListofStatics" local filename = Filename or "StateListofStatics"
@@ -2451,14 +2686,31 @@ function UTILS.LoadStationaryListOfStatics(Path,Filename,Reduce)
if size==0 and reduce then if size==0 and reduce then
local static = STATIC:FindByName(staticname,false) local static = STATIC:FindByName(staticname,false)
if static then if static then
if Dead then
local deadobject = SPAWNSTATIC:NewFromStatic(staticname,static:GetCountry())
deadobject:InitDead(true)
local heading = static:GetHeading()
local coord = static:GetCoordinate()
static:Destroy(false) static:Destroy(false)
deadobject:SpawnFromCoordinate(coord,heading,staticname)
if Cinematic then
local effect = math.random(8)
if type(Effect) == "number" then
effect = Effect
end
coord:BigSmokeAndFire(effect,Density,staticname)
table.insert(fires,staticname)
end
else
static:Destroy(false)
end
end end
end end
end end
else else
return nil return nil
end end
return datatable return datatable,fires
end end
--- Heading Degrees (0-360) to Cardinal --- Heading Degrees (0-360) to Cardinal
@@ -2483,7 +2735,7 @@ end
-- @return #string Formatted BRAA NATO call -- @return #string Formatted BRAA NATO call
function UTILS.ToStringBRAANATO(FromGrp,ToGrp) function UTILS.ToStringBRAANATO(FromGrp,ToGrp)
local BRAANATO = "Merged." local BRAANATO = "Merged."
local GroupNumber = FromGrp:GetSize() local GroupNumber = ToGrp:GetSize()
local GroupWords = "Singleton" local GroupWords = "Singleton"
if GroupNumber == 2 then GroupWords = "Two-Ship" if GroupNumber == 2 then GroupWords = "Two-Ship"
elseif GroupNumber >= 3 then GroupWords = "Heavy" elseif GroupNumber >= 3 then GroupWords = "Heavy"
@@ -2507,3 +2759,51 @@ function UTILS.ToStringBRAANATO(FromGrp,ToGrp)
end end
return BRAANATO return BRAANATO
end end
--- Check if an object is contained in a table.
-- @param #table Table The table.
-- @param #table Object The object to check.
-- @param #string Key (Optional) Key to check. By default, the object itself is checked.
-- @return #booolen Returns `true` if object is in table.
function UTILS.IsInTable(Table, Object, Key)
for key, object in pairs(Table) do
if Key then
if Object[Key]==object[Key] then
return true
end
else
if object==Object then
return true
end
end
end
return false
end
--- Check if any object of multiple given objects is contained in a table.
-- @param #table Table The table.
-- @param #table Objects The objects to check.
-- @param #string Key (Optional) Key to check.
-- @return #booolen Returns `true` if object is in table.
function UTILS.IsAnyInTable(Table, Objects, Key)
for _,Object in pairs(UTILS.EnsureTable(Objects)) do
for key, object in pairs(Table) do
if Key then
if Object[Key]==object[Key] then
return true
end
else
if object==Object then
return true
end
end
end
end
return false
end
+29 -4
View File
@@ -246,7 +246,7 @@ AIRBASE.Normandy = {
-- --
-- * AIRBASE.PersianGulf.Abu_Dhabi_International_Airport -- * AIRBASE.PersianGulf.Abu_Dhabi_International_Airport
-- * AIRBASE.PersianGulf.Abu_Musa_Island_Airport -- * AIRBASE.PersianGulf.Abu_Musa_Island_Airport
-- * AIRBASE.PersianGulf.Al-Bateen_Airport -- * AIRBASE.PersianGulf.Al_Bateen_Airport
-- * AIRBASE.PersianGulf.Al_Ain_International_Airport -- * AIRBASE.PersianGulf.Al_Ain_International_Airport
-- * AIRBASE.PersianGulf.Al_Dhafra_AB -- * AIRBASE.PersianGulf.Al_Dhafra_AB
-- * AIRBASE.PersianGulf.Al_Maktoum_Intl -- * AIRBASE.PersianGulf.Al_Maktoum_Intl
@@ -265,7 +265,7 @@ AIRBASE.Normandy = {
-- * AIRBASE.PersianGulf.Lavan_Island_Airport -- * AIRBASE.PersianGulf.Lavan_Island_Airport
-- * AIRBASE.PersianGulf.Liwa_Airbase -- * AIRBASE.PersianGulf.Liwa_Airbase
-- * AIRBASE.PersianGulf.Qeshm_Island -- * AIRBASE.PersianGulf.Qeshm_Island
-- * AIRBASE.PersianGulf.Ras_Al_Khaimah_International_Airport -- * AIRBASE.PersianGulf.Ras_Al_Khaimah
-- * AIRBASE.PersianGulf.Sas_Al_Nakheel_Airport -- * AIRBASE.PersianGulf.Sas_Al_Nakheel_Airport
-- * AIRBASE.PersianGulf.Sharjah_Intl -- * AIRBASE.PersianGulf.Sharjah_Intl
-- * AIRBASE.PersianGulf.Shiraz_International_Airport -- * AIRBASE.PersianGulf.Shiraz_International_Airport
@@ -504,6 +504,17 @@ AIRBASE.MarianaIslands = {
-- * AIRBASE.SouthAtlantic.Puerto_Williams -- * AIRBASE.SouthAtlantic.Puerto_Williams
-- * AIRBASE.SouthAtlantic.Puerto_Natales -- * AIRBASE.SouthAtlantic.Puerto_Natales
-- * AIRBASE.SouthAtlantic.El_Calafate -- * AIRBASE.SouthAtlantic.El_Calafate
-- * 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
-- * AIRBASE.SouthAtlantic.Rio_Chico
-- * AIRBASE.SouthAtlantic.Franco_Bianco
-- * AIRBASE.SouthAtlantic.Goose_Green
-- * AIRBASE.SouthAtlantic.Hipico
-- * AIRBASE.SouthAtlantic.CaletaTortel
-- --
--@field MarianaIslands --@field MarianaIslands
AIRBASE.SouthAtlantic={ AIRBASE.SouthAtlantic={
@@ -520,6 +531,17 @@ AIRBASE.SouthAtlantic={
["Puerto_Williams"]="Puerto Williams", ["Puerto_Williams"]="Puerto Williams",
["Puerto_Natales"]="Puerto Natales", ["Puerto_Natales"]="Puerto Natales",
["El_Calafate"]="El Calafate", ["El_Calafate"]="El Calafate",
["Puerto_Santa_Cruz"]="Puerto Santa Cruz",
["Comandante_Luis_Piedrabuena"]="Comandante Luis Piedrabuena",
["Aerodromo_De_Tolhuin"]="Aerodromo De Tolhuin",
["Porvenir_Airfield"]="Porvenir Airfield",
["Almirante_Schroeders"]="Almirante Schroeders",
["Rio_Turbio"]="Rio Turbio",
["Rio_Chico"] = "Rio Chico",
["Franco_Bianco"] = "Franco Bianco",
["Goose_Green"] = "Goose Green",
["Hipico"] = "Hipico",
["CaletaTortel"] = "CaletaTortel",
} }
--- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy". --- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
@@ -674,6 +696,9 @@ function AIRBASE:Register(AirbaseName)
self:E(string.format("ERROR: Cound not get position Vec2 of airbase %s", AirbaseName)) self:E(string.format("ERROR: Cound not get position Vec2 of airbase %s", AirbaseName))
end end
-- Debug info.
self:T2(string.format("Registered airbase %s", tostring(self.AirbaseName)))
return self return self
end end
@@ -824,7 +849,7 @@ end
-- Black listed spots overrule white listed spots. -- Black listed spots overrule white listed spots.
-- **NOTE** that terminal IDs are not necessarily the same as those displayed in the mission editor! -- **NOTE** that terminal IDs are not necessarily the same as those displayed in the mission editor!
-- @param #AIRBASE self -- @param #AIRBASE self
-- @param #table TerminalIdBlacklist Table of white listed terminal IDs. -- @param #table TerminalIdWhitelist Table of white listed terminal IDs.
-- @return #AIRBASE self -- @return #AIRBASE self
-- @usage AIRBASE:FindByName("Batumi"):SetParkingSpotWhitelist({2, 3, 4}) --Only allow terminal IDs 2, 3, 4 -- @usage AIRBASE:FindByName("Batumi"):SetParkingSpotWhitelist({2, 3, 4}) --Only allow terminal IDs 2, 3, 4
function AIRBASE:SetParkingSpotWhitelist(TerminalIdWhitelist) function AIRBASE:SetParkingSpotWhitelist(TerminalIdWhitelist)
@@ -1353,7 +1378,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
local _nspots=nspots or group:GetSize() local _nspots=nspots or group:GetSize()
-- Debug info. -- Debug info.
self:E(string.format("%s: Looking for %d parking spot(s) for aircraft of size %.1f m (x=%.1f,y=%.1f,z=%.1f) at terminal type %s.", airport, _nspots, _aircraftsize, ax, ay, az, tostring(terminaltype))) self:T(string.format("%s: Looking for %d parking spot(s) for aircraft of size %.1f m (x=%.1f,y=%.1f,z=%.1f) at terminal type %s.", airport, _nspots, _aircraftsize, ax, ay, az, tostring(terminaltype)))
-- Table of valid spots. -- Table of valid spots.
local validspots={} local validspots={}
+112 -60
View File
@@ -62,11 +62,11 @@
-- * @{#CONTROLLABLE.TaskOrbitCircle}: (AIR) Orbit at the current position of the first unit of the controllable at a specified altitude. -- * @{#CONTROLLABLE.TaskOrbitCircle}: (AIR) Orbit at the current position of the first unit of the controllable at a specified altitude.
-- * @{#CONTROLLABLE.TaskOrbitCircleAtVec2}: (AIR) Orbit at a specified position at a specified altitude during a specified duration with a specified speed. -- * @{#CONTROLLABLE.TaskOrbitCircleAtVec2}: (AIR) Orbit at a specified position at a specified altitude during a specified duration with a specified speed.
-- * @{#CONTROLLABLE.TaskRefueling}: (AIR) Refueling from the nearest tanker. No parameters. -- * @{#CONTROLLABLE.TaskRefueling}: (AIR) Refueling from the nearest tanker. No parameters.
-- * @{#CONTROLLABLE.TaskRecoveryTanker}: (AIR) Set group to act as recovery tanker for a naval group.
-- * @{#CONTROLLABLE.TaskRoute}: (AIR + GROUND) Return a Mission task to follow a given route defined by Points. -- * @{#CONTROLLABLE.TaskRoute}: (AIR + GROUND) Return a Mission task to follow a given route defined by Points.
-- * @{#CONTROLLABLE.TaskRouteToVec2}: (AIR + GROUND) Make the Controllable move to a given point. -- * @{#CONTROLLABLE.TaskRouteToVec2}: (AIR + GROUND) Make the Controllable move to a given point.
-- * @{#CONTROLLABLE.TaskRouteToVec3}: (AIR + GROUND) Make the Controllable move to a given point. -- * @{#CONTROLLABLE.TaskRouteToVec3}: (AIR + GROUND) Make the Controllable move to a given point.
-- * @{#CONTROLLABLE.TaskRouteToZone}: (AIR + GROUND) Route the controllable to a given zone. -- * @{#CONTROLLABLE.TaskRouteToZone}: (AIR + GROUND) Route the controllable to a given zone.
-- * @{#CONTROLLABLE.TaskReturnToBase}: (AIR) Route the controllable to an airbase.
-- --
-- ## 2.2) EnRoute assignment -- ## 2.2) EnRoute assignment
-- --
@@ -668,12 +668,61 @@ function CONTROLLABLE:CommandActivateBeacon( Type, System, Frequency, UnitID, Ch
return self return self
end end
--- Activate ACLS system of the CONTROLLABLE. The controllable should be an aircraft carrier! Also needs Link4 to work.
-- @param #CONTROLLABLE self
-- @param #number UnitID (Optional) The DCS UNIT ID of the unit the ACLS system is attached to. Defaults to the UNIT itself.
-- @param #string Name (Optional) Name of the ACLS Beacon
-- @param #number Delay (Optional) Delay in seconds before the ICLS is activated.
-- @return #CONTROLLABLE self
function CONTROLLABLE:CommandActivateACLS( UnitID, Name, Delay )
-- Command to activate ACLS system.
local CommandActivateACLS= {
id = 'ActivateACLS',
params = {
unitId = UnitID or self:GetID(),
name = Name or "ACL",
}
}
self:T({CommandActivateACLS})
if Delay and Delay > 0 then
SCHEDULER:New( nil, self.CommandActivateACLS, { self, UnitID, Name }, Delay )
else
self:SetCommand( CommandActivateACLS )
end
return self
end
--- Deactivate ACLS system of the CONTROLLABLE. The controllable should be an aircraft carrier!
-- @param #CONTROLLABLE self
-- @param #number Delay (Optional) Delay in seconds before the ICLS is deactivated.
-- @return #CONTROLLABLE self
function CONTROLLABLE:CommandDeactivateACLS( Delay )
-- Command to activate ACLS system.
local CommandDeactivateACLS= {
id = 'DeactivateACLS',
params = { }
}
if Delay and Delay > 0 then
SCHEDULER:New( nil, self.CommandDeactivateACLS, { self }, Delay )
else
self:SetCommand( CommandDeactivateACLS )
end
return self
end
--- Activate ICLS system of the CONTROLLABLE. The controllable should be an aircraft carrier! --- Activate ICLS system of the CONTROLLABLE. The controllable should be an aircraft carrier!
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self
-- @param #number Channel ICLS channel. -- @param #number Channel ICLS channel.
-- @param #number UnitID The DCS UNIT ID of the unit the ICLS system is attached to. Useful if more units are in one group. -- @param #number UnitID The DCS UNIT ID of the unit the ICLS system is attached to. Useful if more units are in one group.
-- @param #string Callsign Morse code identification callsign. -- @param #string Callsign Morse code identification callsign.
-- @param #number Delay (Optional) Delay in seconds before the ICLS is deactivated. -- @param #number Delay (Optional) Delay in seconds before the ICLS is activated.
-- @return #CONTROLLABLE self -- @return #CONTROLLABLE self
function CONTROLLABLE:CommandActivateICLS( Channel, UnitID, Callsign, Delay ) function CONTROLLABLE:CommandActivateICLS( Channel, UnitID, Callsign, Delay )
@@ -683,13 +732,13 @@ function CONTROLLABLE:CommandActivateICLS( Channel, UnitID, Callsign, Delay )
params = { params = {
["type"] = BEACON.Type.ICLS, ["type"] = BEACON.Type.ICLS,
["channel"] = Channel, ["channel"] = Channel,
["unitId"] = UnitID, ["unitId"] = UnitID or self:GetID(),
["callsign"] = Callsign, ["callsign"] = Callsign,
}, },
} }
if Delay and Delay > 0 then if Delay and Delay > 0 then
SCHEDULER:New( nil, self.CommandActivateICLS, { self }, Delay ) SCHEDULER:New( nil, self.CommandActivateICLS, { self, Channel, UnitID, Callsign }, Delay )
else else
self:SetCommand( CommandActivateICLS ) self:SetCommand( CommandActivateICLS )
end end
@@ -699,53 +748,29 @@ end
--- Activate LINK4 system of the CONTROLLABLE. The controllable should be an aircraft carrier! --- Activate LINK4 system of the CONTROLLABLE. The controllable should be an aircraft carrier!
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self
-- @param #number Frequency Link4 Frequency in MHz, e.g. 336 -- @param #number Frequency Link4 Frequency in MHz, e.g. 336 (defaults to 336 MHz)
-- @param #number UnitID The DCS UNIT ID of the unit the LINK4 system is attached to. Useful if more units are in one group. -- @param #number UnitID (Optional) The DCS UNIT ID of the unit the LINK4 system is attached to. Defaults to the UNIT itself.
-- @param #string Callsign Morse code identification callsign. -- @param #string Callsign (Optional) Morse code identification callsign.
-- @param #number Delay (Optional) Delay in seconds before the LINK4 is deactivated. -- @param #number Delay (Optional) Delay in seconds before the LINK4 is activated.
-- @return #CONTROLLABLE self -- @return #CONTROLLABLE self
function CONTROLLABLE:CommandActivateLink4(Frequency, UnitID, Callsign, Delay) function CONTROLLABLE:CommandActivateLink4(Frequency, UnitID, Callsign, Delay)
local freq = Frequency or 336
-- Command to activate Link4 system. -- Command to activate Link4 system.
local CommandActivateLink4= { local CommandActivateLink4= {
id = "ActivateLink4", id = "ActivateLink4",
params= { params= {
["frequency "] = Frequency*1000, ["frequency "] = freq*1000000,
["unitId"] = UnitID, ["unitId"] = UnitID or self:GetID(),
["name"] = Callsign, ["name"] = Callsign or "LNK",
} }
} }
self:T({CommandActivateLink4})
if Delay and Delay>0 then if Delay and Delay>0 then
SCHEDULER:New(nil, self.CommandActivateLink4, {self}, Delay) SCHEDULER:New(nil, self.CommandActivateLink4, {self, Frequency, UnitID, Callsign}, Delay)
else
self:SetCommand(CommandActivateLink4)
end
return self
end
--- Activate LINK4 system of the CONTROLLABLE. The controllable should be an aircraft carrier!
-- @param #CONTROLLABLE self
-- @param #number Frequency Link4 Frequency in MHz, e.g. 336
-- @param #number UnitID The DCS UNIT ID of the unit the LINK4 system is attached to. Useful if more units are in one group.
-- @param #string Callsign Morse code identification callsign.
-- @param #number Delay (Optional) Delay in seconds before the LINK4 is deactivated.
-- @return #CONTROLLABLE self
function CONTROLLABLE:CommandActivateLink4(Frequency, UnitID, Callsign, Delay)
-- Command to activate Link4 system.
local CommandActivateLink4= {
id = "ActivateLink4",
params= {
["frequency "] = Frequency*1000,
["unitId"] = UnitID,
["name"] = Callsign,
}
}
if Delay and Delay>0 then
SCHEDULER:New(nil, self.CommandActivateLink4, {self}, Delay)
else else
self:SetCommand(CommandActivateLink4) self:SetCommand(CommandActivateLink4)
end end
@@ -809,24 +834,6 @@ function CONTROLLABLE:CommandDeactivateICLS( Delay )
return self return self
end end
--- Deactivate the active Link4 of the CONTROLLABLE.
-- @param #CONTROLLABLE self
-- @param #number Delay (Optional) Delay in seconds before the Link4 is deactivated.
-- @return #CONTROLLABLE self
function CONTROLLABLE:CommandDeactivateLink4(Delay)
-- Command to deactivate
local CommandDeactivateLink4={id='DeactivateLink4', params={}}
if Delay and Delay>0 then
SCHEDULER:New(nil, self.CommandDeactivateLink4, {self}, Delay)
else
self:SetCommand(CommandDeactivateLink4)
end
return self
end
--- Set callsign of the CONTROLLABLE. See [DCS command setCallsign](https://wiki.hoggitworld.com/view/DCS_command_setCallsign) --- Set callsign of the CONTROLLABLE. See [DCS command setCallsign](https://wiki.hoggitworld.com/view/DCS_command_setCallsign)
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self
-- @param DCS#CALLSIGN CallName Number corresponding the the callsign identifier you wish this group to be called. -- @param DCS#CALLSIGN CallName Number corresponding the the callsign identifier you wish this group to be called.
@@ -1367,6 +1374,31 @@ function CONTROLLABLE:TaskRefueling()
return DCSTask return DCSTask
end end
--- (AIR) Act as Recovery Tanker for a naval/carrier group.
-- @param #CONTROLLABLE self
-- @param Wrapper.Group#GROUP CarrierGroup
-- @param #number Speed Speed in meters per second
-- @param #number Altitude Altitude the tanker orbits at in meters
-- @param #number LastWptNumber (optional) Waypoint of carrier group that when reached, ends the recovery tanker task
-- @return DCS#Task The DCS task structure.
function CONTROLLABLE:TaskRecoveryTanker(CarrierGroup, Speed, Altitude, LastWptNumber)
local LastWptFlag = type(LastWptNumber) == "number" and true or false
local DCSTask = {
id = "RecoveryTanker",
params = {
groupId = CarrierGroup:GetID(),
speed = Speed,
altitude = Altitude,
lastWptIndexFlag = LastWptFlag,
lastWptIndex = LastWptNumber
}
}
return DCSTask
end
--- (AIR HELICOPTER) Landing at the ground. For helicopters only. --- (AIR HELICOPTER) Landing at the ground. For helicopters only.
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self
-- @param DCS#Vec2 Vec2 The point where to land. -- @param DCS#Vec2 Vec2 The point where to land.
@@ -1390,7 +1422,7 @@ end
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self
-- @param Core.Zone#ZONE Zone The zone where to land. -- @param Core.Zone#ZONE Zone The zone where to land.
-- @param #number Duration The duration in seconds to stay on the ground. -- @param #number Duration The duration in seconds to stay on the ground.
-- @return #CONTROLLABLE self -- @return DCS#Task The DCS task structure.
function CONTROLLABLE:TaskLandAtZone( Zone, Duration, RandomPoint ) function CONTROLLABLE:TaskLandAtZone( Zone, Duration, RandomPoint )
-- Get landing point -- Get landing point
@@ -1639,6 +1671,26 @@ function CONTROLLABLE:EnRouteTaskAntiShip(TargetTypes, Priority)
return DCSTask return DCSTask
end end
--- (AIR) Enroute SEAD task.
-- @param #CONTROLLABLE self
-- @param DCS#AttributeNameArray TargetTypes Array of target categories allowed to engage. Default `{"Air Defence"}`.
-- @param #number Priority (Optional) All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. Default 0.
-- @return DCS#Task The DCS task structure.
function CONTROLLABLE:EnRouteTaskSEAD(TargetTypes, Priority)
local DCSTask = {
id = 'EngageTargets',
key = "SEAD",
--auto = false,
--enabled = true,
params = {
targetTypes = TargetTypes or {"Air Defence"},
priority = Priority or 0
}
}
return DCSTask
end
--- (AIR) Engaging a controllable. The task does not assign the target controllable to the unit/controllable to attack now; it just allows the unit/controllable to engage the target controllable as well as other assigned targets. --- (AIR) Engaging a controllable. The task does not assign the target controllable to the unit/controllable to attack now; it just allows the unit/controllable to engage the target controllable as well as other assigned targets.
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self
@@ -2369,7 +2421,7 @@ do -- Route methods
-- @return DCS#Task Task. -- @return DCS#Task Task.
-- @return #boolean If true, path on road is possible. If false, task will route the group directly to its destination. -- @return #boolean If true, path on road is possible. If false, task will route the group directly to its destination.
function CONTROLLABLE:TaskGroundOnRoad( ToCoordinate, Speed, OffRoadFormation, Shortcut, FromCoordinate, WaypointFunction, WaypointFunctionArguments ) function CONTROLLABLE:TaskGroundOnRoad( ToCoordinate, Speed, OffRoadFormation, Shortcut, FromCoordinate, WaypointFunction, WaypointFunctionArguments )
self:I( { ToCoordinate = ToCoordinate, Speed = Speed, OffRoadFormation = OffRoadFormation, WaypointFunction = WaypointFunction, Args = WaypointFunctionArguments } ) self:T( { ToCoordinate = ToCoordinate, Speed = Speed, OffRoadFormation = OffRoadFormation, WaypointFunction = WaypointFunction, Args = WaypointFunctionArguments } )
-- Defaults. -- Defaults.
Speed = Speed or 20 Speed = Speed or 20
+55 -21
View File
@@ -624,10 +624,9 @@ function GROUP:GetRange()
return nil return nil
end end
--- Returns a list of @{Wrapper.Unit} objects of the @{Wrapper.Group}. --- Returns a list of @{Wrapper.Unit} objects of the @{Wrapper.Group}.
-- @param #GROUP self -- @param #GROUP self
-- @return #list<Wrapper.Unit#UNIT> The list of @{Wrapper.Unit} objects of the @{Wrapper.Group}. -- @return #table of Wrapper.Unit#UNIT objects, indexed by number.
function GROUP:GetUnits() function GROUP:GetUnits()
self:F2( { self.GroupName } ) self:F2( { self.GroupName } )
local DCSGroup = self:GetDCSObject() local DCSGroup = self:GetDCSObject()
@@ -645,7 +644,6 @@ function GROUP:GetUnits()
return nil return nil
end end
--- Returns a list of @{Wrapper.Unit} objects of the @{Wrapper.Group} that are occupied by a player. --- Returns a list of @{Wrapper.Unit} objects of the @{Wrapper.Group} that are occupied by a player.
-- @param #GROUP self -- @param #GROUP self
-- @return #list<Wrapper.Unit#UNIT> The list of player occupied @{Wrapper.Unit} objects of the @{Wrapper.Group}. -- @return #list<Wrapper.Unit#UNIT> The list of player occupied @{Wrapper.Unit} objects of the @{Wrapper.Group}.
@@ -676,41 +674,38 @@ function GROUP:IsPlayer()
return self:GetUnit(1):IsPlayer() return self:GetUnit(1):IsPlayer()
end end
--- Returns the UNIT wrapper class with number UnitNumber. --- Returns the UNIT wrapper object with number UnitNumber. If it doesn't exist, tries to return the next available unit.
-- If the underlying DCS Unit does not exist, the method will return nil. . -- If no underlying DCS Units exist, the method will return nil.
-- @param #GROUP self -- @param #GROUP self
-- @param #number UnitNumber The number of the UNIT wrapper class to be returned. -- @param #number UnitNumber The number of the UNIT wrapper class to be returned.
-- @return Wrapper.Unit#UNIT The UNIT wrapper class. -- @return Wrapper.Unit#UNIT The UNIT object or nil
function GROUP:GetUnit( UnitNumber ) function GROUP:GetUnit( UnitNumber )
local DCSGroup = self:GetDCSObject() local DCSGroup = self:GetDCSObject()
if DCSGroup then if DCSGroup then
local UnitFound = nil local UnitFound = nil
-- 2.7.1 dead event bug, return the first alive unit instead -- 2.7.1 dead event bug, return the first alive unit instead
-- Maybe fixed with 2.8?
local units = DCSGroup:getUnits() or {} local units = DCSGroup:getUnits() or {}
if units[UnitNumber] then
for _,_unit in pairs(units) do local UnitFound = UNIT:Find(units[UnitNumber])
if UnitFound then
local UnitFound = UNIT:Find(_unit) return UnitFound
end
else
for _,_unit in pairs(units) do
local UnitFound = UNIT:Find(_unit)
if UnitFound then if UnitFound then
return UnitFound return UnitFound
end end
end end
end end
end
return nil return nil
end end
--- Returns the DCS Unit with number UnitNumber. --- Returns the DCS Unit with number UnitNumber.
-- If the underlying DCS Unit does not exist, the method will return nil. . -- If the underlying DCS Unit does not exist, the method will return try to find the next unit. Returns nil if no units are found.
-- @param #GROUP self -- @param #GROUP self
-- @param #number UnitNumber The number of the DCS Unit to be returned. -- @param #number UnitNumber The number of the DCS Unit to be returned.
-- @return DCS#Unit The DCS Unit. -- @return DCS#Unit The DCS Unit.
@@ -724,7 +719,6 @@ function GROUP:GetDCSUnit( UnitNumber )
return DCSGroup:getUnit( UnitNumber ) return DCSGroup:getUnit( UnitNumber )
else else
local UnitFound = nil
-- 2.7.1 dead event bug, return the first alive unit instead -- 2.7.1 dead event bug, return the first alive unit instead
local units = DCSGroup:getUnits() or {} local units = DCSGroup:getUnits() or {}
@@ -803,7 +797,20 @@ function GROUP:GetFirstUnitAlive()
return nil return nil
end end
--- Get the first unit of the group. Might be nil!
-- @param #GROUP self
-- @return Wrapper.Unit#UNIT First unit or nil if it does not exist.
function GROUP:GetFirstUnit()
self:F3({self.GroupName})
local DCSGroup = self:GetDCSObject()
if DCSGroup then
local units=self:GetUnits()
return units[1]
end
return nil
end
--- Returns the average velocity Vec3 vector. --- Returns the average velocity Vec3 vector.
-- @param Wrapper.Group#GROUP self -- @param Wrapper.Group#GROUP self
@@ -2855,3 +2862,30 @@ function GROUP:GetCustomCallSign(ShortCallsign,Keepnumber,CallsignTranslations)
return callsign return callsign
end end
---
-- @param #GROUP self
-- @param Wrapper.Group#GROUP CarrierGroup.
-- @param #number Speed Speed in knots.
-- @param #boolean ToKIAS If true, adjust speed to altitude (KIAS).
-- @param #number Altitude Altitude the tanker orbits at in feet.
-- @param #number Delay (optional) Set the task after this many seconds. Defaults to one.
-- @param #number LastWaypoint (optional) Waypoint number of carrier group that when reached, ends the recovery tanker task.
-- @return #GROUP self
function GROUP:SetAsRecoveryTanker(CarrierGroup,Speed,ToKIAS,Altitude,Delay,LastWaypoint)
local speed = ToKIAS == true and UTILS.KnotsToAltKIAS(Speed,Altitude) or Speed
speed = UTILS.KnotsToMps(speed)
local alt = UTILS.FeetToMeters(Altitude)
local delay = Delay or 1
local task = self:TaskRecoveryTanker(CarrierGroup,speed,alt,LastWaypoint)
self:SetTask(task,delay)
local tankertask = self:EnRouteTaskTanker()
self:PushTask(tankertask,delay+2)
return self
end
+5 -9
View File
@@ -59,17 +59,15 @@
-- --
-- mymarker = MARKER:New( Coordinate , "I am Batumi Airfield" ):ToCoalition( coalition.side.BLUE ) -- mymarker = MARKER:New( Coordinate , "I am Batumi Airfield" ):ToCoalition( coalition.side.BLUE )
-- --
-- ### To Blue Coalition
--
-- ### To Red Coalition
--
-- This would show the marker only to the Blue coalition. -- This would show the marker only to the Blue coalition.
-- --
-- ## For a Group -- ## For a Group
-- --
-- mymarker = MARKER:New( Coordinate , "Target Location" ):ToGroup( tankGroup )
-- --
-- # Removing a Marker -- # Removing a Marker
-- -- mymarker:Remove(60)
-- This removes the marker after 60 seconds
-- --
-- # Updating a Marker -- # Updating a Marker
-- --
@@ -175,8 +173,6 @@ function MARKER:New( Coordinate, Text )
-- Inherit everything from FSM class. -- Inherit everything from FSM class.
local self = BASE:Inherit( self, FSM:New() ) -- #MARKER local self = BASE:Inherit( self, FSM:New() ) -- #MARKER
local self=BASE:Inherit(self, FSM:New()) -- #MARKER
self.coordinate=UTILS.DeepCopy(Coordinate) self.coordinate=UTILS.DeepCopy(Coordinate)
self.text = Text self.text = Text
@@ -307,7 +303,7 @@ end
-- User API Functions -- User API Functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Marker is readonly. Text cannot be changed and marker cannot be removed. --- Marker is readonly. Text cannot be changed and marker cannot be removed. The will not update the marker in the game, Call MARKER:Refresh to update state.
-- @param #MARKER self -- @param #MARKER self
-- @return #MARKER self -- @return #MARKER self
function MARKER:ReadOnly() function MARKER:ReadOnly()
@@ -317,7 +313,7 @@ function MARKER:ReadOnly()
return self return self
end end
--- Marker is readonly. Text cannot be changed and marker cannot be removed. --- Marker is read and write. Text cannot be changed and marker cannot be removed. The will not update the marker in the game, Call MARKER:Refresh to update state.
-- @param #MARKER self -- @param #MARKER self
-- @return #MARKER self -- @return #MARKER self
function MARKER:ReadWrite() function MARKER:ReadWrite()
@@ -225,3 +225,10 @@ function SCENERY:FindAllByZoneName( ZoneName )
end end
end end
end end
--- SCENERY objects cannot be destroyed via the API (at the punishment of game crash).
--@param #SCENERY self
--@return #SCENERY self
function SCENERY:Destroy()
return self
end
+10 -8
View File
@@ -229,7 +229,7 @@ function UNIT:ReSpawnAt( Coordinate, Heading )
SpawnGroupTemplate.y = Coordinate.z SpawnGroupTemplate.y = Coordinate.z
self:F( #SpawnGroupTemplate.units ) self:F( #SpawnGroupTemplate.units )
for UnitID, UnitData in pairs( SpawnGroup:GetUnits() ) do for UnitID, UnitData in pairs( SpawnGroup:GetUnits() or {} ) do
local GroupUnit = UnitData -- #UNIT local GroupUnit = UnitData -- #UNIT
self:F( GroupUnit:GetName() ) self:F( GroupUnit:GetName() )
if GroupUnit:IsAlive() then if GroupUnit:IsAlive() then
@@ -631,20 +631,22 @@ end
-- @return Wrapper.Group#GROUP The Group of the Unit or `nil` if the unit does not exist. -- @return Wrapper.Group#GROUP The Group of the Unit or `nil` if the unit does not exist.
function UNIT:GetGroup() function UNIT:GetGroup()
self:F2( self.UnitName ) self:F2( self.UnitName )
local UnitGroup = GROUP:FindByName(self.GroupName)
if UnitGroup then
return UnitGroup
else
local DCSUnit = self:GetDCSObject() local DCSUnit = self:GetDCSObject()
if DCSUnit then if DCSUnit then
local UnitGroup = GROUP:FindByName( DCSUnit:getGroup():getName() ) local grp = DCSUnit:getGroup()
if grp then
local UnitGroup = GROUP:FindByName( grp:getName() )
return UnitGroup return UnitGroup
end end
end
end
return nil return nil
end end
-- Need to add here functions to check if radar is on and which object etc.
--- Returns the prefix name of the DCS Unit. A prefix name is a part of the name before a '#'-sign. --- Returns the prefix name of the DCS Unit. A prefix name is a part of the name before a '#'-sign.
-- DCS Units spawned with the @{Core.Spawn#SPAWN} class contain a '#'-sign to indicate the end of the (base) DCS Unit name. -- DCS Units spawned with the @{Core.Spawn#SPAWN} class contain a '#'-sign to indicate the end of the (base) DCS Unit name.
-- The spawn sequence number and unit number are contained within the name after the '#' sign. -- The spawn sequence number and unit number are contained within the name after the '#' sign.
+1 -1
View File
@@ -68,7 +68,7 @@ Pene has kindly created a [tutorial series for MOOSE](https://youtube.com/playli
## [MOOSE on Discord](https://discord.gg/yBPfxC6) ## [MOOSE on Discord](https://discord.gg/aQtjcR94Qf)
MOOSE has a living (chat and video) community of users, beta testers and contributors. The gathering point is a service provided by discord.com. If you want to join this community, just click Discord and you'll be on board in no time. MOOSE has a living (chat and video) community of users, beta testers and contributors. The gathering point is a service provided by discord.com. If you want to join this community, just click Discord and you'll be on board in no time.