mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Merge pull request #1112 from FlightControl-Master/FF/Develop
Carrier Ops
This commit is contained in:
commit
264e84649e
@ -7,7 +7,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI.AI_Air
|
-- @module AI.AI_Air
|
||||||
-- @image AI_Air_Operations.JPG
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
--- @type AI_AIR
|
--- @type AI_AIR
|
||||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||||
|
|||||||
@ -325,6 +325,7 @@ function SPAWN:New( SpawnTemplatePrefix )
|
|||||||
self.SpawnInitFreq = nil -- No special frequency.
|
self.SpawnInitFreq = nil -- No special frequency.
|
||||||
self.SpawnInitModu = nil -- No special modulation.
|
self.SpawnInitModu = nil -- No special modulation.
|
||||||
self.SpawnInitRadio = nil -- No radio comms setting.
|
self.SpawnInitRadio = nil -- No radio comms setting.
|
||||||
|
self.SpawnInitModex = nil
|
||||||
|
|
||||||
self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned.
|
self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned.
|
||||||
else
|
else
|
||||||
@ -376,6 +377,7 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix )
|
|||||||
self.SpawnInitFreq = nil -- No special frequency.
|
self.SpawnInitFreq = nil -- No special frequency.
|
||||||
self.SpawnInitModu = nil -- No special modulation.
|
self.SpawnInitModu = nil -- No special modulation.
|
||||||
self.SpawnInitRadio = nil -- No radio comms setting.
|
self.SpawnInitRadio = nil -- No radio comms setting.
|
||||||
|
self.SpawnInitModex = nil
|
||||||
|
|
||||||
self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned.
|
self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned.
|
||||||
else
|
else
|
||||||
@ -430,6 +432,7 @@ function SPAWN:NewFromTemplate( SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPr
|
|||||||
self.SpawnInitFreq = nil -- No special frequency.
|
self.SpawnInitFreq = nil -- No special frequency.
|
||||||
self.SpawnInitModu = nil -- No special modulation.
|
self.SpawnInitModu = nil -- No special modulation.
|
||||||
self.SpawnInitRadio = nil -- No radio comms setting.
|
self.SpawnInitRadio = nil -- No radio comms setting.
|
||||||
|
self.SpawnInitModex = nil
|
||||||
|
|
||||||
self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned.
|
self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned.
|
||||||
else
|
else
|
||||||
@ -642,6 +645,19 @@ function SPAWN:InitRadioModulation(modulation)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Sets the modex of the first unit of the group. If more units are in the group, the number is increased by one with every unit.
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @param #number modex Modex of the first unit.
|
||||||
|
-- @return #SPAWN self
|
||||||
|
function SPAWN:InitModex(modex)
|
||||||
|
|
||||||
|
if modex then
|
||||||
|
self.SpawnInitModex=tonumber(modex)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Randomizes the defined route of the SpawnTemplatePrefix group in the ME. This is very useful to define extra variation of the behaviour of groups.
|
--- Randomizes the defined route of the SpawnTemplatePrefix group in the ME. This is very useful to define extra variation of the behaviour of groups.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
@ -1219,6 +1235,12 @@ function SPAWN:SpawnWithIndex( SpawnIndex )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Set tail number.
|
||||||
|
if self.SpawnInitModex then
|
||||||
|
for UnitID = 1, #SpawnTemplate.units do
|
||||||
|
SpawnTemplate.units[UnitID].onboard_num = string.format("%03d", self.SpawnInitModex+(UnitID-1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Set radio comms on/off.
|
-- Set radio comms on/off.
|
||||||
if self.SpawnInitRadio then
|
if self.SpawnInitRadio then
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
--
|
--
|
||||||
-- ## Features:
|
-- ## Features:
|
||||||
--
|
--
|
||||||
-- * Impact points of bombs, rockets and missils are recorded and distance to closest range target is measured and reported to the player.
|
-- * Impact points of bombs, rockets and missiles are recorded and distance to closest range target is measured and reported to the player.
|
||||||
-- * Number of hits on strafing passes are counted and reported. Also the percentage of hits w.r.t fired shots is evaluated.
|
-- * Number of hits on strafing passes are counted and reported. Also the percentage of hits w.r.t fired shots is evaluated.
|
||||||
-- * Results of all bombing and strafing runs are stored and top 10 results can be displayed.
|
-- * Results of all bombing and strafing runs are stored and top 10 results can be displayed.
|
||||||
-- * Range targets can be marked by smoke.
|
-- * Range targets can be marked by smoke.
|
||||||
@ -56,9 +56,9 @@
|
|||||||
-- @field #table strafeStatus Table containing the current strafing target a player as assigned to.
|
-- @field #table strafeStatus Table containing the current strafing target a player as assigned to.
|
||||||
-- @field #table strafePlayerResults Table containing the strafing results of each player.
|
-- @field #table strafePlayerResults Table containing the strafing results of each player.
|
||||||
-- @field #table bombPlayerResults Table containing the bombing results of each player.
|
-- @field #table bombPlayerResults Table containing the bombing results of each player.
|
||||||
-- @field #table PlayerSettings Indiviual player settings.
|
-- @field #table PlayerSettings Individual player settings.
|
||||||
-- @field #number dtBombtrack Time step [sec] used for tracking released bomb/rocket positions. Default 0.005 seconds.
|
-- @field #number dtBombtrack Time step [sec] used for tracking released bomb/rocket positions. Default 0.005 seconds.
|
||||||
-- @field #number BombtrackThreshold Bombs/rockets/missiles are only tracked if player-range distance is smaller than this threashold [m]. Default 25000 m.
|
-- @field #number BombtrackThreshold Bombs/rockets/missiles are only tracked if player-range distance is smaller than this threshold [m]. Default 25000 m.
|
||||||
-- @field #number Tmsg Time [sec] messages to players are displayed. Default 30 sec.
|
-- @field #number Tmsg Time [sec] messages to players are displayed. Default 30 sec.
|
||||||
-- @field #string examinergroupname Name of the examiner group which should get all messages.
|
-- @field #string examinergroupname Name of the examiner group which should get all messages.
|
||||||
-- @field #boolean examinerexclusive If true, only the examiner gets messages. If false, clients and examiner get messages.
|
-- @field #boolean examinerexclusive If true, only the examiner gets messages. If false, clients and examiner get messages.
|
||||||
@ -75,10 +75,11 @@
|
|||||||
-- @field #boolean trackbombs If true (default), all bomb types are tracked and impact point to closest bombing target is evaluated.
|
-- @field #boolean trackbombs If true (default), all bomb types are tracked and impact point to closest bombing target is evaluated.
|
||||||
-- @field #boolean trackrockets If true (default), all rocket types are tracked and impact point to closest bombing target is evaluated.
|
-- @field #boolean trackrockets If true (default), all rocket types are tracked and impact point to closest bombing target is evaluated.
|
||||||
-- @field #boolean trackmissiles If true (default), all missile types are tracked and impact point to closest bombing target is evaluated.
|
-- @field #boolean trackmissiles If true (default), all missile types are tracked and impact point to closest bombing target is evaluated.
|
||||||
|
-- @field #boolean defaultsmokebomb If true, initialize player settings to smoke bomb.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
--- Enables a mission designer to easily set up practice ranges in DCS. A new RANGE object can be created with the @{#RANGE.New}(rangename) contructor.
|
--- Enables a mission designer to easily set up practice ranges in DCS. A new RANGE object can be created with the @{#RANGE.New}(rangename) contructor.
|
||||||
-- The parameter "rangename" defindes the name of the range. It has to be unique since this is also the name displayed in the radio menu.
|
-- The parameter "rangename" defines the name of the range. It has to be unique since this is also the name displayed in the radio menu.
|
||||||
--
|
--
|
||||||
-- Generally, a range consists of strafe pits and bombing targets. For strafe pits the number of hits for each pass is counted and tabulated.
|
-- Generally, a range consists of strafe pits and bombing targets. For strafe pits the number of hits for each pass is counted and tabulated.
|
||||||
-- For bombing targets, the distance from the impact point of the bomb, rocket or missile to the closest range target is measured and tabulated.
|
-- For bombing targets, the distance from the impact point of the bomb, rocket or missile to the closest range target is measured and tabulated.
|
||||||
@ -89,12 +90,12 @@
|
|||||||
-- **IMPORTANT**
|
-- **IMPORTANT**
|
||||||
--
|
--
|
||||||
-- Due to a DCS bug, it is not possible to directly monitor when a player enters a plane. So in a mission with client slots, it is vital that
|
-- Due to a DCS bug, it is not possible to directly monitor when a player enters a plane. So in a mission with client slots, it is vital that
|
||||||
-- a player first enters as spector and **after that** jumps into the slot of his aircraft!
|
-- a player first enters as spectator or hits ESC twice and **after that** jumps into the slot of his aircraft!
|
||||||
-- If that is not done, the script is not started correctly. This can be checked by looking at the radio menues. If the mission was entered correctly,
|
-- If that is not done, the script is not started correctly. This can be checked by looking at the radio menues. If the mission was entered correctly,
|
||||||
-- there should be an "On the Range" menu items in the "F10. Other..." menu.
|
-- there should be an "On the Range" menu items in the "F10. Other..." menu.
|
||||||
--
|
--
|
||||||
-- ## Strafe Pits
|
-- ## Strafe Pits
|
||||||
-- Each strafe pit can consist of multiple targets. Often one findes two or three strafe targets next to each other.
|
-- Each strafe pit can consist of multiple targets. Often one finds two or three strafe targets next to each other.
|
||||||
--
|
--
|
||||||
-- A strafe pit can be added to the range by the @{#RANGE.AddStrafePit}(*targetnames, boxlength, boxwidth, heading, inverseheading, goodpass, foulline*) function.
|
-- A strafe pit can be added to the range by the @{#RANGE.AddStrafePit}(*targetnames, boxlength, boxwidth, heading, inverseheading, goodpass, foulline*) function.
|
||||||
--
|
--
|
||||||
@ -104,7 +105,7 @@
|
|||||||
-- If the parameter *heading* is passed as **nil**, the heading is automatically taken from the heading of the first target unit as defined in the ME.
|
-- If the parameter *heading* is passed as **nil**, the heading is automatically taken from the heading of the first target unit as defined in the ME.
|
||||||
-- The parameter *inverseheading* turns the heading around by 180 degrees. This is sometimes useful, since the default heading of strafe target units point in the
|
-- The parameter *inverseheading* turns the heading around by 180 degrees. This is sometimes useful, since the default heading of strafe target units point in the
|
||||||
-- wrong/opposite direction.
|
-- wrong/opposite direction.
|
||||||
-- * The parameter *goodpass* defines the number of hits a pilot has to achive during a run to be judged as a "good" pass.
|
-- * The parameter *goodpass* defines the number of hits a pilot has to achieve during a run to be judged as a "good" pass.
|
||||||
-- * The last parameter *foulline* sets the distance from the pit targets to the foul line. Hit from closer than this line are not counted!
|
-- * The last parameter *foulline* sets the distance from the pit targets to the foul line. Hit from closer than this line are not counted!
|
||||||
--
|
--
|
||||||
-- Another function to add a strafe pit is @{#RANGE.AddStrafePitGroup}(*group, boxlength, boxwidth, heading, inverseheading, goodpass, foulline*). Here,
|
-- Another function to add a strafe pit is @{#RANGE.AddStrafePitGroup}(*group, boxlength, boxwidth, heading, inverseheading, goodpass, foulline*). Here,
|
||||||
@ -151,7 +152,7 @@
|
|||||||
-- * "F2. My Settings": Player specific settings.
|
-- * "F2. My Settings": Player specific settings.
|
||||||
-- * "F3. Stats" Player: statistics and scores.
|
-- * "F3. Stats" Player: statistics and scores.
|
||||||
-- * "Range Information": Information about the range, such as bearing and range. Also range and player specific settings are displayed.
|
-- * "Range Information": Information about the range, such as bearing and range. Also range and player specific settings are displayed.
|
||||||
-- * "Weather Report": Temperatur, wind and QFE pressure information is provided.
|
-- * "Weather Report": Temperature, wind and QFE pressure information is provided.
|
||||||
--
|
--
|
||||||
-- ## Examples
|
-- ## Examples
|
||||||
--
|
--
|
||||||
@ -243,6 +244,7 @@ RANGE={
|
|||||||
trackbombs=true,
|
trackbombs=true,
|
||||||
trackrockets=true,
|
trackrockets=true,
|
||||||
trackmissiles=true,
|
trackmissiles=true,
|
||||||
|
defaultsmokebomb=true,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Default range parameters.
|
--- Default range parameters.
|
||||||
@ -266,19 +268,25 @@ RANGE.Defaults={
|
|||||||
-- @field #table Names
|
-- @field #table Names
|
||||||
RANGE.Names={}
|
RANGE.Names={}
|
||||||
|
|
||||||
--- Main radio menu.
|
--- Main radio menu on group level.
|
||||||
-- @field #table MenuF10
|
-- @field #table MenuF10 Root menu table on group level.
|
||||||
RANGE.MenuF10={}
|
RANGE.MenuF10={}
|
||||||
|
|
||||||
|
--- Main radio menu on mission level.
|
||||||
|
-- @field #table MenuF10Root Root menu on mission level.
|
||||||
|
RANGE.MenuF10Root=nil
|
||||||
|
|
||||||
--- Some ID to identify who we are in output of the DCS.log file.
|
--- Some ID to identify who we are in output of the DCS.log file.
|
||||||
-- @field #string id
|
-- @field #string id
|
||||||
RANGE.id="RANGE | "
|
RANGE.id="RANGE | "
|
||||||
|
|
||||||
--- Range script version.
|
--- Range script version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
RANGE.version="1.2.3"
|
RANGE.version="1.2.4"
|
||||||
|
|
||||||
--TODO list:
|
--TODO list:
|
||||||
|
--TODO: Verbosity level for messages.
|
||||||
|
--TODO: Add option for default settings such as smoke off.
|
||||||
--TODO: Add custom weapons, which can be specified by the user.
|
--TODO: Add custom weapons, which can be specified by the user.
|
||||||
--TODO: Check if units are still alive.
|
--TODO: Check if units are still alive.
|
||||||
--DONE: Add statics for strafe pits.
|
--DONE: Add statics for strafe pits.
|
||||||
@ -311,15 +319,24 @@ function RANGE:New(rangename)
|
|||||||
self:E(RANGE.id..text)
|
self:E(RANGE.id..text)
|
||||||
MESSAGE:New(text, 10):ToAllIf(self.Debug)
|
MESSAGE:New(text, 10):ToAllIf(self.Debug)
|
||||||
|
|
||||||
|
-- Defaults
|
||||||
|
self:SetDefaultPlayerSmokeBomb()
|
||||||
|
|
||||||
-- Return object.
|
-- Return object.
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Initializes number of targets and location of the range. Starts the event handlers.
|
--- Initializes number of targets and location of the range. Starts the event handlers.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
function RANGE:Start()
|
-- @param #number delay Delay in seconds, before the RANGE is started. Default immediately.
|
||||||
|
-- @return self
|
||||||
|
function RANGE:Start(delay)
|
||||||
self:F()
|
self:F()
|
||||||
|
|
||||||
|
if delay and delay>0 then
|
||||||
|
SCHEDULER:New(nil, self.Start, {self}, delay)
|
||||||
|
else
|
||||||
|
|
||||||
-- Location/coordinate of range.
|
-- Location/coordinate of range.
|
||||||
local _location=nil
|
local _location=nil
|
||||||
|
|
||||||
@ -366,7 +383,7 @@ function RANGE:Start()
|
|||||||
|
|
||||||
-- Starting range.
|
-- Starting range.
|
||||||
local text=string.format("Starting RANGE %s. Number of strafe targets = %d. Number of bomb targets = %d.", self.rangename, self.nstrafetargets, self.nbombtargets)
|
local text=string.format("Starting RANGE %s. Number of strafe targets = %d. Number of bomb targets = %d.", self.rangename, self.nstrafetargets, self.nbombtargets)
|
||||||
self:E(RANGE.id..text)
|
self:I(RANGE.id..text)
|
||||||
MESSAGE:New(text,10):ToAllIf(self.Debug)
|
MESSAGE:New(text,10):ToAllIf(self.Debug)
|
||||||
|
|
||||||
-- Event handling.
|
-- Event handling.
|
||||||
@ -406,150 +423,208 @@ function RANGE:Start()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- User Functions
|
-- User Functions
|
||||||
|
|
||||||
--- Set maximal strafing altitude. Player entering a strafe pit above that altitude are not registered for a valid pass.
|
--- Set maximal strafing altitude. Player entering a strafe pit above that altitude are not registered for a valid pass.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #number maxalt Maximum altitude AGL in meters. Default is 914 m= 3000 ft.
|
-- @param #number maxalt Maximum altitude AGL in meters. Default is 914 m= 3000 ft.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:SetMaxStrafeAlt(maxalt)
|
function RANGE:SetMaxStrafeAlt(maxalt)
|
||||||
self.strafemaxalt=maxalt or RANGE.Defaults.strafemaxalt
|
self.strafemaxalt=maxalt or RANGE.Defaults.strafemaxalt
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set time interval for tracking bombs. A smaller time step increases accuracy but needs more CPU time.
|
--- Set time interval for tracking bombs. A smaller time step increases accuracy but needs more CPU time.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #number dt Time interval in seconds. Default is 0.005 s.
|
-- @param #number dt Time interval in seconds. Default is 0.005 s.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:SetBombtrackTimestep(dt)
|
function RANGE:SetBombtrackTimestep(dt)
|
||||||
self.dtBombtrack=dt or RANGE.Defaults.dtBombtrack
|
self.dtBombtrack=dt or RANGE.Defaults.dtBombtrack
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set time how long (most) messages are displayed.
|
--- Set time how long (most) messages are displayed.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #number time Time in seconds. Default is 30 s.
|
-- @param #number time Time in seconds. Default is 30 s.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:SetMessageTimeDuration(time)
|
function RANGE:SetMessageTimeDuration(time)
|
||||||
self.Tmsg=time or RANGE.Defaults.Tmsg
|
self.Tmsg=time or RANGE.Defaults.Tmsg
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set messages to examiner. The examiner will receive messages from all clients.
|
--- Set messages to examiner. The examiner will receive messages from all clients.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #string examinergroupname Name of the group of the examiner.
|
-- @param #string examinergroupname Name of the group of the examiner.
|
||||||
-- @param #boolean exclusively If true, messages are send exclusively to the examiner, i.e. not to the clients.
|
-- @param #boolean exclusively If true, messages are send exclusively to the examiner, i.e. not to the clients.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:SetMessageToExaminer(examinergroupname, exclusively)
|
function RANGE:SetMessageToExaminer(examinergroupname, exclusively)
|
||||||
self.examinergroupname=examinergroupname
|
self.examinergroupname=examinergroupname
|
||||||
self.examinerexclusive=exclusively
|
self.examinerexclusive=exclusively
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set max number of player results that are displayed.
|
--- Set max number of player results that are displayed.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #number nmax Number of results. Default is 10.
|
-- @param #number nmax Number of results. Default is 10.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:SetDisplayedMaxPlayerResults(nmax)
|
function RANGE:SetDisplayedMaxPlayerResults(nmax)
|
||||||
self.ndisplayresult=nmax or RANGE.Defaults.ndisplayresult
|
self.ndisplayresult=nmax or RANGE.Defaults.ndisplayresult
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set range radius. Defines the area in which e.g. bomb impacts are smoked.
|
--- Set range radius. Defines the area in which e.g. bomb impacts are smoked.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #number radius Radius in km. Default 5 km.
|
-- @param #number radius Radius in km. Default 5 km.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:SetRangeRadius(radius)
|
function RANGE:SetRangeRadius(radius)
|
||||||
self.rangeradius=radius*1000 or RANGE.Defaults.rangeradius
|
self.rangeradius=radius*1000 or RANGE.Defaults.rangeradius
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set player setting whether bomb impact points are smoked or not
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #boolean If true nor nil default is to smoke impact points of bombs.
|
||||||
|
-- @return #RANGE self
|
||||||
|
function RANGE:SetDefaultPlayerSmokeBomb(switch)
|
||||||
|
if switch==true or switch==nil then
|
||||||
|
self.defaultsmokebomb=true
|
||||||
|
else
|
||||||
|
self.defaultsmokebomb=false
|
||||||
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set bomb track threshold distance. Bombs/rockets/missiles are only tracked if player-range distance is less than this distance. Default 25 km.
|
--- Set bomb track threshold distance. Bombs/rockets/missiles are only tracked if player-range distance is less than this distance. Default 25 km.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #number distance Threshold distance in km. Default 25 km.
|
-- @param #number distance Threshold distance in km. Default 25 km.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:SetBombtrackThreshold(distance)
|
function RANGE:SetBombtrackThreshold(distance)
|
||||||
self.BombtrackThreshold=distance*1000 or 25*1000
|
self.BombtrackThreshold=distance*1000 or 25*1000
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set range location. If this is not done, one (random) unit position of the range is used to determine the location of the range.
|
--- Set range location. If this is not done, one (random) unit position of the range is used to determine the location of the range.
|
||||||
-- The range location determines the position at which the weather data is evaluated.
|
-- The range location determines the position at which the weather data is evaluated.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param Core.Point#COORDINATE coordinate Coordinate of the range.
|
-- @param Core.Point#COORDINATE coordinate Coordinate of the range.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:SetRangeLocation(coordinate)
|
function RANGE:SetRangeLocation(coordinate)
|
||||||
self.location=coordinate
|
self.location=coordinate
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set range zone. For example, no bomb impact points are smoked if a bomb falls outside of this zone.
|
--- Set range zone. For example, no bomb impact points are smoked if a bomb falls outside of this zone.
|
||||||
-- If a zone is not explicitly specified, the range zone is determined by its location and radius.
|
-- If a zone is not explicitly specified, the range zone is determined by its location and radius.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param Core.Zone#ZONE zone MOOSE zone defining the range perimeters.
|
-- @param Core.Zone#ZONE zone MOOSE zone defining the range perimeters.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:SetRangeZone(zone)
|
function RANGE:SetRangeZone(zone)
|
||||||
self.rangezone=zone
|
self.rangezone=zone
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set smoke color for marking bomb targets. By default bomb targets are marked by red smoke.
|
--- Set smoke color for marking bomb targets. By default bomb targets are marked by red smoke.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param Utilities.Utils#SMOKECOLOR colorid Color id. Default SMOKECOLOR.Red.
|
-- @param Utilities.Utils#SMOKECOLOR colorid Color id. Default SMOKECOLOR.Red.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:SetBombTargetSmokeColor(colorid)
|
function RANGE:SetBombTargetSmokeColor(colorid)
|
||||||
self.BombSmokeColor=colorid or SMOKECOLOR.Red
|
self.BombSmokeColor=colorid or SMOKECOLOR.Red
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set smoke color for marking strafe targets. By default strafe targets are marked by green smoke.
|
--- Set smoke color for marking strafe targets. By default strafe targets are marked by green smoke.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param Utilities.Utils#SMOKECOLOR colorid Color id. Default SMOKECOLOR.Green.
|
-- @param Utilities.Utils#SMOKECOLOR colorid Color id. Default SMOKECOLOR.Green.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:SetStrafeTargetSmokeColor(colorid)
|
function RANGE:SetStrafeTargetSmokeColor(colorid)
|
||||||
self.StrafeSmokeColor=colorid or SMOKECOLOR.Green
|
self.StrafeSmokeColor=colorid or SMOKECOLOR.Green
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set smoke color for marking strafe pit approach boxes. By default strafe pit boxes are marked by white smoke.
|
--- Set smoke color for marking strafe pit approach boxes. By default strafe pit boxes are marked by white smoke.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param Utilities.Utils#SMOKECOLOR colorid Color id. Default SMOKECOLOR.White.
|
-- @param Utilities.Utils#SMOKECOLOR colorid Color id. Default SMOKECOLOR.White.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:SetStrafePitSmokeColor(colorid)
|
function RANGE:SetStrafePitSmokeColor(colorid)
|
||||||
self.StrafePitSmokeColor=colorid or SMOKECOLOR.White
|
self.StrafePitSmokeColor=colorid or SMOKECOLOR.White
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set time delay between bomb impact and starting to smoke the impact point.
|
--- Set time delay between bomb impact and starting to smoke the impact point.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #number delay Time delay in seconds. Default is 3 seconds.
|
-- @param #number delay Time delay in seconds. Default is 3 seconds.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:SetSmokeTimeDelay(delay)
|
function RANGE:SetSmokeTimeDelay(delay)
|
||||||
self.TdelaySmoke=delay or RANGE.Defaults.TdelaySmoke
|
self.TdelaySmoke=delay or RANGE.Defaults.TdelaySmoke
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Enable debug modus.
|
--- Enable debug modus.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:DebugON()
|
function RANGE:DebugON()
|
||||||
self.Debug=true
|
self.Debug=true
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Disable debug modus.
|
--- Disable debug modus.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:DebugOFF()
|
function RANGE:DebugOFF()
|
||||||
self.Debug=false
|
self.Debug=false
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Enables tracking of all bomb types. Note that this is the default setting.
|
--- Enables tracking of all bomb types. Note that this is the default setting.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:TrackBombsON()
|
function RANGE:TrackBombsON()
|
||||||
self.trackbombs=true
|
self.trackbombs=true
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Disables tracking of all bomb types.
|
--- Disables tracking of all bomb types.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:TrackBombsOFF()
|
function RANGE:TrackBombsOFF()
|
||||||
self.trackbombs=false
|
self.trackbombs=false
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Enables tracking of all rocket types. Note that this is the default setting.
|
--- Enables tracking of all rocket types. Note that this is the default setting.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:TrackRocketsON()
|
function RANGE:TrackRocketsON()
|
||||||
self.trackrockets=true
|
self.trackrockets=true
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Disables tracking of all rocket types.
|
--- Disables tracking of all rocket types.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:TrackRocketsOFF()
|
function RANGE:TrackRocketsOFF()
|
||||||
self.trackrockets=false
|
self.trackrockets=false
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Enables tracking of all missile types. Note that this is the default setting.
|
--- Enables tracking of all missile types. Note that this is the default setting.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:TrackMissilesON()
|
function RANGE:TrackMissilesON()
|
||||||
self.trackmissiles=true
|
self.trackmissiles=true
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Disables tracking of all missile types.
|
--- Disables tracking of all missile types.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:TrackMissilesOFF()
|
function RANGE:TrackMissilesOFF()
|
||||||
self.trackmissiles=false
|
self.trackmissiles=false
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -564,6 +639,7 @@ end
|
|||||||
-- @param #boolean inverseheading (Optional) Take inverse heading (heading --> heading - 180 Degrees). Default is false.
|
-- @param #boolean inverseheading (Optional) Take inverse heading (heading --> heading - 180 Degrees). Default is false.
|
||||||
-- @param #number goodpass (Optional) Number of hits for a "good" strafing pass. Default is 20.
|
-- @param #number goodpass (Optional) Number of hits for a "good" strafing pass. Default is 20.
|
||||||
-- @param #number foulline (Optional) Foul line distance. Hits from closer than this distance are not counted. Default 610 m = 2000 ft. Set to 0 for no foul line.
|
-- @param #number foulline (Optional) Foul line distance. Hits from closer than this distance are not counted. Default 610 m = 2000 ft. Set to 0 for no foul line.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:AddStrafePit(targetnames, boxlength, boxwidth, heading, inverseheading, goodpass, foulline)
|
function RANGE:AddStrafePit(targetnames, boxlength, boxwidth, heading, inverseheading, goodpass, foulline)
|
||||||
self:F({targetnames=targetnames, boxlength=boxlength, boxwidth=boxwidth, heading=heading, inverseheading=inverseheading, goodpass=goodpass, foulline=foulline})
|
self:F({targetnames=targetnames, boxlength=boxlength, boxwidth=boxwidth, heading=heading, inverseheading=inverseheading, goodpass=goodpass, foulline=foulline})
|
||||||
|
|
||||||
@ -681,6 +757,8 @@ function RANGE:AddStrafePit(targetnames, boxlength, boxwidth, heading, inversehe
|
|||||||
local text=string.format("Adding new strafe target %s with %d targets: heading = %03d, box_L = %.1f, box_W = %.1f, goodpass = %d, foul line = %.1f", _name, ntargets, heading, l, w, goodpass, foulline)
|
local text=string.format("Adding new strafe target %s with %d targets: heading = %03d, box_L = %.1f, box_W = %.1f, goodpass = %d, foul line = %.1f", _name, ntargets, heading, l, w, goodpass, foulline)
|
||||||
self:T(RANGE.id..text)
|
self:T(RANGE.id..text)
|
||||||
MESSAGE:New(text, 5):ToAllIf(self.Debug)
|
MESSAGE:New(text, 5):ToAllIf(self.Debug)
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -696,6 +774,7 @@ end
|
|||||||
-- @param #boolean inverseheading (Optional) Take inverse heading (heading --> heading - 180 Degrees). Default is false.
|
-- @param #boolean inverseheading (Optional) Take inverse heading (heading --> heading - 180 Degrees). Default is false.
|
||||||
-- @param #number goodpass (Optional) Number of hits for a "good" strafing pass. Default is 20.
|
-- @param #number goodpass (Optional) Number of hits for a "good" strafing pass. Default is 20.
|
||||||
-- @param #number foulline (Optional) Foul line distance. Hits from closer than this distance are not counted. Default 610 m = 2000 ft. Set to 0 for no foul line.
|
-- @param #number foulline (Optional) Foul line distance. Hits from closer than this distance are not counted. Default 610 m = 2000 ft. Set to 0 for no foul line.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:AddStrafePitGroup(group, boxlength, boxwidth, heading, inverseheading, goodpass, foulline)
|
function RANGE:AddStrafePitGroup(group, boxlength, boxwidth, heading, inverseheading, goodpass, foulline)
|
||||||
self:F({group=group, boxlength=boxlength, boxwidth=boxwidth, heading=heading, inverseheading=inverseheading, goodpass=goodpass, foulline=foulline})
|
self:F({group=group, boxlength=boxlength, boxwidth=boxwidth, heading=heading, inverseheading=inverseheading, goodpass=goodpass, foulline=foulline})
|
||||||
|
|
||||||
@ -721,6 +800,7 @@ function RANGE:AddStrafePitGroup(group, boxlength, boxwidth, heading, inversehea
|
|||||||
self:AddStrafePit(_names, boxlength, boxwidth, heading, inverseheading, goodpass, foulline)
|
self:AddStrafePit(_names, boxlength, boxwidth, heading, inverseheading, goodpass, foulline)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add bombing target(s) to range.
|
--- Add bombing target(s) to range.
|
||||||
@ -728,6 +808,7 @@ end
|
|||||||
-- @param #table targetnames Table containing names of unit or static objects serving as bomb targets.
|
-- @param #table targetnames Table containing names of unit or static objects serving as bomb targets.
|
||||||
-- @param #number goodhitrange (Optional) Max distance from target unit (in meters) which is considered as a good hit. Default is 25 m.
|
-- @param #number goodhitrange (Optional) Max distance from target unit (in meters) which is considered as a good hit. Default is 25 m.
|
||||||
-- @param #boolean randommove If true, unit will move randomly within the range. Default is false.
|
-- @param #boolean randommove If true, unit will move randomly within the range. Default is false.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:AddBombingTargets(targetnames, goodhitrange, randommove)
|
function RANGE:AddBombingTargets(targetnames, goodhitrange, randommove)
|
||||||
self:F({targetnames=targetnames, goodhitrange=goodhitrange, randommove=randommove})
|
self:F({targetnames=targetnames, goodhitrange=goodhitrange, randommove=randommove})
|
||||||
|
|
||||||
@ -757,6 +838,8 @@ function RANGE:AddBombingTargets(targetnames, goodhitrange, randommove)
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add a unit or static object as bombing target.
|
--- Add a unit or static object as bombing target.
|
||||||
@ -764,6 +847,7 @@ end
|
|||||||
-- @param Wrapper.Positionable#POSITIONABLE unit Positionable (unit or static) of the strafe target.
|
-- @param Wrapper.Positionable#POSITIONABLE unit Positionable (unit or static) of the strafe target.
|
||||||
-- @param #number goodhitrange Max distance from unit which is considered as a good hit.
|
-- @param #number goodhitrange Max distance from unit which is considered as a good hit.
|
||||||
-- @param #boolean randommove If true, unit will move randomly within the range. Default is false.
|
-- @param #boolean randommove If true, unit will move randomly within the range. Default is false.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:AddBombingTargetUnit(unit, goodhitrange, randommove)
|
function RANGE:AddBombingTargetUnit(unit, goodhitrange, randommove)
|
||||||
self:F({unit=unit, goodhitrange=goodhitrange, randommove=randommove})
|
self:F({unit=unit, goodhitrange=goodhitrange, randommove=randommove})
|
||||||
|
|
||||||
@ -798,6 +882,8 @@ function RANGE:AddBombingTargetUnit(unit, goodhitrange, randommove)
|
|||||||
|
|
||||||
-- Insert target to table.
|
-- Insert target to table.
|
||||||
table.insert(self.bombingTargets, {name=name, target=unit, goodhitrange=goodhitrange, move=randommove, speed=speed})
|
table.insert(self.bombingTargets, {name=name, target=unit, goodhitrange=goodhitrange, move=randommove, speed=speed})
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add all units of a group as bombing targets.
|
--- Add all units of a group as bombing targets.
|
||||||
@ -805,6 +891,7 @@ end
|
|||||||
-- @param Wrapper.Group#GROUP group Group of bombing targets.
|
-- @param Wrapper.Group#GROUP group Group of bombing targets.
|
||||||
-- @param #number goodhitrange Max distance from unit which is considered as a good hit.
|
-- @param #number goodhitrange Max distance from unit which is considered as a good hit.
|
||||||
-- @param #boolean randommove If true, unit will move randomly within the range. Default is false.
|
-- @param #boolean randommove If true, unit will move randomly within the range. Default is false.
|
||||||
|
-- @return #RANGE self
|
||||||
function RANGE:AddBombingTargetGroup(group, goodhitrange, randommove)
|
function RANGE:AddBombingTargetGroup(group, goodhitrange, randommove)
|
||||||
self:F({group=group, goodhitrange=goodhitrange, randommove=randommove})
|
self:F({group=group, goodhitrange=goodhitrange, randommove=randommove})
|
||||||
|
|
||||||
@ -819,6 +906,7 @@ function RANGE:AddBombingTargetGroup(group, goodhitrange, randommove)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Measures the foule line distance between two unit or static objects.
|
--- Measures the foule line distance between two unit or static objects.
|
||||||
@ -971,11 +1059,12 @@ function RANGE:OnEventBirth(EventData)
|
|||||||
|
|
||||||
-- By default, some bomb impact points and do not flare each hit on target.
|
-- By default, some bomb impact points and do not flare each hit on target.
|
||||||
self.PlayerSettings[_playername]={}
|
self.PlayerSettings[_playername]={}
|
||||||
self.PlayerSettings[_playername].smokebombimpact=true
|
self.PlayerSettings[_playername].smokebombimpact=self.defaultsmokebomb
|
||||||
self.PlayerSettings[_playername].flaredirecthits=false
|
self.PlayerSettings[_playername].flaredirecthits=false
|
||||||
self.PlayerSettings[_playername].smokecolor=SMOKECOLOR.Blue
|
self.PlayerSettings[_playername].smokecolor=SMOKECOLOR.Blue
|
||||||
self.PlayerSettings[_playername].flarecolor=FLARECOLOR.Red
|
self.PlayerSettings[_playername].flarecolor=FLARECOLOR.Red
|
||||||
self.PlayerSettings[_playername].delaysmoke=true
|
self.PlayerSettings[_playername].delaysmoke=true
|
||||||
|
self.PlayerSettings[_playername].messages=true
|
||||||
|
|
||||||
-- Start check in zone timer.
|
-- Start check in zone timer.
|
||||||
if self.planes[_uid] ~= true then
|
if self.planes[_uid] ~= true then
|
||||||
@ -1042,7 +1131,7 @@ function RANGE:OnEventHit(EventData)
|
|||||||
if _currentTarget.pastfoulline==false and _unit and _playername then
|
if _currentTarget.pastfoulline==false and _unit and _playername then
|
||||||
local _d=_currentTarget.zone.foulline
|
local _d=_currentTarget.zone.foulline
|
||||||
local text=string.format("%s, Invalid hit!\nYou already passed foul line distance of %d m for target %s.", self:_myname(_unitName), _d, targetname)
|
local text=string.format("%s, Invalid hit!\nYou already passed foul line distance of %d m for target %s.", self:_myname(_unitName), _d, targetname)
|
||||||
self:_DisplayMessageToGroup(_unit, text, 10)
|
self:_DisplayMessageToGroup(_unit, text)
|
||||||
self:T2(RANGE.id..text)
|
self:T2(RANGE.id..text)
|
||||||
_currentTarget.pastfoulline=true
|
_currentTarget.pastfoulline=true
|
||||||
end
|
end
|
||||||
@ -1320,7 +1409,7 @@ function RANGE:_DisplayMyStrafePitResults(_unitName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Send message to group.
|
-- Send message to group.
|
||||||
self:_DisplayMessageToGroup(_unit, _message, nil, true)
|
self:_DisplayMessageToGroup(_unit, _message, nil, true, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1376,7 +1465,7 @@ function RANGE:_DisplayStrafePitResults(_unitName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Send message.
|
-- Send message.
|
||||||
self:_DisplayMessageToGroup(_unit, _message, nil, true)
|
self:_DisplayMessageToGroup(_unit, _message, nil, true, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1433,7 +1522,7 @@ function RANGE:_DisplayMyBombingResults(_unitName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Send message.
|
-- Send message.
|
||||||
self:_DisplayMessageToGroup(_unit, _message, nil, true)
|
self:_DisplayMessageToGroup(_unit, _message, nil, true, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1489,7 +1578,7 @@ function RANGE:_DisplayBombingResults(_unitName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Send message.
|
-- Send message.
|
||||||
self:_DisplayMessageToGroup(_unit, _message, nil, true)
|
self:_DisplayMessageToGroup(_unit, _message, nil, true, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1566,7 +1655,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)
|
self:_DisplayMessageToGroup(unit, text, nil, true, true)
|
||||||
|
|
||||||
-- Debug output.
|
-- Debug output.
|
||||||
self:T2(RANGE.id..text)
|
self:T2(RANGE.id..text)
|
||||||
@ -1603,7 +1692,7 @@ function RANGE:_DisplayBombTargets(_unitname)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:_DisplayMessageToGroup(_unit,_text, nil, true)
|
self:_DisplayMessageToGroup(_unit,_text, nil, true, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1643,7 +1732,7 @@ function RANGE:_DisplayStrafePits(_unitname)
|
|||||||
_text=_text..string.format("\n- %s: %s - heading %03d",_strafepit.name, mycoord, heading)
|
_text=_text..string.format("\n- %s: %s - heading %03d",_strafepit.name, mycoord, heading)
|
||||||
end
|
end
|
||||||
|
|
||||||
self:_DisplayMessageToGroup(_unit,_text, nil, true)
|
self:_DisplayMessageToGroup(_unit,_text, nil, true, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1705,7 +1794,7 @@ function RANGE:_DisplayRangeWeather(_unitname)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Send message to player group.
|
-- Send message to player group.
|
||||||
self:_DisplayMessageToGroup(unit, text, nil, true)
|
self:_DisplayMessageToGroup(unit, text, nil, true, true)
|
||||||
|
|
||||||
-- Debug output.
|
-- Debug output.
|
||||||
self:T2(RANGE.id..text)
|
self:T2(RANGE.id..text)
|
||||||
@ -1749,7 +1838,7 @@ function RANGE:_CheckInZone(_unitName)
|
|||||||
local unitinzone=_unit:IsInZone(zone) and unitalt <= self.strafemaxalt and towardspit
|
local unitinzone=_unit:IsInZone(zone) and unitalt <= self.strafemaxalt and towardspit
|
||||||
|
|
||||||
-- Debug output
|
-- Debug output
|
||||||
local text=string.format("Checking stil in zone. Unit = %s, player = %s in zone = %s. alt = %d, delta heading = %d", _unitName, _playername, tostring(unitinzone), unitalt, deltaheading)
|
local text=string.format("Checking still in zone. Unit = %s, player = %s in zone = %s. alt = %d, delta heading = %d", _unitName, _playername, tostring(unitinzone), unitalt, deltaheading)
|
||||||
self:T2(RANGE.id..text)
|
self:T2(RANGE.id..text)
|
||||||
|
|
||||||
-- Check if player is in strafe zone and below max alt.
|
-- Check if player is in strafe zone and below max alt.
|
||||||
@ -1895,11 +1984,32 @@ function RANGE:_AddF10Commands(_unitName)
|
|||||||
-- Enable switch so we don't do this twice.
|
-- Enable switch so we don't do this twice.
|
||||||
self.MenuAddedTo[_gid] = true
|
self.MenuAddedTo[_gid] = true
|
||||||
|
|
||||||
|
-- Range root menu path.
|
||||||
|
local _rangePath=nil
|
||||||
|
|
||||||
|
if RANGE.MenuF10Root then
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
-- MISSION LEVEL --
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
_rangePath = missionCommands.addSubMenuForGroup(_gid, self.rangename, RANGE.MenuF10Root)
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
-- GROUP LEVEL --
|
||||||
|
-----------------
|
||||||
|
|
||||||
-- Main F10 menu: F10/On the Range/<Range Name>/
|
-- Main F10 menu: F10/On the Range/<Range Name>/
|
||||||
if RANGE.MenuF10[_gid] == nil then
|
if RANGE.MenuF10[_gid] == nil then
|
||||||
RANGE.MenuF10[_gid]=missionCommands.addSubMenuForGroup(_gid, "On the Range")
|
RANGE.MenuF10[_gid]=missionCommands.addSubMenuForGroup(_gid, "On the Range")
|
||||||
end
|
end
|
||||||
local _rangePath = missionCommands.addSubMenuForGroup(_gid, self.rangename, RANGE.MenuF10[_gid])
|
_rangePath = missionCommands.addSubMenuForGroup(_gid, self.rangename, RANGE.MenuF10[_gid])
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
local _statsPath = missionCommands.addSubMenuForGroup(_gid, "Statistics", _rangePath)
|
local _statsPath = missionCommands.addSubMenuForGroup(_gid, "Statistics", _rangePath)
|
||||||
local _markPath = missionCommands.addSubMenuForGroup(_gid, "Mark Targets", _rangePath)
|
local _markPath = missionCommands.addSubMenuForGroup(_gid, "Mark Targets", _rangePath)
|
||||||
local _settingsPath = missionCommands.addSubMenuForGroup(_gid, "My Settings", _rangePath)
|
local _settingsPath = missionCommands.addSubMenuForGroup(_gid, "My Settings", _rangePath)
|
||||||
@ -1935,6 +2045,8 @@ function RANGE:_AddF10Commands(_unitName)
|
|||||||
missionCommands.addCommandForGroup(_gid, "Smoke Delay On/Off", _settingsPath, self._SmokeBombDelayOnOff, self, _unitName)
|
missionCommands.addCommandForGroup(_gid, "Smoke Delay On/Off", _settingsPath, self._SmokeBombDelayOnOff, self, _unitName)
|
||||||
missionCommands.addCommandForGroup(_gid, "Smoke Impact On/Off", _settingsPath, self._SmokeBombImpactOnOff, self, _unitName)
|
missionCommands.addCommandForGroup(_gid, "Smoke Impact On/Off", _settingsPath, self._SmokeBombImpactOnOff, self, _unitName)
|
||||||
missionCommands.addCommandForGroup(_gid, "Flare Hits On/Off", _settingsPath, self._FlareDirectHitsOnOff, self, _unitName)
|
missionCommands.addCommandForGroup(_gid, "Flare Hits On/Off", _settingsPath, self._FlareDirectHitsOnOff, self, _unitName)
|
||||||
|
missionCommands.addCommandForGroup(_gid, "All Messages On/Off", _settingsPath, self._MessagesToPlayerOnOff, self, _unitName)
|
||||||
|
|
||||||
-- F10/On the Range/<Range Name>/Range Information
|
-- F10/On the Range/<Range Name>/Range Information
|
||||||
missionCommands.addCommandForGroup(_gid, "General Info", _infoPath, self._DisplayRangeInfo, self, _unitName)
|
missionCommands.addCommandForGroup(_gid, "General Info", _infoPath, self._DisplayRangeInfo, self, _unitName)
|
||||||
missionCommands.addCommandForGroup(_gid, "Weather Report", _infoPath, self._DisplayRangeWeather, self, _unitName)
|
missionCommands.addCommandForGroup(_gid, "Weather Report", _infoPath, self._DisplayRangeWeather, self, _unitName)
|
||||||
@ -2114,7 +2226,7 @@ function RANGE:_ResetRangeStats(_unitName)
|
|||||||
self.strafePlayerResults[_playername] = nil
|
self.strafePlayerResults[_playername] = nil
|
||||||
self.bombPlayerResults[_playername] = nil
|
self.bombPlayerResults[_playername] = nil
|
||||||
local text=string.format("%s, %s, your range stats were cleared.", self.rangename, _playername)
|
local text=string.format("%s, %s, your range stats were cleared.", self.rangename, _playername)
|
||||||
self:DisplayMessageToGroup(_unit, text, 5)
|
self:DisplayMessageToGroup(_unit, text, 5, false, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -2124,33 +2236,35 @@ end
|
|||||||
-- @param #string _text Message text.
|
-- @param #string _text Message text.
|
||||||
-- @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.
|
||||||
function RANGE:_DisplayMessageToGroup(_unit, _text, _time, _clear)
|
-- @param #boolean display If true, display message regardless of player setting "Messages Off".
|
||||||
|
function RANGE:_DisplayMessageToGroup(_unit, _text, _time, _clear, display)
|
||||||
self:F({unit=_unit, text=_text, time=_time, clear=_clear})
|
self:F({unit=_unit, text=_text, time=_time, clear=_clear})
|
||||||
|
|
||||||
|
-- Defaults
|
||||||
_time=_time or self.Tmsg
|
_time=_time or self.Tmsg
|
||||||
if _clear==nil then
|
if _clear==nil or _clear==false then
|
||||||
_clear=false
|
_clear=false
|
||||||
|
else
|
||||||
|
_clear=true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Group ID.
|
-- Group ID.
|
||||||
local _gid=_unit:GetGroup():GetID()
|
local _gid=_unit:GetGroup():GetID()
|
||||||
|
|
||||||
if _gid and not self.examinerexclusive then
|
-- Get playername and player settings
|
||||||
if _clear == true then
|
local _, playername=self:_GetPlayerUnitAndName(_unit:GetName())
|
||||||
|
local playermessage=self.PlayerSettings[playername].messages
|
||||||
|
|
||||||
|
-- Send message to player if messages enabled and not only for the examiner.
|
||||||
|
if _gid and (playermessage==true or display) and (not self.examinerexclusive) then
|
||||||
trigger.action.outTextForGroup(_gid, _text, _time, _clear)
|
trigger.action.outTextForGroup(_gid, _text, _time, _clear)
|
||||||
else
|
|
||||||
trigger.action.outTextForGroup(_gid, _text, _time)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Send message to examiner.
|
||||||
if self.examinergroupname~=nil then
|
if self.examinergroupname~=nil then
|
||||||
local _examinerid=GROUP:FindByName(self.examinergroupname):GetID()
|
local _examinerid=GROUP:FindByName(self.examinergroupname):GetID()
|
||||||
if _examinerid then
|
if _examinerid then
|
||||||
if _clear == true then
|
|
||||||
trigger.action.outTextForGroup(_examinerid, _text, _time, _clear)
|
trigger.action.outTextForGroup(_examinerid, _text, _time, _clear)
|
||||||
else
|
|
||||||
trigger.action.outTextForGroup(_examinerid, _text, _time)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -2172,7 +2286,7 @@ function RANGE:_SmokeBombImpactOnOff(unitname)
|
|||||||
self.PlayerSettigs[playername].smokebombimpact=true
|
self.PlayerSettigs[playername].smokebombimpact=true
|
||||||
text=string.format("%s, %s, smoking impact points of bombs is now ON.", self.rangename, playername)
|
text=string.format("%s, %s, smoking impact points of bombs is now ON.", self.rangename, playername)
|
||||||
end
|
end
|
||||||
self:_DisplayMessageToGroup(unit, text, 5)
|
self:_DisplayMessageToGroup(unit, text, 5, false, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -2193,7 +2307,27 @@ function RANGE:_SmokeBombDelayOnOff(unitname)
|
|||||||
self.PlayerSettigs[playername].delaysmoke=true
|
self.PlayerSettigs[playername].delaysmoke=true
|
||||||
text=string.format("%s, %s, delayed smoke of bombs is now ON.", self.rangename, playername)
|
text=string.format("%s, %s, delayed smoke of bombs is now ON.", self.rangename, playername)
|
||||||
end
|
end
|
||||||
self:_DisplayMessageToGroup(unit, text, 5)
|
self:_DisplayMessageToGroup(unit, text, 5, false, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle display messages to player.
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #string unitname Name of the player unit.
|
||||||
|
function RANGE:_MessagesToPlayerOnOff(unitname)
|
||||||
|
self:F(unitname)
|
||||||
|
|
||||||
|
local unit, playername = self:_GetPlayerUnitAndName(unitname)
|
||||||
|
if unit and playername then
|
||||||
|
local text
|
||||||
|
if self.PlayerSettings[playername].messages==true then
|
||||||
|
text=string.format("%s, %s, display of ALL messages is now OFF.", self.rangename, playername)
|
||||||
|
else
|
||||||
|
text=string.format("%s, %s, display of ALL messages is now ON.", self.rangename, playername)
|
||||||
|
end
|
||||||
|
self:_DisplayMessageToGroup(unit, text, 5, false, true)
|
||||||
|
self.PlayerSettings[playername].messages=not self.PlayerSettings[playername].messages
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -2214,7 +2348,7 @@ function RANGE:_FlareDirectHitsOnOff(unitname)
|
|||||||
self.PlayerSettings[playername].flaredirecthits=true
|
self.PlayerSettings[playername].flaredirecthits=true
|
||||||
text=string.format("%s, %s, flaring direct hits is now ON.", self.rangename, playername)
|
text=string.format("%s, %s, flaring direct hits is now ON.", self.rangename, playername)
|
||||||
end
|
end
|
||||||
self:_DisplayMessageToGroup(unit, text, 5)
|
self:_DisplayMessageToGroup(unit, text, 5, false, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -2332,7 +2466,7 @@ function RANGE:_smokecolor2text(color)
|
|||||||
elseif color==SMOKECOLOR.White then
|
elseif color==SMOKECOLOR.White then
|
||||||
txt="white"
|
txt="white"
|
||||||
else
|
else
|
||||||
txt=string.format("unkown color (%s)", tostring(color))
|
txt=string.format("unknown color (%s)", tostring(color))
|
||||||
end
|
end
|
||||||
|
|
||||||
return txt
|
return txt
|
||||||
@ -2355,7 +2489,7 @@ function RANGE:_flarecolor2text(color)
|
|||||||
elseif color==FLARECOLOR.Yellow then
|
elseif color==FLARECOLOR.Yellow then
|
||||||
txt="yellow"
|
txt="yellow"
|
||||||
else
|
else
|
||||||
txt=string.format("unkown color (%s)", tostring(color))
|
txt=string.format("unknown color (%s)", tostring(color))
|
||||||
end
|
end
|
||||||
|
|
||||||
return txt
|
return txt
|
||||||
|
|||||||
@ -45,6 +45,11 @@
|
|||||||
-- **PLEASE NOTE** that his class is work in progress and in an early **alpha** stage. Many/most things work already very nicely but there a lot of cases I did not run into yet.
|
-- **PLEASE NOTE** that his class is work in progress and in an early **alpha** stage. Many/most things work already very nicely but there a lot of cases I did not run into yet.
|
||||||
-- Therefore, your *constructive* feedback is both necessary and appreciated!
|
-- Therefore, your *constructive* feedback is both necessary and appreciated!
|
||||||
--
|
--
|
||||||
|
-- ## Discussion
|
||||||
|
--
|
||||||
|
-- If you have questions or suggestions, visit the MOOSE Discord [#ops-airboss](https://discordapp.com/channels/378590350614462464/527363141185830915) channel.
|
||||||
|
-- There you also find an example mission and the necessary voice over sound files. Check the **pinned messages**.
|
||||||
|
--
|
||||||
-- ## IMPORTANT
|
-- ## IMPORTANT
|
||||||
--
|
--
|
||||||
-- Due to technical restrictions of DCS make sure you have:
|
-- Due to technical restrictions of DCS make sure you have:
|
||||||
@ -52,6 +57,12 @@
|
|||||||
-- * Each player slot in a separate group. DCS does only allow to send messages to groups and not to individual units.
|
-- * Each player slot in a separate group. DCS does only allow to send messages to groups and not to individual units.
|
||||||
-- * Players are identified by their player name. Ensure that no two player have the same name, e.g. "New Callsign", as this will lead to unexpected results.
|
-- * Players are identified by their player name. Ensure that no two player have the same name, e.g. "New Callsign", as this will lead to unexpected results.
|
||||||
--
|
--
|
||||||
|
-- ## Youtube Videos
|
||||||
|
--
|
||||||
|
-- * [[MOOSE] Airboss - Groove Testing (WIP)](https://www.youtube.com/watch?v=94KHQxxX3UI)
|
||||||
|
-- * [[MOOSE] Airboss - Groove Test A-4E Community Mod](https://www.youtube.com/watch?v=ZbjD7FHiaHo)
|
||||||
|
--
|
||||||
|
--
|
||||||
-- ### Open Questions?
|
-- ### Open Questions?
|
||||||
--
|
--
|
||||||
-- * Currently the script does not support spin patterns. Marshal releases flights only when there is a free slot in the landing pattern. How is this handled in real life?
|
-- * Currently the script does not support spin patterns. Marshal releases flights only when there is a free slot in the landing pattern. How is this handled in real life?
|
||||||
@ -163,6 +174,8 @@
|
|||||||
-- @field Core.Set#SET_GROUP squadsetAI AI groups in this set will be handled by the airboss.
|
-- @field Core.Set#SET_GROUP squadsetAI AI groups in this set will be handled by the airboss.
|
||||||
-- @field #boolean menusingle If true, menu is optimized for a single carrier.
|
-- @field #boolean menusingle If true, menu is optimized for a single carrier.
|
||||||
-- @field #number collisiondist Distance up to which collision checks are done.
|
-- @field #number collisiondist Distance up to which collision checks are done.
|
||||||
|
-- @field #number Tmessage Default duration in seconds messages are displayed to players.
|
||||||
|
-- @field #string soundfolder Folder within the mission (miz) file where airboss sound files are located.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- Be the boss!
|
--- Be the boss!
|
||||||
@ -246,9 +259,11 @@
|
|||||||
-- The F10 radio menu can be used to post requests to Marshal but also provides information about the player and carrier status. Additionally, helper functions
|
-- The F10 radio menu can be used to post requests to Marshal but also provides information about the player and carrier status. Additionally, helper functions
|
||||||
-- can be called.
|
-- can be called.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- By default, the script creates a submenu "Airboss" in the "F10 Other ..." menu and each @{#AIRBOSS} carrier gets its own submenu.
|
-- By default, the script creates a submenu "Airboss" in the "F10 Other ..." menu and each @{#AIRBOSS} carrier gets its own submenu.
|
||||||
-- If you intend to have only one carrier, you can simplify the menu structure using the @{#AIRBOSS.SetMenuSingleCarrier} function, which will create all carrier specific menu entries directly
|
-- If you intend to have only one carrier, you can simplify the menu structure using the @{#AIRBOSS.SetMenuSingleCarrier} function, which will create all carrier specific menu entries directly
|
||||||
-- in the "Airboss" submenu. (Needless to say, that if you enable this and define mulitiple carriers, the menu structure will get completely screwed up.)
|
-- in the "Airboss" submenu. (Needless to say, that if you enable this and define multiple carriers, the menu structure will get completely screwed up.)
|
||||||
--
|
--
|
||||||
-- ## Root Menu
|
-- ## Root Menu
|
||||||
--
|
--
|
||||||
@ -274,9 +289,17 @@
|
|||||||
-- ### Request Commence
|
-- ### Request Commence
|
||||||
--
|
--
|
||||||
-- This command can be used to request commencing from the marshal stack to the landing pattern. Necessary condition is that the player is in the lowest marshal stack
|
-- This command can be used to request commencing from the marshal stack to the landing pattern. Necessary condition is that the player is in the lowest marshal stack
|
||||||
-- and that the number of aircraft in the landing pattern is smaller than four.
|
-- and that the number of aircraft in the landing pattern is smaller than four (or the number set by the mission designer).
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- The image displays the standard Case I Marshal pattern recovery. Pilots are supposed to fly a clockwise circle and descent between the **3** and **1** positions.
|
||||||
|
--
|
||||||
|
-- Commence should be performed at around the **3** position. If the pilot is in the lowest Marshal stack, and flies through this area, he is automatically cleared for the
|
||||||
|
-- landing pattern. In other words, there is no need for the "Request Commence" radio command. The zone can be marked via smoke or flared using the player's F10 radio menu.
|
||||||
--
|
--
|
||||||
-- A player can also request commencing if he is not registered in a marshal stack yet. If the pattern is free, Marshal will allow him to directly enter the landing pattern.
|
-- A player can also request commencing if he is not registered in a marshal stack yet. If the pattern is free, Marshal will allow him to directly enter the landing pattern.
|
||||||
|
-- However, this is only possible when the Airboss has a nice day - see @{#AIRBOSS.SetAirbossNiceGuy}.
|
||||||
--
|
--
|
||||||
-- ### Request Refueling
|
-- ### Request Refueling
|
||||||
--
|
--
|
||||||
@ -441,7 +464,7 @@
|
|||||||
-- * **IM** In the Middle (0.5 NM = 926 m), middle one third of the glideslope.
|
-- * **IM** In the Middle (0.5 NM = 926 m), middle one third of the glideslope.
|
||||||
-- * **IC** In Close (0.25 NM = 463 m), last one third of the glideslope.
|
-- * **IC** In Close (0.25 NM = 463 m), last one third of the glideslope.
|
||||||
-- * **AR** At the Ramp (0.027 NM = 50 m).
|
-- * **AR** At the Ramp (0.027 NM = 50 m).
|
||||||
-- * **IW** In the Wiress (at the landing position).
|
-- * **IW** In the Wires (at the landing position).
|
||||||
--
|
--
|
||||||
-- Grading at each step includes the above calls, i.e.
|
-- Grading at each step includes the above calls, i.e.
|
||||||
--
|
--
|
||||||
@ -689,6 +712,27 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
-- # Sound Files
|
||||||
|
--
|
||||||
|
-- An important aspect of the AIRBOSS is that it uses voice overs for greater immersion. The necessary sound files can be obtained from the
|
||||||
|
-- MOOSE Discord in the [#ops-airboss](https://discordapp.com/channels/378590350614462464/527363141185830915) channel. Check out the **pinned messages**.
|
||||||
|
--
|
||||||
|
-- However, including sound files into a new mission is tedious as these usually need to be included into the mission **miz** file via (unused) triggers.
|
||||||
|
--
|
||||||
|
-- The default location inside the miz file is "l10n/DEFAULT/". But simply opening the *miz* file with e.g. [7-zip](https://www.7-zip.org/) and copying the files into that folder does not work.
|
||||||
|
-- The next time the mission is saved, files not included via trigger are automatically removed by DCS.
|
||||||
|
--
|
||||||
|
-- However, if you create a new folder inside the miz file, which contains the sounds, it will not be deleted and can be used. The location of the sound files can be specified
|
||||||
|
-- via the @{#AIRBOSS.SetSoundfilesFolder}(*folderpath*) function. The parameter *folderpath* defines the location of the sound files folder within the mission *miz* file.
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- For example as
|
||||||
|
--
|
||||||
|
-- airbossStennis:SetSoundfilesFolder("Airboss Soundfiles/")
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
-- # AI Handling
|
-- # AI Handling
|
||||||
--
|
--
|
||||||
-- The @{#AIRBOSS} class allows to handle incoming AI units and integrate them into the marshal and landing pattern.
|
-- The @{#AIRBOSS} class allows to handle incoming AI units and integrate them into the marshal and landing pattern.
|
||||||
@ -855,6 +899,8 @@ AIRBOSS = {
|
|||||||
squadsetAI = nil,
|
squadsetAI = nil,
|
||||||
menusingle = nil,
|
menusingle = nil,
|
||||||
collisiondist = nil,
|
collisiondist = nil,
|
||||||
|
Tmessage = nil,
|
||||||
|
soundfolder = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Player aircraft types capable of landing on carriers.
|
--- Player aircraft types capable of landing on carriers.
|
||||||
@ -1520,13 +1566,17 @@ AIRBOSS.Difficulty={
|
|||||||
-- @field #boolean subtitles If true, display subtitles of radio messages.
|
-- @field #boolean subtitles If true, display subtitles of radio messages.
|
||||||
-- @extends #AIRBOSS.FlightGroup
|
-- @extends #AIRBOSS.FlightGroup
|
||||||
|
|
||||||
--- Main radio menu: F10 Other/Airboss
|
--- Main group level radio menu: F10 Other/Airboss.
|
||||||
-- @field #table MenuF10
|
-- @field #table MenuF10
|
||||||
AIRBOSS.MenuF10={}
|
AIRBOSS.MenuF10={}
|
||||||
|
|
||||||
|
--- Airboss mission level F10 root menu.
|
||||||
|
-- @field #table MenuF10Root
|
||||||
|
AIRBOSS.MenuF10Root=nil
|
||||||
|
|
||||||
--- Airboss class version.
|
--- Airboss class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
AIRBOSS.version="0.9.2"
|
AIRBOSS.version="0.9.3"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@ -1707,6 +1757,7 @@ function AIRBOSS:New(carriername, alias)
|
|||||||
-- Set update time intervals.
|
-- Set update time intervals.
|
||||||
self:SetQueueUpdateTime()
|
self:SetQueueUpdateTime()
|
||||||
self:SetStatusUpdateTime()
|
self:SetStatusUpdateTime()
|
||||||
|
self:SetDefaultMessageDuration()
|
||||||
|
|
||||||
-- Menu options.
|
-- Menu options.
|
||||||
self:SetMenuMarkZones()
|
self:SetMenuMarkZones()
|
||||||
@ -2271,6 +2322,31 @@ function AIRBOSS:SetAirbossNiceGuy(switch)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set folder where the airboss 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 #AIRBOSS self
|
||||||
|
-- @param #string folderpath The path to the sound files, e.g. "Airboss Soundfiles/".
|
||||||
|
-- @return #AIRBOSS self
|
||||||
|
function AIRBOSS:SetSoundfilesFolder(folderpath)
|
||||||
|
|
||||||
|
-- Check that it ends with /
|
||||||
|
if folderpath then
|
||||||
|
local lastchar=string.sub(folderpath, -1)
|
||||||
|
if lastchar~="/" then
|
||||||
|
folderpath=folderpath.."/"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Folderpath.
|
||||||
|
self.soundfolder=folderpath
|
||||||
|
|
||||||
|
-- Info message.
|
||||||
|
self:I(self.lid..string.format("Setting sound files folder to: %s", self.soundfolder))
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Set time interval for updating player status and other things.
|
--- Set time interval for updating player status and other things.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param #number interval Time interval in seconds. Default 0.5 sec.
|
-- @param #number interval Time interval in seconds. Default 0.5 sec.
|
||||||
@ -2280,13 +2356,22 @@ function AIRBOSS:SetStatusUpdateTime(interval)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set duration how long messages are displayed to players.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
-- @param #number duration Duration in seconds. Default 10 sec.
|
||||||
|
-- @return #AIRBOSS self
|
||||||
|
function AIRBOSS:SetDefaultMessageDuration(duration)
|
||||||
|
self.Tmessage=duration or 10
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Set Case I Marshal radius. This is the radius of the valid zone around "the post" aircraft are supposed to be holding in the Case I Marshal stack.
|
--- Set Case I Marshal radius. This is the radius of the valid zone around "the post" aircraft are supposed to be holding in the Case I Marshal stack.
|
||||||
-- The post is 2.5 NM port of the carrier.
|
-- The post is 2.5 NM port of the carrier.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param #number Radius in NM. Default 2.75 NM, which gives a diameter of 5.5 NM.
|
-- @param #number Radius in NM. Default 2.8 NM, which gives a diameter of 5.6 NM.
|
||||||
-- @return #AIRBOSS self
|
-- @return #AIRBOSS self
|
||||||
function AIRBOSS:SetMarshalRadius(radius)
|
function AIRBOSS:SetMarshalRadius(radius)
|
||||||
self.marshalradius=UTILS.NMToMeters(radius or 2.75)
|
self.marshalradius=UTILS.NMToMeters(radius or 2.8)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -3940,7 +4025,7 @@ function AIRBOSS:_ClearForLanding(flight)
|
|||||||
local text=string.format("you are cleared for Case %d recovery.", flight.case)
|
local text=string.format("you are cleared for Case %d recovery.", flight.case)
|
||||||
|
|
||||||
-- Add a little delay because message that recovery window opened could come just before.
|
-- Add a little delay because message that recovery window opened could come just before.
|
||||||
self:MessageToMarshal(text, "MARSHAL", flight.onboard, 10, false, 2)
|
self:MessageToMarshal(text, "MARSHAL", flight.onboard, nil, false, 2)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -4141,7 +4226,7 @@ function AIRBOSS:_WaitPlayer(playerData)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Send message.
|
-- Send message.
|
||||||
self:MessageToMarshal(text, "AIRBOSS", playerData.onboard, 10)
|
self:MessageToMarshal(text, "AIRBOSS", playerData.onboard)
|
||||||
|
|
||||||
-- Add player flight to waiting queue.
|
-- Add player flight to waiting queue.
|
||||||
table.insert(self.Qwaiting, playerData)
|
table.insert(self.Qwaiting, playerData)
|
||||||
@ -6141,7 +6226,7 @@ function AIRBOSS:_Waiting(playerData)
|
|||||||
-- Warning if player is inside the zone.
|
-- Warning if player is inside the zone.
|
||||||
if inzone and Twaiting>3*60 and not playerData.warning then
|
if inzone and Twaiting>3*60 and not playerData.warning then
|
||||||
local text=string.format("You are supposed to wait outside the 10 NM zone.")
|
local text=string.format("You are supposed to wait outside the 10 NM zone.")
|
||||||
self:MessageToPlayer(playerData, text, "AIRBOSS", nil, 10)
|
self:MessageToPlayer(playerData, text, "AIRBOSS")
|
||||||
playerData.warning=true
|
playerData.warning=true
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -6373,7 +6458,8 @@ function AIRBOSS:_Commencing(playerData, zonecheck)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Message to player.
|
-- Message to player.
|
||||||
self:MessageToPlayer(playerData, text, "MARSHAL", nil, 3)
|
--self:MessageToPlayer(playerData, text, "MARSHAL", nil, 3)
|
||||||
|
self:MessageToPlayer(playerData, text, "MARSHAL")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Next step: depends on case recovery.
|
-- Next step: depends on case recovery.
|
||||||
@ -7482,7 +7568,7 @@ function AIRBOSS:_CheckFoulDeck(playerData)
|
|||||||
-- Player hint for flight students.
|
-- Player hint for flight students.
|
||||||
if playerData.difficulty~=AIRBOSS.Difficulty.HARD then
|
if playerData.difficulty~=AIRBOSS.Difficulty.HARD then
|
||||||
local text=string.format("overfly landing area and enter bolter pattern.")
|
local text=string.format("overfly landing area and enter bolter pattern.")
|
||||||
self:MessageToPlayer(playerData, text, "LSO", nil, 10, false, 3)
|
self:MessageToPlayer(playerData, text, "LSO", nil, nil, false, 3)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set player parameters for foul deck
|
-- Set player parameters for foul deck
|
||||||
@ -7495,7 +7581,7 @@ function AIRBOSS:_CheckFoulDeck(playerData)
|
|||||||
if foulunit then
|
if foulunit then
|
||||||
local foulflight=self:_GetFlightFromGroupInQueue(foulunit:GetGroup(), self.flights)
|
local foulflight=self:_GetFlightFromGroupInQueue(foulunit:GetGroup(), self.flights)
|
||||||
if foulflight and not foulflight.ai then
|
if foulflight and not foulflight.ai then
|
||||||
self:MessageToPlayer(foulflight, "move your ass from my runway. NOW!", "AIRBOSS", nil, 10)
|
self:MessageToPlayer(foulflight, "move your ass from my runway. NOW!", "AIRBOSS")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -9134,7 +9220,7 @@ function AIRBOSS:_AbortPattern(playerData, X, Z, posData, patternwo)
|
|||||||
self:T(self.lid..dtext)
|
self:T(self.lid..dtext)
|
||||||
|
|
||||||
-- Message to player.
|
-- Message to player.
|
||||||
self:MessageToPlayer(playerData, text, "LSO", nil, 20)
|
self:MessageToPlayer(playerData, text, "LSO")
|
||||||
|
|
||||||
if patternwo then
|
if patternwo then
|
||||||
|
|
||||||
@ -9579,7 +9665,7 @@ function AIRBOSS:_Debrief(playerData)
|
|||||||
|
|
||||||
-- Re-enter message.
|
-- Re-enter message.
|
||||||
local text=string.format("fly heading %03d° for %d NM to re-enter the pattern.", heading, UTILS.MetersToNM(distance))
|
local text=string.format("fly heading %03d° for %d NM to re-enter the pattern.", heading, UTILS.MetersToNM(distance))
|
||||||
self:MessageToPlayer(playerData, text, "LSO", nil, 10, false, 5)
|
self:MessageToPlayer(playerData, text, "LSO", nil, nil, false, 5)
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
@ -9607,7 +9693,7 @@ function AIRBOSS:_Debrief(playerData)
|
|||||||
|
|
||||||
-- Airboss talkto!
|
-- Airboss talkto!
|
||||||
local text=string.format("the deck was fouled but landed anyway. Airboss wants to talk to you!")
|
local text=string.format("the deck was fouled but landed anyway. Airboss wants to talk to you!")
|
||||||
self:MessageToPlayer(playerData, text, "LSO", nil, 10, false, 3)
|
self:MessageToPlayer(playerData, text, "LSO", nil, nil, false, 3)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -9630,7 +9716,7 @@ function AIRBOSS:_Debrief(playerData)
|
|||||||
|
|
||||||
-- Airboss talkto!
|
-- Airboss talkto!
|
||||||
local text=string.format("you were waved off but landed anyway. Airboss wants to talk to you!")
|
local text=string.format("you were waved off but landed anyway. Airboss wants to talk to you!")
|
||||||
self:MessageToPlayer(playerData, text, "LSO", nil, 10, false, 3)
|
self:MessageToPlayer(playerData, text, "LSO", nil, nil, false, 3)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -9663,7 +9749,7 @@ function AIRBOSS:_Debrief(playerData)
|
|||||||
else
|
else
|
||||||
|
|
||||||
-- Message to player.
|
-- Message to player.
|
||||||
self:MessageToPlayer(playerData, "Undefined state after landing! Please report.", "ERROR", nil, 10)
|
self:MessageToPlayer(playerData, "Undefined state after landing! Please report.", "ERROR", nil, 20)
|
||||||
|
|
||||||
-- Next step.
|
-- Next step.
|
||||||
playerData.step=AIRBOSS.PatternStep.UNDEFINED
|
playerData.step=AIRBOSS.PatternStep.UNDEFINED
|
||||||
@ -9739,7 +9825,7 @@ function AIRBOSS:_StepHint(playerData, step)
|
|||||||
local text=string.format("Optimal setup at next step %s:%s", step, hint)
|
local text=string.format("Optimal setup at next step %s:%s", step, hint)
|
||||||
|
|
||||||
-- Send hint to player.
|
-- Send hint to player.
|
||||||
self:MessageToPlayer(playerData, text, "AIRBOSS", "", 10, false, 1)
|
self:MessageToPlayer(playerData, text, "AIRBOSS", "", nil, false, 1)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -10158,7 +10244,7 @@ function AIRBOSS:_CheckPatternUpdate()
|
|||||||
-- 99, new final bearing XXX
|
-- 99, new final bearing XXX
|
||||||
local FB=self:GetFinalBearing(true)
|
local FB=self:GetFinalBearing(true)
|
||||||
local text=string.format("new final bearing %03d°.", FB)
|
local text=string.format("new final bearing %03d°.", FB)
|
||||||
self:MessageToMarshal(text, "AIRBOSS", "99", 10)
|
self:MessageToMarshal(text, "AIRBOSS", "99")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Reset parameters for next update check.
|
-- Reset parameters for next update check.
|
||||||
@ -10919,7 +11005,7 @@ function AIRBOSS:Sound2Player(playerData, radio, call, loud, delay)
|
|||||||
|
|
||||||
-- Only to players with subtitle on or if noise is played.
|
-- Only to players with subtitle on or if noise is played.
|
||||||
if playerData.subtitles or self:_NeedsSubtitle(call) then
|
if playerData.subtitles or self:_NeedsSubtitle(call) then
|
||||||
self:MessageToPlayer(playerData, subtitle, nil, "", call.subduration or 10, false, delay)
|
self:MessageToPlayer(playerData, subtitle, nil, "", call.subduration, false, delay)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -10985,7 +11071,9 @@ function AIRBOSS:_RadioFilename(call, loud)
|
|||||||
-- Construct file name and subtitle.
|
-- Construct file name and subtitle.
|
||||||
local prefix=call.file or ""
|
local prefix=call.file or ""
|
||||||
local suffix=call.suffix or "ogg"
|
local suffix=call.suffix or "ogg"
|
||||||
local path="l10n/DEFAULT/"
|
|
||||||
|
-- Path to sound files. Default is in the ME
|
||||||
|
local path=self.soundfolder or "l10n/DEFAULT/"
|
||||||
|
|
||||||
-- Loud version.
|
-- Loud version.
|
||||||
if loud then
|
if loud then
|
||||||
@ -11014,7 +11102,7 @@ function AIRBOSS:MessageToPlayer(playerData, message, sender, receiver, duration
|
|||||||
if playerData and message and message~="" then
|
if playerData and message and message~="" then
|
||||||
|
|
||||||
-- Default duration.
|
-- Default duration.
|
||||||
duration=duration or 10
|
duration=duration or self.Tmessage
|
||||||
|
|
||||||
-- Format message.
|
-- Format message.
|
||||||
local text
|
local text
|
||||||
@ -11070,9 +11158,6 @@ end
|
|||||||
-- @param #number delay Delay in seconds, before the message is displayed.
|
-- @param #number delay Delay in seconds, before the message is displayed.
|
||||||
function AIRBOSS:MessageToPattern(message, sender, receiver, duration, clear, delay)
|
function AIRBOSS:MessageToPattern(message, sender, receiver, duration, clear, delay)
|
||||||
|
|
||||||
-- Local delay.
|
|
||||||
local _delay=delay or 0
|
|
||||||
|
|
||||||
-- Create new (fake) radio call to show the subtitile.
|
-- Create new (fake) radio call to show the subtitile.
|
||||||
local call=self:_NewRadioCall(AIRBOSS.LSOCall.NOISE, sender or "LSO", message, duration, receiver, sender)
|
local call=self:_NewRadioCall(AIRBOSS.LSOCall.NOISE, sender or "LSO", message, duration, receiver, sender)
|
||||||
|
|
||||||
@ -11092,9 +11177,6 @@ end
|
|||||||
-- @param #number delay Delay in seconds, before the message is displayed.
|
-- @param #number delay Delay in seconds, before the message is displayed.
|
||||||
function AIRBOSS:MessageToMarshal(message, sender, receiver, duration, clear, delay)
|
function AIRBOSS:MessageToMarshal(message, sender, receiver, duration, clear, delay)
|
||||||
|
|
||||||
-- Local delay.
|
|
||||||
local _delay=delay or 0
|
|
||||||
|
|
||||||
-- Create new (fake) radio call to show the subtitile.
|
-- Create new (fake) radio call to show the subtitile.
|
||||||
local call=self:_NewRadioCall(AIRBOSS.MarshalCall.NOISE, sender or "MARSHAL", message, duration, receiver, sender)
|
local call=self:_NewRadioCall(AIRBOSS.MarshalCall.NOISE, sender or "MARSHAL", message, duration, receiver, sender)
|
||||||
|
|
||||||
@ -11123,7 +11205,7 @@ function AIRBOSS:_NewRadioCall(call, sender, subtitle, subduration, modexreceive
|
|||||||
newcall.subtitle=subtitle or call.subtitle
|
newcall.subtitle=subtitle or call.subtitle
|
||||||
|
|
||||||
-- Duration of subtitle display.
|
-- Duration of subtitle display.
|
||||||
newcall.subduration=subduration or 10
|
newcall.subduration=subduration or self.Tmessage
|
||||||
|
|
||||||
-- Tail number of the receiver.
|
-- Tail number of the receiver.
|
||||||
if self:_IsOnboard(modexreceiver) then
|
if self:_IsOnboard(modexreceiver) then
|
||||||
@ -11238,7 +11320,8 @@ function AIRBOSS:_Number2Sound(playerData, sender, number, delay)
|
|||||||
local call=AIRBOSS[Sender][N] --#AIRBOSS.RadioCall
|
local call=AIRBOSS[Sender][N] --#AIRBOSS.RadioCall
|
||||||
|
|
||||||
-- Create file name.
|
-- Create file name.
|
||||||
local filename=string.format("%s.%s", call.file, call.suffix)
|
--local filename=string.format("%s.%s", call.file, call.suffix)
|
||||||
|
local filename=self:_RadioFilename(call, false)
|
||||||
|
|
||||||
-- Play sound.
|
-- Play sound.
|
||||||
USERSOUND:New(filename):ToGroup(playerData.group, delay+wait)
|
USERSOUND:New(filename):ToGroup(playerData.group, delay+wait)
|
||||||
@ -11332,19 +11415,42 @@ function AIRBOSS:_AddF10Commands(_unitName)
|
|||||||
-- Enable switch so we don't do this twice.
|
-- Enable switch so we don't do this twice.
|
||||||
self.menuadded[gid]=true
|
self.menuadded[gid]=true
|
||||||
|
|
||||||
-- Main F10 menu: F10/Airboss/<Carrier Name>/
|
-- Set menu root path.
|
||||||
|
local _rootPath=nil
|
||||||
|
if AIRBOSS.MenuF10Root then
|
||||||
|
------------------------
|
||||||
|
-- MISSON LEVEL MENUE --
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
if self.menusingle then
|
||||||
|
-- F10/Airboss/...
|
||||||
|
_rootPath=AIRBOSS.MenuF10Root
|
||||||
|
else
|
||||||
|
-- F10/Airboss/<Carrier Alias>/...
|
||||||
|
_rootPath=missionCommands.addSubMenuForGroup(gid, self.alias, AIRBOSS.MenuF10Root)
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
------------------------
|
||||||
|
-- GROUP LEVEL MENUES --
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
-- Main F10 menu: F10/Airboss/
|
||||||
if AIRBOSS.MenuF10[gid]==nil then
|
if AIRBOSS.MenuF10[gid]==nil then
|
||||||
AIRBOSS.MenuF10[gid]=missionCommands.addSubMenuForGroup(gid, "Airboss")
|
AIRBOSS.MenuF10[gid]=missionCommands.addSubMenuForGroup(gid, "Airboss")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- F10/Airboss/<Carrier>
|
|
||||||
local _rootPath
|
|
||||||
if self.menusingle then
|
if self.menusingle then
|
||||||
|
-- F10/Airboss/...
|
||||||
_rootPath=AIRBOSS.MenuF10[gid]
|
_rootPath=AIRBOSS.MenuF10[gid]
|
||||||
else
|
else
|
||||||
|
-- F10/Airboss/<Carrier Alias>/...
|
||||||
_rootPath=missionCommands.addSubMenuForGroup(gid, self.alias, AIRBOSS.MenuF10[gid])
|
_rootPath=missionCommands.addSubMenuForGroup(gid, self.alias, AIRBOSS.MenuF10[gid])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--------------------------------
|
--------------------------------
|
||||||
-- F10/Airboss/<Carrier>/F1 Help
|
-- F10/Airboss/<Carrier>/F1 Help
|
||||||
@ -12156,7 +12262,7 @@ function AIRBOSS:_DisplayQueue(_unitname, queue, qname)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Send message.
|
-- Send message.
|
||||||
self:MessageToPlayer(playerData, text, nil, "", 10, true)
|
self:MessageToPlayer(playerData, text, nil, "", nil, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -12472,7 +12578,7 @@ function AIRBOSS:_DisplayPlayerStatus(_unitName)
|
|||||||
local fuel=playerData.unit:GetFuel()*100
|
local fuel=playerData.unit:GetFuel()*100
|
||||||
local fuelstate=self:_GetFuelState(playerData.unit)
|
local fuelstate=self:_GetFuelState(playerData.unit)
|
||||||
|
|
||||||
---
|
-- Number of units in group.
|
||||||
local _,nunitsGround=self:_GetFlightUnits(playerData, true)
|
local _,nunitsGround=self:_GetFlightUnits(playerData, true)
|
||||||
local _,nunitsAirborne=self:_GetFlightUnits(playerData, false)
|
local _,nunitsAirborne=self:_GetFlightUnits(playerData, false)
|
||||||
|
|
||||||
@ -12487,8 +12593,6 @@ function AIRBOSS:_DisplayPlayerStatus(_unitName)
|
|||||||
text=text..string.format("Skill Level: %s\n", playerData.difficulty)
|
text=text..string.format("Skill Level: %s\n", playerData.difficulty)
|
||||||
text=text..string.format("Tail # %s (%s)\n", playerData.onboard, self:_GetACNickname(playerData.actype))
|
text=text..string.format("Tail # %s (%s)\n", playerData.onboard, self:_GetACNickname(playerData.actype))
|
||||||
text=text..string.format("Fuel State: %.1f lbs/1000 (%.1f %%)\n", fuelstate/1000, fuel)
|
text=text..string.format("Fuel State: %.1f lbs/1000 (%.1f %%)\n", fuelstate/1000, fuel)
|
||||||
--text=text..string.format("Aircraft: %s\n", self:_GetACNickname(playerData.actype))
|
|
||||||
--text=text..string.format("Group: %s\n", playerData.group:GetName())
|
|
||||||
text=text..string.format("# units: %d (%d airborne)\n", nunitsGround, nunitsAirborne)
|
text=text..string.format("# units: %d (%d airborne)\n", nunitsGround, nunitsAirborne)
|
||||||
text=text..string.format("Section Lead: %s (%d/%d)", tostring(playerData.seclead), #playerData.section+1, self.NmaxSection+1)
|
text=text..string.format("Section Lead: %s (%d/%d)", tostring(playerData.seclead), #playerData.section+1, self.NmaxSection+1)
|
||||||
for _,_sec in pairs(playerData.section) do
|
for _,_sec in pairs(playerData.section) do
|
||||||
|
|||||||
@ -59,6 +59,7 @@
|
|||||||
-- @field #boolean awacs If true, the groups gets the enroute task AWACS instead of tanker.
|
-- @field #boolean awacs If true, the groups gets the enroute task AWACS instead of tanker.
|
||||||
-- @field #number callsignname Number for the callsign name.
|
-- @field #number callsignname Number for the callsign name.
|
||||||
-- @field #number callsignnumber Number of the callsign name.
|
-- @field #number callsignnumber Number of the callsign name.
|
||||||
|
-- @field #string modex Tail number of the tanker.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- Recovery Tanker.
|
--- Recovery Tanker.
|
||||||
@ -292,6 +293,7 @@ RECOVERYTANKER = {
|
|||||||
awacs = nil,
|
awacs = nil,
|
||||||
callsignname = nil,
|
callsignname = nil,
|
||||||
callsignnumber = nil,
|
callsignnumber = nil,
|
||||||
|
modex = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Unique ID (global).
|
--- Unique ID (global).
|
||||||
@ -300,7 +302,7 @@ RECOVERYTANKER.UID=0
|
|||||||
|
|
||||||
--- Class version.
|
--- Class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
RECOVERYTANKER.version="1.0.5"
|
RECOVERYTANKER.version="1.0.6"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@ -617,6 +619,15 @@ function RECOVERYTANKER:SetCallsign(callsignname, callsignnumber)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set modex (tail number) of the tanker.
|
||||||
|
-- @param #RECOVERYTANKER self
|
||||||
|
-- @param #number modex Tail number.
|
||||||
|
-- @return #RECOVERYTANKER self
|
||||||
|
function RECOVERYTANKER:SetModex(modex)
|
||||||
|
self.modex=modex
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Set takeoff type.
|
--- Set takeoff type.
|
||||||
-- @param #RECOVERYTANKER self
|
-- @param #RECOVERYTANKER self
|
||||||
-- @param #number takeofftype Takeoff type.
|
-- @param #number takeofftype Takeoff type.
|
||||||
@ -810,8 +821,10 @@ function RECOVERYTANKER:onafterStart(From, Event, To)
|
|||||||
|
|
||||||
-- Handle events.
|
-- Handle events.
|
||||||
self:HandleEvent(EVENTS.EngineShutdown)
|
self:HandleEvent(EVENTS.EngineShutdown)
|
||||||
self:HandleEvent(EVENTS.Refueling, self._RefuelingStart) --Need explcit functions sice OnEventRefueling and OnEventRefuelingStop did not hook.
|
self:HandleEvent(EVENTS.Refueling, self._RefuelingStart) --Need explicit functions since OnEventRefueling and OnEventRefuelingStop did not hook!
|
||||||
self:HandleEvent(EVENTS.RefuelingStop, self._RefuelingStop)
|
self:HandleEvent(EVENTS.RefuelingStop, self._RefuelingStop)
|
||||||
|
self:HandleEvent(EVENTS.Crash, self._OnEventCrashOrDead)
|
||||||
|
self:HandleEvent(EVENTS.Dead, self._OnEventCrashOrDead)
|
||||||
|
|
||||||
-- Spawn tanker. We need to introduce an alias in case this class is used twice. This would confuse the spawn routine.
|
-- Spawn tanker. We need to introduce an alias in case this class is used twice. This would confuse the spawn routine.
|
||||||
local Spawn=SPAWN:NewWithAlias(self.tankergroupname, self.alias)
|
local Spawn=SPAWN:NewWithAlias(self.tankergroupname, self.alias)
|
||||||
@ -820,6 +833,7 @@ function RECOVERYTANKER:onafterStart(From, Event, To)
|
|||||||
Spawn:InitRadioCommsOnOff(true)
|
Spawn:InitRadioCommsOnOff(true)
|
||||||
Spawn:InitRadioFrequency(self.RadioFreq)
|
Spawn:InitRadioFrequency(self.RadioFreq)
|
||||||
Spawn:InitRadioModulation(self.RadioModu)
|
Spawn:InitRadioModulation(self.RadioModu)
|
||||||
|
Spawn:InitModex(self.modex)
|
||||||
|
|
||||||
-- Spawn on carrier.
|
-- Spawn on carrier.
|
||||||
if self.takeoff==SPAWN.Takeoff.Air then
|
if self.takeoff==SPAWN.Takeoff.Air then
|
||||||
@ -935,6 +949,7 @@ function RECOVERYTANKER:onafterStatus(From, Event, To)
|
|||||||
self.tanker:InitRadioCommsOnOff(true)
|
self.tanker:InitRadioCommsOnOff(true)
|
||||||
self.tanker:InitRadioFrequency(self.RadioFreq)
|
self.tanker:InitRadioFrequency(self.RadioFreq)
|
||||||
self.tanker:InitRadioModulation(self.RadioModu)
|
self.tanker:InitRadioModulation(self.RadioModu)
|
||||||
|
self.tanker:InitModex(self.modex)
|
||||||
|
|
||||||
-- Respawn tanker.
|
-- Respawn tanker.
|
||||||
self.tanker=self.tanker:Respawn(nil, true)
|
self.tanker=self.tanker:Respawn(nil, true)
|
||||||
@ -991,6 +1006,8 @@ function RECOVERYTANKER:onafterStatus(From, Event, To)
|
|||||||
-- TANKER is DEAD --
|
-- TANKER is DEAD --
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
if not self:IsStopped() then
|
||||||
|
|
||||||
-- Stop FSM.
|
-- Stop FSM.
|
||||||
self:Stop()
|
self:Stop()
|
||||||
|
|
||||||
@ -1000,6 +1017,7 @@ function RECOVERYTANKER:onafterStatus(From, Event, To)
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1103,9 +1121,22 @@ end
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
function RECOVERYTANKER:onafterStop(From, Event, To)
|
function RECOVERYTANKER:onafterStop(From, Event, To)
|
||||||
|
|
||||||
|
-- Unhandle events.
|
||||||
self:UnHandleEvent(EVENTS.EngineShutdown)
|
self:UnHandleEvent(EVENTS.EngineShutdown)
|
||||||
self:UnHandleEvent(EVENTS.Refueling)
|
self:UnHandleEvent(EVENTS.Refueling)
|
||||||
self:UnHandleEvent(EVENTS.RefuelingStop)
|
self:UnHandleEvent(EVENTS.RefuelingStop)
|
||||||
|
self:UnHandleEvent(EVENTS.Dead)
|
||||||
|
self:UnHandleEvent(EVENTS.Crash)
|
||||||
|
|
||||||
|
-- If tanker is alive, despawn it.
|
||||||
|
if self.helo and self.helo:IsAlive() then
|
||||||
|
self:I(self.lid.."Stopping FSM and despawning tanker.")
|
||||||
|
self.tanker:Destroy()
|
||||||
|
else
|
||||||
|
self:I(self.lid.."Stopping FSM. Tanker was not alive.")
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@ -1139,6 +1170,7 @@ function RECOVERYTANKER:OnEventEngineShutdown(EventData)
|
|||||||
group:InitRadioCommsOnOff(true)
|
group:InitRadioCommsOnOff(true)
|
||||||
group:InitRadioFrequency(self.RadioFreq)
|
group:InitRadioFrequency(self.RadioFreq)
|
||||||
group:InitRadioModulation(self.RadioModu)
|
group:InitRadioModulation(self.RadioModu)
|
||||||
|
group:InitModex(self.modex)
|
||||||
|
|
||||||
-- Respawn tanker.
|
-- Respawn tanker.
|
||||||
-- Delaying respawn due to DCS bug https://github.com/FlightControl-Master/MOOSE/issues/1076
|
-- Delaying respawn due to DCS bug https://github.com/FlightControl-Master/MOOSE/issues/1076
|
||||||
@ -1221,6 +1253,37 @@ function RECOVERYTANKER:_RefuelingStop(EventData)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- A unit crashed or died.
|
||||||
|
-- @param #RECOVERYTANKER self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData Event data.
|
||||||
|
function RECOVERYTANKER:_OnEventCrashOrDead(EventData)
|
||||||
|
self:F2({eventdata=EventData})
|
||||||
|
|
||||||
|
-- Check that there is an initiating unit in the event data.
|
||||||
|
if EventData and EventData.IniUnit then
|
||||||
|
|
||||||
|
-- Crashed or dead unit.
|
||||||
|
local unit=EventData.IniUnit
|
||||||
|
local unitname=tostring(EventData.IniUnitName)
|
||||||
|
|
||||||
|
-- Check that it was the tanker that crashed.
|
||||||
|
if EventData.IniGroupName==self.tanker:GetName() then
|
||||||
|
|
||||||
|
-- Error message.
|
||||||
|
self:E(self.lid..string.format("Recovery tanker %s crashed!", unitname))
|
||||||
|
|
||||||
|
-- Stop FSM.
|
||||||
|
self:Stop()
|
||||||
|
|
||||||
|
-- Restart.
|
||||||
|
if self.respawn then
|
||||||
|
self:__Start(5)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- MISC functions
|
-- MISC functions
|
||||||
|
|||||||
@ -11,6 +11,12 @@
|
|||||||
-- * Multiple helos at different carriers due to object oriented approach.
|
-- * Multiple helos at different carriers due to object oriented approach.
|
||||||
-- * Finite State Machine (FSM) implementation.
|
-- * Finite State Machine (FSM) implementation.
|
||||||
--
|
--
|
||||||
|
-- ## Known (DCS) Issues
|
||||||
|
--
|
||||||
|
-- * CH-53E does only report 27.5% fuel even if fuel is set to 100% in the ME. See [bug report](https://forums.eagle.ru/showthread.php?t=223712)
|
||||||
|
-- * CH-53E does not accept USS Tarawa as landing airbase (even it can be spawned on it).
|
||||||
|
-- * Helos dont move away from their landing position on carriers.
|
||||||
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **funkyfranky**
|
-- ### Author: **funkyfranky**
|
||||||
@ -50,6 +56,7 @@
|
|||||||
-- @field #number hid Unit ID of the helo group. (Global) Running number.
|
-- @field #number hid Unit ID of the helo group. (Global) Running number.
|
||||||
-- @field #string alias Alias of the spawn group.
|
-- @field #string alias Alias of the spawn group.
|
||||||
-- @field #number uid Unique ID of this helo.
|
-- @field #number uid Unique ID of this helo.
|
||||||
|
-- @field #number modex Tail number of the helo.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- Rescue Helo
|
--- Rescue Helo
|
||||||
@ -219,6 +226,7 @@ RESCUEHELO = {
|
|||||||
carrierstop = nil,
|
carrierstop = nil,
|
||||||
alias = nil,
|
alias = nil,
|
||||||
uid = 0,
|
uid = 0,
|
||||||
|
modex = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Unique ID (global).
|
--- Unique ID (global).
|
||||||
@ -227,7 +235,7 @@ RESCUEHELO.UID=0
|
|||||||
|
|
||||||
--- Class version.
|
--- Class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
RESCUEHELO.version="1.0.3"
|
RESCUEHELO.version="1.0.5"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@ -322,7 +330,9 @@ function RESCUEHELO:New(carrierunit, helogroupname)
|
|||||||
self:AddTransition("Running", "Rescue", "Rescuing")
|
self:AddTransition("Running", "Rescue", "Rescuing")
|
||||||
self:AddTransition("Running", "RTB", "Returning")
|
self:AddTransition("Running", "RTB", "Returning")
|
||||||
self:AddTransition("Rescuing", "RTB", "Returning")
|
self:AddTransition("Rescuing", "RTB", "Returning")
|
||||||
self:AddTransition("*", "Run", "Running")
|
self:AddTransition("Returning", "Returned", "Returned")
|
||||||
|
self:AddTransition("Running", "Run", "Running")
|
||||||
|
self:AddTransition("Returned", "Run", "Running")
|
||||||
self:AddTransition("*", "Status", "*")
|
self:AddTransition("*", "Status", "*")
|
||||||
self:AddTransition("*", "Stop", "Stopped")
|
self:AddTransition("*", "Stop", "Stopped")
|
||||||
|
|
||||||
@ -376,6 +386,25 @@ function RESCUEHELO:New(carrierunit, helogroupname)
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param Wrapper.Airbase#AIRBASE airbase The airbase to return to. Default is the home base.
|
-- @param Wrapper.Airbase#AIRBASE airbase The airbase to return to. Default is the home base.
|
||||||
|
|
||||||
|
--- Triggers the FSM event "Returned" after the helo has landed.
|
||||||
|
-- @function [parent=#RESCUEHELO] Returned
|
||||||
|
-- @param #RESCUEHELO self
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE airbase The airbase the helo has landed.
|
||||||
|
|
||||||
|
--- Triggers the delayed FSM event "Returned" after the helo has landed.
|
||||||
|
-- @function [parent=#RESCUEHELO] __Returned
|
||||||
|
-- @param #RESCUEHELO self
|
||||||
|
-- @param #number delay Delay in seconds.
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE airbase The airbase the helo has landed.
|
||||||
|
|
||||||
|
--- On after "Returned" event user function. Called when a the the helo has landed at an airbase.
|
||||||
|
-- @function [parent=#RESCUEHELO] OnAfterReturned
|
||||||
|
-- @param #RESCUEHELO self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE airbase The airbase the helo has landed.
|
||||||
|
|
||||||
|
|
||||||
--- Triggers the FSM event "Run".
|
--- Triggers the FSM event "Run".
|
||||||
-- @function [parent=#RESCUEHELO] Run
|
-- @function [parent=#RESCUEHELO] Run
|
||||||
@ -599,6 +628,15 @@ function RESCUEHELO:SetRespawnInAir()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set modex (tail number) of the helo.
|
||||||
|
-- @param #RESCUEHELO self
|
||||||
|
-- @param #number modex Tail number.
|
||||||
|
-- @return #RESCUEHELO self
|
||||||
|
function RESCUEHELO:SetModex(modex)
|
||||||
|
self.modex=modex
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Use an uncontrolled aircraft already present in the mission rather than spawning a new helo as initial rescue helo.
|
--- Use an uncontrolled aircraft already present in the mission rather than spawning a new helo as initial rescue helo.
|
||||||
-- This can be useful when interfaced with, e.g., a warehouse.
|
-- This can be useful when interfaced with, e.g., a warehouse.
|
||||||
-- The group name is the one specified in the @{#RESCUEHELO.New} function.
|
-- The group name is the one specified in the @{#RESCUEHELO.New} function.
|
||||||
@ -694,44 +732,24 @@ function RESCUEHELO:OnEventLand(EventData)
|
|||||||
MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug)
|
MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug)
|
||||||
self:T(self.lid..text)
|
self:T(self.lid..text)
|
||||||
|
|
||||||
|
-- Helo has rescued someone.
|
||||||
|
-- TODO: Add "Rescued" event.
|
||||||
if self:IsRescuing() then
|
if self:IsRescuing() then
|
||||||
|
|
||||||
self:T(self.lid..string.format("Rescue helo %s returned from rescue operation.", groupname))
|
self:T(self.lid..string.format("Rescue helo %s returned from rescue operation.", groupname))
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check if takeoff air or respawn in air is set. Landing event should not happen unless the helo was on a rescue mission.
|
-- Check if takeoff air or respawn in air is set. Landing event should not happen unless the helo was on a rescue mission.
|
||||||
if self.takeoff==SPAWN.Takeoff.Air or self.respawninair then
|
if self.takeoff==SPAWN.Takeoff.Air or self.respawninair then
|
||||||
|
|
||||||
if self:IsRescuing() then
|
if not self:IsRescuing() then
|
||||||
|
|
||||||
self:T(self.lid..string.format("Rescue helo %s returned from rescue operation.", groupname))
|
self:E(self.lid..string.format("WARNING: Rescue helo %s landed. This should not happen for Takeoff=Air or respawninair=true and no rescue operation in progress.", groupname))
|
||||||
|
|
||||||
-- Respawn helo at current airbase.
|
|
||||||
SCHEDULER:New(nil, group.RespawnAtCurrentAirbase, {group}, 3)
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
self:T2(self.lid..string.format("WARNING: Rescue helo %s landed. This should not happen for Takeoff=Air or respawninair=true unless a rescue operation finished.", groupname))
|
|
||||||
|
|
||||||
-- Respawn helo at current airbase anyway.
|
|
||||||
if self.respawn then
|
|
||||||
SCHEDULER:New(nil, group.RespawnAtCurrentAirbase, {group}, 3)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
-- Respawn helo at current airbase.
|
|
||||||
if self.respawn then
|
|
||||||
SCHEDULER:New(nil, group.RespawnAtCurrentAirbase, {group}, 3)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
-- Trigger returned event. Respawn at current airbase.
|
||||||
|
self:__Returned(3, EventData.Place)
|
||||||
-- Restart the formation.
|
|
||||||
self:__Run(10)
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -789,6 +807,11 @@ function RESCUEHELO:_OnEventCrashOrEject(EventData)
|
|||||||
-- Stop FSM.
|
-- Stop FSM.
|
||||||
self:Stop()
|
self:Stop()
|
||||||
|
|
||||||
|
-- Restart.
|
||||||
|
if self.respawn then
|
||||||
|
self:__Start(5)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -822,6 +845,9 @@ function RESCUEHELO:onafterStart(From, Event, To)
|
|||||||
-- Spawn helo. We need to introduce an alias in case this class is used twice. This would confuse the spawn routine.
|
-- Spawn helo. We need to introduce an alias in case this class is used twice. This would confuse the spawn routine.
|
||||||
local Spawn=SPAWN:NewWithAlias(self.helogroupname, self.alias)
|
local Spawn=SPAWN:NewWithAlias(self.helogroupname, self.alias)
|
||||||
|
|
||||||
|
-- Set modex for spawn.
|
||||||
|
Spawn:InitModex(self.modex)
|
||||||
|
|
||||||
-- Spawn in air or at airbase.
|
-- Spawn in air or at airbase.
|
||||||
if self.takeoff==SPAWN.Takeoff.Air then
|
if self.takeoff==SPAWN.Takeoff.Air then
|
||||||
|
|
||||||
@ -920,11 +946,14 @@ function RESCUEHELO:onafterStatus(From, Event, To)
|
|||||||
-- HELO is ALIVE --
|
-- HELO is ALIVE --
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
-- Get relative fuel wrt to initial fuel of helo (DCS bug https://forums.eagle.ru/showthread.php?t=223712)
|
-- Get (relative) fuel wrt to initial fuel of helo (DCS bug https://forums.eagle.ru/showthread.php?t=223712)
|
||||||
local fuel=self.helo:GetFuel()/self.HeloFuel0*100
|
local fuel=self.helo:GetFuel()*100
|
||||||
|
local fuelrel=fuel/self.HeloFuel0
|
||||||
|
local life=self.helo:GetUnit(1):GetLife()
|
||||||
|
local life0=self.helo:GetUnit(1):GetLife0()
|
||||||
|
|
||||||
-- Report current fuel.
|
-- Report current fuel.
|
||||||
local text=string.format("Rescue Helo %s: state=%s fuel=%.1f", self.helo:GetName(), self:GetState(), fuel)
|
local text=string.format("Rescue Helo %s: state=%s fuel=%.1f, rel.fuel=%.1f, life=%.1f/%.1f", self.helo:GetName(), self:GetState(), fuel, fuelrel, life, life0)
|
||||||
MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug)
|
MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug)
|
||||||
self:T(self.lid..text)
|
self:T(self.lid..text)
|
||||||
|
|
||||||
@ -939,9 +968,16 @@ function RESCUEHELO:onafterStatus(From, Event, To)
|
|||||||
-- Check if respawn is enabled.
|
-- Check if respawn is enabled.
|
||||||
if self.respawn then
|
if self.respawn then
|
||||||
|
|
||||||
|
-- Set modex for respawn.
|
||||||
|
self.helo:InitModex(self.modex)
|
||||||
|
|
||||||
-- Respawn helo in air.
|
-- Respawn helo in air.
|
||||||
self.helo=self.helo:Respawn(nil, true)
|
self.helo=self.helo:Respawn(nil, true)
|
||||||
|
|
||||||
|
-- XXX: ATTENTION: if helo automatically RTBs on low fuel, it goes a bit cazy. The formation is not stopped and he partially dives into the water.
|
||||||
|
-- Also trying to find a ship to land on he flies right through it.
|
||||||
|
--self.helo:OptionRTBBingoFuel(false)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -955,15 +991,7 @@ function RESCUEHELO:onafterStatus(From, Event, To)
|
|||||||
|
|
||||||
elseif self:IsRescuing() then
|
elseif self:IsRescuing() then
|
||||||
|
|
||||||
if self.rtb then
|
-- Helo is on a rescue mission.
|
||||||
|
|
||||||
-- Send helo back to base.
|
|
||||||
--self:RTB()
|
|
||||||
|
|
||||||
-- Switch to false.
|
|
||||||
self.rtb=false
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -972,13 +1000,14 @@ function RESCUEHELO:onafterStatus(From, Event, To)
|
|||||||
self:__Status(-30)
|
self:__Status(-30)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
------------------
|
------------------
|
||||||
-- HELO is DEAD --
|
-- HELO is DEAD --
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
if not self:IsStopped() then
|
||||||
|
|
||||||
-- Stop FSM.
|
-- Stop FSM.
|
||||||
self:Stop()
|
self:Stop()
|
||||||
|
|
||||||
@ -990,7 +1019,9 @@ function RESCUEHELO:onafterStatus(From, Event, To)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after "Run" event. FSM will go to "Running" state. If formation is topped, it will be started again.
|
end
|
||||||
|
|
||||||
|
--- On after "Run" event. FSM will go to "Running" state. If formation is stopped, it will be started again.
|
||||||
-- @param #RESCUEHELO self
|
-- @param #RESCUEHELO self
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
@ -1037,7 +1068,7 @@ function RESCUEHELO:_TaskRTB()
|
|||||||
-- Task script.
|
-- Task script.
|
||||||
local DCSScript = {}
|
local DCSScript = {}
|
||||||
DCSScript[#DCSScript+1] = string.format('local mycarrier = UNIT:FindByName(\"%s\") ', carriername) -- The carrier unit that holds the self object.
|
DCSScript[#DCSScript+1] = string.format('local mycarrier = UNIT:FindByName(\"%s\") ', carriername) -- The carrier unit that holds the self object.
|
||||||
DCSScript[#DCSScript+1] = string.format('local myhelo = mycarrier:GetState(mycarrier, \"RESCUEHELO_%d\") ', self.uid) -- Get the RECOVERYTANKER self object.
|
DCSScript[#DCSScript+1] = string.format('local myhelo = mycarrier:GetState(mycarrier, \"RESCUEHELO_%d\") ', self.uid) -- Get the RESCUEHELO self object.
|
||||||
DCSScript[#DCSScript+1] = string.format('myhelo:RTB()') -- Call the function, e.g. myhelo.(self)
|
DCSScript[#DCSScript+1] = string.format('myhelo:RTB()') -- Call the function, e.g. myhelo.(self)
|
||||||
|
|
||||||
-- Create task.
|
-- Create task.
|
||||||
@ -1155,16 +1186,58 @@ function RESCUEHELO:onafterRTB(From, Event, To, airbase)
|
|||||||
self:RouteRTB(airbase)
|
self:RouteRTB(airbase)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after Stop event. Unhandle events and stop status updates.
|
--- On after Returned event. Helo has landed.
|
||||||
|
-- @param #RESCUEHELO self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE airbase The base to which the helo has returned.
|
||||||
|
function RESCUEHELO:onafterReturned(From, Event, To, airbase)
|
||||||
|
|
||||||
|
if airbase then
|
||||||
|
local airbasename=airbase:GetName()
|
||||||
|
self:T(self.lid..string.format("Helo returned to airbase %s", tostring(airbasename)))
|
||||||
|
else
|
||||||
|
self:E(self.lid..string.format("WARNING: Helo landed but airbase (EventData.Place) is nil!"))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Respawn helo at current airbase.
|
||||||
|
if self.respawn then
|
||||||
|
|
||||||
|
-- Set modex for respawn.
|
||||||
|
self.helo:InitModex(self.modex)
|
||||||
|
|
||||||
|
-- Respawn helo at current airbase.
|
||||||
|
self.helo:RespawnAtCurrentAirbase()
|
||||||
|
|
||||||
|
-- Restart the formation.
|
||||||
|
self:__Run(10)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after Stop event. Unhandle events and stop status updates. If helo is alive, it is despawned.
|
||||||
-- @param #RESCUEHELO self
|
-- @param #RESCUEHELO self
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
function RESCUEHELO:onafterStop(From, Event, To)
|
function RESCUEHELO:onafterStop(From, Event, To)
|
||||||
|
|
||||||
|
-- Stop formation
|
||||||
self.formation:Stop()
|
self.formation:Stop()
|
||||||
|
|
||||||
|
-- Unhandle events.
|
||||||
self:UnHandleEvent(EVENTS.Land)
|
self:UnHandleEvent(EVENTS.Land)
|
||||||
self:UnHandleEvent(EVENTS.Crash)
|
self:UnHandleEvent(EVENTS.Crash)
|
||||||
self:UnHandleEvent(EVENTS.Ejection)
|
self:UnHandleEvent(EVENTS.Ejection)
|
||||||
|
|
||||||
|
-- If helo is alive, despawn it.
|
||||||
|
if self.helo and self.helo:IsAlive() then
|
||||||
|
self:I(self.lid.."Stopping FSM and despawning helo.")
|
||||||
|
self.helo:Destroy()
|
||||||
|
else
|
||||||
|
self:I(self.lid.."Stopping FSM. Helo was not alive.")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -1196,6 +1269,9 @@ function RESCUEHELO:RouteRTB(RTBAirbase, Speed)
|
|||||||
-- Set route points.
|
-- Set route points.
|
||||||
Template.route.points=Points
|
Template.route.points=Points
|
||||||
|
|
||||||
|
-- Set modex for respawn.
|
||||||
|
self.helo:InitModex(self.modex)
|
||||||
|
|
||||||
-- Respawn the group.
|
-- Respawn the group.
|
||||||
self.helo=self.helo:Respawn(Template, true)
|
self.helo=self.helo:Respawn(Template, true)
|
||||||
|
|
||||||
|
|||||||
@ -890,4 +890,19 @@ function UTILS.GetMagneticDeclination(map)
|
|||||||
return declination
|
return declination
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Checks if a file exists or not. This requires **io** to be desanitized.
|
||||||
|
-- @param #string file File that should be checked.
|
||||||
|
-- @return #boolean True if the file exists, false if the file does not exist or nil if the io module is not available and the check could not be performed.
|
||||||
|
function UTILS.FileExists(file)
|
||||||
|
if io then
|
||||||
|
local f=io.open(file, "r")
|
||||||
|
if f~=nil then
|
||||||
|
io.close(f)
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|||||||
@ -657,7 +657,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
|
|||||||
if r1 and r2 then
|
if r1 and r2 then
|
||||||
local safedist=(r1+r2)*1.1
|
local safedist=(r1+r2)*1.1
|
||||||
local safe = (dist > safedist)
|
local safe = (dist > safedist)
|
||||||
self:E(string.format("r1=%.1f r2=%.1f s=%.1f d=%.1f ==> safe=%s", r1, r2, safedist, dist, tostring(safe)))
|
self:T2(string.format("r1=%.1f r2=%.1f s=%.1f d=%.1f ==> safe=%s", r1, r2, safedist, dist, tostring(safe)))
|
||||||
return safe
|
return safe
|
||||||
else
|
else
|
||||||
return true
|
return true
|
||||||
@ -710,7 +710,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
|
|||||||
if verysafe and (parkingspot.Free==false or parkingspot.TOAC==true) then
|
if verysafe and (parkingspot.Free==false or parkingspot.TOAC==true) then
|
||||||
|
|
||||||
-- DCS getParking() routine returned that spot is not free.
|
-- DCS getParking() routine returned that spot is not free.
|
||||||
self:E(string.format("%s: Parking spot id %d NOT free (or aircraft has not taken off yet). Free=%s, TOAC=%s.", airport, parkingspot.TerminalID, tostring(parkingspot.Free), tostring(parkingspot.TOAC)))
|
self:T(string.format("%s: Parking spot id %d NOT free (or aircraft has not taken off yet). Free=%s, TOAC=%s.", airport, parkingspot.TerminalID, tostring(parkingspot.Free), tostring(parkingspot.TOAC)))
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
@ -790,6 +790,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
|
|||||||
table.insert(validspots, {Coordinate=_spot, TerminalID=_termid})
|
table.insert(validspots, {Coordinate=_spot, TerminalID=_termid})
|
||||||
end
|
end
|
||||||
nvalid=nvalid+1
|
nvalid=nvalid+1
|
||||||
|
self:I(string.format("%s: Parking spot id %d free. Nfree=%d/%d.", airport, _termid, nvalid,_nspots))
|
||||||
end
|
end
|
||||||
|
|
||||||
end -- loop over units
|
end -- loop over units
|
||||||
|
|||||||
@ -400,7 +400,8 @@ function CONTROLLABLE:SetTask( DCSTask, WaitTime )
|
|||||||
local Controller = self:_GetController()
|
local Controller = self:_GetController()
|
||||||
--self:I( "Before SetTask" )
|
--self:I( "Before SetTask" )
|
||||||
Controller:setTask( DCSTask )
|
Controller:setTask( DCSTask )
|
||||||
self:I( { ControllableName = self:GetName(), DCSTask = DCSTask } )
|
-- AI_FORMATION class (used by RESCUEHELO) calls SetTask twice per second! hence spamming the DCS log file ==> setting this to trace.
|
||||||
|
self:T( { ControllableName = self:GetName(), DCSTask = DCSTask } )
|
||||||
else
|
else
|
||||||
BASE:E( { DCSControllableName .. " is not alive anymore.", DCSTask = DCSTask } )
|
BASE:E( { DCSControllableName .. " is not alive anymore.", DCSTask = DCSTask } )
|
||||||
end
|
end
|
||||||
@ -408,7 +409,8 @@ function CONTROLLABLE:SetTask( DCSTask, WaitTime )
|
|||||||
|
|
||||||
if not WaitTime or WaitTime == 0 then
|
if not WaitTime or WaitTime == 0 then
|
||||||
SetTask( self, DCSTask )
|
SetTask( self, DCSTask )
|
||||||
self:I( { ControllableName = self:GetName(), DCSTask = DCSTask } )
|
-- See above.
|
||||||
|
self:T( { ControllableName = self:GetName(), DCSTask = DCSTask } )
|
||||||
else
|
else
|
||||||
self.TaskScheduler:Schedule( self, SetTask, { DCSTask }, WaitTime )
|
self.TaskScheduler:Schedule( self, SetTask, { DCSTask }, WaitTime )
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1457,11 +1457,16 @@ end
|
|||||||
|
|
||||||
--- Sets the radio comms on or off when the group is respawned. Same as checking/unchecking the COMM box in the mission editor.
|
--- Sets the radio comms on or off when the group is respawned. Same as checking/unchecking the COMM box in the mission editor.
|
||||||
-- @param #GROUP self
|
-- @param #GROUP self
|
||||||
-- @param #number switch If true (or nil), enables the radio comms. If false, disables the radio for the spawned group.
|
-- @param #boolean switch If true (or nil), enables the radio comms. If false, disables the radio for the spawned group.
|
||||||
-- @return #GROUP self
|
-- @return #GROUP self
|
||||||
function GROUP:InitRadioCommsOnOff(switch)
|
function GROUP:InitRadioCommsOnOff(switch)
|
||||||
self:F({switch=switch})
|
self:F({switch=switch})
|
||||||
self.InitRespawnRadio=switch or true
|
if switch==true or switch==nil then
|
||||||
|
self.InitRespawnRadio=true
|
||||||
|
else
|
||||||
|
self.InitRespawnRadio=false
|
||||||
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Sets the radio frequency of the group when it is respawned.
|
--- Sets the radio frequency of the group when it is respawned.
|
||||||
@ -1490,6 +1495,17 @@ function GROUP:InitRadioModulation(modulation)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Sets the modex (tail number) of the first unit of the group. If more units are in the group, the number is increased with every unit.
|
||||||
|
-- @param #GROUP self
|
||||||
|
-- @param #string modex Tail number of the first unit.
|
||||||
|
-- @return #GROUP self
|
||||||
|
function GROUP:InitModex(modex)
|
||||||
|
self:F({modex=modex})
|
||||||
|
if modex then
|
||||||
|
self.InitRespawnModex=tonumber(modex)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Respawn the @{Wrapper.Group} at a @{Point}.
|
--- Respawn the @{Wrapper.Group} at a @{Point}.
|
||||||
-- The method will setup the new group template according the Init(Respawn) settings provided for the group.
|
-- The method will setup the new group template according the Init(Respawn) settings provided for the group.
|
||||||
@ -1641,6 +1657,13 @@ function GROUP:Respawn( Template, Reset )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Set tail number.
|
||||||
|
if self.InitRespawnModex then
|
||||||
|
for UnitID=1,#Template.units do
|
||||||
|
Template.units[UnitID].onboard_num=string.format("%03d", self.InitRespawnModex+(UnitID-1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Set radio frequency and modulation.
|
-- Set radio frequency and modulation.
|
||||||
if self.InitRespawnRadio then
|
if self.InitRespawnRadio then
|
||||||
Template.communication=self.InitRespawnRadio
|
Template.communication=self.InitRespawnRadio
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user