AIRBOSS v0.3.9

This commit is contained in:
Frank 2018-11-28 23:55:14 +01:00
parent 5e8b461478
commit 50c40cb4e9

View File

@ -7,7 +7,7 @@
-- * CASE I, II and III recoveries. -- * CASE I, II and III recoveries.
-- * Supports human pilots as well as AI flight groups. -- * Supports human pilots as well as AI flight groups.
-- * Automatic LSO grading. -- * Automatic LSO grading.
-- * Different skill levels from tipps on-the-fly for students to complete ziplip for pros. -- * Different skill levels from on-the-fly tipps for students to ziplip for pros.
-- * Recovery tanker option. -- * Recovery tanker option.
-- * Voice overs for LSO and AIRBOSS calls. Can easily be customized by users. -- * Voice overs for LSO and AIRBOSS calls. Can easily be customized by users.
-- * Automatic TACAN and ICLS channel setting. -- * Automatic TACAN and ICLS channel setting.
@ -58,7 +58,6 @@
-- @field #AIRBOSS.Checkpoint Wake Right behind the carrier. -- @field #AIRBOSS.Checkpoint Wake Right behind the carrier.
-- @field #AIRBOSS.Checkpoint Groove In the groove checkpoint. -- @field #AIRBOSS.Checkpoint Groove In the groove checkpoint.
-- @field #AIRBOSS.Checkpoint Trap Landing checkpoint. -- @field #AIRBOSS.Checkpoint Trap Landing checkpoint.
-- @field #AIRBOSS.Checkpoint Descent4k Case II/III descent at 4000 ft/min right after leaving holding pattern.
-- @field #AIRBOSS.Checkpoint Platform Case II/III descent at 2000 ft/min at 5000 ft platform. -- @field #AIRBOSS.Checkpoint Platform Case II/III descent at 2000 ft/min at 5000 ft platform.
-- @field #AIRBOSS.Checkpoint DirtyUp Case II/III dirty up and on speed position at 1200 ft and 10-12 NM from the carrier. -- @field #AIRBOSS.Checkpoint DirtyUp Case II/III dirty up and on speed position at 1200 ft and 10-12 NM from the carrier.
-- @field #AIRBOSS.Checkpoint Bullseye Case III intercept glideslope and follow ICLS aka "bullseye". -- @field #AIRBOSS.Checkpoint Bullseye Case III intercept glideslope and follow ICLS aka "bullseye".
@ -140,7 +139,6 @@ AIRBOSS = {
Wake = {}, Wake = {},
Groove = {}, Groove = {},
Trap = {}, Trap = {},
Descent4k = {},
Platform = {}, Platform = {},
DirtyUp = {}, DirtyUp = {},
Bullseye = {}, Bullseye = {},
@ -220,10 +218,13 @@ AIRBOSS.CarrierType={
-- @type AIRBOSS.PatternStep -- @type AIRBOSS.PatternStep
AIRBOSS.PatternStep={ AIRBOSS.PatternStep={
UNDEFINED="Undefined", UNDEFINED="Undefined",
REFUELING="Refueling",
SPINNING="Spinning",
COMMENCING="Commencing", COMMENCING="Commencing",
HOLDING="Holding", HOLDING="Holding",
DESCENT4K="Descent 4000 ft/min",
PLATFORM="Platform", PLATFORM="Platform",
ARCIN="Arc Turn In",
ARCOUT="Arc Turn Out",
DIRTYUP="Level out and Dirty Up", DIRTYUP="Level out and Dirty Up",
BULLSEYE="Follow Bullseye", BULLSEYE="Follow Bullseye",
INITIAL="Initial", INITIAL="Initial",
@ -462,7 +463,7 @@ AIRBOSS.MenuF10={}
--- Airboss class version. --- Airboss class version.
-- @field #string version -- @field #string version
AIRBOSS.version="0.3.7" AIRBOSS.version="0.3.9"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -477,7 +478,7 @@ AIRBOSS.version="0.3.7"
-- TODO: Generalize parameters for other aircraft. -- TODO: Generalize parameters for other aircraft.
-- TODO: Foul deck check. -- TODO: Foul deck check.
-- TODO: Persistence of results. -- TODO: Persistence of results.
-- TODO: Strike group with helo bringing cargo etc. -- NOPE: Strike group with helo bringing cargo etc.
-- TODO: Right pattern step after bolter/wo/patternWO? -- TODO: Right pattern step after bolter/wo/patternWO?
-- TODO: CASE II. -- TODO: CASE II.
-- TODO: CASE III. -- TODO: CASE III.
@ -556,20 +557,19 @@ function AIRBOSS:New(carriername, alias)
self:SetTACAN() self:SetTACAN()
-- Set max aircraft in landing pattern. -- Set max aircraft in landing pattern.
self:SetMaxLandingPattern(1) self:SetMaxLandingPattern(1)
-- Set holding offset to 0 degrees. -- Set holding offset to 0 degrees.
self:SetHoldingOffsetAngle(30) self:SetHoldingOffsetAngle(30)
-- Default recovery case. -- Default recovery case.
self:SetRecoveryCase(1) self:SetRecoveryCase(3)
-- CCA 50 NM radius zone around the carrier. -- CCA 50 NM radius zone around the carrier.
self:SetCarrierControlledArea() self:SetCarrierControlledArea()
-- CCZ 5 NM radius zone around the carrier. -- CCZ 5 NM radius zone around the carrier.
self:SetCarrierControlledZone() self:SetCarrierControlledZone()
-- Init carrier parameters. -- Init carrier parameters.
if self.carriertype==AIRBOSS.CarrierType.STENNIS then if self.carriertype==AIRBOSS.CarrierType.STENNIS then
@ -593,20 +593,14 @@ function AIRBOSS:New(carriername, alias)
-- Smoke zones. -- Smoke zones.
if self.Debug then if self.Debug and false then
--self.zoneInitial:SmokeZone(SMOKECOLOR.White, 90) local case=2
--self.zonePlatform:SmokeZone(SMOKECOLOR.Orange, 90)
--self.zoneDirtyup:SmokeZone(SMOKECOLOR.Blue, 90)
--self.zoneBullseye:SmokeZone(SMOKECOLOR.Red, 90)
--self.zoneInitial:SmokeZone(SMOKECOLOR.White, 90)
local case=3
self:_GetZoneBullseye(case):SmokeZone(SMOKECOLOR.White, 45) self:_GetZoneBullseye(case):SmokeZone(SMOKECOLOR.White, 45)
self:_GetZoneDirtyUp(case):SmokeZone(SMOKECOLOR.Orange, 45) self:_GetZoneDirtyUp(case):SmokeZone(SMOKECOLOR.Orange, 45)
self:_GetZoneArcIn(case):SmokeZone(SMOKECOLOR.Blue, 45) self:_GetZoneArcIn(case):SmokeZone(SMOKECOLOR.Blue, 45)
self:_GetZoneArcOut(case):SmokeZone(SMOKECOLOR.Blue, 45) self:_GetZoneArcOut(case):SmokeZone(SMOKECOLOR.Blue, 45)
self:_GetZonePlatform(case):SmokeZone(SMOKECOLOR.Red, 45) self:_GetZonePlatform(case):SmokeZone(SMOKECOLOR.Red, 45)
self:_GetZoneCorridor(case):SmokeZone(SMOKECOLOR.Green, 45) self:_GetZoneCorridor(case):SmokeZone(SMOKECOLOR.Green, 45)
end end
-- Init default sound files. -- Init default sound files.
@ -837,7 +831,6 @@ function AIRBOSS:SetCarrierradio(frequency, modulation)
return self return self
end end
--- Set number of aircraft units which can be in the landing pattern before the pattern is full. --- Set number of aircraft units which can be in the landing pattern before the pattern is full.
-- @param #AIRBOSS self -- @param #AIRBOSS self
-- @param #number nmax Max number. Default 4. -- @param #number nmax Max number. Default 4.
@ -856,7 +849,6 @@ function AIRBOSS:SetRecoveryTanker(recoverytanker)
return self return self
end end
--- Define warehouse associated with the carrier. --- Define warehouse associated with the carrier.
-- @param #AIRBOSS self -- @param #AIRBOSS self
-- @param Functional.Warehouse#WAREHOUSE warehouse Warehouse object of the carrier. -- @param Functional.Warehouse#WAREHOUSE warehouse Warehouse object of the carrier.
@ -866,7 +858,6 @@ function AIRBOSS:SetWarehouse(warehouse)
return self return self
end end
--- Check if carrier is recovering aircraft. --- Check if carrier is recovering aircraft.
-- @param #AIRBOSS self -- @param #AIRBOSS self
-- @return #boolean If true, time slot for recovery is open. -- @return #boolean If true, time slot for recovery is open.
@ -1066,9 +1057,6 @@ end
function AIRBOSS:onbeforeCase(From, Event, To, OldCase, NewCase) function AIRBOSS:onbeforeCase(From, Event, To, OldCase, NewCase)
self.case=NewCase self.case=NewCase
end end
@ -1121,17 +1109,6 @@ function AIRBOSS:_InitStennis()
q2:BigSmokeSmall(0.1)--:SmokeBlue() q2:BigSmokeSmall(0.1)--:SmokeBlue()
]] ]]
-- 4k descent from holding pattern to 5k platform.
self.Descent4k.name="Descent 4k"
self.Descent4k.Xmin=-UTILS.NMToMeters(50) -- Not more than 50 NM behind the boat.
self.Descent4k.Xmax=nil -- -UTILS.NMToMeters(20) -- Not more than 20 NM closer to the boat from behind.
self.Descent4k.Zmin=-UTILS.NMToMeters(15) -- Not more than 15 NM port/left of boat.
self.Descent4k.Zmax= UTILS.NMToMeters(5) -- Not more than 5 NM starboard/right of boat.
self.Descent4k.LimitXmin=nil
self.Descent4k.LimitXmax=-UTILS.NMToMeters(21) -- Check and next step when 21 NM behind the boat.
self.Descent4k.LimitZmin=nil
self.Descent4k.LimitZmax=nil
-- Platform at 5k. Reduce descent rate to 2000 ft/min to 1200 dirty up level flight. -- Platform at 5k. Reduce descent rate to 2000 ft/min to 1200 dirty up level flight.
self.Platform.name="Platform 5k" self.Platform.name="Platform 5k"
self.Platform.Xmin=-UTILS.NMToMeters(22) -- Not more than 22 NM behind the boat. Last check was at 21 NM. self.Platform.Xmin=-UTILS.NMToMeters(22) -- Not more than 22 NM behind the boat. Last check was at 21 NM.
@ -1281,19 +1258,23 @@ function AIRBOSS:_GetAircraftParameters(playerData, step)
local dist local dist
local speed local speed
if step==AIRBOSS.PatternStep.DESCENT4K then if step==AIRBOSS.PatternStep.PLATFORM then
speed=UTILS.KnotsToMps(250)
elseif step==AIRBOSS.PatternStep.PLATFORM then
alt=UTILS.FeetToMeters(5000) alt=UTILS.FeetToMeters(5000)
dist=UTILS.NMToMeters(20) dist=UTILS.NMToMeters(20)
speed=UTILS.KnotsToMps(250) speed=UTILS.KnotsToMps(250)
elseif step==AIRBOSS.PatternStep.ARCIN then
speed=UTILS.KnotsToMps(250)
elseif step==AIRBOSS.PatternStep.ARCOUT then
speed=UTILS.KnotsToMps(250)
elseif step==AIRBOSS.PatternStep.DIRTYUP then elseif step==AIRBOSS.PatternStep.DIRTYUP then
alt=UTILS.FeetToMeters(1200) alt=UTILS.FeetToMeters(1200)
@ -2079,6 +2060,11 @@ function AIRBOSS:_InitPlayer(playerData)
playerData.landed=false playerData.landed=false
playerData.Tlso=timer.getTime() playerData.Tlso=timer.getTime()
if playerData.group:GetName():match("Groove") then
self:MessageToPlayer(playerData, "Group name contains Groove. You are supposed to test the groove.")
playerData.step=AIRBOSS.PatternStep.FINAL
end
return playerData return playerData
end end
@ -2275,13 +2261,10 @@ function AIRBOSS:_CheckPlayerStatus()
local time=timer.getAbsTime() local time=timer.getAbsTime()
local clock=UTILS.SecondsToClock(time) local clock=UTILS.SecondsToClock(time)
self:T3(string.format("Player status undefined. Waiting for next step. Time %s", clock)) self:T3(string.format("Player status undefined. Waiting for next step. Time %s", clock))
elseif playerData.step==AIRBOSS.PatternStep.REFUELING then
-- Jump to final/groove for testing.
if self.groovedebug then -- Nothing to do here at the moment.
playerData.step=AIRBOSS.PatternStep.FINAL
self.groovedebug=false
end
elseif playerData.step==AIRBOSS.PatternStep.HOLDING then elseif playerData.step==AIRBOSS.PatternStep.HOLDING then
@ -2293,19 +2276,24 @@ function AIRBOSS:_CheckPlayerStatus()
-- CASE I/II/III: New approach. -- CASE I/II/III: New approach.
self:_Commencing(playerData) self:_Commencing(playerData)
elseif playerData.step==AIRBOSS.PatternStep.DESCENT4K then
-- CASE II/III: Initial descent with 4000 ft/min.
self:_Descent4k(playerData)
elseif playerData.step==AIRBOSS.PatternStep.PLATFORM then elseif playerData.step==AIRBOSS.PatternStep.PLATFORM then
-- CASE II/III: Player has reached 5k "Platform". -- CASE II/III: Player has reached 5k "Platform".
self:_Platform(playerData) self:_Platform(playerData)
elseif playerData.step==AIRBOSS.PatternStep.ARCIN then
-- Case II/III if offset.
self:_ArcInTurn(playerData)
elseif playerData.step==AIRBOSS.PatternStep.ARCOUT then
-- Case II/III if offset.
self:_ArcOutTurn(playerData)
elseif playerData.step==AIRBOSS.PatternStep.DIRTYUP then elseif playerData.step==AIRBOSS.PatternStep.DIRTYUP then
-- CASE II/III: Player has descended to 1200 ft and is going level from now on. -- CASE III: Player has descended to 1200 ft and is going level from now on.
self:_DirtyUp(playerData) self:_DirtyUp(playerData)
elseif playerData.step==AIRBOSS.PatternStep.BULLSEYE then elseif playerData.step==AIRBOSS.PatternStep.BULLSEYE then
@ -2374,6 +2362,10 @@ function AIRBOSS:_CheckPlayerStatus()
-- Undefined status. -- Undefined status.
playerData.step=AIRBOSS.PatternStep.UNDEFINED playerData.step=AIRBOSS.PatternStep.UNDEFINED
else
self:E(self.lid..string.format("ERROR: unknown player step %s", tostring(playerData.step)))
end end
else else
@ -2438,12 +2430,9 @@ function AIRBOSS:OnEventBirth(EventData)
--self:RadioTransmission(self.LSOradio, self.radiocall.LONGINGROOVE, false, 20) --self:RadioTransmission(self.LSOradio, self.radiocall.LONGINGROOVE, false, 20)
if self.Debug then if self.Debug then
self:_MarkCase23Zones(_unit:GetName()) --self:_MarkCase23Zones(_unit:GetName())
end end
-- Start in the groove for debugging.
self.groovedebug=false
end end
end end
@ -2500,6 +2489,10 @@ function AIRBOSS:OnEventLand(EventData)
-- Landing distance to carrier position. -- Landing distance to carrier position.
local dist=coord:Get2DDistance(self:GetCoordinate()) local dist=coord:Get2DDistance(self:GetCoordinate())
if X<0 then
dist=-dist
end
-- TODO: check if 360 degrees correctino is necessary! -- TODO: check if 360 degrees correctino is necessary!
local hdg=self.carrier:GetHeading()+self.carrierparam.rwyangle local hdg=self.carrier:GetHeading()+self.carrierparam.rwyangle
@ -2527,7 +2520,7 @@ function AIRBOSS:OnEventLand(EventData)
playerData.step=AIRBOSS.PatternStep.UNDEFINED playerData.step=AIRBOSS.PatternStep.UNDEFINED
-- Call trapped function in 3 seconds to make sure we did not bolter. -- Call trapped function in 3 seconds to make sure we did not bolter.
SCHEDULER:New(nil, self._Trapped,{self, playerData, dist}, 3) SCHEDULER:New(nil, self._Trapped,{self, playerData, wire}, 3)
end end
else else
@ -2925,10 +2918,10 @@ function AIRBOSS:_GetZoneCorridor(case)
local alpha=math.rad(self.holdingoffset) local alpha=math.rad(self.holdingoffset)
-- Distance from ArcIn to ArcOut zone -- Distance from ArcIn to ArcOut zone
local d=UTILS.NMToMeters(12) local d=12
local y=d*math.tan(alpha) local y=d*math.tan(alpha)
local d2=math.cos(alpha)/UTILS.NMToMeters(2) local d2=math.cos(alpha)/2
local c={} local c={}
c[1]=self:GetCoordinate() -- Carrier coordinate c[1]=self:GetCoordinate() -- Carrier coordinate
@ -2938,8 +2931,8 @@ function AIRBOSS:_GetZoneCorridor(case)
c[5]=c[4]:Translate( UTILS.NMToMeters(10), offset) -- to back wall angled c[5]=c[4]:Translate( UTILS.NMToMeters(10), offset) -- to back wall angled
c[6]=c[5]:Translate( UTILS.NMToMeters( 2), offset+90) -- Back wall (angled) c[6]=c[5]:Translate( UTILS.NMToMeters( 2), offset+90) -- Back wall (angled)
c[7]=c[6]:Translate(-UTILS.NMToMeters(10+d2), offset) -- back along X & Z c[7]=c[6]:Translate(-UTILS.NMToMeters(10+d2), offset) -- back along X & Z
c[8]=c[7]:Translate( UTILS.NMToMeters( y), radial-90) -- back along X c[8]=c[7]:Translate( UTILS.NMToMeters( y), radial-90) -- back along X
c[9]=c[1]:Translate(-UTILS.NMToMeters( 1), radial+90) -- 1 left of carrier c[9]=c[1]:Translate( UTILS.NMToMeters( 1), radial+90) -- 1 left of carrier
-- Create an array of a square! -- Create an array of a square!
@ -2991,13 +2984,16 @@ function AIRBOSS:_GetHoldingZone(playerData)
else else
-- CASE II/II -- CASE II/II
-- Get radial.
local hdg
if playerData.case==2 then
hdg=self:GetRadialCase2(false, true)
else
hdg=self:GetRadialCase3(false, true)
end
-- TODO: Include 15 or 30 degrees offset. -- TODO: This is WRONG!
local hdg=self.carrier:GetHeading()-self.holdingoffset
--TODO: case dependend radial!
local hdg=self:GetRadialCase3(false)
-- Create an array of a square! -- Create an array of a square!
local p={} local p={}
p[1]=c1:Translate(UTILS.NMToMeters(1), hdg+90):GetVec2() --c1 is at (angels+15) NM directly behind the carrier. We translate it 1 NM starboard. p[1]=c1:Translate(UTILS.NMToMeters(1), hdg+90):GetVec2() --c1 is at (angels+15) NM directly behind the carrier. We translate it 1 NM starboard.
@ -3033,12 +3029,12 @@ function AIRBOSS:_Commencing(playerData)
-- CASE I: Player has to fly to the initial which is 3 NM DME astern of the boat. -- CASE I: Player has to fly to the initial which is 3 NM DME astern of the boat.
playerData.step=AIRBOSS.PatternStep.INITIAL playerData.step=AIRBOSS.PatternStep.INITIAL
else else
-- CASE III: Player has to start the descent at 4000 ft/min. -- CASE II/III: Player has to start the descent at 4000 ft/min.
playerData.step=AIRBOSS.PatternStep.PLATFORM playerData.step=AIRBOSS.PatternStep.PLATFORM
end end
end end
--- Start pattern when player enters the initial zone. --- Start pattern when player enters the initial zone in case I/II recoveries.
-- @param #AIRBOSS self -- @param #AIRBOSS self
-- @param #AIRBOSS.PlayerData playerData Player data table. -- @param #AIRBOSS.PlayerData playerData Player data table.
function AIRBOSS:_Initial(playerData) function AIRBOSS:_Initial(playerData)
@ -3061,28 +3057,7 @@ function AIRBOSS:_Initial(playerData)
end end
--- Descent at 4k. --- Platform at 5k ft for case II/III recoveries. Descent at 2000 ft/min.
-- @param #AIRBOSS self
-- @param #AIRBOSS.PlayerData playerData Player data table.
function AIRBOSS:_Descent4k(playerData)
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
local X, Z, rho, phi=self:_GetDistances(playerData.unit)
-- Abort condition check.
if self:_CheckAbort(X, Z, self.Descent4k) then
self:_AbortPattern(playerData, X, Z, self.Descent4k)
--return
end
-- Check if we are in front of the boat (diffX > 0).
if self:_CheckLimits(X, Z, self.Descent4k) then
-- Next step: Platform at 5k
playerData.step=AIRBOSS.PatternStep.PLATFORM
end
end
--- Platform at 5k ft. Descent at 2000 ft/min.
-- @param #AIRBOSS self -- @param #AIRBOSS self
-- @param #AIRBOSS.PlayerData playerData Player data table. -- @param #AIRBOSS.PlayerData playerData Player data table.
function AIRBOSS:_Platform(playerData) function AIRBOSS:_Platform(playerData)
@ -3095,7 +3070,7 @@ function AIRBOSS:_Platform(playerData)
-- Issue warning. -- Issue warning.
if invalid and not playerData.warning then if invalid and not playerData.warning then
self:MessageToPlayer(playerData, "You left the valid pattern zone!", "AIRBOSS") self:MessageToPlayer(playerData, "You left the valid approach corridor!", "AIRBOSS")
playerData.warning=true playerData.warning=true
end end
@ -3123,17 +3098,123 @@ function AIRBOSS:_Platform(playerData)
self:MessageToPlayer(playerData, hint, "MARSHAL", "") self:MessageToPlayer(playerData, hint, "MARSHAL", "")
end end
-- Next step: Dirty up and level out at 1200 ft. -- Next step: depends.
if math.abs(self.holdingoffset)>0 then if math.abs(self.holdingoffset)>0 then
-- Turn to BRC (case I) or FB (case III).
playerData.step=AIRBOSS.PatternStep.ARCIN playerData.step=AIRBOSS.PatternStep.ARCIN
else else
playerData.step=AIRBOSS.PatternStep.DIRTYUP if playerData.case==2 then
-- Case II: Initial zone then Case I recovery.
playerData.step=AIRBOSS.PatternStep.INITIAL
elseif playerData.case==3 then
-- CASE III: Dirty up.
playerData.step=AIRBOSS.PatternStep.DIRTYUP
end
end end
playerData.warning=nil playerData.warning=nil
end end
end end
--- Dirty up and level out at 1200 ft.
--- Arc in turn for case II/III recoveries.
-- @param #AIRBOSS self
-- @param #AIRBOSS.PlayerData playerData Player data table.
function AIRBOSS:_ArcInTurn(playerData)
-- Check if player is in valid zone
local validzone=self:_GetZoneCorridor(playerData.case)
-- Check if we are inside the moving zone.
local invalid=playerData.unit:IsNotInZone(validzone)
-- Issue warning.
if invalid and not playerData.warning then
self:MessageToPlayer(playerData, "You left the valid approach corridor!", "AIRBOSS")
playerData.warning=true
end
-- Check if we are inside the moving zone.
local inzone=playerData.unit:IsInZone(self:_GetZoneArcIn(playerData.case))
--if self:_CheckLimits(X, Z, self.DirtyUp) then
if inzone then
-- Debug message.
MESSAGE:New("Arc Turn In step reached", 5):ToAllIf(self.Debug)
-- Get optimal altitiude.
local altitude, aoa, distance, speed=self:_GetAircraftParameters(playerData)
-- Get speed hint.
local hintSpeed=self:_SpeedCheck(playerData, speed)
-- Message to player.
if playerData.difficulty~=AIRBOSS.Difficulty.HARD then
local hint=string.format("%s\n%s", playerData.step, hintSpeed)
self:MessageToPlayer(playerData, hint, "MARSHAL", "")
end
-- Next step: Arc Out Turn.
playerData.step=AIRBOSS.PatternStep.ARCOUT
playerData.warning=nil
end
end
--- Arc out turn for case II/III recoveries.
-- @param #AIRBOSS self
-- @param #AIRBOSS.PlayerData playerData Player data table.
function AIRBOSS:_ArcOutTurn(playerData)
-- Check if player is in valid zone
local validzone=self:_GetZoneCorridor(playerData.case)
-- Check if we are inside the moving zone.
local invalid=playerData.unit:IsNotInZone(validzone)
-- Issue warning.
if invalid and not playerData.warning then
self:MessageToPlayer(playerData, "You left the valid approach corridor!", "AIRBOSS")
playerData.warning=true
end
-- Check if we are inside the moving zone.
local inzone=playerData.unit:IsInZone(self:_GetZoneArcOut(playerData.case))
--if self:_CheckLimits(X, Z, self.DirtyUp) then
if inzone then
-- Debug message.
MESSAGE:New("Arc Turn Out step reached", 5):ToAllIf(self.Debug)
-- Get optimal altitiude.
local altitude, aoa, distance, speed=self:_GetAircraftParameters(playerData)
-- Get speed hint.
local hintSpeed=self:_SpeedCheck(playerData, speed)
-- Message to player.
if playerData.difficulty~=AIRBOSS.Difficulty.HARD then
local hint=string.format("%s\n%s", playerData.step, hintSpeed)
self:MessageToPlayer(playerData, hint, "MARSHAL", "")
end
-- Next step:
if playerData.case==2 then
-- Case II: Initial.
playerData.step=AIRBOSS.PatternStep.INITIAL
elseif playerdata.case==3 then
-- Case III: Dirty up.
playerData.step=AIRBOSS.PatternStep.DIRTYUP
else
-- ERROR!
end
playerData.warning=nil
end
end
--- Dirty up and level out at 1200 ft for case III recovery.
-- @param #AIRBOSS self -- @param #AIRBOSS self
-- @param #AIRBOSS.PlayerData playerData Player data table. -- @param #AIRBOSS.PlayerData playerData Player data table.
function AIRBOSS:_DirtyUp(playerData) function AIRBOSS:_DirtyUp(playerData)
@ -3146,8 +3227,8 @@ function AIRBOSS:_DirtyUp(playerData)
-- Issue warning. -- Issue warning.
if invalid and not playerData.warning then if invalid and not playerData.warning then
self:MessageToPlayer(playerData, "You left the valid pattern zone!", "AIRBOSS") self:MessageToPlayer(playerData, "You left the valid approach corridor!", "AIRBOSS")
playerData.warning=true playerData.warning=true
end end
-- Check if we are inside the moving zone. -- Check if we are inside the moving zone.
@ -3175,19 +3256,14 @@ function AIRBOSS:_DirtyUp(playerData)
self:MessageToPlayer(playerData, hint, "MARSHAL", "") self:MessageToPlayer(playerData, hint, "MARSHAL", "")
end end
-- Next step: -- Next step: CASE III: Intercept glide slope and follow bullseye (ICLS).
if self.case==2 then playerData.step=AIRBOSS.PatternStep.BULLSEYE
-- CASE II: Fly to the initial and perform CASE I pattern.
playerData.step=AIRBOSS.PatternStep.INITIAL
elseif self.case==3 then
-- CASE III: Intercept glide slope and follow bullseye (ICLS).
playerData.step=AIRBOSS.PatternStep.BULLSEYE
end
playerData.warning=nil playerData.warning=nil
end end
end end
--- Intercept glide slop and follow ICLS, aka Bullseye. --- Intercept glide slop and follow ICLS, aka Bullseye for case III recovery.
-- @param #AIRBOSS self -- @param #AIRBOSS self
-- @param #AIRBOSS.PlayerData playerData Player data table. -- @param #AIRBOSS.PlayerData playerData Player data table.
function AIRBOSS:_Bullseye(playerData) function AIRBOSS:_Bullseye(playerData)
@ -3200,7 +3276,7 @@ function AIRBOSS:_Bullseye(playerData)
-- Issue warning. -- Issue warning.
if invalid and not playerData.warning then if invalid and not playerData.warning then
self:MessageToPlayer(playerData, "You left the valid pattern zone!", "AIRBOSS") self:MessageToPlayer(playerData, "You left the valid approach corridor!", "AIRBOSS")
playerData.warning=true playerData.warning=true
end end
@ -3231,12 +3307,13 @@ function AIRBOSS:_Bullseye(playerData)
-- Next step: Groove Call the ball. -- Next step: Groove Call the ball.
playerData.step=AIRBOSS.PatternStep.GROOVE_XX playerData.step=AIRBOSS.PatternStep.GROOVE_XX
playerData.warning=nil playerData.warning=nil
end end
end end
--- Upwind leg or break entry. --- Upwind leg or break entry for case I/II recoveries.
-- @param #AIRBOSS self -- @param #AIRBOSS self
-- @param #AIRBOSS.PlayerData playerData Player data table. -- @param #AIRBOSS.PlayerData playerData Player data table.
function AIRBOSS:_Upwind(playerData) function AIRBOSS:_Upwind(playerData)
@ -3781,13 +3858,13 @@ function AIRBOSS:_GetWire(d)
-- Which wire was caught? X>0 since calculated as distance! -- Which wire was caught? X>0 since calculated as distance!
local wire local wire
if d>math.abs(self.carrierparam.wire1+wdx) then if d<self.carrierparam.wire1+wdx then
wire=1 wire=1
elseif d>math.abs(self.carrierparam.wire2+wdx) then elseif d<self.carrierparam.wire2+wdx then
wire=2 wire=2
elseif d>math.abs(self.carrierparam.wire3+wdx) then elseif d<self.carrierparam.wire3+wdx then
wire=3 wire=3
elseif d>math.abs(self.carrierparam.wire4+wdx) then elseif d<self.carrierparam.wire4+wdx then
wire=4 wire=4
else else
wire=99 wire=99
@ -3799,35 +3876,22 @@ end
--- Trapped? --- Trapped?
-- @param #AIRBOSS self -- @param #AIRBOSS self
-- @param #AIRBOSS.PlayerData playerData Player data table. -- @param #AIRBOSS.PlayerData playerData Player data table.
-- @param #number X Distance in meters wrt carrier position where player landed. -- @param #number wire The wire caught.
function AIRBOSS:_Trapped(playerData, X) function AIRBOSS:_Trapped(playerData, wire)
self:I(self.lid.."FF TRAPPED")
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
--local X, Z, rho, phi = self:_GetDistances(pos)
if playerData.unit:InAir()==false then if playerData.unit:InAir()==false then
-- Seems we have successfully landed. -- Seems we have successfully landed.
-- Get wire. -- Message to player.
local wire=self:_GetWire(X)
-- Info to player.
local text=string.format("Trapped! %d-wire.", wire) local text=string.format("Trapped! %d-wire.", wire)
self:MessageToPlayer(playerData, text, "LSO", "") self:MessageToPlayer(playerData, text, "LSO", "")
-- Debug message.
local text=string.format("Distance X=%.1f meters resulted in a %d-wire estimate.", X, wire)
MESSAGE:New(text, 30):ToAllIf(self.Debug)
self:I(self.lid..text)
-- Debrief. -- Debrief.
local hint = string.format("Trapped catching the %d-wire.", wire) local hint = string.format("Trapped catching the %d-wire.", wire)
self:_AddToSummary(playerData, "Goove: IW", hint) self:_AddToSummary(playerData, "Goove: IW", hint)
else else
--Boltered! --Still in air ==> Boltered!
playerData.boltered=true playerData.boltered=true
end end
@ -4012,7 +4076,7 @@ function AIRBOSS:GetRadialCase2(magnetic, offset)
-- Holding offset angle (+-15 or 30 degrees usually) -- Holding offset angle (+-15 or 30 degrees usually)
if offset then if offset then
radial=radial-self.holdingoffset radial=radial+self.holdingoffset
end end
-- Adjust for negative values. -- Adjust for negative values.
@ -4035,7 +4099,7 @@ function AIRBOSS:GetRadialCase3(magnetic, offset)
-- Holding offset angle (+-15 or 30 degrees usually) -- Holding offset angle (+-15 or 30 degrees usually)
if offset then if offset then
radial=radial-self.holdingoffset radial=radial+self.holdingoffset
end end
-- Adjust for negative values. -- Adjust for negative values.
@ -5285,14 +5349,20 @@ function AIRBOSS:_ResetPlayerStatus(_unitName)
if playerData then if playerData then
-- Inform player.
local text="Status reset executed! You have been removed from all queues." local text="Status reset executed! You have been removed from all queues."
self:MessageToPlayer(playerData, text, nil, "")
-- Remove from marhal stack can collapse stack if necessary.
if self:_InQueue(self.Qmarshal, playerData.group) then if self:_InQueue(self.Qmarshal, playerData.group) then
self:_CollapseMarshalStack(playerData, true) self:_CollapseMarshalStack(playerData, true)
end end
-- Remove flight from queues. -- Remove flight from queues.
self:_RemoveFlight(playerData) self:_RemoveFlight(playerData)
-- Initialize player data.
self:_InitPlayer(playerData)
end end
end end
@ -5770,6 +5840,21 @@ function AIRBOSS:_DisplayCarrierInfo(_unitname)
icls=string.format("%d", self.ICLSchannel) icls=string.format("%d", self.ICLSchannel)
end end
-- Get groups, units in queues.
local Nmarshal,nmarshal=self:_GetQueueInfo(self.Qmarshal, playerData.case)
local Npattern,npattern=self:_GetQueueInfo(self.Qpattern)
-- Get recovery times of carrier.
local recoverytimes="Recovery time slots:"
if #self.recoverytime==0 then
recoverytimes=recoverytimes.." empty"
else
for _,_rtime in pairs(self.recoverytime) do
local rtime=_rtime --#AIRBOSS.Recovery
recoverytimes=recoverytimes..string.format("\nSlot %s - %s", UTILS.SecondsToClock(rtime.START), UTILS.SecondsToClock(rtime.STOP))
end
end
-- Message text. -- Message text.
local text=string.format("%s info:\n", self.alias) local text=string.format("%s info:\n", self.alias)
text=text..string.format("=============================================\n") text=text..string.format("=============================================\n")
@ -5783,8 +5868,9 @@ function AIRBOSS:_DisplayCarrierInfo(_unitname)
text=text..string.format("TACAN Channel %s\n", tacan) text=text..string.format("TACAN Channel %s\n", tacan)
text=text..string.format("ICLS Channel %s\n", icls) text=text..string.format("ICLS Channel %s\n", icls)
text=text..string.format("# A/C total %d\n", #self.flights) text=text..string.format("# A/C total %d\n", #self.flights)
text=text..string.format("# A/C holding %d\n", #self.Qmarshal) text=text..string.format("# A/C marshal %d (%d)\n", Nmarshal, nmarshal)
text=text..string.format("# A/C pattern %d", #self.Qpattern) text=text..string.format("# A/C pattern %d (%d)\n", Npattern, npattern)
text=text..string.format(recoverytimes)
self:T2(self.lid..text) self:T2(self.lid..text)
-- Send message. -- Send message.
@ -5989,8 +6075,7 @@ function AIRBOSS:_MarkCase23Zones(_unitName, flare)
if case<2 then if case<2 then
case=3 case=3
end end
-- Initial -- Initial
local text=string.format("Marking CASE %d zone:\n", case) local text=string.format("Marking CASE %d zone:\n", case)