diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 53b5ebba8..6b4a3bc14 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -19,17 +19,17 @@ -- * Bomb, rocket and missile impact points can be marked by smoke. -- * Direct hits on targets can trigger flares. -- * 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. -- * Range control voice overs (>40) for hit assessment. -- -- === -- -- ## Youtube Videos: - -- +-- -- * [MOOSE YouTube Channel](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg) -- * [MOOSE - On the Range - Demonstration Video](https://www.youtube.com/watch?v=kIXcxNB9_3M) --- +-- -- === -- -- ## Missions: @@ -50,11 +50,10 @@ -- @module Functional.Range -- @image Range.JPG -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- RANGE class -- @type RANGE -- @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 #string id String id of range for output in DCS log. -- @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 #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 #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 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 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 illuminationmaxalt Maximum altitude AGL in meters at which illumination bombs are fired. Default is 1000 m. +-- @field #number illuminationminalt Minimum altitude in meters AGL at which illumination bombs are fired. Default is 500 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 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. @@ -105,7 +104,7 @@ -- @extends Core.Fsm#FSM --- *Don't only practice your art, but force your way into its secrets; art deserves that, for it and knowledge can raise man to the Divine.* - Ludwig van Beethoven --- +-- -- === -- -- ![Banner Image](..\Presentations\RANGE\RANGE_Main.png) @@ -129,17 +128,17 @@ -- there should be an "On the Range" menu items in the "F10. Other..." menu. -- -- # Strafe Pits --- +-- -- 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. -- --- * 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 --- of the strafe targets. The parameters *boxlength* and *boxwidth* define the size of the box while the parameter *heading* defines its direction. --- 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 --- wrong/opposite 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. +-- 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. +-- 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. +-- * 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 last parameter *foulline* sets the distance from the pit targets to the foul line. Hit from closer than this line are not counted! -- @@ -150,27 +149,26 @@ -- strafing pits of the range and can be adjusted by the @{#RANGE.SetMaxStrafeAlt}(maxalt) function. -- -- # Bombing targets --- +-- -- 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. --- 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 around the target. If a bomb or rocket falls at a distance smaller than this number, the hit is considered to be "good". +-- * The first parameter *targetnames* defines the target or targets. This can be a single item or a Table with the name(s) of @{Wrapper.Unit} or @{Static} objects defined in the mission editor. +-- * The (optional) parameter *goodhitrange* specifies the radius in metres around the target within which a bomb/rocket hit is considered to be "good". -- * If final (optional) parameter "*randommove*" can be enabled to create moving targets. If this parameter is set to true, the units of this bombing target will randomly move within the range zone. -- Note that there might be quirks since DCS units can get stuck in buildings etc. So it might be safer to manually define a route for the units in the mission editor if moving targets are desired. -- -- ## Adding Groups --- +-- -- Another possibility to add bombing targets is the @{#RANGE.AddBombingTargetGroup}(*group, goodhitrange, randommove*) function. Here the parameter *group* is a MOOSE @{Wrapper.Group} object -- and **all** units in this group are defined as bombing targets. --- +-- -- ## Specifying Coordinates --- +-- -- It is also possible to specify coordinates rather than unit or static objects as bombing target locations. This has the advantage, that even when the unit/static object is dead, the specified -- coordinate will still be a valid impact point. This can be done via the @{#RANGE.AddBombingTargetCoordinate}(*coord*, *name*, *goodhitrange*) function. -- -- # Fine Tuning --- +-- -- Many range parameters have good default values. However, the mission designer can change these settings easily with the supplied user functions: -- -- * @{#RANGE.SetMaxStrafeAlt}() sets the max altitude for valid strafing runs. @@ -186,60 +184,70 @@ -- * @{#RANGE.TrackMissilesON}() or @{#RANGE.TrackMissilesOFF}() can be used to enable/disable tracking and evaluating of all missile types a player fires. -- -- # Radio Menu --- +-- -- Each range gets a radio menu with various submenus where each player can adjust his individual settings or request information about the range or his scores. -- -- The main range menu can be found at "F10. Other..." --> "F*X*. On the Range..." --> "F1. ...". -- --- The range menu contains the following submenues: --- +-- The range menu contains the following submenus: +-- -- ![Banner Image](..\Presentations\RANGE\Menu_Main.png) -- -- * "F1. Statistics...": Range results of all players and personal stats. -- * "F2. Mark Targets": Mark range targets by smoke or flares. -- * "F3. My Settings" Personal settings. -- * "F4. Range Info": Information about the range, such as bearing and range. --- +-- -- ## F1 Statistics --- +-- -- ![Banner Image](..\Presentations\RANGE\Menu_Stats.png) --- +-- -- ## F2 Mark Targets --- +-- -- ![Banner Image](..\Presentations\RANGE\Menu_Stats.png) --- +-- -- ## F3 My Settings --- +-- -- ![Banner Image](..\Presentations\RANGE\Menu_MySettings.png) --- +-- -- ## F4 Range Info --- +-- -- ![Banner Image](..\Presentations\RANGE\Menu_RangeInfo.png) --- +-- -- # Voice Overs --- +-- -- Voice over sound files can be downloaded from the Moose Discord. Check the pinned messages in the *#func-range* channel. --- +-- -- Instructor radio will inform players when they enter or exit the range zone and provide the radio frequency of the range control for hit assessment. -- This can be enabled via the @{#RANGE.SetInstructorRadio}(*frequency*) functions, where *frequency* is the AM frequency in MHz. --- +-- -- The range control can be enabled via the @{#RANGE.SetRangeControl}(*frequency*) functions, where *frequency* is the AM frequency in MHz. --- +-- -- By default, the sound files are placed in the "Range Soundfiles/" folder inside the mission (.miz) file. Another folder can be specified via the @{#RANGE.SetSoundfilesPath}(*path*) function. --- +-- -- # Persistence --- +-- -- To automatically save bombing results to disk, use the @{#RANGE.SetAutosave}() function. Bombing results will be saved as csv file in your "Saved Games\DCS.openbeta\Logs" directory. -- Each range has a separate file, which is named "RANGE-<*RangeName*>_BombingResults.csv". --- +-- -- The next time you start the mission, these results are also automatically loaded. --- +-- -- 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 -- -- ## Goldwater Range --- +-- -- This example shows hot to set up the [Barry M. Goldwater range](https://en.wikipedia.org/wiki/Barry_M._Goldwater_Air_Force_Range). -- It consists of two strafe pits each has two targets plus three bombing targets. -- @@ -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. -- GoldwaterRange:GetFoullineDistance("GWR Strafe Pit Left 1", "GWR Foul Line Left") -- --- -- Add strafe pits. Each pit (left and right) consists of two targets. --- GoldwaterRange:AddStrafePit(strafepit_left, 3000, 300, nil, true, 20, fouldist) --- GoldwaterRange:AddStrafePit(strafepit_right, nil, nil, nil, true, nil, fouldist) +-- -- 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, 30, 500) +-- 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. -- GoldwaterRange:AddBombingTargets(bombtargets, 50) @@ -290,74 +298,71 @@ -- 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. -- --- --- -- @field #RANGE -RANGE={ - ClassName = "RANGE", - Debug = false, - verbose = 0, - id = nil, - rangename = nil, - location = nil, - messages = true, - rangeradius = 5000, - rangezone = nil, - strafeTargets = {}, - bombingTargets = {}, - nbombtargets = 0, - nstrafetargets = 0, - MenuAddedTo = {}, - planes = {}, - strafeStatus = {}, +RANGE = { + ClassName = "RANGE", + Debug = false, + verbose = 0, + id = nil, + rangename = nil, + location = nil, + messages = true, + rangeradius = 5000, + rangezone = nil, + strafeTargets = {}, + bombingTargets = {}, + nbombtargets = 0, + nstrafetargets = 0, + MenuAddedTo = {}, + planes = {}, + strafeStatus = {}, strafePlayerResults = {}, - bombPlayerResults = {}, - PlayerSettings = {}, - dtBombtrack = 0.005, - BombtrackThreshold = 25000, - Tmsg = 30, - examinergroupname = nil, - examinerexclusive = nil, - strafemaxalt = 914, - ndisplayresult = 10, - BombSmokeColor = SMOKECOLOR.Red, - StrafeSmokeColor = SMOKECOLOR.Green, + bombPlayerResults = {}, + PlayerSettings = {}, + dtBombtrack = 0.005, + BombtrackThreshold = 25000, + Tmsg = 30, + examinergroupname = nil, + examinerexclusive = nil, + strafemaxalt = 914, + ndisplayresult = 10, + BombSmokeColor = SMOKECOLOR.Red, + StrafeSmokeColor = SMOKECOLOR.Green, StrafePitSmokeColor = SMOKECOLOR.White, - illuminationminalt = 500, - illuminationmaxalt = 1000, - scorebombdistance = 1000, - TdelaySmoke = 3.0, - eventmoose = true, - trackbombs = true, - trackrockets = true, - trackmissiles = true, - defaultsmokebomb = true, - autosave = false, - instructorfreq = nil, - instructor = nil, - rangecontrolfreq = nil, - rangecontrol = nil, - soundpath = "Range Soundfiles/", - targetsheet = nil, - targetpath = nil, - targetprefix = nil, + illuminationminalt = 500, + illuminationmaxalt = 1000, + scorebombdistance = 1000, + TdelaySmoke = 3.0, + eventmoose = true, + trackbombs = true, + trackrockets = true, + trackmissiles = true, + defaultsmokebomb = true, + autosave = false, + instructorfreq = nil, + instructor = nil, + rangecontrolfreq = nil, + rangecontrol = nil, + soundpath = "Range Soundfiles/", + targetsheet = nil, + targetpath = nil, + targetprefix = nil, } --- Default range parameters. -- @list Defaults -RANGE.Defaults={ - goodhitrange=25, - strafemaxalt=914, - dtBombtrack=0.005, - Tmsg=30, - ndisplayresult=10, - rangeradius=5000, - TdelaySmoke=3.0, - boxlength=3000, - boxwidth=300, - goodpass=20, - goodhitrange=25, - foulline=610, +RANGE.Defaults = { + goodhitrange = 25, + strafemaxalt = 914, + dtBombtrack = 0.005, + Tmsg = 30, + ndisplayresult = 10, + rangeradius = 5000, + TdelaySmoke = 3.0, + boxlength = 3000, + boxwidth = 300, + goodpass = 20, + foulline = 610 } --- Target type, i.e. unit, static, or coordinate. @@ -365,19 +370,12 @@ RANGE.Defaults={ -- @field #string UNIT Target is a unit. -- @field #string STATIC Target is a static. -- @field #string COORD Target is a coordinate. -RANGE.TargetType={ - UNIT="Unit", - STATIC="Static", - COORD="Coordinate", +RANGE.TargetType = { + UNIT = "Unit", + STATIC = "Static", + COORD = "Coordinate" } ---- Default range variables for RangeBoss/Hypeman tie in. -hypemanStrafeRollIn = "nil" -StrafeAircraftType = "strafeAircraftTypeNotSet" -Straferesult={} -clientRollingIn = false -clientStrafed = false -invalidStrafe = false --- Player settings. -- @type RANGE.PlayerData -- @field #boolean smokebombimpact Smoke bomb impact points. @@ -412,6 +410,14 @@ invalidStrafe = false -- @field #number smokepoints Number of smoke points. -- @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. -- @type RANGE.BombResult -- @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 #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. -- @type RANGE.Soundfile -- @field #string filename Name of the file @@ -476,81 +489,81 @@ invalidStrafe = false -- @field #RANGE.Soundfile IREnterRange -- @field #RANGE.Soundfile IRExitRange RANGE.Sound = { - RC0={filename="RC-0.ogg", duration=0.60}, - RC1={filename="RC-1.ogg", duration=0.47}, - RC2={filename="RC-2.ogg", duration=0.43}, - RC3={filename="RC-3.ogg", duration=0.50}, - RC4={filename="RC-4.ogg", duration=0.58}, - RC5={filename="RC-5.ogg", duration=0.54}, - RC6={filename="RC-6.ogg", duration=0.61}, - RC7={filename="RC-7.ogg", duration=0.53}, - RC8={filename="RC-8.ogg", duration=0.34}, - RC9={filename="RC-9.ogg", duration=0.54}, - RCAccuracy={filename="RC-Accuracy.ogg", duration=0.67}, - RCDegrees={filename="RC-Degrees.ogg", duration=0.59}, - RCExcellentHit={filename="RC-ExcellentHit.ogg", duration=0.76}, - RCExcellentPass={filename="RC-ExcellentPass.ogg", duration=0.89}, - RCFeet={filename="RC-Feet.ogg", duration=0.49}, - RCFor={filename="RC-For.ogg", duration=0.64}, - RCGoodHit={filename="RC-GoodHit.ogg", duration=0.52}, - RCGoodPass={filename="RC-GoodPass.ogg", duration=0.62}, - RCHitsOnTarget={filename="RC-HitsOnTarget.ogg", duration=0.88}, - RCImpact={filename="RC-Impact.ogg", duration=0.61}, - RCIneffectiveHit={filename="RC-IneffectiveHit.ogg", duration=0.86}, - RCIneffectivePass={filename="RC-IneffectivePass.ogg", duration=0.99}, - RCInvalidHit={filename="RC-InvalidHit.ogg", duration=2.97}, - RCLeftStrafePitTooQuickly={filename="RC-LeftStrafePitTooQuickly.ogg", duration=3.09}, - RCPercent={filename="RC-Percent.ogg", duration=0.56}, - RCPoorHit={filename="RC-PoorHit.ogg", duration=0.54}, - RCPoorPass={filename="RC-PoorPass.ogg", duration=0.68}, - RCRollingInOnStrafeTarget={filename="RC-RollingInOnStrafeTarget.ogg", duration=1.38}, - RCTotalRoundsFired={filename="RC-TotalRoundsFired.ogg", duration=1.22}, - RCWeaponImpactedTooFar={filename="RC-WeaponImpactedTooFar.ogg", duration=3.73}, - IR0={filename="IR-0.ogg", duration=0.55}, - IR1={filename="IR-1.ogg", duration=0.41}, - IR2={filename="IR-2.ogg", duration=0.37}, - IR3={filename="IR-3.ogg", duration=0.41}, - IR4={filename="IR-4.ogg", duration=0.37}, - IR5={filename="IR-5.ogg", duration=0.43}, - IR6={filename="IR-6.ogg", duration=0.55}, - IR7={filename="IR-7.ogg", duration=0.43}, - IR8={filename="IR-8.ogg", duration=0.38}, - IR9={filename="IR-9.ogg", duration=0.55}, - IRDecimal={filename="IR-Decimal.ogg", duration=0.54}, - IRMegaHertz={filename="IR-MegaHertz.ogg", duration=0.87}, - IREnterRange={filename="IR-EnterRange.ogg", duration=4.83}, - IRExitRange={filename="IR-ExitRange.ogg", duration=3.10}, + RC0 = { filename = "RC-0.ogg", duration = 0.60 }, + RC1 = { filename = "RC-1.ogg", duration = 0.47 }, + RC2 = { filename = "RC-2.ogg", duration = 0.43 }, + RC3 = { filename = "RC-3.ogg", duration = 0.50 }, + RC4 = { filename = "RC-4.ogg", duration = 0.58 }, + RC5 = { filename = "RC-5.ogg", duration = 0.54 }, + RC6 = { filename = "RC-6.ogg", duration = 0.61 }, + RC7 = { filename = "RC-7.ogg", duration = 0.53 }, + RC8 = { filename = "RC-8.ogg", duration = 0.34 }, + RC9 = { filename = "RC-9.ogg", duration = 0.54 }, + RCAccuracy = { filename = "RC-Accuracy.ogg", duration = 0.67 }, + RCDegrees = { filename = "RC-Degrees.ogg", duration = 0.59 }, + RCExcellentHit = { filename = "RC-ExcellentHit.ogg", duration = 0.76 }, + RCExcellentPass = { filename = "RC-ExcellentPass.ogg", duration = 0.89 }, + RCFeet = { filename = "RC-Feet.ogg", duration = 0.49 }, + RCFor = { filename = "RC-For.ogg", duration = 0.64 }, + RCGoodHit = { filename = "RC-GoodHit.ogg", duration = 0.52 }, + RCGoodPass = { filename = "RC-GoodPass.ogg", duration = 0.62 }, + RCHitsOnTarget = { filename = "RC-HitsOnTarget.ogg", duration = 0.88 }, + RCImpact = { filename = "RC-Impact.ogg", duration = 0.61 }, + RCIneffectiveHit = { filename = "RC-IneffectiveHit.ogg", duration = 0.86 }, + RCIneffectivePass = { filename = "RC-IneffectivePass.ogg", duration = 0.99 }, + RCInvalidHit = { filename = "RC-InvalidHit.ogg", duration = 2.97 }, + RCLeftStrafePitTooQuickly = { filename = "RC-LeftStrafePitTooQuickly.ogg", duration = 3.09 }, + RCPercent = { filename = "RC-Percent.ogg", duration = 0.56 }, + RCPoorHit = { filename = "RC-PoorHit.ogg", duration = 0.54 }, + RCPoorPass = { filename = "RC-PoorPass.ogg", duration = 0.68 }, + RCRollingInOnStrafeTarget = { filename = "RC-RollingInOnStrafeTarget.ogg", duration = 1.38 }, + RCTotalRoundsFired = { filename = "RC-TotalRoundsFired.ogg", duration = 1.22 }, + RCWeaponImpactedTooFar = { filename = "RC-WeaponImpactedTooFar.ogg", duration = 3.73 }, + IR0 = { filename = "IR-0.ogg", duration = 0.55 }, + IR1 = { filename = "IR-1.ogg", duration = 0.41 }, + IR2 = { filename = "IR-2.ogg", duration = 0.37 }, + IR3 = { filename = "IR-3.ogg", duration = 0.41 }, + IR4 = { filename = "IR-4.ogg", duration = 0.37 }, + IR5 = { filename = "IR-5.ogg", duration = 0.43 }, + IR6 = { filename = "IR-6.ogg", duration = 0.55 }, + IR7 = { filename = "IR-7.ogg", duration = 0.43 }, + IR8 = { filename = "IR-8.ogg", duration = 0.38 }, + IR9 = { filename = "IR-9.ogg", duration = 0.55 }, + IRDecimal = { filename = "IR-Decimal.ogg", duration = 0.54 }, + IRMegaHertz = { filename = "IR-MegaHertz.ogg", duration = 0.87 }, + IREnterRange = { filename = "IR-EnterRange.ogg", duration = 4.83 }, + IRExitRange = { filename = "IR-ExitRange.ogg", duration = 3.10 }, } --- Global list of all defined range names. -- @field #table Names -RANGE.Names={} +RANGE.Names = {} --- Main radio menu on group level. -- @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 +RANGE.MenuF10Root = nil --- Range script version. -- @field #string version -RANGE.version="2.3.0" +RANGE.version = "2.4.0" ---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: Check if units are still alive. ---DONE: Add statics for strafe pits. ---DONE: Add missiles. ---DONE: Convert env.info() to self:T() ---DONE: Add user functions. ---DONE: Rename private functions, i.e. start with _functionname. ---DONE: number of displayed results variable. ---DONE: Add tire option for strafe pits. ==> No really feasible since tires are very small and cannot be seen. ---DONE: Check that menu texts are short enough to be correctly displayed in VR. +-- 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: Check if units are still alive. +-- DONE: Add statics for strafe pits. +-- DONE: Add missiles. +-- DONE: Convert env.info() to self:T() +-- DONE: Add user functions. +-- DONE: Rename private functions, i.e. start with _functionname. +-- DONE: number of displayed results variable. +-- DONE: Add tire option for strafe pits. ==> No really feasible since tires are very small and cannot be seen. +-- DONE: Check that menu texts are short enough to be correctly displayed in VR. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -558,28 +571,28 @@ RANGE.version="2.3.0" -- @param #RANGE self -- @param #string rangename Name of the range. Has to be unique. Will we used to create F10 menu items etc. -- @return #RANGE RANGE object. -function RANGE:New(rangename) - BASE:F({rangename=rangename}) +function RANGE:New( rangename ) + BASE:F( { rangename = rangename } ) -- Inherit BASE. - local self=BASE:Inherit(self, FSM:New()) -- #RANGE + local self = BASE:Inherit( self, FSM:New() ) -- #RANGE -- Get range name. - --TODO: make sure that the range name is not given twice. This would lead to problems in the F10 radio menu. - self.rangename=rangename or "Practice Range" + -- TODO: make sure that the range name is not given twice. This would lead to problems in the F10 radio menu. + self.rangename = rangename or "Practice Range" -- Log id. - self.id=string.format("RANGE %s | ", self.rangename) + self.id = string.format( "RANGE %s | ", self.rangename ) -- Debug info. - local text=string.format("Script version %s - creating new RANGE object %s.", RANGE.version, self.rangename) - self:I(self.id..text) + local text = string.format( "Script version %s - creating new RANGE object %s.", RANGE.version, self.rangename ) + self:I( self.id .. text ) -- Defaults self:SetDefaultPlayerSmokeBomb() -- Start State. - self:SetStartState("Stopped") + self:SetStartState( "Stopped" ) --- -- Add FSM transitions. @@ -587,6 +600,8 @@ function RANGE:New(rangename) self:AddTransition("Stopped", "Start", "Running") -- Start RANGE script. self:AddTransition("*", "Status", "*") -- Status of RANGE script. 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("*", "ExitRange", "*") -- Player leaves the range. 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.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". -- @function [parent=#RANGE] EnterRange -- @param #RANGE self @@ -694,136 +740,136 @@ end function RANGE:onafterStart() -- Location/coordinate of range. - local _location=nil + local _location = nil -- Count bomb targets. - local _count=0 - for _,_target in pairs(self.bombingTargets) do - _count=_count+1 + local _count = 0 + for _, _target in pairs( self.bombingTargets ) do + _count = _count + 1 -- Get range location. - if _location==nil then - _location=self:_GetBombTargetCoordinate(_target) + if _location == nil then + _location = self:_GetBombTargetCoordinate( _target ) end end - self.nbombtargets=_count + self.nbombtargets = _count -- Count strafing targets. - _count=0 - for _,_target in pairs(self.strafeTargets) do - _count=_count+1 + _count = 0 + for _, _target in pairs( self.strafeTargets ) do + _count = _count + 1 - for _,_unit in pairs(_target.targets) do - if _location==nil then - _location=_unit:GetCoordinate() + for _, _unit in pairs( _target.targets ) do + if _location == nil then + _location = _unit:GetCoordinate() end end end - self.nstrafetargets=_count + self.nstrafetargets = _count -- Location of the range. We simply take the first unit/target we find if it was not explicitly specified by the user. - if self.location==nil then - self.location=_location + if self.location == nil then + self.location = _location end - if self.location==nil then - local text=string.format("ERROR! No range location found. Number of strafe targets = %d. Number of bomb targets = %d.", self.nstrafetargets, self.nbombtargets) - self:E(self.id..text) + if self.location == nil then + local text = string.format( "ERROR! No range location found. Number of strafe targets = %d. Number of bomb targets = %d.", self.nstrafetargets, self.nbombtargets ) + self:E( self.id .. text ) return end -- Define a MOOSE zone of the range. - if self.rangezone==nil then - self.rangezone=ZONE_RADIUS:New(self.rangename, {x=self.location.x, y=self.location.z}, self.rangeradius) + if self.rangezone == nil then + self.rangezone = ZONE_RADIUS:New( self.rangename, { x = self.location.x, y = self.location.z }, self.rangeradius ) end -- 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) - self:I(self.id..text) + local text = string.format( "Starting RANGE %s. Number of strafe targets = %d. Number of bomb targets = %d.", self.rangename, self.nstrafetargets, self.nbombtargets ) + self:I( self.id .. text ) -- Event handling. if self.eventmoose then -- Events are handled my MOOSE. - self:T(self.id.."Events are handled by MOOSE.") - self:HandleEvent(EVENTS.Birth) - self:HandleEvent(EVENTS.Hit) - self:HandleEvent(EVENTS.Shot) + self:T( self.id .. "Events are handled by MOOSE." ) + self:HandleEvent( EVENTS.Birth ) + self:HandleEvent( EVENTS.Hit ) + self:HandleEvent( EVENTS.Shot ) else -- Events are handled directly by DCS. - self:T(self.id.."Events are handled directly by DCS.") - world.addEventHandler(self) + self:T( self.id .. "Events are handled directly by DCS." ) + world.addEventHandler( self ) end -- Make bomb target move randomly within the range zone. - for _,_target in pairs(self.bombingTargets) do + for _, _target in pairs( self.bombingTargets ) do -- Check if it is a static object. - --local _static=self:_CheckStatic(_target.target:GetName()) - local _static=_target.type==RANGE.TargetType.STATIC + -- local _static=self:_CheckStatic(_target.target:GetName()) + local _static = _target.type == RANGE.TargetType.STATIC - if _target.move and _static==false and _target.speed>1 then - local unit=_target.target --Wrapper.Unit#UNIT - _target.target:PatrolZones({self.rangezone}, _target.speed*0.75, "Off road") + if _target.move and _static == false and _target.speed > 1 then + local unit = _target.target -- Wrapper.Unit#UNIT + _target.target:PatrolZones( { self.rangezone }, _target.speed * 0.75, "Off road" ) end end - + -- Init range control. if self.rangecontrolfreq then - + -- Radio queue. - self.rangecontrol=RADIOQUEUE:New(self.rangecontrolfreq, nil, self.rangename) - self.rangecontrol.schedonce=true - + self.rangecontrol = RADIOQUEUE:New( self.rangecontrolfreq, nil, self.rangename ) + self.rangecontrol.schedonce = true + -- Init numbers. - self.rangecontrol:SetDigit(0, RANGE.Sound.RC0.filename, RANGE.Sound.RC0.duration, self.soundpath) - self.rangecontrol:SetDigit(1, RANGE.Sound.RC1.filename, RANGE.Sound.RC1.duration, self.soundpath) - self.rangecontrol:SetDigit(2, RANGE.Sound.RC2.filename, RANGE.Sound.RC2.duration, self.soundpath) - self.rangecontrol:SetDigit(3, RANGE.Sound.RC3.filename, RANGE.Sound.RC3.duration, self.soundpath) - self.rangecontrol:SetDigit(4, RANGE.Sound.RC4.filename, RANGE.Sound.RC4.duration, self.soundpath) - self.rangecontrol:SetDigit(5, RANGE.Sound.RC5.filename, RANGE.Sound.RC5.duration, self.soundpath) - self.rangecontrol:SetDigit(6, RANGE.Sound.RC6.filename, RANGE.Sound.RC6.duration, self.soundpath) - self.rangecontrol:SetDigit(7, RANGE.Sound.RC7.filename, RANGE.Sound.RC7.duration, self.soundpath) - self.rangecontrol:SetDigit(8, RANGE.Sound.RC8.filename, RANGE.Sound.RC8.duration, self.soundpath) - self.rangecontrol:SetDigit(9, RANGE.Sound.RC9.filename, RANGE.Sound.RC9.duration, self.soundpath) - + self.rangecontrol:SetDigit( 0, RANGE.Sound.RC0.filename, RANGE.Sound.RC0.duration, self.soundpath ) + self.rangecontrol:SetDigit( 1, RANGE.Sound.RC1.filename, RANGE.Sound.RC1.duration, self.soundpath ) + self.rangecontrol:SetDigit( 2, RANGE.Sound.RC2.filename, RANGE.Sound.RC2.duration, self.soundpath ) + self.rangecontrol:SetDigit( 3, RANGE.Sound.RC3.filename, RANGE.Sound.RC3.duration, self.soundpath ) + self.rangecontrol:SetDigit( 4, RANGE.Sound.RC4.filename, RANGE.Sound.RC4.duration, self.soundpath ) + self.rangecontrol:SetDigit( 5, RANGE.Sound.RC5.filename, RANGE.Sound.RC5.duration, self.soundpath ) + self.rangecontrol:SetDigit( 6, RANGE.Sound.RC6.filename, RANGE.Sound.RC6.duration, self.soundpath ) + self.rangecontrol:SetDigit( 7, RANGE.Sound.RC7.filename, RANGE.Sound.RC7.duration, self.soundpath ) + self.rangecontrol:SetDigit( 8, RANGE.Sound.RC8.filename, RANGE.Sound.RC8.duration, self.soundpath ) + self.rangecontrol:SetDigit( 9, RANGE.Sound.RC9.filename, RANGE.Sound.RC9.duration, self.soundpath ) + -- Set location where the messages are transmitted from. - self.rangecontrol:SetSenderCoordinate(self.location) - self.rangecontrol:SetSenderUnitName(self.rangecontrolrelayname) - + self.rangecontrol:SetSenderCoordinate( self.location ) + self.rangecontrol:SetSenderUnitName( self.rangecontrolrelayname ) + -- Start range control radio queue. - self.rangecontrol:Start(1, 0.1) + self.rangecontrol:Start( 1, 0.1 ) -- Init range control. if self.instructorfreq then - + -- Radio queue. - self.instructor=RADIOQUEUE:New(self.instructorfreq, nil, self.rangename) - self.instructor.schedonce=true - + self.instructor = RADIOQUEUE:New( self.instructorfreq, nil, self.rangename ) + self.instructor.schedonce = true + -- Init numbers. - self.instructor:SetDigit(0, RANGE.Sound.IR0.filename, RANGE.Sound.IR0.duration, self.soundpath) - self.instructor:SetDigit(1, RANGE.Sound.IR1.filename, RANGE.Sound.IR1.duration, self.soundpath) - self.instructor:SetDigit(2, RANGE.Sound.IR2.filename, RANGE.Sound.IR2.duration, self.soundpath) - self.instructor:SetDigit(3, RANGE.Sound.IR3.filename, RANGE.Sound.IR3.duration, self.soundpath) - self.instructor:SetDigit(4, RANGE.Sound.IR4.filename, RANGE.Sound.IR4.duration, self.soundpath) - self.instructor:SetDigit(5, RANGE.Sound.IR5.filename, RANGE.Sound.IR5.duration, self.soundpath) - self.instructor:SetDigit(6, RANGE.Sound.IR6.filename, RANGE.Sound.IR6.duration, self.soundpath) - self.instructor:SetDigit(7, RANGE.Sound.IR7.filename, RANGE.Sound.IR7.duration, self.soundpath) - self.instructor:SetDigit(8, RANGE.Sound.IR8.filename, RANGE.Sound.IR8.duration, self.soundpath) - self.instructor:SetDigit(9, RANGE.Sound.IR9.filename, RANGE.Sound.IR9.duration, self.soundpath) - + self.instructor:SetDigit( 0, RANGE.Sound.IR0.filename, RANGE.Sound.IR0.duration, self.soundpath ) + self.instructor:SetDigit( 1, RANGE.Sound.IR1.filename, RANGE.Sound.IR1.duration, self.soundpath ) + self.instructor:SetDigit( 2, RANGE.Sound.IR2.filename, RANGE.Sound.IR2.duration, self.soundpath ) + self.instructor:SetDigit( 3, RANGE.Sound.IR3.filename, RANGE.Sound.IR3.duration, self.soundpath ) + self.instructor:SetDigit( 4, RANGE.Sound.IR4.filename, RANGE.Sound.IR4.duration, self.soundpath ) + self.instructor:SetDigit( 5, RANGE.Sound.IR5.filename, RANGE.Sound.IR5.duration, self.soundpath ) + self.instructor:SetDigit( 6, RANGE.Sound.IR6.filename, RANGE.Sound.IR6.duration, self.soundpath ) + self.instructor:SetDigit( 7, RANGE.Sound.IR7.filename, RANGE.Sound.IR7.duration, self.soundpath ) + self.instructor:SetDigit( 8, RANGE.Sound.IR8.filename, RANGE.Sound.IR8.duration, self.soundpath ) + self.instructor:SetDigit( 9, RANGE.Sound.IR9.filename, RANGE.Sound.IR9.duration, self.soundpath ) + -- Set location where the messages are transmitted from. - self.instructor:SetSenderCoordinate(self.location) - self.instructor:SetSenderUnitName(self.instructorrelayname) - + self.instructor:SetSenderCoordinate( self.location ) + self.instructor:SetSenderUnitName( self.instructorrelayname ) + -- Start instructor radio queue. - self.instructor:Start(1, 0.1) - + self.instructor:Start( 1, 0.1 ) + end - + end - + -- Load prev results. if self.autosave then self:Load() @@ -835,10 +881,10 @@ function RANGE:onafterStart() self:_SmokeBombTargets() self:_SmokeStrafeTargets() self:_SmokeStrafeTargetBoxes() - self.rangezone:SmokeZone(SMOKECOLOR.White) + self.rangezone:SmokeZone( SMOKECOLOR.White ) end - self:__Status(-60) + self:__Status( -60 ) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -847,10 +893,10 @@ end --- Set maximal strafing altitude. Player entering a strafe pit above that altitude are not registered for a valid pass. -- @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 -function RANGE:SetMaxStrafeAlt(maxalt) - self.strafemaxalt=maxalt or RANGE.Defaults.strafemaxalt +function RANGE:SetMaxStrafeAlt( maxalt ) + self.strafemaxalt = maxalt or RANGE.Defaults.strafemaxalt return self end @@ -858,8 +904,8 @@ end -- @param #RANGE self -- @param #number dt Time interval in seconds. Default is 0.005 s. -- @return #RANGE self -function RANGE:SetBombtrackTimestep(dt) - self.dtBombtrack=dt or RANGE.Defaults.dtBombtrack +function RANGE:SetBombtrackTimestep( dt ) + self.dtBombtrack = dt or RANGE.Defaults.dtBombtrack return self end @@ -867,8 +913,8 @@ end -- @param #RANGE self -- @param #number time Time in seconds. Default is 30 s. -- @return #RANGE self -function RANGE:SetMessageTimeDuration(time) - self.Tmsg=time or RANGE.Defaults.Tmsg +function RANGE:SetMessageTimeDuration( time ) + self.Tmsg = time or RANGE.Defaults.Tmsg return self end @@ -876,7 +922,7 @@ end -- @param #RANGE self -- @return #RANGE self function RANGE:SetAutosaveOn() - self.autosave=true + self.autosave = true return self end @@ -884,7 +930,7 @@ end -- @param #RANGE self -- @return #RANGE self function RANGE:SetAutosaveOff() - self.autosave=false + self.autosave = false return self end @@ -893,13 +939,13 @@ end -- @param #string path (Optional) Path where to save the target sheets. -- @param #string prefix (Optional) Prefix for target sheet files. File name will be saved as *prefix_aircrafttype-0001.csv*, *prefix_aircrafttype-0002.csv*, etc. -- @return #RANGE self -function RANGE:SetTargetSheet(path, prefix) +function RANGE:SetTargetSheet( path, prefix ) if io then - self.targetsheet=true - self.targetpath=path - self.targetprefix=prefix + self.targetsheet = true + self.targetpath = path + self.targetprefix = prefix else - self:E(self.lid.."ERROR: io is not desanitized. Cannot save target sheet.") + self:E( self.lid .. "ERROR: io is not desanitized. Cannot save target sheet." ) end return self end @@ -909,9 +955,9 @@ end -- @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. -- @return #RANGE self -function RANGE:SetMessageToExaminer(examinergroupname, exclusively) - self.examinergroupname=examinergroupname - self.examinerexclusive=exclusively +function RANGE:SetMessageToExaminer( examinergroupname, exclusively ) + self.examinergroupname = examinergroupname + self.examinerexclusive = exclusively return self end @@ -919,8 +965,8 @@ end -- @param #RANGE self -- @param #number nmax Number of results. Default is 10. -- @return #RANGE self -function RANGE:SetDisplayedMaxPlayerResults(nmax) - self.ndisplayresult=nmax or RANGE.Defaults.ndisplayresult +function RANGE:SetDisplayedMaxPlayerResults( nmax ) + self.ndisplayresult = nmax or RANGE.Defaults.ndisplayresult return self end @@ -928,8 +974,8 @@ end -- @param #RANGE self -- @param #number radius Radius in km. Default 5 km. -- @return #RANGE self -function RANGE:SetRangeRadius(radius) - self.rangeradius=radius*1000 or RANGE.Defaults.rangeradius +function RANGE:SetRangeRadius( radius ) + self.rangeradius = radius * 1000 or RANGE.Defaults.rangeradius return self end @@ -937,11 +983,11 @@ end -- @param #RANGE self -- @param #boolean switch 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 +function RANGE:SetDefaultPlayerSmokeBomb( switch ) + if switch == true or switch == nil then + self.defaultsmokebomb = true else - self.defaultsmokebomb=false + self.defaultsmokebomb = false end return self end @@ -950,8 +996,8 @@ end -- @param #RANGE self -- @param #number distance Threshold distance in km. Default 25 km. -- @return #RANGE self -function RANGE:SetBombtrackThreshold(distance) - self.BombtrackThreshold=(distance or 25)*1000 +function RANGE:SetBombtrackThreshold( distance ) + self.BombtrackThreshold = (distance or 25) * 1000 return self end @@ -960,8 +1006,8 @@ end -- @param #RANGE self -- @param Core.Point#COORDINATE coordinate Coordinate of the range. -- @return #RANGE self -function RANGE:SetRangeLocation(coordinate) - self.location=coordinate +function RANGE:SetRangeLocation( coordinate ) + self.location = coordinate return self end @@ -970,8 +1016,8 @@ end -- @param #RANGE self -- @param Core.Zone#ZONE zone MOOSE zone defining the range perimeters. -- @return #RANGE self -function RANGE:SetRangeZone(zone) - self.rangezone=zone +function RANGE:SetRangeZone( zone ) + self.rangezone = zone return self end @@ -979,8 +1025,8 @@ end -- @param #RANGE self -- @param Utilities.Utils#SMOKECOLOR colorid Color id. Default SMOKECOLOR.Red. -- @return #RANGE self -function RANGE:SetBombTargetSmokeColor(colorid) - self.BombSmokeColor=colorid or SMOKECOLOR.Red +function RANGE:SetBombTargetSmokeColor( colorid ) + self.BombSmokeColor = colorid or SMOKECOLOR.Red return self end @@ -988,8 +1034,8 @@ end -- @param #RANGE self -- @param #number distance Distance in meters. Default 1000 m. -- @return #RANGE self -function RANGE:SetScoreBombDistance(distance) - self.scorebombdistance=distance or 1000 +function RANGE:SetScoreBombDistance( distance ) + self.scorebombdistance = distance or 1000 return self end @@ -997,8 +1043,8 @@ end -- @param #RANGE self -- @param Utilities.Utils#SMOKECOLOR colorid Color id. Default SMOKECOLOR.Green. -- @return #RANGE self -function RANGE:SetStrafeTargetSmokeColor(colorid) - self.StrafeSmokeColor=colorid or SMOKECOLOR.Green +function RANGE:SetStrafeTargetSmokeColor( colorid ) + self.StrafeSmokeColor = colorid or SMOKECOLOR.Green return self end @@ -1006,8 +1052,8 @@ end -- @param #RANGE self -- @param Utilities.Utils#SMOKECOLOR colorid Color id. Default SMOKECOLOR.White. -- @return #RANGE self -function RANGE:SetStrafePitSmokeColor(colorid) - self.StrafePitSmokeColor=colorid or SMOKECOLOR.White +function RANGE:SetStrafePitSmokeColor( colorid ) + self.StrafePitSmokeColor = colorid or SMOKECOLOR.White return self end @@ -1015,8 +1061,8 @@ end -- @param #RANGE self -- @param #number delay Time delay in seconds. Default is 3 seconds. -- @return #RANGE self -function RANGE:SetSmokeTimeDelay(delay) - self.TdelaySmoke=delay or RANGE.Defaults.TdelaySmoke +function RANGE:SetSmokeTimeDelay( delay ) + self.TdelaySmoke = delay or RANGE.Defaults.TdelaySmoke return self end @@ -1024,7 +1070,7 @@ end -- @param #RANGE self -- @return #RANGE self function RANGE:DebugON() - self.Debug=true + self.Debug = true return self end @@ -1032,7 +1078,7 @@ end -- @param #RANGE self -- @return #RANGE self function RANGE:DebugOFF() - self.Debug=false + self.Debug = false return self end @@ -1040,7 +1086,7 @@ end -- @param #RANGE self -- @return #RANGE self function RANGE:SetMessagesOFF() - self.messages=false + self.messages = false return self end @@ -1048,16 +1094,15 @@ end -- @param #RANGE self -- @return #RANGE self function RANGE:SetMessagesON() - self.messages=true + self.messages = true return self end - --- Enables tracking of all bomb types. Note that this is the default setting. -- @param #RANGE self -- @return #RANGE self function RANGE:TrackBombsON() - self.trackbombs=true + self.trackbombs = true return self end @@ -1065,7 +1110,7 @@ end -- @param #RANGE self -- @return #RANGE self function RANGE:TrackBombsOFF() - self.trackbombs=false + self.trackbombs = false return self end @@ -1073,7 +1118,7 @@ end -- @param #RANGE self -- @return #RANGE self function RANGE:TrackRocketsON() - self.trackrockets=true + self.trackrockets = true return self end @@ -1081,7 +1126,7 @@ end -- @param #RANGE self -- @return #RANGE self function RANGE:TrackRocketsOFF() - self.trackrockets=false + self.trackrockets = false return self end @@ -1089,7 +1134,7 @@ end -- @param #RANGE self -- @return #RANGE self function RANGE:TrackMissilesON() - self.trackmissiles=true + self.trackmissiles = true return self end @@ -1097,19 +1142,18 @@ end -- @param #RANGE self -- @return #RANGE self function RANGE:TrackMissilesOFF() - self.trackmissiles=false + self.trackmissiles = false return self end - --- Enable range control and set frequency. -- @param #RANGE self -- @param #number frequency Frequency in MHz. Default 256 MHz. -- @param #string relayunitname Name of the unit used for transmission. -- @return #RANGE self -function RANGE:SetRangeControl(frequency, relayunitname) - self.rangecontrolfreq=frequency or 256 - self.rangecontrolrelayname=relayunitname +function RANGE:SetRangeControl( frequency, relayunitname ) + self.rangecontrolfreq = frequency or 256 + self.rangecontrolrelayname = relayunitname return self end @@ -1118,163 +1162,162 @@ end -- @param #number frequency Frequency in MHz. Default 305 MHz. -- @param #string relayunitname Name of the unit used for transmission. -- @return #RANGE self -function RANGE:SetInstructorRadio(frequency, relayunitname) - self.instructorfreq=frequency or 305 - self.instructorrelayname=relayunitname +function RANGE:SetInstructorRadio( frequency, relayunitname ) + self.instructorfreq = frequency or 305 + self.instructorrelayname = relayunitname return self end --- Set sound files folder within miz file. -- @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 -function RANGE:SetSoundfilesPath(path) - self.soundpath=tostring(path or "Range Soundfiles/") - self:I(self.id..string.format("Setting sound files path to %s", self.soundpath)) +function RANGE:SetSoundfilesPath( path ) + self.soundpath = tostring( path or "Range Soundfiles/" ) + self:I( self.id .. string.format( "Setting sound files path to %s", self.soundpath ) ) return self end --- 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. -- @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 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 #boolean inverseheading (Optional) Take inverse heading (heading --> heading - 180 Degrees). Default is false. +-- @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) 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 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 -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}) +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 } ) -- Create table if necessary. - if type(targetnames) ~= "table" then - targetnames={targetnames} + if type( targetnames ) ~= "table" then + targetnames = { targetnames } end -- Make targets - local _targets={} - local center=nil --Wrapper.Unit#UNIT - local ntargets=0 + local _targets = {} + local center = nil -- Wrapper.Unit#UNIT + local ntargets = 0 - for _i,_name in ipairs(targetnames) do + for _i, _name in ipairs( targetnames ) do -- Check if we have a static or unit object. - local _isstatic=self:_CheckStatic(_name) + local _isstatic = self:_CheckStatic( _name ) - local unit=nil - if _isstatic==true then + local unit = nil + if _isstatic == true then -- Add static object. - self:T(self.id..string.format("Adding STATIC object %s as strafe target #%d.", _name, _i)) - unit=STATIC:FindByName(_name, false) + self:T( self.id .. string.format( "Adding STATIC object %s as strafe target #%d.", _name, _i ) ) + unit = STATIC:FindByName( _name, false ) - elseif _isstatic==false then + elseif _isstatic == false then -- Add unit object. - self:T(self.id..string.format("Adding UNIT object %s as strafe target #%d.", _name, _i)) - unit=UNIT:FindByName(_name) + self:T( self.id .. string.format( "Adding UNIT object %s as strafe target #%d.", _name, _i ) ) + unit = UNIT:FindByName( _name ) else -- Neither unit nor static object with this name could be found. - local text=string.format("ERROR! Could not find ANY strafe target object with name %s.", _name) - self:E(self.id..text) + local text = string.format( "ERROR! Could not find ANY strafe target object with name %s.", _name ) + self:E( self.id .. text ) end -- Add object to targets. if unit then - table.insert(_targets, unit) + table.insert( _targets, unit ) -- Define center as the first unit we find - if center==nil then - center=unit + if center == nil then + center = unit end - ntargets=ntargets+1 + ntargets = ntargets + 1 end end -- Check if at least one target could be found. - if ntargets==0 then - local text=string.format("ERROR! No strafe target could be found when calling RANGE:AddStrafePit() for range %s", self.rangename) - self:E(self.id..text) + if ntargets == 0 then + local text = string.format( "ERROR! No strafe target could be found when calling RANGE:AddStrafePit() for range %s", self.rangename ) + self:E( self.id .. text ) return end -- Approach box dimensions. - local l=boxlength or RANGE.Defaults.boxlength - local w=(boxwidth or RANGE.Defaults.boxwidth)/2 + local l = boxlength or RANGE.Defaults.boxlength + local w = (boxwidth or RANGE.Defaults.boxwidth) / 2 -- Heading: either manually entered or automatically taken from unit heading. - local heading=heading or center:GetHeading() + local heading = heading or center:GetHeading() -- Invert the heading since some units point in the "wrong" direction. In particular the strafe pit from 476th range objects. if inverseheading ~= nil then if inverseheading then - heading=heading-180 + heading = heading - 180 end end - if heading<0 then - heading=heading+360 + if heading < 0 then + heading = heading + 360 end - if heading>360 then - heading=heading-360 + if heading > 360 then + heading = heading - 360 end -- Number of hits called a "good" pass. - goodpass=goodpass or RANGE.Defaults.goodpass + goodpass = goodpass or RANGE.Defaults.goodpass -- Foule line distance. - foulline=foulline or RANGE.Defaults.foulline + foulline = foulline or RANGE.Defaults.foulline -- Coordinate of the range. - local Ccenter=center:GetCoordinate() + local Ccenter = center:GetCoordinate() -- Name of the target defined as its unit name. - local _name=center:GetName() + local _name = center:GetName() -- Points defining the approach area. - local p={} - p[#p+1]=Ccenter:Translate( w, heading+90) - p[#p+1]= p[#p]:Translate( l, heading) - p[#p+1]= p[#p]:Translate(2*w, heading-90) - p[#p+1]= p[#p]:Translate( -l, heading) + local p = {} + p[#p + 1] = Ccenter:Translate( w, heading + 90 ) + p[#p + 1] = p[#p]:Translate( l, heading ) + p[#p + 1] = p[#p]:Translate( 2 * w, heading - 90 ) + p[#p + 1] = p[#p]:Translate( -l, heading ) - local pv2={} - for i,p in ipairs(p) do - pv2[i]={x=p.x, y=p.z} + local pv2 = {} + for i, p in ipairs( p ) do + pv2[i] = { x = p.x, y = p.z } end -- Create polygon zone. - local _polygon=ZONE_POLYGON_BASE:New(_name, pv2) + local _polygon = ZONE_POLYGON_BASE:New( _name, pv2 ) -- Create tires - --_polygon:BoundZone() + -- _polygon:BoundZone() - local st={} --#RANGE.StrafeTarget - st.name=_name - st.polygon=_polygon - st.coordinate=Ccenter - st.goodPass=goodpass - st.targets=_targets - st.foulline=foulline - st.smokepoints=p - st.heading=heading + local st = {} -- #RANGE.StrafeTarget + st.name = _name + st.polygon = _polygon + st.coordinate = Ccenter + st.goodPass = goodpass + st.targets = _targets + st.foulline = foulline + st.smokepoints = p + st.heading = heading -- Add zone to table. - table.insert(self.strafeTargets, st) + table.insert( self.strafeTargets, st ) -- Debug info - 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(self.id..text) + 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( self.id .. text ) return self end - --- 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. -- Note, an approach is only valid, if the player enters via a zone in front of the pit, which defined by boxlength and boxheading. @@ -1288,29 +1331,29 @@ end -- @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. -- @return #RANGE self -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}) +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 } ) if group and group:IsAlive() then -- Get units of group. - local _units=group:GetUnits() + local _units = group:GetUnits() -- Make table of unit names. - local _names={} - for _,_unit in ipairs(_units) do + local _names = {} + for _, _unit in ipairs( _units ) do - local _unit=_unit --Wrapper.Unit#UNIT + local _unit = _unit -- Wrapper.Unit#UNIT if _unit and _unit:IsAlive() then - local _name=_unit:GetName() - table.insert(_names,_name) + local _name = _unit:GetName() + table.insert( _names, _name ) end end -- Add strafe pit. - self:AddStrafePit(_names, boxlength, boxwidth, heading, inverseheading, goodpass, foulline) + self:AddStrafePit( _names, boxlength, boxwidth, heading, inverseheading, goodpass, foulline ) end return self @@ -1318,36 +1361,36 @@ end --- Add bombing target(s) to range. -- @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 #boolean randommove If true, unit will move randomly within the range. Default is false. -- @return #RANGE self -function RANGE:AddBombingTargets(targetnames, goodhitrange, randommove) - self:F({targetnames=targetnames, goodhitrange=goodhitrange, randommove=randommove}) +function RANGE:AddBombingTargets( targetnames, goodhitrange, randommove ) + self:F( { targetnames = targetnames, goodhitrange = goodhitrange, randommove = randommove } ) -- Create a table if necessary. - if type(targetnames) ~= "table" then - targetnames={targetnames} + if type( targetnames ) ~= "table" then + targetnames = { targetnames } end -- Default range is 25 m. - goodhitrange=goodhitrange or RANGE.Defaults.goodhitrange + goodhitrange = goodhitrange or RANGE.Defaults.goodhitrange - for _,name in pairs(targetnames) do + for _, name in pairs( targetnames ) do -- Check if we have a static or unit object. - local _isstatic=self:_CheckStatic(name) + local _isstatic = self:_CheckStatic( name ) - if _isstatic==true then - local _static=STATIC:FindByName(name) - self:T2(self.id..string.format("Adding static bombing target %s with hit range %d.", name, goodhitrange, false)) - self:AddBombingTargetUnit(_static, goodhitrange) - elseif _isstatic==false then - local _unit=UNIT:FindByName(name) - self:T2(self.id..string.format("Adding unit bombing target %s with hit range %d.", name, goodhitrange, randommove)) - self:AddBombingTargetUnit(_unit, goodhitrange) + if _isstatic == true then + local _static = STATIC:FindByName( name ) + self:T2( self.id .. string.format( "Adding static bombing target %s with hit range %d.", name, goodhitrange, false ) ) + self:AddBombingTargetUnit( _static, goodhitrange ) + elseif _isstatic == false then + local _unit = UNIT:FindByName( name ) + self:T2( self.id .. string.format( "Adding unit bombing target %s with hit range %d.", name, goodhitrange, randommove ) ) + self:AddBombingTargetUnit( _unit, goodhitrange ) else - self:E(self.id..string.format("ERROR! Could not find bombing target %s.", name)) + self:E( self.id .. string.format( "ERROR! Could not find bombing target %s.", name ) ) end end @@ -1361,77 +1404,76 @@ end -- @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. -- @return #RANGE self -function RANGE:AddBombingTargetUnit(unit, goodhitrange, randommove) - self:F({unit=unit, goodhitrange=goodhitrange, randommove=randommove}) +function RANGE:AddBombingTargetUnit( unit, goodhitrange, randommove ) + self:F( { unit = unit, goodhitrange = goodhitrange, randommove = randommove } ) -- Get name of positionable. - local name=unit:GetName() + local name = unit:GetName() -- Check if we have a static or unit object. - local _isstatic=self:_CheckStatic(name) + local _isstatic = self:_CheckStatic( name ) -- Default range is 25 m. - goodhitrange=goodhitrange or RANGE.Defaults.goodhitrange + goodhitrange = goodhitrange or RANGE.Defaults.goodhitrange -- Set randommove to false if it was not specified. - if randommove==nil or _isstatic==true then - randommove=false + if randommove == nil or _isstatic == true then + randommove = false end -- Debug or error output. - if _isstatic==true then - self:I(self.id..string.format("Adding STATIC bombing target %s with good hit range %d. Random move = %s.", name, goodhitrange, tostring(randommove))) - elseif _isstatic==false then - self:I(self.id..string.format("Adding UNIT bombing target %s with good hit range %d. Random move = %s.", name, goodhitrange, tostring(randommove))) + if _isstatic == true then + self:I( self.id .. string.format( "Adding STATIC bombing target %s with good hit range %d. Random move = %s.", name, goodhitrange, tostring( randommove ) ) ) + elseif _isstatic == false then + self:I( self.id .. string.format( "Adding UNIT bombing target %s with good hit range %d. Random move = %s.", name, goodhitrange, tostring( randommove ) ) ) else - self:E(self.id..string.format("ERROR! No bombing target with name %s could be found. Carefully check all UNIT and STATIC names defined in the mission editor!", name)) + self:E( self.id .. string.format( "ERROR! No bombing target with name %s could be found. Carefully check all UNIT and STATIC names defined in the mission editor!", name ) ) end -- Get max speed of unit in km/h. - local speed=0 - if _isstatic==false then - speed=self:_GetSpeed(unit) + local speed = 0 + if _isstatic == false then + speed = self:_GetSpeed( unit ) end - local target={} --#RANGE.BombTarget - target.name=name - target.target=unit - target.goodhitrange=goodhitrange - target.move=randommove - target.speed=speed - target.coordinate=unit:GetCoordinate() + local target = {} -- #RANGE.BombTarget + target.name = name + target.target = unit + target.goodhitrange = goodhitrange + target.move = randommove + target.speed = speed + target.coordinate = unit:GetCoordinate() if _isstatic then - target.type=RANGE.TargetType.STATIC + target.type = RANGE.TargetType.STATIC else - target.type=RANGE.TargetType.UNIT + target.type = RANGE.TargetType.UNIT end -- Insert target to table. - table.insert(self.bombingTargets, target) + table.insert( self.bombingTargets, target ) return self end - --- Add a coordinate of a bombing target. This -- @param #RANGE self -- @param Core.Point#COORDINATE coord The coordinate. -- @param #string name Name of target. -- @param #number goodhitrange Max distance from unit which is considered as a good hit. -- @return #RANGE self -function RANGE:AddBombingTargetCoordinate(coord, name, goodhitrange) +function RANGE:AddBombingTargetCoordinate( coord, name, goodhitrange ) - local target={} --#RANGE.BombTarget - target.name=name or "Bomb Target" - target.target=nil - target.goodhitrange=goodhitrange or RANGE.Defaults.goodhitrange - target.move=false - target.speed=0 - target.coordinate=coord - target.type=RANGE.TargetType.COORD + local target = {} -- #RANGE.BombTarget + target.name = name or "Bomb Target" + target.target = nil + target.goodhitrange = goodhitrange or RANGE.Defaults.goodhitrange + target.move = false + target.speed = 0 + target.coordinate = coord + target.type = RANGE.TargetType.COORD -- Insert target to table. - table.insert(self.bombingTargets, target) + table.insert( self.bombingTargets, target ) return self end @@ -1442,16 +1484,16 @@ end -- @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. -- @return #RANGE self -function RANGE:AddBombingTargetGroup(group, goodhitrange, randommove) - self:F({group=group, goodhitrange=goodhitrange, randommove=randommove}) +function RANGE:AddBombingTargetGroup( group, goodhitrange, randommove ) + self:F( { group = group, goodhitrange = goodhitrange, randommove = randommove } ) if group then - local _units=group:GetUnits() + local _units = group:GetUnits() - for _,_unit in pairs(_units) do + for _, _unit in pairs( _units ) do if _unit and _unit:IsAlive() then - self:AddBombingTargetUnit(_unit, goodhitrange, randommove) + self:AddBombingTargetUnit( _unit, goodhitrange, randommove ) end end end @@ -1464,42 +1506,42 @@ end -- @param #string namepit Name of the strafe pit target object. -- @param #string namefoulline Name of the fould line distance marker object. -- @return #number Foul line distance in meters. -function RANGE:GetFoullineDistance(namepit, namefoulline) - self:F({namepit=namepit, namefoulline=namefoulline}) +function RANGE:GetFoullineDistance( namepit, namefoulline ) + self:F( { namepit = namepit, namefoulline = namefoulline } ) -- Check if we have units or statics. - local _staticpit=self:_CheckStatic(namepit) - local _staticfoul=self:_CheckStatic(namefoulline) + local _staticpit = self:_CheckStatic( namepit ) + local _staticfoul = self:_CheckStatic( namefoulline ) -- Get the unit or static pit object. - local pit=nil - if _staticpit==true then - pit=STATIC:FindByName(namepit, false) - elseif _staticpit==false then - pit=UNIT:FindByName(namepit) + local pit = nil + if _staticpit == true then + pit = STATIC:FindByName( namepit, false ) + elseif _staticpit == false then + pit = UNIT:FindByName( namepit ) else - self:E(self.id..string.format("ERROR! Pit object %s could not be found in GetFoullineDistance function. Check the name in the ME.", namepit)) + self:E( self.id .. string.format( "ERROR! Pit object %s could not be found in GetFoullineDistance function. Check the name in the ME.", namepit ) ) end -- Get the unit or static foul line object. - local foul=nil - if _staticfoul==true then - foul=STATIC:FindByName(namefoulline, false) - elseif _staticfoul==false then - foul=UNIT:FindByName(namefoulline) + local foul = nil + if _staticfoul == true then + foul = STATIC:FindByName( namefoulline, false ) + elseif _staticfoul == false then + foul = UNIT:FindByName( namefoulline ) else - self:E(self.id..string.format("ERROR! Foul line object %s could not be found in GetFoullineDistance function. Check the name in the ME.", namefoulline)) + self:E( self.id .. string.format( "ERROR! Foul line object %s could not be found in GetFoullineDistance function. Check the name in the ME.", namefoulline ) ) end -- Get the distance between the two objects. - local fouldist=0 - if pit~=nil and foul~=nil then - fouldist=pit:GetCoordinate():Get2DDistance(foul:GetCoordinate()) + local fouldist = 0 + if pit ~= nil and foul ~= nil then + fouldist = pit:GetCoordinate():Get2DDistance( foul:GetCoordinate() ) else - self:E(self.id..string.format("ERROR! Foul line distance could not be determined. Check pit object name %s and foul line object name %s in the ME.", namepit, namefoulline)) + self:E( self.id .. string.format( "ERROR! Foul line distance could not be determined. Check pit object name %s and foul line object name %s in the ME.", namepit, namefoulline ) ) end - self:T(self.id..string.format("Foul line distance = %.1f m.", fouldist)) + self:T( self.id .. string.format( "Foul line distance = %.1f m.", fouldist ) ) return fouldist end @@ -1510,120 +1552,117 @@ end --- General event handler. -- @param #RANGE self -- @param #table Event DCS event table. -function RANGE:onEvent(Event) - self:F3(Event) +function RANGE:onEvent( Event ) + self:F3( Event ) if Event == nil or Event.initiator == nil then - self:T3("Skipping onEvent. Event or Event.initiator unknown.") + self:T3( "Skipping onEvent. Event or Event.initiator unknown." ) return true end - if Unit.getByName(Event.initiator:getName()) == nil then - self:T3("Skipping onEvent. Initiator unit name unknown.") + if Unit.getByName( Event.initiator:getName() ) == nil then + self:T3( "Skipping onEvent. Initiator unit name unknown." ) return true end local DCSiniunit = Event.initiator local DCStgtunit = Event.target - local DCSweapon = Event.weapon + local DCSweapon = Event.weapon - local EventData={} - local _playerunit=nil - local _playername=nil + local EventData = {} + local _playerunit = nil + local _playername = nil if Event.initiator then - EventData.IniUnitName = Event.initiator:getName() - EventData.IniDCSGroup = Event.initiator:getGroup() + EventData.IniUnitName = Event.initiator:getName() + EventData.IniDCSGroup = Event.initiator:getGroup() EventData.IniGroupName = Event.initiator:getGroup():getName() -- Get player unit and name. This returns nil,nil if the event was not fired by a player unit. And these are the only events we are interested in. - _playerunit, _playername = self:_GetPlayerUnitAndName(EventData.IniUnitName) + _playerunit, _playername = self:_GetPlayerUnitAndName( EventData.IniUnitName ) end if Event.target then - EventData.TgtUnitName = Event.target:getName() - EventData.TgtUnit = UNIT:FindByName(EventData.TgtUnitName) + EventData.TgtUnitName = Event.target:getName() + EventData.TgtUnit = UNIT:FindByName( EventData.TgtUnitName ) end if Event.weapon then - EventData.Weapon = Event.weapon - EventData.weapon = Event.weapon + EventData.Weapon = Event.weapon + EventData.weapon = Event.weapon EventData.WeaponTypeName = Event.weapon:getTypeName() end -- Event info. - self:T3(self.id..string.format("EVENT: Event in onEvent with ID = %s", tostring(Event.id))) - self:T3(self.id..string.format("EVENT: Ini unit = %s" , tostring(EventData.IniUnitName))) - self:T3(self.id..string.format("EVENT: Ini group = %s" , tostring(EventData.IniGroupName))) - self:T3(self.id..string.format("EVENT: Ini player = %s" , tostring(_playername))) - self:T3(self.id..string.format("EVENT: Tgt unit = %s" , tostring(EventData.TgtUnitName))) - self:T3(self.id..string.format("EVENT: Wpn type = %s" , tostring(EventData.WeaponTypeName))) + self:T3( self.id .. string.format( "EVENT: Event in onEvent with ID = %s", tostring( Event.id ) ) ) + self:T3( self.id .. string.format( "EVENT: Ini unit = %s", tostring( EventData.IniUnitName ) ) ) + self:T3( self.id .. string.format( "EVENT: Ini group = %s", tostring( EventData.IniGroupName ) ) ) + self:T3( self.id .. string.format( "EVENT: Ini player = %s", tostring( _playername ) ) ) + self:T3( self.id .. string.format( "EVENT: Tgt unit = %s", tostring( EventData.TgtUnitName ) ) ) + self:T3( self.id .. string.format( "EVENT: Wpn type = %s", tostring( EventData.WeaponTypeName ) ) ) -- Call event Birth function. - if Event.id==world.event.S_EVENT_BIRTH and _playername then - self:OnEventBirth(EventData) + if Event.id == world.event.S_EVENT_BIRTH and _playername then + self:OnEventBirth( EventData ) end -- Call event Shot function. - if Event.id==world.event.S_EVENT_SHOT and _playername and Event.weapon then - self:OnEventShot(EventData) + if Event.id == world.event.S_EVENT_SHOT and _playername and Event.weapon then + self:OnEventShot( EventData ) end -- Call event Hit function. - if Event.id==world.event.S_EVENT_HIT and _playername and DCStgtunit then - self:OnEventHit(EventData) + if Event.id == world.event.S_EVENT_HIT and _playername and DCStgtunit then + self:OnEventHit( EventData ) end end - --- Range event handler for event birth. -- @param #RANGE self -- @param Core.Event#EVENTDATA EventData -function RANGE:OnEventBirth(EventData) - self:F({eventbirth = EventData}) +function RANGE:OnEventBirth( EventData ) + self:F( { eventbirth = EventData } ) - local _unitName=EventData.IniUnitName - local _unit, _playername=self:_GetPlayerUnitAndName(_unitName) + local _unitName = EventData.IniUnitName + local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) - self:T3(self.id.."BIRTH: unit = "..tostring(EventData.IniUnitName)) - self:T3(self.id.."BIRTH: group = "..tostring(EventData.IniGroupName)) - self:T3(self.id.."BIRTH: player = "..tostring(_playername)) + self:T3( self.id .. "BIRTH: unit = " .. tostring( EventData.IniUnitName ) ) + self:T3( self.id .. "BIRTH: group = " .. tostring( EventData.IniGroupName ) ) + self:T3( self.id .. "BIRTH: player = " .. tostring( _playername ) ) if _unit and _playername then - local _uid=_unit:GetID() - local _group=_unit:GetGroup() - local _gid=_group:GetID() - local _callsign=_unit:GetCallsign() + local _uid = _unit:GetID() + local _group = _unit:GetGroup() + local _gid = _group:GetID() + local _callsign = _unit:GetCallsign() -- Debug output. - local text=string.format("Player %s, callsign %s entered unit %s (UID %d) of group %s (GID %d)", _playername, _callsign, _unitName, _uid, _group:GetName(), _gid) - self:T(self.id..text) + local text = string.format( "Player %s, callsign %s entered unit %s (UID %d) of group %s (GID %d)", _playername, _callsign, _unitName, _uid, _group:GetName(), _gid ) + self:T( self.id .. text ) -- Reset current strafe status. self.strafeStatus[_uid] = nil -- 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. - self.PlayerSettings[_playername]={} --#RANGE.PlayerData - self.PlayerSettings[_playername].smokebombimpact=self.defaultsmokebomb - self.PlayerSettings[_playername].flaredirecthits=false - self.PlayerSettings[_playername].smokecolor=SMOKECOLOR.Blue - self.PlayerSettings[_playername].flarecolor=FLARECOLOR.Red - self.PlayerSettings[_playername].delaysmoke=true - self.PlayerSettings[_playername].messages=true - self.PlayerSettings[_playername].client=CLIENT:FindByName(_unitName, nil, true) - self.PlayerSettings[_playername].unitname=_unitName - self.PlayerSettings[_playername].playername=_playername - self.PlayerSettings[_playername].airframe=EventData.IniUnit:GetTypeName() - self.PlayerSettings[_playername].inzone=false + self.PlayerSettings[_playername] = {} -- #RANGE.PlayerData + self.PlayerSettings[_playername].smokebombimpact = self.defaultsmokebomb + self.PlayerSettings[_playername].flaredirecthits = false + self.PlayerSettings[_playername].smokecolor = SMOKECOLOR.Blue + self.PlayerSettings[_playername].flarecolor = FLARECOLOR.Red + self.PlayerSettings[_playername].delaysmoke = true + self.PlayerSettings[_playername].messages = true + self.PlayerSettings[_playername].client = CLIENT:FindByName( _unitName, nil, true ) + self.PlayerSettings[_playername].unitname = _unitName + self.PlayerSettings[_playername].playername = _playername + self.PlayerSettings[_playername].airframe = EventData.IniUnit:GetTypeName() + self.PlayerSettings[_playername].inzone = false -- Start check in zone timer. 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 end @@ -1633,18 +1672,18 @@ end --- Range event handler for event hit. -- @param #RANGE self -- @param Core.Event#EVENTDATA EventData -function RANGE:OnEventHit(EventData) - self:F({eventhit = EventData}) +function RANGE:OnEventHit( EventData ) + self:F( { eventhit = EventData } ) -- Debug info. - self:T3(self.id.."HIT: Ini unit = "..tostring(EventData.IniUnitName)) - self:T3(self.id.."HIT: Ini group = "..tostring(EventData.IniGroupName)) - self:T3(self.id.."HIT: Tgt target = "..tostring(EventData.TgtUnitName)) + self:T3( self.id .. "HIT: Ini unit = " .. tostring( EventData.IniUnitName ) ) + self:T3( self.id .. "HIT: Ini group = " .. tostring( EventData.IniGroupName ) ) + self:T3( self.id .. "HIT: Tgt target = " .. tostring( EventData.TgtUnitName ) ) -- Player info local _unitName = EventData.IniUnitName - local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) - if _unit==nil or _playername==nil then + local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) + if _unit == nil or _playername == nil then return end @@ -1652,11 +1691,11 @@ function RANGE:OnEventHit(EventData) local _unitID = _unit:GetID() -- Target - local target = EventData.TgtUnit + local target = EventData.TgtUnit local targetname = EventData.TgtUnitName -- 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. if _currentTarget and target:IsAlive() then @@ -1665,31 +1704,31 @@ function RANGE:OnEventHit(EventData) local targetPos = target:GetCoordinate() -- Loop over valid targets for this run. - for _,_target in pairs(_currentTarget.zone.targets) do + for _, _target in pairs( _currentTarget.zone.targets ) do -- Check the the target is the same that was actually hit. - if _target and _target:IsAlive() and _target:GetName() == targetname then + if _target and _target:IsAlive() and _target:GetName() == targetname then -- Get distance between player and target. - local dist=playerPos:Get2DDistance(targetPos) + local dist = playerPos:Get2DDistance( targetPos ) if dist > _currentTarget.zone.foulline then -- Increase hit counter of this run. - _currentTarget.hits = _currentTarget.hits + 1 + _currentTarget.hits = _currentTarget.hits + 1 -- Flare target. if _unit and _playername and self.PlayerSettings[_playername].flaredirecthits then - targetPos:Flare(self.PlayerSettings[_playername].flarecolor) + targetPos:Flare( self.PlayerSettings[_playername].flarecolor ) end else -- Too close to the target. - if _currentTarget.pastfoulline==false and _unit and _playername then - 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) - self:_DisplayMessageToGroup(_unit, text) - self:T2(self.id..text) - _currentTarget.pastfoulline=true - invalidStrafe = true --Rangeboss Edit + if _currentTarget.pastfoulline == false and _unit and _playername then + 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 ) + self:_DisplayMessageToGroup( _unit, text ) + self:T2( self.id .. text ) + _currentTarget.pastfoulline = true + invalidStrafe = true -- Rangeboss Edit end end @@ -1698,9 +1737,9 @@ function RANGE:OnEventHit(EventData) end -- Bombing Targets - for _,_bombtarget in pairs(self.bombingTargets) do + for _, _bombtarget in pairs( self.bombingTargets ) do - local _target=_bombtarget.target --Wrapper.Positionable#POSITIONABLE + local _target = _bombtarget.target -- Wrapper.Positionable#POSITIONABLE -- Check if one of the bomb targets was hit. if _target and _target:IsAlive() and _bombtarget.name == targetname then @@ -1709,11 +1748,11 @@ function RANGE:OnEventHit(EventData) -- Flare target. if self.PlayerSettings[_playername].flaredirecthits then - + -- Position of target. local targetPos = _target:GetCoordinate() - - targetPos:Flare(self.PlayerSettings[_playername].flarecolor) + + targetPos:Flare( self.PlayerSettings[_playername].flarecolor ) end end @@ -1724,40 +1763,40 @@ end --- Range event handler for event shot (when a unit releases a rocket or bomb (but not a fast firing gun). -- @param #RANGE self -- @param Core.Event#EVENTDATA EventData -function RANGE:OnEventShot(EventData) - self:F({eventshot = EventData}) +function RANGE:OnEventShot( EventData ) + self:F( { eventshot = EventData } ) -- Nil checks. - if EventData.Weapon==nil then + if EventData.Weapon == nil then return end - if EventData.IniDCSUnit==nil then + if EventData.IniDCSUnit == nil then return end -- Weapon data. - local _weapon = EventData.Weapon:getTypeName() -- should be the same as Event.WeaponTypeName - local _weaponStrArray = UTILS.Split(_weapon,"%.") + local _weapon = EventData.Weapon:getTypeName() -- should be the same as Event.WeaponTypeName + local _weaponStrArray = UTILS.Split( _weapon, "%." ) local _weaponName = _weaponStrArray[#_weaponStrArray] -- Weapon descriptor. - local desc=EventData.Weapon:getDesc() + local desc = EventData.Weapon:getDesc() -- Weapon category: 0=SHELL, 1=MISSILE, 2=ROCKET, 3=BOMB (Weapon.Category.X) - local weaponcategory=desc.category + local weaponcategory = desc.category -- Debug info. - self:T(self.id.."EVENT SHOT: Range "..self.rangename) - self:T(self.id.."EVENT SHOT: Ini unit = "..EventData.IniUnitName) - self:T(self.id.."EVENT SHOT: Ini group = "..EventData.IniGroupName) - self:T(self.id.."EVENT SHOT: Weapon type = ".._weapon) - self:T(self.id.."EVENT SHOT: Weapon name = ".._weaponName) - self:T(self.id.."EVENT SHOT: Weapon cate = "..weaponcategory) + self:T( self.id .. "EVENT SHOT: Range " .. self.rangename ) + self:T( self.id .. "EVENT SHOT: Ini unit = " .. EventData.IniUnitName ) + self:T( self.id .. "EVENT SHOT: Ini group = " .. EventData.IniGroupName ) + self:T( self.id .. "EVENT SHOT: Weapon type = " .. _weapon ) + self:T( self.id .. "EVENT SHOT: Weapon name = " .. _weaponName ) + self:T( self.id .. "EVENT SHOT: Weapon cate = " .. weaponcategory ) -- Tracking conditions for bombs, rockets and missiles. - local _bombs = weaponcategory==Weapon.Category.BOMB --string.match(_weapon, "weapons.bombs") - local _rockets = weaponcategory==Weapon.Category.ROCKET --string.match(_weapon, "weapons.nurs") - local _missiles = weaponcategory==Weapon.Category.MISSILE --string.match(_weapon, "weapons.missiles") or _viggen + local _bombs = weaponcategory == Weapon.Category.BOMB -- string.match(_weapon, "weapons.bombs") + local _rockets = weaponcategory == Weapon.Category.ROCKET -- string.match(_weapon, "weapons.nurs") + local _missiles = weaponcategory == Weapon.Category.MISSILE -- string.match(_weapon, "weapons.missiles") or _viggen -- Check if any condition applies here. local _track = (_bombs and self.trackbombs) or (_rockets and self.trackrockets) or (_missiles and self.trackmissiles) @@ -1766,39 +1805,38 @@ function RANGE:OnEventShot(EventData) local _unitName = EventData.IniUnitName -- Get player unit and name. - local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) + local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) -- Set this to larger value than the threshold. - local dPR=self.BombtrackThreshold*2 + local dPR = self.BombtrackThreshold * 2 -- Distance player to range. if _unit and _playername then - dPR=_unit:GetCoordinate():Get2DDistance(self.location) - self:T(self.id..string.format("Range %s, player %s, player-range distance = %d km.", self.rangename, _playername, dPR/1000)) + dPR = _unit:GetCoordinate():Get2DDistance( self.location ) + self:T( self.id .. string.format( "Range %s, player %s, player-range distance = %d km.", self.rangename, _playername, dPR / 1000 ) ) end -- Only track if distance player to range is < 25 km. Also check that a player shot. No need to track AI weapons. - if _track and dPR<=self.BombtrackThreshold and _unit and _playername then + if _track and dPR <= self.BombtrackThreshold and _unit and _playername then -- Player data. - local playerData=self.PlayerSettings[_playername] --#RANGE.PlayerData + local playerData = self.PlayerSettings[_playername] -- #RANGE.PlayerData -- Tracking info and init of last bomb position. - self:T(self.id..string.format("RANGE %s: Tracking %s - %s.", self.rangename, _weapon, EventData.weapon:getName())) + self:T( self.id .. string.format( "RANGE %s: Tracking %s - %s.", self.rangename, _weapon, EventData.weapon:getName() ) ) -- Init bomb position. - local _lastBombPos = {x=0,y=0,z=0} --DCS#Vec3 + local _lastBombPos = { x = 0, y = 0, z = 0 } -- DCS#Vec3 -- Function monitoring the position of a bomb until impact. - local function trackBomb(_ordnance) + local function trackBomb( _ordnance ) -- When the pcall returns a failure the weapon has hit. - local _status,_bombPos = pcall( - function() + local _status, _bombPos = pcall( function() return _ordnance:getPoint() - end) + end ) - self:T2(self.id..string.format("Range %s: Bomb still in air: %s", self.rangename, tostring(_status))) + self:T2( self.id .. string.format( "Range %s: Bomb still in air: %s", self.rangename, tostring( _status ) ) ) if _status then ---------------------------- @@ -1806,7 +1844,7 @@ function RANGE:OnEventShot(EventData) ---------------------------- -- Remember this position. - _lastBombPos = {x = _bombPos.x, y = _bombPos.y, z= _bombPos.z } + _lastBombPos = { x = _bombPos.x, y = _bombPos.y, z = _bombPos.z } -- Check again in ~0.005 seconds ==> 200 checks per second. return timer.getTime() + self.dtBombtrack @@ -1818,57 +1856,57 @@ function RANGE:OnEventShot(EventData) ----------------------------- -- Get closet target to last position. - local _closetTarget=nil --#RANGE.BombTarget - local _distance=nil - local _closeCoord=nil - local _hitquality="POOR" + local _closetTarget = nil -- #RANGE.BombTarget + local _distance = nil + local _closeCoord = nil + local _hitquality = "POOR" -- Get callsign. - local _callsign=self:_myname(_unitName) + local _callsign = self:_myname( _unitName ) -- Coordinate of impact point. - local impactcoord=COORDINATE:NewFromVec3(_lastBombPos) + local impactcoord = COORDINATE:NewFromVec3( _lastBombPos ) -- Check if impact happened in range zone. - local insidezone=self.rangezone:IsCoordinateInZone(impactcoord) + local insidezone = self.rangezone:IsCoordinateInZone( impactcoord ) -- Impact point of bomb. if self.Debug then - impactcoord:MarkToAll("Bomb impact point") + impactcoord:MarkToAll( "Bomb impact point" ) end -- Smoke impact point of bomb. if playerData.smokebombimpact and insidezone then if playerData.delaysmoke then - timer.scheduleFunction(self._DelayedSmoke, {coord=impactcoord, color=playerData.smokecolor}, timer.getTime() + self.TdelaySmoke) + timer.scheduleFunction( self._DelayedSmoke, { coord = impactcoord, color = playerData.smokecolor }, timer.getTime() + self.TdelaySmoke ) else - impactcoord:Smoke(playerData.smokecolor) + impactcoord:Smoke( playerData.smokecolor ) end end -- Loop over defined bombing targets. - for _,_bombtarget in pairs(self.bombingTargets) do + for _, _bombtarget in pairs( self.bombingTargets ) do -- Get target coordinate. - local targetcoord=self:_GetBombTargetCoordinate(_bombtarget) + local targetcoord = self:_GetBombTargetCoordinate( _bombtarget ) if targetcoord then -- Distance between bomb and target. - local _temp = impactcoord:Get2DDistance(targetcoord) + local _temp = impactcoord:Get2DDistance( targetcoord ) -- Find closest target to last known position of the bomb. if _distance == nil or _temp < _distance then _distance = _temp _closetTarget = _bombtarget - _closeCoord=targetcoord + _closeCoord = targetcoord if _distance <= 1.53 then -- Rangeboss Edit _hitquality = "SHACK" -- Rangeboss Edit - elseif _distance <= 0.5*_bombtarget.goodhitrange then --Rangeboss Edit + elseif _distance <= 0.5 * _bombtarget.goodhitrange then -- Rangeboss Edit _hitquality = "EXCELLENT" elseif _distance <= _bombtarget.goodhitrange then _hitquality = "GOOD" - elseif _distance <= 2*_bombtarget.goodhitrange then + elseif _distance <= 2 * _bombtarget.goodhitrange then _hitquality = "INEFFECTIVE" else _hitquality = "POOR" @@ -1882,48 +1920,48 @@ function RANGE:OnEventShot(EventData) if _distance and _distance <= self.scorebombdistance then -- Init bomb player results. if not self.bombPlayerResults[_playername] then - self.bombPlayerResults[_playername]={} + self.bombPlayerResults[_playername] = {} end -- Local results. - local _results=self.bombPlayerResults[_playername] + local _results = self.bombPlayerResults[_playername] - local result={} --#RANGE.BombResult - result.name=_closetTarget.name or "unknown" - result.distance=_distance - result.radial=_closeCoord:HeadingTo(impactcoord) - result.weapon=_weaponName or "unknown" - result.quality=_hitquality - result.player=playerData.playername - result.time=timer.getAbsTime() - result.airframe=playerData.airframe - result.roundsFired=0 --Rangeboss Edit - result.roundsHit=0 --Rangeboss Edit - result.roundsQuality="N/A" --Rangeboss Edit - result.rangename = self.rangename + local result = {} -- #RANGE.BombResult + result.name = _closetTarget.name or "unknown" + result.distance = _distance + result.radial = _closeCoord:HeadingTo( impactcoord ) + result.weapon = _weaponName or "unknown" + result.quality = _hitquality + result.player = playerData.playername + result.time = timer.getAbsTime() + result.airframe = playerData.airframe + result.roundsFired = 0 -- Rangeboss Edit + result.roundsHit = 0 -- Rangeboss Edit + result.roundsQuality = "N/A" -- Rangeboss Edit + result.rangename = self.rangename -- Add to table. - table.insert(_results, result) + table.insert( _results, result ) -- Call impact. - self:Impact(result, playerData) + self:Impact( result, playerData ) elseif insidezone then -- Send message. - local _message=string.format("%s, weapon impacted too far from nearest range target (>%.1f km). No score!", _callsign, self.scorebombdistance/1000) - self:_DisplayMessageToGroup(_unit, _message, nil, false) - + local _message = string.format( "%s, weapon impacted too far from nearest range target (>%.1f km). No score!", _callsign, self.scorebombdistance / 1000 ) + self:_DisplayMessageToGroup( _unit, _message, nil, false ) + if self.rangecontrol then - self.rangecontrol:NewTransmission(RANGE.Sound.RCWeaponImpactedTooFar.filename, RANGE.Sound.RCWeaponImpactedTooFar.duration, self.soundpath, nil, nil, _message, self.subduration) + self.rangecontrol:NewTransmission( RANGE.Sound.RCWeaponImpactedTooFar.filename, RANGE.Sound.RCWeaponImpactedTooFar.duration, self.soundpath, nil, nil, _message, self.subduration ) end else - self:T(self.id.."Weapon impacted outside range zone.") + self:T( self.id .. "Weapon impacted outside range zone." ) end - --Terminate the timer - self:T(self.id..string.format("Range %s, player %s: Terminating bomb track timer.", self.rangename, _playername)) + -- Terminate the timer + self:T( self.id .. string.format( "Range %s, player %s: Terminating bomb track timer.", self.rangename, _playername ) ) return nil end -- _status check @@ -1931,133 +1969,62 @@ function RANGE:OnEventShot(EventData) end -- end function trackBomb -- Weapon is not yet "alife" just yet. Start timer in one second. - self:T(self.id..string.format("Range %s, player %s: Tracking of weapon starts in 0.1 seconds.", self.rangename, _playername)) - timer.scheduleFunction(trackBomb, EventData.weapon, timer.getTime()+0.1) + self:T( self.id .. string.format( "Range %s, player %s: Tracking of weapon starts in 0.1 seconds.", self.rangename, _playername ) ) + timer.scheduleFunction( trackBomb, EventData.weapon, timer.getTime() + 0.1 ) - end --if _track (string.match) and player-range distance < threshold. + end -- if _track (string.match) and player-range distance < threshold. end ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- 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. -- @param #RANGE self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -function RANGE:onafterStatus(From, Event, To) +function RANGE:onafterStatus( From, Event, To ) - if self.verbose>0 then + if self.verbose > 0 then - local fsmstate=self:GetState() - - local text=string.format("Range status: %s", fsmstate) - - if self.instructor then - local alive="N/A" + local fsmstate = self:GetState() + + local text = string.format( "Range status: %s", fsmstate ) + + if self.instructor then + local alive = "N/A" if self.instructorrelayname then - local relay=UNIT:FindByName(self.instructorrelayname) + local relay = UNIT:FindByName( self.instructorrelayname ) if relay then - alive=tostring(relay:IsAlive()) + alive = tostring( relay:IsAlive() ) end end - text=text..string.format(", Instructor %.3f MHz (Relay=%s alive=%s)", self.instructorfreq, tostring(self.instructorrelayname), alive) + text = text .. string.format( ", Instructor %.3f MHz (Relay=%s alive=%s)", self.instructorfreq, tostring( self.instructorrelayname ), alive ) end - - if self.rangecontrol then - local alive="N/A" + + if self.rangecontrol then + local alive = "N/A" if self.rangecontrolrelayname then - local relay=UNIT:FindByName(self.rangecontrolrelayname) + local relay = UNIT:FindByName( self.rangecontrolrelayname ) if relay then - alive=tostring(relay:IsAlive()) + alive = tostring( relay:IsAlive() ) end end - 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 - - + -- Check range status. - self:I(self.id..text) - + self:I( self.id .. text ) + end -- Check player status. self:_CheckPlayers() -- Check back in ~10 seconds. - self:__Status(-10) + self:__Status( -10 ) end --- Function called after player enters the range zone. @@ -2066,23 +2033,23 @@ end -- @param #string Event Event. -- @param #string To To state. -- @param #RANGE.PlayerData player Player data. -function RANGE:onafterEnterRange(From, Event, To, player) - +function RANGE:onafterEnterRange( From, Event, To, player ) + if self.instructor and self.rangecontrol then - + -- Range control radio frequency split. - local RF=UTILS.Split(string.format("%.3f", self.rangecontrolfreq), ".") - + local RF = UTILS.Split( string.format( "%.3f", self.rangecontrolfreq ), "." ) + -- Radio message that player entered the range - self.instructor:NewTransmission(RANGE.Sound.IREnterRange.filename, RANGE.Sound.IREnterRange.duration, self.soundpath) - self.instructor:Number2Transmission(RF[1]) - if tonumber(RF[2])>0 then - self.instructor:NewTransmission(RANGE.Sound.IRDecimal.filename, RANGE.Sound.IRDecimal.duration, self.soundpath) - self.instructor:Number2Transmission(RF[2]) + self.instructor:NewTransmission( RANGE.Sound.IREnterRange.filename, RANGE.Sound.IREnterRange.duration, self.soundpath ) + self.instructor:Number2Transmission( RF[1] ) + if tonumber( RF[2] ) > 0 then + self.instructor:NewTransmission( RANGE.Sound.IRDecimal.filename, RANGE.Sound.IRDecimal.duration, self.soundpath ) + self.instructor:Number2Transmission( RF[2] ) end - self.instructor:NewTransmission(RANGE.Sound.IRMegaHertz.filename, RANGE.Sound.IRMegaHertz.duration, self.soundpath) + self.instructor:NewTransmission( RANGE.Sound.IRMegaHertz.filename, RANGE.Sound.IRMegaHertz.duration, self.soundpath ) end - + end --- Function called after player leaves the range zone. @@ -2091,15 +2058,14 @@ end -- @param #string Event Event. -- @param #string To To state. -- @param #RANGE.PlayerData player Player data. -function RANGE:onafterExitRange(From, Event, To, player) +function RANGE:onafterExitRange( From, Event, To, player ) if self.instructor then - self.instructor:NewTransmission(RANGE.Sound.IRExitRange.filename, RANGE.Sound.IRExitRange.duration, self.soundpath) + self.instructor:NewTransmission( RANGE.Sound.IRExitRange.filename, RANGE.Sound.IRExitRange.duration, self.soundpath ) end end - --- Function called after bomb impact on range. -- @param #RANGE self -- @param #string From From state. @@ -2107,49 +2073,49 @@ end -- @param #string To To state. -- @param #RANGE.BombResult result Result of bomb impact. -- @param #RANGE.PlayerData player Player data table. -function RANGE:onafterImpact(From, Event, To, result, player) +function RANGE:onafterImpact( From, Event, To, result, player ) -- Only display target name if there is more than one bomb target. - local targetname=nil - if #self.bombingTargets>1 then - local targetname=result.name + local targetname = nil + if #self.bombingTargets > 1 then + local targetname = result.name end -- Send message to player. - local text=string.format("%s, impact %03d° for %d ft", player.playername, result.radial, UTILS.MetersToFeet(result.distance)) + local text = string.format( "%s, impact %03d° for %d ft", player.playername, result.radial, UTILS.MetersToFeet( result.distance ) ) if targetname then - text=text..string.format(" from bulls of target %s.") + text = text .. string.format( " from bulls of target %s." ) else - text=text.."." + text = text .. "." end - text=text..string.format(" %s hit.", result.quality) - + text = text .. string.format( " %s hit.", result.quality ) + if self.rangecontrol then - self.rangecontrol:NewTransmission(RANGE.Sound.RCImpact.filename, RANGE.Sound.RCImpact.duration, self.soundpath, nil, nil, text, self.subduration) - self.rangecontrol:Number2Transmission(string.format("%03d", result.radial), nil, 0.1) - self.rangecontrol:NewTransmission(RANGE.Sound.RCDegrees.filename, RANGE.Sound.RCDegrees.duration, self.soundpath) - self.rangecontrol:NewTransmission(RANGE.Sound.RCFor.filename, RANGE.Sound.RCFor.duration, self.soundpath) - self.rangecontrol:Number2Transmission(string.format("%d", UTILS.MetersToFeet(result.distance))) - self.rangecontrol:NewTransmission(RANGE.Sound.RCFeet.filename, RANGE.Sound.RCFeet.duration, self.soundpath) - if result.quality=="POOR" then - self.rangecontrol:NewTransmission(RANGE.Sound.RCPoorHit.filename, RANGE.Sound.RCPoorHit.duration, self.soundpath, nil, 0.5) - elseif result.quality=="INEFFECTIVE" then - self.rangecontrol:NewTransmission(RANGE.Sound.RCIneffectiveHit.filename, RANGE.Sound.RCIneffectiveHit.duration, self.soundpath, nil, 0.5) - elseif result.quality=="GOOD" then - self.rangecontrol:NewTransmission(RANGE.Sound.RCGoodHit.filename, RANGE.Sound.RCGoodHit.duration, self.soundpath, nil, 0.5) - elseif result.quality=="EXCELLENT" then - self.rangecontrol:NewTransmission(RANGE.Sound.RCExcellentHit.filename, RANGE.Sound.RCExcellentHit.duration, self.soundpath, nil, 0.5) + self.rangecontrol:NewTransmission( RANGE.Sound.RCImpact.filename, RANGE.Sound.RCImpact.duration, self.soundpath, nil, nil, text, self.subduration ) + self.rangecontrol:Number2Transmission( string.format( "%03d", result.radial ), nil, 0.1 ) + self.rangecontrol:NewTransmission( RANGE.Sound.RCDegrees.filename, RANGE.Sound.RCDegrees.duration, self.soundpath ) + self.rangecontrol:NewTransmission( RANGE.Sound.RCFor.filename, RANGE.Sound.RCFor.duration, self.soundpath ) + self.rangecontrol:Number2Transmission( string.format( "%d", UTILS.MetersToFeet( result.distance ) ) ) + self.rangecontrol:NewTransmission( RANGE.Sound.RCFeet.filename, RANGE.Sound.RCFeet.duration, self.soundpath ) + if result.quality == "POOR" then + self.rangecontrol:NewTransmission( RANGE.Sound.RCPoorHit.filename, RANGE.Sound.RCPoorHit.duration, self.soundpath, nil, 0.5 ) + elseif result.quality == "INEFFECTIVE" then + self.rangecontrol:NewTransmission( RANGE.Sound.RCIneffectiveHit.filename, RANGE.Sound.RCIneffectiveHit.duration, self.soundpath, nil, 0.5 ) + elseif result.quality == "GOOD" then + self.rangecontrol:NewTransmission( RANGE.Sound.RCGoodHit.filename, RANGE.Sound.RCGoodHit.duration, self.soundpath, nil, 0.5 ) + elseif result.quality == "EXCELLENT" then + self.rangecontrol:NewTransmission( RANGE.Sound.RCExcellentHit.filename, RANGE.Sound.RCExcellentHit.duration, self.soundpath, nil, 0.5 ) end - - end + + end -- Unit. - local unit=UNIT:FindByName(player.unitname) + local unit = UNIT:FindByName( player.unitname ) -- Send message. - self:_DisplayMessageToGroup(unit, text, nil, true) - self:T(self.id..text) - + self:_DisplayMessageToGroup( unit, text, nil, true ) + self:T( self.id .. text ) + -- Save results. if self.autosave then self:Save() @@ -2162,11 +2128,11 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -function RANGE:onbeforeSave(From, Event, To) +function RANGE:onbeforeSave( From, Event, To ) if io and lfs then return true else - self:E(self.id..string.format("WARNING: io and/or lfs not desanitized. Cannot save player results.")) + self:E( self.id .. string.format( "WARNING: io and/or lfs not desanitized. Cannot save player results." ) ) return false end end @@ -2176,50 +2142,50 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -function RANGE:onafterSave(From, Event, To) +function RANGE:onafterSave( From, Event, To ) - local function _savefile(filename, data) - local f=io.open(filename, "wb") + local function _savefile( filename, data ) + local f = io.open( filename, "wb" ) if f then - f:write(data) + f:write( data ) f:close() - self:I(self.id..string.format("Saving player results to file %s", tostring(filename))) + self:I( self.id .. string.format( "Saving player results to file %s", tostring( filename ) ) ) else - self:E(self.id..string.format("ERROR: Could not save results to file %s", tostring(filename))) + self:E( self.id .. string.format( "ERROR: Could not save results to file %s", tostring( filename ) ) ) end end -- Path. - local path=lfs.writedir()..[[Logs\]] + local path = lfs.writedir() .. [[Logs\]] -- Set file name. - local filename=path..string.format("RANGE-%s_BombingResults.csv", self.rangename) + local filename = path .. string.format( "RANGE-%s_BombingResults.csv", self.rangename ) -- Header line. - local scores="Name,Pass,Target,Distance,Radial,Quality,Weapon,Airframe,Mission Time" + local scores = "Name,Pass,Target,Distance,Radial,Quality,Weapon,Airframe,Mission Time" -- Loop over all players. - for playername,results in pairs(self.bombPlayerResults) do + for playername, results in pairs( self.bombPlayerResults ) do -- Loop over player grades table. - for i,_result in pairs(results) do - 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" + for i, _result in pairs( results ) do + 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" if os then - date=os.date() + date = os.date() end - scores=scores..string.format("\n%s,%d,%s,%.2f,%03d,%s,%s,%s,%s,%s", playername, i, target, distance, radial, quality, weapon, airframe, time, date) + scores = scores .. string.format( "\n%s,%d,%s,%.2f,%03d,%s,%s,%s,%s,%s", playername, i, target, distance, radial, quality, weapon, airframe, time, date ) end end - _savefile(filename, scores) + _savefile( filename, scores ) end --- Function called before save event. Checks that io and lfs are desanitized. @@ -2227,11 +2193,11 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -function RANGE:onbeforeLoad(From, Event, To) +function RANGE:onbeforeLoad( From, Event, To ) if io and lfs then return true else - self:E(self.id..string.format("WARNING: io and/or lfs not desanitized. Cannot load player results.")) + self:E( self.id .. string.format( "WARNING: io and/or lfs not desanitized. Cannot load player results." ) ) return false end end @@ -2241,128 +2207,198 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -function RANGE:onafterLoad(From, Event, To) +function RANGE:onafterLoad( From, Event, To ) --- Function that load data from a file. - local function _loadfile(filename) - local f=io.open(filename, "rb") + local function _loadfile( filename ) + local f = io.open( filename, "rb" ) if f then - --self:I(self.id..string.format("Loading player results from file %s", tostring(filename))) - local data=f:read("*all") + -- self:I(self.id..string.format("Loading player results from file %s", tostring(filename))) + local data = f:read( "*all" ) f:close() return data else - self:E(self.id..string.format("WARNING: Could not load player results from file %s. File might not exist just yet.", tostring(filename))) + self:E( self.id .. string.format( "WARNING: Could not load player results from file %s. File might not exist just yet.", tostring( filename ) ) ) return nil end end -- Path in DCS log file. - local path=lfs.writedir()..[[Logs\]] + local path = lfs.writedir() .. [[Logs\]] -- Set file name. - local filename=path..string.format("RANGE-%s_BombingResults.csv", self.rangename) + local filename = path .. string.format( "RANGE-%s_BombingResults.csv", self.rangename ) -- Info message. - local text=string.format("Loading player bomb results from file %s", filename) - self:I(self.id..text) + local text = string.format( "Loading player bomb results from file %s", filename ) + self:I( self.id .. text ) -- Load asset data from file. - local data=_loadfile(filename) + local data = _loadfile( filename ) if data then -- Split by line break. - local results=UTILS.Split(data,"\n") + local results = UTILS.Split( data, "\n" ) -- Remove first header line. - table.remove(results, 1) + table.remove( results, 1 ) -- Init player scores table. - self.bombPlayerResults={} + self.bombPlayerResults = {} -- Loop over all lines. - for _,_result in pairs(results) do + for _, _result in pairs( results ) do -- Parameters are separated by commata. - local resultdata=UTILS.Split(_result, ",") + local resultdata = UTILS.Split( _result, "," ) -- Grade table - local result={} --#RANGE.BombResult + local result = {} -- #RANGE.BombResult -- Player name. - local playername=resultdata[1] - result.player=playername + local playername = resultdata[1] + result.player = playername -- Results data. - result.name=tostring(resultdata[3]) - result.distance=tonumber(resultdata[4]) - result.radial=tonumber(resultdata[5]) - result.quality=tostring(resultdata[6]) - result.weapon=tostring(resultdata[7]) - result.airframe=tostring(resultdata[8]) - result.time=UTILS.ClockToSeconds(resultdata[9] or "00:00:00") - result.date=resultdata[10] or "n/a" + result.name = tostring( resultdata[3] ) + result.distance = tonumber( resultdata[4] ) + result.radial = tonumber( resultdata[5] ) + result.quality = tostring( resultdata[6] ) + result.weapon = tostring( resultdata[7] ) + result.airframe = tostring( resultdata[8] ) + result.time = UTILS.ClockToSeconds( resultdata[9] or "00:00:00" ) + result.date = resultdata[10] or "n/a" -- Create player array if necessary. - self.bombPlayerResults[playername]=self.bombPlayerResults[playername] or {} + self.bombPlayerResults[playername] = self.bombPlayerResults[playername] or {} -- Add result to table. - table.insert(self.bombPlayerResults[playername], result) + table.insert( self.bombPlayerResults[playername], result ) 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 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Start smoking a coordinate with a delay. -- @param #table _args Argements passed. -function RANGE._DelayedSmoke(_args) - trigger.action.smoke(_args.coord:GetVec3(), _args.color) +function RANGE._DelayedSmoke( _args ) + trigger.action.smoke( _args.coord:GetVec3(), _args.color ) end --- Display top 10 stafing results of a specific player. -- @param #RANGE self -- @param #string _unitName Name of the player unit. -function RANGE:_DisplayMyStrafePitResults(_unitName) - self:F(_unitName) +function RANGE:_DisplayMyStrafePitResults( _unitName ) + self:F( _unitName ) -- Get player unit and name - local _unit,_playername = self:_GetPlayerUnitAndName(_unitName) + local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) if _unit and _playername then -- Message header. - local _message = string.format("My Top %d Strafe Pit Results:\n", self.ndisplayresult) + local _message = string.format( "My Top %d Strafe Pit Results:\n", self.ndisplayresult ) -- Get player results. - local _results = self.strafePlayerResults[_playername] + local _results = self.strafePlayerResults[_playername] -- Create message. if _results == nil then - -- No score yet. - _message = string.format("%s: No Score yet.", _playername) + -- No score yet. + _message = string.format( "%s: No Score yet.", _playername ) else -- Sort results table wrt number of hits. - local _sort = function( a,b ) return a.hits > b.hits end - table.sort(_results,_sort) + local _sort = function( a, b ) + return a.hits > b.hits + end + table.sort( _results, _sort ) -- Prepare message of best results. local _bestMsg = "" local _count = 1 -- Loop over results - for _,_result in pairs(_results) do + for _, _result in pairs( _results ) do + local result=_result --#RANGE.StrafeResult -- 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. if _bestMsg == "" then - _bestMsg = string.format("Hits %d - %s - %s", _result.hits, _result.zone.name, _result.text) + _bestMsg = string.format( "Hits %d - %s - %s", _result.hits, _result.zone.name, _result.text ) end -- 10 runs @@ -2371,26 +2407,26 @@ function RANGE:_DisplayMyStrafePitResults(_unitName) end -- Increase counter - _count = _count+1 + _count = _count + 1 end -- Message text. - _message = _message .."\n\nBEST: ".._bestMsg + _message = _message .. "\n\nBEST: " .. _bestMsg end -- Send message to group. - self:_DisplayMessageToGroup(_unit, _message, nil, true, true) + self:_DisplayMessageToGroup( _unit, _message, nil, true, true ) end end --- Display top 10 strafing results of all players. -- @param #RANGE self -- @param #string _unitName Name fo the player unit. -function RANGE:_DisplayStrafePitResults(_unitName) - self:F(_unitName) +function RANGE:_DisplayStrafePitResults( _unitName ) + self:F( _unitName ) -- Get player unit and name. - local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) + local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) -- Check if we have a unit which is a player. if _unit and _playername then @@ -2399,14 +2435,14 @@ function RANGE:_DisplayStrafePitResults(_unitName) local _playerResults = {} -- Message text. - local _message = string.format("Strafe Pit Results - Top %d Players:\n", self.ndisplayresult) + local _message = string.format( "Strafe Pit Results - Top %d Players:\n", self.ndisplayresult ) -- Loop over player results. - for _playerName,_results in pairs(self.strafePlayerResults) do + for _playerName, _results in pairs( self.strafePlayerResults ) do -- Get the best result of the player. local _best = nil - for _,_result in pairs(_results) do + for _, _result in pairs( _results ) do if _best == nil or _result.hits > _best.hits then _best = _result end @@ -2414,226 +2450,232 @@ function RANGE:_DisplayStrafePitResults(_unitName) -- Add best result to table. if _best ~= nil then - local text=string.format("%s: Hits %i - %s - %s", _playerName, _best.hits, _best.zone.name, _best.text) - table.insert(_playerResults,{msg = text, hits = _best.hits}) + local text = string.format( "%s: Hits %i - %s - %s", _playerName, _best.hits, _best.zone.name, _best.text ) + table.insert( _playerResults, { msg = text, hits = _best.hits } ) end end - --Sort list! - local _sort = function( a,b ) return a.hits > b.hits end - table.sort(_playerResults,_sort) + -- Sort list! + local _sort = function( a, b ) + return a.hits > b.hits + end + table.sort( _playerResults, _sort ) -- Add top 10 results. - for _i = 1, math.min(#_playerResults, self.ndisplayresult) do - _message = _message..string.format("\n[%d] %s", _i, _playerResults[_i].msg) + for _i = 1, math.min( #_playerResults, self.ndisplayresult ) do + _message = _message .. string.format( "\n[%d] %s", _i, _playerResults[_i].msg ) end -- In case there are no scores yet. - if #_playerResults<1 then - _message = _message.."No player scored yet." + if #_playerResults < 1 then + _message = _message .. "No player scored yet." end -- Send message. - self:_DisplayMessageToGroup(_unit, _message, nil, true, true) + self:_DisplayMessageToGroup( _unit, _message, nil, true, true ) end end --- Display top 10 bombing run results of specific player. -- @param #RANGE self -- @param #string _unitName Name of the player unit. -function RANGE:_DisplayMyBombingResults(_unitName) - self:F(_unitName) +function RANGE:_DisplayMyBombingResults( _unitName ) + self:F( _unitName ) -- Get player unit and name. - local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) + local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) if _unit and _playername then -- Init message. - local _message = string.format("My Top %d Bombing Results:\n", self.ndisplayresult) + local _message = string.format( "My Top %d Bombing Results:\n", self.ndisplayresult ) -- Results from player. local _results = self.bombPlayerResults[_playername] -- No score so far. if _results == nil then - _message = _playername..": No Score yet." + _message = _playername .. ": No Score yet." else -- Sort results wrt to distance. - local _sort = function( a,b ) return a.distance < b.distance end - table.sort(_results,_sort) + local _sort = function( a, b ) + return a.distance < b.distance + end + table.sort( _results, _sort ) -- Loop over results. local _bestMsg = "" - for i,_result in pairs(_results) do - local result=_result --#RANGE.BombResult + for i, _result in pairs( _results ) do + local result = _result -- #RANGE.BombResult -- Message with name, weapon and distance. - _message = _message.."\n"..string.format("[%d] %d m %03d° - %s - %s - %s hit", i, result.distance, result.radial, result.name, result.weapon, result.quality) + _message = _message .. "\n" .. string.format( "[%d] %d m %03d° - %s - %s - %s hit", i, result.distance, result.radial, result.name, result.weapon, result.quality ) -- Store best/first result. if _bestMsg == "" then - _bestMsg = string.format("%d m %03d° - %s - %s - %s hit", result.distance, result.radial, result.name, result.weapon, result.quality) + _bestMsg = string.format( "%d m %03d° - %s - %s - %s hit", result.distance, result.radial, result.name, result.weapon, result.quality ) end -- Best 10 runs only. - if i==self.ndisplayresult then + if i == self.ndisplayresult then break end end -- Message. - _message = _message .."\n\nBEST: ".._bestMsg + _message = _message .. "\n\nBEST: " .. _bestMsg end -- Send message. - self:_DisplayMessageToGroup(_unit, _message, nil, true, true) + self:_DisplayMessageToGroup( _unit, _message, nil, true, true ) end end --- Display best bombing results of top 10 players. -- @param #RANGE self -- @param #string _unitName Name of player unit. -function RANGE:_DisplayBombingResults(_unitName) - self:F(_unitName) +function RANGE:_DisplayBombingResults( _unitName ) + self:F( _unitName ) -- Results table. local _playerResults = {} -- Get player unit and name. - local _unit, _player = self:_GetPlayerUnitAndName(_unitName) + local _unit, _player = self:_GetPlayerUnitAndName( _unitName ) -- Check if we have a unit with a player. if _unit and _player then -- Message header. - local _message = string.format("Bombing Results - Top %d Players:\n", self.ndisplayresult) + local _message = string.format( "Bombing Results - Top %d Players:\n", self.ndisplayresult ) -- Loop over players. - for _playerName,_results in pairs(self.bombPlayerResults) do + for _playerName, _results in pairs( self.bombPlayerResults ) do -- Find best result of player. local _best = nil - for _,_result in pairs(_results) do + for _, _result in pairs( _results ) do if _best == nil or _result.distance < _best.distance then - _best = _result + _best = _result end end -- Put best result of player into table. if _best ~= nil then - local bestres=string.format("%s: %d m - %s - %s - %s hit", _playerName, _best.distance, _best.name, _best.weapon, _best.quality) - table.insert(_playerResults, {msg = bestres, distance = _best.distance}) + local bestres = string.format( "%s: %d m - %s - %s - %s hit", _playerName, _best.distance, _best.name, _best.weapon, _best.quality ) + table.insert( _playerResults, { msg = bestres, distance = _best.distance } ) end end -- Sort list of player results. - local _sort = function( a,b ) return a.distance < b.distance end - table.sort(_playerResults,_sort) + local _sort = function( a, b ) + return a.distance < b.distance + end + table.sort( _playerResults, _sort ) -- Loop over player results. - for _i = 1, math.min(#_playerResults, self.ndisplayresult) do - _message = _message..string.format("\n[%d] %s", _i, _playerResults[_i].msg) + for _i = 1, math.min( #_playerResults, self.ndisplayresult ) do + _message = _message .. string.format( "\n[%d] %s", _i, _playerResults[_i].msg ) end -- In case there are no scores yet. - if #_playerResults<1 then - _message = _message.."No player scored yet." + if #_playerResults < 1 then + _message = _message .. "No player scored yet." end -- Send message. - self:_DisplayMessageToGroup(_unit, _message, nil, true, true) + self:_DisplayMessageToGroup( _unit, _message, nil, true, true ) end end --- Report information like bearing and range from player unit to range. -- @param #RANGE self -- @param #string _unitname Name of the player unit. -function RANGE:_DisplayRangeInfo(_unitname) - self:F(_unitname) +function RANGE:_DisplayRangeInfo( _unitname ) + self:F( _unitname ) -- Get player unit and player name. - local unit, playername = self:_GetPlayerUnitAndName(_unitname) + local unit, playername = self:_GetPlayerUnitAndName( _unitname ) -- Check if we have a player. if unit and playername then -- Message text. - local text="" + local text = "" -- Current coordinates. - local coord=unit:GetCoordinate() + local coord = unit:GetCoordinate() if self.location then - local settings=_DATABASE:GetPlayerSettings(playername) or _SETTINGS --Core.Settings#SETTINGS + local settings = _DATABASE:GetPlayerSettings( playername ) or _SETTINGS -- Core.Settings#SETTINGS -- Direction vector from current position (coord) to target (position). - local position=self.location --Core.Point#COORDINATE - local bulls=position:ToStringBULLS(unit:GetCoalition(), settings) - local lldms=position:ToStringLLDMS(settings) - local llddm=position:ToStringLLDDM(settings) - local rangealt=position:GetLandHeight() - local vec3=coord:GetDirectionVec3(position) - local angle=coord:GetAngleDegrees(vec3) - local range=coord:Get2DDistance(position) + local position = self.location -- Core.Point#COORDINATE + local bulls = position:ToStringBULLS( unit:GetCoalition(), settings ) + local lldms = position:ToStringLLDMS( settings ) + local llddm = position:ToStringLLDDM( settings ) + local rangealt = position:GetLandHeight() + local vec3 = coord:GetDirectionVec3( position ) + local angle = coord:GetAngleDegrees( vec3 ) + local range = coord:Get2DDistance( position ) -- Bearing string. - local Bs=string.format('%03d°', angle) + local Bs = string.format( '%03d°', angle ) local texthit if self.PlayerSettings[playername].flaredirecthits then - texthit=string.format("Flare direct hits: ON (flare color %s)\n", self:_flarecolor2text(self.PlayerSettings[playername].flarecolor)) + texthit = string.format( "Flare direct hits: ON (flare color %s)\n", self:_flarecolor2text( self.PlayerSettings[playername].flarecolor ) ) else - texthit=string.format("Flare direct hits: OFF\n") + texthit = string.format( "Flare direct hits: OFF\n" ) end local textbomb if self.PlayerSettings[playername].smokebombimpact then - textbomb=string.format("Smoke bomb impact points: ON (smoke color %s)\n", self:_smokecolor2text(self.PlayerSettings[playername].smokecolor)) + textbomb = string.format( "Smoke bomb impact points: ON (smoke color %s)\n", self:_smokecolor2text( self.PlayerSettings[playername].smokecolor ) ) else - textbomb=string.format("Smoke bomb impact points: OFF\n") + textbomb = string.format( "Smoke bomb impact points: OFF\n" ) end local textdelay if self.PlayerSettings[playername].delaysmoke then - textdelay=string.format("Smoke bomb delay: ON (delay %.1f seconds)", self.TdelaySmoke) + textdelay = string.format( "Smoke bomb delay: ON (delay %.1f seconds)", self.TdelaySmoke ) else - textdelay=string.format("Smoke bomb delay: OFF") + textdelay = string.format( "Smoke bomb delay: OFF" ) end -- Player unit settings. - local trange=string.format("%.1f km", range/1000) - local trangealt=string.format("%d m", rangealt) - local tstrafemaxalt=string.format("%d m", self.strafemaxalt) + local trange = string.format( "%.1f km", range / 1000 ) + local trangealt = string.format( "%d m", rangealt ) + local tstrafemaxalt = string.format( "%d m", self.strafemaxalt ) if settings:IsImperial() then - trange=string.format("%.1f NM", UTILS.MetersToNM(range)) - trangealt=string.format("%d feet", UTILS.MetersToFeet(rangealt)) - tstrafemaxalt=string.format("%d feet", UTILS.MetersToFeet(self.strafemaxalt)) + trange = string.format( "%.1f NM", UTILS.MetersToNM( range ) ) + trangealt = string.format( "%d feet", UTILS.MetersToFeet( rangealt ) ) + tstrafemaxalt = string.format( "%d feet", UTILS.MetersToFeet( self.strafemaxalt ) ) end -- Message. - text=text..string.format("Information on %s:\n", self.rangename) - text=text..string.format("-------------------------------------------------------\n") - text=text..string.format("Bearing %s, Range %s\n", Bs, trange) - text=text..string.format("%s\n", bulls) - text=text..string.format("%s\n", lldms) - text=text..string.format("%s\n", llddm) - text=text..string.format("Altitude ASL: %s\n", trangealt) - text=text..string.format("Max strafing alt AGL: %s\n", tstrafemaxalt) - text=text..string.format("# of strafe targets: %d\n", self.nstrafetargets) - text=text..string.format("# of bomb targets: %d\n", self.nbombtargets) - text=text..texthit - text=text..textbomb - text=text..textdelay + text = text .. string.format( "Information on %s:\n", self.rangename ) + text = text .. string.format( "-------------------------------------------------------\n" ) + text = text .. string.format( "Bearing %s, Range %s\n", Bs, trange ) + text = text .. string.format( "%s\n", bulls ) + text = text .. string.format( "%s\n", lldms ) + text = text .. string.format( "%s\n", llddm ) + text = text .. string.format( "Altitude ASL: %s\n", trangealt ) + text = text .. string.format( "Max strafing alt AGL: %s\n", tstrafemaxalt ) + text = text .. string.format( "# of strafe targets: %d\n", self.nstrafetargets ) + text = text .. string.format( "# of bomb targets: %d\n", self.nbombtargets ) + text = text .. texthit + text = text .. textbomb + text = text .. textdelay -- Send message to player group. - self:_DisplayMessageToGroup(unit, text, nil, true, true) + self:_DisplayMessageToGroup( unit, text, nil, true, true ) -- Debug output. - self:T2(self.id..text) + self:T2( self.id .. text ) end end end @@ -2641,150 +2683,148 @@ end --- Display bombing target locations to player. -- @param #RANGE self -- @param #string _unitname Name of the player unit. -function RANGE:_DisplayBombTargets(_unitname) - self:F(_unitname) +function RANGE:_DisplayBombTargets( _unitname ) + self:F( _unitname ) -- Get player unit and player name. - local _unit, _playername = self:_GetPlayerUnitAndName(_unitname) + local _unit, _playername = self:_GetPlayerUnitAndName( _unitname ) -- Check if we have a player. if _unit and _playername then -- Player settings. - local _settings=_DATABASE:GetPlayerSettings(_playername) or _SETTINGS --Core.Settings#SETTINGS + local _settings = _DATABASE:GetPlayerSettings( _playername ) or _SETTINGS -- Core.Settings#SETTINGS -- Message text. - local _text="Bomb Target Locations:" + local _text = "Bomb Target Locations:" - for _,_bombtarget in pairs(self.bombingTargets) do - local bombtarget=_bombtarget --#RANGE.BombTarget + for _, _bombtarget in pairs( self.bombingTargets ) do + local bombtarget = _bombtarget -- #RANGE.BombTarget -- Coordinate of bombtarget. - local coord=self:_GetBombTargetCoordinate(bombtarget) + local coord = self:_GetBombTargetCoordinate( bombtarget ) if coord then - + -- Get elevation - local elevation=coord:GetLandHeight() - local eltxt=string.format("%d m", elevation) + local elevation = coord:GetLandHeight() + local eltxt = string.format( "%d m", elevation ) if not _settings:IsMetric() then - elevation=UTILS.MetersToFeet(elevation) - eltxt=string.format("%d ft", elevation) + elevation = UTILS.MetersToFeet( elevation ) + eltxt = string.format( "%d ft", elevation ) end - local ca2g=coord:ToStringA2G(_unit,_settings) - _text=_text..string.format("\n- %s:\n%s @ %s", bombtarget.name or "unknown", ca2g, eltxt) + local ca2g = coord:ToStringA2G( _unit, _settings ) + _text = _text .. string.format( "\n- %s:\n%s @ %s", bombtarget.name or "unknown", ca2g, eltxt ) end end - self:_DisplayMessageToGroup(_unit,_text, 120, true, true) + self:_DisplayMessageToGroup( _unit, _text, 120, true, true ) end end --- Display pit location and heading to player. -- @param #RANGE self -- @param #string _unitname Name of the player unit. -function RANGE:_DisplayStrafePits(_unitname) - self:F(_unitname) +function RANGE:_DisplayStrafePits( _unitname ) + self:F( _unitname ) -- Get player unit and player name. - local _unit, _playername = self:_GetPlayerUnitAndName(_unitname) + local _unit, _playername = self:_GetPlayerUnitAndName( _unitname ) -- Check if we have a player. if _unit and _playername then -- Player settings. - local _settings=_DATABASE:GetPlayerSettings(_playername) or _SETTINGS --Core.Settings#SETTINGS + local _settings = _DATABASE:GetPlayerSettings( _playername ) or _SETTINGS -- Core.Settings#SETTINGS -- Message text. - local _text="Strafe Target Locations:" + local _text = "Strafe Target Locations:" - for _,_strafepit in pairs(self.strafeTargets) do - local _target=_strafepit --Wrapper.Positionable#POSITIONABLE + for _, _strafepit in pairs( self.strafeTargets ) do + local _target = _strafepit -- Wrapper.Positionable#POSITIONABLE -- Pit parameters. - local coord=_strafepit.coordinate --Core.Point#COORDINATE - local heading=_strafepit.heading + local coord = _strafepit.coordinate -- Core.Point#COORDINATE + local heading = _strafepit.heading -- Turn heading around ==> approach heading. - if heading>180 then - heading=heading-180 + if heading > 180 then + heading = heading - 180 else - heading=heading+180 + heading = heading + 180 end - local mycoord=coord:ToStringA2G(_unit, _settings) - _text=_text..string.format("\n- %s: heading %03d°\n%s",_strafepit.name, heading, mycoord) + local mycoord = coord:ToStringA2G( _unit, _settings ) + _text = _text .. string.format( "\n- %s: heading %03d°\n%s", _strafepit.name, heading, mycoord ) end - self:_DisplayMessageToGroup(_unit,_text, nil, true, true) + self:_DisplayMessageToGroup( _unit, _text, nil, true, true ) end end - --- Report weather conditions at range. Temperature, QFE pressure and wind data. -- @param #RANGE self -- @param #string _unitname Name of the player unit. -function RANGE:_DisplayRangeWeather(_unitname) - self:F(_unitname) +function RANGE:_DisplayRangeWeather( _unitname ) + self:F( _unitname ) -- Get player unit and player name. - local unit, playername = self:_GetPlayerUnitAndName(_unitname) + local unit, playername = self:_GetPlayerUnitAndName( _unitname ) -- Check if we have a player. if unit and playername then -- Message text. - local text="" + local text = "" -- Current coordinates. - local coord=unit:GetCoordinate() + local coord = unit:GetCoordinate() if self.location then -- Get atmospheric data at range location. - local position=self.location --Core.Point#COORDINATE - local T=position:GetTemperature() - local P=position:GetPressure() - local Wd,Ws=position:GetWind() + local position = self.location -- Core.Point#COORDINATE + local T = position:GetTemperature() + local P = position:GetPressure() + local Wd, Ws = position:GetWind() -- Get Beaufort wind scale. - local Bn,Bd=UTILS.BeaufortScale(Ws) + local Bn, Bd = UTILS.BeaufortScale( Ws ) - local WD=string.format('%03d°', Wd) - local Ts=string.format("%d°C",T) + local WD = string.format( '%03d°', Wd ) + local Ts = string.format( "%d°C", T ) - local hPa2inHg=0.0295299830714 - local hPa2mmHg=0.7500615613030 + local hPa2inHg = 0.0295299830714 + local hPa2mmHg = 0.7500615613030 - local settings=_DATABASE:GetPlayerSettings(playername) or _SETTINGS --Core.Settings#SETTINGS - local tT=string.format("%d°C",T) - local tW=string.format("%.1f m/s", Ws) - local tP=string.format("%.1f mmHg", P*hPa2mmHg) + local settings = _DATABASE:GetPlayerSettings( playername ) or _SETTINGS -- Core.Settings#SETTINGS + local tT = string.format( "%d°C", T ) + local tW = string.format( "%.1f m/s", Ws ) + local tP = string.format( "%.1f mmHg", P * hPa2mmHg ) if settings:IsImperial() then - --tT=string.format("%d°F", UTILS.CelsiusToFahrenheit(T)) - tW=string.format("%.1f knots", UTILS.MpsToKnots(Ws)) - tP=string.format("%.2f inHg", P*hPa2inHg) + -- tT=string.format("%d°F", UTILS.CelsiusToFahrenheit(T)) + tW = string.format( "%.1f knots", UTILS.MpsToKnots( Ws ) ) + tP = string.format( "%.2f inHg", P * hPa2inHg ) end - -- Message text. - text=text..string.format("Weather Report at %s:\n", self.rangename) - text=text..string.format("--------------------------------------------------\n") - text=text..string.format("Temperature %s\n", tT) - text=text..string.format("Wind from %s at %s (%s)\n", WD, tW, Bd) - text=text..string.format("QFE %.1f hPa = %s", P, tP) + text = text .. string.format( "Weather Report at %s:\n", self.rangename ) + text = text .. string.format( "--------------------------------------------------\n" ) + text = text .. string.format( "Temperature %s\n", tT ) + text = text .. string.format( "Wind from %s at %s (%s)\n", WD, tW, Bd ) + text = text .. string.format( "QFE %.1f hPa = %s", P, tP ) else - text=string.format("No range location defined for range %s.", self.rangename) + text = string.format( "No range location defined for range %s.", self.rangename ) end -- Send message to player group. - self:_DisplayMessageToGroup(unit, text, nil, true, true) + self:_DisplayMessageToGroup( unit, text, nil, true, true ) -- Debug output. - self:T2(self.id..text) + self:T2( self.id .. text ) else - self:T(self.id..string.format("ERROR! Could not find player unit in RangeInfo! Name = %s", _unitname)) + self:T( self.id .. string.format( "ERROR! Could not find player unit in RangeInfo! Name = %s", _unitname ) ) end end @@ -2796,23 +2836,23 @@ end -- @param #string _unitName Name of player unit. function RANGE:_CheckPlayers() - for playername,_playersettings in pairs(self.PlayerSettings) do - local playersettings=_playersettings --#RANGE.PlayerData + for playername, _playersettings in pairs( self.PlayerSettings ) do + local playersettings = _playersettings -- #RANGE.PlayerData - local unitname=playersettings.unitname - local unit=UNIT:FindByName(unitname) + local unitname = playersettings.unitname + local unit = UNIT:FindByName( unitname ) if unit and unit:IsAlive() then - if unit:IsInZone(self.rangezone) then + if unit:IsInZone( self.rangezone ) then ------------------------------ -- Player INSIDE Range Zone -- ------------------------------ if not playersettings.inzone then - playersettings.inzone=true - self:EnterRange(playersettings) + playersettings.inzone = true + self:EnterRange( playersettings ) end else @@ -2821,9 +2861,9 @@ function RANGE:_CheckPlayers() -- Player OUTSIDE Range Zone -- ------------------------------- - if playersettings.inzone==true then - playersettings.inzone=false - self:ExitRange(playersettings) + if playersettings.inzone == true then + playersettings.inzone = false + self:ExitRange( playersettings ) end end @@ -2835,66 +2875,67 @@ end --- Check if player is inside a strafing zone. If he is, we start looking for hits. If he was and left the zone again, the result is stored. -- @param #RANGE self -- @param #string _unitName Name of player unit. -function RANGE:_CheckInZone(_unitName) - self:F2(_unitName) +function RANGE:_CheckInZone( _unitName ) + self:F2( _unitName ) -- Get player unit and name. - local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) - local unitheading = 0 --RangeBoss + local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) + local unitheading = 0 -- RangeBoss 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. - local function checkme(targetheading, _zone) - local zone=_zone --Core.Zone#ZONE + local function checkme( targetheading, _zone ) + local zone = _zone -- Core.Zone#ZONE -- Heading check. - local unitheading = _unit:GetHeading() - unitheadingStrafe = _unit:GetHeading() --RangeBoss - local pitheading = targetheading-180 - local deltaheading = unitheading-pitheading - local towardspit = math.abs(deltaheading)<=90 or math.abs(deltaheading-360)<=90 - + local unitheading = _unit:GetHeading() + local pitheading = targetheading - 180 + local deltaheading = unitheading - pitheading + local towardspit = math.abs( deltaheading ) <= 90 or math.abs( deltaheading - 360 ) <= 90 + if towardspit then - - local vec3=_unit:GetVec3() - local vec2={x=vec3.x, y=vec3.z} --DCS#Vec2 - local landheight=land.getHeight(vec2) - local unitalt=vec3.y-landheight - - if unitalt<=self.strafemaxalt then - local unitinzone=zone:IsVec2InZone(vec2) + + local vec3 = _unit:GetVec3() + local vec2 = { x = vec3.x, y = vec3.z } -- DCS#Vec2 + local landheight = land.getHeight( vec2 ) + local unitalt = vec3.y - landheight + + if unitalt <= self.strafemaxalt then + local unitinzone = zone:IsVec2InZone( vec2 ) return unitinzone end end - + return false end -- Current position of player unit. - local _unitID = _unit:GetID() + local _unitID = _unit:GetID() -- 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. -- Get the current approach zone and check if player is inside. - local zone=_currentStrafeRun.zone.polygon --Core.Zone#ZONE_POLYGON_BASE + local zone = _currentStrafeRun.zone.polygon -- Core.Zone#ZONE_POLYGON_BASE -- Check if unit in zone and facing the right direction. - local unitinzone=checkme(_currentStrafeRun.zone.heading, zone) + local unitinzone = checkme( _currentStrafeRun.zone.heading, zone ) -- Check if player is in strafe zone and below max alt. if unitinzone then - StrafeAircraftType = _unit:GetTypeName() --RangeBoss -- Still in zone, keep counting hits. Increase counter. - _currentStrafeRun.time = _currentStrafeRun.time+1 + _currentStrafeRun.time = _currentStrafeRun.time + 1 else -- Increase counter - _currentStrafeRun.time = _currentStrafeRun.time+1 + _currentStrafeRun.time = _currentStrafeRun.time + 1 if _currentStrafeRun.time <= 3 then @@ -2902,23 +2943,25 @@ function RANGE:_CheckInZone(_unitName) self.strafeStatus[_unitID] = nil -- Message text. - local _msg = string.format("%s left strafing zone %s too quickly. No Score.", _playername, _currentStrafeRun.zone.name) + local _msg = string.format( "%s left strafing zone %s too quickly. No Score.", _playername, _currentStrafeRun.zone.name ) -- Send message. - self:_DisplayMessageToGroup(_unit, _msg, nil, true) - + self:_DisplayMessageToGroup( _unit, _msg, nil, true ) + if self.rangecontrol then - self.rangecontrol:NewTransmission(RANGE.Sound.RCLeftStrafePitTooQuickly.filename, RANGE.Sound.RCLeftStrafePitTooQuickly.duration, self.soundpath) + self.rangecontrol:NewTransmission( RANGE.Sound.RCLeftStrafePitTooQuickly.filename, RANGE.Sound.RCLeftStrafePitTooQuickly.duration, self.soundpath ) end else -- Get current ammo. - local _ammo=self:_GetAmmo(_unitName) + local _ammo = self:_GetAmmo( _unitName ) -- Result. - local _result = self.strafeStatus[_unitID] - local _sound = nil --#RANGE.Soundfile + local _result = self.strafeStatus[_unitID] --#RANGE.StrafeStatus + + local _sound = nil -- #RANGE.Soundfile + --[[ --RangeBoss commented out in order to implement strafe quality based on accuracy percentage, not the number of rounds on target -- Judge this pass. Text is displayed on summary. if _result.hits >= _result.zone.goodPass*2 then @@ -2935,98 +2978,84 @@ function RANGE:_CheckInZone(_unitName) _sound=RANGE.Sound.RCPoorPass end ]] + -- Calculate accuracy of run. Number of hits wrt number of rounds fired. - local shots=_result.ammo-_ammo - local accur=0 - if shots>0 then - accur=_result.hits/shots*100 - if accur > 100 then accur = 100 end + local shots = _result.ammo - _ammo + local accur = 0 + if shots > 0 then + accur = _result.hits / shots * 100 + if accur > 100 then + accur = 100 + end end - - if invalidStrafe == true then-- - _result.text = "* INVALID - PASSED FOUL LINE *" - _sound=RANGE.Sound.RCPoorPass -- + + -- Results text and sound message. + local resulttext="" + if _result.pastfoulline == true then -- + resulttext = "* INVALID - PASSED FOUL LINE *" + _sound = RANGE.Sound.RCPoorPass -- else if accur >= 90 then - _result.text = "DEADEYE PASS" - _sound=RANGE.Sound.RCExcellentPass + resulttext = "DEADEYE PASS" + _sound = RANGE.Sound.RCExcellentPass elseif accur >= 75 then - _result.text = "EXCELLENT PASS" - _sound=RANGE.Sound.RCExcellentPass + resulttext = "EXCELLENT PASS" + _sound = RANGE.Sound.RCExcellentPass elseif accur >= 50 then - _result.text = "GOOD PASS" - _sound=RANGE.Sound.RCGoodPass + resulttext = "GOOD PASS" + _sound = RANGE.Sound.RCGoodPass elseif accur >= 25 then - _result.text = "INEFFECTIVE PASS" - _sound=RANGE.Sound.RCIneffectivePass + resulttext = "INEFFECTIVE PASS" + _sound = RANGE.Sound.RCIneffectivePass else - _result.text = "POOR PASS" - _sound=RANGE.Sound.RCPoorPass + resulttext = "POOR PASS" + _sound = RANGE.Sound.RCPoorPass end end - clientStrafed = true --RANGEBOSS -- 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 ) if shots and accur then - _text=_text..string.format("\nTotal rounds fired %d. Accuracy %.1f %%.", shots, accur) + _text = _text .. string.format( "\nTotal rounds fired %d. Accuracy %.1f %%.", shots, accur ) end - _text=_text..string.format("\n%s", _result.text) + _text = _text .. string.format( "\n%s", _result.text ) -- Send message. - self:_DisplayMessageToGroup(_unit, _text) + self:_DisplayMessageToGroup( _unit, _text ) - --RangeBoss Edit for strafe table insert - - -- Local results. - - local result={} --#RANGE.BombResult + -- Strafe result. + local result = {} -- #RANGE.StrafeResult + result.player=_playername 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.airframe=StrafeAircraftType - result.roundsFired=shots --RANGEBOSS - result.roundsHit=_result.hits --RANGEBOSS - result.roundsQuality=_result.text --RANGEBOSS - result.strafeAccuracy=accur - result.heading =unitheadingStrafe --RANGEBOSS + result.time = timer.getAbsTime() + result.roundsFired = shots + result.roundsHit = _result.hits + result.roundsQuality = resulttext + result.strafeAccuracy = accur + result.rangename = self.rangename + result.airframe=playerData.airframe + result.invalid = _result.pastfoulline + + -- Griger Results. + self:StrafeResult(playerData, result) - Straferesult.name= _result.zone.name or "unknown" - Straferesult.distance=0 - 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. - if playerData and playerData.targeton and self.targetsheet then - self:_SaveTargetSheet(_playername, result) - end - --RangeBoss edit for strafe data saved to file + -- Save trap sheet. + if playerData and playerData.targeton and self.targetsheet then + self:_SaveTargetSheet( _playername, result ) + end -- Voice over. - if self.rangecontrol then - self.rangecontrol:NewTransmission(RANGE.Sound.RCHitsOnTarget.filename, RANGE.Sound.RCHitsOnTarget.duration, self.soundpath) - self.rangecontrol:Number2Transmission(string.format("%d", _result.hits)) + if self.rangecontrol then + self.rangecontrol:NewTransmission( RANGE.Sound.RCHitsOnTarget.filename, RANGE.Sound.RCHitsOnTarget.duration, self.soundpath ) + self.rangecontrol:Number2Transmission( string.format( "%d", _result.hits ) ) if shots and accur then - self.rangecontrol:NewTransmission(RANGE.Sound.RCTotalRoundsFired.filename, RANGE.Sound.RCTotalRoundsFired.duration, self.soundpath, nil, 0.2) - self.rangecontrol:Number2Transmission(string.format("%d", shots), nil, 0.2) - self.rangecontrol:NewTransmission(RANGE.Sound.RCAccuracy.filename, RANGE.Sound.RCAccuracy.duration, self.soundpath, nil, 0.2) - self.rangecontrol:Number2Transmission(string.format("%d", UTILS.Round(accur, 0))) - self.rangecontrol:NewTransmission(RANGE.Sound.RCPercent.filename, RANGE.Sound.RCPercent.duration, self.soundpath) + self.rangecontrol:NewTransmission( RANGE.Sound.RCTotalRoundsFired.filename, RANGE.Sound.RCTotalRoundsFired.duration, self.soundpath, nil, 0.2 ) + self.rangecontrol:Number2Transmission( string.format( "%d", shots ), nil, 0.2 ) + self.rangecontrol:NewTransmission( RANGE.Sound.RCAccuracy.filename, RANGE.Sound.RCAccuracy.duration, self.soundpath, nil, 0.2 ) + self.rangecontrol:Number2Transmission( string.format( "%d", UTILS.Round( accur, 0 ) ) ) + self.rangecontrol:NewTransmission( RANGE.Sound.RCPercent.filename, RANGE.Sound.RCPercent.duration, self.soundpath ) end - self.rangecontrol:NewTransmission(_sound.filename, _sound.duration, self.soundpath, nil, 0.5) + self.rangecontrol:NewTransmission( _sound.filename, _sound.duration, self.soundpath, nil, 0.5 ) end -- Set strafe status to nil. @@ -3034,7 +3063,7 @@ function RANGE:_CheckInZone(_unitName) -- Save stats so the player can retrieve them. local _stats = self.strafePlayerResults[_playername] or {} - table.insert(_stats, _result) + table.insert( _stats, result ) self.strafePlayerResults[_playername] = _stats end @@ -3043,34 +3072,36 @@ function RANGE:_CheckInZone(_unitName) else -- 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. - 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. - local unitinzone=checkme(_targetZone.heading, zone) + local unitinzone = checkme( target.heading, zone ) -- Player is inside zone. if unitinzone then -- Get ammo at the beginning of the run. - local _ammo=self:_GetAmmo(_unitName) + local _ammo = self:_GetAmmo( _unitName ) -- 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! - 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 - self.rangecontrol:NewTransmission(RANGE.Sound.RCRollingInOnStrafeTarget.filename, RANGE.Sound.RCRollingInOnStrafeTarget.duration, self.soundpath) - end - clientRollingIn = true --RANGEBOSS + self.rangecontrol:NewTransmission( RANGE.Sound.RCRollingInOnStrafeTarget.filename, RANGE.Sound.RCRollingInOnStrafeTarget.duration, self.soundpath ) + end -- Send message. - self:_DisplayMessageToGroup(_unit, _msg, 10, true) - hypemanStrafeRollIn = _msg --RANGEBOSS + self:_DisplayMessageToGroup( _unit, _msg, 10, true ) + + -- Trigger event that player is rolling in. + self:RollingIn(playerData, target) -- We found our player. Skip remaining checks. break @@ -3090,18 +3121,18 @@ end --- Add menu commands for player. -- @param #RANGE self -- @param #string _unitName Name of player unit. -function RANGE:_AddF10Commands(_unitName) - self:F(_unitName) +function RANGE:_AddF10Commands( _unitName ) + self:F( _unitName ) -- Get player unit and name. - local _unit, playername = self:_GetPlayerUnitAndName(_unitName) + local _unit, playername = self:_GetPlayerUnitAndName( _unitName ) -- Check for player unit. if _unit and playername then -- Get group and ID. - local group=_unit:GetGroup() - local _gid=group:GetID() + local group = _unit:GetGroup() + local _gid = group:GetID() if group and _gid then @@ -3111,7 +3142,7 @@ function RANGE:_AddF10Commands(_unitName) self.MenuAddedTo[_gid] = true -- Range root menu path. - local _rangePath=nil + local _rangePath = nil if RANGE.MenuF10Root then @@ -3119,8 +3150,8 @@ function RANGE:_AddF10Commands(_unitName) -- MISSION LEVEL -- ------------------- - --_rangePath = missionCommands.addSubMenuForGroup(_gid, self.rangename, RANGE.MenuF10Root) - _rangePath = MENU_GROUP:New(group,"On the Range") + -- _rangePath = missionCommands.addSubMenuForGroup(_gid, self.rangename, RANGE.MenuF10Root) + _rangePath = MENU_GROUP:New( group, "On the Range" ) else @@ -3130,63 +3161,63 @@ function RANGE:_AddF10Commands(_unitName) -- Main F10 menu: F10/On the Range// if RANGE.MenuF10[_gid] == nil then - --RANGE.MenuF10[_gid]=missionCommands.addSubMenuForGroup(_gid, "On the Range") - RANGE.MenuF10[_gid]=MENU_GROUP:New(group,"On the Range") + -- RANGE.MenuF10[_gid]=missionCommands.addSubMenuForGroup(_gid, "On the Range") + RANGE.MenuF10[_gid] = MENU_GROUP:New( group, "On the Range" ) end - --_rangePath = missionCommands.addSubMenuForGroup(_gid, self.rangename, RANGE.MenuF10[_gid]) - _rangePath = MENU_GROUP:New(group,self.rangename,RANGE.MenuF10[_gid]) + -- _rangePath = missionCommands.addSubMenuForGroup(_gid, self.rangename, RANGE.MenuF10[_gid]) + _rangePath = MENU_GROUP:New( group, self.rangename, RANGE.MenuF10[_gid] ) end - - local _statsPath = MENU_GROUP:New(group,"Statistics",_rangePath) - local _markPath = MENU_GROUP:New(group,"Mark Targets",_rangePath) - local _settingsPath = MENU_GROUP:New(group,"My Settings",_rangePath) - local _infoPath = MENU_GROUP:New(group,"Range Info",_rangePath) - - -- F10/On the Range//My Settings/ - local _mysmokePath = MENU_GROUP:New(group,"Smoke Color",_settingsPath) - local _myflarePath = MENU_GROUP:New(group,"Flare Color",_settingsPath) - --F10/On the Range//Mark Targets/ - local _MoMap = MENU_GROUP_COMMAND:New(group,"Mark On Map",_markPath,self._MarkTargetsOnMap, self, _unitName) - local _IllRng = MENU_GROUP_COMMAND:New(group, "Illuminate Range", _markPath, self._IlluminateBombTargets, self, _unitName) - local _SSpit = MENU_GROUP_COMMAND:New(group, "Smoke Strafe Pits", _markPath, self._SmokeStrafeTargetBoxes, self, _unitName) - local _SStgts = MENU_GROUP_COMMAND:New(group, "Smoke Strafe Tgts", _markPath, self._SmokeStrafeTargets, self, _unitName) - local _SBtgts = MENU_GROUP_COMMAND:New(group, "Smoke Bomb Tgts", _markPath, self._SmokeBombTargets, self, _unitName) - -- F10/On the Range//Stats/ - local _AllSR = MENU_GROUP_COMMAND:New(group, "All Strafe Results", _statsPath, self._DisplayStrafePitResults, self, _unitName) - local _AllBR = MENU_GROUP_COMMAND:New(group, "All Bombing Results", _statsPath, self._DisplayBombingResults, self, _unitName) - local _MySR = MENU_GROUP_COMMAND:New(group, "My Strafe Results", _statsPath, self._DisplayMyStrafePitResults, self, _unitName) - local _MyBR = MENU_GROUP_COMMAND:New(group, "My Bomb Results", _statsPath, self._DisplayMyBombingResults, self, _unitName) - local _ResetST = MENU_GROUP_COMMAND:New(group, "Reset All Stats", _statsPath, self._ResetRangeStats, self, _unitName) - -- F10/On the Range//My Settings/Smoke Color/ - local _BlueSM = MENU_GROUP_COMMAND:New(group, "Blue Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Blue) - local _GrSM = MENU_GROUP_COMMAND:New(group, "Green Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Green) - local _OrSM = MENU_GROUP_COMMAND:New(group, "Orange Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Orange) - local _ReSM = MENU_GROUP_COMMAND:New(group, "Red Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Red) - local _WhSm = MENU_GROUP_COMMAND:New(group, "White Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.White) - -- F10/On the Range//My Settings/Flare Color/ - local _GrFl = MENU_GROUP_COMMAND:New(group, "Green Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.Green) - local _ReFl = MENU_GROUP_COMMAND:New(group, "Red Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.Red) - local _WhFl = MENU_GROUP_COMMAND:New(group, "White Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.White) - local _YeFl = MENU_GROUP_COMMAND:New(group, "Yellow Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.Yellow) + local _statsPath = MENU_GROUP:New( group, "Statistics", _rangePath ) + local _markPath = MENU_GROUP:New( group, "Mark Targets", _rangePath ) + local _settingsPath = MENU_GROUP:New( group, "My Settings", _rangePath ) + local _infoPath = MENU_GROUP:New( group, "Range Info", _rangePath ) + -- F10/On the Range//My Settings/ - local _SmDe = MENU_GROUP_COMMAND:New(group, "Smoke Delay On/Off", _settingsPath, self._SmokeBombDelayOnOff, self, _unitName) - local _SmIm = MENU_GROUP_COMMAND:New(group, "Smoke Impact On/Off", _settingsPath, self._SmokeBombImpactOnOff, self, _unitName) - local _FlHi = MENU_GROUP_COMMAND:New(group, "Flare Hits On/Off", _settingsPath, self._FlareDirectHitsOnOff, self, _unitName) - local _AlMeA = MENU_GROUP_COMMAND:New(group, "All Messages On/Off", _settingsPath, self._MessagesToPlayerOnOff, self, _unitName) - local _TrpSh = MENU_GROUP_COMMAND:New(group, "Targetsheet On/Off", _settingsPath, self._TargetsheetOnOff, self, _unitName) + local _mysmokePath = MENU_GROUP:New( group, "Smoke Color", _settingsPath ) + local _myflarePath = MENU_GROUP:New( group, "Flare Color", _settingsPath ) + + -- F10/On the Range//Mark Targets/ + local _MoMap = MENU_GROUP_COMMAND:New( group, "Mark On Map", _markPath, self._MarkTargetsOnMap, self, _unitName ) + local _IllRng = MENU_GROUP_COMMAND:New( group, "Illuminate Range", _markPath, self._IlluminateBombTargets, self, _unitName ) + local _SSpit = MENU_GROUP_COMMAND:New( group, "Smoke Strafe Pits", _markPath, self._SmokeStrafeTargetBoxes, self, _unitName ) + local _SStgts = MENU_GROUP_COMMAND:New( group, "Smoke Strafe Tgts", _markPath, self._SmokeStrafeTargets, self, _unitName ) + local _SBtgts = MENU_GROUP_COMMAND:New( group, "Smoke Bomb Tgts", _markPath, self._SmokeBombTargets, self, _unitName ) + -- F10/On the Range//Stats/ + local _AllSR = MENU_GROUP_COMMAND:New( group, "All Strafe Results", _statsPath, self._DisplayStrafePitResults, self, _unitName ) + local _AllBR = MENU_GROUP_COMMAND:New( group, "All Bombing Results", _statsPath, self._DisplayBombingResults, self, _unitName ) + local _MySR = MENU_GROUP_COMMAND:New( group, "My Strafe Results", _statsPath, self._DisplayMyStrafePitResults, self, _unitName ) + local _MyBR = MENU_GROUP_COMMAND:New( group, "My Bomb Results", _statsPath, self._DisplayMyBombingResults, self, _unitName ) + local _ResetST = MENU_GROUP_COMMAND:New( group, "Reset All Stats", _statsPath, self._ResetRangeStats, self, _unitName ) + -- F10/On the Range//My Settings/Smoke Color/ + local _BlueSM = MENU_GROUP_COMMAND:New( group, "Blue Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Blue ) + local _GrSM = MENU_GROUP_COMMAND:New( group, "Green Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Green ) + local _OrSM = MENU_GROUP_COMMAND:New( group, "Orange Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Orange ) + local _ReSM = MENU_GROUP_COMMAND:New( group, "Red Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Red ) + local _WhSm = MENU_GROUP_COMMAND:New( group, "White Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.White ) + -- F10/On the Range//My Settings/Flare Color/ + local _GrFl = MENU_GROUP_COMMAND:New( group, "Green Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.Green ) + local _ReFl = MENU_GROUP_COMMAND:New( group, "Red Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.Red ) + local _WhFl = MENU_GROUP_COMMAND:New( group, "White Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.White ) + local _YeFl = MENU_GROUP_COMMAND:New( group, "Yellow Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.Yellow ) + -- F10/On the Range//My Settings/ + local _SmDe = MENU_GROUP_COMMAND:New( group, "Smoke Delay On/Off", _settingsPath, self._SmokeBombDelayOnOff, self, _unitName ) + local _SmIm = MENU_GROUP_COMMAND:New( group, "Smoke Impact On/Off", _settingsPath, self._SmokeBombImpactOnOff, self, _unitName ) + local _FlHi = MENU_GROUP_COMMAND:New( group, "Flare Hits On/Off", _settingsPath, self._FlareDirectHitsOnOff, self, _unitName ) + local _AlMeA = MENU_GROUP_COMMAND:New( group, "All Messages On/Off", _settingsPath, self._MessagesToPlayerOnOff, self, _unitName ) + local _TrpSh = MENU_GROUP_COMMAND:New( group, "Targetsheet On/Off", _settingsPath, self._TargetsheetOnOff, self, _unitName ) -- F10/On the Range//Range Information - local _WeIn = MENU_GROUP_COMMAND:New(group, "General Info", _infoPath, self._DisplayRangeInfo, self, _unitName) - local _WeRe = MENU_GROUP_COMMAND:New(group, "Weather Report", _infoPath, self._DisplayRangeWeather, self, _unitName) - local _BoTgtgs = MENU_GROUP_COMMAND:New(group, "Bombing Targets", _infoPath, self._DisplayBombTargets, self, _unitName) - local _StrPits = MENU_GROUP_COMMAND:New(group, "Strafe Pits", _infoPath, self._DisplayStrafePits, self, _unitName):Refresh() + local _WeIn = MENU_GROUP_COMMAND:New( group, "General Info", _infoPath, self._DisplayRangeInfo, self, _unitName ) + local _WeRe = MENU_GROUP_COMMAND:New( group, "Weather Report", _infoPath, self._DisplayRangeWeather, self, _unitName ) + local _BoTgtgs = MENU_GROUP_COMMAND:New( group, "Bombing Targets", _infoPath, self._DisplayBombTargets, self, _unitName ) + local _StrPits = MENU_GROUP_COMMAND:New( group, "Strafe Pits", _infoPath, self._DisplayStrafePits, self, _unitName ):Refresh() end else - self:E(self.id.."Could not find group or group ID in AddF10Menu() function. Unit name: ".._unitName) + self:E( self.id .. "Could not find group or group ID in AddF10Menu() function. Unit name: " .. _unitName ) end else - self:E(self.id.."Player unit does not exist in AddF10Menu() function. Unit name: ".._unitName) + self:E( self.id .. "Player unit does not exist in AddF10Menu() function. Unit name: " .. _unitName ) end end @@ -3199,80 +3230,79 @@ end -- @param #RANGE self -- @param #RANGE.BombTarget target Bomb target data. -- @return Core.Point#COORDINATE Target coordinate. -function RANGE:_GetBombTargetCoordinate(target) +function RANGE:_GetBombTargetCoordinate( target ) - local coord=nil --Core.Point#COORDINATE + local coord = nil -- Core.Point#COORDINATE - if target.type==RANGE.TargetType.UNIT then + if target.type == RANGE.TargetType.UNIT then if not target.move then -- Target should not move. - coord=target.coordinate + coord = target.coordinate else -- Moving target. Check if alive and get current position if target.target and target.target:IsAlive() then - coord=target.target:GetCoordinate() + coord = target.target:GetCoordinate() end end - elseif target.type==RANGE.TargetType.STATIC then + elseif target.type == RANGE.TargetType.STATIC then -- Static targets dont move. - coord=target.coordinate + coord = target.coordinate - elseif target.type==RANGE.TargetType.COORD then + elseif target.type == RANGE.TargetType.COORD then -- Coordinates dont move. - coord=target.coordinate + coord = target.coordinate else - self:E(self.id.."ERROR: Unknown target type.") + self:E( self.id .. "ERROR: Unknown target type." ) end return coord end - --- Get the number of shells a unit currently has. -- @param #RANGE self -- @param #string unitname Name of the player unit. -- @return Number of shells left -function RANGE:_GetAmmo(unitname) - self:F2(unitname) +function RANGE:_GetAmmo( unitname ) + self:F2( unitname ) -- Init counter. - local ammo=0 + local ammo = 0 - local unit, playername = self:_GetPlayerUnitAndName(unitname) + local unit, playername = self:_GetPlayerUnitAndName( unitname ) if unit and playername then - local has_ammo=false + local has_ammo = false - local ammotable=unit:GetAmmo() - self:T2({ammotable=ammotable}) + local ammotable = unit:GetAmmo() + self:T2( { ammotable = ammotable } ) if ammotable ~= nil then - local weapons=#ammotable - self:T2(self.id..string.format("Number of weapons %d.", weapons)) + local weapons = #ammotable + self:T2( self.id .. string.format( "Number of weapons %d.", weapons ) ) - for w=1,weapons do + for w = 1, weapons do - local Nammo=ammotable[w]["count"] - local Tammo=ammotable[w]["desc"]["typeName"] + local Nammo = ammotable[w]["count"] + local Tammo = ammotable[w]["desc"]["typeName"] -- We are specifically looking for shells here. - if string.match(Tammo, "shell") then + if string.match( Tammo, "shell" ) then -- Add up all shells - ammo=ammo+Nammo + ammo = ammo + Nammo - local text=string.format("Player %s has %d rounds ammo of type %s", playername, Nammo, Tammo) - self:T(self.id..text) + local text = string.format( "Player %s has %d rounds ammo of type %s", playername, Nammo, Tammo ) + self:T( self.id .. text ) else - local text=string.format("Player %s has %d ammo of type %s", playername, Nammo, Tammo) - self:T(self.id..text) + local text = string.format( "Player %s has %d ammo of type %s", playername, Nammo, Tammo ) + self:T( self.id .. text ) end end end @@ -3284,46 +3314,46 @@ end --- Mark targets on F10 map. -- @param #RANGE self -- @param #string _unitName Name of the player unit. -function RANGE:_MarkTargetsOnMap(_unitName) - self:F(_unitName) +function RANGE:_MarkTargetsOnMap( _unitName ) + self:F( _unitName ) -- Get group. - local group=nil --Wrapper.Group#GROUP + local group = nil -- Wrapper.Group#GROUP if _unitName then - group=UNIT:FindByName(_unitName):GetGroup() + group = UNIT:FindByName( _unitName ):GetGroup() end -- Mark bomb targets. - for _,_bombtarget in pairs(self.bombingTargets) do - local bombtarget=_bombtarget --#RANGE.BombTarget - local coord=self:_GetBombTargetCoordinate(_bombtarget) + for _, _bombtarget in pairs( self.bombingTargets ) do + local bombtarget = _bombtarget -- #RANGE.BombTarget + local coord = self:_GetBombTargetCoordinate( _bombtarget ) if group then - coord:MarkToGroup(string.format("Bomb target %s:\n%s\n%s", bombtarget.name, coord:ToStringLLDMS(), coord:ToStringBULLS(group:GetCoalition())), group) + coord:MarkToGroup( string.format( "Bomb target %s:\n%s\n%s", bombtarget.name, coord:ToStringLLDMS(), coord:ToStringBULLS( group:GetCoalition() ) ), group ) else - coord:MarkToAll(string.format("Bomb target %s", bombtarget.name)) + coord:MarkToAll( string.format( "Bomb target %s", bombtarget.name ) ) end end -- Mark strafe targets. - for _,_strafepit in pairs(self.strafeTargets) do - for _,_target in pairs(_strafepit.targets) do - local _target=_target --Wrapper.Positionable#POSITIONABLE + for _, _strafepit in pairs( self.strafeTargets ) do + for _, _target in pairs( _strafepit.targets ) do + local _target = _target -- Wrapper.Positionable#POSITIONABLE if _target and _target:IsAlive() then - local coord=_target:GetCoordinate() --Core.Point#COORDINATE + local coord = _target:GetCoordinate() -- Core.Point#COORDINATE if group then - --coord:MarkToGroup("Strafe target ".._target:GetName(), group) - coord:MarkToGroup(string.format("Strafe target %s:\n%s\n%s", _target:GetName(), coord:ToStringLLDMS(), coord:ToStringBULLS(group:GetCoalition())), group) + -- coord:MarkToGroup("Strafe target ".._target:GetName(), group) + coord:MarkToGroup( string.format( "Strafe target %s:\n%s\n%s", _target:GetName(), coord:ToStringLLDMS(), coord:ToStringBULLS( group:GetCoalition() ) ), group ) else - coord:MarkToAll("Strafe target ".._target:GetName()) + coord:MarkToAll( "Strafe target " .. _target:GetName() ) end end end end if _unitName then - local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) - local text=string.format("%s, %s, range targets are now marked on F10 map.", self.rangename, _playername) - self:_DisplayMessageToGroup(_unit, text, 5) + local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) + local text = string.format( "%s, %s, range targets are now marked on F10 map.", self.rangename, _playername ) + self:_DisplayMessageToGroup( _unit, text, 5 ) end end @@ -3331,67 +3361,67 @@ end --- Illuminate targets. Fires illumination bombs at one random bomb and one random strafe target at a random altitude between 400 and 800 m. -- @param #RANGE self -- @param #string _unitName (Optional) Name of the player unit. -function RANGE:_IlluminateBombTargets(_unitName) - self:F(_unitName) +function RANGE:_IlluminateBombTargets( _unitName ) + self:F( _unitName ) -- All bombing target coordinates. - local bomb={} + local bomb = {} - for _,_bombtarget in pairs(self.bombingTargets) do - local _target=_bombtarget.target --Wrapper.Positionable#POSITIONABLE - local coord=self:_GetBombTargetCoordinate(_bombtarget) + for _, _bombtarget in pairs( self.bombingTargets ) do + local _target = _bombtarget.target -- Wrapper.Positionable#POSITIONABLE + local coord = self:_GetBombTargetCoordinate( _bombtarget ) if coord then - table.insert(bomb, coord) + table.insert( bomb, coord ) end end - if #bomb>0 then - local coord=bomb[math.random(#bomb)] --Core.Point#COORDINATE - local c=COORDINATE:New(coord.x,coord.y+math.random(self.illuminationminalt,self.illuminationmaxalt),coord.z) + if #bomb > 0 then + local coord = bomb[math.random( #bomb )] -- Core.Point#COORDINATE + local c = COORDINATE:New( coord.x, coord.y + math.random( self.illuminationminalt, self.illuminationmaxalt ), coord.z ) c:IlluminationBomb() end -- All strafe target coordinates. - local strafe={} + local strafe = {} - for _,_strafepit in pairs(self.strafeTargets) do - for _,_target in pairs(_strafepit.targets) do - local _target=_target --Wrapper.Positionable#POSITIONABLE + for _, _strafepit in pairs( self.strafeTargets ) do + for _, _target in pairs( _strafepit.targets ) do + local _target = _target -- Wrapper.Positionable#POSITIONABLE if _target and _target:IsAlive() then - local coord=_target:GetCoordinate() --Core.Point#COORDINATE - table.insert(strafe, coord) + local coord = _target:GetCoordinate() -- Core.Point#COORDINATE + table.insert( strafe, coord ) end end end -- Pick a random strafe target. - if #strafe>0 then - local coord=strafe[math.random(#strafe)] --Core.Point#COORDINATE - local c=COORDINATE:New(coord.x,coord.y+math.random(self.illuminationminalt,self.illuminationmaxalt),coord.z) + if #strafe > 0 then + local coord = strafe[math.random( #strafe )] -- Core.Point#COORDINATE + local c = COORDINATE:New( coord.x, coord.y + math.random( self.illuminationminalt, self.illuminationmaxalt ), coord.z ) c:IlluminationBomb() end if _unitName then - local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) - local text=string.format("%s, %s, range targets are illuminated.", self.rangename, _playername) - self:_DisplayMessageToGroup(_unit, text, 5) + local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) + local text = string.format( "%s, %s, range targets are illuminated.", self.rangename, _playername ) + self:_DisplayMessageToGroup( _unit, text, 5 ) end end --- Reset player statistics. -- @param #RANGE self -- @param #string _unitName Name of the player unit. -function RANGE:_ResetRangeStats(_unitName) - self:F(_unitName) +function RANGE:_ResetRangeStats( _unitName ) + self:F( _unitName ) -- Get player unit and name. - local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) + local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) if _unit and _playername then self.strafePlayerResults[_playername] = nil self.bombPlayerResults[_playername] = nil - local text=string.format("%s, %s, your range stats were cleared.", self.rangename, _playername) - self:DisplayMessageToGroup(_unit, text, 5, false, true) + local text = string.format( "%s, %s, your range stats were cleared.", self.rangename, _playername ) + self:DisplayMessageToGroup( _unit, text, 5, false, true ) end end @@ -3402,19 +3432,19 @@ end -- @param #number _time Duration how long the message is displayed. -- @param #boolean _clear Clear up old messages. -- @param #boolean display If true, display message regardless of player setting "Messages Off". -function RANGE:_DisplayMessageToGroup(_unit, _text, _time, _clear, display) - self:F({unit=_unit, text=_text, time=_time, clear=_clear}) +function RANGE:_DisplayMessageToGroup( _unit, _text, _time, _clear, display ) + self:F( { unit = _unit, text = _text, time = _time, clear = _clear } ) -- Defaults - _time=_time or self.Tmsg - if _clear==nil or _clear==false then - _clear=false + _time = _time or self.Tmsg + if _clear == nil or _clear == false then + _clear = false else - _clear=true + _clear = true end -- Messages globally disabled. - if self.messages==false then + if self.messages == false then return end @@ -3422,22 +3452,22 @@ function RANGE:_DisplayMessageToGroup(_unit, _text, _time, _clear, display) if _unit and _unit:IsAlive() then -- Group ID. - local _gid=_unit:GetGroup():GetID() + local _gid = _unit:GetGroup():GetID() -- Get playername and player settings - local _, playername=self:_GetPlayerUnitAndName(_unit:GetName()) - local playermessage=self.PlayerSettings[playername].messages + 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) + if _gid and (playermessage == true or display) and (not self.examinerexclusive) then + trigger.action.outTextForGroup( _gid, _text, _time, _clear ) end -- Send message to examiner. - if self.examinergroupname~=nil then - local _examinerid=GROUP:FindByName(self.examinergroupname):GetID() + if self.examinergroupname ~= nil then + local _examinerid = GROUP:FindByName( self.examinergroupname ):GetID() if _examinerid then - trigger.action.outTextForGroup(_examinerid, _text, _time, _clear) + trigger.action.outTextForGroup( _examinerid, _text, _time, _clear ) end end end @@ -3447,20 +3477,20 @@ end --- Toggle status of smoking bomb impact points. -- @param #RANGE self -- @param #string unitname Name of the player unit. -function RANGE:_SmokeBombImpactOnOff(unitname) - self:F(unitname) +function RANGE:_SmokeBombImpactOnOff( unitname ) + self:F( unitname ) - local unit, playername = self:_GetPlayerUnitAndName(unitname) + local unit, playername = self:_GetPlayerUnitAndName( unitname ) if unit and playername then local text - if self.PlayerSettings[playername].smokebombimpact==true then - self.PlayerSettings[playername].smokebombimpact=false - text=string.format("%s, %s, smoking impact points of bombs is now OFF.", self.rangename, playername) + if self.PlayerSettings[playername].smokebombimpact == true then + self.PlayerSettings[playername].smokebombimpact = false + text = string.format( "%s, %s, smoking impact points of bombs is now OFF.", self.rangename, playername ) else - self.PlayerSettigs[playername].smokebombimpact=true - text=string.format("%s, %s, smoking impact points of bombs is now ON.", self.rangename, playername) + self.PlayerSettigs[playername].smokebombimpact = true + text = string.format( "%s, %s, smoking impact points of bombs is now ON.", self.rangename, playername ) end - self:_DisplayMessageToGroup(unit, text, 5, false, true) + self:_DisplayMessageToGroup( unit, text, 5, false, true ) end end @@ -3468,20 +3498,20 @@ end --- Toggle status of time delay for smoking bomb impact points -- @param #RANGE self -- @param #string unitname Name of the player unit. -function RANGE:_SmokeBombDelayOnOff(unitname) - self:F(unitname) +function RANGE:_SmokeBombDelayOnOff( unitname ) + self:F( unitname ) - local unit, playername = self:_GetPlayerUnitAndName(unitname) + local unit, playername = self:_GetPlayerUnitAndName( unitname ) if unit and playername then local text - if self.PlayerSettings[playername].delaysmoke==true then - self.PlayerSettings[playername].delaysmoke=false - text=string.format("%s, %s, delayed smoke of bombs is now OFF.", self.rangename, playername) + if self.PlayerSettings[playername].delaysmoke == true then + self.PlayerSettings[playername].delaysmoke = false + text = string.format( "%s, %s, delayed smoke of bombs is now OFF.", self.rangename, playername ) else - self.PlayerSettigs[playername].delaysmoke=true - text=string.format("%s, %s, delayed smoke of bombs is now ON.", self.rangename, playername) + self.PlayerSettigs[playername].delaysmoke = true + text = string.format( "%s, %s, delayed smoke of bombs is now ON.", self.rangename, playername ) end - self:_DisplayMessageToGroup(unit, text, 5, false, true) + self:_DisplayMessageToGroup( unit, text, 5, false, true ) end end @@ -3489,19 +3519,19 @@ end --- Toggle display messages to player. -- @param #RANGE self -- @param #string unitname Name of the player unit. -function RANGE:_MessagesToPlayerOnOff(unitname) - self:F(unitname) +function RANGE:_MessagesToPlayerOnOff( unitname ) + self:F( unitname ) - local unit, playername = self:_GetPlayerUnitAndName(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) + 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) + 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 + self:_DisplayMessageToGroup( unit, text, 5, false, true ) + self.PlayerSettings[playername].messages = not self.PlayerSettings[playername].messages end end @@ -3509,41 +3539,41 @@ end --- Targetsheet saves if player on or off. -- @param #RANGE self -- @param #string _unitname Name of the player unit. -function RANGE:_TargetsheetOnOff(_unitname) - self:F2(_unitname) +function RANGE:_TargetsheetOnOff( _unitname ) + self:F2( _unitname ) -- Get player unit and player name. - local unit, playername = self:_GetPlayerUnitAndName(_unitname) + local unit, playername = self:_GetPlayerUnitAndName( _unitname ) -- Check if we have a player. if unit and playername then -- Player data. - local playerData=self.PlayerSettings[playername] --#RANGE.PlayerData + local playerData = self.PlayerSettings[playername] -- #RANGE.PlayerData if playerData then -- Check if option is enabled at all. - local text="" + local text = "" if self.targetsheet then -- Invert current setting. - playerData.targeton=not playerData.targeton + playerData.targeton = not playerData.targeton -- Inform player. - if playerData.targeton==true then - text=string.format("roger, your targetsheets are now SAVED.") + if playerData and playerData.targeton == true then + text = string.format( "roger, your targetsheets are now SAVED." ) else - text=string.format("affirm, your targetsheets are NOT SAVED.") + text = string.format( "affirm, your targetsheets are NOT SAVED." ) end else - text="negative, target sheet data recorder is broken on this range." + text = "negative, target sheet data recorder is broken on this range." end -- Message to player. - --self:MessageToPlayer(playerData, text, nil, playerData.name, 5) - self:_DisplayMessageToGroup(unit,text,5,false,false) + -- self:MessageToPlayer(playerData, text, nil, playerData.name, 5) + self:_DisplayMessageToGroup( unit, text, 5, false, false ) end end @@ -3552,20 +3582,20 @@ end --- Toggle status of flaring direct hits of range targets. -- @param #RANGE self -- @param #string unitname Name of the player unit. -function RANGE:_FlareDirectHitsOnOff(unitname) - self:F(unitname) +function RANGE:_FlareDirectHitsOnOff( unitname ) + self:F( unitname ) - local unit, playername = self:_GetPlayerUnitAndName(unitname) + local unit, playername = self:_GetPlayerUnitAndName( unitname ) if unit and playername then local text - if self.PlayerSettings[playername].flaredirecthits==true then - self.PlayerSettings[playername].flaredirecthits=false - text=string.format("%s, %s, flaring direct hits is now OFF.", self.rangename, playername) + if self.PlayerSettings[playername].flaredirecthits == true then + self.PlayerSettings[playername].flaredirecthits = false + text = string.format( "%s, %s, flaring direct hits is now OFF.", self.rangename, playername ) else - self.PlayerSettings[playername].flaredirecthits=true - text=string.format("%s, %s, flaring direct hits is now ON.", self.rangename, playername) + self.PlayerSettings[playername].flaredirecthits = true + text = string.format( "%s, %s, flaring direct hits is now ON.", self.rangename, playername ) end - self:_DisplayMessageToGroup(unit, text, 5, false, true) + self:_DisplayMessageToGroup( unit, text, 5, false, true ) end end @@ -3573,21 +3603,21 @@ end --- Mark bombing targets with smoke. -- @param #RANGE self -- @param #string unitname Name of the player unit. -function RANGE:_SmokeBombTargets(unitname) - self:F(unitname) +function RANGE:_SmokeBombTargets( unitname ) + self:F( unitname ) - for _,_bombtarget in pairs(self.bombingTargets) do - local _target=_bombtarget.target --Wrapper.Positionable#POSITIONABLE - local coord=self:_GetBombTargetCoordinate(_bombtarget) + for _, _bombtarget in pairs( self.bombingTargets ) do + local _target = _bombtarget.target -- Wrapper.Positionable#POSITIONABLE + local coord = self:_GetBombTargetCoordinate( _bombtarget ) if coord then - coord:Smoke(self.BombSmokeColor) + coord:Smoke( self.BombSmokeColor ) end end if unitname then - local unit, playername = self:_GetPlayerUnitAndName(unitname) - local text=string.format("%s, %s, bombing targets are now marked with %s smoke.", self.rangename, playername, self:_smokecolor2text(self.BombSmokeColor)) - self:_DisplayMessageToGroup(unit, text, 5) + local unit, playername = self:_GetPlayerUnitAndName( unitname ) + local text = string.format( "%s, %s, bombing targets are now marked with %s smoke.", self.rangename, playername, self:_smokecolor2text( self.BombSmokeColor ) ) + self:_DisplayMessageToGroup( unit, text, 5 ) end end @@ -3595,17 +3625,17 @@ end --- Mark strafing targets with smoke. -- @param #RANGE self -- @param #string unitname Name of the player unit. -function RANGE:_SmokeStrafeTargets(unitname) - self:F(unitname) +function RANGE:_SmokeStrafeTargets( unitname ) + self:F( unitname ) - for _,_target in pairs(self.strafeTargets) do - _target.coordinate:Smoke(self.StrafeSmokeColor) + for _, _target in pairs( self.strafeTargets ) do + _target.coordinate:Smoke( self.StrafeSmokeColor ) end if unitname then - local unit, playername = self:_GetPlayerUnitAndName(unitname) - local text=string.format("%s, %s, strafing tragets are now marked with %s smoke.", self.rangename, playername, self:_smokecolor2text(self.StrafeSmokeColor)) - self:_DisplayMessageToGroup(unit, text, 5) + local unit, playername = self:_GetPlayerUnitAndName( unitname ) + local text = string.format( "%s, %s, strafing tragets are now marked with %s smoke.", self.rangename, playername, self:_smokecolor2text( self.StrafeSmokeColor ) ) + self:_DisplayMessageToGroup( unit, text, 5 ) end end @@ -3613,21 +3643,21 @@ end --- Mark approach boxes of strafe targets with smoke. -- @param #RANGE self -- @param #string unitname Name of the player unit. -function RANGE:_SmokeStrafeTargetBoxes(unitname) - self:F(unitname) +function RANGE:_SmokeStrafeTargetBoxes( unitname ) + self:F( unitname ) - for _,_target in pairs(self.strafeTargets) do - local zone=_target.polygon --Core.Zone#ZONE - zone:SmokeZone(self.StrafePitSmokeColor, 4) - for _,_point in pairs(_target.smokepoints) do - _point:SmokeOrange() --Corners are smoked orange. + for _, _target in pairs( self.strafeTargets ) do + local zone = _target.polygon -- Core.Zone#ZONE + zone:SmokeZone( self.StrafePitSmokeColor, 4 ) + for _, _point in pairs( _target.smokepoints ) do + _point:SmokeOrange() -- Corners are smoked orange. end end if unitname then - local unit, playername = self:_GetPlayerUnitAndName(unitname) - local text=string.format("%s, %s, strafing pit approach boxes are now marked with %s smoke.", self.rangename, playername, self:_smokecolor2text(self.StrafePitSmokeColor)) - self:_DisplayMessageToGroup(unit, text, 5) + local unit, playername = self:_GetPlayerUnitAndName( unitname ) + local text = string.format( "%s, %s, strafing pit approach boxes are now marked with %s smoke.", self.rangename, playername, self:_smokecolor2text( self.StrafePitSmokeColor ) ) + self:_DisplayMessageToGroup( unit, text, 5 ) end end @@ -3636,14 +3666,14 @@ end -- @param #RANGE self -- @param #string _unitName Name of the player unit. -- @param Utilities.Utils#SMOKECOLOR color ID of the smoke color. -function RANGE:_playersmokecolor(_unitName, color) - self:F({unitname=_unitName, color=color}) +function RANGE:_playersmokecolor( _unitName, color ) + self:F( { unitname = _unitName, color = color } ) - local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) + local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) if _unit and _playername then - self.PlayerSettings[_playername].smokecolor=color - local text=string.format("%s, %s, your bomb impacts are now smoked in %s.", self.rangename, _playername, self:_smokecolor2text(color)) - self:_DisplayMessageToGroup(_unit, text, 5) + self.PlayerSettings[_playername].smokecolor = color + local text = string.format( "%s, %s, your bomb impacts are now smoked in %s.", self.rangename, _playername, self:_smokecolor2text( color ) ) + self:_DisplayMessageToGroup( _unit, text, 5 ) end end @@ -3652,14 +3682,14 @@ end -- @param #RANGE self -- @param #string _unitName Name of the player unit. -- @param Utilities.Utils#FLARECOLOR color ID of flare color. -function RANGE:_playerflarecolor(_unitName, color) - self:F({unitname=_unitName, color=color}) +function RANGE:_playerflarecolor( _unitName, color ) + self:F( { unitname = _unitName, color = color } ) - local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) + local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) if _unit and _playername then - self.PlayerSettings[_playername].flarecolor=color - local text=string.format("%s, %s, your direct hits are now flared in %s.", self.rangename, _playername, self:_flarecolor2text(color)) - self:_DisplayMessageToGroup(_unit, text, 5) + self.PlayerSettings[_playername].flarecolor = color + local text = string.format( "%s, %s, your direct hits are now flared in %s.", self.rangename, _playername, self:_flarecolor2text( color ) ) + self:_DisplayMessageToGroup( _unit, text, 5 ) end end @@ -3668,22 +3698,22 @@ end -- @param #RANGE self -- @param Utilities.Utils#SMOKECOLOR color Color Id. -- @return #string Color text. -function RANGE:_smokecolor2text(color) - self:F(color) +function RANGE:_smokecolor2text( color ) + self:F( color ) - local txt="" - if color==SMOKECOLOR.Blue then - txt="blue" - elseif color==SMOKECOLOR.Green then - txt="green" - elseif color==SMOKECOLOR.Orange then - txt="orange" - elseif color==SMOKECOLOR.Red then - txt="red" - elseif color==SMOKECOLOR.White then - txt="white" + local txt = "" + if color == SMOKECOLOR.Blue then + txt = "blue" + elseif color == SMOKECOLOR.Green then + txt = "green" + elseif color == SMOKECOLOR.Orange then + txt = "orange" + elseif color == SMOKECOLOR.Red then + txt = "red" + elseif color == SMOKECOLOR.White then + txt = "white" else - txt=string.format("unknown color (%s)", tostring(color)) + txt = string.format( "unknown color (%s)", tostring( color ) ) end return txt @@ -3693,20 +3723,20 @@ end -- @param #RANGE self -- @param Utilities.Utils#FLARECOLOR color Color Id. -- @return #string Color text. -function RANGE:_flarecolor2text(color) - self:F(color) +function RANGE:_flarecolor2text( color ) + self:F( color ) - local txt="" - if color==FLARECOLOR.Green then - txt="green" - elseif color==FLARECOLOR.Red then - txt="red" - elseif color==FLARECOLOR.White then - txt="white" - elseif color==FLARECOLOR.Yellow then - txt="yellow" + local txt = "" + if color == FLARECOLOR.Green then + txt = "green" + elseif color == FLARECOLOR.Red then + txt = "red" + elseif color == FLARECOLOR.White then + txt = "white" + elseif color == FLARECOLOR.Yellow then + txt = "yellow" else - txt=string.format("unknown color (%s)", tostring(color)) + txt = string.format( "unknown color (%s)", tostring( color ) ) end return txt @@ -3716,33 +3746,33 @@ end -- @param #RANGE self -- @param #string name Name of the potential static object. -- @return #boolean Returns true if a static with this name exists. Retruns false if a unit with this name exists. Returns nil if neither unit or static exist. -function RANGE:_CheckStatic(name) - self:F2(name) +function RANGE:_CheckStatic( name ) + self:F2( name ) -- Get DCS static object. - local _DCSstatic=StaticObject.getByName(name) + local _DCSstatic = StaticObject.getByName( name ) if _DCSstatic and _DCSstatic:isExist() then - --Static does exist at least in DCS. Check if it also in the MOOSE DB. - local _MOOSEstatic=STATIC:FindByName(name, false) + -- Static does exist at least in DCS. Check if it also in the MOOSE DB. + local _MOOSEstatic = STATIC:FindByName( name, false ) -- If static is not yet in MOOSE DB, we add it. Can happen for cargo statics! if not _MOOSEstatic then - self:T(self.id..string.format("Adding DCS static to MOOSE database. Name = %s.", name)) - _DATABASE:AddStatic(name) + self:T( self.id .. string.format( "Adding DCS static to MOOSE database. Name = %s.", name ) ) + _DATABASE:AddStatic( name ) end return true else - self:T3(self.id..string.format("No static object with name %s exists.", name)) + self:T3( self.id .. string.format( "No static object with name %s exists.", name ) ) end -- Check if a unit has this name. - if UNIT:FindByName(name) then + if UNIT:FindByName( name ) then return false else - self:T3(self.id..string.format("No unit object with name %s exists.", name)) + self:T3( self.id .. string.format( "No unit object with name %s exists.", name ) ) end -- If not unit or static exist, we return nil. @@ -3753,17 +3783,17 @@ end -- @param #RANGE self -- @param Wrapper.Controllable#CONTROLLABLE controllable -- @return Maximum speed in km/h. -function RANGE:_GetSpeed(controllable) - self:F2(controllable) +function RANGE:_GetSpeed( controllable ) + self:F2( controllable ) -- Get DCS descriptors - local desc=controllable:GetDesc() + local desc = controllable:GetDesc() -- Get speed - local speed=0 + local speed = 0 if desc then - speed=desc.speedMax*3.6 - self:T({speed=speed}) + speed = desc.speedMax * 3.6 + self:T( { speed = speed } ) end return speed @@ -3775,20 +3805,20 @@ end -- @return Wrapper.Unit#UNIT Unit of player. -- @return #string Name of the player. -- @return nil If player does not exist. -function RANGE:_GetPlayerUnitAndName(_unitName) - self:F2(_unitName) +function RANGE:_GetPlayerUnitAndName( _unitName ) + self:F2( _unitName ) if _unitName ~= nil then -- Get DCS unit from its name. - local DCSunit=Unit.getByName(_unitName) + local DCSunit = Unit.getByName( _unitName ) if DCSunit then - local playername=DCSunit:getPlayerName() - local unit=UNIT:Find(DCSunit) + local playername = DCSunit:getPlayerName() + local unit = UNIT:Find( DCSunit ) - self:T2({DCSunit=DCSunit, unit=unit, playername=playername}) + self:T2( { DCSunit = DCSunit, unit = unit, playername = playername } ) if DCSunit and unit and playername then return unit, playername end @@ -3798,21 +3828,21 @@ function RANGE:_GetPlayerUnitAndName(_unitName) end -- Return nil if we could not find a player. - return nil,nil + return nil, nil 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 #string unitname Name of the player unit. -function RANGE:_myname(unitname) - self:F2(unitname) +function RANGE:_myname( unitname ) + self:F2( unitname ) - local unit=UNIT:FindByName(unitname) - local pname=unit:GetPlayerName() - local csign=unit:GetCallsign() + local unit = UNIT:FindByName( unitname ) + local pname = unit:GetPlayerName() + -- local csign = unit:GetCallsign() - --return string.format("%s (%s)", csign, pname) - return string.format("%s", pname) + -- return string.format("%s (%s)", csign, pname) + return string.format( "%s", pname ) end -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------