From 8e92b8045b5fa2331e91dfec00808e46001528f8 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 13 May 2019 21:57:09 +0200 Subject: [PATCH] MISC 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. --- .../Moose/Functional/FlightModelData.lua | 117 +++-- Moose Development/Moose/Functional/Fox2.lua | 431 +++++++++++------- Moose Development/Moose/Functional/Range.lua | 6 +- .../Moose/Functional/Scoring.lua | 201 ++++++-- .../Moose/Functional/Warehouse.lua | 32 +- Moose Development/Moose/Ops/Airboss.lua | 1 - 6 files changed, 539 insertions(+), 249 deletions(-) diff --git a/Moose Development/Moose/Functional/FlightModelData.lua b/Moose Development/Moose/Functional/FlightModelData.lua index 25ef658e4..d82b25641 100644 --- a/Moose Development/Moose/Functional/FlightModelData.lua +++ b/Moose Development/Moose/Functional/FlightModelData.lua @@ -145,7 +145,7 @@ function FMD:New() self:AddTransition("*", "Status", "*") -- Start FMD script. -- Start FMD. - FMD:Start() + self:Start() return self end @@ -239,28 +239,33 @@ end -- @param Wrapper.Unit#UNIT unit -- @return #FMD.DataPoint Datapoint. function FMD:_GetDataPoint(unit) + + if unit and unit:IsAlive() then - -- Current coordinate. - local coord=unit:GetCoordinate() - - local dp={} --#FMD.DataPoint - - dp.a={} - dp.Alt=coord.y - dp.AoA=unit:GetAoA() - dp.Atot=nil - dp.P=coord:GetPressure() - dp.Pitch=unit:GetPitch() - dp.Roll=unit:GetRoll() - dp.time=timer.getAbsTime() - dp.T=coord:GetTemperature() - dp.v=unit:GetVelocityVec3() - dp.Vtot=UTILS.VecNorm(dp.v) - dp.Yaw=unit:GetYaw() - dp.o=unit:GetOrientationX() - dp.Hdg=unit:GetHeading() - - return dp + -- Current coordinate. + local coord=unit:GetCoordinate() + + local dp={} --#FMD.DataPoint + + dp.a={} + dp.Alt=coord.y + dp.AoA=unit:GetAoA() + dp.Atot=nil + dp.P=coord:GetPressure() + dp.Pitch=unit:GetPitch() + dp.Roll=unit:GetRoll() + dp.time=timer.getAbsTime() + dp.T=coord:GetTemperature() + dp.v=unit:GetVelocityVec3() + dp.Vtot=UTILS.VecNorm(dp.v) + dp.Yaw=unit:GetYaw() + dp.o=unit:GetOrientationX() + dp.Hdg=unit:GetHeading() + + return dp + else + return nil + end end --- Get data of unit. @@ -292,9 +297,32 @@ function FMD:_Derivative(playerData) dpi.a.z=numderiv(dpm.v.z, dpp.v.z, 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) + + -- 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) dpi.omega=numderiv(0, ang, dt) @@ -317,12 +345,20 @@ function FMD:_RecordData(playerData) -- Activate recording switch. playerData.recording=true end - - -- Get data point. - local dp=self:_GetDataPoint(playerData.unit) - -- Add data point to player table. - table.insert(playerData.data, dp) + -- Check if unit is alive. + 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 @@ -374,7 +410,7 @@ function FMD:_SaveData(playerData) self:I(self.lid..text) -- 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 T0=g0.time @@ -404,7 +440,11 @@ function FMD:_SaveData(playerData) local l=dp.AoA or 0 local m=dp.Pitch 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 q=dp.Yaw 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=60 s", _timePath, self._SetTimeInterval, self, _unitName, 60.0) + ------------------------------- + -- F10/F FMD/F1 Rec Duration + ------------------------------- local _durPath=missionCommands.addSubMenuForGroup(gid, "Rec Duration", _rootPath) -- F10/FMD/F1 Rec Duration/ - missionCommands.addCommandForGroup(gid, "T=10 s", _timePath, self._SetRecDuration, self, _unitName, 10) - missionCommands.addCommandForGroup(gid, "T=30 s", _timePath, self._SetRecDuration, self, _unitName, 30) - missionCommands.addCommandForGroup(gid, "T=60 s", _timePath, self._SetRecDuration, self, _unitName, 60) - missionCommands.addCommandForGroup(gid, "T=5 min", _timePath, self._SetRecDuration, self, _unitName, 5*60) - missionCommands.addCommandForGroup(gid, "T=10 min", _timePath, self._SetRecDuration, self, _unitName, 10*60) + missionCommands.addCommandForGroup(gid, "T=10 s", _durPath, self._SetRecDuration, self, _unitName, 10) + missionCommands.addCommandForGroup(gid, "T=30 s", _durPath, self._SetRecDuration, self, _unitName, 30) + missionCommands.addCommandForGroup(gid, "T=60 s", _durPath, self._SetRecDuration, self, _unitName, 60) + missionCommands.addCommandForGroup(gid, "T=5 min", _durPath, self._SetRecDuration, self, _unitName, 5*60) + missionCommands.addCommandForGroup(gid, "T=10 min", _durPath, self._SetRecDuration, self, _unitName, 10*60) -------------------------------- -- F10/F FMD/ @@ -536,7 +579,7 @@ end -- @param #FMD self -- @param #string _unitName Name of player unit. -- @param #number rd Recording duration in sec. -function FMD:_SetTimeInterval(_unitName, rd) +function FMD:_SetRecDuration(_unitName, rd) -- Get player unit and name. 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) -- 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 diff --git a/Moose Development/Moose/Functional/Fox2.lua b/Moose Development/Moose/Functional/Fox2.lua index 42ec11239..f5fd19aa2 100644 --- a/Moose Development/Moose/Functional/Fox2.lua +++ b/Moose Development/Moose/Functional/Fox2.lua @@ -18,12 +18,12 @@ -- === -- -- ### Author: **funkyfranky** --- @module Functional.FOX2 --- @image Functional_FOX2.png +-- @module Functional.FOX +-- @image Functional_FOX.png ---- FOX2 class. --- @type FOX2 +--- FOX class. +-- @type FOX -- @field #string ClassName Name of the class. -- @field #boolean Debug Debug mode. Messages to all about status. -- @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 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 #boolean -- @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 --- 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. +-- 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. -- -- -- --- @field #FOX2 -FOX2 = { - ClassName = "FOX2", +-- @field #FOX +FOX = { + ClassName = "FOX", Debug = false, lid = nil, menuadded = {}, @@ -78,7 +79,7 @@ FOX2 = { --- 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 #string unitname Name of the unit. -- @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 #number defeated Number of missiles defeated. -- @field #number dead Number of missiles not defeated. +-- @field #boolean inzone Player is inside a protected zone. --- Missile data table. --- @type FOX2.MissileData +-- @type FOX.MissileData -- @field Wrapper.Unit#UNIT weapon Missile weapon unit. -- @field #boolean active If true the missile is active. -- @field #string missileType Type of missile. @@ -106,132 +108,175 @@ FOX2 = { -- @field #number shotTime Abs mission time in seconds 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 #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. -- @field #table MenuF10 Root menu table on group level. -FOX2.MenuF10={} +FOX.MenuF10={} --- Main radio 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 -FOX2.version="0.1.4" +FOX.version="0.3.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list: --- TODO: safe zones --- TODO: mark shooter on F10 +-- DONE: safe zones +-- DONE: mark shooter on F10 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Create a new FOX2 class object. --- @param #FOX2 self --- @return #FOX2 self. -function FOX2:New() +--- Create a new FOX class object. +-- @param #FOX self +-- @return #FOX self. +function FOX:New() - self.lid="FOX2 | " + self.lid="FOX | " -- Inherit everthing from FSM class. - local self=BASE:Inherit(self, FSM:New()) -- #FOX2 + local self=BASE:Inherit(self, FSM:New()) -- #FOX -- Start State. self:SetStartState("Stopped") -- Add FSM transitions. -- From State --> Event --> To State - self:AddTransition("Stopped", "Start", "Running") -- Start FOX2 script. - self:AddTransition("*", "Status", "*") -- Start FOX2 script. - self:AddTransition("*", "MissileLaunch", "*") -- Start FOX2 script. - self:AddTransition("*", "MissileDestroyed", "*") -- Start FOX2 script. + self:AddTransition("Stopped", "Start", "Running") -- Start FOX script. + self:AddTransition("*", "Status", "*") -- Status update. + self:AddTransition("*", "MissileLaunch", "*") -- Missile was launched. + 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 --- ------------------------ - --- Triggers the FSM event "Start". Starts the FOX2. Initializes parameters and starts event handlers. - -- @function [parent=#FOX2] Start - -- @param #FOX2 self + --- Triggers the FSM event "Start". Starts the FOX. Initializes parameters and starts event handlers. + -- @function [parent=#FOX] Start + -- @param #FOX self - --- Triggers the FSM event "Start" after a delay. Starts the FOX2. Initializes parameters and starts event handlers. - -- @function [parent=#FOX2] __Start - -- @param #FOX2 self + --- Triggers the FSM event "Start" after a delay. Starts the FOX. Initializes parameters and starts event handlers. + -- @function [parent=#FOX] __Start + -- @param #FOX self -- @param #number delay Delay in seconds. - --- Triggers the FSM event "Stop". Stops the FOX2 and all its event handlers. - -- @param #FOX2 self + --- Triggers the FSM event "Stop". Stops the FOX and all its event handlers. + -- @param #FOX self - --- Triggers the FSM event "Stop" after a delay. Stops the FOX2 and all its event handlers. - -- @function [parent=#FOX2] __Stop - -- @param #FOX2 self + --- Triggers the FSM event "Stop" after a delay. Stops the FOX and all its event handlers. + -- @function [parent=#FOX] __Stop + -- @param #FOX self -- @param #number delay Delay in seconds. --- Triggers the FSM event "Status". - -- @function [parent=#FOX2] Status - -- @param #FOX2 self + -- @function [parent=#FOX] Status + -- @param #FOX self --- Triggers the FSM event "Status" after a delay. - -- @function [parent=#FOX2] __Status - -- @param #FOX2 self + -- @function [parent=#FOX] __Status + -- @param #FOX self -- @param #number delay Delay in seconds. --- Triggers the FSM event "MissileLaunch". - -- @function [parent=#FOX2] MissileLaunch - -- @param #FOX2 self - -- @param #FOX2.MissileData missile Data of the fired missile. + -- @function [parent=#FOX] MissileLaunch + -- @param #FOX self + -- @param #FOX.MissileData missile Data of the fired missile. --- Triggers the FSM delayed event "MissileLaunch". - -- @function [parent=#FOX2] __MissileLaunch - -- @param #FOX2 self + -- @function [parent=#FOX] __MissileLaunch + -- @param #FOX self -- @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. - -- @function [parent=#FOX2] OnAfterMissileLaunch - -- @param #RECOVERYTANKER self + -- @function [parent=#FOX] OnAfterMissileLaunch + -- @param #FOX self -- @param #string From From state. -- @param #string Event Event. -- @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". - -- @function [parent=#FOX2] MissileDestroyed - -- @param #FOX2 self - -- @param #FOX2.MissileData missile Data of the destroyed missile. + -- @function [parent=#FOX] MissileDestroyed + -- @param #FOX self + -- @param #FOX.MissileData missile Data of the destroyed missile. --- Triggers the FSM delayed event "MissileDestroyed". - -- @function [parent=#FOX2] __MissileDestroyed - -- @param #FOX2 self + -- @function [parent=#FOX] __MissileDestroyed + -- @param #FOX self -- @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. - -- @function [parent=#FOX2] OnAfterMissileLaunch - -- @param #RECOVERYTANKER self + --- On after "MissileDestroyed" event user function. Called when a missile was destroyed. + -- @function [parent=#FOX] OnAfterMissileDestroyed + -- @param #FOX self -- @param #string From From state. -- @param #string Event Event. -- @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 end --- 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 Event Event. -- @param #string To To state. -function FOX2:onafterStart(From, Event, To) +function FOX:onafterStart(From, Event, To) -- 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) -- Handle events: @@ -247,14 +292,14 @@ function FOX2:onafterStart(From, Event, To) end --- On after Stop event. Stops the missile trainer and unhandles events. --- @param #FOX2 self +-- @param #FOX self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -function FOX2:onafterStop(From, Event, To) +function FOX:onafterStop(From, Event, To) -- 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) -- Handle events: @@ -268,10 +313,10 @@ end --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Add a training zone. Players in the zone are safe. --- @param #FOX2 self +-- @param #FOX self -- @param Core.Zone#ZONE zone Training zone. --- @return #FOX2 self -function FOX2:AddSafeZone(zone) +-- @return #FOX self +function FOX:AddSafeZone(zone) table.insert(self.safezones, zone) @@ -279,10 +324,10 @@ function FOX2:AddSafeZone(zone) end --- 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. --- @return #FOX2 self -function FOX2:AddLaunchZone(zone) +-- @return #FOX self +function FOX:AddLaunchZone(zone) table.insert(self.launchzones, zone) @@ -290,10 +335,10 @@ function FOX2:AddLaunchZone(zone) end --- 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 --- @return #FOX2 self -function FOX2:SetDebugOnOff(switch) +-- @return #FOX self +function FOX:SetDebugOnOff(switch) if switch==nil then self.Debug=false @@ -305,17 +350,17 @@ function FOX2:SetDebugOnOff(switch) end --- Set debug mode on. --- @param #FOX2 self --- @return #FOX2 self -function FOX2:SetDebugOn() +-- @param #FOX self +-- @return #FOX self +function FOX:SetDebugOn() self:SetDebugOnOff(true) return self end --- Set debug mode off. --- @param #FOX2 self --- @return #FOX2 self -function FOX2:SetDebugOff() +-- @param #FOX self +-- @return #FOX self +function FOX:SetDebugOff() self:SetDebugOff(false) return self end @@ -325,26 +370,77 @@ end --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Check spawn queue and spawn aircraft if necessary. --- @param #FOX2 self +-- @param #FOX self -- @param #string From From state. -- @param #string Event Event. -- @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:__Status(-30) + if fsmstate=="Running" then + self:__Status(-10) + 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 --- @param #FOX2 self -function FOX2:_CheckMissileStatus() +-- @param #FOX self +function FOX:_CheckMissileStatus() local text="Missiles:" for i,_missile in pairs(self.missiles) do - local missile=_missile --#FOX2.MissileData + local missile=_missile --#FOX.MissileData local targetname="unkown" if missile.targetUnit then @@ -368,19 +464,19 @@ function FOX2:_CheckMissileStatus() end --- Missle launch. --- @param #FOX2 self +-- @param #FOX self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. --- @param #FOX2.MissileData missile Fired missile -function FOX2:onafterMissileLaunch(From, Event, To, missile) +-- @param #FOX.MissileData missile Fired missile +function FOX:onafterMissileLaunch(From, Event, To, missile) -- 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. for _,_player in pairs(self.players) do - local player=_player --#FOX2.PlayerData + local player=_player --#FOX.PlayerData -- Player position. 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) 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. MESSAGE:New(text, 5, "ALERT"):ToClient(player.client) @@ -482,7 +578,7 @@ function FOX2:onafterMissileLaunch(From, Event, To, missile) -- Loop over players. 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. if player.unitname~=missile.shooterName then @@ -588,7 +684,7 @@ function FOX2:onafterMissileLaunch(From, Event, To, missile) missile.active=false --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 end -- _status check @@ -596,7 +692,7 @@ function FOX2:onafterMissileLaunch(From, Event, To, missile) end -- end function trackBomb -- 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) end @@ -605,10 +701,10 @@ end -- Event Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- FOX2 event handler for event birth. --- @param #FOX2 self +--- FOX event handler for event birth. +-- @param #FOX self -- @param Core.Event#EVENTDATA EventData -function FOX2:OnEventBirth(EventData) +function FOX:OnEventBirth(EventData) self:F3({eventbirth = EventData}) -- Nil checks. @@ -649,7 +745,7 @@ function FOX2:OnEventBirth(EventData) SCHEDULER:New(nil, self._AddF10Commands, {self,_unitName}, 0.1) -- Player data. - local playerData={} --#FOX2.PlayerData + local playerData={} --#FOX.PlayerData -- Player unit, client and callsign. playerData.unit = playerunit @@ -677,10 +773,10 @@ function FOX2:OnEventBirth(EventData) end end ---- FOX2 event handler for event shot (when a unit releases a rocket or bomb (but not a fast firing gun). --- @param #FOX2 self +--- FOX event handler for event shot (when a unit releases a rocket or bomb (but not a fast firing gun). +-- @param #FOX self -- @param Core.Event#EVENTDATA EventData -function FOX2:OnEventShot(EventData) +function FOX:OnEventShot(EventData) self:I({eventshot = EventData}) if EventData.Weapon==nil then @@ -712,13 +808,13 @@ function FOX2:OnEventShot(EventData) end -- Debug info. - self:E(FOX2.lid.."EVENT SHOT: FOX2") - self:E(FOX2.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(FOX2.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(FOX2.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.."EVENT SHOT: FOX") + self:E(FOX.lid..string.format("EVENT SHOT: Ini unit = %s", tostring(EventData.IniUnitName))) + self:E(FOX.lid..string.format("EVENT SHOT: Ini group = %s", tostring(EventData.IniGroupName))) + self:E(FOX.lid..string.format("EVENT SHOT: Weapon type = %s", tostring(_weapon))) + self:E(FOX.lid..string.format("EVENT SHOT: Weapon categ = %s", tostring(weaponcategory))) + self:E(FOX.lid..string.format("EVENT SHOT: Missil categ = %s", tostring(missilecategory))) + self:E(FOX.lid..string.format("EVENT SHOT: Missil range = %s", tostring(missilerange))) -- Check if fired in launch zone. @@ -734,7 +830,7 @@ function FOX2:OnEventShot(EventData) --_targetUnit=UNIT:FindByName(_targetName) _targetUnit=UNIT:Find(_target) 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 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 if _track then - local missile={} --#FOX2.MissileData + local missile={} --#FOX.MissileData missile.active=true missile.weapon=EventData.weapon @@ -758,10 +854,15 @@ function FOX2:OnEventShot(EventData) missile.targetUnit=_targetUnit missile.targetPlayer=self:_GetPlayerFromUnit(missile.targetUnit) - -- Add missile table. - table.insert(self.missiles, missile) + -- TODO: or in protected set! + 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 @@ -773,9 +874,9 @@ end ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Add menu commands for player. --- @param #FOX2 self +-- @param #FOX self -- @param #string _unitName Name of player unit. -function FOX2:_AddF10Commands(_unitName) +function FOX:_AddF10Commands(_unitName) self:F(_unitName) -- Get player unit and name. @@ -797,40 +898,40 @@ function FOX2:_AddF10Commands(_unitName) -- Set menu root path. local _rootPath=nil - if FOX2.MenuF10Root then + if FOX.MenuF10Root then ------------------------ -- MISSON LEVEL MENUE -- ------------------------ - -- F10/FOX2/... - _rootPath=FOX2.MenuF10Root + -- F10/FOX/... + _rootPath=FOX.MenuF10Root else ------------------------ -- GROUP LEVEL MENUES -- ------------------------ - -- Main F10 menu: F10/FOX2/ - if FOX2.MenuF10[gid]==nil then - FOX2.MenuF10[gid]=missionCommands.addSubMenuForGroup(gid, "FOX2") + -- Main F10 menu: F10/FOX/ + if FOX.MenuF10[gid]==nil then + FOX.MenuF10[gid]=missionCommands.addSubMenuForGroup(gid, "FOX") end - -- F10/FOX2/... - _rootPath=FOX2.MenuF10[gid] + -- F10/FOX/... + _rootPath=FOX.MenuF10[gid] end -------------------------------- - -- F10/F FOX2/F1 Help + -- F10/F FOX/F1 Help -------------------------------- 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, "Trapsheet On/Off", _helpPath, self._TrapsheetOnOff, self, _unitName) -- F8 ------------------------- - -- F10/F FOX2/ + -- F10/F FOX/ ------------------------- 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. --- @param #FOX2 self +-- @param #FOX self -- @param #string _unitname Name of the player unit. -function FOX2:_MyStatus(_unitname) +function FOX:_MyStatus(_unitname) self:F2(_unitname) -- Get player unit and player name. @@ -860,7 +961,7 @@ function FOX2:_MyStatus(_unitname) if unit and playername then -- Player data. - local playerData=self.players[playername] --#FOX2.PlayerData + local playerData=self.players[playername] --#FOX.PlayerData if playerData then @@ -877,9 +978,9 @@ end --- Turn player's launch alert on/off. --- @param #FOX2 self +-- @param #FOX self -- @param #string _unitname Name of the player unit. -function FOX2:_ToggleLaunchAlert(_unitname) +function FOX:_ToggleLaunchAlert(_unitname) self:F2(_unitname) -- Get player unit and player name. @@ -889,7 +990,7 @@ function FOX2:_ToggleLaunchAlert(_unitname) if unit and playername then -- Player data. - local playerData=self.players[playername] --#FOX2.PlayerData + local playerData=self.players[playername] --#FOX.PlayerData if playerData then @@ -910,9 +1011,9 @@ function FOX2:_ToggleLaunchAlert(_unitname) end --- Turn player's --- @param #FOX2 self +-- @param #FOX self -- @param #string _unitname Name of the player unit. -function FOX2:_ToggleDestroyMissiles(_unitname) +function FOX:_ToggleDestroyMissiles(_unitname) self:F2(_unitname) -- Get player unit and player name. @@ -922,7 +1023,7 @@ function FOX2:_ToggleDestroyMissiles(_unitname) if unit and playername then -- Player data. - local playerData=self.players[playername] --#FOX2.PlayerData + local playerData=self.players[playername] --#FOX.PlayerData if playerData then @@ -948,9 +1049,9 @@ end --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Get a random text message in case you die. --- @param #FOX2 self +-- @param #FOX self -- @return #string Text in case you die. -function FOX2:_DeadText() +function FOX:_DeadText() local texts={} texts[1]="You're dead!" @@ -967,10 +1068,10 @@ end --- Check if a coordinate lies within a safe training zone. --- @param #FOX2 self +-- @param #FOX self -- @param Core.Point#COORDINATE coord Coordinate to check. -- @return #boolean True if safe. -function FOX2:_CheckCoordSafe(coord) +function FOX:_CheckCoordSafe(coord) -- No safe zones defined ==> Everything is safe. if #self.safezones==0 then @@ -990,10 +1091,10 @@ function FOX2:_CheckCoordSafe(coord) end --- Check if a coordinate lies within a launch zone. --- @param #FOX2 self +-- @param #FOX self -- @param Core.Point#COORDINATE coord Coordinate to check. -- @return #boolean True if in launch zone. -function FOX2:_CheckCoordLaunch(coord) +function FOX:_CheckCoordLaunch(coord) -- No safe zones defined ==> Everything is safe. if #self.launchzones==0 then @@ -1013,10 +1114,10 @@ function FOX2:_CheckCoordLaunch(coord) end --- 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 #DCS.Weapon weapon The weapon. +-- @param #FOX self +-- @param DCS#Weapon weapon The weapon. -- @return #number Heading of weapon in degrees or -1. -function FOX2:_GetWeapongHeading(weapon) +function FOX:_GetWeapongHeading(weapon) if weapon and weapon:isExist() then @@ -1037,11 +1138,11 @@ function FOX2:_GetWeapongHeading(weapon) end --- 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 #DCS.Weapon weapon The weapon. +-- @param #FOX self +-- @param DCS#Weapon weapon The weapon. -- @return #number Notching heading right, 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 @@ -1064,13 +1165,13 @@ function FOX2:_GetNotchingHeadings(weapon) end --- Returns the player data from a unit name. --- @param #FOX2 self +-- @param #FOX self -- @param #string unitName Name of the unit. --- @return #FOX2.PlayerData Player data. -function FOX2:_GetPlayerFromUnitname(unitName) +-- @return #FOX.PlayerData Player data. +function FOX:_GetPlayerFromUnitname(unitName) for _,_player in pairs(self.players) do - local player=_player --#FOX2.PlayerData + local player=_player --#FOX.PlayerData if player.unitname==unitName then return player @@ -1081,10 +1182,10 @@ function FOX2:_GetPlayerFromUnitname(unitName) end --- Retruns the player data from a unit. --- @param #FOX2 self +-- @param #FOX self -- @param Wrapper.Unit#UNIT unit --- @return #FOX2.PlayerData Player data. -function FOX2:_GetPlayerFromUnit(unit) +-- @return #FOX.PlayerData Player data. +function FOX:_GetPlayerFromUnit(unit) if unit and unit:IsAlive() then @@ -1092,7 +1193,7 @@ function FOX2:_GetPlayerFromUnit(unit) local unitname=unit:GetName() for _,_player in pairs(self.players) do - local player=_player --#FOX2.PlayerData + local player=_player --#FOX.PlayerData if player.unitname==unitname then return player @@ -1105,11 +1206,11 @@ function FOX2:_GetPlayerFromUnit(unit) end --- 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. -- @return Wrapper.Unit#UNIT Unit of player or nil. -- @return #string Name of the player or nil. -function FOX2:_GetPlayerUnitAndName(_unitName) +function FOX:_GetPlayerUnitAndName(_unitName) self:F2(_unitName) if _unitName ~= nil then diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 364a29660..500b966b7 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -340,7 +340,7 @@ RANGE.MenuF10Root=nil --- Range script version. -- @field #string version -RANGE.version="2.1.0" +RANGE.version="2.1.1" --TODO list: --TODO: Verbosity level for messages. @@ -532,7 +532,7 @@ function RANGE:onafterStart() 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.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) return end @@ -1095,7 +1095,7 @@ function RANGE:AddBombingTargetUnit(unit, goodhitrange, randommove) local target={} --#RANGE.BombTarget target.name=name - target.target=target + target.target=unit target.goodhitrange=goodhitrange target.move=randommove target.speed=speed diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index af50957e6..4a1d751b7 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -151,7 +151,7 @@ -- -- 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. --- 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. -- @@ -227,10 +227,12 @@ SCORING = { ClassName = "SCORING", ClassID = 0, Players = {}, + CSVdata = {}, } local _SCORINGCoalition = { + [0] = "Neutral", [1] = "Red", [2] = "Blue", } @@ -247,13 +249,15 @@ local _SCORINGCategory = --- Creates a new SCORING object to administer the scoring achieved by players. -- @param #SCORING self -- @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 -- @usage -- -- -- Define a new scoring object for the mission Gori Valley. -- ScoringObject = SCORING:New( "Gori Valley" ) -- -function SCORING:New( GameName ) +function SCORING:New( GameName, FileName, MenuOff ) -- Inherits from BASE 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" ) end + if FileName then + self.FileName = FileName + end + -- Additional Object scores self.ScoringObjects = {} @@ -290,6 +298,9 @@ function SCORING:New( GameName ) self:SetDisplayMessagePrefix() + -- No player menus. + self.MenuOff=MenuOff + -- Event handlers self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) @@ -312,7 +323,7 @@ function SCORING:New( GameName ) -- Create the CSV file. - self:OpenCSV( GameName ) + self:OpenCSV( GameName, FileName ) return self @@ -600,11 +611,13 @@ end -- @param #SCORING self -- @return #SCORING function SCORING:SetScoringMenu( ScoringGroup ) + if not self.MenuOff then 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 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 ) self:SetState( ScoringGroup, "ScoringMenu", Menu ) + end return self end @@ -1758,47 +1771,49 @@ function SCORING:ReportScoreAllSummary( PlayerGroup ) 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. -- @param #SCORING self -- @param #string ScoringCSV +-- @param #string FileName Name of the csv file. -- @return #SCORING self -- @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". -- ScoringObject = SCORING:New( "Gori Valley" ) -- ScoringObject:OpenCSV( "Player Scores" ) -function SCORING:OpenCSV( ScoringCSV ) +function SCORING:OpenCSV( ScoringCSV, FileName ) self:F( ScoringCSV ) if lfs and io and os then + if ScoringCSV then - self.ScoringCSV = ScoringCSV - local fdir = lfs.writedir() .. [[Logs\]] .. self.ScoringCSV .. " " .. os.date( "%Y-%m-%d %H-%M-%S" ) .. ".csv" - - self.CSVFile, self.err = io.open( fdir, "w+" ) - if not self.CSVFile then - error( "Error: Cannot open CSV file in " .. lfs.writedir() ) + + -- File name. + local fdir = lfs.writedir() .. [[Logs\]] .. ScoringCSV .. " " .. os.date( "%Y-%m-%d %H-%M-%S" ) .. ".csv" + + if FileName then + 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 - 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") else error( "A string containing the CSV file name must be given." ) end + else self:F( "The MissionScripting.lua file has not been changed to allow lfs, io and os modules to be used..." ) end @@ -1806,6 +1821,101 @@ function SCORING:OpenCSV( ScoringCSV ) 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. -- @param #SCORING self -- @param #string PlayerName The name of the player. @@ -1823,11 +1933,17 @@ end -- @param #string TargetUnitType The type of the target unit. -- @return #SCORING self function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes, ScoreAmount, PlayerUnitName, PlayerUnitCoalition, PlayerUnitCategory, PlayerUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) + --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( '"', '_' ) - TargetPlayerName = TargetPlayerName or "" + -- Target NAme + TargetPlayerName = TargetPlayerName or "n/a" + TargetPlayerName = TargetPlayerName:gsub( '"', '_' ) if PlayerUnitName and PlayerUnitName ~= '' then @@ -1847,22 +1963,22 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes, PlayerUnitType = PlayerUnit:getTypeName() end else - PlayerUnitName = '' - PlayerUnitCategory = '' - PlayerUnitCoalition = '' - PlayerUnitType = '' + PlayerUnitName = 'n/a' + PlayerUnitCategory = 'n/a' + PlayerUnitCoalition = 'n/a' + PlayerUnitType = 'n/a' end else - PlayerUnitName = '' - PlayerUnitCategory = '' - PlayerUnitCoalition = '' - PlayerUnitType = '' + PlayerUnitName = 'n/a' + PlayerUnitCategory = 'n/a' + PlayerUnitCoalition = 'n/a' + PlayerUnitType = 'n/a' end - TargetUnitCoalition = TargetUnitCoalition or "" - TargetUnitCategory = TargetUnitCategory or "" - TargetUnitType = TargetUnitType or "" - TargetUnitName = TargetUnitName or "" + TargetUnitCoalition = TargetUnitCoalition or "n/a" + TargetUnitCategory = TargetUnitCategory or "n/a" + TargetUnitType = TargetUnitType or "n/a" + TargetUnitName = TargetUnitName or "n/a" if lfs and io and os then self.CSVFile:write( @@ -1881,14 +1997,15 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes, '"' .. TargetUnitType .. '"' .. ',' .. '"' .. TargetUnitName .. '"' .. ',' .. '' .. ScoreTimes .. '' .. ',' .. - '' .. ScoreAmount + '' .. ScoreAmount ) self.CSVFile:write( "\n" ) end end - +--- Close csv file. +-- @param #SCORING self function SCORING:CloseCSV() if lfs and io and os then self.CSVFile:close() diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 84fbb7cd0..da9895bc9 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -1733,7 +1733,7 @@ _WAREHOUSEDB = { --- Warehouse class version. -- @field #string version -WAREHOUSE.version="0.7.0" +WAREHOUSE.version="0.7.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- 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("Attacked", "Request", "*") -- Process a request. Only in running mode. 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("*", "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. @@ -2301,6 +2302,29 @@ function WAREHOUSE:New(warehouse, alias) -- @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. -- @function [parent=#WAREHOUSE] Save -- @param #WAREHOUSE self @@ -4259,6 +4283,9 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request) -- Add transport assets. table.insert(_transportassets,_assetitem) + + -- Asset spawned FSM function. + self:__AssetSpawned(1, spawngroup, _assetitem) end end @@ -5195,6 +5222,9 @@ function WAREHOUSE:_SpawnAssetRequest(Request) if _group then _groupset:AddGroup(_group) table.insert(_assets, _assetitem) + + -- Call FSM function. + self:__AssetSpawned(1,_group,_assetitem) else self:E(self.wid.."ERROR: Cargo asset could not be spawned!") end diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 8bc34ee99..24a36a7c8 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -8320,7 +8320,6 @@ end --- Airboss event handler for event that a unit takes off. -- @param #AIRBOSS self -- @param Core.Event#EVENTDATA EventData ---function AIRBOSS:OnEventPlayerLeaveUnit(EventData) function AIRBOSS:OnEventTakeoff(EventData) self:F3({eventtakeoff=EventData})