RESCUEHELO v1.0.5

- Added Returned event.
- Fixed automatic RTB on low fuel bug.
This commit is contained in:
Frank 2019-01-31 13:43:17 +01:00
parent 1cb248692b
commit c4016cfa4d
3 changed files with 172 additions and 89 deletions

View File

@ -11158,9 +11158,6 @@ end
-- @param #number delay Delay in seconds, before the message is displayed. -- @param #number delay Delay in seconds, before the message is displayed.
function AIRBOSS:MessageToPattern(message, sender, receiver, duration, clear, delay) function AIRBOSS:MessageToPattern(message, sender, receiver, duration, clear, delay)
-- Local delay.
local _delay=delay or 0
-- Create new (fake) radio call to show the subtitile. -- Create new (fake) radio call to show the subtitile.
local call=self:_NewRadioCall(AIRBOSS.LSOCall.NOISE, sender or "LSO", message, duration, receiver, sender) local call=self:_NewRadioCall(AIRBOSS.LSOCall.NOISE, sender or "LSO", message, duration, receiver, sender)
@ -11180,9 +11177,6 @@ end
-- @param #number delay Delay in seconds, before the message is displayed. -- @param #number delay Delay in seconds, before the message is displayed.
function AIRBOSS:MessageToMarshal(message, sender, receiver, duration, clear, delay) function AIRBOSS:MessageToMarshal(message, sender, receiver, duration, clear, delay)
-- Local delay.
local _delay=delay or 0
-- Create new (fake) radio call to show the subtitile. -- Create new (fake) radio call to show the subtitile.
local call=self:_NewRadioCall(AIRBOSS.MarshalCall.NOISE, sender or "MARSHAL", message, duration, receiver, sender) local call=self:_NewRadioCall(AIRBOSS.MarshalCall.NOISE, sender or "MARSHAL", message, duration, receiver, sender)
@ -12584,7 +12578,7 @@ function AIRBOSS:_DisplayPlayerStatus(_unitName)
local fuel=playerData.unit:GetFuel()*100 local fuel=playerData.unit:GetFuel()*100
local fuelstate=self:_GetFuelState(playerData.unit) local fuelstate=self:_GetFuelState(playerData.unit)
--- -- Number of units in group.
local _,nunitsGround=self:_GetFlightUnits(playerData, true) local _,nunitsGround=self:_GetFlightUnits(playerData, true)
local _,nunitsAirborne=self:_GetFlightUnits(playerData, false) local _,nunitsAirborne=self:_GetFlightUnits(playerData, false)
@ -12599,8 +12593,6 @@ function AIRBOSS:_DisplayPlayerStatus(_unitName)
text=text..string.format("Skill Level: %s\n", playerData.difficulty) text=text..string.format("Skill Level: %s\n", playerData.difficulty)
text=text..string.format("Tail # %s (%s)\n", playerData.onboard, self:_GetACNickname(playerData.actype)) text=text..string.format("Tail # %s (%s)\n", playerData.onboard, self:_GetACNickname(playerData.actype))
text=text..string.format("Fuel State: %.1f lbs/1000 (%.1f %%)\n", fuelstate/1000, fuel) text=text..string.format("Fuel State: %.1f lbs/1000 (%.1f %%)\n", fuelstate/1000, fuel)
--text=text..string.format("Aircraft: %s\n", self:_GetACNickname(playerData.actype))
--text=text..string.format("Group: %s\n", playerData.group:GetName())
text=text..string.format("# units: %d (%d airborne)\n", nunitsGround, nunitsAirborne) text=text..string.format("# units: %d (%d airborne)\n", nunitsGround, nunitsAirborne)
text=text..string.format("Section Lead: %s (%d/%d)", tostring(playerData.seclead), #playerData.section+1, self.NmaxSection+1) text=text..string.format("Section Lead: %s (%d/%d)", tostring(playerData.seclead), #playerData.section+1, self.NmaxSection+1)
for _,_sec in pairs(playerData.section) do for _,_sec in pairs(playerData.section) do

View File

@ -821,8 +821,10 @@ function RECOVERYTANKER:onafterStart(From, Event, To)
-- Handle events. -- Handle events.
self:HandleEvent(EVENTS.EngineShutdown) self:HandleEvent(EVENTS.EngineShutdown)
self:HandleEvent(EVENTS.Refueling, self._RefuelingStart) --Need explcit functions sice OnEventRefueling and OnEventRefuelingStop did not hook. self:HandleEvent(EVENTS.Refueling, self._RefuelingStart) --Need explicit functions since OnEventRefueling and OnEventRefuelingStop did not hook!
self:HandleEvent(EVENTS.RefuelingStop, self._RefuelingStop) self:HandleEvent(EVENTS.RefuelingStop, self._RefuelingStop)
self:HandleEvent(EVENTS.Crash, self._OnEventCrashOrDead)
self:HandleEvent(EVENTS.Dead, self._OnEventCrashOrDead)
-- Spawn tanker. We need to introduce an alias in case this class is used twice. This would confuse the spawn routine. -- Spawn tanker. We need to introduce an alias in case this class is used twice. This would confuse the spawn routine.
local Spawn=SPAWN:NewWithAlias(self.tankergroupname, self.alias) local Spawn=SPAWN:NewWithAlias(self.tankergroupname, self.alias)
@ -1004,6 +1006,8 @@ function RECOVERYTANKER:onafterStatus(From, Event, To)
-- TANKER is DEAD -- -- TANKER is DEAD --
-------------------- --------------------
if not self:IsStopped() then
-- Stop FSM. -- Stop FSM.
self:Stop() self:Stop()
@ -1013,6 +1017,7 @@ function RECOVERYTANKER:onafterStatus(From, Event, To)
end end
end end
end
end end
@ -1116,9 +1121,22 @@ end
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
function RECOVERYTANKER:onafterStop(From, Event, To) function RECOVERYTANKER:onafterStop(From, Event, To)
-- Unhandle events.
self:UnHandleEvent(EVENTS.EngineShutdown) self:UnHandleEvent(EVENTS.EngineShutdown)
self:UnHandleEvent(EVENTS.Refueling) self:UnHandleEvent(EVENTS.Refueling)
self:UnHandleEvent(EVENTS.RefuelingStop) self:UnHandleEvent(EVENTS.RefuelingStop)
self:UnHandleEvent(EVENTS.Dead)
self:UnHandleEvent(EVENTS.Crash)
-- If tanker is alive, despawn it.
if self.helo and self.helo:IsAlive() then
self:I(self.lid.."Stopping FSM and despawning tanker.")
self.tanker:Destroy()
else
self:I(self.lid.."Stopping FSM. Tanker was not alive.")
end
end end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -1235,6 +1253,37 @@ function RECOVERYTANKER:_RefuelingStop(EventData)
end end
--- A unit crashed or died.
-- @param #RECOVERYTANKER self
-- @param Core.Event#EVENTDATA EventData Event data.
function RECOVERYTANKER:_OnEventCrashOrDead(EventData)
self:F2({eventdata=EventData})
-- Check that there is an initiating unit in the event data.
if EventData and EventData.IniUnit then
-- Crashed or dead unit.
local unit=EventData.IniUnit
local unitname=tostring(EventData.IniUnitName)
-- Check that it was the tanker that crashed.
if EventData.IniGroupName==self.tanker:GetName() then
-- Error message.
self:E(self.lid..string.format("Recovery tanker %s crashed!", unitname))
-- Stop FSM.
self:Stop()
-- Restart.
if self.respawn then
self:__Start(5)
end
end
end
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- MISC functions -- MISC functions

View File

@ -11,6 +11,12 @@
-- * Multiple helos at different carriers due to object oriented approach. -- * Multiple helos at different carriers due to object oriented approach.
-- * Finite State Machine (FSM) implementation. -- * Finite State Machine (FSM) implementation.
-- --
-- ## Known (DCS) Issues
--
-- * CH-53E does only report 27.5% fuel even if fuel is set to 100% in the ME. See [bug report](https://forums.eagle.ru/showthread.php?t=223712)
-- * CH-53E does not accept USS Tarawa as landing airbase (even it can be spawned on it).
-- * Helos dont move away from their landing position on carriers.
--
-- === -- ===
-- --
-- ### Author: **funkyfranky** -- ### Author: **funkyfranky**
@ -229,7 +235,7 @@ RESCUEHELO.UID=0
--- Class version. --- Class version.
-- @field #string version -- @field #string version
RESCUEHELO.version="1.0.4" RESCUEHELO.version="1.0.5"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -324,7 +330,9 @@ function RESCUEHELO:New(carrierunit, helogroupname)
self:AddTransition("Running", "Rescue", "Rescuing") self:AddTransition("Running", "Rescue", "Rescuing")
self:AddTransition("Running", "RTB", "Returning") self:AddTransition("Running", "RTB", "Returning")
self:AddTransition("Rescuing", "RTB", "Returning") self:AddTransition("Rescuing", "RTB", "Returning")
self:AddTransition("*", "Run", "Running") self:AddTransition("Returning", "Returned", "Returned")
self:AddTransition("Running", "Run", "Running")
self:AddTransition("Returned", "Run", "Running")
self:AddTransition("*", "Status", "*") self:AddTransition("*", "Status", "*")
self:AddTransition("*", "Stop", "Stopped") self:AddTransition("*", "Stop", "Stopped")
@ -378,6 +386,25 @@ function RESCUEHELO:New(carrierunit, helogroupname)
-- @param #string To To state. -- @param #string To To state.
-- @param Wrapper.Airbase#AIRBASE airbase The airbase to return to. Default is the home base. -- @param Wrapper.Airbase#AIRBASE airbase The airbase to return to. Default is the home base.
--- Triggers the FSM event "Returned" after the helo has landed.
-- @function [parent=#RESCUEHELO] Returned
-- @param #RESCUEHELO self
-- @param Wrapper.Airbase#AIRBASE airbase The airbase the helo has landed.
--- Triggers the delayed FSM event "Returned" after the helo has landed.
-- @function [parent=#RESCUEHELO] __Returned
-- @param #RESCUEHELO self
-- @param #number delay Delay in seconds.
-- @param Wrapper.Airbase#AIRBASE airbase The airbase the helo has landed.
--- On after "Returned" event user function. Called when a the the helo has landed at an airbase.
-- @function [parent=#RESCUEHELO] OnAfterReturned
-- @param #RESCUEHELO self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Airbase#AIRBASE airbase The airbase the helo has landed.
--- Triggers the FSM event "Run". --- Triggers the FSM event "Run".
-- @function [parent=#RESCUEHELO] Run -- @function [parent=#RESCUEHELO] Run
@ -705,58 +732,24 @@ function RESCUEHELO:OnEventLand(EventData)
MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug) MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug)
self:T(self.lid..text) self:T(self.lid..text)
-- Helo has rescued someone.
-- TODO: Add "Rescued" event.
if self:IsRescuing() then if self:IsRescuing() then
self:T(self.lid..string.format("Rescue helo %s returned from rescue operation.", groupname)) self:T(self.lid..string.format("Rescue helo %s returned from rescue operation.", groupname))
end end
-- Check if takeoff air or respawn in air is set. Landing event should not happen unless the helo was on a rescue mission. -- Check if takeoff air or respawn in air is set. Landing event should not happen unless the helo was on a rescue mission.
if self.takeoff==SPAWN.Takeoff.Air or self.respawninair then if self.takeoff==SPAWN.Takeoff.Air or self.respawninair then
if self:IsRescuing() then if not self:IsRescuing() then
self:T(self.lid..string.format("Rescue helo %s returned from rescue operation.", groupname)) self:E(self.lid..string.format("WARNING: Rescue helo %s landed. This should not happen for Takeoff=Air or respawninair=true and no rescue operation in progress.", groupname))
-- Set modex for respawn.
group:InitModex(self.modex)
-- Respawn helo at current airbase.
SCHEDULER:New(nil, group.RespawnAtCurrentAirbase, {group}, 3)
else
self:T2(self.lid..string.format("WARNING: Rescue helo %s landed. This should not happen for Takeoff=Air or respawninair=true unless a rescue operation finished.", groupname))
-- Respawn helo at current airbase anyway.
if self.respawn then
-- Set modex for respawn.
group:InitModex(self.modex)
-- Respawn helo at current airbase.
SCHEDULER:New(nil, group.RespawnAtCurrentAirbase, {group}, 3)
end end
end end
else -- Trigger returned event. Respawn at current airbase.
self:__Returned(3, EventData.Place)
-- Respawn helo at current airbase.
if self.respawn then
-- Set modex for respawn.
group:InitModex(self.modex)
-- Respawn helo at current airbase.
SCHEDULER:New(nil, group.RespawnAtCurrentAirbase, {group}, 3)
end
end
-- Restart the formation.
self:__Run(10)
end end
end end
@ -814,6 +807,11 @@ function RESCUEHELO:_OnEventCrashOrEject(EventData)
-- Stop FSM. -- Stop FSM.
self:Stop() self:Stop()
-- Restart.
if self.respawn then
self:__Start(5)
end
end end
end end
@ -948,11 +946,14 @@ function RESCUEHELO:onafterStatus(From, Event, To)
-- HELO is ALIVE -- -- HELO is ALIVE --
------------------- -------------------
-- Get relative fuel wrt to initial fuel of helo (DCS bug https://forums.eagle.ru/showthread.php?t=223712) -- Get (relative) fuel wrt to initial fuel of helo (DCS bug https://forums.eagle.ru/showthread.php?t=223712)
local fuel=self.helo:GetFuel()/self.HeloFuel0*100 local fuel=self.helo:GetFuel()*100
local fuelrel=fuel/self.HeloFuel0
local life=self.helo:GetUnit(1):GetLife()
local life0=self.helo:GetUnit(1):GetLife0()
-- Report current fuel. -- Report current fuel.
local text=string.format("Rescue Helo %s: state=%s fuel=%.1f", self.helo:GetName(), self:GetState(), fuel) local text=string.format("Rescue Helo %s: state=%s fuel=%.1f, rel.fuel=%.1f, life=%.1f/%.1f", self.helo:GetName(), self:GetState(), fuel, fuelrel, life, life0)
MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug) MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug)
self:T(self.lid..text) self:T(self.lid..text)
@ -973,6 +974,10 @@ function RESCUEHELO:onafterStatus(From, Event, To)
-- Respawn helo in air. -- Respawn helo in air.
self.helo=self.helo:Respawn(nil, true) self.helo=self.helo:Respawn(nil, true)
-- XXX: ATTENTION: if helo automatically RTBs on low fuel, it goes a bit cazy. The formation is not stopped and he partially dives into the water.
-- Also trying to find a ship to land on he flies right through it.
--self.helo:OptionRTBBingoFuel(false)
end end
else else
@ -986,15 +991,7 @@ function RESCUEHELO:onafterStatus(From, Event, To)
elseif self:IsRescuing() then elseif self:IsRescuing() then
if self.rtb then -- Helo is on a rescue mission.
-- Send helo back to base.
--self:RTB()
-- Switch to false.
self.rtb=false
end
end end
@ -1003,13 +1000,14 @@ function RESCUEHELO:onafterStatus(From, Event, To)
self:__Status(-30) self:__Status(-30)
end end
else else
------------------ ------------------
-- HELO is DEAD -- -- HELO is DEAD --
------------------ ------------------
if not self:IsStopped() then
-- Stop FSM. -- Stop FSM.
self:Stop() self:Stop()
@ -1021,7 +1019,9 @@ function RESCUEHELO:onafterStatus(From, Event, To)
end end
end end
--- On after "Run" event. FSM will go to "Running" state. If formation is topped, it will be started again. end
--- On after "Run" event. FSM will go to "Running" state. If formation is stopped, it will be started again.
-- @param #RESCUEHELO self -- @param #RESCUEHELO self
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
@ -1068,7 +1068,7 @@ function RESCUEHELO:_TaskRTB()
-- Task script. -- Task script.
local DCSScript = {} local DCSScript = {}
DCSScript[#DCSScript+1] = string.format('local mycarrier = UNIT:FindByName(\"%s\") ', carriername) -- The carrier unit that holds the self object. DCSScript[#DCSScript+1] = string.format('local mycarrier = UNIT:FindByName(\"%s\") ', carriername) -- The carrier unit that holds the self object.
DCSScript[#DCSScript+1] = string.format('local myhelo = mycarrier:GetState(mycarrier, \"RESCUEHELO_%d\") ', self.uid) -- Get the RECOVERYTANKER self object. DCSScript[#DCSScript+1] = string.format('local myhelo = mycarrier:GetState(mycarrier, \"RESCUEHELO_%d\") ', self.uid) -- Get the RESCUEHELO self object.
DCSScript[#DCSScript+1] = string.format('myhelo:RTB()') -- Call the function, e.g. myhelo.(self) DCSScript[#DCSScript+1] = string.format('myhelo:RTB()') -- Call the function, e.g. myhelo.(self)
-- Create task. -- Create task.
@ -1186,16 +1186,58 @@ function RESCUEHELO:onafterRTB(From, Event, To, airbase)
self:RouteRTB(airbase) self:RouteRTB(airbase)
end end
--- On after Stop event. Unhandle events and stop status updates. --- On after Returned event. Helo has landed.
-- @param #RESCUEHELO self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Airbase#AIRBASE airbase The base to which the helo has returned.
function RESCUEHELO:onafterReturned(From, Event, To, airbase)
if airbase then
local airbasename=airbase:GetName()
self:T(self.lid..string.format("Helo returned to airbase %s", tostring(airbasename)))
else
self:E(self.lid..string.format("WARNING: Helo landed but airbase (EventData.Place) is nil!"))
end
-- Respawn helo at current airbase.
if self.respawn then
-- Set modex for respawn.
self.helo:InitModex(self.modex)
-- Respawn helo at current airbase.
self.helo:RespawnAtCurrentAirbase()
-- Restart the formation.
self:__Run(10)
end
end
--- On after Stop event. Unhandle events and stop status updates. If helo is alive, it is despawned.
-- @param #RESCUEHELO self -- @param #RESCUEHELO self
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
function RESCUEHELO:onafterStop(From, Event, To) function RESCUEHELO:onafterStop(From, Event, To)
-- Stop formation
self.formation:Stop() self.formation:Stop()
-- Unhandle events.
self:UnHandleEvent(EVENTS.Land) self:UnHandleEvent(EVENTS.Land)
self:UnHandleEvent(EVENTS.Crash) self:UnHandleEvent(EVENTS.Crash)
self:UnHandleEvent(EVENTS.Ejection) self:UnHandleEvent(EVENTS.Ejection)
-- If helo is alive, despawn it.
if self.helo and self.helo:IsAlive() then
self:I(self.lid.."Stopping FSM and despawning helo.")
self.helo:Destroy()
else
self:I(self.lid.."Stopping FSM. Helo was not alive.")
end
end end