mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
AIRBOSS v0.9.7
This commit is contained in:
parent
d01b55c790
commit
412d9e7a82
@ -57,11 +57,11 @@
|
|||||||
--
|
--
|
||||||
-- ## IMPORTANT
|
-- ## IMPORTANT
|
||||||
--
|
--
|
||||||
-- Some important restrictions of DCS you should be aware of:
|
-- Some important restrictions (of DCS) you should be aware of:
|
||||||
--
|
--
|
||||||
-- * Each player slot (client) should be in a separate group as DCS does only allow for sending messages to groups and not individual units.
|
-- * Each player slot (client) should be in a separate group as DCS does only allow for sending messages to groups and not individual units.
|
||||||
-- * Players are identified by their player name. Ensure that no two player have the same name, e.g. "New Callsign", as this will lead to unexpected results.
|
-- * Players are identified by their player name. Hence, ensure that no two player have the same name, e.g. "New Callsign", as this will lead to unexpected results.
|
||||||
-- * The modex (tail number) of an aircraft should be changed dynamically in the mission by a player. Unfortunately, there is no way to get this information via scripting API functions.
|
-- * The modex (tail number) of an aircraft should **not** be changed dynamically in the mission by a player. Unfortunately, there is no way to get this information via scripting API functions.
|
||||||
-- * The A-4E-C mod needs *easy comms* activated to interact with the F10 radio menu.
|
-- * The A-4E-C mod needs *easy comms* activated to interact with the F10 radio menu.
|
||||||
--
|
--
|
||||||
-- ## Youtube Videos
|
-- ## Youtube Videos
|
||||||
@ -70,6 +70,7 @@
|
|||||||
--
|
--
|
||||||
-- * [[MOOSE] Airboss - Groove Testing (WIP)](https://www.youtube.com/watch?v=94KHQxxX3UI)
|
-- * [[MOOSE] Airboss - Groove Testing (WIP)](https://www.youtube.com/watch?v=94KHQxxX3UI)
|
||||||
-- * [[MOOSE] Airboss - Groove Test A-4E Community Mod](https://www.youtube.com/watch?v=ZbjD7FHiaHo)
|
-- * [[MOOSE] Airboss - Groove Test A-4E Community Mod](https://www.youtube.com/watch?v=ZbjD7FHiaHo)
|
||||||
|
-- * [[MOOSE] Airboss - Groove Test: On-the-fly LSO Grading](https://www.youtube.com/watch?v=Xgs1hwDcPyM)
|
||||||
--
|
--
|
||||||
-- Lex explaining Boat Ops:
|
-- Lex explaining Boat Ops:
|
||||||
--
|
--
|
||||||
@ -84,7 +85,6 @@
|
|||||||
--
|
--
|
||||||
-- ### 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?
|
|
||||||
-- * What is the next step after a pattern wave off during Case II or III recovery? A: Go back to start!
|
-- * 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?
|
||||||
@ -199,6 +199,8 @@
|
|||||||
-- @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.
|
-- @field #boolean despawnshutdown Despawn group after engine shutdown.
|
||||||
|
-- @field #number Tbeacon Last time the beacons were refeshed.
|
||||||
|
-- @field #number dTbeacon Time interval to refresh the beacons. Default 5 minutes.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- Be the boss!
|
--- Be the boss!
|
||||||
@ -333,13 +335,14 @@
|
|||||||
-- ### Spinning
|
-- ### Spinning
|
||||||
--
|
--
|
||||||
-- If the pattern is full, players can go into the spinning pattern. This step is only allowed, if the player is in the pattern and his next step
|
-- If the pattern is full, players can go into the spinning pattern. This step is only allowed, if the player is in the pattern and his next step
|
||||||
-- is initial, break entry, early/late break.
|
-- is initial, break entry, early/late break. At this point, the player should climb to 1200 ft a fly on the port side of the boat to go back to the initial again.
|
||||||
--
|
--
|
||||||
-- If a player is in the spin pattern, flights in the Marshal queue should hold their altitude and are not allowed into the pattern until the spinning aircraft
|
-- If a player is in the spin pattern, flights in the Marshal queue should hold their altitude and are not allowed into the pattern until the spinning aircraft
|
||||||
-- proceeds.
|
-- proceeds.
|
||||||
--
|
--
|
||||||
|
-- Once the player reaches a point 100 meters behind the boat and at least 1 NM port, his step is set to "Initial" and he can resume the normal pattern approach.
|
||||||
--
|
--
|
||||||
-- If a player
|
-- If necessary, the player can call "Spinning" again when in the above mentioned steps.
|
||||||
--
|
--
|
||||||
-- ### [Reset My Status]
|
-- ### [Reset My Status]
|
||||||
--
|
--
|
||||||
@ -395,7 +398,7 @@
|
|||||||
--
|
--
|
||||||
-- ### LSO Radio Check
|
-- ### LSO Radio Check
|
||||||
--
|
--
|
||||||
-- LSO will transmit a short message on his radio frequency. See @{#AIRBOSS.SetLSORadio}.
|
-- LSO will transmit a short message on his radio frequency. See @{#AIRBOSS.SetLSORadio}. Note that in the A-4E you will not hear the message unless you are in the pattern.
|
||||||
--
|
--
|
||||||
-- ### Marshal Radio Check
|
-- ### Marshal Radio Check
|
||||||
--
|
--
|
||||||
@ -643,16 +646,18 @@
|
|||||||
--
|
--
|
||||||
-- airbossStennis:AddRecoveryWindow("8:30", "9:30", 1, nil, true, 20)
|
-- airbossStennis:AddRecoveryWindow("8:30", "9:30", 1, nil, true, 20)
|
||||||
--
|
--
|
||||||
-- Setting the fifth parameter to *true* enables the automatic turning into the wind. The sixth parameter (here 20) specifies the speed in knots the carrier will go so that to total wind above the deck.
|
-- Setting the fifth parameter to *true* enables the automatic turning into the wind. The sixth parameter (here 20) specifies the speed in knots the carrier will go so that to total wind above the deck
|
||||||
-- For example, if the is blowing with 5 knots, the carrier will go 15 knots so that it adds up to the specified 20 knots.
|
-- corresponds to this wind speed. For example, if the is blowing with 5 knots, the carrier will go 15 knots so that the total velocity adds up to the specified 20 knots for the pilot.
|
||||||
--
|
--
|
||||||
-- The carrier will steam into the wind for as long as the recovery window is open. The distance up to which possible collisions are detected can be set by the @{#AIRBOSS.SetCollisionDistance} function.
|
-- The carrier will steam into the wind for as long as the recovery window is open. The distance up to which possible collisions are detected can be set by the @{#AIRBOSS.SetCollisionDistance} function.
|
||||||
--
|
--
|
||||||
-- However, the airboss scans the type of the surface up to 5 NM in the direction of movement of the carrier. If he detects anything but deep water, he will stop the current course and head back to
|
-- However, the AIRBOSS scans the type of the surface up to 5 NM in the direction of movement of the carrier. If he detects anything but deep water, he will stop the current course and head back to
|
||||||
-- the point where he initially turned into the wind.
|
-- the point where he initially turned into the wind.
|
||||||
--
|
--
|
||||||
-- The same holds true after the recovery window closes. The carrier will head back to the place where he left its assigned route and resume the path to the next waypoint defined in the mission editor.
|
-- The same holds true after the recovery window closes. The carrier will head back to the place where he left its assigned route and resume the path to the next waypoint defined in the mission editor.
|
||||||
--
|
--
|
||||||
|
-- Note that the carrier will only head into the wind, if the wind direction is different by more than 5° from the current heading of the carrier (the angled runway, if any, fis taken into account here).
|
||||||
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- # Persistence of Player Results
|
-- # Persistence of Player Results
|
||||||
@ -991,6 +996,8 @@ AIRBOSS = {
|
|||||||
Tmessage = nil,
|
Tmessage = nil,
|
||||||
soundfolder = nil,
|
soundfolder = nil,
|
||||||
despawnshutdown= nil,
|
despawnshutdown= nil,
|
||||||
|
dTbeacon = nil,
|
||||||
|
Tbeacon = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Aircraft types capable of landing on carrier (human+AI).
|
--- Aircraft types capable of landing on carrier (human+AI).
|
||||||
@ -1637,14 +1644,15 @@ AIRBOSS.Difficulty={
|
|||||||
-- @field #number wire Wire caught.
|
-- @field #number wire Wire caught.
|
||||||
-- @field #number Tgroove Time in the groove in seconds.
|
-- @field #number Tgroove Time in the groove in seconds.
|
||||||
-- @field #number case Recovery case.
|
-- @field #number case Recovery case.
|
||||||
-- @field #string time Mission time.
|
|
||||||
-- @field #string wind Wind speed on deck in knots.
|
-- @field #string wind Wind speed on deck in knots.
|
||||||
-- @field #string airframe Aircraft type name of player.
|
|
||||||
-- @field #string modex Onboard number.
|
-- @field #string modex Onboard number.
|
||||||
|
-- @field #string airframe Aircraft type name of player.
|
||||||
-- @field #string carriertype Carrier type name.
|
-- @field #string carriertype Carrier type name.
|
||||||
-- @field #string carriername Carrier name/alias.
|
-- @field #string carriername Carrier name/alias.
|
||||||
-- @field #string theatre DCS map.
|
-- @field #string theatre DCS map.
|
||||||
-- @field #string date Real live date. Needs **os** to be desanitized.
|
-- @field #string mitime Mission time in hh:mm:ss+d format
|
||||||
|
-- @field #string midate Mission date in yyyy/mm/dd format.
|
||||||
|
-- @field #string osdate Real live date. Needs **os** to be desanitized.
|
||||||
|
|
||||||
--- Checkpoint parameters triggering the next step in the pattern.
|
--- Checkpoint parameters triggering the next step in the pattern.
|
||||||
-- @type AIRBOSS.Checkpoint
|
-- @type AIRBOSS.Checkpoint
|
||||||
@ -1687,7 +1695,6 @@ 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
|
||||||
@ -1727,7 +1734,7 @@ AIRBOSS.MenuF10Root=nil
|
|||||||
|
|
||||||
--- Airboss class version.
|
--- Airboss class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
AIRBOSS.version="0.9.7w"
|
AIRBOSS.version="0.9.7"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@ -1823,6 +1830,10 @@ function AIRBOSS:New(carriername, alias)
|
|||||||
-- Set some string id for output to DCS.log file.
|
-- Set some string id for output to DCS.log file.
|
||||||
self.lid=string.format("AIRBOSS %s | ", carriername)
|
self.lid=string.format("AIRBOSS %s | ", carriername)
|
||||||
|
|
||||||
|
-- Current map.
|
||||||
|
self.theatre=env.mission.theatre
|
||||||
|
self:T2(self.lid..string.format("Theatre = %s.", tostring(self.theatre)))
|
||||||
|
|
||||||
-- Get carrier type.
|
-- Get carrier type.
|
||||||
self.carriertype=self.carrier:GetTypeName()
|
self.carriertype=self.carrier:GetTypeName()
|
||||||
|
|
||||||
@ -1866,6 +1877,9 @@ function AIRBOSS:New(carriername, alias)
|
|||||||
-- Set TACAN to channel 74X.
|
-- Set TACAN to channel 74X.
|
||||||
self:SetTACAN()
|
self:SetTACAN()
|
||||||
|
|
||||||
|
-- Becons are reactivated very 5 min.
|
||||||
|
self:SetBeaconRefresh()
|
||||||
|
|
||||||
-- Set max aircraft in landing pattern. Default 4.
|
-- Set max aircraft in landing pattern. Default 4.
|
||||||
self:SetMaxLandingPattern()
|
self:SetMaxLandingPattern()
|
||||||
|
|
||||||
@ -2678,6 +2692,16 @@ function AIRBOSS:SetICLS(channel, morsecode)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Set beacon (TACAN/ICLS) time refresh interfal in case the beacons die.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
-- @param #number interval Time interval in seconds. Default 300 sec = 5 min.
|
||||||
|
-- @return #AIRBOSS self
|
||||||
|
function AIRBOSS:SetBeaconRefresh(interval)
|
||||||
|
self.dTbeacon=interval or 300
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set LSO radio frequency and modulation. Default frequency is 264 MHz AM.
|
--- Set LSO radio frequency and modulation. Default frequency is 264 MHz AM.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param #number frequency Frequency in MHz. Default 264 MHz.
|
-- @param #number frequency Frequency in MHz. Default 264 MHz.
|
||||||
@ -2927,6 +2951,25 @@ function AIRBOSS:IsPaused()
|
|||||||
return self:is("Paused")
|
return self:is("Paused")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Activate TACAN and ICLS beacons.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
function AIRBOSS:_ActivateBeacons()
|
||||||
|
self:T(self.lid..string.format("Activating Beacons (TACAN=%s, ICLS=%s)", tostring(self.TACANon), tostring(self.ICLSon)))
|
||||||
|
|
||||||
|
-- Activate TACAN.
|
||||||
|
if self.TACANon then
|
||||||
|
self.beacon:ActivateTACAN(self.TACANchannel, self.TACANmode, self.TACANmorse, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Activate ICLS.
|
||||||
|
if self.ICLSon then
|
||||||
|
self.beacon:ActivateICLS(self.ICLSchannel, self.ICLSmorse)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set time stamp.
|
||||||
|
self.Tbeacon=timer.getTime()
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- FSM event functions
|
-- FSM event functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@ -2939,21 +2982,10 @@ end
|
|||||||
function AIRBOSS:onafterStart(From, Event, To)
|
function AIRBOSS:onafterStart(From, Event, To)
|
||||||
|
|
||||||
-- Events are handled my MOOSE.
|
-- Events are handled my MOOSE.
|
||||||
self:I(self.lid..string.format("Starting AIRBOSS v%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 on map %s", AIRBOSS.version, self.carrier:GetName(), self.carriertype, self.theatre))
|
||||||
|
|
||||||
-- Activate TACAN.
|
-- Activate TACAN and ICLS if desired.
|
||||||
if self.TACANon then
|
self:_ActivateBeacons()
|
||||||
self.beacon:ActivateTACAN(self.TACANchannel, self.TACANmode, self.TACANmorse, true)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Current map.
|
|
||||||
self.theatre=env.mission.theatre
|
|
||||||
self:T2(self.lid..string.format("Theatre = %s.", tostring(self.theatre)))
|
|
||||||
|
|
||||||
-- Activate ICLS.
|
|
||||||
if self.ICLSon then
|
|
||||||
self.beacon:ActivateICLS(self.ICLSchannel, self.ICLSmorse)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Schedule radio queue checks.
|
-- Schedule radio queue checks.
|
||||||
self.RQLid=self.radiotimer:Schedule(self, self._CheckRadioQueue, {self.RQLSO, "LSO"}, 1, 0.01)
|
self.RQLid=self.radiotimer:Schedule(self, self._CheckRadioQueue, {self.RQLSO, "LSO"}, 1, 0.01)
|
||||||
@ -3073,6 +3105,11 @@ function AIRBOSS:onafterStatus(From, Event, To)
|
|||||||
self.Tqueue=time
|
self.Tqueue=time
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- (Re-)activate TACAN and ICLS channels.
|
||||||
|
if time-self.Tbeacon>self.dTbeacon then
|
||||||
|
self:_ActivateBeacons()
|
||||||
|
end
|
||||||
|
|
||||||
-- Check player status.
|
-- Check player status.
|
||||||
self:_CheckPlayerStatus()
|
self:_CheckPlayerStatus()
|
||||||
|
|
||||||
@ -3145,6 +3182,24 @@ end
|
|||||||
-- @param #AIRBOSS.PlayerData player Player data.
|
-- @param #AIRBOSS.PlayerData player Player data.
|
||||||
function AIRBOSS:_CheckPlayerPatternDistance(player)
|
function AIRBOSS:_CheckPlayerPatternDistance(player)
|
||||||
|
|
||||||
|
-- Check if player is too close to another aircraft in the pattern.
|
||||||
|
-- TODO: At which steps is the really necessary. Case II/III?
|
||||||
|
if player.step==AIRBOSS.PatternStep.INITIAL or
|
||||||
|
player.step==AIRBOSS.PatternStep.BREAKENTRY or
|
||||||
|
player.step==AIRBOSS.PatternStep.EARLYBREAK or
|
||||||
|
player.step==AIRBOSS.PatternStep.LATEBREAK or
|
||||||
|
player.step==AIRBOSS.PatternStep.ABEAM or
|
||||||
|
player.step==AIRBOSS.PatternStep.GROOVE_XX or
|
||||||
|
player.step==AIRBOSS.PatternStep.GROOVE_IM then
|
||||||
|
|
||||||
|
-- Right step but not implemented.
|
||||||
|
return
|
||||||
|
|
||||||
|
else
|
||||||
|
-- Wrong step - no check performed.
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Nothing to do since we check only in the pattern.
|
-- Nothing to do since we check only in the pattern.
|
||||||
if #self.Qpattern==0 then
|
if #self.Qpattern==0 then
|
||||||
return
|
return
|
||||||
@ -3344,16 +3399,33 @@ function AIRBOSS:_CheckRecoveryTimes()
|
|||||||
-- Check if time is less than 5 minutes.
|
-- Check if time is less than 5 minutes.
|
||||||
if nextwindow.WIND and nextwindow.START-time<5*60 and not self.turnintowind then
|
if nextwindow.WIND and nextwindow.START-time<5*60 and not self.turnintowind then
|
||||||
|
|
||||||
-- Calculate distance we travel into the wind.
|
-- Check that wind is blowing from a direction > 5° different from the current heading.
|
||||||
local t=nextwindow.STOP-nextwindow.START
|
local hdg=self:GetHeading()
|
||||||
local v=UTILS.KnotsToMps(nextwindow.SPEED)
|
local wind=self:GetHeadingIntoWind()
|
||||||
local s=v*t
|
local delta=self:_GetDeltaHeading(hdg, wind)
|
||||||
|
local uturn=delta>5
|
||||||
|
|
||||||
-- Distance in NM to go + 1 NM safety.
|
-- Check if wind is actually blowing (0.1 m/s = 0.36 km/h = 0.2 knots)
|
||||||
local d=UTILS.MetersToNM(s)+1
|
local _,vwind=self:GetWind()
|
||||||
|
if vwind<0.1 then
|
||||||
|
uturn=false
|
||||||
|
end
|
||||||
|
|
||||||
|
--Debug info
|
||||||
|
self:T(self.lid..string.format("Heading=%03d°, Wind=%03d° %.1f kts, Delta=%03d° ==> U-turn=%s", hdg, wind,UTILS.MpsToKnots(vwind), delta, tostring(uturn)))
|
||||||
|
|
||||||
|
|
||||||
|
-- Time into the wind + the 5 min early.
|
||||||
|
local t=nextwindow.STOP-nextwindow.START+300
|
||||||
|
local v=UTILS.KnotsToMps(nextwindow.SPEED)
|
||||||
|
|
||||||
|
-- Check that we do not go above max possible speed.
|
||||||
|
local vmax=self.carrier:GetSpeedMax()
|
||||||
|
v=math.min(v,vmax)
|
||||||
|
|
||||||
-- Route carrier into the wind. Sets self.turnintowind=true
|
-- Route carrier into the wind. Sets self.turnintowind=true
|
||||||
self:CarrierTurnIntoWind(t, v)
|
self:CarrierTurnIntoWind(t, v, uturn)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set current recovery window.
|
-- Set current recovery window.
|
||||||
@ -4913,7 +4985,7 @@ function AIRBOSS:_GetMarshalAltitude(stack, case)
|
|||||||
-- For CCW pattern: p1 further astern than p2.
|
-- For CCW pattern: p1 further astern than p2.
|
||||||
|
|
||||||
-- Length of the race track pattern.
|
-- Length of the race track pattern.
|
||||||
local l=UTILS.NMToMeters(7)
|
local l=UTILS.NMToMeters(10)
|
||||||
|
|
||||||
-- First point of race track pattern.
|
-- First point of race track pattern.
|
||||||
p1=Carrier:Translate(Dist+l, radial)
|
p1=Carrier:Translate(Dist+l, radial)
|
||||||
@ -5055,11 +5127,8 @@ function AIRBOSS:_AddMarshalGroup(flight, stack)
|
|||||||
|
|
||||||
-- If the carrier is supposed to turn into the wind, we take the wind coordinate.
|
-- If the carrier is supposed to turn into the wind, we take the wind coordinate.
|
||||||
if self.recoverywindow and self.recoverywindow.WIND then
|
if self.recoverywindow and self.recoverywindow.WIND then
|
||||||
local _,vwind=self:GetCoordinate():GetWind(50)
|
|
||||||
if vwind>0.1 then
|
|
||||||
brc=self:GetBRCintoWind()
|
brc=self:GetBRCintoWind()
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
-- Get charlie time estimate.
|
-- Get charlie time estimate.
|
||||||
flight.Tcharlie=self:_GetCharlieTime(flight)
|
flight.Tcharlie=self:_GetCharlieTime(flight)
|
||||||
@ -5521,7 +5590,6 @@ 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
|
||||||
@ -5549,6 +5617,7 @@ function AIRBOSS:_NewPlayer(unitname)
|
|||||||
|
|
||||||
if playerunit and playername then
|
if playerunit and playername then
|
||||||
|
|
||||||
|
-- Get group.
|
||||||
local group=playerunit:GetGroup()
|
local group=playerunit:GetGroup()
|
||||||
|
|
||||||
-- Player data.
|
-- Player data.
|
||||||
@ -5557,6 +5626,9 @@ function AIRBOSS:_NewPlayer(unitname)
|
|||||||
-- Create a flight group for the player.
|
-- Create a flight group for the player.
|
||||||
playerData=self:_CreateFlightGroup(group)
|
playerData=self:_CreateFlightGroup(group)
|
||||||
|
|
||||||
|
-- Nil check.
|
||||||
|
if playerData then
|
||||||
|
|
||||||
-- Player unit, client and callsign.
|
-- Player unit, client and callsign.
|
||||||
playerData.unit = playerunit
|
playerData.unit = playerunit
|
||||||
playerData.name = playername
|
playerData.name = playername
|
||||||
@ -5596,6 +5668,8 @@ function AIRBOSS:_NewPlayer(unitname)
|
|||||||
-- Welcome player message.
|
-- Welcome player message.
|
||||||
self:MessageToPlayer(playerData, string.format("Welcome, %s %s!", playerData.difficulty, playerData.name), string.format("AIRBOSS %s", self.alias), "", 5)
|
self:MessageToPlayer(playerData, string.format("Welcome, %s %s!", playerData.difficulty, playerData.name), string.format("AIRBOSS %s", self.alias), "", 5)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
-- Return player data table.
|
-- Return player data table.
|
||||||
return playerData
|
return playerData
|
||||||
end
|
end
|
||||||
@ -5633,8 +5707,8 @@ function AIRBOSS:_InitPlayer(playerData, step)
|
|||||||
self:MessageToPlayer(playerData, "Group name contains \"Groove\". Happy groove testing.")
|
self:MessageToPlayer(playerData, "Group name contains \"Groove\". Happy groove testing.")
|
||||||
playerData.attitudemonitor=true
|
playerData.attitudemonitor=true
|
||||||
playerData.step=AIRBOSS.PatternStep.FINAL
|
playerData.step=AIRBOSS.PatternStep.FINAL
|
||||||
--table.insert(self.Qpattern, playerData)
|
|
||||||
self:_AddFlightToPatternQueue(playerData)
|
self:_AddFlightToPatternQueue(playerData)
|
||||||
|
self.dTstatus=0.1
|
||||||
end
|
end
|
||||||
|
|
||||||
return playerData
|
return playerData
|
||||||
@ -6084,6 +6158,7 @@ function AIRBOSS:_RemoveFlight(flight, completely)
|
|||||||
self:_RemoveFlightFromMarshalQueue(flight, true)
|
self:_RemoveFlightFromMarshalQueue(flight, true)
|
||||||
self:_RemoveFlightFromQueue(self.Qpattern, flight)
|
self:_RemoveFlightFromQueue(self.Qpattern, flight)
|
||||||
self:_RemoveFlightFromQueue(self.Qwaiting, flight)
|
self:_RemoveFlightFromQueue(self.Qwaiting, flight)
|
||||||
|
self:_RemoveFlightFromQueue(self.Qspinning, flight)
|
||||||
|
|
||||||
-- Check if player or AI
|
-- Check if player or AI
|
||||||
if flight.ai then
|
if flight.ai then
|
||||||
@ -6118,6 +6193,8 @@ function AIRBOSS:_RemoveFlight(flight, completely)
|
|||||||
-- Also set this for the section members as they are in the same boat.
|
-- Also set this for the section members as they are in the same boat.
|
||||||
for _,sectionmember in pairs(flight.section) do
|
for _,sectionmember in pairs(flight.section) do
|
||||||
self:_SetPlayerStep(sectionmember, AIRBOSS.PatternStep.UNDEFINED)
|
self:_SetPlayerStep(sectionmember, AIRBOSS.PatternStep.UNDEFINED)
|
||||||
|
-- Also remove section member in case they are in the spinning queue.
|
||||||
|
self:_RemoveFlightFromQueue(self.Qspinning, sectionmember)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- What if flight is member of a section. His status is now undefined. Should he be removed from the section?
|
-- What if flight is member of a section. His status is now undefined. Should he be removed from the section?
|
||||||
@ -6157,17 +6234,8 @@ function AIRBOSS:_CheckPlayerStatus()
|
|||||||
self:_AttitudeMonitor(playerData)
|
self:_AttitudeMonitor(playerData)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check if player is too close to another aircraft in the pattern.
|
-- Check distance to other flights.
|
||||||
-- TODO: At which steps is the really necessary. Case II/III?
|
self:_CheckPlayerPatternDistance(playerData)
|
||||||
if playerData.step==AIRBOSS.PatternStep.INITIAL or
|
|
||||||
playerData.step==AIRBOSS.PatternStep.BREAKENTRY or
|
|
||||||
playerData.step==AIRBOSS.PatternStep.EARLYBREAK or
|
|
||||||
playerData.step==AIRBOSS.PatternStep.LATEBREAK or
|
|
||||||
playerData.step==AIRBOSS.PatternStep.ABEAM or
|
|
||||||
playerData.step==AIRBOSS.PatternStep.GROOVE_XX or
|
|
||||||
playerData.step==AIRBOSS.PatternStep.GROOVE_IM then
|
|
||||||
--self:_CheckPlayerPatternDistance(playerData)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Foul deck check.
|
-- Foul deck check.
|
||||||
self:_CheckFoulDeck(playerData)
|
self:_CheckFoulDeck(playerData)
|
||||||
@ -6379,6 +6447,40 @@ function AIRBOSS:_CheckMissedStepOnEntry(playerData)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set time in the groove for player.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
-- @param #AIRBOSS.PlayerData playerData Player data.
|
||||||
|
function AIRBOSS:_SetTimeInGroove(playerData)
|
||||||
|
|
||||||
|
-- Get time in the groove.
|
||||||
|
local gdataX0=playerData.groove.X0 --#AIRBOSS.GrooveData
|
||||||
|
if gdataX0 then
|
||||||
|
playerData.Tgroove=timer.getTime()-gdataX0.TGroove
|
||||||
|
else
|
||||||
|
playerData.Tgroove=9999
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get time in the groove of player.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
-- @param #AIRBOSS.PlayerData playerData Player data.
|
||||||
|
-- @return #number Player's time in groove in seconds.
|
||||||
|
function AIRBOSS:_GetTimeInGroove(playerData)
|
||||||
|
|
||||||
|
local Tgroove=999
|
||||||
|
|
||||||
|
-- Get time in the groove.
|
||||||
|
local gdataX0=playerData.groove.X0 --#AIRBOSS.GrooveData
|
||||||
|
if gdataX0 then
|
||||||
|
Tgroove=timer.getTime()-gdataX0.TGroove
|
||||||
|
end
|
||||||
|
|
||||||
|
return Tgroove
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- EVENT functions
|
-- EVENT functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@ -6544,13 +6646,13 @@ function AIRBOSS:OnEventLand(EventData)
|
|||||||
coord:SmokeGreen()
|
coord:SmokeGreen()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get time in the groove.
|
-- Set time in the groove of player.
|
||||||
local gdataX0=playerData.groove.X0 --#AIRBOSS.GrooveData
|
self:_SetTimeInGroove(playerData)
|
||||||
if gdataX0 then
|
|
||||||
playerData.Tgroove=timer.getTime()-gdataX0.TGroove
|
-- Debug text.
|
||||||
else
|
local text=string.format("Player %s AC type %s landed at dist=%.1f m. Tgroove=%.1f sec.", playerData.name, playerData.actype, dist, self:_GetTimeInGroove(playerData))
|
||||||
playerData.Tgroove=999
|
text=text..string.format(" X=%.1f m, Z=%.1f m, rho=%.1f m.", X, Z, rho)
|
||||||
end
|
self:T(self.lid..text)
|
||||||
|
|
||||||
-- Check carrier type.
|
-- Check carrier type.
|
||||||
if self.carriertype==AIRBOSS.CarrierType.TARAWA then
|
if self.carriertype==AIRBOSS.CarrierType.TARAWA then
|
||||||
@ -6563,23 +6665,8 @@ function AIRBOSS:OnEventLand(EventData)
|
|||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
-- Get wire. We additionally shift the landing coord back because landing event for players is unfortunately delayed.
|
-- Next step undefined until we know more.
|
||||||
local wire=self:_GetWire(coord, 75)
|
self:_SetPlayerStep(playerData, AIRBOSS.PatternStep.UNDEFINED)
|
||||||
|
|
||||||
-- No wire ==> Bolter, Bolter radio call.
|
|
||||||
-- TODO: might need a better place for this. or check
|
|
||||||
--if wire>4 then
|
|
||||||
-- self:RadioTransmission(self.LSORadio, AIRBOSS.LSOCall.BOLTER)
|
|
||||||
--end
|
|
||||||
|
|
||||||
-- Debug text.
|
|
||||||
local text=string.format("Player %s AC type %s landed at dist=%.1f m. Trapped wire=%d.", playerData.name, playerData.actype, dist, wire)
|
|
||||||
text=text..string.format(" X=%.1f m, Z=%.1f m, rho=%.1f m.", X, Z, rho)
|
|
||||||
self:T(self.lid..text)
|
|
||||||
|
|
||||||
-- Unkonwn step until we now more.
|
|
||||||
playerData.step=AIRBOSS.PatternStep.UNDEFINED
|
|
||||||
playerData.warning=nil
|
|
||||||
|
|
||||||
-- Call trapped function in 1 second to make sure we did not bolter.
|
-- Call trapped function in 1 second to make sure we did not bolter.
|
||||||
SCHEDULER:New(nil, self._Trapped, {self, playerData}, 1)
|
SCHEDULER:New(nil, self._Trapped, {self, playerData}, 1)
|
||||||
@ -6693,22 +6780,43 @@ function AIRBOSS:OnEventTakeoff(EventData)
|
|||||||
self:T3(self.lid.."TAKEOFF: group = "..tostring(EventData.IniGroupName))
|
self:T3(self.lid.."TAKEOFF: group = "..tostring(EventData.IniGroupName))
|
||||||
self:T3(self.lid.."TAKEOFF: player = "..tostring(_playername))
|
self:T3(self.lid.."TAKEOFF: player = "..tostring(_playername))
|
||||||
|
|
||||||
|
-- Airbase.
|
||||||
|
local airbase=EventData.Place
|
||||||
|
|
||||||
|
-- Airbase name.
|
||||||
|
local airbasename="unknown"
|
||||||
|
if airbase then
|
||||||
|
airbasename=airbase:GetName()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check right airbase.
|
||||||
|
if airbasename==self.carrier:GetName() then
|
||||||
|
|
||||||
if _unit and _playername then
|
if _unit and _playername then
|
||||||
|
|
||||||
-- Debug message.
|
-- Debug message.
|
||||||
self:T(self.lid..string.format("Player %s took off!",_playername))
|
self:T(self.lid..string.format("Player %s took off at %s!",_playername, airbasename))
|
||||||
|
|
||||||
-- TODO: Set recoverd status.
|
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
-- Debug message.
|
-- Debug message.
|
||||||
self:T2(self.lid..string.format("AI unit %s took off!", _unitName))
|
self:T2(self.lid..string.format("AI unit %s took off at %s!", _unitName, airbasename))
|
||||||
|
|
||||||
-- TODO: Set recoverd status.
|
-- Get flight.
|
||||||
|
local flight=self:_GetFlightFromGroupInQueue(EventData.IniGroup, self.flights)
|
||||||
|
|
||||||
|
if flight then
|
||||||
|
|
||||||
|
-- Set ballcall and recoverd status.
|
||||||
|
for _,elem in pairs(flight.elements) do
|
||||||
|
local element=elem --#AIRBOSS.FlightElement
|
||||||
|
element.ballcall=false
|
||||||
|
element.recovered=nil
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Airboss event handler for event crash.
|
--- Airboss event handler for event crash.
|
||||||
@ -6837,13 +6945,13 @@ function AIRBOSS:_Spinning(playerData)
|
|||||||
-- Early break.
|
-- Early break.
|
||||||
local SpinIt={}
|
local SpinIt={}
|
||||||
SpinIt.name="Spinning"
|
SpinIt.name="Spinning"
|
||||||
SpinIt.Xmin=-UTILS.NMToMeters(5) -- Not more than 5 NM behind the boat.
|
SpinIt.Xmin=-UTILS.NMToMeters(6) -- Not more than 5 NM behind the boat.
|
||||||
SpinIt.Xmax= UTILS.NMToMeters(5) -- Not more than 5 NM in front of the boat.
|
SpinIt.Xmax= UTILS.NMToMeters(5) -- Not more than 5 NM in front of the boat.
|
||||||
SpinIt.Zmin=-UTILS.NMToMeters(5) -- Not more than 5 NM port.
|
SpinIt.Zmin=-UTILS.NMToMeters(6) -- Not more than 5 NM port.
|
||||||
SpinIt.Zmax= UTILS.NMToMeters(3) -- Not more than 3 NM starboard.
|
SpinIt.Zmax= UTILS.NMToMeters(2) -- Not more than 3 NM starboard.
|
||||||
SpinIt.LimitXmin=100 -- 100 meters ahead and a bit starboard.
|
SpinIt.LimitXmin=-100 -- 100 meters behind the boat
|
||||||
SpinIt.LimitXmax=nil
|
SpinIt.LimitXmax=nil
|
||||||
SpinIt.LimitZmin=10
|
SpinIt.LimitZmin=-UTILS.NMToMeters(1) -- 1 NM port
|
||||||
SpinIt.LimitZmax=nil
|
SpinIt.LimitZmax=nil
|
||||||
|
|
||||||
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
||||||
@ -6852,11 +6960,11 @@ function AIRBOSS:_Spinning(playerData)
|
|||||||
-- Check if we are in front of the boat (diffX > 0).
|
-- Check if we are in front of the boat (diffX > 0).
|
||||||
if self:_CheckLimits(X, Z, SpinIt) then
|
if self:_CheckLimits(X, Z, SpinIt) then
|
||||||
|
|
||||||
-- Player is "de-spinned".
|
-- Player is "de-spinned". Should go to initial again.
|
||||||
--self:_SetPlayerStep(playerData, AIRBOSS.PatternStep.EARLYBREAK)
|
self:_SetPlayerStep(playerData, AIRBOSS.PatternStep.INITIAL)
|
||||||
|
|
||||||
-- Remove player from spinning queue.
|
-- Remove player from spinning queue.
|
||||||
--self:_RemoveFlightFromQueue(self.Qspinning, playerData)
|
self:_RemoveFlightFromQueue(self.Qspinning, playerData)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -7820,8 +7928,8 @@ function AIRBOSS:_Final(playerData)
|
|||||||
-- Player's angle of bank.
|
-- Player's angle of bank.
|
||||||
local roll=playerData.unit:GetRoll()
|
local roll=playerData.unit:GetRoll()
|
||||||
|
|
||||||
-- Check if player is in +-5 deg cone and flying towards the runway.
|
-- Check if player is in +-4 deg cone and flying towards the runway.
|
||||||
if math.abs(lineup)<5 then --and math.abs(relhead)<5 then
|
if math.abs(lineup)<=4 then
|
||||||
|
|
||||||
-- Get optimal altitude, distance and speed.
|
-- Get optimal altitude, distance and speed.
|
||||||
local alt, aoa, dist, speed=self:_GetAircraftParameters(playerData)
|
local alt, aoa, dist, speed=self:_GetAircraftParameters(playerData)
|
||||||
@ -8448,7 +8556,7 @@ function AIRBOSS:_GetWire(Lcoord, dc)
|
|||||||
wire=99
|
wire=99
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.Debug then
|
if self.Debug and false then
|
||||||
|
|
||||||
-- Wire position coodinates.
|
-- Wire position coodinates.
|
||||||
local wp1=Scoord:Translate(w1, FB)
|
local wp1=Scoord:Translate(w1, FB)
|
||||||
@ -8800,7 +8908,7 @@ function AIRBOSS:_GetZoneCorridor(case)
|
|||||||
|
|
||||||
-- Length of the box in NM.
|
-- Length of the box in NM.
|
||||||
local x=(d+w/2)/math.cos(alpha)
|
local x=(d+w/2)/math.cos(alpha)
|
||||||
local l=28-x
|
local l=31-x
|
||||||
|
|
||||||
-- Some math...
|
-- Some math...
|
||||||
local y1=d-w2
|
local y1=d-w2
|
||||||
@ -9193,6 +9301,7 @@ function AIRBOSS:_AttitudeMonitor(playerData)
|
|||||||
text=text..string.format("\nDist=%.1f m Alt=%.1f m delta|V|=%.1f km/h", dist, self:_GetAltCarrier(playerData.unit), dv)
|
text=text..string.format("\nDist=%.1f m Alt=%.1f m delta|V|=%.1f km/h", dist, self:_GetAltCarrier(playerData.unit), dv)
|
||||||
text=text..string.format("\nLineUp=%.2f° | GlideSlope=%.2f° | AoA=%.1f", lineup, glideslope, self:_AoADeg2Units(playerData, aoa))
|
text=text..string.format("\nLineUp=%.2f° | GlideSlope=%.2f° | AoA=%.1f", lineup, glideslope, self:_AoADeg2Units(playerData, aoa))
|
||||||
local grade, points, analysis=self:_LSOgrade(playerData)
|
local grade, points, analysis=self:_LSOgrade(playerData)
|
||||||
|
text=text..string.format("\nTgroove=%.1f sec", self:_GetTimeInGroove(playerData))
|
||||||
text=text..string.format("\nGrade: %s %.1f PT - %s", grade, points, analysis)
|
text=text..string.format("\nGrade: %s %.1f PT - %s", grade, points, analysis)
|
||||||
else
|
else
|
||||||
text=text..string.format("\nR=%.2f NM | X=%d Z=%d m", UTILS.MetersToNM(rho), dx, dz)
|
text=text..string.format("\nR=%.2f NM | X=%d Z=%d m", UTILS.MetersToNM(rho), dx, dz)
|
||||||
@ -9400,13 +9509,15 @@ end
|
|||||||
|
|
||||||
--- Get wind direction and speed at carrier position.
|
--- Get wind direction and speed at carrier position.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param #number alt Altitude in meters. Default 50 m.
|
-- @param #number alt Altitude ASL in meters. Default 50 m.
|
||||||
-- @return #number Direction the wind is blowing **from** in degrees.
|
-- @return #number Direction the wind is blowing **from** in degrees.
|
||||||
-- @return #number Wind speed in m/s.
|
-- @return #number Wind speed in m/s.
|
||||||
function AIRBOSS:GetWind(alt)
|
function AIRBOSS:GetWind(alt)
|
||||||
|
|
||||||
|
-- Current position of the carrier
|
||||||
local cv=self:GetCoordinate()
|
local cv=self:GetCoordinate()
|
||||||
|
|
||||||
|
-- Wind direction and speed. By default at 50 meters ASL.
|
||||||
local Wdir, Wspeed=cv:GetWind(alt or 50)
|
local Wdir, Wspeed=cv:GetWind(alt or 50)
|
||||||
|
|
||||||
return Wdir, Wspeed
|
return Wdir, Wspeed
|
||||||
@ -9425,16 +9536,24 @@ function AIRBOSS:GetWindOnDeck(alt)
|
|||||||
-- Velocity vector of carrier.
|
-- Velocity vector of carrier.
|
||||||
local vc=self.carrier:GetVelocityVec3()
|
local vc=self.carrier:GetVelocityVec3()
|
||||||
|
|
||||||
|
-- Rotate to angled deck.
|
||||||
|
vc=UTILS.Rotate2D(vc, self.carrierparam.rwyangle)
|
||||||
|
|
||||||
-- Wind (from) vector
|
-- Wind (from) vector
|
||||||
local vw=cv:GetWindWithTurbulenceVec3(alt or 50)
|
local vw=cv:GetWindWithTurbulenceVec3(alt or 50)
|
||||||
|
|
||||||
-- Carrier velocity has to be negative. If carrier drives in the direction the wind is blowing from, we have less wind in total.
|
-- Carrier velocity has to be negative. If carrier drives in the direction the wind is blowing from, we have less wind in total.
|
||||||
local vd=UTILS.VecSubstract(vw, vc)
|
local vd=UTILS.VecSubstract(vw, vc)
|
||||||
|
|
||||||
|
local vh=math.deg(math.atan2(vd.z, vd.x))
|
||||||
|
if vh<0 then
|
||||||
|
vh=vh+360
|
||||||
|
end
|
||||||
|
|
||||||
-- Strength.
|
-- Strength.
|
||||||
local vabs=UTILS.VecNorm(vd)
|
local vabs=UTILS.VecNorm(vd)
|
||||||
|
|
||||||
return vd, vabs
|
return vh, vabs
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -9445,11 +9564,16 @@ end
|
|||||||
function AIRBOSS:GetHeadingIntoWind(magnetic)
|
function AIRBOSS:GetHeadingIntoWind(magnetic)
|
||||||
|
|
||||||
-- Get direction the wind is blowing from. This is where we want to go.
|
-- Get direction the wind is blowing from. This is where we want to go.
|
||||||
local windfrom=self:GetCoordinate():GetWind(50)
|
local windfrom, vwind=self:GetWind()
|
||||||
|
|
||||||
-- Actually, we want the runway in the wind.
|
-- Actually, we want the runway in the wind.
|
||||||
local intowind=windfrom-self.carrierparam.rwyangle
|
local intowind=windfrom-self.carrierparam.rwyangle
|
||||||
|
|
||||||
|
-- If no wind, take current heading.
|
||||||
|
if vwind<0.1 then
|
||||||
|
intowind=self:GetHeading()
|
||||||
|
end
|
||||||
|
|
||||||
-- Magnetic heading.
|
-- Magnetic heading.
|
||||||
if magnetic then
|
if magnetic then
|
||||||
intowind=intowind-self.magvar
|
intowind=intowind-self.magvar
|
||||||
@ -9564,6 +9688,28 @@ function AIRBOSS:GetRadial(case, magnetic, offset, inverse)
|
|||||||
return radial
|
return radial
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get difference between to headings in degrees taking into accound the [0,360) periodocity.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
-- @param #number hdg1 Heading one.
|
||||||
|
-- @param #number hdg2 Heading two.
|
||||||
|
-- @return #number Difference between the two headings in degrees.
|
||||||
|
function AIRBOSS:_GetDeltaHeading(hdg1, hdg2)
|
||||||
|
|
||||||
|
local V={} --DCS#Vec3
|
||||||
|
V.x=math.cos(math.rad(hdg1))
|
||||||
|
V.y=0
|
||||||
|
V.z=math.sin(math.rad(hdg1))
|
||||||
|
|
||||||
|
local W={} --DCS#Vec3
|
||||||
|
W.x=math.cos(math.rad(hdg2))
|
||||||
|
W.y=0
|
||||||
|
W.z=math.sin(math.rad(hdg2))
|
||||||
|
|
||||||
|
local alpha=UTILS.VecAngle(V,W)
|
||||||
|
|
||||||
|
return alpha
|
||||||
|
end
|
||||||
|
|
||||||
--- Get relative heading of player wrt carrier.
|
--- Get relative heading of player wrt carrier.
|
||||||
-- This is the angle between the direction/orientation vector of the carrier and the direction/orientation vector of the provided unit.
|
-- This is the angle between the direction/orientation vector of the carrier and the direction/orientation vector of the provided unit.
|
||||||
-- Note that this is calculated in the X-Z plane, i.e. the altitude Y is not taken into account.
|
-- Note that this is calculated in the X-Z plane, i.e. the altitude Y is not taken into account.
|
||||||
@ -10575,17 +10721,18 @@ function AIRBOSS:_Debrief(playerData)
|
|||||||
mygrade.finalscore=Points
|
mygrade.finalscore=Points
|
||||||
end
|
end
|
||||||
mygrade.case=playerData.case
|
mygrade.case=playerData.case
|
||||||
mygrade.time=UTILS.SecondsToClock(timer.getAbsTime())
|
|
||||||
local _,windondeck=self:GetWindOnDeck()
|
local _,windondeck=self:GetWindOnDeck()
|
||||||
mygrade.wind=tostring(UTILS.Round(windondeck, 1))
|
mygrade.wind=tostring(UTILS.Round(UTILS.MpsToKnots(windondeck), 1))
|
||||||
mygrade.airframe=playerData.actype
|
|
||||||
mygrade.modex=playerData.onboard
|
mygrade.modex=playerData.onboard
|
||||||
|
mygrade.airframe=playerData.actype
|
||||||
mygrade.carriertype=self.carriertype
|
mygrade.carriertype=self.carriertype
|
||||||
mygrade.carriername=self.alias
|
mygrade.carriername=self.alias
|
||||||
mygrade.theatre=self.theatre
|
mygrade.theatre=self.theatre
|
||||||
mygrade.date="n/a"
|
mygrade.mitime=UTILS.SecondsToClock(timer.getAbsTime())
|
||||||
|
mygrade.midate=UTILS.GetDCSMissionDate()
|
||||||
|
mygrade.osdate="n/a"
|
||||||
if os then
|
if os then
|
||||||
mygrade.date=os.date() --os.date("%d.%m.%Y")
|
mygrade.osdate=os.date() --os.date("%d.%m.%Y")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Add LSO grade to player grades table.
|
-- Add LSO grade to player grades table.
|
||||||
@ -11055,16 +11202,12 @@ end
|
|||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param #number time Time in seconds.
|
-- @param #number time Time in seconds.
|
||||||
-- @param #number vdeck Speed on deck m/s. Carrier will
|
-- @param #number vdeck Speed on deck m/s. Carrier will
|
||||||
|
-- @param #boolean uturn Make U-turn and go back to initial after downwind leg.
|
||||||
-- @return #AIRBOSS self
|
-- @return #AIRBOSS self
|
||||||
function AIRBOSS:CarrierTurnIntoWind(time, vdeck)
|
function AIRBOSS:CarrierTurnIntoWind(time, vdeck, uturn)
|
||||||
|
|
||||||
-- Wind speed.
|
-- Wind speed.
|
||||||
local _,vwind=self:GetCoordinate():GetWind(50)
|
local _,vwind=self:GetWind()
|
||||||
|
|
||||||
-- Check that wind is >= 0.1 m/s.
|
|
||||||
if vwind<0.1 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Speed of carrier in m/s.
|
-- Speed of carrier in m/s.
|
||||||
local vtot=vdeck-vwind
|
local vtot=vdeck-vwind
|
||||||
@ -11093,22 +11236,34 @@ 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 waypoint.
|
||||||
|
local nextwp=self:_GetNextWaypoint()
|
||||||
|
|
||||||
|
-- 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.
|
||||||
|
self:CarrierDetour(pos1, speedknots, uturn, vdownwind)
|
||||||
|
|
||||||
|
-- Set switch that we are currently turning into the wind.
|
||||||
|
self.turnintowind=true
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get next waypoint of the carrier.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
-- @return Core.Point#COORDINATE Coordinate of the next waypoint.
|
||||||
|
-- @return #number Number of waypoint
|
||||||
|
function AIRBOSS:_GetNextWaypoint()
|
||||||
|
|
||||||
-- Next wp = current+1 (or last)
|
-- Next wp = current+1 (or last)
|
||||||
local Nnextwp=math.min(self.currentwp+1, #self.waypoints)
|
local Nnextwp=math.min(self.currentwp+1, #self.waypoints)
|
||||||
|
|
||||||
-- Next waypoint.
|
-- Next waypoint.
|
||||||
local nextwp=self.waypoints[Nnextwp] --Core.Point#COORDINATE
|
local nextwp=self.waypoints[Nnextwp] --Core.Point#COORDINATE
|
||||||
|
|
||||||
-- For downwind, we take the velocity at the next WP.
|
return nextwp,Nnextwp
|
||||||
local vdownwind=UTILS.MpsToKnots(nextwp:GetVelocity())
|
|
||||||
|
|
||||||
-- Let the carrier make a detour from its route but return to its current position.
|
|
||||||
self:CarrierDetour(pos1, speedknots, true, vdownwind)
|
|
||||||
|
|
||||||
-- Set switch that we are currently turning into the wind.
|
|
||||||
self.turnintowind=true
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Patrol carrier.
|
--- Patrol carrier.
|
||||||
@ -11323,6 +11478,9 @@ function AIRBOSS._PassingWaypoint(group, airboss, i, final)
|
|||||||
-- Set current waypoint.
|
-- Set current waypoint.
|
||||||
airboss.currentwp=i
|
airboss.currentwp=i
|
||||||
|
|
||||||
|
-- Reactivate beacons.
|
||||||
|
--airboss:_ActivateBeacons()
|
||||||
|
|
||||||
-- If final waypoint reached, do route all over again.
|
-- If final waypoint reached, do route all over again.
|
||||||
if i==final and final>1 and airboss.adinfinitum then
|
if i==final and final>1 and airboss.adinfinitum then
|
||||||
airboss:_PatrolRoute()
|
airboss:_PatrolRoute()
|
||||||
@ -11335,15 +11493,11 @@ end
|
|||||||
--@param Core.Point#COORDINATE gotocoord Go to coordinate before route is resumed.
|
--@param Core.Point#COORDINATE gotocoord Go to coordinate before route is resumed.
|
||||||
function AIRBOSS._ResumeRoute(group, airboss, gotocoord)
|
function AIRBOSS._ResumeRoute(group, airboss, gotocoord)
|
||||||
|
|
||||||
-- Next wp = current+1 (or last)
|
-- Get next waypoint
|
||||||
local nextwp=math.min(airboss.currentwp+1, #airboss.waypoints)
|
local nextwp,Nextwp=airboss:_GetNextWaypoint()
|
||||||
|
|
||||||
-- Debug message.
|
-- Velocity at that coordinate.
|
||||||
local text=string.format("Group %s is resuming route. Next waypoint %d.", group:GetName(), nextwp)
|
local speedkmh=nextwp.Velocity*3.6
|
||||||
|
|
||||||
-- Debug message.
|
|
||||||
MESSAGE:New(text,10):ToAllIf(airboss.Debug)
|
|
||||||
airboss:T(airboss.lid..text)
|
|
||||||
|
|
||||||
-- Waypoints array.
|
-- Waypoints array.
|
||||||
local waypoints={}
|
local waypoints={}
|
||||||
@ -11352,16 +11506,24 @@ function AIRBOSS._ResumeRoute(group, airboss, gotocoord)
|
|||||||
local velocity=group:GetVelocityKMH()
|
local velocity=group:GetVelocityKMH()
|
||||||
|
|
||||||
-- Current positon as first waypoint.
|
-- Current positon as first waypoint.
|
||||||
local wp0=group:GetCoordinate():WaypointGround(velocity)
|
local wp0=group:GetCoordinate():WaypointGround(speedkmh)
|
||||||
table.insert(waypoints, wp0)
|
table.insert(waypoints, wp0)
|
||||||
|
|
||||||
|
-- First goto this coordinate.
|
||||||
if gotocoord then
|
if gotocoord then
|
||||||
local wp1=gotocoord:WaypointGround(velocity)
|
local wp1=gotocoord:WaypointGround(speedkmh)
|
||||||
table.insert(waypoints, wp1)
|
table.insert(waypoints, wp1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Debug message.
|
||||||
|
local text=string.format("Carrier is resuming route. Next waypoint %d, Speed=%.1f knots.", Nextwp, UTILS.KmphToKnots(speedkmh))
|
||||||
|
|
||||||
|
-- Debug message.
|
||||||
|
MESSAGE:New(text,10):ToAllIf(airboss.Debug)
|
||||||
|
airboss:I(airboss.lid..text)
|
||||||
|
|
||||||
-- Loop over all remaining waypoints.
|
-- Loop over all remaining waypoints.
|
||||||
for i=nextwp, #airboss.waypoints do
|
for i=Nextwp, #airboss.waypoints do
|
||||||
|
|
||||||
-- Coordinate of the next WP.
|
-- Coordinate of the next WP.
|
||||||
local coord=airboss.waypoints[i] --Core.Point#COORDINATE
|
local coord=airboss.waypoints[i] --Core.Point#COORDINATE
|
||||||
@ -12592,7 +12754,8 @@ function AIRBOSS:_AddF10Commands(_unitName)
|
|||||||
missionCommands.addCommandForGroup(gid, "Request Marshal", _rootPath, self._RequestMarshal, self, _unitName) -- F3
|
missionCommands.addCommandForGroup(gid, "Request Marshal", _rootPath, self._RequestMarshal, self, _unitName) -- F3
|
||||||
missionCommands.addCommandForGroup(gid, "Request Commence", _rootPath, self._RequestCommence, self, _unitName) -- F4
|
missionCommands.addCommandForGroup(gid, "Request Commence", _rootPath, self._RequestCommence, self, _unitName) -- F4
|
||||||
missionCommands.addCommandForGroup(gid, "Request Refueling", _rootPath, self._RequestRefueling, self, _unitName) -- F5
|
missionCommands.addCommandForGroup(gid, "Request Refueling", _rootPath, self._RequestRefueling, self, _unitName) -- F5
|
||||||
missionCommands.addCommandForGroup(gid, "[Reset My Status]", _rootPath, self._ResetPlayerStatus, self, _unitName) -- F6
|
missionCommands.addCommandForGroup(gid, "Spinning", _rootPath, self._RequestSpinning, self, _unitName) -- F6
|
||||||
|
missionCommands.addCommandForGroup(gid, "[Reset My Status]", _rootPath, self._ResetPlayerStatus, self, _unitName) -- F7
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:E(self.lid..string.format("ERROR: Could not find group or group ID in AddF10Menu() function. Unit name: %s.", _unitName))
|
self:E(self.lid..string.format("ERROR: Could not find group or group ID in AddF10Menu() function. Unit name: %s.", _unitName))
|
||||||
@ -12627,7 +12790,7 @@ function AIRBOSS:_ResetPlayerStatus(_unitName)
|
|||||||
self:MessageToPlayer(playerData, text, "AIRBOSS")
|
self:MessageToPlayer(playerData, text, "AIRBOSS")
|
||||||
|
|
||||||
-- Remove flight from queues. Collapse marshal stack if necessary.
|
-- Remove flight from queues. Collapse marshal stack if necessary.
|
||||||
-- TODO: This has not the completely tag. What to do with section members if flight is lead or not?
|
-- Section members are removed from the Spinning queue. If flight is member, he is removed from the section.
|
||||||
self:_RemoveFlight(playerData)
|
self:_RemoveFlight(playerData)
|
||||||
|
|
||||||
-- Initialize player data.
|
-- Initialize player data.
|
||||||
@ -12746,29 +12909,17 @@ function AIRBOSS:_RequestSpinning(_unitName)
|
|||||||
text="negative, your section lead has to call spinning."
|
text="negative, your section lead has to call spinning."
|
||||||
]]
|
]]
|
||||||
|
|
||||||
|
elseif playerData.step==AIRBOSS.PatternStep.SPINNING then
|
||||||
|
|
||||||
|
text="negative, you are already spinning."
|
||||||
|
|
||||||
-- Check if player is in the right step.
|
-- Check if player is in the right step.
|
||||||
elseif not (playerData.step==AIRBOSS.PatternStep.BREAKENTRY or
|
elseif not (playerData.step==AIRBOSS.PatternStep.BREAKENTRY or
|
||||||
playerData.step==AIRBOSS.PatternStep.EARLYBREAK or
|
playerData.step==AIRBOSS.PatternStep.EARLYBREAK or
|
||||||
playerData.step==AIRBOSS.PatternStep.LATEBREAK or
|
playerData.step==AIRBOSS.PatternStep.LATEBREAK) then
|
||||||
playerData.step==AIRBOSS.PatternStep.INITIAL) then
|
|
||||||
|
|
||||||
text="negative, you have to be in the right step to spin it!"
|
text="negative, you have to be in the right step to spin it!"
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
-- Check if player is in the pattern.
|
|
||||||
if self:_InQueue(self.Qspinning, playerData.group) then
|
|
||||||
|
|
||||||
if playerData.difficulty~=AIRBOSS.Difficulty.HARD then
|
|
||||||
text="Proceed to early break."
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Player is "de-spinned".
|
|
||||||
self:_SetPlayerStep(playerData, AIRBOSS.PatternStep.EARLYBREAK)
|
|
||||||
|
|
||||||
-- Remove player from spinning queue
|
|
||||||
self:_RemoveFlightFromQueue(self.Qspinning, playerData)
|
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
-- Set player step.
|
-- Set player step.
|
||||||
@ -12777,9 +12928,13 @@ function AIRBOSS:_RequestSpinning(_unitName)
|
|||||||
-- Add player to spinning queue.
|
-- Add player to spinning queue.
|
||||||
table.insert(self.Qspinning, playerData)
|
table.insert(self.Qspinning, playerData)
|
||||||
|
|
||||||
|
-- Some advice.
|
||||||
if playerData.difficulty~=AIRBOSS.Difficulty.HARD then
|
if playerData.difficulty~=AIRBOSS.Difficulty.HARD then
|
||||||
text="Spin it!"
|
text="Spin it!"
|
||||||
end
|
end
|
||||||
|
if playerData.difficulty==AIRBOSS.Difficulty.EASY then
|
||||||
|
text=text.." Climb to 1200 feet and proceed to the initial."
|
||||||
|
end
|
||||||
|
|
||||||
-- Set step for section members.
|
-- Set step for section members.
|
||||||
--[[
|
--[[
|
||||||
@ -12795,8 +12950,6 @@ function AIRBOSS:_RequestSpinning(_unitName)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Send message.
|
-- Send message.
|
||||||
self:MessageToPlayer(playerData, text, "MARSHAL")
|
self:MessageToPlayer(playerData, text, "MARSHAL")
|
||||||
|
|
||||||
@ -13311,7 +13464,7 @@ function AIRBOSS:_DisplayPlayerGrades(_unitName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Time in the groove if any.
|
-- Time in the groove if any.
|
||||||
if grade.Tgroove and grade.Tgroove<=60 then
|
if grade.Tgroove and grade.Tgroove<=120 then
|
||||||
text=text..string.format(" Tgroove=%.1f s", grade.Tgroove)
|
text=text..string.format(" Tgroove=%.1f s", grade.Tgroove)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -13487,11 +13640,15 @@ function AIRBOSS:_DisplayCarrierInfo(_unitname)
|
|||||||
icls=string.format("%d (%s)", self.ICLSchannel, self.ICLSmorse)
|
icls=string.format("%d (%s)", self.ICLSchannel, self.ICLSmorse)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Wind on flight deck
|
||||||
|
local wind=UTILS.MpsToKnots(select(2, self:GetWindOnDeck()))
|
||||||
|
|
||||||
-- Get groups, units in queues.
|
-- Get groups, units in queues.
|
||||||
local Nmarshal,nmarshal=self:_GetQueueInfo(self.Qmarshal, playerData.case)
|
local Nmarshal,nmarshal = self:_GetQueueInfo(self.Qmarshal, playerData.case)
|
||||||
local Npattern,npattern=self:_GetQueueInfo(self.Qpattern)
|
local Npattern,npattern = self:_GetQueueInfo(self.Qpattern)
|
||||||
local Nwaiting,nwaiting=self:_GetQueueInfo(self.Qwaiting)
|
local Nspinning,nspinning = self:_GetQueueInfo(self.Qspinning)
|
||||||
local Ntotal,ntotal=self:_GetQueueInfo(self.flights)
|
local Nwaiting,nwaiting = self:_GetQueueInfo(self.Qwaiting)
|
||||||
|
local Ntotal,ntotal = self:_GetQueueInfo(self.flights)
|
||||||
|
|
||||||
-- Current abs time.
|
-- Current abs time.
|
||||||
local Tabs=timer.getAbsTime()
|
local Tabs=timer.getAbsTime()
|
||||||
@ -13540,8 +13697,7 @@ function AIRBOSS:_DisplayCarrierInfo(_unitname)
|
|||||||
text=text..string.format("Case %d recovery ops\nMarshal radial %03d°\n", self.case, radial)
|
text=text..string.format("Case %d recovery ops\nMarshal radial %03d°\n", self.case, radial)
|
||||||
end
|
end
|
||||||
text=text..string.format("BRC %03d° - FB %03d°\n", self:GetBRC(), self:GetFinalBearing(true))
|
text=text..string.format("BRC %03d° - FB %03d°\n", self:GetBRC(), self:GetFinalBearing(true))
|
||||||
--text=text..string.format("FB %03d°\n", self:GetFinalBearing(true))
|
text=text..string.format("Speed %.1f kts - Wind on deck %.1f kts\n", carrierspeed, wind)
|
||||||
text=text..string.format("Speed %d kts\n", carrierspeed)
|
|
||||||
text=text..string.format("Tower frequency %.3f MHz\n", self.TowerFreq)
|
text=text..string.format("Tower frequency %.3f MHz\n", self.TowerFreq)
|
||||||
text=text..string.format("Marshal radio %.3f MHz\n", self.MarshalFreq)
|
text=text..string.format("Marshal radio %.3f MHz\n", self.MarshalFreq)
|
||||||
text=text..string.format("LSO radio %.3f MHz\n", self.LSOFreq)
|
text=text..string.format("LSO radio %.3f MHz\n", self.LSOFreq)
|
||||||
@ -13550,10 +13706,9 @@ function AIRBOSS:_DisplayCarrierInfo(_unitname)
|
|||||||
if tankertext then
|
if tankertext then
|
||||||
text=text..tankertext.."\n"
|
text=text..tankertext.."\n"
|
||||||
end
|
end
|
||||||
--text=text..string.format("# A/C total %d\n", #self.flights)
|
|
||||||
text=text..string.format("# A/C total %d (%d)\n", Ntotal, ntotal)
|
text=text..string.format("# A/C total %d (%d)\n", Ntotal, ntotal)
|
||||||
text=text..string.format("# A/C marshal %d (%d)\n", Nmarshal, nmarshal)
|
text=text..string.format("# A/C marshal %d (%d)\n", Nmarshal, nmarshal)
|
||||||
text=text..string.format("# A/C pattern %d (%d)\n", Npattern, npattern)
|
text=text..string.format("# A/C pattern %d (%d) - spinning %d (%d)\n", Npattern, npattern, Nspinning, nspinning)
|
||||||
text=text..string.format("# A/C waiting %d (%d)\n", Nwaiting, nwaiting)
|
text=text..string.format("# A/C waiting %d (%d)\n", Nwaiting, nwaiting)
|
||||||
text=text..string.format(recoverytext)
|
text=text..string.format(recoverytext)
|
||||||
self:T2(self.lid..text)
|
self:T2(self.lid..text)
|
||||||
@ -13590,11 +13745,14 @@ function AIRBOSS:_DisplayCarrierWeather(_unitname)
|
|||||||
-- Get atmospheric data at carrier location.
|
-- Get atmospheric data at carrier location.
|
||||||
local T=coord:GetTemperature()
|
local T=coord:GetTemperature()
|
||||||
local P=coord:GetPressure()
|
local P=coord:GetPressure()
|
||||||
local Wd,Ws=coord:GetWind(50)
|
local Wd,Ws=self:GetWind()
|
||||||
|
|
||||||
-- Get Beaufort wind scale.
|
-- Get Beaufort wind scale.
|
||||||
local Bn,Bd=UTILS.BeaufortScale(Ws)
|
local Bn,Bd=UTILS.BeaufortScale(Ws)
|
||||||
|
|
||||||
|
-- Wind on flight deck
|
||||||
|
local Wod=UTILS.MpsToKnots(select(2, self:GetWindOnDeck()))
|
||||||
|
|
||||||
local WD=string.format('%03d°', Wd)
|
local WD=string.format('%03d°', Wd)
|
||||||
local Ts=string.format("%d°C",T)
|
local Ts=string.format("%d°C",T)
|
||||||
|
|
||||||
@ -13607,6 +13765,7 @@ function AIRBOSS:_DisplayCarrierWeather(_unitname)
|
|||||||
text=text..string.format("================================\n")
|
text=text..string.format("================================\n")
|
||||||
text=text..string.format("Temperature %s\n", tT)
|
text=text..string.format("Temperature %s\n", tT)
|
||||||
text=text..string.format("Wind from %s at %s (%s)\n", WD, tW, Bd)
|
text=text..string.format("Wind from %s at %s (%s)\n", WD, tW, Bd)
|
||||||
|
text=text..string.format("Wind on deck %.1f knots\n", Wod)
|
||||||
text=text..string.format("QFE %.1f hPa = %s", P, tP)
|
text=text..string.format("QFE %.1f hPa = %s", P, tP)
|
||||||
|
|
||||||
-- More info only reliable if Mission uses static weather.
|
-- More info only reliable if Mission uses static weather.
|
||||||
@ -13778,7 +13937,7 @@ function AIRBOSS:_DisplayPlayerStatus(_unitName)
|
|||||||
end
|
end
|
||||||
text=text..string.format("Recovery Case: %d\n", playerData.case)
|
text=text..string.format("Recovery Case: %d\n", playerData.case)
|
||||||
text=text..string.format("Skill Level: %s\n", playerData.difficulty)
|
text=text..string.format("Skill Level: %s\n", playerData.difficulty)
|
||||||
text=text..string.format("Tail # %s (%s)\n", playerData.onboard, self:_GetACNickname(playerData.actype))
|
text=text..string.format("Modex: %s (%s)\n", playerData.onboard, self:_GetACNickname(playerData.actype))
|
||||||
text=text..string.format("Fuel State: %.1f lbs/1000 (%.1f %%)\n", fuelstate/1000, fuel)
|
text=text..string.format("Fuel State: %.1f lbs/1000 (%.1f %%)\n", fuelstate/1000, fuel)
|
||||||
text=text..string.format("# units: %d (%d airborne)\n", nunitsGround, nunitsAirborne)
|
text=text..string.format("# units: %d (%d airborne)\n", nunitsGround, nunitsAirborne)
|
||||||
text=text..string.format("Section Lead: %s (%d/%d)", tostring(playerData.seclead), #playerData.section+1, self.NmaxSection+1)
|
text=text..string.format("Section Lead: %s (%d/%d)", tostring(playerData.seclead), #playerData.section+1, self.NmaxSection+1)
|
||||||
@ -14124,7 +14283,6 @@ function AIRBOSS:onafterSave(From, Event, To, path, filename)
|
|||||||
self:I(self.lid..text)
|
self:I(self.lid..text)
|
||||||
|
|
||||||
-- Header line
|
-- Header line
|
||||||
--local scores="Name,Pass,Points Final,Points Pass,Grade,Details,Wire,Tgroove,Case,Mission Time,Wind,Airframe,Modex,Carrier Type,Carrier Name,Theatre,Date OS\n"
|
|
||||||
local scores="Name,Pass,Points Final,Points Pass,Grade,Details,Wire,Tgroove,Case,Wind,Modex,Airframe,Carrier Type, Carrier Name,Theatre,Mission Time,Mission Date,OS Date\n"
|
local scores="Name,Pass,Points Final,Points Pass,Grade,Details,Wire,Tgroove,Case,Wind,Modex,Airframe,Carrier Type, Carrier Name,Theatre,Mission Time,Mission Date,OS Date\n"
|
||||||
|
|
||||||
-- Loop over all players.
|
-- Loop over all players.
|
||||||
@ -14141,7 +14299,7 @@ function AIRBOSS:onafterSave(From, Event, To, path, filename)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local Tgroove="n/a"
|
local Tgroove="n/a"
|
||||||
if grade.Tgroove and grade.Tgroove<=60 and grade.case<3 then
|
if grade.Tgroove and grade.Tgroove<=120 and grade.case<3 then
|
||||||
Tgroove=tostring(UTILS.Round(grade.Tgroove, 1))
|
Tgroove=tostring(UTILS.Round(grade.Tgroove, 1))
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -14152,9 +14310,9 @@ function AIRBOSS:onafterSave(From, Event, To, path, filename)
|
|||||||
|
|
||||||
-- Compile grade line.
|
-- Compile grade line.
|
||||||
--scores=scores..string.format("%s,%d,%s,%.1f,%s,%s,%s,%s,%d\n",
|
--scores=scores..string.format("%s,%d,%s,%.1f,%s,%s,%s,%s,%d\n",
|
||||||
scores=scores..string.format("%s,%d,%s,%.1f,%s,%s,%s,%s,%d,%s,%s,%s,%s,%s,%s\n",
|
scores=scores..string.format("%s,%d,%s,%.1f,%s,%s,%s,%s,%d,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
|
||||||
playername, i, finalscore, grade.points, grade.grade, grade.details, wire, Tgroove, grade.case,
|
playername, i, finalscore, grade.points, grade.grade, grade.details, wire, Tgroove, grade.case,
|
||||||
grade.time, grade.wind, grade.airframe, grade.modex, grade.carriertype, grade.carriername, grade.theatre, grade.date)
|
grade.wind, grade.modex, grade.airframe, grade.carriertype, grade.carriername, grade.theatre, grade.mitime, grade.midate, grade.osdate)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -14296,14 +14454,16 @@ function AIRBOSS:onafterLoad(From, Event, To, path, filename)
|
|||||||
grade.Tgroove=tonumber(gradedata[8])
|
grade.Tgroove=tonumber(gradedata[8])
|
||||||
end
|
end
|
||||||
grade.case=tonumber(gradedata[9])
|
grade.case=tonumber(gradedata[9])
|
||||||
grade.time=gradedata[10] or "n/a"
|
-- new
|
||||||
grade.wind=gradedata[11] or "n/a"
|
grade.wind=gradedata[10] or "n/a"
|
||||||
|
grade.modex=gradedata[11] or "n/a"
|
||||||
grade.airframe=gradedata[12] or "n/a"
|
grade.airframe=gradedata[12] or "n/a"
|
||||||
grade.modex=gradedata[13] or "n/a"
|
grade.carriertype=gradedata[13] or "n/a"
|
||||||
grade.carriertype=gradedata[14] or "n/a"
|
grade.carriername=gradedata[14] or "n/a"
|
||||||
grade.carriername=gradedata[15] or "n/a"
|
grade.theatre=gradedata[15] or "n/a"
|
||||||
grade.theatre=gradedata[16] or "n/a"
|
grade.mitime=gradedata[16] or "n/a"
|
||||||
grade.date=gradedata[17] or "n/a"
|
grade.midate=gradedata[17] or "n/a"
|
||||||
|
grade.osdate=gradedata[18] or "n/a"
|
||||||
|
|
||||||
-- Init player table if necessary.
|
-- Init player table if necessary.
|
||||||
self.playerscores[playername]=self.playerscores[playername] or {}
|
self.playerscores[playername]=self.playerscores[playername] or {}
|
||||||
|
|||||||
@ -864,6 +864,16 @@ function UTILS.GetDCSMap()
|
|||||||
return env.mission.theatre
|
return env.mission.theatre
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns the mission date. This is the date the mission started.
|
||||||
|
-- @return #string Mission date in yyyy/mm/dd format.
|
||||||
|
function UTILS.GetDCSMissionDate()
|
||||||
|
local year=tostring(env.mission.date.Year)
|
||||||
|
local month=tostring(env.mission.date.Month)
|
||||||
|
local day=tostring(env.mission.date.Day)
|
||||||
|
return string.format("%s/%s/%s", year, month, day)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns the magnetic declination of the map.
|
--- Returns the magnetic declination of the map.
|
||||||
-- Returned values for the current maps are:
|
-- Returned values for the current maps are:
|
||||||
--
|
--
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user