AIRBOSS v0.2.9

- Added holding check (WIP)
- Many improvents and fixes.
This commit is contained in:
Frank 2018-11-18 23:57:41 +01:00
parent 9d9f233c15
commit 2feb293c12
4 changed files with 247 additions and 135 deletions

View File

@ -84,6 +84,7 @@
-- @field #number SubtitleDuration Duration of the Subtitle in seconds.
-- @field #number Power Power of the antenna is Watts.
-- @field #boolean Loop Transmission is repeated (default true).
-- @field #string alias Name of the radio transmitter.
-- @extends Core.Base#BASE
RADIO = {
ClassName = "RADIO",
@ -94,6 +95,7 @@ RADIO = {
SubtitleDuration = 0,
Power = 100,
Loop = false,
alias=nil,
}
--- Create a new RADIO Object. This doesn't broadcast a transmission, though, use @{#RADIO.Broadcast} to actually broadcast.
@ -116,6 +118,22 @@ function RADIO:New(Positionable)
return nil
end
--- Set alias of the transmitter.
-- @param #RADIO self
-- @param #string alias Name of the radio transmitter.
-- @return #RADIO self
function RADIO:SetAlias(alias)
self.alias=tostring(alias)
return self
end
--- Get alias of the transmitter.
-- @param #RADIO self
-- @return #string Name of the transmitter.
function RADIO:GetAlias()
return tostring(self.alias)
end
--- Set the file name for the radio transmission.
-- @param #RADIO self
-- @param #string FileName File name of the sound file (i.e. "Noise.ogg")

View File

@ -4,16 +4,16 @@
--
-- Features:
--
-- * CASE I and III recovery.
-- * Supports human and AI pilots.
-- * CASE I, II and III recoveries.
-- * Supports human pilots as well as AI.
-- * Automatic LSO grading.
-- * Different skill level supporting tipps during for students or complete zip lip for pros.
-- * Different skill levels from tipps on-the-fly for students to complete ziplip for pros.
-- * Rescue helo option.
-- * Recovery tanker option.
-- * Voice overs for LSO and AIRBOSS calls. Can easily customized by users.
-- * 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).
-- * F10 radio menu including carrier info (weather, radio frequencies, TACAN/ICLS channels, LSO grades).
-- * Multiple carriers supported.
--
-- **PLEASE NOTE** that his class is work in progress and in an **alpha** stage.
@ -47,7 +47,6 @@
-- @field #AIRBOSS.RadioCalls radiocall LSO and Airboss call sound files and texts.
-- @field Core.Zone#ZONE_UNIT zoneCCA Carrier controlled area (CCA), i.e. a zone of 50 NM radius around the carrier.
-- @field Core.Zone#ZONE_UNIT zoneCCZ Carrier controlled zone (CCZ), i.e. a zone of 5 NM radius around the carrier.
-- @field Core.Zone#ZONE_UNIT zoneHolding Zone where aircraft are holding before entering the landing pattern.
-- @field Core.Zone#ZONE_UNIT zoneInitial Zone usually 3 NM astern of carrier where pilots start their CASE I pattern.
-- @field #table players Table of players.
-- @field #table menuadded Table of units where the F10 radio menu was added.
@ -103,7 +102,6 @@ AIRBOSS = {
radiocall = {},
zoneCCA = nil,
zoneCCZ = nil,
zoneHolding = nil,
zoneInitial = nil,
players = {},
menuadded = {},
@ -152,6 +150,7 @@ AIRBOSS.AircraftCarrier={
E2D="E-2C",
FA18C="F/A-18C",
F14A="F-14A",
--TODO: Add A-A4-E-C
}
@ -366,7 +365,7 @@ AIRBOSS.GroovePos={
-- @field #boolean attitudemonitor If true, display aircraft attitude and other parameters constantly.
-- @field #table debrief Debrief analysis of the current step of this pass.
-- @field #table grades LSO grades of player passes.
-- @field #boolean inbigzone If true, player is in the big zone.
-- @field #boolean holding If true, player is in holding zone.
-- @field #boolean landed If true, player landed or attempted to land.
-- @field #boolean bolter If true, LSO told player to bolter.
-- @field #boolean boltered If true, player boltered.
@ -375,6 +374,7 @@ AIRBOSS.GroovePos={
-- @field #boolean lig If true, player was long in the groove.
-- @field #number Tlso Last time the LSO gave an advice.
-- @field #AIRBOSS.GroovePos groove Data table at each position in the groove. Elemets are of type @{#AIRBOSS.GrooveData}.
-- @field #table menu F10 radio menu
--- Checkpoint parameters triggering the next step in the pattern.
-- @type AIRBOSS.Checkpoint
@ -417,12 +417,13 @@ AIRBOSS.MenuF10={}
--- Airboss class version.
-- @field #string version
AIRBOSS.version="0.2.8"
AIRBOSS.version="0.2.9"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Get an _OK_ pass if long in groove. Possible other pattern wave offs as well?!
-- TODO: Add radio transmission queue for LSO and airboss.
-- TODO: Get correct wire when trapped.
-- TODO: Add radio check (LSO, AIRBOSS) to F10 radio menu.
@ -489,10 +490,12 @@ function AIRBOSS:New(carriername, alias)
-- Set up Airboss radio.
self.Carrierradio=RADIO:New(self.carrier)
self.Carrierradio:SetAlias("AIRBOSS")
self:SetCarrierradio()
-- Set up LSO radio.
self.LSOradio=RADIO:New(self.carrier)
self.LSOradio:SetAlias("LSO")
self:SetLSOradio()
-- Init carrier parameters.
@ -752,7 +755,7 @@ end
function AIRBOSS:onafterStart(From, Event, To)
-- Events are handled my MOOSE.
self:I(self.lid..string.format("Starting Carrier Training %s for carrier unit %s of type %s.", AIRBOSS.version, self.carrier:GetName(), self.carriertype))
self:I(self.lid..string.format("Starting AIRBOSS v%s for carrier unit %s of type %s.", AIRBOSS.version, self.carrier:GetName(), self.carriertype))
local theatre=env.mission.theatre
@ -772,6 +775,7 @@ function AIRBOSS:onafterStart(From, Event, To)
self:HandleEvent(EVENTS.Birth)
self:HandleEvent(EVENTS.Land)
self:HandleEvent(EVENTS.Crash)
--self:HandleEvent(EVENTS.Ejection)
-- Time stamp for checking queues.
self.Tqueue=timer.getTime()
@ -818,6 +822,7 @@ function AIRBOSS:onafterStatus(From, Event, To)
self:_CheckPlayerStatus()
-- Call status every 0.5 seconds.
-- TODO: make dt user input.
self:__Status(-0.5)
end
@ -1179,7 +1184,6 @@ function AIRBOSS:_PrintQueue(queue, name)
for i,_flight in pairs(queue) do
local flight=_flight --#AIRBOSS.Flightitem
local clock=UTILS.SecondsToClock(flight.time)
-- TODO: add stack alt from flag
local stack=flight.flag:Get()
local alt=UTILS.MetersToFeet(self:_GetMarshalAltitude(stack))
local fuel=flight.group:GetFuelMin()*100
@ -1190,19 +1194,6 @@ function AIRBOSS:_PrintQueue(queue, name)
self:I(self.lid..text)
end
--- Get carrier coaltion.
-- @param #AIRBOSS self
function AIRBOSS:GetCoalition()
return self.carrier:GetCoalition()
end
--- Get carrier coordinate.
-- @param #AIRBOSS self
function AIRBOSS:GetCoordinate()
return self.carrier:GetCoordinate()
end
--- Scan carrier zone for (new) units.
-- @param #AIRBOSS self
function AIRBOSS:_ScanCarrierZone()
@ -1312,12 +1303,13 @@ function AIRBOSS:_GetOnboardNumbers(group)
-- Onboard number and unit name.
local n=tostring(unit.onboard_num)
local name=unit.name
local skill=unit.skill
-- Table entry.
numbers[name]=n
-- Debug text.
text=text..string.format("\n- unit=%s - onboard #=%s", name, n)
text=text..string.format("\n- unit %s: onboard #=%s skill=%s", name, n, skill)
end
-- Debug info.
@ -1399,12 +1391,15 @@ function AIRBOSS:_MarshalPlayer(group)
-- Get player data.
local playerData=self:_GetPlayerDataGroup(group)
-- Get flight data.
local knownflight=self:_GetFlightFromGroupInQueue(group, self.flights)
-- Check if flight is known to the airboss already.
if playerData and knownflight then
-- Add group to marshal stack.
self:_AddMarshallGroup(knownflight, nstacks+1)
-- Set step to holding.
playerData.step=AIRBOSS.PatternStep.HOLDING
else
-- Flight is not registered yet.
local text="You are not yet registered inside the CCA. Marshal request denied!"
@ -1485,11 +1480,12 @@ end
-- @param #number stack Assigned stack number. Counting starts at one, i.e. stack=1 is the first stack.
-- @return #number Holding altitude in meters.
-- @return Core.Point#COORDINATE Holding position coordinate.
-- @return Core.Point#COORDINATE Second holding position coordinate of racetrack pattern for CASE III recoveries.
-- @return Core.Point#COORDINATE Second holding position coordinate of racetrack pattern for CASE II/III recoveries.
function AIRBOSS:_GetMarshalAltitude(stack)
-- Carrier position.
local Carrier=self:GetCoordinate()
local hdg=self.carrier:GetHeading()
-- Altitude of first stack. Depends on recovery case.
local angels0
@ -1501,13 +1497,13 @@ function AIRBOSS:_GetMarshalAltitude(stack)
-- CASE I: Holding at 2000 ft on a circular pattern port of the carrier. Interval +1000 ft for next stack.
angels0=2
Dist=UTILS.NMToMeters(2.5)
p1=Carrier:Translate(Dist, 280)
p1=Carrier:Translate(Dist, hdg-70)
else
-- CASE III: Holding at 6000 ft on a racetrack pattern astern the carrier.
angels0=6
Dist=UTILS.NMToMeters((stack-1)*angels0+15)
p1=Carrier:Translate(Dist, self:_Radial())
p2=Carrier:Translate(Dist+UTILS.NMToMeters(10), self:_Radial())
p1=Carrier:Translate(-Dist, hdg)
p2=Carrier:Translate(-(Dist+UTILS.NMToMeters(10)), hdg)
end
-- Pattern altitude.
@ -1526,11 +1522,12 @@ function AIRBOSS:_AddMarshallGroup(flight, flagvalue)
flight.flag:Set(flagvalue)
-- Pressure.
local hPa2inHg=0.0295299830714
local P=self:GetCoordinate():GetPressure()*hPa2inHg
local P=UTILS.hPa2inHg(self:GetCoordinate():GetPressure())
local unitname=flight.group:GetUnit(1):GetName()
-- TODO: Get correct board number if possible?
local boardnumber=flight.groupname
local boardnumber=tostring(flight.onboardnumbers[unitname])
local alt=UTILS.MetersToFeet(self:_GetMarshalAltitude(flagvalue))
local brc=self:_BaseRecoveryCourse()
@ -1547,7 +1544,7 @@ end
-- @param #AIRBOSS self
function AIRBOSS:_CollapseMarshalStack()
-- Decrease flag values of all groups in marshal stack.
-- Decrease flag values of all flight groups in marshal stack.
for _,_flight in pairs(self.Qmarshal) do
local flight=_flight --#AIRBOSS.Flightitem
local flagvalue=flight.flag:Get()
@ -1557,6 +1554,7 @@ function AIRBOSS:_CollapseMarshalStack()
-- Number of marshal flight groups.
local nmarshal=#self.Qmarshal
-- TODO: collapse marschal stack only from N to N-x. For example, when a group in the stack leaves (e.g. for refuelling).
for i=nmarshal,1,-1 do
local flight=self.Qmarshal[i] --#AIRBOSS.Flightitem
--flight.
@ -1565,7 +1563,7 @@ function AIRBOSS:_CollapseMarshalStack()
-- First flight to enter the landing pattern.
local flight=self.Qmarshal[1] --#AIRBOSS.Flightitem
self:I(self..lid..string.format("New pattern flight %s.", flight.groupname))
self:I(self.lid..string.format("New pattern flight %s.", flight.groupname))
-- TODO: better message.
MESSAGE:New(string.format("Marshal, %s, you are cleared for Case I recovery pattern!", flight.groupname), 15):ToAll()
@ -1573,6 +1571,8 @@ function AIRBOSS:_CollapseMarshalStack()
-- Set player step.
if flight.ai==false then
local playerData=self:_GetPlayerDataGroup(flight.group)
playerData.step=AIRBOSS.PatternStep.COMMENCING
end
@ -1683,25 +1683,12 @@ function AIRBOSS:_CheckPlayerStatus()
-- Check if player is in carrier controlled area (zone with R=50 NM around the carrier).
if unit:IsInZone(self.zoneCCA) then
-- Check if player was previously not inside the zone.
if playerData.inbigzone==false then
-- Welcome player once he enters the carrier zone.
local text=string.format("Welcome back, %s! TCN 74X, ICLS 1, BRC 354 (MAG HDG).\n", playerData.callsign)
-- Heading and distance to register for approach.
local heading=playerData.unit:GetCoordinate():HeadingTo(self.zoneInitial:GetCoordinate())
local distance=playerData.unit:GetCoordinate():Get2DDistance(self.zoneInitialzone:GetCoordinate())
-- Send message.
text=text..string.format("Fly heading %d for %.1f NM and turn to BRC.", heading, distance)
MESSAGE:New(text, 5):ToClient(playerData.client)
end
if playerData.step==AIRBOSS.PatternStep.UNDEFINED then
self:I("Player status undefined. Waiting for next step.")
-- Status undefined.
local time=timer.getAbsTime()
local clock=UTILS.SecondsToClock(time)
self:I(string.format("Player status undefined. Waiting for next step. Time %s", clock))
-- Jump directly to CASE I straight in approach.
--playerData.step=AIRBOSS.PatternStep.COMMENCING
@ -1712,28 +1699,29 @@ function AIRBOSS:_CheckPlayerStatus()
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.
-- CASE I/II/III: In holding pattern.
self:_Holding(playerData)
elseif playerData.step==AIRBOSS.PatternStep.COMMENCING then
-- CASE I/II/III: New approach.
self:_Commencing(playerData)
elseif playerData.step==AIRBOSS.PatternStep.DESCENT4K then
-- CASE III: Initial descent with 4000 ft/min.
-- CASE II/III: Initial descent with 4000 ft/min.
self:_Descent4k(playerData)
elseif playerData.step==AIRBOSS.PatternStep.DESCENT2K then
-- CASE III: Player has reached 5k "Platform".
-- CASE II/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.
-- CASE II/III: Player has descended to 1200 ft and is going level from now on.
self:_DirtyUp(playerData)
elseif playerData.step==AIRBOSS.PatternStep.BULLSEYE then
@ -1743,32 +1731,32 @@ function AIRBOSS:_CheckPlayerStatus()
elseif playerData.step==AIRBOSS.PatternStep.INITIAL then
-- Player is at the initial position entering the landing pattern.
-- CASE I/II: Player is at the initial position entering the landing pattern.
self:_Initial(playerData)
elseif playerData.step==AIRBOSS.PatternStep.UPWIND then
-- Upwind leg aka break entry.
-- CASE I/II: Upwind leg aka break entry.
self:_Upwind(playerData)
elseif playerData.step==AIRBOSS.PatternStep.EARLYBREAK then
-- Early break.
-- CASE I/II: Early break.
self:_Break(playerData, "early")
elseif playerData.step==AIRBOSS.PatternStep.LATEBREAK then
-- Late break.
-- CASE I/II: Late break.
self:_Break(playerData, "late")
elseif playerData.step==AIRBOSS.PatternStep.ABEAM then
-- Abeam position.
-- CASE I/II: Abeam position.
self:_Abeam(playerData)
elseif playerData.step==AIRBOSS.PatternStep.NINETY then
-- Check long down wind leg.
-- CASE:I/II: Check long down wind leg.
self:_CheckForLongDownwind(playerData)
-- At the ninety.
@ -1776,12 +1764,12 @@ function AIRBOSS:_CheckPlayerStatus()
elseif playerData.step==AIRBOSS.PatternStep.WAKE then
-- In the wake.
-- CASE I/II: In the wake.
self:_Wake(playerData)
elseif playerData.step==AIRBOSS.PatternStep.FINAL then
-- Turn to final and enter the groove.
-- CASE I/II: Turn to final and enter the groove.
self:_Final(playerData)
elseif playerData.step==AIRBOSS.PatternStep.GROOVE_XX or
@ -1791,7 +1779,7 @@ function AIRBOSS:_CheckPlayerStatus()
playerData.step==AIRBOSS.PatternStep.GROOVE_AR or
playerData.step==AIRBOSS.PatternStep.GROOVE_IW then
-- In the groove.
-- CASE I/II: In the groove.
self:_Groove(playerData)
elseif playerData.step==AIRBOSS.PatternStep.DEBRIEF then
@ -1805,7 +1793,8 @@ function AIRBOSS:_CheckPlayerStatus()
end
else
playerData.inbigzone=false
--playerData.inbigzone=false
self:E(self.lid.."WARNING: Player left the CCA!")
end
else
@ -1925,6 +1914,9 @@ function AIRBOSS:OnEventLand(EventData)
local lp=coord:MarkToAll("Landing coord.")
coord:SmokeGreen()
-- Landing distance to carrier position.
local dist=coord:Get2DDistance(self:GetCoordinate())
-- Debug marks of wires.
local w1=self:GetCoordinate():Translate(self.carrierparam.wire1, 0):MarkToAll("Wire 1")
local w2=self:GetCoordinate():Translate(self.carrierparam.wire2, 0):MarkToAll("Wire 2")
@ -1938,13 +1930,24 @@ function AIRBOSS:OnEventLand(EventData)
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)
SCHEDULER:New(nil, self._Trapped,{self, playerData, dist}, 3)
end
else
-- TODO: Get landing coodinates of AI hornet for perfect _OK_ 3-wire pass!
-- Coordinate at landing event
local coord=EventData.IniUnit:GetCoordinate()
-- Debug mark of player landing coord.
local dist=coord:Get2DDistance(self:GetCoordinate())
local text=string.format("AI landing dist=%.1f m", dist)
env.info(text)
local lp=coord:MarkToAll(text)
coord:SmokeGreen()
-- AI: Decrease number of units in flight and remove group from pattern queue if all units landed.
if self:_InQueue(self.Qpattern, EventData.IniGroup) then
@ -2018,7 +2021,7 @@ function AIRBOSS:_NewPlayer(unitname)
playerData.difficulty=playerData.difficulty or AIRBOSS.Difficulty.NORMAL
-- Player is in the big zone around the carrier.
playerData.inbigzone=playerData.unit:IsInZone(self.zoneCCA)
--playerData.inbigzone=playerData.unit:IsInZone(self.zoneCCA)
-- Init stuff for this round.
playerData=self:_InitPlayer(playerData)
@ -2047,18 +2050,93 @@ function AIRBOSS:_InitPlayer(playerData)
playerData.bolter=false
playerData.boltered=false
playerData.landed=false
playerData.holding=nil
playerData.Tlso=timer.getTime()
return playerData
end
--- Holding.
-- @param #AIRBOSS self
-- @param #AIRBOSS.PlayerData playerData Player data.
function AIRBOSS:_Holding(playerData)
local unit=playerData.unit
local flight=self:_GetFlightFromGroupInQueue(playerData.group, self.flights)
local stack=flight.flag:Get()
local alt, c1, c2=self:_GetMarshalAltitude(stack)
-- Create a holding zone depending on recovery case.
local zoneHolding --Core.Zone#ZONE
if self.case==1 then
-- CASE I
-- Zone 2.5 NM port of carrier with a radius of 3 NM (holding pattern should be < 5 NM).
zoneHolding=ZONE_UNIT:New("CASE I Holding Zone", self.carrier, UTILS.NMToMeters(3), {dx=0, dy=-UTILS.NMToMeters(2.5), relative_to_unit=true})
else
-- CASE II/II
local hdg=self.carrier:GetHeading()
-- Create an array of a square!
local p={}
p[1]=c1:GetVec2()
p[2]=c2:GetVec2()
p[3]=c2:Translate(UTILS.NMToMeters(5), hdg-90):GetVec2()
p[4]=c1:Translate(UTILS.NMToMeters(5), hdg-90):GetVec2()
zoneHolding=ZONE_POLYGON_BASE:New("CASE II/III Holding Zone", p)
end
--if bla then
-- zoneHolding:SmokeZone(SMOKECOLOR.Green)
-- bla=false
--end
-- Check if player is in holding zone.
local inholdingzone=unit:IsInZone(zoneHolding)
-- Different cases
if playerData.holding==true then
-- Player was in holding zone last time we checked.
if inholdingzone then
-- Player is still in holding zone.
self:I("Player is still in the holding zone. Good job.")
else
-- Player left the holding zone.
self:I("Player just left the holding zone. Come back!")
end
elseif playerData.holding==false then
-- Player left holding zone
if inholdingzone then
-- Player is back in the holding zone.
self:I("Player is back in the holding zone after leaving it.")
else
-- Player is still outside the holding zone.
self:I("Player still outside the holding zone. What are you doing man?!")
end
elseif playerData.holding==nil then
-- Player never entered the holding zone
if inholdingzone then
-- Player arrived in holding zone.
playerData.holding=true
self:I("Player entered the holding zone for the first time.")
else
-- Player did not yet arrive in holding zone.
self:I("Waiting for player to arrive in the holding zone.")
end
end
end
--- Commence approach.
-- @param #AIRBOSS self
-- @param #AIRBOSS.PlayerData playerData Player data.
function AIRBOSS:_Commencing(playerData)
local text="Commencing."
-- Initialize player data for new approach.
self:_InitPlayer(playerData)
@ -2071,6 +2149,9 @@ function AIRBOSS:_Commencing(playerData)
playerData.step=AIRBOSS.PatternStep.DESCENT4K
end
local text="Commencing."
-- Message to player.
self:_SendMessageToPlayer(text, 10, playerData)
end
@ -2600,10 +2681,6 @@ function AIRBOSS:_Groove(playerData)
if rho<=RXX and playerData.step==AIRBOSS.PatternStep.GROOVE_XX then
-- LSO "Call the ball" call.
-- TODO: take this out.
--self:_SendMessageToPlayer("Call the ball.", 5, playerData)
-- LSO radio call.
self:RadioTransmission(self.LSOradio, self.radiocall.CALLTHEBALL)
playerData.Tlso=timer.getTime()
@ -2616,10 +2693,6 @@ function AIRBOSS:_Groove(playerData)
elseif rho<=RRB and playerData.step==AIRBOSS.PatternStep.GROOVE_RB then
-- Pilot: "Roger ball" call.
-- 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
@ -2659,10 +2732,7 @@ function AIRBOSS:_Groove(playerData)
-- Let's see..
if waveoff then
-- Wave off player.
--self:_SendMessageToPlayer("Wave off!", 10, playerData)
-- LSO radio call.
-- LSO Wave off!
self:RadioTransmission(self.LSOradio, self.radiocall.WAVEOFF)
playerData.Tlso=timer.getTime()
@ -2751,8 +2821,9 @@ function AIRBOSS:_CheckWaveOff(glideslopeError, lineupError, AoA)
end
-- Too slow or too fast?
-- TODO: Only apply for TOPGUN graduate skill level or at least not for Flight Student level.
if AoA<6.9 or AoA>9.3 then
self:I(self.lid.."DEACTIVE! Wave off due to AoA<6.9 or AoA>9.3!")
self:I(self.lid.."INACTIVE! Wave off due to AoA<6.9 or AoA>9.3!")
--waveoff=true
end
@ -2764,19 +2835,19 @@ end
--- Trapped?
-- @param #AIRBOSS self
-- @param #AIRBOSS.PlayerData playerData Player data table.
-- @param Core.Point#COORDINATE pos Position of aircraft on landing event.
function AIRBOSS:_Trapped(playerData, pos)
-- @param #number X Distance in meters wrt carrier position where player landed.
function AIRBOSS:_Trapped(playerData, X)
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)
--local X, Z, rho, phi = self:_GetDistances(pos)
if playerData.unit:InAir()==false then
-- Seems we have successfully landed.
-- Little offset for the exact wire positions.
local wdx=11
local wdx=0
-- Which wire was caught?
local wire
@ -2864,7 +2935,7 @@ function AIRBOSS:_DetailedPlayerStatus(playerData)
text=text..string.format("\nGS Error = %.1f° (glide slope)", glideslope)
end
-- Wind
-- Wind (for debugging).
--text=text..string.format("Wind Vx=%.1f Vy=%.1f Vz=%.1f\n", wind.x, wind.y, wind.z)
MESSAGE:New(text, 1, nil , true):ToClient(playerData.client)
@ -3761,7 +3832,7 @@ function AIRBOSS:RadioTransmission(radio, call, loud, delay)
end
end
--- Send message to playe client.
--- Send message to player client.
-- @param #AIRBOSS self
-- @param #string message The message to send.
-- @param #number duration Display message duration.
@ -3771,21 +3842,18 @@ end
-- @param #number delay Delay in seconds, before the message is send.
function AIRBOSS:_SendMessageToPlayer(message, duration, playerData, clear, sender, delay)
if message then
if playerData and message then
delay=delay or 0
sender=sender or self.alias
local text=string.format("%s, %s, %s", sender, playerData.callsign, message)
-- Format message.
local text=string.format("%s, %s", playerData.callsign, message)
self:I(self.lid..text)
if delay>0 then
if delay and delay>0 then
SCHEDULER:New(nil, self._SendMessageToPlayer, {self, message, duration, playerData, clear, sender}, delay)
else
if playerData.client then
MESSAGE:New(text, duration, nil, clear):ToClient(playerData.client)
MESSAGE:New(text, duration, sender, clear):ToClient(playerData.client)
end
--MESSAGE:New(text, duration, nil, clear):ToAll()
end
end
@ -3888,6 +3956,20 @@ function AIRBOSS:_GetPlayerUnitAndName(_unitName)
return nil,nil
end
--- Get carrier coaltion.
-- @param #AIRBOSS self
-- @return #number Coalition side of carrier.
function AIRBOSS:GetCoalition()
return self.carrier:GetCoalition()
end
--- Get carrier coordinate.
-- @param #AIRBOSS self
-- @return Core.Point#COORDINATE Carrier coordinate.
function AIRBOSS:GetCoordinate()
return self.carrier:GetCoordinate()
end
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Menu Functions
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -3933,7 +4015,7 @@ function AIRBOSS:_AddF10Commands(_unitName)
local _skillPath = missionCommands.addSubMenuForGroup(_gid, "Skill Level", _rootPath)
-- F10/Airboss/<Carrier Name>/My Settings/Kneeboard
--local _kneeboardPath = missionCommands.addSubMenuForGroup(_gid, "Kneeboard", _rootPath)
local _kneeboardPath = missionCommands.addSubMenuForGroup(_gid, "Kneeboard", _rootPath)
-- F10/Airboss/<Carrier Name>/LSO Grades/
missionCommands.addCommandForGroup(_gid, "Greenie Board", _statsPath, self._DisplayScoreBoard, self, _unitName)
@ -3944,18 +4026,18 @@ function AIRBOSS:_AddF10Commands(_unitName)
missionCommands.addCommandForGroup(_gid, "Flight Student", _skillPath, self._SetDifficulty, self, playername, AIRBOSS.Difficulty.EASY)
missionCommands.addCommandForGroup(_gid, "Naval Aviator", _skillPath, self._SetDifficulty, self, playername, AIRBOSS.Difficulty.NORMAL)
missionCommands.addCommandForGroup(_gid, "TOPGUN Graduate", _skillPath, self._SetDifficulty, self, playername, AIRBOSS.Difficulty.HARD)
missionCommands.addCommandForGroup(_gid, "Attitude Monitor ON/OFF", _skillPath, self._AttitudeMonitor, self, playername)
-- F10/Airboss/<Carrier Name>/Kneeboard
missionCommands.addCommandForGroup(_gid, "Attitude Monitor ON/OFF", _kneeboardPath, self._AttitudeMonitor, self, playername)
missionCommands.addCommandForGroup(_gid, "Weather Report", _kneeboardPath, self._DisplayCarrierWeather, self, _unitName)
missionCommands.addCommandForGroup(_gid, "Carrier Info", _kneeboardPath, self._DisplayCarrierInfo, self, _unitName)
-- F10/Airboss/<Carrier Name>/
missionCommands.addCommandForGroup(_gid, "Weather Report", _rootPath, self._DisplayCarrierWeather, self, _unitName)
missionCommands.addCommandForGroup(_gid, "Carrier Info", _rootPath, self._DisplayCarrierInfo, self, _unitName)
missionCommands.addCommandForGroup(_gid, "Request Marshal", _rootPath, self._RequestMarshal, self, _unitName)
missionCommands.addCommandForGroup(_gid, "Request Straight-In", _rootPath, self._RequestStraightIn, self, _unitName)
-- TODO: request straight in approach
-- TODO: request refuelling.
--
missionCommands.addCommandForGroup(_gid, "Request Marshal?", _rootPath, self._RequestMarshal, self, _unitName)
missionCommands.addCommandForGroup(_gid, "Commencing!", _rootPath, self._RequestStraightIn, self, _unitName)
--TODO: request refulling if recovery tanker set! make refuelling queue. add refuelling step.
end
else
@ -3981,7 +4063,7 @@ function AIRBOSS:_RequestStraightIn(_unitName)
local playerData=self.players[_playername] --#AIRBOSS.PlayerData
if playerData then
self:_MarshalPlayer(_unit:GetGroup())
playerData.step=AIRBOSS.PatternStep.COMMENCING
end
end
end
@ -4224,17 +4306,15 @@ function AIRBOSS:_DisplayCarrierWeather(_unitname)
local WD=string.format('%03d°', Wd)
local Ts=string.format("%d°C",T)
local hPa2inHg=0.0295299830714
local hPa2mmHg=0.7500615613030
local settings=_DATABASE:GetPlayerSettings(playername) or _SETTINGS --Core.Settings#SETTINGS
local tT=string.format("%d°C",T)
local tW=string.format("%.1f m/s", Ws)
local tP=string.format("%.1f mmHg", P*hPa2mmHg)
local tP=string.format("%.1f mmHg", UTILS.hPa2mmHg(P))
if settings:IsImperial() then
tT=string.format("%d°F", UTILS.CelciusToFarenheit(T))
tW=string.format("%.1f knots", UTILS.MpsToKnots(Ws))
tP=string.format("%.2f inHg", P*hPa2inHg)
tP=string.format("%.2f inHg", UTILS.hPa2inHg(P))
end
-- Report text.

View File

@ -15,7 +15,7 @@
--
-- ### Author: **funkyfranky**
--
-- @module Ops.CarrierTanker
-- @module Ops.RecoveryTanker
-- @image MOOSE.JPG
--- RECOVERYTANKER class.
@ -36,13 +36,13 @@
-- @field #number lowfuel Low fuel threshold in percent.
-- @extends Core.Fsm#FSM
--- Carrier Tanker.
--- Recovery Tanker.
--
-- ===
--
-- ![Banner Image](..\Presentations\RECOVERYTANKER\RecoveryTanker_Main.jpg)
--
-- # Carrier Tanker
-- # Recovery Tanker
--
-- bla bla
--
@ -129,11 +129,11 @@ function RECOVERYTANKER:New(carrierunit, tankergroupname)
self:AddTransition("Running", "Stop", "Stopped")
--- Triggers the FSM event "Start" that starts the carrier tanker. Initializes parameters and starts event handlers.
--- Triggers the FSM event "Start" that starts the recovery tanker. Initializes parameters and starts event handlers.
-- @function [parent=#RECOVERYTANKER] Start
-- @param #RECOVERYTANKER self
--- Triggers the FSM event "Start" that starts the carrier tanker after a delay. Initializes parameters and starts event handlers.
--- Triggers the FSM event "Start" that starts the recovery tanker after a delay. Initializes parameters and starts event handlers.
-- @function [parent=#RECOVERYTANKER] __Start
-- @param #RECOVERYTANKER self
-- @param #number delay Delay in seconds.
@ -147,11 +147,11 @@ function RECOVERYTANKER:New(carrierunit, tankergroupname)
-- @param #RECOVERYTANKER self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "Stop" that stops the carrier tanker. Event handlers are stopped.
--- Triggers the FSM event "Stop" that stops the recovery tanker. Event handlers are stopped.
-- @function [parent=#RECOVERYTANKER] Stop
-- @param #RECOVERYTANKER self
--- Triggers the FSM event "Stop" that stops the carrier tanker after a delay. Event handlers are stopped.
--- Triggers the FSM event "Stop" that stops the recovery tanker after a delay. Event handlers are stopped.
-- @function [parent=#RECOVERYTANKER] __Stop
-- @param #RECOVERYTANKER self
-- @param #number delay Delay in seconds.
@ -280,7 +280,7 @@ end
function RECOVERYTANKER:onafterStart(From, Event, To)
-- Info on start.
self:I(string.format("Starting Carrier Tanker v%s for carrier unit %s of type %s for tanker group %s.", RECOVERYTANKER.version, self.carrier:GetName(), self.carriertype, self.tankergroupname))
self:I(string.format("Starting Recovery Tanker v%s for carrier unit %s of type %s for tanker group %s.", RECOVERYTANKER.version, self.carrier:GetName(), self.carriertype, self.tankergroupname))
-- Handle events.
self:HandleEvent(EVENTS.EngineShutdown)
@ -429,7 +429,7 @@ end
-- EVENT functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Event handler for engine shutdown of carrier tanker.
--- Event handler for engine shutdown of recovery tanker.
-- Respawn tanker group once it landed because it was out of fuel.
-- @param #RECOVERYTANKER self
-- @param Core.Event#EVENTDATA EventData Event data.
@ -445,7 +445,7 @@ function RECOVERYTANKER:OnEventEngineShutdown(EventData)
if groupname:match(self.tankergroupname) then
-- Debug info.
self:I(string.format("CARIERTANKER: Respawning group %s.", group:GetName()))
self:I(string.format("Respawning recovery tanker group %s.", group:GetName()))
-- Respawn tanker.
self.tanker=group:RespawnAtCurrentAirbase()

View File

@ -294,6 +294,20 @@ UTILS.CelciusToFarenheit = function( Celcius )
return Celcius * 9/5 + 32
end
--- Convert pressure from hecto Pascal (hPa) to inches of mercury (inHg).
-- @param #number hPa Pressure in hPa.
-- @return #number Pressure in inHg.
UTILS.hPa2inHg = function( hPa )
return hPa * 0.0295299830714
end
--- Convert pressure from hecto Pascal (hPa) to millimeters of mercury (mmHg).
-- @param #number hPa Pressure in hPa.
-- @return #number Pressure in mmHg.
UTILS.hPa2mmHg = function( hPa )
return hPa * 0.7500615613030
end
--[[acc: