AIRBOSS v1.0.8
- Fixed bug that status reset after wave off causes a unitcorn grade.
- Optimized radio scheduler calls ==> leads to less mem consumtion according to collectgarbage("count").

RESCUEHELO v1.0.9
- Adjusted default follow time interval to 1.0 sec.
- Added SetFollowTimeInterval() function.
- Respawn after returned delayed by 5 sec.

GROUP
- Added nil check in RespawnAtCurrentAirbase() function.
This commit is contained in:
Frank 2019-08-18 22:21:41 +02:00
parent 97e1a65b52
commit ec85b42a38
3 changed files with 250 additions and 141 deletions

View File

@ -48,11 +48,15 @@
-- --
-- Heatblur's mighty F-14B Tomcat has been added (March 13th 2019) as well. -- Heatblur's mighty F-14B Tomcat has been added (March 13th 2019) as well.
-- --
--
-- ## Discussion -- ## Discussion
-- --
-- If you have questions or suggestions, please visit the [MOOSE Discord](https://discord.gg/AeYAkHP) #ops-airboss channel. -- If you have questions or suggestions, please visit the [MOOSE Discord](https://discord.gg/AeYAkHP) #ops-airboss channel.
-- There you also find an example mission and the necessary voice over sound files. Check out the **pinned messages**. -- There you also find an example mission and the necessary voice over sound files. Check out the **pinned messages**.
--
-- ## Example Missions
--
-- Example missions can be found [here](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Airboss).
-- They contain the latest development Moose.lua file.
-- --
-- ## IMPORTANT -- ## IMPORTANT
-- --
@ -1671,6 +1675,7 @@ AIRBOSS.Difficulty={
-- @field #boolean showhints If true, show step hints. -- @field #boolean showhints If true, show step hints.
-- @field #table trapsheet Groove data table recorded every 0.5 seconds. -- @field #table trapsheet Groove data table recorded every 0.5 seconds.
-- @field #boolean trapon If true, save trap sheets. -- @field #boolean trapon If true, save trap sheets.
-- @field #string debriefschedulerID Debrief scheduler ID.
-- @extends #AIRBOSS.FlightGroup -- @extends #AIRBOSS.FlightGroup
--- Main group level radio menu: F10 Other/Airboss. --- Main group level radio menu: F10 Other/Airboss.
@ -1683,7 +1688,7 @@ AIRBOSS.MenuF10Root=nil
--- Airboss class version. --- Airboss class version.
-- @field #string version -- @field #string version
AIRBOSS.version="1.0.7" AIRBOSS.version="1.0.8"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -1944,7 +1949,7 @@ function AIRBOSS:New(carriername, alias)
self.Debug=true self.Debug=true
BASE:TraceOnOff(true) BASE:TraceOnOff(true)
BASE:TraceClass(self.ClassName) BASE:TraceClass(self.ClassName)
BASE:TraceLevel(1) BASE:TraceLevel(3)
--self.dTstatus=0.1 --self.dTstatus=0.1
end end
@ -2265,6 +2270,29 @@ function AIRBOSS:New(carriername, alias)
-- @param #AIRBOSS.LSOgrade grade LSO grade. -- @param #AIRBOSS.LSOgrade grade LSO grade.
--- Triggers the FSM event "LSOGrade". Called when the LSO grades a player
-- @function [parent=#AIRBOSS] LSOGrade
-- @param #AIRBOSS self
-- @param #AIRBOSS.PlayerData playerData Player Data.
-- @param #AIRBOSS.LSOgrade grade LSO grade.
--- Triggers the FSM event "LSOGrade". Delayed called when the LSO grades a player.
-- @function [parent=#AIRBOSS] __LSOGrade
-- @param #AIRBOSS self
-- @param #number delay Delay in seconds.
-- @param #AIRBOSS.PlayerData playerData Player Data.
-- @param #AIRBOSS.LSOgrade grade LSO grade.
--- On after "LSOGrade" user function. Called when the carrier passes a waypoint of its route.
-- @function [parent=#AIRBOSS] OnAfterLSOGrade
-- @param #AIRBOSS self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #AIRBOSS.PlayerData playerData Player Data.
-- @param #AIRBOSS.LSOgrade grade LSO grade.
--- Triggers the FSM event "Stop" that stops the airboss. Event handlers are stopped. --- Triggers the FSM event "Stop" that stops the airboss. Event handlers are stopped.
-- @function [parent=#AIRBOSS] Stop -- @function [parent=#AIRBOSS] Stop
-- @param #AIRBOSS self -- @param #AIRBOSS self
@ -2494,7 +2522,8 @@ end
function AIRBOSS:CloseCurrentRecoveryWindow(delay) function AIRBOSS:CloseCurrentRecoveryWindow(delay)
if delay and delay>0 then if delay and delay>0 then
SCHEDULER:New(nil, self.CloseCurrentRecoveryWindow, {self}, delay) --SCHEDULER:New(nil, self.CloseCurrentRecoveryWindow, {self}, delay)
self:ScheduleOnce(delay, self.CloseCurrentRecoveryWindow, self)
else else
if self:IsRecovering() and self.recoverywindow and self.recoverywindow.OPEN then if self:IsRecovering() and self.recoverywindow and self.recoverywindow.OPEN then
self:RecoveryStop() self:RecoveryStop()
@ -2544,7 +2573,8 @@ function AIRBOSS:DeleteRecoveryWindow(window, delay)
if delay and delay>0 then if delay and delay>0 then
-- Delayed call. -- Delayed call.
SCHEDULER:New(nil, self.DeleteRecoveryWindow, {self, window}, delay) --SCHEDULER:New(nil, self.DeleteRecoveryWindow, {self, window}, delay)
self:ScheduleOnce(delay, self.DeleteRecoveryWindow, self, window)
else else
for i,_recovery in pairs(self.recoverytimes) do for i,_recovery in pairs(self.recoverytimes) do
@ -2964,7 +2994,8 @@ function AIRBOSS:SoundCheckLSO(delay)
if delay and delay>0 then if delay and delay>0 then
-- Delayed call. -- Delayed call.
SCHEDULER:New(nil, AIRBOSS.SoundCheckLSO, {self}, delay) --SCHEDULER:New(nil, AIRBOSS.SoundCheckLSO, {self}, delay)
self:ScheduleOnce(delay, AIRBOSS.SoundCheckLSO, self)
else else
@ -2999,7 +3030,8 @@ function AIRBOSS:SoundCheckMarshal(delay)
if delay and delay>0 then if delay and delay>0 then
-- Delayed call. -- Delayed call.
SCHEDULER:New(nil, AIRBOSS.SoundCheckMarshal, {self}, delay) --SCHEDULER:New(nil, AIRBOSS.SoundCheckMarshal, {self}, delay)
self:ScheduleOnce(delay, AIRBOSS.SoundCheckMarshal, self)
else else
@ -3249,9 +3281,13 @@ function AIRBOSS:onafterStart(From, Event, To)
self:_ActivateBeacons() self:_ActivateBeacons()
-- Schedule radio queue checks. -- Schedule radio queue checks.
self.RQLid=self.radiotimer:Schedule(self, self._CheckRadioQueue, {self.RQLSO, "LSO"}, 1, 0.01) --self.RQLid=self.radiotimer:Schedule(nil, AIRBOSS._CheckRadioQueue, {self, self.RQLSO, "LSO"}, 1, 0.1)
self.RQMid=self.radiotimer:Schedule(self, self._CheckRadioQueue, {self.RQMarshal, "MARSHAL"}, 1, 0.01) --self.RQMid=self.radiotimer:Schedule(nil, AIRBOSS._CheckRadioQueue, {self, self.RQMarshal, "MARSHAL"}, 1, 0.1)
--self:I("FF: starting timer.scheduleFunction")
--timer.scheduleFunction(AIRBOSS._CheckRadioQueueT, {airboss=self, radioqueue=self.RQLSO, name="LSO"}, timer.getTime()+1)
--timer.scheduleFunction(AIRBOSS._CheckRadioQueueT, {airboss=self, radioqueue=self.RQMarshal, name="MARSHAL"}, timer.getTime()+1)
-- Initial carrier position and orientation. -- Initial carrier position and orientation.
self.Cposition=self:GetCoordinate() self.Cposition=self:GetCoordinate()
self.Corientation=self.carrier:GetOrientationX() self.Corientation=self.carrier:GetOrientationX()
@ -3687,7 +3723,7 @@ function AIRBOSS:_CheckRecoveryTimes()
-- Closed. -- Closed.
recovery.OPEN=false recovery.OPEN=false
-- Window just closed. -- Window just closed.
recovery.OVER=true recovery.OVER=true
@ -4023,6 +4059,8 @@ end
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
function AIRBOSS:onafterStop(From, Event, To) function AIRBOSS:onafterStop(From, Event, To)
self:I(self.lid..string.format("Stopping airboss script."))
-- Unhandle events. -- Unhandle events.
self:UnHandleEvent(EVENTS.Birth) self:UnHandleEvent(EVENTS.Birth)
self:UnHandleEvent(EVENTS.Land) self:UnHandleEvent(EVENTS.Land)
@ -4032,6 +4070,8 @@ function AIRBOSS:onafterStop(From, Event, To)
self:UnHandleEvent(EVENTS.Ejection) self:UnHandleEvent(EVENTS.Ejection)
self:UnHandleEvent(EVENTS.PlayerLeaveUnit) self:UnHandleEvent(EVENTS.PlayerLeaveUnit)
self:UnHandleEvent(EVENTS.MissionEnd) self:UnHandleEvent(EVENTS.MissionEnd)
self.CallScheduler:Clear()
end end
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -5848,7 +5888,8 @@ function AIRBOSS:_SetPlayerStep(playerData, step, delay)
if delay and delay>0 then if delay and delay>0 then
-- Delayed call. -- Delayed call.
SCHEDULER:New(nil, self._SetPlayerStep, {self, playerData, step}, delay) --SCHEDULER:New(nil, self._SetPlayerStep, {self, playerData, step}, delay)
self:ScheduleOnce(delay, self._SetPlayerStep, self, playerData, step)
else else
-- Check if player still exists after possible delay. -- Check if player still exists after possible delay.
@ -7316,6 +7357,7 @@ function AIRBOSS:_InitPlayer(playerData, step)
playerData.TIG0=nil playerData.TIG0=nil
playerData.wire=nil playerData.wire=nil
playerData.flag=-100 playerData.flag=-100
playerData.debriefschedulerID=nil
-- Set us up on final if group name contains "Groove". But only for the first pass. -- Set us up on final if group name contains "Groove". But only for the first pass.
if playerData.group:GetName():match("Groove") and playerData.passes==0 then if playerData.group:GetName():match("Groove") and playerData.passes==0 then
@ -7796,6 +7838,14 @@ function AIRBOSS:_RemoveFlight(flight, completely)
self:_RemoveFlightFromQueue(self.flights, flight) self:_RemoveFlightFromQueue(self.flights, flight)
else else
-- Remove all grades until a final grade is reached.
local grades=self.playerscores[flight.name]
if grades and #grades>0 then
while #grades>0 and grades[#grades].finalscore==nil do
table.remove(grades, #grades)
end
end
-- Check if flight should be completely removed, e.g. after the player died or simply left the slot. -- Check if flight should be completely removed, e.g. after the player died or simply left the slot.
if completely then if completely then
@ -7806,15 +7856,6 @@ function AIRBOSS:_RemoveFlight(flight, completely)
-- Remove completely. -- Remove completely.
self:_RemoveFlightFromQueue(self.flights, flight) self:_RemoveFlightFromQueue(self.flights, flight)
-- Remove all grades until a final grade is reached.
local grades=self.playerscores[flight.name]
if grades and #grades>0 then
while #grades>0 and grades[#grades].finalscore==nil do
table.remove(grades, #grades)
end
end
-- Remove player from players table. -- Remove player from players table.
local playerdata=self.players[flight.name] local playerdata=self.players[flight.name]
if playerdata then if playerdata then
@ -8005,7 +8046,8 @@ function AIRBOSS:_CheckPlayerStatus()
elseif playerData.step==AIRBOSS.PatternStep.DEBRIEF then elseif playerData.step==AIRBOSS.PatternStep.DEBRIEF then
-- Debriefing in 5 seconds. -- Debriefing in 5 seconds.
SCHEDULER:New(nil, self._Debrief, {self, playerData}, 5) --SCHEDULER:New(nil, self._Debrief, {self, playerData}, 5)
playerData.debriefschedulerID=self:ScheduleOnce(5, self._Debrief, self, playerData)
-- Undefined status. -- Undefined status.
playerData.step=AIRBOSS.PatternStep.UNDEFINED playerData.step=AIRBOSS.PatternStep.UNDEFINED
@ -8186,7 +8228,8 @@ function AIRBOSS:OnEventBirth(EventData)
self:_AddF10Commands(_unitName) self:_AddF10Commands(_unitName)
-- Delaying the new player for a second, because AI units of the flight would not be registered correctly. -- Delaying the new player for a second, because AI units of the flight would not be registered correctly.
SCHEDULER:New(nil, self._NewPlayer, {self, _unitName}, 1) --SCHEDULER:New(nil, self._NewPlayer, {self, _unitName}, 1)
self:ScheduleOnce(1, self._NewPlayer, self, _unitName)
end end
end end
@ -8339,7 +8382,8 @@ function AIRBOSS:OnEventLand(EventData)
self:_SetPlayerStep(playerData, AIRBOSS.PatternStep.UNDEFINED) self:_SetPlayerStep(playerData, AIRBOSS.PatternStep.UNDEFINED)
-- Call trapped function in 1 second to make sure we did not bolter. -- Call trapped function in 1 second to make sure we did not bolter.
SCHEDULER:New(nil, self._Trapped, {self, playerData}, 1) --SCHEDULER:New(nil, self._Trapped, {self, playerData}, 1)
self:ScheduleOnce(1, self._Trapped, self, playerData)
end end
@ -10233,7 +10277,8 @@ function AIRBOSS:_Trapped(playerData)
end end
-- Call function again and check if converged or back in air. -- Call function again and check if converged or back in air.
SCHEDULER:New(nil, self._Trapped, {self, playerData}, 0.1) --SCHEDULER:New(nil, self._Trapped, {self, playerData}, 0.1)
self:ScheduleOnce(0.1, self._Trapped, self, playerData)
return return
end end
@ -12672,6 +12717,9 @@ end
-- @param #AIRBOSS.PlayerData playerData Player data. -- @param #AIRBOSS.PlayerData playerData Player data.
function AIRBOSS:_Debrief(playerData) function AIRBOSS:_Debrief(playerData)
self:F(self.lid..string.format("Debriefing of player %s.", playerData.name)) self:F(self.lid..string.format("Debriefing of player %s.", playerData.name))
-- Delete scheduler ID.
playerData.debriefschedulerID=nil
-- Switch attitude monitor off if on. -- Switch attitude monitor off if on.
playerData.attitudemonitor=false playerData.attitudemonitor=false
@ -12735,7 +12783,7 @@ function AIRBOSS:_Debrief(playerData)
-- Add LSO grade to player grades table. -- Add LSO grade to player grades table.
table.insert(self.playerscores[playerData.name], mygrade) table.insert(self.playerscores[playerData.name], mygrade)
-- Trigger grading event. -- Trigger grading event.
self:LSOGrade(playerData, mygrade) self:LSOGrade(playerData, mygrade)
@ -14299,6 +14347,14 @@ end
-- RADIO MESSAGE Functions -- RADIO MESSAGE Functions
----------------------------------------------------------------------------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Function called by DCS timer. Unused.
-- @param #table param Parameters.
-- @param #number time Time.
function AIRBOSS._CheckRadioQueueT(param, time)
AIRBOSS._CheckRadioQueue(param.airboss, param.radioqueue, param.name)
return time+0.05
end
--- Radio queue item. --- Radio queue item.
-- @type AIRBOSS.Radioitem -- @type AIRBOSS.Radioitem
-- @field #number Tplay Abs time when transmission should be played. -- @field #number Tplay Abs time when transmission should be played.
@ -14315,37 +14371,50 @@ end
-- @param #string name Name of the queue. -- @param #string name Name of the queue.
function AIRBOSS:_CheckRadioQueue(radioqueue, name) function AIRBOSS:_CheckRadioQueue(radioqueue, name)
--env.info(string.format("FF %s #radioqueue %d", name, #radioqueue))
-- Check if queue is empty. -- Check if queue is empty.
if #radioqueue==0 then if #radioqueue==0 then
if name=="LSO" then
self:T(self.lid..string.format("Stopping LSO radio queue."))
self.radiotimer:Stop(self.RQLid)
self.RQLid=nil
elseif name=="MARSHAL" then
self:T(self.lid..string.format("Stopping Marshal radio queue."))
self.radiotimer:Stop(self.RQMid)
self.RQMid=nil
end
return return
end end
-- Get current abs time. -- Get current abs time.
local time=timer.getAbsTime() local _time=timer.getAbsTime()
local playing=false local playing=false
local next=nil --#AIRBOSS.Radioitem local next=nil --#AIRBOSS.Radioitem
local remove=nil local _remove=nil
for i,_transmission in ipairs(radioqueue) do for i,_transmission in ipairs(radioqueue) do
local transmission=_transmission --#AIRBOSS.Radioitem local transmission=_transmission --#AIRBOSS.Radioitem
-- Check if transmission time has passed. -- Check if transmission time has passed.
if time>=transmission.Tplay then if _time>=transmission.Tplay then
-- Check if transmission is currently playing. -- Check if transmission is currently playing.
if transmission.isplaying then if transmission.isplaying then
-- Check if transmission is finished. -- Check if transmission is finished.
if time>=transmission.Tstarted+transmission.call.duration then if _time>=transmission.Tstarted+transmission.call.duration then
-- Transmission over. -- Transmission over.
transmission.isplaying=false transmission.isplaying=false
remove=i _remove=i
if transmission.radio.alias=="LSO" then if transmission.radio.alias=="LSO" then
self.TQLSO=time self.TQLSO=_time
elseif transmission.radio.alias=="MARSHAL" then elseif transmission.radio.alias=="MARSHAL" then
self.TQMarshal=time self.TQMarshal=_time
end end
else -- still playing else -- still playing
@ -14375,7 +14444,7 @@ function AIRBOSS:_CheckRadioQueue(radioqueue, name)
else else
if time-Tlast>=transmission.interval then if _time-Tlast>=transmission.interval then
next=transmission next=transmission
else else
@ -14400,14 +14469,15 @@ function AIRBOSS:_CheckRadioQueue(radioqueue, name)
if next~=nil and not playing then if next~=nil and not playing then
self:Broadcast(next.radio, next.call, next.loud) self:Broadcast(next.radio, next.call, next.loud)
next.isplaying=true next.isplaying=true
next.Tstarted=time next.Tstarted=_time
end end
-- Remove completed calls from queue. -- Remove completed calls from queue.
if remove then if _remove then
table.remove(radioqueue, remove) table.remove(radioqueue, _remove)
end end
return
end end
--- Add Radio transmission to radio queue. --- Add Radio transmission to radio queue.
@ -14455,12 +14525,23 @@ function AIRBOSS:RadioTransmission(radio, call, loud, delay, interval, click, pi
table.insert(self.RQLSO, transmission) table.insert(self.RQLSO, transmission)
caller="LSOCall" caller="LSOCall"
-- Schedule radio queue checks.
if not self.RQLid then
self:T(self.lid..string.format("Starting LSO radio queue."))
self.RQLid=self.radiotimer:Schedule(nil, AIRBOSS._CheckRadioQueue, {self, self.RQLSO, "LSO"}, 0.02, 0.05)
end
elseif radio.alias=="MARSHAL" then elseif radio.alias=="MARSHAL" then
table.insert(self.RQMarshal, transmission) table.insert(self.RQMarshal, transmission)
caller="MarshalCall" caller="MarshalCall"
if not self.RQMid then
self:T(self.lid..string.format("Starting Marhal radio queue."))
self.RQMid=self.radiotimer:Schedule(nil, AIRBOSS._CheckRadioQueue, {self, self.RQMarshal, "MARSHAL"}, 0.02, 0.05)
end
end end
@ -14743,7 +14824,8 @@ function AIRBOSS:MessageToPlayer(playerData, message, sender, receiver, duration
if delay and delay>0 then if delay and delay>0 then
-- Delayed call. -- Delayed call.
SCHEDULER:New(nil, self.MessageToPlayer, {self, playerData, message, sender, receiver, duration, clear}, delay) --SCHEDULER:New(nil, self.MessageToPlayer, {self, playerData, message, sender, receiver, duration, clear}, delay)
self:ScheduleOnce(delay, self.MessageToPlayer, self, playerData, message, sender, receiver, duration, clear)
else else
-- Wait until previous sound finished. -- Wait until previous sound finished.
@ -15797,6 +15879,11 @@ function AIRBOSS:_ResetPlayerStatus(_unitName)
-- Remove flight from queues. Collapse marshal stack if necessary. -- Remove flight from queues. Collapse marshal stack if necessary.
-- Section members are removed from the Spinning queue. If flight is member, he is removed from the section. -- Section members are removed from the Spinning queue. If flight is member, he is removed from the section.
self:_RemoveFlight(playerData) self:_RemoveFlight(playerData)
-- Stop pending debrief scheduler.
if playerData.debriefschedulerID and self.Scheduler then
self.Scheduler:Stop(playerData.debriefschedulerID)
end
-- Initialize player data. -- Initialize player data.
self:_InitPlayer(playerData) self:_InitPlayer(playerData)

View File

@ -57,6 +57,7 @@
-- @field #string alias Alias of the spawn group. -- @field #string alias Alias of the spawn group.
-- @field #number uid Unique ID of this helo. -- @field #number uid Unique ID of this helo.
-- @field #number modex Tail number of the helo. -- @field #number modex Tail number of the helo.
-- @field #number dtFollow Follow time update interval in seconds. Default 1.0 sec.
-- @extends Core.Fsm#FSM -- @extends Core.Fsm#FSM
--- Rescue Helo --- Rescue Helo
@ -227,6 +228,7 @@ RESCUEHELO = {
alias = nil, alias = nil,
uid = 0, uid = 0,
modex = nil, modex = nil,
dtFollow = nil,
} }
--- Unique ID (global). --- Unique ID (global).
@ -235,7 +237,7 @@ _RESCUEHELOID=0
--- Class version. --- Class version.
-- @field #string version -- @field #string version
RESCUEHELO.version="1.0.8" RESCUEHELO.version="1.0.9"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -303,6 +305,7 @@ function RESCUEHELO:New(carrierunit, helogroupname)
self:SetRescueZone() self:SetRescueZone()
self:SetRescueHoverSpeed() self:SetRescueHoverSpeed()
self:SetRescueDuration() self:SetRescueDuration()
self:SetFollowTimeInterval()
self:SetRescueStopBoatOff() self:SetRescueStopBoatOff()
-- Some more. -- Some more.
@ -644,6 +647,15 @@ function RESCUEHELO:SetModex(modex)
return self return self
end end
--- Set follow time update interval.
-- @param #RESCUEHELO self
-- @param #number dt Time interval in seconds. Default 1.0 sec.
-- @return #RESCUEHELO self
function RESCUEHELO:SetFollowTimeInterval(dt)
self.dtFollow=dt or 1.0
return self
end
--- Use an uncontrolled aircraft already present in the mission rather than spawning a new helo as initial rescue helo. --- Use an uncontrolled aircraft already present in the mission rather than spawning a new helo as initial rescue helo.
-- This can be useful when interfaced with, e.g., a warehouse. -- This can be useful when interfaced with, e.g., a warehouse.
-- The group name is the one specified in the @{#RESCUEHELO.New} function. -- The group name is the one specified in the @{#RESCUEHELO.New} function.
@ -895,7 +907,7 @@ function RESCUEHELO:onafterStart(From, Event, To)
-- Use an uncontrolled aircraft group. -- Use an uncontrolled aircraft group.
self.helo=GROUP:FindByName(self.helogroupname) self.helo=GROUP:FindByName(self.helogroupname)
if self.helo:IsAlive() then if self.helo and self.helo:IsAlive() then
-- Start uncontrolled group. -- Start uncontrolled group.
self.helo:StartUncontrolled() self.helo:StartUncontrolled()
@ -940,6 +952,9 @@ function RESCUEHELO:onafterStart(From, Event, To)
-- Formation parameters. -- Formation parameters.
self.formation:FormationCenterWing(-self.offsetX, 50, math.abs(self.altitude), 50, self.offsetZ, 50) self.formation:FormationCenterWing(-self.offsetX, 50, math.abs(self.altitude), 50, self.offsetZ, 50)
-- Set follow time interval.
self.formation:SetFollowTimeInterval(self.dtFollow)
-- Formation mode. -- Formation mode.
self.formation:SetFlightModeFormation(self.helo) self.formation:SetFlightModeFormation(self.helo)
@ -1005,7 +1020,7 @@ function RESCUEHELO:onafterStatus(From, Event, To)
else else
-- Send helo back to base. -- Send helo back to base.
self:RTB() self:RTB(self.airbase)
end end
@ -1196,7 +1211,9 @@ function RESCUEHELO:onafterReturned(From, Event, To, airbase)
self.helo:InitModex(self.modex) self.helo:InitModex(self.modex)
-- Respawn helo at current airbase. -- Respawn helo at current airbase.
self.helo:RespawnAtCurrentAirbase() if self.helo and self.helo:IsAlive() then
self:ScheduleOnce(5, self.helo.RespawnAtCurrentAirbase, self.helo)
end
-- Restart the formation. -- Restart the formation.
self:__Run(10) self:__Run(10)

View File

@ -1773,110 +1773,115 @@ end
function GROUP:RespawnAtCurrentAirbase(SpawnTemplate, Takeoff, Uncontrolled) -- R2.4 function GROUP:RespawnAtCurrentAirbase(SpawnTemplate, Takeoff, Uncontrolled) -- R2.4
self:F2( { SpawnTemplate, Takeoff, Uncontrolled} ) self:F2( { SpawnTemplate, Takeoff, Uncontrolled} )
-- Get closest airbase. Should be the one we are currently on. if self and self:IsAlive() then
local airbase=self:GetCoordinate():GetClosestAirbase()
if airbase then
self:F2("Closest airbase = "..airbase:GetName())
else
self:E("ERROR: could not find closest airbase!")
return nil
end
-- Takeoff type. Default hot.
Takeoff = Takeoff or SPAWN.Takeoff.Hot
-- Coordinate of the airbase.
local AirbaseCoord=airbase:GetCoordinate()
-- Spawn template.
SpawnTemplate = SpawnTemplate or self:GetTemplate()
if SpawnTemplate then -- Get closest airbase. Should be the one we are currently on.
local airbase=self:GetCoordinate():GetClosestAirbase()
local SpawnPoint = SpawnTemplate.route.points[1]
-- These are only for ships.
SpawnPoint.linkUnit = nil
SpawnPoint.helipadId = nil
SpawnPoint.airdromeId = nil
-- Aibase id and category.
local AirbaseID = airbase:GetID()
local AirbaseCategory = airbase:GetDesc().category
if AirbaseCategory == Airbase.Category.SHIP or AirbaseCategory == Airbase.Category.HELIPAD then if airbase then
SpawnPoint.linkUnit = AirbaseID self:F2("Closest airbase = "..airbase:GetName())
SpawnPoint.helipadId = AirbaseID else
elseif AirbaseCategory == Airbase.Category.AIRDROME then self:E("ERROR: could not find closest airbase!")
SpawnPoint.airdromeId = AirbaseID return nil
end end
-- Takeoff type. Default hot.
Takeoff = Takeoff or SPAWN.Takeoff.Hot
SpawnPoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type -- Coordinate of the airbase.
SpawnPoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action local AirbaseCoord=airbase:GetCoordinate()
-- Get the units of the group. -- Spawn template.
local units=self:GetUnits() SpawnTemplate = SpawnTemplate or self:GetTemplate()
local x if SpawnTemplate then
local y
for UnitID=1,#units do local SpawnPoint = SpawnTemplate.route.points[1]
-- These are only for ships.
SpawnPoint.linkUnit = nil
SpawnPoint.helipadId = nil
SpawnPoint.airdromeId = nil
-- Aibase id and category.
local AirbaseID = airbase:GetID()
local AirbaseCategory = airbase:GetDesc().category
if AirbaseCategory == Airbase.Category.SHIP or AirbaseCategory == Airbase.Category.HELIPAD then
SpawnPoint.linkUnit = AirbaseID
SpawnPoint.helipadId = AirbaseID
elseif AirbaseCategory == Airbase.Category.AIRDROME then
SpawnPoint.airdromeId = AirbaseID
end
SpawnPoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type
SpawnPoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action
-- Get the units of the group.
local units=self:GetUnits()
local x
local y
for UnitID=1,#units do
local unit=units[UnitID] --Wrapper.Unit#UNIT
-- Get closest parking spot of current unit. Note that we look for occupied spots since the unit is currently sitting on it!
local Parkingspot, TermialID, Distance=unit:GetCoordinate():GetClosestParkingSpot(airbase)
local unit=units[UnitID] --Wrapper.Unit#UNIT --Parkingspot:MarkToAll("parking spot")
self:T2(string.format("Closest parking spot distance = %s, terminal ID=%s", tostring(Distance), tostring(TermialID)))
-- Get closest parking spot of current unit. Note that we look for occupied spots since the unit is currently sitting on it!
local Parkingspot, TermialID, Distance=unit:GetCoordinate():GetClosestParkingSpot(airbase)
--Parkingspot:MarkToAll("parking spot")
self:T2(string.format("Closest parking spot distance = %s, terminal ID=%s", tostring(Distance), tostring(TermialID)))
-- Get unit coordinates for respawning position.
local uc=unit:GetCoordinate()
--uc:MarkToAll(string.format("re-spawnplace %s terminal %d", unit:GetName(), TermialID))
SpawnTemplate.units[UnitID].x = uc.x --Parkingspot.x
SpawnTemplate.units[UnitID].y = uc.z --Parkingspot.z
SpawnTemplate.units[UnitID].alt = uc.y --Parkingspot.y
SpawnTemplate.units[UnitID].parking = TermialID
SpawnTemplate.units[UnitID].parking_id = nil
--SpawnTemplate.units[UnitID].unitId=nil
end
--SpawnTemplate.groupId=nil
SpawnPoint.x = SpawnTemplate.units[1].x --x --AirbaseCoord.x
SpawnPoint.y = SpawnTemplate.units[1].y --y --AirbaseCoord.z
SpawnPoint.alt = SpawnTemplate.units[1].alt --AirbaseCoord:GetLandHeight()
SpawnTemplate.x = SpawnTemplate.units[1].x --x --AirbaseCoord.x
SpawnTemplate.y = SpawnTemplate.units[1].y --y --AirbaseCoord.z
-- Set uncontrolled state.
SpawnTemplate.uncontrolled=Uncontrolled
-- Set radio frequency and modulation.
if self.InitRespawnRadio then
SpawnTemplate.communication=self.InitRespawnRadio
end
if self.InitRespawnFreq then
SpawnTemplate.frequency=self.InitRespawnFreq
end
if self.InitRespawnModu then
SpawnTemplate.modulation=self.InitRespawnModu
end
-- Destroy old group.
self:Destroy(false)
-- Spawn new group.
_DATABASE:Spawn(SpawnTemplate)
-- Reset events. -- Get unit coordinates for respawning position.
self:ResetEvents() local uc=unit:GetCoordinate()
--uc:MarkToAll(string.format("re-spawnplace %s terminal %d", unit:GetName(), TermialID))
return self
SpawnTemplate.units[UnitID].x = uc.x --Parkingspot.x
SpawnTemplate.units[UnitID].y = uc.z --Parkingspot.z
SpawnTemplate.units[UnitID].alt = uc.y --Parkingspot.y
SpawnTemplate.units[UnitID].parking = TermialID
SpawnTemplate.units[UnitID].parking_id = nil
--SpawnTemplate.units[UnitID].unitId=nil
end
--SpawnTemplate.groupId=nil
SpawnPoint.x = SpawnTemplate.units[1].x --x --AirbaseCoord.x
SpawnPoint.y = SpawnTemplate.units[1].y --y --AirbaseCoord.z
SpawnPoint.alt = SpawnTemplate.units[1].alt --AirbaseCoord:GetLandHeight()
SpawnTemplate.x = SpawnTemplate.units[1].x --x --AirbaseCoord.x
SpawnTemplate.y = SpawnTemplate.units[1].y --y --AirbaseCoord.z
-- Set uncontrolled state.
SpawnTemplate.uncontrolled=Uncontrolled
-- Set radio frequency and modulation.
if self.InitRespawnRadio then
SpawnTemplate.communication=self.InitRespawnRadio
end
if self.InitRespawnFreq then
SpawnTemplate.frequency=self.InitRespawnFreq
end
if self.InitRespawnModu then
SpawnTemplate.modulation=self.InitRespawnModu
end
-- Destroy old group.
self:Destroy(false)
-- Spawn new group.
_DATABASE:Spawn(SpawnTemplate)
-- Reset events.
self:ResetEvents()
return self
end
else
self:E("WARNING: GROUP is not alive!")
end end
return nil return nil