AIRBOSS v0.2.6

This commit is contained in:
Frank 2018-11-14 23:23:46 +01:00
parent 3bc2baaf9d
commit 34d7b18c26

View File

@ -14,8 +14,9 @@
-- * Automatic TACAN and ICLS channel setting.
-- * Different radio channels for LSO and airboss calls.
-- * F10 radio menu including carrier info (weather, radio frequencies, TACAN/ICLS channels, pilot grades).
-- * Multiple carriers supported.
--
-- Please not that his class is work in progress and in an **alpha** stage.
-- **PLEASE NOTE** that his class is work in progress and in an **alpha** stage.
-- At the moment training parameters are optimized for F/A-18C Hornet as aircraft and USS Stennis as carrier.
-- Other aircraft and carriers **might** be possible in future but would need a different set of parameters.
--
@ -44,7 +45,7 @@
-- @field Core.Radio#RADIO Carrierradio Radio for carrier calls.
-- @field #AIRBOSS.RadioCalls radiocall LSO and Airboss call sound files and texts.
-- @field Core.Zone#ZONE_UNIT startZone Zone in which the pattern approach starts.
-- @field Core.Zone#ZONE_UNIT carrierZone Large zone around the carrier to welcome players.
-- @field Core.Zone#ZONE_UNIT carrierZone Carrier controlled area (CCA), i.e. a zone of 50 NM radius around the carrier.
-- @field Core.Zone#ZONE_UNIT registerZone Zone behind the carrier to register for a new approach.
-- @field Core.Zone#ZONE_UNIT zoneHolding Zone where aircraft are holding before entering the landing pattern.
-- @field #table players Table of players.
@ -60,10 +61,7 @@
-- @field #AIRBOSS.Checkpoint C3Descent4k Case III descent at 4000 ft/min right after leaving holding pattern.
-- @field #AIRBOSS.Checkpoint C3Descent2k Case III descent at 2000 ft/min at 5000 ft plattform.
-- @field #AIRBOSS.Checkpoint C3DirtyUp Case III dirty up and on speed position at 1200 ft and 10-12 NM from the carrier.
-- @field #AIRBOSS.Checkpoint C3BullsEye Case III intercept glideslope and follow ICLS "bullseye".
-- @field #number rwyangle Angle of the runway wrt to carrier "nose". For the Stennis ~ -10 degrees.
-- @field #number sterndist Distance in meters from carrier coordinate to the end of the deck.
-- @field #number deckheight Height of the deck in meters.
-- @field #AIRBOSS.Checkpoint C3BullsEye Case III intercept glideslope and follow ICLS "bullseye".
-- @field #number case Recovery case I, II or III.
-- @field #table Qmarshal Queue of marshalling aircraft groups.
-- @field #table Qpattern Queue of aircraft groups in the landing pattern.
@ -89,7 +87,7 @@ AIRBOSS = {
Debug = true,
carrier = nil,
carriertype = nil,
carrierparam = nil,
carrierparam = {},
alias = nil,
airbase = nil,
beacon = nil,
@ -119,7 +117,6 @@ AIRBOSS = {
C3Descent2k = {},
C3DirtyUp = {},
C3BullsEye = {},
radiocall = nil,
case = 1,
Qpattern = {},
Qmarshal = {},
@ -164,7 +161,7 @@ AIRBOSS.CarrierType={
-- @type AIRBOSS.PatternStep
AIRBOSS.PatternStep={
UNDEFINED="Undefined",
UNREGISTERED="Unregistered",
COMMENCING="Commencing",
HOLDING="Holding",
DESCENT4K="Descent 4000 ft/min",
DESCENT2K="Descent 2000 ft/min",
@ -212,11 +209,13 @@ AIRBOSS.PatternStep={
-- @type AIRBOSS.Soundfile
-- @field #AIRBOSS.RadioSound RIGHTFORLINEUP
-- @field #AIRBOSS.RadioSound COMELEFT
-- @field #AIRBOSS.RadioSound
-- @field #AIRBOSS.RadioSound
-- @field #AIRBOSS.RadioSound
-- @field #AIRBOSS.RadioSound
-- @field #AIRBOSS.RadioSound
-- @field #AIRBOSS.RadioSound HIGH
-- @field #AIRBOSS.RadioSound POWER
-- @field #AIRBOSS.RadioSound CALLTHEBALL
-- @field #AIRBOSS.RadioSound ROGERBALL
-- @field #AIRBOSS.RadioSound WAVEOFF
-- @field #AIRBOSS.RadioSound BOLTER
-- @field #AIRBOSS.RadioSound LONGINGROOVE
AIRBOSS.Soundfile={
RIGHTFORLINEUP={
normal="LSO - RightLineUp(L).ogg",
@ -328,6 +327,7 @@ AIRBOSS.GroovePos={
-- @field Wrapper.Group#GROUP group Aircraft group the player is in.
-- @field #string callsign Callsign of player.
-- @field #string difficulty Difficulty level.
-- @field #string step Coming pattern step.
-- @field #number passes Number of passes.
-- @field #boolean attitudemonitor If true, display aircraft attitude and other parameters constantly.
-- @field #table debrief Debrief analysis of the current step of this pass.
@ -380,13 +380,14 @@ AIRBOSS.MenuF10={}
--- Airboss class version.
-- @field #string version
AIRBOSS.version="0.2.5w"
AIRBOSS.version="0.2.6"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Handle crash event. Delete ac from queue, send rescue helo, stop carrier?
-- TODO: Handle crash event. Delete A/C from queue, send rescue helo, stop carrier?
-- TODO: Add aircraft numbers in queue to carrier info F10 radio output.
-- TODO: Transmission via radio.
-- TODO: Get board numbers.
-- TODO: Get fuel state in pounds.
@ -444,9 +445,11 @@ function AIRBOSS:New(carriername, alias)
-- Set up Airboss radio.
self.Carrierradio=RADIO:New(self.carrier)
self:SetCarrierradio()
-- Set up LSO radio.
self.LSOradio=RADIO:New(self.carrier)
self:SetLSOradio()
-- Init carrier parameters.
if self.carriertype==AIRBOSS.CarrierType.STENNIS then
@ -465,11 +468,11 @@ function AIRBOSS:New(carriername, alias)
return nil
end
-- Zone 5 km astern and 100 m starboard of the carrier with radius of 2.5 km.
self.registerZone = ZONE_UNIT:New("registerZone", self.carrier, 2.5*1000, {dx = -5000, dy = 100, relative_to_unit=true})
-- Zone 3 NM astern and 100 m starboard of the carrier with radius of 2.0 km.
self.zoneInitial=ZONE_UNIT:New("registerZone", self.carrier, 2.0*1000, {dx=-UTILS.NMToMeters(3), dy=100, relative_to_unit=true})
-- Zone 2 km astern and 100 m starboard of the carrier with a radius of 1 km.
self.startZone = ZONE_UNIT:New("startZone", self.carrier, 1.0*1000, {dx = -2000, dy = 100, relative_to_unit=true})
self.startZone = ZONE_UNIT:New("startZone", self.carrier, 1.0*1000, {dx=-2000, dy=100, relative_to_unit=true})
-- Zone around the carrier with a radius of 30 km.
self:SetCarrierControlledZone()
@ -477,6 +480,13 @@ function AIRBOSS:New(carriername, alias)
-- Default recovery case.
self:SetRecoveryCase(1)
env.info("FF sound files:")
for _name,_sound in pairs(AIRBOSS.Soundfile) do
local sound=_sound --#AIRBOSS.RadioSound
self:I{name=_name,sound=_sound}
self.radiocall[_name]=sound
end
-----------------------
--- FSM Transitions ---
-----------------------
@ -601,22 +611,26 @@ end
--- Set LSO radio frequency.
-- @param #AIRBOSS self
-- @param #number freq Frequency in MHz. Default 264 MHz.
-- @param #number frequency Frequency in MHz. Default 264 MHz.
-- @param #string modulation Modulation, i.e. "AM" (default) or "FM".
-- @return #AIRBOSS self
function AIRBOSS:SetLSOradio(freq)
function AIRBOSS:SetLSOradio(frequency, modulation)
self.LSOfreq=freq or 264
self.LSOfreq=frequency or 264
self.LSOmodulation=modulation or "AM"
return self
end
--- Set carrier radio frequency.
-- @param #AIRBOSS self
-- @param #number freq Frequency in MHz. Default 305.
-- @param #number frequency Frequency in MHz. Default 305 MHz.
-- @param #string modulation Modulation, i.e. "AM" (default) or "FM".
-- @return #AIRBOSS self
function AIRBOSS:SetCarrierradio(freq)
function AIRBOSS:SetCarrierradio(frequency, modulation)
self.Carrierfreq=freq or 305
self.Carrierfreq=frequency or 305
self.Carrriermodulation=modulation or "AM"
return self
end
@ -687,12 +701,12 @@ function AIRBOSS:onafterStatus(From, Event, To)
if startrecovery==true then
self:Recover()
end
local text=string.format("AIRBOSS %s: Status %s.", self.alias, self:GetState())
self:I(text)
-- Update marshal and pattern queue every 30 seconds.
if time-self.Tqueue>30 then
local text=string.format("AIRBOSS %s: Status %s.", self.alias, self:GetState())
self:I(text)
-- Scan carrier zone for new aircraft.
self:_ScanCarrierZone()
@ -708,7 +722,7 @@ function AIRBOSS:onafterStatus(From, Event, To)
self:_CheckPlayerStatus()
-- Call status again in one second.
self:__Status(-1)
self:__Status(-0.5)
end
--- Check if recovery times.
@ -850,7 +864,7 @@ function AIRBOSS:_PrintQueue(queue, name)
end
--- Check if new aircraft arrived
--- Scan carrier zone for (new) units.
-- @param #AIRBOSS self
function AIRBOSS:_ScanCarrierZone()
--env.info("FF Scanning Carrier Zone")
@ -874,6 +888,7 @@ function AIRBOSS:_ScanCarrierZone()
-- Check if this an aircraft and that it is airborn and closing in.
if unit:IsAir() and unit:InAir() and unit:IsInZone(zsma)then
-- TODO: check for correct aircraft types and also helos!
-- TODO: check for right coalition.
local group=unit:GetGroup()
local unitname=unit:GetName()
@ -1011,7 +1026,7 @@ function AIRBOSS:_MarshalAI(group)
end
-- Pattern altitude.
local Altitude=UTILS.FeetToMeters((nstacks+angels0)*1000)
local Altitude=UTILS.FeetToMeters((nstacks+angels0)*1000)
-- Add group to marshal stack.
self:_AddMarshallGroup(group, nstacks+1, Altitude)
@ -1077,7 +1092,7 @@ function AIRBOSS:_CollapseMarshalStack()
-- Set player step to 0.
if flight.ai==false then
local playerData=self:_GetPlayerDataGroup(flight.group)
playerData.step=AIRBOSS.PatternStep.UNREGISTERED
playerData.step=AIRBOSS.PatternStep.COMMENCING
end
-- Time stamp.
@ -1168,6 +1183,7 @@ function AIRBOSS:_CheckPlayerStatus()
-- Player unit.
local unit=playerData.unit
-- Check if unit is alive and in air.
if unit:IsAlive() then
-- Display aircraft attitude and other parameters as message text.
@ -1175,7 +1191,7 @@ function AIRBOSS:_CheckPlayerStatus()
self:_DetailedPlayerStatus(playerData)
end
-- Check if player is in carrier controlled zone.
-- Check if player is in carrier controlled area (zone with R=50 NM around the carrier).
if unit:IsInZone(self.carrierZone) then
-- Check if player was previously not inside the zone.
@ -1194,26 +1210,48 @@ function AIRBOSS:_CheckPlayerStatus()
end
if playerData.step==0 and unit:InAir() then
if playerData.step==AIRBOSS.PatternStep.UNDEFINED then
-- New approach.
self:_NewRound(playerData)
self:I("Player status undefined. Waiting for next step.")
-- Jump to Groove for testing.
-- Jump directly to CASE I straight in approach.
playerData.step=AIRBOSS.PatternStep.COMMENCING
-- Jump to final/groove for testing.
if self.groovedebug then
playerData.step=90
playerData.step=AIRBOSS.PatternStep.FINAL
self.groovedebug=false
end
elseif playerData.step==AIRBOSS.PatternStep.COMMENCING and unit:InAir() then
-- New approach.
self:_Commencing(playerData)
elseif playerData.step==AIRBOSS.PatternStep.HOLDING then
-- TODO: holding check.
elseif playerData.step==AIRBOSS.PatternStep.DESCENT4K then
-- CASE III: Initial descent with 4000 ft/min.
self:_Descent4k(playerData)
elseif playerData.step==AIRBOSS.PatternStep.DESCENT2K then
-- CASE III: Player has reached 5k "Platform".
self:_Descent2k(playerData)
elseif playerData.step==AIRBOSS.PatternStep.DIRTYUP then
-- CASE III: Player has descended to 1200 ft and is going level from now on.
self:_DirtyUp(playerData)
elseif playerData.step==AIRBOSS.PatternStep.BULLSEYE then
-- CASE III: Player has intercepted the glide slope and should follow "Bullseye" (ICLS).
self:_BullsEye(playerData)
elseif playerData.step==AIRBOSS.PatternStep.INITIAL then
-- Player is at the initial position entering the landing pattern.
@ -1254,7 +1292,7 @@ function AIRBOSS:_CheckPlayerStatus()
elseif playerData.step==AIRBOSS.PatternStep.FINAL then
-- Entering the groove.
-- Turn to final and enter the groove.
self:_Final(playerData)
elseif playerData.step==AIRBOSS.PatternStep.GROOVE_XX or
@ -1338,7 +1376,7 @@ function AIRBOSS:OnEventBirth(EventData)
self.players[_playername]=self:_InitPlayer(_unitName)
-- Start in the groove for debugging.
self.groovedebug=false
self.groovedebug=true
end
end
@ -1362,43 +1400,50 @@ function AIRBOSS:OnEventLand(EventData)
local _group=_unit:GetGroup()
local _callsign=_unit:GetCallsign()
-- Debug output.
local text=string.format("Player %s, callsign %s unit %s (ID=%d) of group %s landed.", _playername, _callsign, _unitName, _uid, _group:GetName())
self:T(self.lid..text)
MESSAGE:New(text, 5):ToAllIf(self.Debug)
-- This would be the closest airbase.
local airbase=EventData.Place
local airbasename=tostring(airbase:GetName())
-- Player data.
local playerData=self.players[_playername] --#AIRBOSS.PlayerData
-- Check if player landed on the right airbase.
if airbasename==self.airbase:GetName() then
-- Coordinate at landing event
local coord=playerData.unit:GetCoordinate()
-- Debug mark of player landing coord.
local lp=coord:MarkToAll("Landing coord.")
coord:SmokeGreen()
-- Debug marks of wires.
local w1=self.carrier:GetCoordinate():Translate(-104, 0):MarkToAll("Wire 1")
local w2=self.carrier:GetCoordinate():Translate( -92, 0):MarkToAll("Wire 2")
local w3=self.carrier:GetCoordinate():Translate( -80, 0):MarkToAll("Wire 3")
local w4=self.carrier:GetCoordinate():Translate( -68, 0):MarkToAll("Wire 4")
-- We did land.
env.info("FF landed")
playerData.landed=true
-- Unkonwn step.
playerData.step=AIRBOSS.PatternStep.UNDEFINED
--TODO: maybe check that we actually landed on the right carrier.
-- Call trapped function in 3 seconds to make sure we did not bolter.
SCHEDULER:New(nil, self._Trapped,{self, playerData, coord}, 3)
-- Debug output.
local text=string.format("Player %s, callsign %s unit %s (ID=%d) of group %s landed at airbase %s", _playername, _callsign, _unitName, _uid, _group:GetName(), airbasename)
self:T(self.lid..text)
MESSAGE:New(text, 5):ToAllIf(self.Debug)
end
if self:_InQueue(self.Qpattern, EventData.IniGroup) then
self:_RemoveQueue(self.Qpattern, EventData.IniGroup)
-- Player data.
local playerData=self.players[_playername] --#AIRBOSS.PlayerData
-- Coordinate at landing event
local coord=playerData.unit:GetCoordinate()
-- Debug mark of player landing coord.
local lp=coord:MarkToAll("Landing coord.")
coord:SmokeGreen()
-- Debug marks of wires.
local w1=self.carrier:GetCoordinate():Translate(self.carrierparam.wire1, 0):MarkToAll("Wire 1")
local w2=self.carrier:GetCoordinate():Translate(self.carrierparam.wire2, 0):MarkToAll("Wire 2")
local w3=self.carrier:GetCoordinate():Translate(self.carrierparam.wire3, 0):MarkToAll("Wire 3")
local w4=self.carrier:GetCoordinate():Translate(self.carrierparam.wire4, 0):MarkToAll("Wire 4")
-- We did land.
env.info("FF landed")
playerData.landed=true
-- Unkonwn step.
playerData.step=AIRBOSS.PatternStep.UNDEFINED
-- Call trapped function in 3 seconds to make sure we did not bolter.
SCHEDULER:New(nil, self._Trapped,{self, playerData, coord}, 3)
end
if self:_InQueue(self.Qpattern, EventData.IniGroup) then
self:_RemoveQueue(self.Qpattern, EventData.IniGroup)
end
end
end
@ -1482,7 +1527,7 @@ function AIRBOSS:_InitPlayer(unitname)
playerData.inbigzone=playerData.unit:IsInZone(self.carrierZone)
-- Init stuff for this round.
playerData=self:_InitNewRound(playerData)
playerData=self:_InitNewApproach(playerData)
-- Return player data table.
return playerData
@ -1495,9 +1540,11 @@ end
-- @param #AIRBOSS self
-- @param #AIRBOSS.PlayerData playerData Player data.
-- @return #AIRBOSS.PlayerData Initialized player data.
function AIRBOSS:_InitNewRound(playerData)
self:I(self.lid..string.format("New round for player %s.", playerData.callsign))
playerData.step=0
function AIRBOSS:_InitNewApproach(playerData)
self:I(self.lid..string.format("New approach of player %s.", playerData.callsign))
playerData.step=AIRBOSS.PatternStep.UNDEFINED
playerData.groove={}
playerData.debrief={}
playerData.patternwo=false
@ -1507,23 +1554,30 @@ function AIRBOSS:_InitNewRound(playerData)
playerData.boltered=false
playerData.landed=false
playerData.Tlso=timer.getTime()
return playerData
end
--- Initialize player data.
--- Commence approach.
-- @param #AIRBOSS self
-- @param #AIRBOSS.PlayerData playerData Player data.
function AIRBOSS:_NewRound(playerData)
if playerData.unit:IsInZone(self.registerZone) then
local text="Cleared for approach."
self:_SendMessageToPlayer(text, 10, playerData)
function AIRBOSS:_Commencing(playerData)
local text="Commencing."
self:_SendMessageToPlayer(text, 10, playerData)
self:_InitNewRound(playerData)
-- Next step: start of pattern.
playerData.step=1
-- Initialize player data for new approach.
self:_InitNewApproach(playerData)
-- Next step: depends on case recovery.
if self.case==1 then
-- CASE I: Player has to fly to the initial which is 3 NM DME astern of the boat.
playerData.step=AIRBOSS.PatternStep.INITIAL
else
-- CASE III: Player has to start the descent at 4000 ft/min.
playerData.step=AIRBOSS.PatternStep.DESCENT4K
end
end
--- Start pattern when player enters the initial zone.
@ -1531,8 +1585,8 @@ end
-- @param #AIRBOSS.PlayerData playerData Player data table.
function AIRBOSS:_Initial(playerData)
-- Check if player is in start zone and about to enter the pattern.
if playerData.unit:IsInZone(self.startZone) then
-- Check if player is in initial zone and entering the CASE I pattern.
if playerData.unit:IsInZone(self.zoneInitial) then
-- Inform player.
local hint = string.format("Entering the pattern.")
@ -1541,7 +1595,7 @@ function AIRBOSS:_Initial(playerData)
end
-- Send message.
self:_SendMessageToPlayer(hint, 8, playerData)
self:_SendMessageToPlayer(hint, 10, playerData)
-- Next step: upwind.
playerData.step=AIRBOSS.PatternStep.UPWIND
@ -1790,12 +1844,9 @@ function AIRBOSS:_CheckForLongDownwind(playerData)
-- Check we are not too far out w.r.t back of the boat.
if X<limit then --and relhead<45 then
-- Message to player.
self:_SendMessageToPlayer(AIRBOSS.LSOcall.LONGGROOVET, 10, playerData)
-- Sound output.
AIRBOSS.LSOcall.LONGGROOVE:ToGroup(playerData.unit:GetGroup())
self:RadioTransmission(self.LSOradio, self.radiocall.LONGINGROOVE)
-- Debrief.
self:_AddToSummary(playerData, "Downwind", "Long in the groove.")
@ -2039,10 +2090,10 @@ function AIRBOSS:_Groove(playerData)
-- Ranges in the groove.
local RXX=UTILS.NMToMeters(0.750)+math.abs(self.carrierparam.sterndist) -- Start of groove. 0.75 = 1389 m
local RRB=UTILS.NMToMeters(0.500)+math.abs(self.sterndist) -- Roger Ball! call. 0.5 = 926 m
local RIM=UTILS.NMToMeters(0.375)+math.abs(self.sterndist) -- In the Middle 0.75/2. 0.375 = 695 m
local RIC=UTILS.NMToMeters(0.100)+math.abs(self.sterndist) -- In Close. 0.1 = 185 m
local RAR=UTILS.NMToMeters(0.000)+math.abs(self.sterndist) -- At the Ramp.
local RRB=UTILS.NMToMeters(0.500)+math.abs(self.carrierparam.sterndist) -- Roger Ball! call. 0.5 = 926 m
local RIM=UTILS.NMToMeters(0.375)+math.abs(self.carrierparam.sterndist) -- In the Middle 0.75/2. 0.375 = 695 m
local RIC=UTILS.NMToMeters(0.100)+math.abs(self.carrierparam.sterndist) -- In Close. 0.1 = 185 m
local RAR=UTILS.NMToMeters(0.000)+math.abs(self.carrierparam.sterndist) -- At the Ramp.
-- Data
local groovedata={} --#AIRBOSS.GrooveData
@ -2056,8 +2107,11 @@ function AIRBOSS:_Groove(playerData)
if rho<=RXX and playerData.step==AIRBOSS.PatternStep.GROOVE_XX then
-- LSO "Call the ball" call.
self:_SendMessageToPlayer("Call the ball.", 8, playerData)
AIRBOSS.LSOcall.CALLTHEBALL:ToGroup(playerData.unit:GetGroup())
-- TODO: take this out.
self:_SendMessageToPlayer("Call the ball.", 5, playerData)
-- LSO radio call.
self:RadioTransmission(self.LSOradio, self.radiocall.LONGINGROOVE)
playerData.Tlso=timer.getTime()
-- Store data.
@ -2069,8 +2123,11 @@ function AIRBOSS:_Groove(playerData)
elseif rho<=RRB and playerData.step==AIRBOSS.PatternStep.GROOVE_RB then
-- Pilot: "Roger ball" call.
self:_SendMessageToPlayer(AIRBOSS.LSOcall.ROGERBALLT, 8, playerData)
AIRBOSS.LSOcall.ROGERBALL:ToGroup(player)
-- TODO: take this out.
self:_SendMessageToPlayer("Roger ball!", 5, playerData)
-- LSO radio call.
self:RadioTransmission(self.LSOradio, self.radiocall.ROGERBALL)
playerData.Tlso=timer.getTime()+1
-- Store data.
@ -2110,8 +2167,10 @@ function AIRBOSS:_Groove(playerData)
if waveoff then
-- Wave off player.
self:_SendMessageToPlayer(AIRBOSS.LSOcall.WAVEOFFT, 10, playerData)
AIRBOSS.LSOcall.WAVEOFF:ToGroup(playerData.unit:GetGroup())
self:_SendMessageToPlayer("Wave off!", 10, playerData)
-- LSO radio call.
self:RadioTransmission(self.LSOradio, self.radiocall.WAVEOFF)
playerData.Tlso=timer.getTime()
-- Player was waved off!
@ -2250,13 +2309,13 @@ function AIRBOSS:_Trapped(playerData, pos)
-- Which wire was caught?
local wire
if X<-104+wdx then
if X<self.carrierparam.wire1+wdx then
wire=1
elseif X<-92+wdx then
elseif X<self.carrierparam.wire2+wdx then
wire=2
elseif X<-80+wdx then
elseif X<self.carrierparam.wire3+wdx then
wire=3
elseif X<68+wdx then
elseif X<self.carrierparam.wire4+wdx then
wire=4
else
wire=0
@ -2278,7 +2337,7 @@ function AIRBOSS:_Trapped(playerData, pos)
end
-- Next step: debriefing.
playerData.step=999
playerData.step=AIRBOSS.PatternStep.DEBRIEF
end
--- LSO advice call.
@ -2291,9 +2350,7 @@ function AIRBOSS:_LSOadvice(playerData, glideslopeError, lineupError)
-- Player group.
local player=playerData.unit:GetGroup()
-- List of calls
local calls={}
-- Init delay.
local delay=0
-- Glideslope high/low calls.
@ -2396,13 +2453,13 @@ function AIRBOSS:RadioTransmission(radio, call, loud, delay)
if delay==nil or delay and delay==0 then
local filename=call.soundfilenormal
local filename=call.normal
if loud then
filename=call.soundfileloud
filename=call.loud
end
-- New transmission.
radio:NewUnitTransmission(filename, call.subtitle, call.subtitleduration, radio.Frequency, radio.Modulation, false)
radio:NewUnitTransmission(filename, call.subtitle, call.duration, radio.Frequency, radio.Modulation, false)
-- Broadcast message.
radio:Broadcast()
@ -2424,8 +2481,8 @@ function AIRBOSS:_Glideslope(playerData)
local X, Z, rho, phi = self:_GetDistances(playerData.unit)
-- Glideslope. Wee need to correct for the height of the deck. The ideal glide slope is 3.5 degrees.
local h=playerData.unit:GetAltitude()-self.deckheight
local x=math.abs(-86-X) --math.abs(self.sterndist-X) --TODO: maybe sterndist should be replaced by position of 3-wire!
local h=playerData.unit:GetAltitude()-self.carrierparam.deckheight
local x=math.abs(self.carrierparam.wire3-X)
local glideslope=math.atan(h/x)
return math.deg(glideslope)
@ -2442,7 +2499,7 @@ function AIRBOSS:_Lineup(playerData)
local X, Z, rho, phi = self:_GetDistances(playerData.unit)
-- Position at the end of the deck. From there we calculate the angle.
local b={x=self.sterndist, z=0}
local b={x=self.carrierparam.sterndist, z=0}
-- Position of the aircraft wrt carrier coordinates.
local a={x=X, z=Z}
@ -2561,7 +2618,7 @@ function AIRBOSS:_Debrief(playerData)
mygrade.points=points
mygrade.details=analysis
-- Add to table.
-- Add grade to table.
table.insert(playerData.grades, mygrade)
-- LSO grade message.
@ -2570,15 +2627,24 @@ function AIRBOSS:_Debrief(playerData)
-- New approach.
if playerData.boltered or playerData.waveoff or playerData.patternwo then
-- Get heading and distance to register zone ~3 NM astern.
local heading=playerData.unit:GetCoordinate():HeadingTo(self.registerZone:GetCoordinate())
local distance=playerData.unit:GetCoordinate():Get2DDistance(self.registerZone:GetCoordinate())
local text=string.format("fly heading %d for %d NM to re-enter the pattern.", heading, UTILS.MetersToNM(distance))
self:_SendMessageToPlayer(text, 10, playerData, false, nil, 30)
-- Next step?
-- TODO: CASE I: After bolter/wo turn left and climb to 600 ft and re-enter the pattern. But do not go to initial but reenter earlier?
-- TODO: CASE I: After pattern wo? go back to initial, I guess?
-- TODO: CASE III: After bolter/wo turn left and climb to 1200 ft and re-enter pattern?
-- TODO: CASE III: After pattern wo? No idea...
playerData.step=AIRBOSS.PatternStep.COMMENCING
end
-- Next step.
playerData.step=0
playerData.step=AIRBOSS.PatternStep.UNDEFINED
end
--- Get relative heading of player wrt carrier.
@ -2727,7 +2793,7 @@ function AIRBOSS:_AbortPattern(playerData, X, Z, posData)
playerData.patternwo=true
-- Next step debrief.
playerData.step=999
playerData.step=AIRBOSS.PatternStep.DEBRIEF
end
@ -2785,11 +2851,11 @@ function AIRBOSS:_InitStennis()
self.carrierparam.rwyangle = -9
self.carrierparam.sterndist =-150
self.carrierparam.deckheight = 22
self.carrierparam.wire1 =-100
self.carrierparam.wire2 = -90
self.carrierparam.wire1 =-104
self.carrierparam.wire2 = -92
self.carrierparam.wire3 = -80
self.carrierparam.wire4 = -70
self.carrierparam.wire4 = -68
--[[
q0=self.carrier:GetCoordinate():SetAltitude(25)
q0:BigSmokeSmall(0.1)
@ -2857,10 +2923,10 @@ function AIRBOSS:_InitStennis()
-- Upwind leg
self.Upwind.name="Upwind"
self.Upwind.Xmin=-4000 -- TODO Should be withing 4 km behind carrier. Why?
self.Upwind.Xmin=-UTILS.NMToMeters(4)
self.Upwind.Xmax=nil
self.Upwind.Zmin=0
self.Upwind.Zmax=1200
self.Upwind.Zmax=1000
self.Upwind.LimitXmin=0
self.Upwind.LimitXmax=nil
self.Upwind.LimitZmin=0
@ -3224,6 +3290,10 @@ end
-- @return #string Debriefing text.
function AIRBOSS:_AltitudeCheck(playerData, checkpoint, altitude)
if checkpoint.Altitude==nil then
return nil, nil
end
-- Player altitude.
local altitude=playerData.unit:GetAltitude()
@ -3270,6 +3340,10 @@ end
-- @return #string Debriefing text.
function AIRBOSS:_DistanceCheck(playerData, checkpoint, distance)
if checkpoint.Distance==nil then
return nil, nil
end
-- Get relative score.
local lowscore, badscore = self:_GetGoodBadScore(playerData)
@ -3313,6 +3387,10 @@ end
-- @return #string Debriefing text.
function AIRBOSS:_AoACheck(playerData, checkpoint, aoa)
if checkpoint.AoA==nil then
return nil, nil
end
-- Get relative score.
local lowscore, badscore = self:_GetGoodBadScore(playerData)
@ -3357,6 +3435,7 @@ end
-- @param #string sender The person who sends the message. Default is carrier alias.
-- @param #number delay Delay in seconds, before the message is send.
function AIRBOSS:_SendMessageToPlayer(message, duration, playerData, clear, sender, delay)
if message then
delay=delay or 0
@ -3375,6 +3454,7 @@ function AIRBOSS:_SendMessageToPlayer(message, duration, playerData, clear, send
end
end
end
--- Returns the unit of a player and the player name. If the unit does not belong to a player, nil is returned.