mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
AB 0.95wip
This commit is contained in:
parent
70d1f96681
commit
6992e47a66
@ -85,10 +85,9 @@
|
|||||||
-- ### Open Questions?
|
-- ### Open Questions?
|
||||||
--
|
--
|
||||||
-- * Currently the script does not support spin patterns. Marshal releases flights only when there is a free slot in the landing pattern. How is this handled in real life?
|
-- * Currently the script does not support spin patterns. Marshal releases flights only when there is a free slot in the landing pattern. How is this handled in real life?
|
||||||
-- * What is the next step after a pattern wave off during Case II or III recovery?
|
-- * What is the next step after a pattern wave off during Case II or III recovery? A: Go back to start!
|
||||||
-- * What are the conditions for waving off flights when they get too close to a flight ahead in the pattern? At which pattern steps are flights waved off because of this?
|
-- * What are the conditions for waving off flights when they get too close to a flight ahead in the pattern? At which pattern steps are flights waved off because of this?
|
||||||
-- * Some more LSO gradings could be added. What is missing and what are the conditions?
|
-- * Some more LSO gradings could be added. What is missing and what are the conditions?
|
||||||
-- * For the A-4E-C, what are the AoA thresholds for being on speed, (a little) slow, (a little) fast in **degrees**? In know the numbers in units of the indexer but need a proper conversion to degrees.
|
|
||||||
--
|
--
|
||||||
-- If you know the answer to any of this, please get in touch with me! The necessary infrastructure to implement it is most likely already there.
|
-- If you know the answer to any of this, please get in touch with me! The necessary infrastructure to implement it is most likely already there.
|
||||||
--
|
--
|
||||||
@ -197,6 +196,7 @@
|
|||||||
-- @field #number collisiondist Distance up to which collision checks are done.
|
-- @field #number collisiondist Distance up to which collision checks are done.
|
||||||
-- @field #number Tmessage Default duration in seconds messages are displayed to players.
|
-- @field #number Tmessage Default duration in seconds messages are displayed to players.
|
||||||
-- @field #string soundfolder Folder within the mission (miz) file where airboss sound files are located.
|
-- @field #string soundfolder Folder within the mission (miz) file where airboss sound files are located.
|
||||||
|
-- @field #boolean despawnshutdown Despawn group after engine shutdown.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- Be the boss!
|
--- Be the boss!
|
||||||
@ -926,6 +926,7 @@ AIRBOSS = {
|
|||||||
collisiondist = nil,
|
collisiondist = nil,
|
||||||
Tmessage = nil,
|
Tmessage = nil,
|
||||||
soundfolder = nil,
|
soundfolder = nil,
|
||||||
|
despawnshutdown= nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Aircraft types capable of landing on carrier (human+AI).
|
--- Aircraft types capable of landing on carrier (human+AI).
|
||||||
@ -1604,6 +1605,7 @@ AIRBOSS.Difficulty={
|
|||||||
-- @field #boolean ballcall If true, flight called the ball in the groove.
|
-- @field #boolean ballcall If true, flight called the ball in the groove.
|
||||||
-- @field #table elements Flight group elements.
|
-- @field #table elements Flight group elements.
|
||||||
-- @field #number Tcharlie Charlie (abs) time in seconds.
|
-- @field #number Tcharlie Charlie (abs) time in seconds.
|
||||||
|
-- @field #string name Player name or name of first AI unit.
|
||||||
|
|
||||||
--- Parameters of an element in a flight group.
|
--- Parameters of an element in a flight group.
|
||||||
-- @type AIRBOSS.FlightElement
|
-- @type AIRBOSS.FlightElement
|
||||||
@ -1613,11 +1615,11 @@ AIRBOSS.Difficulty={
|
|||||||
-- @field #string onboard Onboard number of the aircraft.
|
-- @field #string onboard Onboard number of the aircraft.
|
||||||
-- @field #boolean ballcall If true, flight called the ball in the groove.
|
-- @field #boolean ballcall If true, flight called the ball in the groove.
|
||||||
-- @field #boolean recovered If true, element was successfully recovered.
|
-- @field #boolean recovered If true, element was successfully recovered.
|
||||||
|
-- @field #boolean isseclead If true, element is the section lead.
|
||||||
|
|
||||||
--- Player data table holding all important parameters of each player.
|
--- Player data table holding all important parameters of each player.
|
||||||
-- @type AIRBOSS.PlayerData
|
-- @type AIRBOSS.PlayerData
|
||||||
-- @field Wrapper.Unit#UNIT unit Aircraft of the player.
|
-- @field Wrapper.Unit#UNIT unit Aircraft of the player.
|
||||||
-- @field #string name Player name.
|
|
||||||
-- @field Wrapper.Client#CLIENT client Client object of player.
|
-- @field Wrapper.Client#CLIENT client Client object of player.
|
||||||
-- @field #string callsign Callsign of player.
|
-- @field #string callsign Callsign of player.
|
||||||
-- @field #string difficulty Difficulty level.
|
-- @field #string difficulty Difficulty level.
|
||||||
@ -1659,14 +1661,14 @@ AIRBOSS.version="0.9.5wip"
|
|||||||
-- TODO list
|
-- TODO list
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- TODO: Despawn AI after landing/engine shutdown option.
|
-- TODO: Handle cases where AI crashes on carrier deck ==> Clean up deck.
|
||||||
-- TODO: Do not remove recovered elements but only set switch. Remove only groups which are completely recovered.
|
|
||||||
-- TODO: Handle cases where AI crashes on carrier deck.
|
|
||||||
-- TODO: Spin pattern. Add radio menu entry. Not sure what to add though?!
|
-- TODO: Spin pattern. Add radio menu entry. Not sure what to add though?!
|
||||||
-- TODO: Player eject and crash debrief "gradings".
|
-- TODO: Player eject and crash debrief "gradings".
|
||||||
-- TODO: What happens when section lead or member dies?
|
|
||||||
-- TODO: PWO during case 2/3.
|
-- TODO: PWO during case 2/3.
|
||||||
-- TODO: PWO when player comes too close to other flight.
|
-- TODO: PWO when player comes too close to other flight.
|
||||||
|
-- DONE: Despawn AI after engine shutdown option.
|
||||||
|
-- DONE: What happens when section lead or member dies?
|
||||||
|
-- DONE: Do not remove recovered elements but only set switch. Remove only groups which are completely recovered.
|
||||||
-- DONE: Option to filter AI groups for recovery.
|
-- DONE: Option to filter AI groups for recovery.
|
||||||
-- DONE: Rework radio messages. Better control over player board numbers.
|
-- DONE: Rework radio messages. Better control over player board numbers.
|
||||||
-- DONE: Case I & II/III zone so that player gets into pattern automatically. Case I 3 position on the circle. Case II/III when the player enters the approach corridor maybe?
|
-- DONE: Case I & II/III zone so that player gets into pattern automatically. Case I 3 position on the circle. Case II/III when the player enters the approach corridor maybe?
|
||||||
@ -1810,6 +1812,9 @@ function AIRBOSS:New(carriername, alias)
|
|||||||
-- Airboss is a nice guy.
|
-- Airboss is a nice guy.
|
||||||
self:SetAirbossNiceGuy()
|
self:SetAirbossNiceGuy()
|
||||||
|
|
||||||
|
-- No despawn after engine shutdown by default.
|
||||||
|
self:SetDespawnOnEngineShutdown(false)
|
||||||
|
|
||||||
-- Mission uses static weather by default.
|
-- Mission uses static weather by default.
|
||||||
self:SetStaticWeather()
|
self:SetStaticWeather()
|
||||||
|
|
||||||
@ -2433,6 +2438,20 @@ function AIRBOSS:SetAirbossNiceGuy(switch)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Despawn AI groups after they they shut down their engines
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
-- @param #boolean switch If true or nil, AI groups are despawned.
|
||||||
|
-- @return #AIRBOSS self
|
||||||
|
function AIRBOSS:SetDespawnOnEngineShutdown(switch)
|
||||||
|
if switch==true or switch==nil then
|
||||||
|
self.despawnshutdown=true
|
||||||
|
else
|
||||||
|
self.despawnshutdown=false
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set folder where the airboss sound files are located **within you mission (miz) file**.
|
--- Set folder where the airboss sound files are located **within you mission (miz) file**.
|
||||||
-- The default path is "l10n/DEFAULT/" but sound files simply copied there will be removed by DCS the next time you save the mission.
|
-- The default path is "l10n/DEFAULT/" but sound files simply copied there will be removed by DCS the next time you save the mission.
|
||||||
-- However, if you create a new folder inside the miz file, which contains the sounds, it will not be deleted and can be used.
|
-- However, if you create a new folder inside the miz file, which contains the sounds, it will not be deleted and can be used.
|
||||||
@ -2897,10 +2916,12 @@ function AIRBOSS:onafterStart(From, Event, To)
|
|||||||
-- Handle events.
|
-- Handle events.
|
||||||
self:HandleEvent(EVENTS.Birth)
|
self:HandleEvent(EVENTS.Birth)
|
||||||
self:HandleEvent(EVENTS.Land)
|
self:HandleEvent(EVENTS.Land)
|
||||||
|
self:HandleEvent(EVENTS.EngineShutdown)
|
||||||
|
self:HandleEvent(EVENTS.Takeoff)
|
||||||
self:HandleEvent(EVENTS.Crash)
|
self:HandleEvent(EVENTS.Crash)
|
||||||
self:HandleEvent(EVENTS.Ejection)
|
self:HandleEvent(EVENTS.Ejection)
|
||||||
self:HandleEvent(EVENTS.PlayerLeaveUnit, self._PlayerLeft)
|
self:HandleEvent(EVENTS.PlayerLeaveUnit, self._PlayerLeft)
|
||||||
--self:HandleEvent(EVENTS.MissionEnd)
|
self:HandleEvent(EVENTS.MissionEnd)
|
||||||
|
|
||||||
-- Start status check in 1 second.
|
-- Start status check in 1 second.
|
||||||
self:__Status(1)
|
self:__Status(1)
|
||||||
@ -4041,7 +4062,6 @@ function AIRBOSS:_GetNextMarshalFight()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Check marshal and pattern queues.
|
--- Check marshal and pattern queues.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
function AIRBOSS:_CheckQueue()
|
function AIRBOSS:_CheckQueue()
|
||||||
@ -4087,12 +4107,19 @@ function AIRBOSS:_CheckQueue()
|
|||||||
-- Check if carrier is currently in recovery mode.
|
-- Check if carrier is currently in recovery mode.
|
||||||
if not self:IsRecovering() then
|
if not self:IsRecovering() then
|
||||||
|
|
||||||
|
-----------------------------
|
||||||
|
-- Switching Recovery Case --
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
-- Loop over all flights currently in the marshal queue.
|
-- Loop over all flights currently in the marshal queue.
|
||||||
for _,_flight in pairs(self.Qmarshal) do
|
for _,_flight in pairs(self.Qmarshal) do
|
||||||
local flight=_flight --#AIRBOSS.FlightGroup
|
local flight=_flight --#AIRBOSS.FlightGroup
|
||||||
|
|
||||||
-- Check if they have the right case.
|
-- TODO: In principle this should be done/necessary only if case 1-->2/3 or 2/3-->1, right?
|
||||||
if flight.case~=self.case then
|
-- When recovery switches from 2->3 or 3-->2 nothing changes in the marshal stack.
|
||||||
|
|
||||||
|
-- Check if a change of stack is necessary.
|
||||||
|
if (flight.case==1 and self.case>1) or (flight.case>1 and self.case==1) then
|
||||||
|
|
||||||
-- Remove flight from marshal queue.
|
-- Remove flight from marshal queue.
|
||||||
local removed=self:_RemoveFlightFromQueue(self.Qmarshal, flight)
|
local removed=self:_RemoveFlightFromQueue(self.Qmarshal, flight)
|
||||||
@ -4114,7 +4141,14 @@ function AIRBOSS:_CheckQueue()
|
|||||||
|
|
||||||
-- Break the loop so that only one flight per 30 seconds is removed. No spam of messages, no conflict with the loop over queue entries.
|
-- Break the loop so that only one flight per 30 seconds is removed. No spam of messages, no conflict with the loop over queue entries.
|
||||||
break
|
break
|
||||||
|
|
||||||
|
elseif flight.case~=self.case then
|
||||||
|
|
||||||
|
-- This should handle 2-->3 or 3-->2
|
||||||
|
flight.case=self.case
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -4173,6 +4207,7 @@ function AIRBOSS:_CheckQueue()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Clear flight for landing. AI are removed from Marshal queue and the Marshal stack is collapsed.
|
--- Clear flight for landing. AI are removed from Marshal queue and the Marshal stack is collapsed.
|
||||||
-- If next in line is an AI flight, this is done. If human player is next, we wait for "Commence" via F10 radio menu command.
|
-- If next in line is an AI flight, this is done. If human player is next, we wait for "Commence" via F10 radio menu command.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
@ -4447,19 +4482,27 @@ function AIRBOSS:_MarshalPlayer(playerData, stack)
|
|||||||
self:_AddMarshalGroup(playerData, stack)
|
self:_AddMarshalGroup(playerData, stack)
|
||||||
|
|
||||||
-- Set step to holding.
|
-- Set step to holding.
|
||||||
playerData.step=AIRBOSS.PatternStep.HOLDING
|
self:_SetPlayerStep(playerData, AIRBOSS.PatternStep.HOLDING)
|
||||||
playerData.warning=nil
|
|
||||||
|
|
||||||
-- Holding switch to nil until player arrives in the holding zone.
|
-- Holding switch to nil until player arrives in the holding zone.
|
||||||
playerData.holding=nil
|
playerData.holding=nil
|
||||||
|
|
||||||
-- Set same stack for all flights in section.
|
-- Set same stack for all flights in section.
|
||||||
for _,_flight in pairs(playerData.section) do
|
for _,_flight in pairs(playerData.section) do
|
||||||
-- TODO: inform section members.
|
|
||||||
local flight=_flight --#AIRBOSS.PlayerData
|
local flight=_flight --#AIRBOSS.PlayerData
|
||||||
flight.case=playerData.case
|
|
||||||
flight.step=AIRBOSS.PatternStep.HOLDING
|
-- TODO: Inform player? Should be done by lead via radio?
|
||||||
|
|
||||||
|
-- Set step.
|
||||||
|
self:_SetPlayerStep(flight, AIRBOSS.PatternStep.HOLDING)
|
||||||
|
|
||||||
|
-- Holding to nil, until arrived.
|
||||||
flight.holding=nil
|
flight.holding=nil
|
||||||
|
|
||||||
|
-- Set case to that of lead.
|
||||||
|
flight.case=playerData.case
|
||||||
|
|
||||||
|
-- Set stack flag.
|
||||||
flight.flag:Set(stack)
|
flight.flag:Set(stack)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -5326,7 +5369,8 @@ function AIRBOSS:_PrintQueue(queue, name)
|
|||||||
end
|
end
|
||||||
for j,_element in pairs(flight.elements) do
|
for j,_element in pairs(flight.elements) do
|
||||||
local element=_element --#AIRBOSS.FlightElement
|
local element=_element --#AIRBOSS.FlightElement
|
||||||
text=text..string.format("\n (%d) %s (%s): ai=%s, ballcall=%s, recovered=%s", j, element.onboard, element.unitname, tostring(element.ai), tostring(element.ballcall), tostring(element.recovered))
|
text=text..string.format("\n (%d) %s (%s): ai=%s, ballcall=%s, recovered=%s",
|
||||||
|
j, element.onboard, element.unitname, tostring(element.ai), tostring(element.ballcall), tostring(element.recovered))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -5371,9 +5415,7 @@ function AIRBOSS:_CreateFlightGroup(group)
|
|||||||
flight.section={}
|
flight.section={}
|
||||||
flight.ballcall=false
|
flight.ballcall=false
|
||||||
flight.holding=nil
|
flight.holding=nil
|
||||||
|
flight.name=flight.group:GetUnit(1):GetName() --Will be overwritten in _Newplayer with player name if human player in the group.
|
||||||
-- TODO Name should also be set for AI as it is used to get the section lead. Switch this from PlayerData to FlightGroup enumerator.
|
|
||||||
flight.name=flight.group:GetUnit(1):GetName()
|
|
||||||
|
|
||||||
-- Note, this should be re-set elsewhere!
|
-- Note, this should be re-set elsewhere!
|
||||||
flight.case=self.case
|
flight.case=self.case
|
||||||
@ -5390,7 +5432,7 @@ function AIRBOSS:_CreateFlightGroup(group)
|
|||||||
element.onboard=flight.onboardnumbers[element.unitname]
|
element.onboard=flight.onboardnumbers[element.unitname]
|
||||||
element.ballcall=false
|
element.ballcall=false
|
||||||
element.ai=not self:_IsHumanUnit(unit)
|
element.ai=not self:_IsHumanUnit(unit)
|
||||||
element.recovered=false
|
element.recovered=nil
|
||||||
text=text..string.format("\n[%d] %s onboard #%s, AI=%s", i, element.unitname, tostring(element.onboard), tostring(element.ai))
|
text=text..string.format("\n[%d] %s onboard #%s, AI=%s", i, element.unitname, tostring(element.onboard), tostring(element.ai))
|
||||||
table.insert(flight.elements, element)
|
table.insert(flight.elements, element)
|
||||||
end
|
end
|
||||||
@ -5400,6 +5442,7 @@ function AIRBOSS:_CreateFlightGroup(group)
|
|||||||
if flight.ai then
|
if flight.ai then
|
||||||
local onboard=flight.onboardnumbers[flight.seclead]
|
local onboard=flight.onboardnumbers[flight.seclead]
|
||||||
flight.onboard=onboard
|
flight.onboard=onboard
|
||||||
|
flight.elements[1].isseclead=true
|
||||||
else
|
else
|
||||||
flight.onboard=self:_GetOnboardNumberPlayer(group)
|
flight.onboard=self:_GetOnboardNumberPlayer(group)
|
||||||
end
|
end
|
||||||
@ -5652,29 +5695,85 @@ function AIRBOSS:_RemoveDeadFlightGroups()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Chech if all elements of a flight were recovered.
|
--- Get the lead flight group of a flight group.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param #AIRBOSS.FlightGroup flight
|
-- @param #AIRBOSS.FlightGroup flight Flight group to check.
|
||||||
-- @return #boolean If true, all elements landed.
|
-- @return #AIRBOSS.FlightGroup Flight group of the leader or flight itself if no other leader.
|
||||||
function AIRBOSS:_CheckAllRecovered(flight)
|
function AIRBOSS:_GetLeadFlight(flight)
|
||||||
|
|
||||||
for _,_element in pairs(flight.elements) do
|
-- Init.
|
||||||
|
local lead=flight
|
||||||
|
|
||||||
|
-- Only human players can be section leads of other players.
|
||||||
|
if flight.name~=flight.seclead then
|
||||||
|
lead=self.players[flight.seclead]
|
||||||
|
end
|
||||||
|
|
||||||
|
return lead
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if all elements of a flight were recovered. This also checks potential section members.
|
||||||
|
-- If so, flight is removed from the queue.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
-- @param #AIRBOSS.FlightGroup flight Flight group to check.
|
||||||
|
-- @return #boolean If true, all elements landed.
|
||||||
|
function AIRBOSS:_CheckSectionRecovered(flight)
|
||||||
|
|
||||||
|
-- Nil check.
|
||||||
|
if flight==nil then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get the lead flight first, so that we can also check all section members.
|
||||||
|
local lead=self:_GetLeadFlight(flight)
|
||||||
|
|
||||||
|
-- Check all elements of the lead flight group.
|
||||||
|
for _,_element in pairs(lead.elements) do
|
||||||
local element=_element --#AIROBSS.FlightElement
|
local element=_element --#AIROBSS.FlightElement
|
||||||
if not element.recovered then
|
if not element.recovered then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Now check all section members, if any.
|
||||||
|
for _,_section in pairs(lead.section) do
|
||||||
|
local sectionmember=_section --#AIRBOSS.FlightGroup
|
||||||
|
|
||||||
|
-- Check all elements of the secmember flight group.
|
||||||
|
for _,_element in pairs(sectionmember.elements) do
|
||||||
|
local element=_element --#AIROBSS.FlightElement
|
||||||
|
if not element.recovered then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Remove lead flight from pattern queue. It is this flight who is added to the queue.
|
||||||
|
self:_RemoveFlightFromQueue(self.Qpattern, lead)
|
||||||
|
|
||||||
|
-- Just for now, check if it is in other queues as well.
|
||||||
|
if self:_InQueue(self.Qmarshal, lead.group) then
|
||||||
|
self:E("ERROR: flight group should not be in marshal queue")
|
||||||
|
self:_RemoveFlightFromMarshalQueue(lead, true)
|
||||||
|
end
|
||||||
|
-- Just for now, check if it is in other queues as well.
|
||||||
|
if self:_InQueue(self.Qwaiting, lead.group) then
|
||||||
|
self:E("ERROR: flight group should not be in pattern queue")
|
||||||
|
self:_RemoveFlightFromQueue(self.Qwaiting, lead)
|
||||||
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Sets flag recovered=true for a flight element, which was successfully recovered (landed).
|
--- Sets flag recovered=true for a flight element, which was successfully recovered (landed).
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param Wrapper.Unit#UNIT unit The aircraft unit that was recovered.
|
-- @param Wrapper.Unit#UNIT unit The aircraft unit that was recovered.
|
||||||
-- @return #boolean If true, all flight elements were rerovered.
|
-- @return #AIRBOSS.FlightGroup Flight group of element.
|
||||||
function AIRBOSS:_RecoveredElement(unit)
|
function AIRBOSS:_RecoveredElement(unit)
|
||||||
local element=self:_GetFlightElement(unit:GetName()) --#AIRBOSS.FlightElement
|
local element, idx, flight=self:_GetFlightElement(unit:GetName()) --#AIRBOSS.FlightElement
|
||||||
element.recovered=true
|
element.recovered=true
|
||||||
|
|
||||||
|
return flight
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Remove a flight group from the Marshal queue. Marshal stack is collapsed, too, if flight was in the queue. Waiting flights are send to marshal.
|
--- Remove a flight group from the Marshal queue. Marshal stack is collapsed, too, if flight was in the queue. Waiting flights are send to marshal.
|
||||||
@ -5797,6 +5896,65 @@ function AIRBOSS:_RemoveUnitFromFlight(unit)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Update section if a flight is removed.
|
||||||
|
-- If removed flight is member of a section, he is removed for the leaders section.
|
||||||
|
-- If removed flight is the section lead, we try to find a new leader.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
-- @param #AIRBOSS.FlightGroup flight The flight to be removed.
|
||||||
|
function AIRBOSS:_UpdateFlightSection(flight)
|
||||||
|
|
||||||
|
-- Check if this player is the leader of a section.
|
||||||
|
if flight.seclead==flight.name then
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
-- Section Leader --
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
-- This player is the leader ==> We need a new one.
|
||||||
|
if #flight.section>=1 then
|
||||||
|
|
||||||
|
-- New leader.
|
||||||
|
local newlead=flight.section[1] --#AIRBOSS.FlightGroup
|
||||||
|
newlead.seclead=newlead.name
|
||||||
|
|
||||||
|
-- Adjust new section members.
|
||||||
|
for i=2,#flight.section do
|
||||||
|
local member=flight.section[i] --#AIRBOSS.FlightGroup
|
||||||
|
|
||||||
|
-- Add remaining members new leaders table.
|
||||||
|
table.insert(newlead.section, member)
|
||||||
|
|
||||||
|
-- Set new section lead of member.
|
||||||
|
member.seclead=newlead.name
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Flight section empty
|
||||||
|
flight.section={}
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
-- Section Member --
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
-- Remove this flight group from the section of the leader.
|
||||||
|
local lead=self.players[flight.seclead] --#AIRBOSS.FlightGroup
|
||||||
|
if lead then
|
||||||
|
for i,sec in pairs(lead.section) do
|
||||||
|
local sectionmember=sec --#AIRBOSS.FlightGroup
|
||||||
|
if sectionmember.name==flight.name then
|
||||||
|
table.remove(lead.section, i)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Remove a flight from Marshal, Pattern and Waiting queues. If flight is in Marhal queue, the above stack is collapsed.
|
--- Remove a flight from Marshal, Pattern and Waiting queues. If flight is in Marhal queue, the above stack is collapsed.
|
||||||
-- Also set player step to undefined if applicable or remove human flight if option *completely* is true.
|
-- Also set player step to undefined if applicable or remove human flight if option *completely* is true.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
@ -5811,12 +5969,33 @@ function AIRBOSS:_RemoveFlight(flight, completely)
|
|||||||
|
|
||||||
-- Check if player or AI
|
-- Check if player or AI
|
||||||
if flight.ai then
|
if flight.ai then
|
||||||
|
|
||||||
-- Remove AI flight completely.
|
-- Remove AI flight completely.
|
||||||
self:_RemoveFlightFromQueue(self.flights, flight)
|
self:_RemoveFlightFromQueue(self.flights, flight)
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
if completely then
|
if completely then
|
||||||
-- Remove HUMAN flight completely.
|
|
||||||
|
-- TODO: update section and checksectinrecovered at the beginning to ensure that not anybody else from the section is in the queue?!
|
||||||
|
|
||||||
|
-- Update flight section. Remove flight from section lead or find new section lead.
|
||||||
|
self:_UpdateFlightSection(flight)
|
||||||
|
|
||||||
|
-- Check if section has recovered, just in case.
|
||||||
|
self:_CheckSectionRecovered(flight)
|
||||||
|
|
||||||
|
-- Remove HUMAN flight completely, e.g. when player died or left.
|
||||||
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
|
||||||
|
|
||||||
else
|
else
|
||||||
-- Set Playerstep to undefined.
|
-- Set Playerstep to undefined.
|
||||||
flight.step=AIRBOSS.PatternStep.UNDEFINED
|
flight.step=AIRBOSS.PatternStep.UNDEFINED
|
||||||
@ -6317,13 +6496,10 @@ function AIRBOSS:OnEventLand(EventData)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- AI always lands ==> remove unit from flight group and queues.
|
-- AI always lands ==> remove unit from flight group and queues.
|
||||||
self:_RecoveredElement(EventData.IniUnit)
|
local flight=self:_RecoveredElement(EventData.IniUnit)
|
||||||
local flight=self:_GetFlightFromGroupInQueue(EventData.IniGroup, self.flights)
|
|
||||||
local allrecovered=self:_CheckAllRecovered(flight)
|
-- Check if all were recovered. If so update pattern queue.
|
||||||
if allrecovered then
|
self:_CheckSectionRecovered(flight)
|
||||||
self:_RemoveFlightFromQueue(self.Qpattern, flight)
|
|
||||||
end
|
|
||||||
--self:_RemoveUnitFromFlight(EventData.IniUnit)
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -6346,12 +6522,32 @@ function AIRBOSS:OnEventEngineShutdown(EventData)
|
|||||||
if _unit and _playername then
|
if _unit and _playername then
|
||||||
|
|
||||||
-- Debug message.
|
-- Debug message.
|
||||||
self:T(self.lid..string.format("Player %s shutted down its engines!",_playername))
|
self:T(self.lid..string.format("Player %s shut down its engines!",_playername))
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
-- Debug message.
|
-- Debug message.
|
||||||
self:T2(self.lid..string.format("AI unit %s shutted down its engines!", _unitName))
|
self:T2(self.lid..string.format("AI unit %s shut down its engines!", _unitName))
|
||||||
|
|
||||||
|
if self.despawnshutdown then
|
||||||
|
|
||||||
|
-- Get flight.
|
||||||
|
local flight=self:_GetFlightFromGroupInQueue(EventData.IniGroup, self.flights)
|
||||||
|
|
||||||
|
-- Only AI flights.
|
||||||
|
if flight and flight.ai then
|
||||||
|
|
||||||
|
-- Check if all elements were recovered.
|
||||||
|
local recovered=self:_CheckSectionRecovered(flight)
|
||||||
|
|
||||||
|
-- Despawn group and completely remove flight.
|
||||||
|
if recovered then
|
||||||
|
-- TODO: This creates an Event RemoveUnit. Should be captured.
|
||||||
|
EventData.IniGroup:Destroy()
|
||||||
|
self:_RemoveFlight(flight)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -6406,18 +6602,11 @@ function AIRBOSS:OnEventCrash(EventData)
|
|||||||
local flight=self.players[_playername]
|
local flight=self.players[_playername]
|
||||||
|
|
||||||
-- Remove flight completely from all queues and collapse marshal if necessary.
|
-- Remove flight completely from all queues and collapse marshal if necessary.
|
||||||
|
-- This also updates the section, if any and removes unfinished gradings.
|
||||||
if flight then
|
if flight then
|
||||||
self:_RemoveFlight(flight, true)
|
self:_RemoveFlight(flight, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Remove all grades until a final grade is reached.
|
|
||||||
local grades=self.playerscores[_playername]
|
|
||||||
if grades and #grades>0 then
|
|
||||||
while #grades>0 and grades[#grades].finalscore==nil do
|
|
||||||
table.remove(grades, #grades)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
else
|
else
|
||||||
-- Debug message.
|
-- Debug message.
|
||||||
self:T2(self.lid..string.format("AI unit %s crashed!", EventData.IniUnitName))
|
self:T2(self.lid..string.format("AI unit %s crashed!", EventData.IniUnitName))
|
||||||
@ -6443,6 +6632,7 @@ function AIRBOSS:OnEventEjection(EventData)
|
|||||||
|
|
||||||
if _unit and _playername then
|
if _unit and _playername then
|
||||||
self:T(self.lid..string.format("Player %s ejected!",_playername))
|
self:T(self.lid..string.format("Player %s ejected!",_playername))
|
||||||
|
|
||||||
-- Get player flight.
|
-- Get player flight.
|
||||||
local flight=self.players[_playername]
|
local flight=self.players[_playername]
|
||||||
|
|
||||||
@ -6451,20 +6641,17 @@ function AIRBOSS:OnEventEjection(EventData)
|
|||||||
self:_RemoveFlight(flight, true)
|
self:_RemoveFlight(flight, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Remove all grades until a final grade is reached.
|
|
||||||
local grades=self.playerscores[_playername]
|
|
||||||
if grades and #grades>0 then
|
|
||||||
while #grades>0 and grades[#grades].finalscore==nil do
|
|
||||||
table.remove(grades, #grades)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
else
|
else
|
||||||
-- Debug message.
|
-- Debug message.
|
||||||
self:T2(self.lid..string.format("AI unit %s ejected!", EventData.IniUnitName))
|
self:T2(self.lid..string.format("AI unit %s ejected!", EventData.IniUnitName))
|
||||||
|
|
||||||
-- Remove unit from flight and queues.
|
-- Remove element/unit from flight group and from all queues if no elements alive.
|
||||||
self:_RemoveUnitFromFlight(EventData.IniUnit)
|
self:_RemoveUnitFromFlight(EventData.IniUnit)
|
||||||
|
|
||||||
|
-- What could happen is, that another element has landed (recovered) already and this one crashes.
|
||||||
|
-- This would mean that the flight would not be deleted from the queue ==> Check if section recovered.
|
||||||
|
local flight=self:_GetFlightFromGroupInQueue(EventData.IniGroup, self.flights)
|
||||||
|
self:_CheckSectionRecovered(flight)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -6496,31 +6683,17 @@ function AIRBOSS:_PlayerLeft(EventData)
|
|||||||
self:_RemoveFlight(flight, true)
|
self:_RemoveFlight(flight, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Remove all grades until a final grade is reached.
|
|
||||||
local grades=self.playerscores[_playername]
|
|
||||||
if grades and #grades>0 then
|
|
||||||
while #grades>0 and grades[#grades].finalscore==nil do
|
|
||||||
table.remove(grades, #grades)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[
|
|
||||||
--- Airboss event function handling the mission end event.
|
--- Airboss event function handling the mission end event.
|
||||||
-- Handles the case when the mission is ended.
|
-- Handles the case when the mission is ended.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param Core.Event#EVENTDATA EventData Event data.
|
-- @param Core.Event#EVENTDATA EventData Event data.
|
||||||
function AIRBOSS:OnEventMissionEnd(EventData)
|
function AIRBOSS:OnEventMissionEnd(EventData)
|
||||||
|
self:T3(self.lid.."Mission Ended")
|
||||||
-- Auto save player results.
|
|
||||||
if self.autosave then
|
|
||||||
self:Save(self.autosavepath, self.autosavefile)
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
]]
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- PATTERN functions
|
-- PATTERN functions
|
||||||
@ -10384,11 +10557,8 @@ function AIRBOSS:_Debrief(playerData)
|
|||||||
-- Set recovered flag.
|
-- Set recovered flag.
|
||||||
self:_RecoveredElement(playerData.unit)
|
self:_RecoveredElement(playerData.unit)
|
||||||
|
|
||||||
local allrecovered=self:_CheckAllRecovered(playerData)
|
-- Check if all elements
|
||||||
|
self:_CheckSectionRecovered(playerData)
|
||||||
if allrecovered then
|
|
||||||
self:_RemoveFlightFromQueue(self.Qpattern, playerData)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Increase number of passes.
|
-- Increase number of passes.
|
||||||
@ -10620,14 +10790,19 @@ end
|
|||||||
-- @param Core.Point#COORDINATE coord Coordinate of the detour.
|
-- @param Core.Point#COORDINATE coord Coordinate of the detour.
|
||||||
-- @param #number speed Speed in knots. Default is current carrier velocity.
|
-- @param #number speed Speed in knots. Default is current carrier velocity.
|
||||||
-- @param #boolean uturn (Optional) If true, carrier will go back to where it came from before it resumes its route to the next waypoint.
|
-- @param #boolean uturn (Optional) If true, carrier will go back to where it came from before it resumes its route to the next waypoint.
|
||||||
|
-- @param #number uspeed Speed in knots after U-turn. Default is same as before.
|
||||||
-- @return #AIRBOSS self
|
-- @return #AIRBOSS self
|
||||||
function AIRBOSS:CarrierDetour(coord, speed, uturn)
|
function AIRBOSS:CarrierDetour(coord, speed, uturn, uspeed)
|
||||||
|
|
||||||
-- Current coordinate of the carrier.
|
-- Current coordinate of the carrier.
|
||||||
local pos0=self:GetCoordinate()
|
local pos0=self:GetCoordinate()
|
||||||
|
|
||||||
|
-- Default.
|
||||||
|
speed=speed or self.carrier:GetVelocityKNOTS()
|
||||||
|
|
||||||
-- Speed in km/h.
|
-- Speed in km/h.
|
||||||
local speedkmh=UTILS.KnotsToKmph(speed or self.carrier:GetVelocityKNOTS())
|
local speedkmh=UTILS.KnotsToKmph(speed)
|
||||||
|
local uspeedkmh=UTILS.KnotsToKmph(uspeed)
|
||||||
|
|
||||||
-- Waypoint table.
|
-- Waypoint table.
|
||||||
local wp={}
|
local wp={}
|
||||||
@ -10638,7 +10813,7 @@ function AIRBOSS:CarrierDetour(coord, speed, uturn)
|
|||||||
|
|
||||||
-- If enabled, go back to where you came from.
|
-- If enabled, go back to where you came from.
|
||||||
if uturn then
|
if uturn then
|
||||||
table.insert(wp, pos0:WaypointGround(speedkmh))
|
table.insert(wp, pos0:WaypointGround(uspeedkmh))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get carrier group.
|
-- Get carrier group.
|
||||||
@ -10688,7 +10863,7 @@ function AIRBOSS:CarrierTurnIntoWind(time, vdeck)
|
|||||||
local distNM=UTILS.MetersToNM(dist)
|
local distNM=UTILS.MetersToNM(dist)
|
||||||
|
|
||||||
-- Debug output
|
-- Debug output
|
||||||
self:E(self.lid..string.format("Carrier steaming into the wind (%.1f kts). Distance=%.1f NM, Speed=%.1f knots, Time=%d sec.", UTILS.MpsToKnots(vwind), distNM, speedknots, time))
|
self:I(self.lid..string.format("Carrier steaming into the wind (%.1f kts). Distance=%.1f NM, Speed=%.1f knots, Time=%d sec.", UTILS.MpsToKnots(vwind), distNM, speedknots, time))
|
||||||
|
|
||||||
-- Get heading into the wind accounting for angled runway.
|
-- Get heading into the wind accounting for angled runway.
|
||||||
local intowind=self:GetHeadingIntoWind(false)
|
local intowind=self:GetHeadingIntoWind(false)
|
||||||
@ -10704,9 +10879,17 @@ function AIRBOSS:CarrierTurnIntoWind(time, vdeck)
|
|||||||
-- Return to coordinate if collision is detected.
|
-- Return to coordinate if collision is detected.
|
||||||
self.Creturnto=self:GetCoordinate()
|
self.Creturnto=self:GetCoordinate()
|
||||||
|
|
||||||
|
-- Next wp = current+1 (or last)
|
||||||
|
local Nnextwp=math.min(self.currentwp+1, #self.waypoints)
|
||||||
|
|
||||||
|
-- Next waypoint.
|
||||||
|
local nextwp=self.waypoints[Nnextwp] --Core.Point#COORDINATE
|
||||||
|
|
||||||
|
-- For downwind, we take the velocity at the next WP.
|
||||||
|
local vdownwind=UTILS.MpsToKnots(nextwp:GetVelocity())
|
||||||
|
|
||||||
-- Let the carrier make a detour from its route but return to its current position.
|
-- Let the carrier make a detour from its route but return to its current position.
|
||||||
-- TODO: Add downwind speed
|
self:CarrierDetour(pos1, speedknots, true, vdownwind)
|
||||||
self:CarrierDetour(pos1, speedknots, true)
|
|
||||||
|
|
||||||
-- Set switch that we are currently turning into the wind.
|
-- Set switch that we are currently turning into the wind.
|
||||||
self.turnintowind=true
|
self.turnintowind=true
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user