mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Merge branch 'FF/Develop' of https://github.com/FlightControl-Master/MOOSE into FF/Develop
This commit is contained in:
commit
b754972490
@ -115,19 +115,20 @@ CARRIERTRAINER.Difficulty={
|
||||
--- Player data table holding all important parameters for each player.
|
||||
-- @type CARRIERTRAINER.PlayerData
|
||||
-- @field #number id Player ID.
|
||||
-- @field #string callsign Callsign of player.
|
||||
-- @field #number score Player score.
|
||||
-- @field #number totalscore Score of all landing attempts.
|
||||
-- @field #number passes Number of passes.
|
||||
-- @field #string collectedResultString Results text of all passes.
|
||||
-- @field Wrapper.Unit#UNIT unit Aircraft unit of the player.
|
||||
-- @field #number lowestAltitude Lowest altitude.
|
||||
-- @field #number highestCarrierXDiff
|
||||
-- @field #number secondsStandingStill Time player does not move after a landing attempt.
|
||||
-- @field #string callsign Callsign of player.
|
||||
-- @field #number score Player score of the current pass.
|
||||
-- @field #number passes Number of passes.
|
||||
-- @field #table debrief Debrief analysis of the current step of this pass.
|
||||
-- @field #table results Results of all passes.
|
||||
-- @field #string summary Result summary text.
|
||||
-- @field Wrapper.Client#CLIENT client object of player.
|
||||
-- @field #string difficulty Difficulty level.
|
||||
-- @field #boolean inbigzone If true, player is in the big zone.
|
||||
-- @field #boolean landed If true, player landed or attempted to land.
|
||||
-- @field #boolean boltered If true, player boltered.
|
||||
-- @field #boolean calledball If true, player called the ball.
|
||||
-- @field #number Tlso Last time the LSO gave an advice.
|
||||
|
||||
--- Checkpoint parameters triggering the next step in the pattern.
|
||||
-- @type CARRIERTRAINER.Checkpoint
|
||||
@ -152,7 +153,7 @@ CARRIERTRAINER.MenuF10={}
|
||||
|
||||
--- Carrier trainer class version.
|
||||
-- @field #string version
|
||||
CARRIERTRAINER.version="0.1.0w"
|
||||
CARRIERTRAINER.version="0.1.1w"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
@ -374,19 +375,27 @@ function CARRIERTRAINER:_InitNewPlayer(unitname)
|
||||
|
||||
local playerData={} --#CARRIERTRAINER.PlayerData
|
||||
|
||||
-- Player unit, client and callsign.
|
||||
playerData.unit = UNIT:FindByName(unitname)
|
||||
playerData.client = CLIENT:FindByName(playerData.unit.UnitName, nil, true)
|
||||
playerData.callsign = playerData.unit:GetCallsign()
|
||||
|
||||
playerData.totalscore = 0
|
||||
playerData.passes = 0
|
||||
playerData.collectedResultString = ""
|
||||
|
||||
playerData=self:_InitNewRound(playerData)
|
||||
-- Number of passes done by player.
|
||||
playerData.passes=0
|
||||
|
||||
playerData.results={}
|
||||
|
||||
-- Set difficulty level.
|
||||
playerData.difficulty=CARRIERTRAINER.Difficulty.NORMAL
|
||||
|
||||
-- Player is in the big zone around the carrier.
|
||||
playerData.inbigzone=playerData.unit:IsInZone(self.giantZone)
|
||||
|
||||
-- Init stuff for this round.
|
||||
playerData=self:_InitNewRound(playerData)
|
||||
|
||||
return playerData
|
||||
end
|
||||
|
||||
@ -395,22 +404,26 @@ end
|
||||
-- @param #CARRIERTRAINER.PlayerData playerData Player data.
|
||||
-- @return #CARRIERTRAINER.PlayerData Initialized player data.
|
||||
function CARRIERTRAINER:_InitNewRound(playerData)
|
||||
playerData.step = 0
|
||||
playerData.score = 0
|
||||
playerData.step=0
|
||||
playerData.score=100
|
||||
playerData.grade={}
|
||||
playerData.summary = "Debriefing:\n"
|
||||
playerData.longDownwindDone = false
|
||||
playerData.highestCarrierXDiff = -9999999
|
||||
playerData.secondsStandingStill = 0
|
||||
playerData.lowestAltitude = 999999
|
||||
playerData.boltered=false
|
||||
playerData.landed=false
|
||||
playerData.calledball=false
|
||||
playerData.Tlso=timer.getTime()
|
||||
return playerData
|
||||
end
|
||||
|
||||
--- Append text to summary text.
|
||||
--- Append text to debrief text.
|
||||
-- @param #CARRIERTRAINER self
|
||||
-- @param #CARRIERTRAINER.PlayerData playerData Player data.
|
||||
-- @param #string item Text item appeded to the summary.
|
||||
function CARRIERTRAINER:_AddToSummary(playerData, item)
|
||||
playerData.summary = playerData.summary .. item .. "\n"
|
||||
-- @param #string step Current step in the pattern.
|
||||
-- @param #string item Text item appeded to the debrief.
|
||||
function CARRIERTRAINER:_AddToSummary(playerData, step, item)
|
||||
--playerData.summary = playerData.summary .. item .. "\n"
|
||||
table.inser(playerData.debrief, {step=step, hint=item})
|
||||
end
|
||||
|
||||
--- Append text to result text.
|
||||
@ -492,7 +505,9 @@ function CARRIERTRAINER:_CheckPlayerStatus()
|
||||
elseif playerData.step == 8 then
|
||||
self:_Groove(playerData)
|
||||
elseif playerData.step == 9 then
|
||||
self:_Trap(playerData)
|
||||
self:_CallTheBall(playerData)
|
||||
elseif playerData.step == 99 then
|
||||
self:_Debrief(playerData)
|
||||
end
|
||||
|
||||
else
|
||||
@ -866,7 +881,7 @@ function CARRIERTRAINER:_NewRound(playerData)
|
||||
self:_InitNewRound(playerData)
|
||||
|
||||
-- Next step: start of pattern.
|
||||
playerData.step = 1
|
||||
playerData.step=1
|
||||
end
|
||||
end
|
||||
|
||||
@ -881,8 +896,7 @@ function CARRIERTRAINER:_Start(playerData)
|
||||
self:_SendMessageToPlayer(hint, 8, playerData)
|
||||
|
||||
-- Next step: upwind.
|
||||
playerData.step = 2
|
||||
|
||||
playerData.step=2
|
||||
end
|
||||
|
||||
end
|
||||
@ -909,12 +923,14 @@ function CARRIERTRAINER:_Upwind(playerData)
|
||||
-- Get altitude.
|
||||
local hint=self:_AltitudeCheck(playerData, self.Upwind, altitude)
|
||||
|
||||
-- Message to player
|
||||
self:_SendMessageToPlayer(hint, 8, playerData)
|
||||
|
||||
-- Debrief.
|
||||
self:_AddToSummary(playerData, hint)
|
||||
|
||||
-- Next step.
|
||||
playerData.step = 3
|
||||
playerData.step=3
|
||||
end
|
||||
end
|
||||
|
||||
@ -952,7 +968,7 @@ function CARRIERTRAINER:_Break(playerData, part)
|
||||
-- Send message to player.
|
||||
self:_SendMessageToPlayer(hint, 10, playerData)
|
||||
|
||||
-- Add hint to summary.
|
||||
-- Debrif
|
||||
self:_AddToSummary(playerData, hint)
|
||||
|
||||
-- Nest step: late break or abeam.
|
||||
@ -986,7 +1002,7 @@ function CARRIERTRAINER:_CheckForLongDownwind(playerData)
|
||||
local hint = "Your downwind leg is too long. Turn to final earlier next time."
|
||||
self:_SendMessageToPlayer(hint, 10, playerData)
|
||||
|
||||
-- Add to debrief.
|
||||
-- Debrief.
|
||||
self:_AddToSummary(playerData, hint)
|
||||
|
||||
-- Decrease score.
|
||||
@ -1042,7 +1058,7 @@ function CARRIERTRAINER:_Abeam(playerData)
|
||||
self:_SendMessageToPlayer(hintFull, 10, playerData)
|
||||
|
||||
-- Add to debrief.
|
||||
self:_AddToSummary(playerData, hintFull)
|
||||
self:_AddToSummary(playerData, "Abeam", hintFull)
|
||||
|
||||
-- Proceed to next step.
|
||||
playerData.step = 6
|
||||
@ -1085,7 +1101,7 @@ function CARRIERTRAINER:_Ninety(playerData)
|
||||
self:_SendMessageToPlayer(hintFull, 10, playerData)
|
||||
|
||||
-- Add to debrief.
|
||||
self:_AddToSummary(playerData, hintFull)
|
||||
self:_AddToSummary(playerData, "At the 90:", hintFull)
|
||||
|
||||
-- Long downwind not an issue any more
|
||||
playerData.longDownwindDone = true
|
||||
@ -1128,14 +1144,14 @@ function CARRIERTRAINER:_Wake(playerData)
|
||||
self:_SendMessageToPlayer(hintFull, 10, playerData)
|
||||
|
||||
-- Add to debrief.
|
||||
self:_AddToSummary(playerData, hintFull)
|
||||
self:_AddToSummary(playerData, "At the wake:", hintFull)
|
||||
|
||||
-- Next step: Groove.
|
||||
playerData.step = 8
|
||||
end
|
||||
end
|
||||
|
||||
--- Groove.
|
||||
--- Entering the Groove.
|
||||
-- @param #CARRIERTRAINER self
|
||||
-- @param #CARRIERTRAINER.PlayerData playerData Player data table.
|
||||
function CARRIERTRAINER:_Groove(playerData)
|
||||
@ -1179,7 +1195,7 @@ function CARRIERTRAINER:_Groove(playerData)
|
||||
self:_SendMessageToPlayer(hintFull, 10, playerData)
|
||||
|
||||
-- Add to debrief.
|
||||
self:_AddToSummary(playerData, hintFull)
|
||||
self:_AddToSummary(playerData, "Entering the Groove:", hintFull)
|
||||
|
||||
-- Next step.
|
||||
playerData.step = 9
|
||||
@ -1187,10 +1203,10 @@ function CARRIERTRAINER:_Groove(playerData)
|
||||
|
||||
end
|
||||
|
||||
--- Trap.
|
||||
--- Call the ball, i.e. 3/4 NM distance between aircraft and carrier.
|
||||
-- @param #CARRIERTRAINER self
|
||||
-- @param #CARRIERTRAINER.PlayerData playerData Player data table.
|
||||
function CARRIERTRAINER:_Trap(playerData)
|
||||
function CARRIERTRAINER:_CallTheBall(playerData)
|
||||
|
||||
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
||||
local diffX, diffZ, rho, phi = self:_GetDistances(playerData.unit)
|
||||
@ -1208,23 +1224,21 @@ function CARRIERTRAINER:_Trap(playerData)
|
||||
return
|
||||
end
|
||||
|
||||
if (diffX > playerData.highestCarrierXDiff) then
|
||||
playerData.highestCarrierXDiff = diffX
|
||||
end
|
||||
|
||||
if (alt < playerData.lowestAltitude) then
|
||||
playerData.lowestAltitude = alt
|
||||
end
|
||||
|
||||
-- Lineup.
|
||||
-- Lineup. We need to correct for the end of the carrier deck and the tilted angle of the runway.
|
||||
-- TODO: make this parameter of the carrier.
|
||||
local lineup = math.asin(diffZ/(-(diffX-100)))
|
||||
local lineuperror = math.deg(lineup)-10
|
||||
|
||||
-- Glideslope.
|
||||
-- Glideslope. Wee need to correct for the height of the deck. The ideal glide slope is 3.5 degrees.
|
||||
-- TODO: make this parameter of the carrier.
|
||||
local glideslope = math.atan((playerData.unit:GetAltitude()-22)/(-diffX))
|
||||
local glideslopeError = math.deg(glideslope) - 3.5
|
||||
|
||||
if diffX<100 then
|
||||
if diffX>-UTILS.NMToMeters(0.75) and diffX<-100 and playerData.calledball==false then
|
||||
|
||||
|
||||
-- Check if we are beween 3/4 NM and end of ship.
|
||||
if diffX>-UTILS.NMToMeters(0.75) and diffX<-100 then
|
||||
|
||||
local text="Good height."
|
||||
if glideslopeError>1 then
|
||||
@ -1259,12 +1273,12 @@ function CARRIERTRAINER:_Trap(playerData)
|
||||
elseif lineuperror <3 then
|
||||
text=text.."Right for lineup!"
|
||||
elseif lineuperror <1 then
|
||||
text=text.."Right for lineup.."
|
||||
text=text.."Right for lineup..."
|
||||
else
|
||||
text=text.."Good on lineup."
|
||||
end
|
||||
|
||||
self:_SendMessageToPlayer(text, 8,playerData)
|
||||
self:_SendMessageToPlayer(text, 8, playerData)
|
||||
|
||||
elseif (diffX > 150) then
|
||||
|
||||
|
||||
@ -5435,7 +5435,7 @@ function RAT:_ATCInit(airports_map)
|
||||
if not RAT.ATC.init then
|
||||
local text
|
||||
text="Starting RAT ATC.\nSimultanious = "..RAT.ATC.Nclearance.."\n".."Delay = "..RAT.ATC.delay
|
||||
self:T(RAT.id..text)
|
||||
BASE:T(RAT.id..text)
|
||||
RAT.ATC.init=true
|
||||
for _,ap in pairs(airports_map) do
|
||||
local name=ap:GetName()
|
||||
@ -5458,7 +5458,7 @@ end
|
||||
-- @param #string name Group name of the flight.
|
||||
-- @param #string dest Name of the destination airport.
|
||||
function RAT:_ATCAddFlight(name, dest)
|
||||
self:T(string.format("%sATC %s: Adding flight %s with destination %s.", RAT.id, dest, name, dest))
|
||||
BASE:T(string.format("%sATC %s: Adding flight %s with destination %s.", RAT.id, dest, name, dest))
|
||||
RAT.ATC.flight[name]={}
|
||||
RAT.ATC.flight[name].destination=dest
|
||||
RAT.ATC.flight[name].Tarrive=-1
|
||||
@ -5483,7 +5483,7 @@ end
|
||||
-- @param #string name Group name of the flight.
|
||||
-- @param #number time Time the fight first registered.
|
||||
function RAT:_ATCRegisterFlight(name, time)
|
||||
self:T(RAT.id.."Flight ".. name.." registered at ATC for landing clearance.")
|
||||
BASE:T(RAT.id.."Flight ".. name.." registered at ATC for landing clearance.")
|
||||
RAT.ATC.flight[name].Tarrive=time
|
||||
RAT.ATC.flight[name].holding=0
|
||||
end
|
||||
@ -5514,7 +5514,7 @@ function RAT:_ATCStatus()
|
||||
|
||||
-- Aircraft is holding.
|
||||
local text=string.format("ATC %s: Flight %s is holding for %i:%02d. %s.", dest, name, hold/60, hold%60, busy)
|
||||
self:T(RAT.id..text)
|
||||
BASE:T(RAT.id..text)
|
||||
|
||||
elseif hold==RAT.ATC.onfinal then
|
||||
|
||||
@ -5522,7 +5522,7 @@ function RAT:_ATCStatus()
|
||||
local Tfinal=Tnow-RAT.ATC.flight[name].Tonfinal
|
||||
|
||||
local text=string.format("ATC %s: Flight %s is on final. Waiting %i:%02d for landing event.", dest, name, Tfinal/60, Tfinal%60)
|
||||
self:T(RAT.id..text)
|
||||
BASE:T(RAT.id..text)
|
||||
|
||||
elseif hold==RAT.ATC.unregistered then
|
||||
|
||||
@ -5530,7 +5530,7 @@ function RAT:_ATCStatus()
|
||||
--self:T(string.format("ATC %s: Flight %s is not registered yet (hold %d).", dest, name, hold))
|
||||
|
||||
else
|
||||
self:E(RAT.id.."ERROR: Unknown holding time in RAT:_ATCStatus().")
|
||||
BASE:E(RAT.id.."ERROR: Unknown holding time in RAT:_ATCStatus().")
|
||||
end
|
||||
end
|
||||
|
||||
@ -5572,12 +5572,12 @@ function RAT:_ATCCheck()
|
||||
|
||||
-- Debug message.
|
||||
local text=string.format("ATC %s: Flight %s runway is busy. You are #%d of %d in landing queue. Your holding time is %i:%02d.", name, flight,qID, nqueue, RAT.ATC.flight[flight].holding/60, RAT.ATC.flight[flight].holding%60)
|
||||
self:T(RAT.id..text)
|
||||
BASE:T(RAT.id..text)
|
||||
|
||||
else
|
||||
|
||||
local text=string.format("ATC %s: Flight %s was cleared for landing. Your holding time was %i:%02d.", name, flight, RAT.ATC.flight[flight].holding/60, RAT.ATC.flight[flight].holding%60)
|
||||
self:T(RAT.id..text)
|
||||
BASE:T(RAT.id..text)
|
||||
|
||||
-- Clear flight for landing.
|
||||
RAT:_ATCClearForLanding(name, flight)
|
||||
@ -5706,11 +5706,6 @@ function RAT:_ATCQueue()
|
||||
table.insert(RAT.ATC.airport[airport].queue, v[1])
|
||||
end
|
||||
|
||||
--fvh
|
||||
--for k,v in ipairs(RAT.ATC.airport[airport].queue) do
|
||||
--print(string.format("queue #%02i flight \"%s\" holding %d seconds",k, v, RAT.ATC.flight[v].holding))
|
||||
--end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -69,6 +69,7 @@
|
||||
-- @field #boolean autosave Automatically save assets to file when mission ends.
|
||||
-- @field #string autosavepath Path where the asset file is saved on auto save.
|
||||
-- @field #string autosavefilename File name of the auto asset save file. Default is auto generated from warehouse id and name.
|
||||
-- @field #boolean safeparking If true, parking spots for aircraft are considered as occupied if e.g. a client aircraft is parked there. Default false.
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- Have your assets at the right place at the right time - or not!
|
||||
@ -1556,6 +1557,7 @@ WAREHOUSE = {
|
||||
autosave = false,
|
||||
autosavepath = nil,
|
||||
autosavefile = nil,
|
||||
saveparking = false,
|
||||
}
|
||||
|
||||
--- Item of the warehouse stock table.
|
||||
@ -2364,6 +2366,24 @@ function WAREHOUSE:SetReportOff()
|
||||
return self
|
||||
end
|
||||
|
||||
--- Enable safe parking option, i.e. parking spots at an airbase will be considered as occupied when a client aircraft is parked there (even if the client slot is not taken by a player yet).
|
||||
-- Note that also incoming aircraft can reserve/occupie parking spaces.
|
||||
-- @param #WAREHOUSE self
|
||||
-- @return #WAREHOUSE self
|
||||
function WAREHOUSE:SetSafeParkingOn()
|
||||
self.safeparking=true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Disable safe parking option. Note that is the default setting.
|
||||
-- @param #WAREHOUSE self
|
||||
-- @return #WAREHOUSE self
|
||||
function WAREHOUSE:SetSafeParkingOff()
|
||||
self.safeparking=false
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set interval of status updates. Note that normally only one request can be processed per time interval.
|
||||
-- @param #WAREHOUSE self
|
||||
-- @param #number timeinterval Time interval in seconds.
|
||||
@ -7004,20 +7024,6 @@ function WAREHOUSE:_FindParkingForAssets(airbase, assets)
|
||||
table.insert(obstacles,{coord=_coord, size=_size, name=_name, type="scenery"})
|
||||
end
|
||||
|
||||
--[[
|
||||
-- TODO Clients? Unoccupied client aircraft are also important! Are they already included in scanned units maybe?
|
||||
local clients=_DATABASE.CLIENTS
|
||||
for _,_client in pairs(clients) do
|
||||
local client=_client --Wrapper.Client#CLIENT
|
||||
env.info(string.format("FF Client name %s", client:GetName()))
|
||||
local unit=UNIT:FindByName(client:GetName())
|
||||
--local unit=client:GetClientGroupUnit()
|
||||
local _coord=unit:GetCoordinate()
|
||||
local _name=unit:GetName()
|
||||
local _size=self:_GetObjectSize(client:GetClientGroupDCSUnit())
|
||||
table.insert(obstacles,{coord=_coord, size=_size, name=_name, type="client"})
|
||||
end
|
||||
]]
|
||||
end
|
||||
|
||||
-- Parking data for all assets.
|
||||
@ -7051,9 +7057,16 @@ function WAREHOUSE:_FindParkingForAssets(airbase, assets)
|
||||
|
||||
--env.info(string.format("FF asset=%s (id=%d): needs terminal type=%d, id=%d, #obstacles=%d", _asset.templatename, _asset.uid, terminaltype, _termid, #obstacles))
|
||||
|
||||
-- Loop over all obstacles.
|
||||
local free=true
|
||||
local problem=nil
|
||||
|
||||
-- Safe parking using TO_AC from DCS result.
|
||||
if self.safeparking and _toac then
|
||||
free=false
|
||||
self:T("Parking spot %d is occupied by other aircraft taking off or landing.", _termid)
|
||||
end
|
||||
|
||||
-- Loop over all obstacles.
|
||||
for _,obstacle in pairs(obstacles) do
|
||||
|
||||
-- Check if aircraft overlaps with any obstacle.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user