Update Range.lua

**RANGE** v2.4.0
- Copy from updated
This commit is contained in:
Frank 2022-05-04 22:40:22 +02:00
parent 290cc151bc
commit 0e74d36227

View File

@ -19,7 +19,7 @@
-- * Bomb, rocket and missile impact points can be marked by smoke. -- * Bomb, rocket and missile impact points can be marked by smoke.
-- * Direct hits on targets can trigger flares. -- * Direct hits on targets can trigger flares.
-- * Smoke and flare colors can be adjusted for each player via radio menu. -- * Smoke and flare colors can be adjusted for each player via radio menu.
-- * Range information and weather report at the range can be reported via radio menu. -- * Range information and weather at the range can be obtained via radio menu.
-- * Persistence: Bombing range results can be saved to disk and loaded the next time the mission is started. -- * Persistence: Bombing range results can be saved to disk and loaded the next time the mission is started.
-- * Range control voice overs (>40) for hit assessment. -- * Range control voice overs (>40) for hit assessment.
-- --
@ -50,11 +50,10 @@
-- @module Functional.Range -- @module Functional.Range
-- @image Range.JPG -- @image Range.JPG
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- RANGE class --- RANGE class
-- @type RANGE -- @type RANGE
-- @field #string ClassName Name of the Class. -- @field #string ClassName Name of the Class.
-- @field #boolean Debug If true, debug info is send as messages on the screen. -- @field #boolean Debug If true, debug info is sent as messages on the screen.
-- @field #boolean verbose Verbosity level. Higher means more output to DCS log file. -- @field #boolean verbose Verbosity level. Higher means more output to DCS log file.
-- @field #string id String id of range for output in DCS log. -- @field #string id String id of range for output in DCS log.
-- @field #string rangename Name of the range. -- @field #string rangename Name of the range.
@ -77,13 +76,13 @@
-- @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.
-- @field #number strafemaxalt Maximum altitude above ground for registering for a strafe run. Default is 914 m = 3000 ft. -- @field #number strafemaxalt Maximum altitude in meters AGL for registering for a strafe run. Default is 914 m = 3000 ft.
-- @field #number ndisplayresult Number of (player) results that a displayed. Default is 10. -- @field #number ndisplayresult Number of (player) results that a displayed. Default is 10.
-- @field Utilities.Utils#SMOKECOLOR BombSmokeColor Color id used for smoking bomb targets. -- @field Utilities.Utils#SMOKECOLOR BombSmokeColor Color id used for smoking bomb targets.
-- @field Utilities.Utils#SMOKECOLOR StrafeSmokeColor Color id used to smoke strafe targets. -- @field Utilities.Utils#SMOKECOLOR StrafeSmokeColor Color id used to smoke strafe targets.
-- @field Utilities.Utils#SMOKECOLOR StrafePitSmokeColor Color id used to smoke strafe pit approach boxes. -- @field Utilities.Utils#SMOKECOLOR StrafePitSmokeColor Color id used to smoke strafe pit approach boxes.
-- @field #number illuminationminalt Minimum altitude AGL in meters at which illumination bombs are fired. Default is 500 m. -- @field #number illuminationminalt Minimum altitude in meters AGL at which illumination bombs are fired. Default is 500 m.
-- @field #number illuminationmaxalt Maximum altitude AGL in meters at which illumination bombs are fired. Default is 1000 m. -- @field #number illuminationmaxalt Maximum altitude in meters AGL at which illumination bombs are fired. Default is 1000 m.
-- @field #number scorebombdistance Distance from closest target up to which bomb hits are counted. Default 1000 m. -- @field #number scorebombdistance Distance from closest target up to which bomb hits are counted. Default 1000 m.
-- @field #number TdelaySmoke Time delay in seconds between impact of bomb and starting the smoke. Default 3 seconds. -- @field #number TdelaySmoke Time delay in seconds between impact of bomb and starting the smoke. Default 3 seconds.
-- @field #boolean eventmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler. Default true. -- @field #boolean eventmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler. Default true.
@ -134,12 +133,12 @@
-- --
-- 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.
-- --
-- * The first parameter *targetnames* defines the target or targets. This has to be given as a lua table which contains the names of @{Wrapper.Unit} or @{Static} objects defined in the mission editor. -- * The first parameter *targetnames* defines the target or targets. This can be a single item or a Table with the name(s) of @{Wrapper.Unit} or @{Static} objects defined in the mission editor.
-- * In order to perform a valid pass on the strafe pit, the pilot has to begin his run from the correct direction. Therefore, an "approach box" is defined in front -- * In order to perform a valid pass on the strafe pit, the pilot has to begin his run from the correct direction. Therefore, an "approach box" is defined in front
-- of the strafe targets. The parameters *boxlength* and *boxwidth* define the size of the box while the parameter *heading* defines its direction. -- of the strafe targets. The parameters *boxlength* and *boxwidth* define the size of the box in meters, while the *heading* parameter defines the heading of the box FROM the target.
-- 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. -- For example, if heading 120 is set, the approach box will start FROM the target and extend outwards on heading 120. A strafe run approach must then be flown apx. heading 300 TOWARDS the target.
-- 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 -- If the parameter *heading* is passed as **nil**, the heading is automatically taken from the heading set in the ME for the first target unit.
-- wrong/opposite direction. -- * The parameter *inverseheading* turns the heading around by 180 degrees. This is useful when the default heading of strafe target units point in the wrong/opposite direction.
-- * The parameter *goodpass* defines the number of hits a pilot has to achieve 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!
-- --
@ -153,9 +152,8 @@
-- --
-- One ore multiple bombing targets can be added to the range by the @{#RANGE.AddBombingTargets}(targetnames, goodhitrange, randommove) function. -- One ore multiple bombing targets can be added to the range by the @{#RANGE.AddBombingTargets}(targetnames, goodhitrange, randommove) function.
-- --
-- * The first parameter *targetnames* has to be a lua table, which contains the names of @{Wrapper.Unit} and/or @{Static} objects defined in the mission editor. -- * The first parameter *targetnames* defines the target or targets. This can be a single item or a Table with the name(s) of @{Wrapper.Unit} or @{Static} objects defined in the mission editor.
-- Note that the @{Range} logic **automatically** determines, if a name belongs to a @{Wrapper.Unit} or @{Static} object now. -- * The (optional) parameter *goodhitrange* specifies the radius in metres around the target within which a bomb/rocket hit is considered to be "good".
-- * The (optional) parameter *goodhitrange* specifies the radius around the target. If a bomb or rocket falls at a distance smaller than this number, the hit is considered to be "good".
-- * If final (optional) parameter "*randommove*" can be enabled to create moving targets. If this parameter is set to true, the units of this bombing target will randomly move within the range zone. -- * If final (optional) parameter "*randommove*" can be enabled to create moving targets. If this parameter is set to true, the units of this bombing target will randomly move within the range zone.
-- Note that there might be quirks since DCS units can get stuck in buildings etc. So it might be safer to manually define a route for the units in the mission editor if moving targets are desired. -- Note that there might be quirks since DCS units can get stuck in buildings etc. So it might be safer to manually define a route for the units in the mission editor if moving targets are desired.
-- --
@ -191,7 +189,7 @@
-- --
-- The main range menu can be found at "F10. Other..." --> "F*X*. On the Range..." --> "F1. <Range Name>...". -- The main range menu can be found at "F10. Other..." --> "F*X*. On the Range..." --> "F1. <Range Name>...".
-- --
-- The range menu contains the following submenues: -- The range menu contains the following submenus:
-- --
-- ![Banner Image](..\Presentations\RANGE\Menu_Main.png) -- ![Banner Image](..\Presentations\RANGE\Menu_Main.png)
-- --
@ -236,6 +234,16 @@
-- --
-- Strafing results are currently **not** saved. -- Strafing results are currently **not** saved.
-- --
-- # FSM Events
--
-- This class creates additional events that can be used by mission designers for custom reactions
--
-- * `EnterRange` when a player enters a range zone. See @{#RANGE.OnAfterEnterRange}
-- * `ExitRange` when a player leaves a range zone. See @{#RANGE.OnAfterExitRange}
-- * `Impact` on impact of a player's weapon on a bombing target. See @{#RANGE.OnAfterImpact}
-- * `RollingIn` when a player rolls in on a strafing target. See @{#RANGE.OnAfterRollingIn}
-- * `StrafeResult` when a player finishes a strafing run. See @{#RANGE.OnAfterStrafeResult}
--
-- # Examples -- # Examples
-- --
-- ## Goldwater Range -- ## Goldwater Range
@ -258,9 +266,9 @@
-- -- Note that this could also be done manually by simply measuring the distance between the target and the foul line in the ME. -- -- Note that this could also be done manually by simply measuring the distance between the target and the foul line in the ME.
-- GoldwaterRange:GetFoullineDistance("GWR Strafe Pit Left 1", "GWR Foul Line Left") -- GoldwaterRange:GetFoullineDistance("GWR Strafe Pit Left 1", "GWR Foul Line Left")
-- --
-- -- Add strafe pits. Each pit (left and right) consists of two targets. -- -- Add strafe pits. Each pit (left and right) consists of two targets. Where "nil" is used as input, the default value is used.
-- GoldwaterRange:AddStrafePit(strafepit_left, 3000, 300, nil, true, 20, fouldist) -- GoldwaterRange:AddStrafePit(strafepit_left, 3000, 300, nil, true, 30, 500)
-- GoldwaterRange:AddStrafePit(strafepit_right, nil, nil, nil, true, nil, fouldist) -- GoldwaterRange:AddStrafePit(strafepit_right, nil, nil, nil, true, nil, 500)
-- --
-- -- Add bombing targets. A good hit is if the bomb falls less then 50 m from the target. -- -- Add bombing targets. A good hit is if the bomb falls less then 50 m from the target.
-- GoldwaterRange:AddBombingTargets(bombtargets, 50) -- GoldwaterRange:AddBombingTargets(bombtargets, 50)
@ -290,8 +298,6 @@
-- Note that it can happen that the RANGE radio menu is not shown. Check that the range object is defined as a **global** variable rather than a local one. -- Note that it can happen that the RANGE radio menu is not shown. Check that the range object is defined as a **global** variable rather than a local one.
-- The could avoid the lua garbage collection to accidentally/falsely deallocate the RANGE objects. -- The could avoid the lua garbage collection to accidentally/falsely deallocate the RANGE objects.
-- --
--
--
-- @field #RANGE -- @field #RANGE
RANGE = { RANGE = {
ClassName = "RANGE", ClassName = "RANGE",
@ -356,8 +362,7 @@ RANGE.Defaults={
boxlength = 3000, boxlength = 3000,
boxwidth = 300, boxwidth = 300,
goodpass = 20, goodpass = 20,
goodhitrange=25, foulline = 610
foulline=610,
} }
--- Target type, i.e. unit, static, or coordinate. --- Target type, i.e. unit, static, or coordinate.
@ -368,16 +373,9 @@ RANGE.Defaults={
RANGE.TargetType = { RANGE.TargetType = {
UNIT = "Unit", UNIT = "Unit",
STATIC = "Static", STATIC = "Static",
COORD="Coordinate", COORD = "Coordinate"
} }
--- Default range variables for RangeBoss/Hypeman tie in.
hypemanStrafeRollIn = "nil"
StrafeAircraftType = "strafeAircraftTypeNotSet"
Straferesult={}
clientRollingIn = false
clientStrafed = false
invalidStrafe = false
--- Player settings. --- Player settings.
-- @type RANGE.PlayerData -- @type RANGE.PlayerData
-- @field #boolean smokebombimpact Smoke bomb impact points. -- @field #boolean smokebombimpact Smoke bomb impact points.
@ -412,6 +410,14 @@ invalidStrafe = false
-- @field #number smokepoints Number of smoke points. -- @field #number smokepoints Number of smoke points.
-- @field #number heading Heading of pit. -- @field #number heading Heading of pit.
--- Strafe status for player.
-- @type RANGE.StrafeStatus
-- @field #number hits Number of hits on target.
-- @field #number time Number of times.
-- @field #number ammo Amount of ammo.
-- @field #boolean pastfoulline If `true`, player passed foul line. Invalid pass.
-- @field #RANGE.StrafeTarget zone Strafe target.
--- Bomb target result. --- Bomb target result.
-- @type RANGE.BombResult -- @type RANGE.BombResult
-- @field #string name Name of closest target. -- @field #string name Name of closest target.
@ -424,6 +430,13 @@ invalidStrafe = false
-- @field #number time Time via timer.getAbsTime() in seconds of impact. -- @field #number time Time via timer.getAbsTime() in seconds of impact.
-- @field #string date OS date. -- @field #string date OS date.
--- Strafe result.
-- @type RANGE.StrafeResult
-- @field #string player Player name.
-- @field #string airframe Aircraft type of player.
-- @field #number time Time via timer.getAbsTime() in seconds of impact.
-- @field #string date OS date.
--- Sound file data. --- Sound file data.
-- @type RANGE.Soundfile -- @type RANGE.Soundfile
-- @field #string filename Name of the file -- @field #string filename Name of the file
@ -536,7 +549,7 @@ RANGE.MenuF10Root=nil
--- Range script version. --- Range script version.
-- @field #string version -- @field #string version
RANGE.version="2.3.0" RANGE.version = "2.4.0"
-- TODO list: -- TODO list:
-- TODO: Verbosity level for messages. -- TODO: Verbosity level for messages.
@ -587,6 +600,8 @@ function RANGE:New(rangename)
self:AddTransition("Stopped", "Start", "Running") -- Start RANGE script. self:AddTransition("Stopped", "Start", "Running") -- Start RANGE script.
self:AddTransition("*", "Status", "*") -- Status of RANGE script. self:AddTransition("*", "Status", "*") -- Status of RANGE script.
self:AddTransition("*", "Impact", "*") -- Impact of bomb/rocket/missile. self:AddTransition("*", "Impact", "*") -- Impact of bomb/rocket/missile.
self:AddTransition("*", "RollingIn", "*") -- Player rolling in on strafe target.
self:AddTransition("*", "StrafeResult", "*") -- Strafe result of player.
self:AddTransition("*", "EnterRange", "*") -- Player enters the range. self:AddTransition("*", "EnterRange", "*") -- Player enters the range.
self:AddTransition("*", "ExitRange", "*") -- Player leaves the range. self:AddTransition("*", "ExitRange", "*") -- Player leaves the range.
self:AddTransition("*", "Save", "*") -- Save player results. self:AddTransition("*", "Save", "*") -- Save player results.
@ -644,6 +659,37 @@ function RANGE:New(rangename)
-- @param #RANGE.BombResult result Data of the bombing run. -- @param #RANGE.BombResult result Data of the bombing run.
-- @param #RANGE.PlayerData player Data of player settings etc. -- @param #RANGE.PlayerData player Data of player settings etc.
--- Triggers the FSM event "RollingIn".
-- @function [parent=#RANGE] RollingIn
-- @param #RANGE self
-- @param #RANGE.PlayerData player Data of player settings etc.
-- @param #RANGE.StrafeTarget target Strafe target.
--- On after "RollingIn" event user function. Called when a player rolls in to a strafe taret.
-- @function [parent=#RANGE] OnAfterRollingIn
-- @param #RANGE self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #RANGE.PlayerData player Data of player settings etc.
-- @param #RANGE.StrafeTarget target Strafe target.
--- Triggers the FSM event "StrafeResult".
-- @function [parent=#RANGE] StrafeResult
-- @param #RANGE self
-- @param #RANGE.PlayerData player Data of player settings etc.
-- @param #RANGE.StrafeResult result Data of the strafing run.
--- On after "StrafeResult" event user function. Called when a player finished a strafing run.
-- @function [parent=#RANGE] OnAfterStrafeResult
-- @param #RANGE self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #RANGE.PlayerData player Data of player settings etc.
-- @param #RANGE.StrafeResult result Data of the strafing run.
--- Triggers the FSM event "EnterRange". --- Triggers the FSM event "EnterRange".
-- @function [parent=#RANGE] EnterRange -- @function [parent=#RANGE] EnterRange
-- @param #RANGE self -- @param #RANGE self
@ -847,7 +893,7 @@ end
--- 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 in meters AGL. Default is 914 m = 3000 ft.
-- @return #RANGE self -- @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
@ -1052,7 +1098,6 @@ function RANGE:SetMessagesON()
return self 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 -- @return #RANGE self
@ -1101,7 +1146,6 @@ function RANGE:TrackMissilesOFF()
return self return self
end end
--- Enable range control and set frequency. --- Enable range control and set frequency.
-- @param #RANGE self -- @param #RANGE self
-- @param #number frequency Frequency in MHz. Default 256 MHz. -- @param #number frequency Frequency in MHz. Default 256 MHz.
@ -1126,7 +1170,7 @@ end
--- Set sound files folder within miz file. --- Set sound files folder within miz file.
-- @param #RANGE self -- @param #RANGE self
-- @param #string path Path for sound files. Default "ATIS Soundfiles/". Mind the slash "/" at the end! -- @param #string path Path for sound files. Default "Range Soundfiles/". Mind the slash "/" at the end!
-- @return #RANGE self -- @return #RANGE self
function RANGE:SetSoundfilesPath( path ) function RANGE:SetSoundfilesPath( path )
self.soundpath = tostring( path or "Range Soundfiles/" ) self.soundpath = tostring( path or "Range Soundfiles/" )
@ -1135,16 +1179,16 @@ function RANGE:SetSoundfilesPath(path)
end end
--- Add new strafe pit. For a strafe pit, hits from guns are counted. One pit can consist of several units. --- Add new strafe pit. For a strafe pit, hits from guns are counted. One pit can consist of several units.
-- Note, an approach is only valid, if the player enters via a zone in front of the pit, which defined by boxlength and boxheading. -- A strafe run approach is only valid if the player enters via a zone in front of the pit, which is defined by boxlength, boxwidth, and heading.
-- Furthermore, the player must not be too high and fly in the direction of the pit to make a valid target apporoach. -- Furthermore, the player must not be too high and fly in the direction of the pit to make a valid target apporoach.
-- @param #RANGE self -- @param #RANGE self
-- @param #table targetnames Table of unit or static names defining the strafe targets. The first target in the list determines the approach zone (heading and box). -- @param #table targetnames Single or multiple (Table) unit or static names defining the strafe targets. The first target in the list determines the approach box origin (heading and box).
-- @param #number boxlength (Optional) Length of the approach box in meters. Default is 3000 m. -- @param #number boxlength (Optional) Length of the approach box in meters. Default is 3000 m.
-- @param #number boxwidth (Optional) Width of the approach box in meters. Default is 300 m. -- @param #number boxwidth (Optional) Width of the approach box in meters. Default is 300 m.
-- @param #number heading (Optional) Approach heading in Degrees. Default is heading of the unit as defined in the mission editor. -- @param #number heading (Optional) Approach box heading in degrees (originating FROM the target). Default is the heading set in the ME for the first target unit
-- @param #boolean inverseheading (Optional) Take inverse heading (heading --> heading - 180 Degrees). Default is false. -- @param #boolean inverseheading (Optional) Use 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 is 610 m = 2000 ft. Set to 0 for no foul line.
-- @return #RANGE self -- @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 } )
@ -1274,7 +1318,6 @@ function RANGE:AddStrafePit(targetnames, boxlength, boxwidth, heading, inversehe
return self return self
end end
--- Add all units of a group as one new strafe target pit. --- Add all units of a group as one new strafe target pit.
-- For a strafe pit, hits from guns are counted. One pit can consist of several units. -- For a strafe pit, hits from guns are counted. One pit can consist of several units.
-- Note, an approach is only valid, if the player enters via a zone in front of the pit, which defined by boxlength and boxheading. -- Note, an approach is only valid, if the player enters via a zone in front of the pit, which defined by boxlength and boxheading.
@ -1318,7 +1361,7 @@ end
--- Add bombing target(s) to range. --- Add bombing target(s) to range.
-- @param #RANGE self -- @param #RANGE self
-- @param #table targetnames Table containing names of unit or static objects serving as bomb targets. -- @param #table targetnames Single or multiple (Table) 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 -- @return #RANGE self
@ -1412,7 +1455,6 @@ function RANGE:AddBombingTargetUnit(unit, goodhitrange, randommove)
return self return self
end end
--- Add a coordinate of a bombing target. This --- Add a coordinate of a bombing target. This
-- @param #RANGE self -- @param #RANGE self
-- @param Core.Point#COORDINATE coord The coordinate. -- @param Core.Point#COORDINATE coord The coordinate.
@ -1574,7 +1616,6 @@ function RANGE:onEvent(Event)
end end
--- Range event handler for event birth. --- Range event handler for event birth.
-- @param #RANGE self -- @param #RANGE self
-- @param Core.Event#EVENTDATA EventData -- @param Core.Event#EVENTDATA EventData
@ -1603,7 +1644,6 @@ function RANGE:OnEventBirth(EventData)
self.strafeStatus[_uid] = nil self.strafeStatus[_uid] = nil
-- Add Menu commands after a delay of 0.1 seconds. -- Add Menu commands after a delay of 0.1 seconds.
--SCHEDULER:New(nil, self._AddF10Commands, {self,_unitName}, 0.1)
self:ScheduleOnce( 0.1, self._AddF10Commands, self, _unitName ) self:ScheduleOnce( 0.1, self._AddF10Commands, self, _unitName )
-- 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.
@ -1622,7 +1662,6 @@ function RANGE:OnEventBirth(EventData)
-- Start check in zone timer. -- Start check in zone timer.
if self.planes[_uid] ~= true then if self.planes[_uid] ~= true then
--SCHEDULER:New(nil, self._CheckInZone, {self, EventData.IniUnitName}, 1, 1)
self.timerCheckZone = TIMER:New( self._CheckInZone, self, EventData.IniUnitName ):Start( 1, 1 ) self.timerCheckZone = TIMER:New( self._CheckInZone, self, EventData.IniUnitName ):Start( 1, 1 )
self.planes[_uid] = true self.planes[_uid] = true
end end
@ -1656,7 +1695,7 @@ function RANGE:OnEventHit(EventData)
local targetname = EventData.TgtUnitName local targetname = EventData.TgtUnitName
-- Current strafe target of player. -- Current strafe target of player.
local _currentTarget = self.strafeStatus[_unitID] local _currentTarget = self.strafeStatus[_unitID] --#RANGE.StrafeStatus
-- Player has rolled in on a strafing target. -- Player has rolled in on a strafing target.
if _currentTarget and target:IsAlive() then if _currentTarget and target:IsAlive() then
@ -1793,8 +1832,7 @@ function RANGE:OnEventShot(EventData)
local function trackBomb( _ordnance ) local function trackBomb( _ordnance )
-- When the pcall returns a failure the weapon has hit. -- When the pcall returns a failure the weapon has hit.
local _status,_bombPos = pcall( local _status, _bombPos = pcall( function()
function()
return _ordnance:getPoint() return _ordnance:getPoint()
end ) end )
@ -1941,76 +1979,6 @@ end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- FSM Functions -- FSM Functions
----------------------------------------------------------------------------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
function RANGE:_SaveTargetSheet(_playername, result) --RangeBoss Specific Function
--- Function that saves data to file
local function _savefile(filename, data)
local f = io.open(filename, "wb")
if f then
f:write(data)
f:close()
else
env.info("RANGEBOSS EDIT - could not save target sheet to file")
--self:E(self.lid..string.format("ERROR: could not save target sheet to file %s.\nFile may contain invalid characters.", tostring(filename)))
end
end
-- Set path or default.
local path=self.targetpath
if lfs then
path=path or lfs.writedir()..[[Logs\]]
end
-- Create unused file name.
local filename=nil
for i=1,9999 do
-- Create file name
if self.targetprefix then
filename=string.format("%s_%s-%04d.csv", self.targetprefix, playerData.actype, i)
else
local name=UTILS.ReplaceIllegalCharacters(_playername, "_")
filename=string.format("RANGERESULTS-%s_Targetsheet-%s-%04d.csv",self.rangename,name, i)
end
-- Set path.
if path~=nil then
filename=path.."\\"..filename
end
-- Check if file exists.
local _exists=UTILS.FileExists(filename)
if not _exists then
break
end
end
-- Header line
local data="Name,Target,Distance,Radial,Quality,Rounds Fired,Rounds Hit,Rounds Quality,Attack Heading,Weapon,Airframe,Mission Time,OS Time\n"
--local result=_result --#RANGE.BombResult
local distance=result.distance
local weapon=result.weapon
local target=result.name
local radial=result.radial
local quality=result.quality
local time=UTILS.SecondsToClock(result.time)
local airframe=result.airframe
local date="n/a"
local roundsFired=result.roundsFired
local roundsHit=result.roundsHit
local strafeResult=result.roundsQuality
local attackHeading=result.heading
if os then
date=os.date()
end
data=data..string.format("%s,%s,%.2f,%03d,%s,%03d,%03d,%s,%03d,%s,%s,%s,%s", _playername, target, distance, radial, quality, roundsFired, roundsHit, strafeResult, attackHeading, weapon, airframe, time, date)
-- Save file.
_savefile(filename, data)
end
--- Check spawn queue and spawn aircraft if necessary. --- Check spawn queue and spawn aircraft if necessary.
-- @param #RANGE self -- @param #RANGE self
@ -2047,7 +2015,6 @@ function RANGE:onafterStatus(From, Event, To)
text = text .. string.format( ", Control %.3f MHz (Relay=%s alive=%s)", self.rangecontrolfreq, tostring( self.rangecontrolrelayname ), alive ) text = text .. string.format( ", Control %.3f MHz (Relay=%s alive=%s)", self.rangecontrolfreq, tostring( self.rangecontrolrelayname ), alive )
end end
-- Check range status. -- Check range status.
self:I( self.id .. text ) self:I( self.id .. text )
@ -2099,7 +2066,6 @@ function RANGE:onafterExitRange(From, Event, To, player)
end end
--- Function called after bomb impact on range. --- Function called after bomb impact on range.
-- @param #RANGE self -- @param #RANGE self
-- @param #string From From state. -- @param #string From From state.
@ -2313,6 +2279,73 @@ function RANGE:onafterLoad(From, Event, To)
end end
end end
--- Save target sheet.
-- @param #RANGE self
-- @param #string _playername Player name.
-- @param #RANGE.StrafeResult result Results table.
function RANGE:_SaveTargetSheet( _playername, result ) -- RangeBoss Specific Function
--- Function that saves data to file
local function _savefile( filename, data )
local f = io.open( filename, "wb" )
if f then
f:write( data )
f:close()
else
env.info( "RANGEBOSS EDIT - could not save target sheet to file" )
-- self:E(self.lid..string.format("ERROR: could not save target sheet to file %s.\nFile may contain invalid characters.", tostring(filename)))
end
end
-- Set path or default.
local path = self.targetpath
if lfs then
path = path or lfs.writedir() .. [[Logs\]]
end
-- Create unused file name.
local filename = nil
for i = 1, 9999 do
-- Create file name
if self.targetprefix then
filename = string.format( "%s_%s-%04d.csv", self.targetprefix, result.airframe, i )
else
local name = UTILS.ReplaceIllegalCharacters( _playername, "_" )
filename = string.format( "RANGERESULTS-%s_Targetsheet-%s-%04d.csv", self.rangename, name, i )
end
-- Set path.
if path ~= nil then
filename = path .. "\\" .. filename
end
-- Check if file exists.
local _exists = UTILS.FileExists( filename )
if not _exists then
break
end
end
-- Header line
local data = "Name,Target,Rounds Fired,Rounds Hit,Rounds Quality,Airframe,Mission Time,OS Time\n"
local target = result.name
local airframe = result.airframe
local roundsFired = result.roundsFired
local roundsHit = result.roundsHit
local strafeResult = result.roundsQuality
local time = UTILS.SecondsToClock( result.time )
local date = "n/a"
if os then
date = os.date()
end
data = data .. string.format( "%s,%s,%d,%d,%s,%s,%s,%s", _playername, target, roundsFired, roundsHit, strafeResult, airframe, time, date )
-- Save file.
_savefile( filename, data )
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Display Messages -- Display Messages
----------------------------------------------------------------------------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -2347,7 +2380,9 @@ function RANGE:_DisplayMyStrafePitResults(_unitName)
else else
-- Sort results table wrt number of hits. -- Sort results table wrt number of hits.
local _sort = function( a,b ) return a.hits > b.hits end local _sort = function( a, b )
return a.hits > b.hits
end
table.sort( _results, _sort ) table.sort( _results, _sort )
-- Prepare message of best results. -- Prepare message of best results.
@ -2356,9 +2391,10 @@ function RANGE:_DisplayMyStrafePitResults(_unitName)
-- Loop over results -- Loop over results
for _, _result in pairs( _results ) do for _, _result in pairs( _results ) do
local result=_result --#RANGE.StrafeResult
-- Message text. -- Message text.
_message = _message..string.format("\n[%d] Hits %d - %s - %s", _count, _result.hits, _result.zone.name, _result.text) _message = _message .. string.format( "\n[%d] Hits %d - %s - %s", _count, result.roundsHit, result.name, result.roundsQuality )
-- Best result. -- Best result.
if _bestMsg == "" then if _bestMsg == "" then
@ -2421,7 +2457,9 @@ function RANGE:_DisplayStrafePitResults(_unitName)
end end
-- Sort list! -- Sort list!
local _sort = function( a,b ) return a.hits > b.hits end local _sort = function( a, b )
return a.hits > b.hits
end
table.sort( _playerResults, _sort ) table.sort( _playerResults, _sort )
-- Add top 10 results. -- Add top 10 results.
@ -2462,7 +2500,9 @@ function RANGE:_DisplayMyBombingResults(_unitName)
else else
-- Sort results wrt to distance. -- Sort results wrt to distance.
local _sort = function( a,b ) return a.distance < b.distance end local _sort = function( a, b )
return a.distance < b.distance
end
table.sort( _results, _sort ) table.sort( _results, _sort )
-- Loop over results. -- Loop over results.
@ -2532,7 +2572,9 @@ function RANGE:_DisplayBombingResults(_unitName)
end end
-- Sort list of player results. -- Sort list of player results.
local _sort = function( a,b ) return a.distance < b.distance end local _sort = function( a, b )
return a.distance < b.distance
end
table.sort( _playerResults, _sort ) table.sort( _playerResults, _sort )
-- Loop over player results. -- Loop over player results.
@ -2721,7 +2763,6 @@ function RANGE:_DisplayStrafePits(_unitname)
end end
end end
--- Report weather conditions at range. Temperature, QFE pressure and wind data. --- Report weather conditions at range. Temperature, QFE pressure and wind data.
-- @param #RANGE self -- @param #RANGE self
-- @param #string _unitname Name of the player unit. -- @param #string _unitname Name of the player unit.
@ -2767,7 +2808,6 @@ function RANGE:_DisplayRangeWeather(_unitname)
tP = string.format( "%.2f inHg", P * hPa2inHg ) tP = string.format( "%.2f inHg", P * hPa2inHg )
end end
-- Message text. -- Message text.
text = text .. string.format( "Weather Report at %s:\n", self.rangename ) text = text .. string.format( "Weather Report at %s:\n", self.rangename )
text = text .. string.format( "--------------------------------------------------\n" ) text = text .. string.format( "--------------------------------------------------\n" )
@ -2844,13 +2884,15 @@ function RANGE:_CheckInZone(_unitName)
if _unit and _playername then if _unit and _playername then
-- Player data.
local playerData=self.PlayerSettings[_playername] -- #RANGE.PlayerData
--- Function to check if unit is in zone and facing in the right direction and is below the max alt. --- Function to check if unit is in zone and facing in the right direction and is below the max alt.
local function checkme( targetheading, _zone ) local function checkme( targetheading, _zone )
local zone = _zone -- Core.Zone#ZONE local zone = _zone -- Core.Zone#ZONE
-- Heading check. -- Heading check.
local unitheading = _unit:GetHeading() local unitheading = _unit:GetHeading()
unitheadingStrafe = _unit:GetHeading() --RangeBoss
local pitheading = targetheading - 180 local pitheading = targetheading - 180
local deltaheading = unitheading - pitheading local deltaheading = unitheading - pitheading
local towardspit = math.abs( deltaheading ) <= 90 or math.abs( deltaheading - 360 ) <= 90 local towardspit = math.abs( deltaheading ) <= 90 or math.abs( deltaheading - 360 ) <= 90
@ -2875,7 +2917,7 @@ function RANGE:_CheckInZone(_unitName)
local _unitID = _unit:GetID() local _unitID = _unit:GetID()
-- Currently strafing? (strafeStatus is nil if not) -- Currently strafing? (strafeStatus is nil if not)
local _currentStrafeRun = self.strafeStatus[_unitID] local _currentStrafeRun = self.strafeStatus[_unitID] --#RANGE.StrafeStatus
if _currentStrafeRun then -- player has already registered for a strafing run. if _currentStrafeRun then -- player has already registered for a strafing run.
@ -2887,7 +2929,6 @@ function RANGE:_CheckInZone(_unitName)
-- Check if player is in strafe zone and below max alt. -- Check if player is in strafe zone and below max alt.
if unitinzone then if unitinzone then
StrafeAircraftType = _unit:GetTypeName() --RangeBoss
-- Still in zone, keep counting hits. Increase counter. -- Still in zone, keep counting hits. Increase counter.
_currentStrafeRun.time = _currentStrafeRun.time + 1 _currentStrafeRun.time = _currentStrafeRun.time + 1
@ -2917,8 +2958,10 @@ function RANGE:_CheckInZone(_unitName)
local _ammo = self:_GetAmmo( _unitName ) local _ammo = self:_GetAmmo( _unitName )
-- Result. -- Result.
local _result = self.strafeStatus[_unitID] local _result = self.strafeStatus[_unitID] --#RANGE.StrafeStatus
local _sound = nil -- #RANGE.Soundfile local _sound = nil -- #RANGE.Soundfile
--[[ --RangeBoss commented out in order to implement strafe quality based on accuracy percentage, not the number of rounds on target --[[ --RangeBoss commented out in order to implement strafe quality based on accuracy percentage, not the number of rounds on target
-- Judge this pass. Text is displayed on summary. -- Judge this pass. Text is displayed on summary.
if _result.hits >= _result.zone.goodPass*2 then if _result.hits >= _result.zone.goodPass*2 then
@ -2935,36 +2978,40 @@ function RANGE:_CheckInZone(_unitName)
_sound=RANGE.Sound.RCPoorPass _sound=RANGE.Sound.RCPoorPass
end end
]] ]]
-- Calculate accuracy of run. Number of hits wrt number of rounds fired. -- Calculate accuracy of run. Number of hits wrt number of rounds fired.
local shots = _result.ammo - _ammo local shots = _result.ammo - _ammo
local accur = 0 local accur = 0
if shots > 0 then if shots > 0 then
accur = _result.hits / shots * 100 accur = _result.hits / shots * 100
if accur > 100 then accur = 100 end if accur > 100 then
accur = 100
end
end end
if invalidStrafe == true then-- -- Results text and sound message.
_result.text = "* INVALID - PASSED FOUL LINE *" local resulttext=""
if _result.pastfoulline == true then --
resulttext = "* INVALID - PASSED FOUL LINE *"
_sound = RANGE.Sound.RCPoorPass -- _sound = RANGE.Sound.RCPoorPass --
else else
if accur >= 90 then if accur >= 90 then
_result.text = "DEADEYE PASS" resulttext = "DEADEYE PASS"
_sound = RANGE.Sound.RCExcellentPass _sound = RANGE.Sound.RCExcellentPass
elseif accur >= 75 then elseif accur >= 75 then
_result.text = "EXCELLENT PASS" resulttext = "EXCELLENT PASS"
_sound = RANGE.Sound.RCExcellentPass _sound = RANGE.Sound.RCExcellentPass
elseif accur >= 50 then elseif accur >= 50 then
_result.text = "GOOD PASS" resulttext = "GOOD PASS"
_sound = RANGE.Sound.RCGoodPass _sound = RANGE.Sound.RCGoodPass
elseif accur >= 25 then elseif accur >= 25 then
_result.text = "INEFFECTIVE PASS" resulttext = "INEFFECTIVE PASS"
_sound = RANGE.Sound.RCIneffectivePass _sound = RANGE.Sound.RCIneffectivePass
else else
_result.text = "POOR PASS" resulttext = "POOR PASS"
_sound = RANGE.Sound.RCPoorPass _sound = RANGE.Sound.RCPoorPass
end end
end end
clientStrafed = true --RANGEBOSS
-- Message text. -- Message text.
local _text = string.format( "%s, hits on target %s: %d", self:_myname( _unitName ), _result.zone.name, _result.hits ) local _text = string.format( "%s, hits on target %s: %d", self:_myname( _unitName ), _result.zone.name, _result.hits )
@ -2976,44 +3023,26 @@ function RANGE:_CheckInZone(_unitName)
-- Send message. -- Send message.
self:_DisplayMessageToGroup( _unit, _text ) self:_DisplayMessageToGroup( _unit, _text )
--RangeBoss Edit for strafe table insert -- Strafe result.
local result = {} -- #RANGE.StrafeResult
-- Local results. result.player=_playername
local result={} --#RANGE.BombResult
result.name=_result.zone.name or "unknown" result.name=_result.zone.name or "unknown"
result.distance=0
result.radial=0
result.weapon="N/A"
result.quality="N/A"
result.player=_playernamee
result.time = timer.getAbsTime() result.time = timer.getAbsTime()
result.airframe=StrafeAircraftType result.roundsFired = shots
result.roundsFired=shots --RANGEBOSS result.roundsHit = _result.hits
result.roundsHit=_result.hits --RANGEBOSS result.roundsQuality = resulttext
result.roundsQuality=_result.text --RANGEBOSS
result.strafeAccuracy = accur result.strafeAccuracy = accur
result.heading =unitheadingStrafe --RANGEBOSS result.rangename = self.rangename
result.airframe=playerData.airframe
result.invalid = _result.pastfoulline
Straferesult.name= _result.zone.name or "unknown" -- Griger Results.
Straferesult.distance=0 self:StrafeResult(playerData, result)
Straferesult.radial=0
Straferesult.weapon="N/A"
Straferesult.quality="N/A"
Straferesult.player=_playername
Straferesult.time=timer.getAbsTime()
Straferesult.airframe=StrafeAircraftType
Straferesult.roundsFired=shots
Straferesult.roundsHit= _result.hits
Straferesult.roundsQuality=_result.text
Straferesult.strafeAccuracy=accur
Straferesult.rangename=self.rangename
-- Save trap sheet. -- Save trap sheet.
if playerData and playerData.targeton and self.targetsheet then if playerData and playerData.targeton and self.targetsheet then
self:_SaveTargetSheet( _playername, result ) self:_SaveTargetSheet( _playername, result )
end end
--RangeBoss edit for strafe data saved to file
-- Voice over. -- Voice over.
if self.rangecontrol then if self.rangecontrol then
@ -3034,7 +3063,7 @@ function RANGE:_CheckInZone(_unitName)
-- Save stats so the player can retrieve them. -- Save stats so the player can retrieve them.
local _stats = self.strafePlayerResults[_playername] or {} local _stats = self.strafePlayerResults[_playername] or {}
table.insert(_stats, _result) table.insert( _stats, result )
self.strafePlayerResults[_playername] = _stats self.strafePlayerResults[_playername] = _stats
end end
@ -3044,12 +3073,13 @@ function RANGE:_CheckInZone(_unitName)
-- Check to see if we're in any of the strafing zones (first time). -- Check to see if we're in any of the strafing zones (first time).
for _, _targetZone in pairs( self.strafeTargets ) do for _, _targetZone in pairs( self.strafeTargets ) do
local target=_targetZone --#RANGE.StrafeTarget
-- Get the current approach zone and check if player is inside. -- Get the current approach zone and check if player is inside.
local zone=_targetZone.polygon --Core.Zone#ZONE_POLYGON_BASE local zone = target.polygon -- Core.Zone#ZONE_POLYGON_BASE
-- Check if unit in zone and facing the right direction. -- Check if unit in zone and facing the right direction.
local unitinzone=checkme(_targetZone.heading, zone) local unitinzone = checkme( target.heading, zone )
-- Player is inside zone. -- Player is inside zone.
if unitinzone then if unitinzone then
@ -3058,19 +3088,20 @@ function RANGE:_CheckInZone(_unitName)
local _ammo = self:_GetAmmo( _unitName ) local _ammo = self:_GetAmmo( _unitName )
-- Init strafe status for this player. -- Init strafe status for this player.
self.strafeStatus[_unitID] = {hits = 0, zone = _targetZone, time = 1, ammo=_ammo, pastfoulline=false} self.strafeStatus[_unitID] = { hits = 0, zone = target, time = 1, ammo = _ammo, pastfoulline = false }
-- Rolling in! -- Rolling in!
local _msg=string.format("%s, rolling in on strafe pit %s.", self:_myname(_unitName), _targetZone.name) local _msg = string.format( "%s, rolling in on strafe pit %s.", self:_myname( _unitName ), target.name )
if self.rangecontrol then if self.rangecontrol then
self.rangecontrol:NewTransmission( RANGE.Sound.RCRollingInOnStrafeTarget.filename, RANGE.Sound.RCRollingInOnStrafeTarget.duration, self.soundpath ) self.rangecontrol:NewTransmission( RANGE.Sound.RCRollingInOnStrafeTarget.filename, RANGE.Sound.RCRollingInOnStrafeTarget.duration, self.soundpath )
end end
clientRollingIn = true --RANGEBOSS
-- Send message. -- Send message.
self:_DisplayMessageToGroup( _unit, _msg, 10, true ) self:_DisplayMessageToGroup( _unit, _msg, 10, true )
hypemanStrafeRollIn = _msg --RANGEBOSS
-- Trigger event that player is rolling in.
self:RollingIn(playerData, target)
-- We found our player. Skip remaining checks. -- We found our player. Skip remaining checks.
break break
@ -3232,7 +3263,6 @@ function RANGE:_GetBombTargetCoordinate(target)
return coord return coord
end end
--- Get the number of shells a unit currently has. --- Get the number of shells a unit currently has.
-- @param #RANGE self -- @param #RANGE self
-- @param #string unitname Name of the player unit. -- @param #string unitname Name of the player unit.
@ -3531,7 +3561,7 @@ function RANGE:_TargetsheetOnOff(_unitname)
playerData.targeton = not playerData.targeton playerData.targeton = not playerData.targeton
-- Inform player. -- Inform player.
if playerData.targeton==true then if playerData and playerData.targeton == true then
text = string.format( "roger, your targetsheets are now SAVED." ) text = string.format( "roger, your targetsheets are now SAVED." )
else else
text = string.format( "affirm, your targetsheets are NOT SAVED." ) text = string.format( "affirm, your targetsheets are NOT SAVED." )
@ -3801,7 +3831,7 @@ function RANGE:_GetPlayerUnitAndName(_unitName)
return nil, nil return nil, nil
end end
--- Returns a string which consits of this callsign and the player name. --- Returns a string which consists of the player name.
-- @param #RANGE self -- @param #RANGE self
-- @param #string unitname Name of the player unit. -- @param #string unitname Name of the player unit.
function RANGE:_myname( unitname ) function RANGE:_myname( unitname )
@ -3809,7 +3839,7 @@ function RANGE:_myname(unitname)
local unit = UNIT:FindByName( unitname ) local unit = UNIT:FindByName( unitname )
local pname = unit:GetPlayerName() local pname = unit:GetPlayerName()
local csign=unit:GetCallsign() -- local csign = unit:GetCallsign()
-- return string.format("%s (%s)", csign, pname) -- return string.format("%s (%s)", csign, pname)
return string.format( "%s", pname ) return string.format( "%s", pname )