FMD: misc
FOX v0.3.0 improvements
RANGE v2.1.1 fixed bugs
SCORING added option to reload csv file
WAREHOUSE v0.7.1 added AssedSpawned FMS event.
This commit is contained in:
Frank
2019-05-13 21:57:09 +02:00
parent b795d2fd09
commit 8e92b8045b
6 changed files with 539 additions and 249 deletions
@@ -145,7 +145,7 @@ function FMD:New()
self:AddTransition("*", "Status", "*") -- Start FMD script. self:AddTransition("*", "Status", "*") -- Start FMD script.
-- Start FMD. -- Start FMD.
FMD:Start() self:Start()
return self return self
end end
@@ -239,28 +239,33 @@ end
-- @param Wrapper.Unit#UNIT unit -- @param Wrapper.Unit#UNIT unit
-- @return #FMD.DataPoint Datapoint. -- @return #FMD.DataPoint Datapoint.
function FMD:_GetDataPoint(unit) function FMD:_GetDataPoint(unit)
if unit and unit:IsAlive() then
-- Current coordinate. -- Current coordinate.
local coord=unit:GetCoordinate() local coord=unit:GetCoordinate()
local dp={} --#FMD.DataPoint local dp={} --#FMD.DataPoint
dp.a={} dp.a={}
dp.Alt=coord.y dp.Alt=coord.y
dp.AoA=unit:GetAoA() dp.AoA=unit:GetAoA()
dp.Atot=nil dp.Atot=nil
dp.P=coord:GetPressure() dp.P=coord:GetPressure()
dp.Pitch=unit:GetPitch() dp.Pitch=unit:GetPitch()
dp.Roll=unit:GetRoll() dp.Roll=unit:GetRoll()
dp.time=timer.getAbsTime() dp.time=timer.getAbsTime()
dp.T=coord:GetTemperature() dp.T=coord:GetTemperature()
dp.v=unit:GetVelocityVec3() dp.v=unit:GetVelocityVec3()
dp.Vtot=UTILS.VecNorm(dp.v) dp.Vtot=UTILS.VecNorm(dp.v)
dp.Yaw=unit:GetYaw() dp.Yaw=unit:GetYaw()
dp.o=unit:GetOrientationX() dp.o=unit:GetOrientationX()
dp.Hdg=unit:GetHeading() dp.Hdg=unit:GetHeading()
return dp return dp
else
return nil
end
end end
--- Get data of unit. --- Get data of unit.
@@ -292,9 +297,32 @@ function FMD:_Derivative(playerData)
dpi.a.z=numderiv(dpm.v.z, dpp.v.z, dt) dpi.a.z=numderiv(dpm.v.z, dpp.v.z, dt)
dpi.DPitch=numderiv(dpm.Pitch, dpp.Pitch, dt) dpi.DPitch=numderiv(dpm.Pitch, dpp.Pitch, dt)
dpi.DRoll=numderiv(dpm.Roll, dpp.Roll, dt) --dpi.DRoll=numderiv(dpm.Roll, dpp.Roll, dt)
dpi.DYaw=numderiv(dpm.Yaw, dpp.Yaw, dt) dpi.DYaw=numderiv(dpm.Yaw, dpp.Yaw, dt)
-- Roll shortcuts.
local r1=dpm.Roll
local r2=dpp.Roll
-- Put roll in [0,360)
if (r1<0) then
r1=r1+360
end
if (r2<0) then
r2=r2+360
end
-- Handle case where 360 deg periodicity strikes.
if r1<90 and r2>270 then
r1=r1+360
end
if r1>270 and r2<90 then
r2=r2+360
end
--
dpi.DRoll=numderiv(r1, r2, dt)
local ang=UTILS.VecAngle(dpm.o, dpp.o) local ang=UTILS.VecAngle(dpm.o, dpp.o)
dpi.omega=numderiv(0, ang, dt) dpi.omega=numderiv(0, ang, dt)
@@ -317,12 +345,20 @@ function FMD:_RecordData(playerData)
-- Activate recording switch. -- Activate recording switch.
playerData.recording=true playerData.recording=true
end end
-- Get data point.
local dp=self:_GetDataPoint(playerData.unit)
-- Add data point to player table. -- Check if unit is alive.
table.insert(playerData.data, dp) if playerData.unit and playerData.unit:IsAlive() then
-- Get data point.
local dp=self:_GetDataPoint(playerData.unit)
-- Add data point to player table.
table.insert(playerData.data, dp)
else
-- Stop recording if player unit is not alive.
self:_StopRecording(playerData.unitname)
end
end end
@@ -374,7 +410,7 @@ function FMD:_SaveData(playerData)
self:I(self.lid..text) self:I(self.lid..text)
-- Header line -- Header line
local data="#Time,Altitude,Temperature,Pressure,Vtot,Vx,Vy,Vz,Atot,ax,ay,az,AoA,Pitch,dPitch/dt,Roll,dRoll/dt,Yaw,dYaw/dt\n" local data="#Time,Altitude,Temperature,Pressure,Vtot,Vx,Vy,Vz,Atot,ax,ay,az,AoA,Pitch,dPitch/dt,Roll,dRoll/dt,Yaw,dYaw/dt,Turn Rate\n"
local g0=playerData.data[1] --#FMD.DataPoint local g0=playerData.data[1] --#FMD.DataPoint
local T0=g0.time local T0=g0.time
@@ -404,7 +440,11 @@ function FMD:_SaveData(playerData)
local l=dp.AoA or 0 local l=dp.AoA or 0
local m=dp.Pitch or 0 local m=dp.Pitch or 0
local n=dp.DPitch or 0 local n=dp.DPitch or 0
local o=dp.Roll or 0 local roll=dp.Roll or 0
if roll<0 then
roll=roll+360
end
local o=roll --dp.Roll or 0
local p=dp.DRoll or 0 local p=dp.DRoll or 0
local q=dp.Yaw or 0 local q=dp.Yaw or 0
local r=dp.DYaw or 0 local r=dp.DYaw or 0
@@ -510,13 +550,16 @@ function FMD:_AddF10Commands(_unitName)
missionCommands.addCommandForGroup(gid, "Delta t=30 s", _timePath, self._SetTimeInterval, self, _unitName, 30.0) missionCommands.addCommandForGroup(gid, "Delta t=30 s", _timePath, self._SetTimeInterval, self, _unitName, 30.0)
missionCommands.addCommandForGroup(gid, "Delta t=60 s", _timePath, self._SetTimeInterval, self, _unitName, 60.0) missionCommands.addCommandForGroup(gid, "Delta t=60 s", _timePath, self._SetTimeInterval, self, _unitName, 60.0)
-------------------------------
-- F10/F<X> FMD/F1 Rec Duration
-------------------------------
local _durPath=missionCommands.addSubMenuForGroup(gid, "Rec Duration", _rootPath) local _durPath=missionCommands.addSubMenuForGroup(gid, "Rec Duration", _rootPath)
-- F10/FMD/F1 Rec Duration/ -- F10/FMD/F1 Rec Duration/
missionCommands.addCommandForGroup(gid, "T=10 s", _timePath, self._SetRecDuration, self, _unitName, 10) missionCommands.addCommandForGroup(gid, "T=10 s", _durPath, self._SetRecDuration, self, _unitName, 10)
missionCommands.addCommandForGroup(gid, "T=30 s", _timePath, self._SetRecDuration, self, _unitName, 30) missionCommands.addCommandForGroup(gid, "T=30 s", _durPath, self._SetRecDuration, self, _unitName, 30)
missionCommands.addCommandForGroup(gid, "T=60 s", _timePath, self._SetRecDuration, self, _unitName, 60) missionCommands.addCommandForGroup(gid, "T=60 s", _durPath, self._SetRecDuration, self, _unitName, 60)
missionCommands.addCommandForGroup(gid, "T=5 min", _timePath, self._SetRecDuration, self, _unitName, 5*60) missionCommands.addCommandForGroup(gid, "T=5 min", _durPath, self._SetRecDuration, self, _unitName, 5*60)
missionCommands.addCommandForGroup(gid, "T=10 min", _timePath, self._SetRecDuration, self, _unitName, 10*60) missionCommands.addCommandForGroup(gid, "T=10 min", _durPath, self._SetRecDuration, self, _unitName, 10*60)
-------------------------------- --------------------------------
-- F10/F<X> FMD/ -- F10/F<X> FMD/
@@ -536,7 +579,7 @@ end
-- @param #FMD self -- @param #FMD self
-- @param #string _unitName Name of player unit. -- @param #string _unitName Name of player unit.
-- @param #number rd Recording duration in sec. -- @param #number rd Recording duration in sec.
function FMD:_SetTimeInterval(_unitName, rd) function FMD:_SetRecDuration(_unitName, rd)
-- Get player unit and name. -- Get player unit and name.
local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) local _unit, _playername = self:_GetPlayerUnitAndName(_unitName)
@@ -610,7 +653,7 @@ function FMD:_StartRecording(_unitName)
playerData.SID=playerData.scheduler:Schedule(nil, self._RecordData, {self, playerData}, delay, playerData.dt, 0.0) playerData.SID=playerData.scheduler:Schedule(nil, self._RecordData, {self, playerData}, delay, playerData.dt, 0.0)
-- Stop scheduler once. -- Stop scheduler once.
playerData.scheduler:ScheduleOnce(playerData.rd+delay, self._StopRecording, {self,_unitName}) playerData.scheduler:ScheduleOnce(playerData.rd+delay, self._StopRecording, self,_unitName)
end end
end end
+266 -165
View File
@@ -18,12 +18,12 @@
-- === -- ===
-- --
-- ### Author: **funkyfranky** -- ### Author: **funkyfranky**
-- @module Functional.FOX2 -- @module Functional.FOX
-- @image Functional_FOX2.png -- @image Functional_FOX.png
--- FOX2 class. --- FOX class.
-- @type FOX2 -- @type FOX
-- @field #string ClassName Name of the class. -- @field #string ClassName Name of the class.
-- @field #boolean Debug Debug mode. Messages to all about status. -- @field #boolean Debug Debug mode. Messages to all about status.
-- @field #string lid Class id string for output to DCS log file. -- @field #string lid Class id string for output to DCS log file.
@@ -40,24 +40,25 @@
-- @field #number dt05 Time step [sec] for missile position updates if distance to target > 5 km and < 10 km. Default 0.5 sec. -- @field #number dt05 Time step [sec] for missile position updates if distance to target > 5 km and < 10 km. Default 0.5 sec.
-- @field #number dt01 Time step [sec] for missile position updates if distance to target > 1 km and < 5 km. Default 0.1 sec. -- @field #number dt01 Time step [sec] for missile position updates if distance to target > 1 km and < 5 km. Default 0.1 sec.
-- @field #number dt00 Time step [sec] for missile position updates if distance to target < 1 km. Default 0.01 sec. -- @field #number dt00 Time step [sec] for missile position updates if distance to target < 1 km. Default 0.01 sec.
-- @field #boolean
-- @extends Core.Fsm#FSM -- @extends Core.Fsm#FSM
--- Fox 2! --- Fox 3!
-- --
-- === -- ===
-- --
-- ![Banner Image](..\Presentations\FOX2\FOX2_Main.png) -- ![Banner Image](..\Presentations\FOX\FOX_Main.png)
-- --
-- # The FOX2 Concept -- # The FOX Concept
-- --
-- As you probably know [Fox](https://en.wikipedia.org/wiki/Fox_(code_word)) is a NATO bevity code for launching air-to-air munition. Therefore, the class name is not 100% accurate as this -- As you probably know [Fox](https://en.wikipedia.org/wiki/Fox_(code_word)) is a NATO brevity code for launching air-to-air munition. Therefore, the class name is not 100% accurate as this
-- script handles air-to-air and surface-to-air missiles. Furthermore, it handles not only Fox **2**, i.e. IR, missiles but also radar guided missiles. -- script handles air-to-air and surface-to-air missiles.
-- --
-- --
-- --
-- @field #FOX2 -- @field #FOX
FOX2 = { FOX = {
ClassName = "FOX2", ClassName = "FOX",
Debug = false, Debug = false,
lid = nil, lid = nil,
menuadded = {}, menuadded = {},
@@ -78,7 +79,7 @@ FOX2 = {
--- Player data table holding all important parameters of each player. --- Player data table holding all important parameters of each player.
-- @type FOX2.PlayerData -- @type FOX.PlayerData
-- @field Wrapper.Unit#UNIT unit Aircraft of the player. -- @field Wrapper.Unit#UNIT unit Aircraft of the player.
-- @field #string unitname Name of the unit. -- @field #string unitname Name of the unit.
-- @field Wrapper.Client#CLIENT client Client object of player. -- @field Wrapper.Client#CLIENT client Client object of player.
@@ -92,9 +93,10 @@ FOX2 = {
-- @field #boolean marklaunch Mark position of launched missile on F10 map. -- @field #boolean marklaunch Mark position of launched missile on F10 map.
-- @field #number defeated Number of missiles defeated. -- @field #number defeated Number of missiles defeated.
-- @field #number dead Number of missiles not defeated. -- @field #number dead Number of missiles not defeated.
-- @field #boolean inzone Player is inside a protected zone.
--- Missile data table. --- Missile data table.
-- @type FOX2.MissileData -- @type FOX.MissileData
-- @field Wrapper.Unit#UNIT weapon Missile weapon unit. -- @field Wrapper.Unit#UNIT weapon Missile weapon unit.
-- @field #boolean active If true the missile is active. -- @field #boolean active If true the missile is active.
-- @field #string missileType Type of missile. -- @field #string missileType Type of missile.
@@ -106,132 +108,175 @@ FOX2 = {
-- @field #number shotTime Abs mission time in seconds the missile was fired. -- @field #number shotTime Abs mission time in seconds the missile was fired.
-- @field Core.Point#COORDINATE shotCoord Coordinate where the missile was fired. -- @field Core.Point#COORDINATE shotCoord Coordinate where the missile was fired.
-- @field Wrapper.Unit#UNIT targetUnit Unit that was targeted. -- @field Wrapper.Unit#UNIT targetUnit Unit that was targeted.
-- @field #FOX2.PlayerData targetPlayer Player that was targeted or nil. -- @field #FOX.PlayerData targetPlayer Player that was targeted or nil.
--- Main radio menu on group level. --- Main radio menu on group level.
-- @field #table MenuF10 Root menu table on group level. -- @field #table MenuF10 Root menu table on group level.
FOX2.MenuF10={} FOX.MenuF10={}
--- Main radio menu on mission level. --- Main radio menu on mission level.
-- @field #table MenuF10Root Root menu on mission level. -- @field #table MenuF10Root Root menu on mission level.
FOX2.MenuF10Root=nil FOX.MenuF10Root=nil
--- FOX2 class version. --- FOX class version.
-- @field #string version -- @field #string version
FOX2.version="0.1.4" FOX.version="0.3.0"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list -- ToDo list
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list: -- TODO list:
-- TODO: safe zones -- DONE: safe zones
-- TODO: mark shooter on F10 -- DONE: mark shooter on F10
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor -- Constructor
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new FOX2 class object. --- Create a new FOX class object.
-- @param #FOX2 self -- @param #FOX self
-- @return #FOX2 self. -- @return #FOX self.
function FOX2:New() function FOX:New()
self.lid="FOX2 | " self.lid="FOX | "
-- Inherit everthing from FSM class. -- Inherit everthing from FSM class.
local self=BASE:Inherit(self, FSM:New()) -- #FOX2 local self=BASE:Inherit(self, FSM:New()) -- #FOX
-- Start State. -- Start State.
self:SetStartState("Stopped") self:SetStartState("Stopped")
-- Add FSM transitions. -- Add FSM transitions.
-- From State --> Event --> To State -- From State --> Event --> To State
self:AddTransition("Stopped", "Start", "Running") -- Start FOX2 script. self:AddTransition("Stopped", "Start", "Running") -- Start FOX script.
self:AddTransition("*", "Status", "*") -- Start FOX2 script. self:AddTransition("*", "Status", "*") -- Status update.
self:AddTransition("*", "MissileLaunch", "*") -- Start FOX2 script. self:AddTransition("*", "MissileLaunch", "*") -- Missile was launched.
self:AddTransition("*", "MissileDestroyed", "*") -- Start FOX2 script. self:AddTransition("*", "MissileDestroyed", "*") -- Missile was destroyed before impact.
self:AddTransition("*", "EnterSafeZone", "*") -- Player enters a safe zone.
self:AddTransition("*", "ExitSafeZone", "*") -- Player exists a safe zone.
------------------------ ------------------------
--- Pseudo Functions --- --- Pseudo Functions ---
------------------------ ------------------------
--- Triggers the FSM event "Start". Starts the FOX2. Initializes parameters and starts event handlers. --- Triggers the FSM event "Start". Starts the FOX. Initializes parameters and starts event handlers.
-- @function [parent=#FOX2] Start -- @function [parent=#FOX] Start
-- @param #FOX2 self -- @param #FOX self
--- Triggers the FSM event "Start" after a delay. Starts the FOX2. Initializes parameters and starts event handlers. --- Triggers the FSM event "Start" after a delay. Starts the FOX. Initializes parameters and starts event handlers.
-- @function [parent=#FOX2] __Start -- @function [parent=#FOX] __Start
-- @param #FOX2 self -- @param #FOX self
-- @param #number delay Delay in seconds. -- @param #number delay Delay in seconds.
--- Triggers the FSM event "Stop". Stops the FOX2 and all its event handlers. --- Triggers the FSM event "Stop". Stops the FOX and all its event handlers.
-- @param #FOX2 self -- @param #FOX self
--- Triggers the FSM event "Stop" after a delay. Stops the FOX2 and all its event handlers. --- Triggers the FSM event "Stop" after a delay. Stops the FOX and all its event handlers.
-- @function [parent=#FOX2] __Stop -- @function [parent=#FOX] __Stop
-- @param #FOX2 self -- @param #FOX self
-- @param #number delay Delay in seconds. -- @param #number delay Delay in seconds.
--- Triggers the FSM event "Status". --- Triggers the FSM event "Status".
-- @function [parent=#FOX2] Status -- @function [parent=#FOX] Status
-- @param #FOX2 self -- @param #FOX self
--- Triggers the FSM event "Status" after a delay. --- Triggers the FSM event "Status" after a delay.
-- @function [parent=#FOX2] __Status -- @function [parent=#FOX] __Status
-- @param #FOX2 self -- @param #FOX self
-- @param #number delay Delay in seconds. -- @param #number delay Delay in seconds.
--- Triggers the FSM event "MissileLaunch". --- Triggers the FSM event "MissileLaunch".
-- @function [parent=#FOX2] MissileLaunch -- @function [parent=#FOX] MissileLaunch
-- @param #FOX2 self -- @param #FOX self
-- @param #FOX2.MissileData missile Data of the fired missile. -- @param #FOX.MissileData missile Data of the fired missile.
--- Triggers the FSM delayed event "MissileLaunch". --- Triggers the FSM delayed event "MissileLaunch".
-- @function [parent=#FOX2] __MissileLaunch -- @function [parent=#FOX] __MissileLaunch
-- @param #FOX2 self -- @param #FOX self
-- @param #number delay Delay in seconds before the function is called. -- @param #number delay Delay in seconds before the function is called.
-- @param #FOX2.MissileData missile Data of the fired missile. -- @param #FOX.MissileData missile Data of the fired missile.
--- On after "MissileLaunch" event user function. Called when a missile was launched. --- On after "MissileLaunch" event user function. Called when a missile was launched.
-- @function [parent=#FOX2] OnAfterMissileLaunch -- @function [parent=#FOX] OnAfterMissileLaunch
-- @param #RECOVERYTANKER self -- @param #FOX self
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
-- @param #FOX2.MissileData missile Data of the fired missile. -- @param #FOX.MissileData missile Data of the fired missile.
--- Triggers the FSM event "MissileDestroyed". --- Triggers the FSM event "MissileDestroyed".
-- @function [parent=#FOX2] MissileDestroyed -- @function [parent=#FOX] MissileDestroyed
-- @param #FOX2 self -- @param #FOX self
-- @param #FOX2.MissileData missile Data of the destroyed missile. -- @param #FOX.MissileData missile Data of the destroyed missile.
--- Triggers the FSM delayed event "MissileDestroyed". --- Triggers the FSM delayed event "MissileDestroyed".
-- @function [parent=#FOX2] __MissileDestroyed -- @function [parent=#FOX] __MissileDestroyed
-- @param #FOX2 self -- @param #FOX self
-- @param #number delay Delay in seconds before the function is called. -- @param #number delay Delay in seconds before the function is called.
-- @param #FOX2.MissileData missile Data of the destroyed missile. -- @param #FOX.MissileData missile Data of the destroyed missile.
--- On after "MissileLaunch" event user function. Called when a missile was launched. --- On after "MissileDestroyed" event user function. Called when a missile was destroyed.
-- @function [parent=#FOX2] OnAfterMissileLaunch -- @function [parent=#FOX] OnAfterMissileDestroyed
-- @param #RECOVERYTANKER self -- @param #FOX self
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
-- @param #FOX2.MissileData missile Data of the fired missile. -- @param #FOX.MissileData missile Data of the destroyed missile.
--- Triggers the FSM event "EnterSafeZone".
-- @function [parent=#FOX] EnterSafeZone
-- @param #FOX self
-- @param #FOX.PlayerData player Player data.
--- Triggers the FSM delayed event "EnterSafeZone".
-- @function [parent=#FOX] __EnterSafeZone
-- @param #FOX self
-- @param #number delay Delay in seconds before the function is called.
-- @param #FOX.PlayerData player Player data.
--- On after "EnterSafeZone" event user function. Called when a player enters a safe zone.
-- @function [parent=#FOX] OnAfterEnterSafeZone
-- @param #FOX self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #FOX.PlayerData player Player data.
--- Triggers the FSM event "ExitSafeZone".
-- @function [parent=#FOX] ExitSafeZone
-- @param #FOX self
-- @param #FOX.PlayerData player Player data.
--- Triggers the FSM delayed event "ExitSafeZone".
-- @function [parent=#FOX] __ExitSafeZone
-- @param #FOX self
-- @param #number delay Delay in seconds before the function is called.
-- @param #FOX.PlayerData player Player data.
--- On after "ExitSafeZone" event user function. Called when a player exists a safe zone.
-- @function [parent=#FOX] OnAfterExitSafeZone
-- @param #FOX self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #FOX.PlayerData player Player data.
return self return self
end end
--- On after Start event. Starts the missile trainer and adds event handlers. --- On after Start event. Starts the missile trainer and adds event handlers.
-- @param #FOX2 self -- @param #FOX self
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
function FOX2:onafterStart(From, Event, To) function FOX:onafterStart(From, Event, To)
-- Short info. -- Short info.
local text=string.format("Starting FOX2 Missile Trainer %s", FOX2.version) local text=string.format("Starting FOX Missile Trainer %s", FOX.version)
env.info(text) env.info(text)
-- Handle events: -- Handle events:
@@ -247,14 +292,14 @@ function FOX2:onafterStart(From, Event, To)
end end
--- On after Stop event. Stops the missile trainer and unhandles events. --- On after Stop event. Stops the missile trainer and unhandles events.
-- @param #FOX2 self -- @param #FOX self
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
function FOX2:onafterStop(From, Event, To) function FOX:onafterStop(From, Event, To)
-- Short info. -- Short info.
local text=string.format("Stopping FOX2 Missile Trainer v0.0.1") local text=string.format("Stopping FOX Missile Trainer %s", FOX.version)
env.info(text) env.info(text)
-- Handle events: -- Handle events:
@@ -268,10 +313,10 @@ end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Add a training zone. Players in the zone are safe. --- Add a training zone. Players in the zone are safe.
-- @param #FOX2 self -- @param #FOX self
-- @param Core.Zone#ZONE zone Training zone. -- @param Core.Zone#ZONE zone Training zone.
-- @return #FOX2 self -- @return #FOX self
function FOX2:AddSafeZone(zone) function FOX:AddSafeZone(zone)
table.insert(self.safezones, zone) table.insert(self.safezones, zone)
@@ -279,10 +324,10 @@ function FOX2:AddSafeZone(zone)
end end
--- Add a launch zone. Only missiles launched within these zones will be tracked. --- Add a launch zone. Only missiles launched within these zones will be tracked.
-- @param #FOX2 self -- @param #FOX self
-- @param Core.Zone#ZONE zone Training zone. -- @param Core.Zone#ZONE zone Training zone.
-- @return #FOX2 self -- @return #FOX self
function FOX2:AddLaunchZone(zone) function FOX:AddLaunchZone(zone)
table.insert(self.launchzones, zone) table.insert(self.launchzones, zone)
@@ -290,10 +335,10 @@ function FOX2:AddLaunchZone(zone)
end end
--- Set debug mode on/off. --- Set debug mode on/off.
-- @param #FOX2 self -- @param #FOX self
-- @param #boolean switch If true debug mode on. If false/nil debug mode off -- @param #boolean switch If true debug mode on. If false/nil debug mode off
-- @return #FOX2 self -- @return #FOX self
function FOX2:SetDebugOnOff(switch) function FOX:SetDebugOnOff(switch)
if switch==nil then if switch==nil then
self.Debug=false self.Debug=false
@@ -305,17 +350,17 @@ function FOX2:SetDebugOnOff(switch)
end end
--- Set debug mode on. --- Set debug mode on.
-- @param #FOX2 self -- @param #FOX self
-- @return #FOX2 self -- @return #FOX self
function FOX2:SetDebugOn() function FOX:SetDebugOn()
self:SetDebugOnOff(true) self:SetDebugOnOff(true)
return self return self
end end
--- Set debug mode off. --- Set debug mode off.
-- @param #FOX2 self -- @param #FOX self
-- @return #FOX2 self -- @return #FOX self
function FOX2:SetDebugOff() function FOX:SetDebugOff()
self:SetDebugOff(false) self:SetDebugOff(false)
return self return self
end end
@@ -325,26 +370,77 @@ end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Check spawn queue and spawn aircraft if necessary. --- Check spawn queue and spawn aircraft if necessary.
-- @param #FOX2 self -- @param #FOX self
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
function FOX2:onafterStatus(From, Event, To) function FOX:onafterStatus(From, Event, To)
self:I(self.lid..string.format("Missile trainer status: %s", self:GetState())) local fsmstate=self:GetState()
self:I(self.lid..string.format("Missile trainer status: %s", fsmstate))
self:_CheckMissileStatus() self:_CheckMissileStatus()
self:__Status(-30) if fsmstate=="Running" then
self:__Status(-10)
end
end end
--- Check status of players.
-- @param #FOX self
-- @param #string _unitName Name of player unit.
function FOX:_CheckPlayers()
for playername,_playersettings in pairs(self.players) do
local playersettings=_playersettings --#FOX.PlayerData
local unitname=playersettings.unitname
local unit=UNIT:FindByName(unitname)
if unit and unit:IsAlive() then
local coord=unit:GetCoordinate()
local issafe=self:_CheckCoordSafe(coord)
if issafe then
-----------------------------
-- Player INSIDE Safe Zone --
-----------------------------
if not playersettings.inzone then
self:EnterSafeZone(playersettings)
playersettings.inzone=true
end
else
------------------------------
-- Player OUTSIDE Safe Zone --
------------------------------
if playersettings.inzone==true then
self:ExitSafeZone(playersettings)
playersettings.inzone=false
end
end
end
end
end
--- Missile status --- Missile status
-- @param #FOX2 self -- @param #FOX self
function FOX2:_CheckMissileStatus() function FOX:_CheckMissileStatus()
local text="Missiles:" local text="Missiles:"
for i,_missile in pairs(self.missiles) do for i,_missile in pairs(self.missiles) do
local missile=_missile --#FOX2.MissileData local missile=_missile --#FOX.MissileData
local targetname="unkown" local targetname="unkown"
if missile.targetUnit then if missile.targetUnit then
@@ -368,19 +464,19 @@ function FOX2:_CheckMissileStatus()
end end
--- Missle launch. --- Missle launch.
-- @param #FOX2 self -- @param #FOX self
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
-- @param #FOX2.MissileData missile Fired missile -- @param #FOX.MissileData missile Fired missile
function FOX2:onafterMissileLaunch(From, Event, To, missile) function FOX:onafterMissileLaunch(From, Event, To, missile)
-- Tracking info and init of last bomb position. -- Tracking info and init of last bomb position.
self:I(FOX2.lid..string.format("FOX2: Tracking %s - %s.", missile.missileType, missile.missileName)) self:I(FOX.lid..string.format("FOX: Tracking %s - %s.", missile.missileType, missile.missileName))
-- Loop over players. -- Loop over players.
for _,_player in pairs(self.players) do for _,_player in pairs(self.players) do
local player=_player --#FOX2.PlayerData local player=_player --#FOX.PlayerData
-- Player position. -- Player position.
local playerUnit=player.unit local playerUnit=player.unit
@@ -406,7 +502,7 @@ function FOX2:onafterMissileLaunch(From, Event, To, missile)
local text=string.format("Missile launch detected! Distance %.1f NM, bearing %03d°.", UTILS.MetersToNM(distance), bearing) local text=string.format("Missile launch detected! Distance %.1f NM, bearing %03d°.", UTILS.MetersToNM(distance), bearing)
text=text..string.format("\nNotching heading %03d or %03d", nr, nl) text=text..string.format("\nNotching heading %03d or %03d", nr, nl)
--TODO: ALERT or INFO depending on wether this is a direct target. --TODO: ALERT or INFO depending on whether this is a direct target.
--TODO: lauchalertall option. --TODO: lauchalertall option.
MESSAGE:New(text, 5, "ALERT"):ToClient(player.client) MESSAGE:New(text, 5, "ALERT"):ToClient(player.client)
@@ -482,7 +578,7 @@ function FOX2:onafterMissileLaunch(From, Event, To, missile)
-- Loop over players. -- Loop over players.
for _,_player in pairs(self.players) do for _,_player in pairs(self.players) do
local player=_player --#FOX2.PlayerData local player=_player --#FOX.PlayerData
-- Check that player was not the one who launched the missile. -- Check that player was not the one who launched the missile.
if player.unitname~=missile.shooterName then if player.unitname~=missile.shooterName then
@@ -588,7 +684,7 @@ function FOX2:onafterMissileLaunch(From, Event, To, missile)
missile.active=false missile.active=false
--Terminate the timer. --Terminate the timer.
self:T(FOX2.lid..string.format("Terminating missile track timer.")) self:T(FOX.lid..string.format("Terminating missile track timer."))
return nil return nil
end -- _status check end -- _status check
@@ -596,7 +692,7 @@ function FOX2:onafterMissileLaunch(From, Event, To, missile)
end -- end function trackBomb end -- end function trackBomb
-- Weapon is not yet "alife" just yet. Start timer with a little delay. -- Weapon is not yet "alife" just yet. Start timer with a little delay.
self:T(FOX2.lid..string.format("Tracking of missile starts in 0.1 seconds.")) self:T(FOX.lid..string.format("Tracking of missile starts in 0.1 seconds."))
timer.scheduleFunction(trackMissile, missile.weapon, timer.getTime()+0.0001) timer.scheduleFunction(trackMissile, missile.weapon, timer.getTime()+0.0001)
end end
@@ -605,10 +701,10 @@ end
-- Event Functions -- Event Functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- FOX2 event handler for event birth. --- FOX event handler for event birth.
-- @param #FOX2 self -- @param #FOX self
-- @param Core.Event#EVENTDATA EventData -- @param Core.Event#EVENTDATA EventData
function FOX2:OnEventBirth(EventData) function FOX:OnEventBirth(EventData)
self:F3({eventbirth = EventData}) self:F3({eventbirth = EventData})
-- Nil checks. -- Nil checks.
@@ -649,7 +745,7 @@ function FOX2:OnEventBirth(EventData)
SCHEDULER:New(nil, self._AddF10Commands, {self,_unitName}, 0.1) SCHEDULER:New(nil, self._AddF10Commands, {self,_unitName}, 0.1)
-- Player data. -- Player data.
local playerData={} --#FOX2.PlayerData local playerData={} --#FOX.PlayerData
-- Player unit, client and callsign. -- Player unit, client and callsign.
playerData.unit = playerunit playerData.unit = playerunit
@@ -677,10 +773,10 @@ function FOX2:OnEventBirth(EventData)
end end
end end
--- FOX2 event handler for event shot (when a unit releases a rocket or bomb (but not a fast firing gun). --- FOX event handler for event shot (when a unit releases a rocket or bomb (but not a fast firing gun).
-- @param #FOX2 self -- @param #FOX self
-- @param Core.Event#EVENTDATA EventData -- @param Core.Event#EVENTDATA EventData
function FOX2:OnEventShot(EventData) function FOX:OnEventShot(EventData)
self:I({eventshot = EventData}) self:I({eventshot = EventData})
if EventData.Weapon==nil then if EventData.Weapon==nil then
@@ -712,13 +808,13 @@ function FOX2:OnEventShot(EventData)
end end
-- Debug info. -- Debug info.
self:E(FOX2.lid.."EVENT SHOT: FOX2") self:E(FOX.lid.."EVENT SHOT: FOX")
self:E(FOX2.lid..string.format("EVENT SHOT: Ini unit = %s", tostring(EventData.IniUnitName))) self:E(FOX.lid..string.format("EVENT SHOT: Ini unit = %s", tostring(EventData.IniUnitName)))
self:E(FOX2.lid..string.format("EVENT SHOT: Ini group = %s", tostring(EventData.IniGroupName))) self:E(FOX.lid..string.format("EVENT SHOT: Ini group = %s", tostring(EventData.IniGroupName)))
self:E(FOX2.lid..string.format("EVENT SHOT: Weapon type = %s", tostring(_weapon))) self:E(FOX.lid..string.format("EVENT SHOT: Weapon type = %s", tostring(_weapon)))
self:E(FOX2.lid..string.format("EVENT SHOT: Weapon categ = %s", tostring(weaponcategory))) self:E(FOX.lid..string.format("EVENT SHOT: Weapon categ = %s", tostring(weaponcategory)))
self:E(FOX2.lid..string.format("EVENT SHOT: Missil categ = %s", tostring(missilecategory))) self:E(FOX.lid..string.format("EVENT SHOT: Missil categ = %s", tostring(missilecategory)))
self:E(FOX2.lid..string.format("EVENT SHOT: Missil range = %s", tostring(missilerange))) self:E(FOX.lid..string.format("EVENT SHOT: Missil range = %s", tostring(missilerange)))
-- Check if fired in launch zone. -- Check if fired in launch zone.
@@ -734,7 +830,7 @@ function FOX2:OnEventShot(EventData)
--_targetUnit=UNIT:FindByName(_targetName) --_targetUnit=UNIT:FindByName(_targetName)
_targetUnit=UNIT:Find(_target) _targetUnit=UNIT:Find(_target)
end end
self:E(FOX2.lid..string.format("EVENT SHOT: Target name = %s", tostring(_targetName))) self:E(FOX.lid..string.format("EVENT SHOT: Target name = %s", tostring(_targetName)))
-- Track missiles of type AAM=1, SAM=2 or OTHER=6 -- Track missiles of type AAM=1, SAM=2 or OTHER=6
local _track = weaponcategory==1 and missilecategory and (missilecategory==1 or missilecategory==2 or missilecategory==6) local _track = weaponcategory==1 and missilecategory and (missilecategory==1 or missilecategory==2 or missilecategory==6)
@@ -742,7 +838,7 @@ function FOX2:OnEventShot(EventData)
-- Only track missiles -- Only track missiles
if _track then if _track then
local missile={} --#FOX2.MissileData local missile={} --#FOX.MissileData
missile.active=true missile.active=true
missile.weapon=EventData.weapon missile.weapon=EventData.weapon
@@ -758,10 +854,15 @@ function FOX2:OnEventShot(EventData)
missile.targetUnit=_targetUnit missile.targetUnit=_targetUnit
missile.targetPlayer=self:_GetPlayerFromUnit(missile.targetUnit) missile.targetPlayer=self:_GetPlayerFromUnit(missile.targetUnit)
-- Add missile table. -- TODO: or in protected set!
table.insert(self.missiles, missile) if missile.targetPlayer then
self:__MissileLaunch(0.1, missile) -- Add missile table.
table.insert(self.missiles, missile)
self:__MissileLaunch(0.1, missile)
end
end --if _track end --if _track
@@ -773,9 +874,9 @@ end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Add menu commands for player. --- Add menu commands for player.
-- @param #FOX2 self -- @param #FOX self
-- @param #string _unitName Name of player unit. -- @param #string _unitName Name of player unit.
function FOX2:_AddF10Commands(_unitName) function FOX:_AddF10Commands(_unitName)
self:F(_unitName) self:F(_unitName)
-- Get player unit and name. -- Get player unit and name.
@@ -797,40 +898,40 @@ function FOX2:_AddF10Commands(_unitName)
-- Set menu root path. -- Set menu root path.
local _rootPath=nil local _rootPath=nil
if FOX2.MenuF10Root then if FOX.MenuF10Root then
------------------------ ------------------------
-- MISSON LEVEL MENUE -- -- MISSON LEVEL MENUE --
------------------------ ------------------------
-- F10/FOX2/... -- F10/FOX/...
_rootPath=FOX2.MenuF10Root _rootPath=FOX.MenuF10Root
else else
------------------------ ------------------------
-- GROUP LEVEL MENUES -- -- GROUP LEVEL MENUES --
------------------------ ------------------------
-- Main F10 menu: F10/FOX2/ -- Main F10 menu: F10/FOX/
if FOX2.MenuF10[gid]==nil then if FOX.MenuF10[gid]==nil then
FOX2.MenuF10[gid]=missionCommands.addSubMenuForGroup(gid, "FOX2") FOX.MenuF10[gid]=missionCommands.addSubMenuForGroup(gid, "FOX")
end end
-- F10/FOX2/... -- F10/FOX/...
_rootPath=FOX2.MenuF10[gid] _rootPath=FOX.MenuF10[gid]
end end
-------------------------------- --------------------------------
-- F10/F<X> FOX2/F1 Help -- F10/F<X> FOX/F1 Help
-------------------------------- --------------------------------
local _helpPath=missionCommands.addSubMenuForGroup(gid, "Help", _rootPath) local _helpPath=missionCommands.addSubMenuForGroup(gid, "Help", _rootPath)
-- F10/FOX2/F1 Help/ -- F10/FOX/F1 Help/
--missionCommands.addCommandForGroup(gid, "Subtitles On/Off", _helpPath, self._SubtitlesOnOff, self, _unitName) -- F7 --missionCommands.addCommandForGroup(gid, "Subtitles On/Off", _helpPath, self._SubtitlesOnOff, self, _unitName) -- F7
--missionCommands.addCommandForGroup(gid, "Trapsheet On/Off", _helpPath, self._TrapsheetOnOff, self, _unitName) -- F8 --missionCommands.addCommandForGroup(gid, "Trapsheet On/Off", _helpPath, self._TrapsheetOnOff, self, _unitName) -- F8
------------------------- -------------------------
-- F10/F<X> FOX2/ -- F10/F<X> FOX/
------------------------- -------------------------
missionCommands.addCommandForGroup(gid, "Launch Alerts On/Off", _rootPath, self._ToggleLaunchAlert, self, _unitName) -- F2 missionCommands.addCommandForGroup(gid, "Launch Alerts On/Off", _rootPath, self._ToggleLaunchAlert, self, _unitName) -- F2
@@ -848,9 +949,9 @@ end
--- Turn player's launch alert on/off. --- Turn player's launch alert on/off.
-- @param #FOX2 self -- @param #FOX self
-- @param #string _unitname Name of the player unit. -- @param #string _unitname Name of the player unit.
function FOX2:_MyStatus(_unitname) function FOX:_MyStatus(_unitname)
self:F2(_unitname) self:F2(_unitname)
-- Get player unit and player name. -- Get player unit and player name.
@@ -860,7 +961,7 @@ function FOX2:_MyStatus(_unitname)
if unit and playername then if unit and playername then
-- Player data. -- Player data.
local playerData=self.players[playername] --#FOX2.PlayerData local playerData=self.players[playername] --#FOX.PlayerData
if playerData then if playerData then
@@ -877,9 +978,9 @@ end
--- Turn player's launch alert on/off. --- Turn player's launch alert on/off.
-- @param #FOX2 self -- @param #FOX self
-- @param #string _unitname Name of the player unit. -- @param #string _unitname Name of the player unit.
function FOX2:_ToggleLaunchAlert(_unitname) function FOX:_ToggleLaunchAlert(_unitname)
self:F2(_unitname) self:F2(_unitname)
-- Get player unit and player name. -- Get player unit and player name.
@@ -889,7 +990,7 @@ function FOX2:_ToggleLaunchAlert(_unitname)
if unit and playername then if unit and playername then
-- Player data. -- Player data.
local playerData=self.players[playername] --#FOX2.PlayerData local playerData=self.players[playername] --#FOX.PlayerData
if playerData then if playerData then
@@ -910,9 +1011,9 @@ function FOX2:_ToggleLaunchAlert(_unitname)
end end
--- Turn player's --- Turn player's
-- @param #FOX2 self -- @param #FOX self
-- @param #string _unitname Name of the player unit. -- @param #string _unitname Name of the player unit.
function FOX2:_ToggleDestroyMissiles(_unitname) function FOX:_ToggleDestroyMissiles(_unitname)
self:F2(_unitname) self:F2(_unitname)
-- Get player unit and player name. -- Get player unit and player name.
@@ -922,7 +1023,7 @@ function FOX2:_ToggleDestroyMissiles(_unitname)
if unit and playername then if unit and playername then
-- Player data. -- Player data.
local playerData=self.players[playername] --#FOX2.PlayerData local playerData=self.players[playername] --#FOX.PlayerData
if playerData then if playerData then
@@ -948,9 +1049,9 @@ end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Get a random text message in case you die. --- Get a random text message in case you die.
-- @param #FOX2 self -- @param #FOX self
-- @return #string Text in case you die. -- @return #string Text in case you die.
function FOX2:_DeadText() function FOX:_DeadText()
local texts={} local texts={}
texts[1]="You're dead!" texts[1]="You're dead!"
@@ -967,10 +1068,10 @@ end
--- Check if a coordinate lies within a safe training zone. --- Check if a coordinate lies within a safe training zone.
-- @param #FOX2 self -- @param #FOX self
-- @param Core.Point#COORDINATE coord Coordinate to check. -- @param Core.Point#COORDINATE coord Coordinate to check.
-- @return #boolean True if safe. -- @return #boolean True if safe.
function FOX2:_CheckCoordSafe(coord) function FOX:_CheckCoordSafe(coord)
-- No safe zones defined ==> Everything is safe. -- No safe zones defined ==> Everything is safe.
if #self.safezones==0 then if #self.safezones==0 then
@@ -990,10 +1091,10 @@ function FOX2:_CheckCoordSafe(coord)
end end
--- Check if a coordinate lies within a launch zone. --- Check if a coordinate lies within a launch zone.
-- @param #FOX2 self -- @param #FOX self
-- @param Core.Point#COORDINATE coord Coordinate to check. -- @param Core.Point#COORDINATE coord Coordinate to check.
-- @return #boolean True if in launch zone. -- @return #boolean True if in launch zone.
function FOX2:_CheckCoordLaunch(coord) function FOX:_CheckCoordLaunch(coord)
-- No safe zones defined ==> Everything is safe. -- No safe zones defined ==> Everything is safe.
if #self.launchzones==0 then if #self.launchzones==0 then
@@ -1013,10 +1114,10 @@ function FOX2:_CheckCoordLaunch(coord)
end end
--- Returns the unit of a player and the player name. If the unit does not belong to a player, nil is returned. --- Returns the unit of a player and the player name. If the unit does not belong to a player, nil is returned.
-- @param #FOX2 self -- @param #FOX self
-- @param #DCS.Weapon weapon The weapon. -- @param DCS#Weapon weapon The weapon.
-- @return #number Heading of weapon in degrees or -1. -- @return #number Heading of weapon in degrees or -1.
function FOX2:_GetWeapongHeading(weapon) function FOX:_GetWeapongHeading(weapon)
if weapon and weapon:isExist() then if weapon and weapon:isExist() then
@@ -1037,11 +1138,11 @@ function FOX2:_GetWeapongHeading(weapon)
end end
--- Returns the unit of a player and the player name. If the unit does not belong to a player, nil is returned. --- Returns the unit of a player and the player name. If the unit does not belong to a player, nil is returned.
-- @param #FOX2 self -- @param #FOX self
-- @param #DCS.Weapon weapon The weapon. -- @param DCS#Weapon weapon The weapon.
-- @return #number Notching heading right, i.e. missile heading +90 -- @return #number Notching heading right, i.e. missile heading +90
-- @return #number Notching heading left, i.e. missile heading -90. -- @return #number Notching heading left, i.e. missile heading -90.
function FOX2:_GetNotchingHeadings(weapon) function FOX:_GetNotchingHeadings(weapon)
if weapon then if weapon then
@@ -1064,13 +1165,13 @@ function FOX2:_GetNotchingHeadings(weapon)
end end
--- Returns the player data from a unit name. --- Returns the player data from a unit name.
-- @param #FOX2 self -- @param #FOX self
-- @param #string unitName Name of the unit. -- @param #string unitName Name of the unit.
-- @return #FOX2.PlayerData Player data. -- @return #FOX.PlayerData Player data.
function FOX2:_GetPlayerFromUnitname(unitName) function FOX:_GetPlayerFromUnitname(unitName)
for _,_player in pairs(self.players) do for _,_player in pairs(self.players) do
local player=_player --#FOX2.PlayerData local player=_player --#FOX.PlayerData
if player.unitname==unitName then if player.unitname==unitName then
return player return player
@@ -1081,10 +1182,10 @@ function FOX2:_GetPlayerFromUnitname(unitName)
end end
--- Retruns the player data from a unit. --- Retruns the player data from a unit.
-- @param #FOX2 self -- @param #FOX self
-- @param Wrapper.Unit#UNIT unit -- @param Wrapper.Unit#UNIT unit
-- @return #FOX2.PlayerData Player data. -- @return #FOX.PlayerData Player data.
function FOX2:_GetPlayerFromUnit(unit) function FOX:_GetPlayerFromUnit(unit)
if unit and unit:IsAlive() then if unit and unit:IsAlive() then
@@ -1092,7 +1193,7 @@ function FOX2:_GetPlayerFromUnit(unit)
local unitname=unit:GetName() local unitname=unit:GetName()
for _,_player in pairs(self.players) do for _,_player in pairs(self.players) do
local player=_player --#FOX2.PlayerData local player=_player --#FOX.PlayerData
if player.unitname==unitname then if player.unitname==unitname then
return player return player
@@ -1105,11 +1206,11 @@ function FOX2:_GetPlayerFromUnit(unit)
end end
--- Returns the unit of a player and the player name. If the unit does not belong to a player, nil is returned. --- Returns the unit of a player and the player name. If the unit does not belong to a player, nil is returned.
-- @param #FOX2 self -- @param #FOX self
-- @param #string _unitName Name of the player unit. -- @param #string _unitName Name of the player unit.
-- @return Wrapper.Unit#UNIT Unit of player or nil. -- @return Wrapper.Unit#UNIT Unit of player or nil.
-- @return #string Name of the player or nil. -- @return #string Name of the player or nil.
function FOX2:_GetPlayerUnitAndName(_unitName) function FOX:_GetPlayerUnitAndName(_unitName)
self:F2(_unitName) self:F2(_unitName)
if _unitName ~= nil then if _unitName ~= nil then
+3 -3
View File
@@ -340,7 +340,7 @@ RANGE.MenuF10Root=nil
--- Range script version. --- Range script version.
-- @field #string version -- @field #string version
RANGE.version="2.1.0" RANGE.version="2.1.1"
--TODO list: --TODO list:
--TODO: Verbosity level for messages. --TODO: Verbosity level for messages.
@@ -532,7 +532,7 @@ function RANGE:onafterStart()
end end
if self.location==nil then 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.rangename, self.nstrafetargets, self.nbombtargets) 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) self:E(self.id..text)
return return
end end
@@ -1095,7 +1095,7 @@ function RANGE:AddBombingTargetUnit(unit, goodhitrange, randommove)
local target={} --#RANGE.BombTarget local target={} --#RANGE.BombTarget
target.name=name target.name=name
target.target=target target.target=unit
target.goodhitrange=goodhitrange target.goodhitrange=goodhitrange
target.move=randommove target.move=randommove
target.speed=speed target.speed=speed
+159 -42
View File
@@ -151,7 +151,7 @@
-- --
-- When a player commits too much damage to friendlies, his penalty score will reach a certain level. -- When a player commits too much damage to friendlies, his penalty score will reach a certain level.
-- Use the method @{#SCORING.SetFratricide}() to define the level when a player gets kicked. -- Use the method @{#SCORING.SetFratricide}() to define the level when a player gets kicked.
-- By default, the fratricide level is the default penalty mutiplier * 2 for the penalty score. -- By default, the fratricide level is the default penalty multiplier * 2 for the penalty score.
-- --
-- # Penalty score when a player changes the coalition. -- # Penalty score when a player changes the coalition.
-- --
@@ -227,10 +227,12 @@ SCORING = {
ClassName = "SCORING", ClassName = "SCORING",
ClassID = 0, ClassID = 0,
Players = {}, Players = {},
CSVdata = {},
} }
local _SCORINGCoalition = local _SCORINGCoalition =
{ {
[0] = "Neutral",
[1] = "Red", [1] = "Red",
[2] = "Blue", [2] = "Blue",
} }
@@ -247,13 +249,15 @@ local _SCORINGCategory =
--- Creates a new SCORING object to administer the scoring achieved by players. --- Creates a new SCORING object to administer the scoring achieved by players.
-- @param #SCORING self -- @param #SCORING self
-- @param #string GameName The name of the game. This name is also logged in the CSV score file. -- @param #string GameName The name of the game. This name is also logged in the CSV score file.
-- @param #string FileName (Optional) Name of the CSV file for saving results. If the file exists, player scores are read.
-- @param #boolean MenuOff (Optional) Done create player menus.
-- @return #SCORING self -- @return #SCORING self
-- @usage -- @usage
-- --
-- -- Define a new scoring object for the mission Gori Valley. -- -- Define a new scoring object for the mission Gori Valley.
-- ScoringObject = SCORING:New( "Gori Valley" ) -- ScoringObject = SCORING:New( "Gori Valley" )
-- --
function SCORING:New( GameName ) function SCORING:New( GameName, FileName, MenuOff )
-- Inherits from BASE -- Inherits from BASE
local self = BASE:Inherit( self, BASE:New() ) -- #SCORING local self = BASE:Inherit( self, BASE:New() ) -- #SCORING
@@ -264,6 +268,10 @@ function SCORING:New( GameName )
error( "A game name must be given to register the scoring results" ) error( "A game name must be given to register the scoring results" )
end end
if FileName then
self.FileName = FileName
end
-- Additional Object scores -- Additional Object scores
self.ScoringObjects = {} self.ScoringObjects = {}
@@ -290,6 +298,9 @@ function SCORING:New( GameName )
self:SetDisplayMessagePrefix() self:SetDisplayMessagePrefix()
-- No player menus.
self.MenuOff=MenuOff
-- Event handlers -- Event handlers
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
@@ -312,7 +323,7 @@ function SCORING:New( GameName )
-- Create the CSV file. -- Create the CSV file.
self:OpenCSV( GameName ) self:OpenCSV( GameName, FileName )
return self return self
@@ -600,11 +611,13 @@ end
-- @param #SCORING self -- @param #SCORING self
-- @return #SCORING -- @return #SCORING
function SCORING:SetScoringMenu( ScoringGroup ) function SCORING:SetScoringMenu( ScoringGroup )
if not self.MenuOff then
local Menu = MENU_GROUP:New( ScoringGroup, 'Scoring and Statistics' ) local Menu = MENU_GROUP:New( ScoringGroup, 'Scoring and Statistics' )
local ReportGroupSummary = MENU_GROUP_COMMAND:New( ScoringGroup, 'Summary report players in group', Menu, SCORING.ReportScoreGroupSummary, self, ScoringGroup ) local ReportGroupSummary = MENU_GROUP_COMMAND:New( ScoringGroup, 'Summary report players in group', Menu, SCORING.ReportScoreGroupSummary, self, ScoringGroup )
local ReportGroupDetailed = MENU_GROUP_COMMAND:New( ScoringGroup, 'Detailed report players in group', Menu, SCORING.ReportScoreGroupDetailed, self, ScoringGroup ) local ReportGroupDetailed = MENU_GROUP_COMMAND:New( ScoringGroup, 'Detailed report players in group', Menu, SCORING.ReportScoreGroupDetailed, self, ScoringGroup )
local ReportToAllSummary = MENU_GROUP_COMMAND:New( ScoringGroup, 'Summary report all players', Menu, SCORING.ReportScoreAllSummary, self, ScoringGroup ) local ReportToAllSummary = MENU_GROUP_COMMAND:New( ScoringGroup, 'Summary report all players', Menu, SCORING.ReportScoreAllSummary, self, ScoringGroup )
self:SetState( ScoringGroup, "ScoringMenu", Menu ) self:SetState( ScoringGroup, "ScoringMenu", Menu )
end
return self return self
end end
@@ -1758,47 +1771,49 @@ function SCORING:ReportScoreAllSummary( PlayerGroup )
end end
function SCORING:SecondsToClock(sSeconds)
local nSeconds = sSeconds
if nSeconds == 0 then
--return nil;
return "00:00:00";
else
nHours = string.format("%02.f", math.floor(nSeconds/3600));
nMins = string.format("%02.f", math.floor(nSeconds/60 - (nHours*60)));
nSecs = string.format("%02.f", math.floor(nSeconds - nHours*3600 - nMins *60));
return nHours..":"..nMins..":"..nSecs
end
end
--- Opens a score CSV file to log the scores. --- Opens a score CSV file to log the scores.
-- @param #SCORING self -- @param #SCORING self
-- @param #string ScoringCSV -- @param #string ScoringCSV
-- @param #string FileName Name of the csv file.
-- @return #SCORING self -- @return #SCORING self
-- @usage -- @usage
-- -- Open a new CSV file to log the scores of the game Gori Valley. Let the name of the CSV file begin with "Player Scores". -- -- Open a new CSV file to log the scores of the game Gori Valley. Let the name of the CSV file begin with "Player Scores".
-- ScoringObject = SCORING:New( "Gori Valley" ) -- ScoringObject = SCORING:New( "Gori Valley" )
-- ScoringObject:OpenCSV( "Player Scores" ) -- ScoringObject:OpenCSV( "Player Scores" )
function SCORING:OpenCSV( ScoringCSV ) function SCORING:OpenCSV( ScoringCSV, FileName )
self:F( ScoringCSV ) self:F( ScoringCSV )
if lfs and io and os then if lfs and io and os then
if ScoringCSV then if ScoringCSV then
self.ScoringCSV = ScoringCSV
local fdir = lfs.writedir() .. [[Logs\]] .. self.ScoringCSV .. " " .. os.date( "%Y-%m-%d %H-%M-%S" ) .. ".csv" -- File name.
local fdir = lfs.writedir() .. [[Logs\]] .. ScoringCSV .. " " .. os.date( "%Y-%m-%d %H-%M-%S" ) .. ".csv"
self.CSVFile, self.err = io.open( fdir, "w+" )
if not self.CSVFile then if FileName then
error( "Error: Cannot open CSV file in " .. lfs.writedir() ) fdir=lfs.writedir() .. [[Logs\]] .. FileName
end
if UTILS.FileExists(fdir) then
self:LoadCSV(fdir)
self.CSVFile, self.err = io.open( fdir, "a+" )
if not self.CSVFile then
error( "Error: Cannot open CSV file in " .. lfs.writedir() )
end
else
self.CSVFile, self.err = io.open( fdir, "w+" )
if not self.CSVFile then
error( "Error: Cannot open CSV file in " .. lfs.writedir() )
end
self.CSVFile:write( '"GameName","RunTime","Time","PlayerName","TargetPlayerName","ScoreType","PlayerUnitCoaltion","PlayerUnitCategory","PlayerUnitType","PlayerUnitName","TargetUnitCoalition","TargetUnitCategory","TargetUnitType","TargetUnitName","Times","Score"\n' )
end end
self.CSVFile:write( '"GameName","RunTime","Time","PlayerName","TargetPlayerName","ScoreType","PlayerUnitCoaltion","PlayerUnitCategory","PlayerUnitType","PlayerUnitName","TargetUnitCoalition","TargetUnitCategory","TargetUnitType","TargetUnitName","Times","Score"\n' )
self.RunTime = os.date("%y-%m-%d_%H-%M-%S") self.RunTime = os.date("%y-%m-%d_%H-%M-%S")
else else
error( "A string containing the CSV file name must be given." ) error( "A string containing the CSV file name must be given." )
end end
else else
self:F( "The MissionScripting.lua file has not been changed to allow lfs, io and os modules to be used..." ) self:F( "The MissionScripting.lua file has not been changed to allow lfs, io and os modules to be used..." )
end end
@@ -1806,6 +1821,101 @@ function SCORING:OpenCSV( ScoringCSV )
end end
--- Load player data from file.
-- @param #SCORING self
-- @param #string filename File name containing player scoring data.
function SCORING:LoadCSV(filename)
--- Function that load data from a file.
local function _loadfile(filename)
local f=io.open(filename, "rb")
if f then
local data=f:read("*all")
f:close()
return data
else
self:E(self.id..string.format("ERROR: Could not load player results from file %s", tostring(filename)))
return nil
end
end
-- Info message.
local text=string.format("Loading player scoring from file %s", filename)
self:I(text)
-- Load asset data from file.
local data=_loadfile(filename)
if data then
-- Split by line break.
local results=UTILS.Split(data,"\n")
-- Remove first header line.
table.remove(results, 1)
-- Init player scores table.
self.CSVdata=self.CSVdata or {}
-- Loop over all lines.
for _,_result in pairs(results) do
-- Parameters are separated by commata.
local resultdata=UTILS.Split(_result, ",")
-- Grade table
local result={}
--'"GameName","RunTime","Time","PlayerName","TargetPlayerName","ScoreType","PlayerUnitCoaltion","PlayerUnitCategory","PlayerUnitType","PlayerUnitName","TargetUnitCoalition",
-- "TargetUnitCategory","TargetUnitType","TargetUnitName","Times","Score"\n'
local PlayerName=tostring(resultdata[4])
-- Results data.
result.GameName=tostring(resultdata[1])
result.RunTime=tostring(resultdata[2])
result.Time=tonumber(resultdata[3])
result.PlayerName=tostring(resultdata[4])
result.TargetPlayerName=tostring(resultdata[5])
result.ScoreType=tostring(resultdata[6])
result.PlayerUnitCoaltion=tostring(resultdata[7])
result.PlayerUnitCategory=tostring(resultdata[8])
result.PlayerUnitType=tostring(resultdata[9])
result.PlayerUnitName=tostring(resultdata[10])
result.TargetUnitCoalition=tostring(resultdata[11])
result.TargetUnitCategory=tostring(resultdata[12])
result.TargetUnitType=tostring(resultdata[13])
result.TargetUnitName=tostring(resultdata[14])
result.Times=tonumber(resultdata[15])
result.Score=tonumber(resultdata[16])
self:E(result.Score)
-- Create player array if necessary.
self.CSVdata[result.PlayerName]=self.CSVdata[result.PlayerName] or {}
if self.Players[PlayerName] == nil then -- I believe this is the place where a Player gets a life in a mission when he enters a unit ...
self.Players[PlayerName] = {}
self.Players[PlayerName].Hit = {}
self.Players[PlayerName].Destroy = {}
self.Players[PlayerName].Goals = {}
self.Players[PlayerName].Mission = {}
self.Players[PlayerName].HitPlayers = {}
self.Players[PlayerName].Score = 0
self.Players[PlayerName].Penalty = 0
self.Players[PlayerName].PenaltyCoalition = 0
self.Players[PlayerName].PenaltyWarning = 0
end
--self.Players[PlayerName].Score=self.Players[PlayerName].Score+result.Score
-- Add result to table.
table.insert(self.CSVdata[result.PlayerName], result)
end
end
end
--- Registers a score for a player. --- Registers a score for a player.
-- @param #SCORING self -- @param #SCORING self
-- @param #string PlayerName The name of the player. -- @param #string PlayerName The name of the player.
@@ -1823,11 +1933,17 @@ end
-- @param #string TargetUnitType The type of the target unit. -- @param #string TargetUnitType The type of the target unit.
-- @return #SCORING self -- @return #SCORING self
function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes, ScoreAmount, PlayerUnitName, PlayerUnitCoalition, PlayerUnitCategory, PlayerUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes, ScoreAmount, PlayerUnitName, PlayerUnitCoalition, PlayerUnitCategory, PlayerUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
--write statistic information to file --write statistic information to file
local ScoreTime = self:SecondsToClock( timer.getTime() ) --local ScoreTime = self:SecondsToClock( timer.getTime() )
local ScoreTime = UTILS.SecondsToClock(timer.getAbsTime())
-- Player name
PlayerName = PlayerName:gsub( '"', '_' ) PlayerName = PlayerName:gsub( '"', '_' )
TargetPlayerName = TargetPlayerName or "" -- Target NAme
TargetPlayerName = TargetPlayerName or "n/a"
TargetPlayerName = TargetPlayerName:gsub( '"', '_' ) TargetPlayerName = TargetPlayerName:gsub( '"', '_' )
if PlayerUnitName and PlayerUnitName ~= '' then if PlayerUnitName and PlayerUnitName ~= '' then
@@ -1847,22 +1963,22 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes,
PlayerUnitType = PlayerUnit:getTypeName() PlayerUnitType = PlayerUnit:getTypeName()
end end
else else
PlayerUnitName = '' PlayerUnitName = 'n/a'
PlayerUnitCategory = '' PlayerUnitCategory = 'n/a'
PlayerUnitCoalition = '' PlayerUnitCoalition = 'n/a'
PlayerUnitType = '' PlayerUnitType = 'n/a'
end end
else else
PlayerUnitName = '' PlayerUnitName = 'n/a'
PlayerUnitCategory = '' PlayerUnitCategory = 'n/a'
PlayerUnitCoalition = '' PlayerUnitCoalition = 'n/a'
PlayerUnitType = '' PlayerUnitType = 'n/a'
end end
TargetUnitCoalition = TargetUnitCoalition or "" TargetUnitCoalition = TargetUnitCoalition or "n/a"
TargetUnitCategory = TargetUnitCategory or "" TargetUnitCategory = TargetUnitCategory or "n/a"
TargetUnitType = TargetUnitType or "" TargetUnitType = TargetUnitType or "n/a"
TargetUnitName = TargetUnitName or "" TargetUnitName = TargetUnitName or "n/a"
if lfs and io and os then if lfs and io and os then
self.CSVFile:write( self.CSVFile:write(
@@ -1881,14 +1997,15 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes,
'"' .. TargetUnitType .. '"' .. ',' .. '"' .. TargetUnitType .. '"' .. ',' ..
'"' .. TargetUnitName .. '"' .. ',' .. '"' .. TargetUnitName .. '"' .. ',' ..
'' .. ScoreTimes .. '' .. ',' .. '' .. ScoreTimes .. '' .. ',' ..
'' .. ScoreAmount '' .. ScoreAmount
) )
self.CSVFile:write( "\n" ) self.CSVFile:write( "\n" )
end end
end end
--- Close csv file.
-- @param #SCORING self
function SCORING:CloseCSV() function SCORING:CloseCSV()
if lfs and io and os then if lfs and io and os then
self.CSVFile:close() self.CSVFile:close()
@@ -1733,7 +1733,7 @@ _WAREHOUSEDB = {
--- Warehouse class version. --- Warehouse class version.
-- @field #string version -- @field #string version
WAREHOUSE.version="0.7.0" WAREHOUSE.version="0.7.1"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Warehouse todo list. -- TODO: Warehouse todo list.
@@ -1876,6 +1876,7 @@ function WAREHOUSE:New(warehouse, alias)
self:AddTransition("Running", "Request", "*") -- Process a request. Only in running mode. self:AddTransition("Running", "Request", "*") -- Process a request. Only in running mode.
self:AddTransition("Attacked", "Request", "*") -- Process a request. Only in running mode. self:AddTransition("Attacked", "Request", "*") -- Process a request. Only in running mode.
self:AddTransition("*", "Unloaded", "*") -- Cargo has been unloaded from the carrier (unused ==> unnecessary?). self:AddTransition("*", "Unloaded", "*") -- Cargo has been unloaded from the carrier (unused ==> unnecessary?).
self:AddTransition("*", "AssetSpawned", "*") -- Asset has been spawned into the world.
self:AddTransition("*", "Arrived", "*") -- Cargo or transport group has arrived. self:AddTransition("*", "Arrived", "*") -- Cargo or transport group has arrived.
self:AddTransition("*", "Delivered", "*") -- All cargo groups of a request have been delivered to the requesting warehouse. self:AddTransition("*", "Delivered", "*") -- All cargo groups of a request have been delivered to the requesting warehouse.
self:AddTransition("Running", "SelfRequest", "*") -- Request to warehouse itself. Requested assets are only spawned but not delivered anywhere. self:AddTransition("Running", "SelfRequest", "*") -- Request to warehouse itself. Requested assets are only spawned but not delivered anywhere.
@@ -2301,6 +2302,29 @@ function WAREHOUSE:New(warehouse, alias)
-- @param #string To To state. -- @param #string To To state.
--- Triggers the FSM event "AssetSpawned" when the warehouse has spawned an asset.
-- @function [parent=#WAREHOUSE] AssetSpawned
-- @param #WAREHOUSE self
-- @param Wrapper.Group#GROUP group the group that was spawned.
-- @param #WAREHOUSE.Assetitem asset The asset that was spawned.
--- Triggers the FSM event "AssetSpawned" with a delay when the warehouse has spawned an asset.
-- @function [parent=#WAREHOUSE] __AssetSpawned
-- @param #WAREHOUSE self
-- @param #number delay Delay in seconds.
-- @param Wrapper.Group#GROUP group the group that was spawned.
-- @param #WAREHOUSE.Assetitem asset The asset that was spawned.
--- On after "AssetSpawned" event user function. Called when the warehouse has spawned an asset.
-- @function [parent=#WAREHOUSE] OnAfterAssetSpawned
-- @param #WAREHOUSE self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Group#GROUP group the group that was spawned.
-- @param #WAREHOUSE.Assetitem asset The asset that was spawned.
--- Triggers the FSM event "Save" when the warehouse assets are saved to file on disk. --- Triggers the FSM event "Save" when the warehouse assets are saved to file on disk.
-- @function [parent=#WAREHOUSE] Save -- @function [parent=#WAREHOUSE] Save
-- @param #WAREHOUSE self -- @param #WAREHOUSE self
@@ -4259,6 +4283,9 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request)
-- Add transport assets. -- Add transport assets.
table.insert(_transportassets,_assetitem) table.insert(_transportassets,_assetitem)
-- Asset spawned FSM function.
self:__AssetSpawned(1, spawngroup, _assetitem)
end end
end end
@@ -5195,6 +5222,9 @@ function WAREHOUSE:_SpawnAssetRequest(Request)
if _group then if _group then
_groupset:AddGroup(_group) _groupset:AddGroup(_group)
table.insert(_assets, _assetitem) table.insert(_assets, _assetitem)
-- Call FSM function.
self:__AssetSpawned(1,_group,_assetitem)
else else
self:E(self.wid.."ERROR: Cargo asset could not be spawned!") self:E(self.wid.."ERROR: Cargo asset could not be spawned!")
end end
-1
View File
@@ -8320,7 +8320,6 @@ end
--- Airboss event handler for event that a unit takes off. --- Airboss event handler for event that a unit takes off.
-- @param #AIRBOSS self -- @param #AIRBOSS self
-- @param Core.Event#EVENTDATA EventData -- @param Core.Event#EVENTDATA EventData
--function AIRBOSS:OnEventPlayerLeaveUnit(EventData)
function AIRBOSS:OnEventTakeoff(EventData) function AIRBOSS:OnEventTakeoff(EventData)
self:F3({eventtakeoff=EventData}) self:F3({eventtakeoff=EventData})