Ops FlightGroup & FlightControl

This commit is contained in:
Frank
2019-11-09 15:19:11 +01:00
parent 0db24006e1
commit 880fae604d
4 changed files with 171 additions and 107 deletions
@@ -5606,7 +5606,7 @@ function WAREHOUSE:_SpawnAssetAircraft(alias, asset, request, parking, uncontrol
self:T2({airtemplate=template})
-- Create a flight group.
FLIGHTGROUP:New(template.name)
--FLIGHTGROUP:New(template.name)
-- Spawn group.
local group=_DATABASE:Spawn(template) --Wrapper.Group#GROUP
@@ -5823,7 +5823,7 @@ function WAREHOUSE:_RouteAir(aircraft)
local fc=_DATABASE:GetFlightControl(self.airbasename)
if fc then
--local flightgroup=FLIGHTGROUP:New(aircraft:GetName())
-- Nothing to do. FC will start the aircraft once it gets taxi clearance.
else
aircraft:StartUncontrolled(starttime)
end
+7
View File
@@ -1655,6 +1655,13 @@ end
-- Misc Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Get runway from user supplied magnetic heading.
-- @param #ATIS self
-- @return #string Runway magnetic heading divided by ten (and rounded). Eg, "13" for 130°.
function ATIS:GetActiveRunway()
end
--- Get runway from user supplied magnetic heading.
-- @param #ATIS self
-- @param #number windfrom Wind direction (from) in degrees.
+107 -76
View File
@@ -33,6 +33,7 @@
-- @field #number activerwyno Number of active runway.
-- @field #number atcfreq ATC radio frequency.
-- @field Core.RadioQueue#RADIOQUEUE atcradio ATC radio queue.
-- @field #table playermenu Player Menu.
-- @extends Core.Fsm#FSM
--- Be surprised!
@@ -66,6 +67,7 @@ FLIGHTCONTROL = {
atcfreq = nil,
atcradio = nil,
atcradiounitname = nil,
playermenu = nil,
}
--- Holding point
@@ -75,6 +77,11 @@ FLIGHTCONTROL = {
-- @field #number angelsmin Smallest holding altitude in angels.
-- @field #number angelsmax Largest holding alitude in angels.
--- Player menu data.
-- @type FLIGHTCONTROL.PlayerMenu
-- @field Core.Menu#MENU_GROUP root Root menu.
-- @field Core.Menu#MENU_GROUP_COMMAND RequestTaxi Request taxi.
--- Parking spot data.
-- @type FLIGHTCONTROL.ParkingSpot
-- @field #number index Parking index.
@@ -95,7 +102,7 @@ FLIGHTCONTROL = {
--- FlightControl class version.
-- @field #string version
FLIGHTCONTROL.version="0.0.6"
FLIGHTCONTROL.version="0.0.7"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@@ -122,14 +129,17 @@ function FLIGHTCONTROL:New(airbasename)
-- Inherit everything from FSM class.
local self=BASE:Inherit(self, FSM:New()) -- #FLIGHTCONTROL
-- Try to get the airbase.
self.airbase=AIRBASE:FindByName(airbasename)
-- Check if the airbase exists.
if not self.airbase then
self:E(string.format("ERROR: Could not find airbase %s!", tostring(airbasename)))
return nil
end
-- Check if airbase is an airdrome.
if self.airbase:GetAirbaseCategory()~=Airbase.Category.AIRDROME then
self:E(string.format("ERROR: Airbase %s is not an AIRDROMOE! Script does not handle FARPS or ships.", tostring(airbasename)))
self:E(string.format("ERROR: Airbase %s is not an AIRDROME! Script does not handle FARPS or ships.", tostring(airbasename)))
return nil
end
@@ -154,6 +164,8 @@ function FLIGHTCONTROL:New(airbasename)
-- Init parking spots.
self:_InitParkingSpots()
self.playermenu={}
-- Start State.
self:SetStartState("Stopped")
@@ -168,7 +180,6 @@ function FLIGHTCONTROL:New(airbasename)
BASE:TraceOnOff(true)
BASE:TraceClass(self.ClassName)
BASE:TraceLevel(1)
--self.dTstatus=0.1
end
-- Add to data base.
@@ -236,7 +247,7 @@ function FLIGHTCONTROL:onafterStart()
self:HandleEvent(EVENTS.EngineShutdown)
self:HandleEvent(EVENTS.Crash)
self.atcradio=RADIOQUEUE:New(self.atcfreq or 305)
self.atcradio=RADIOQUEUE:New(self.atcfreq or 305, nil, string.format("FC %s", self.airbasename))
self.atcradio:Start(1, 0.01)
-- Init status updates.
@@ -265,7 +276,7 @@ function FLIGHTCONTROL:onafterStatus()
local nfree=self:_GetFreeParkingSpots()
-- Info text.
local text=string.format("State %s - Active Runway %s - Free Parking %d", self:GetState(), runway.idx, nfree)
local text=string.format("State %s - Runway %s - Parking %d/%d - Qpark=%d Qtakeoff=%d Qland=%d Qhold=%d", self:GetState(), runway.idx, nfree, #self.parking, #self.Qparking, #self.Qtakeoff, #self.Qlanding, #self.Qwaiting)
self:I(self.lid..text)
-- Next status update in ~30 seconds.
@@ -282,8 +293,15 @@ end
function FLIGHTCONTROL:OnEventBirth(EventData)
self:F3({EvendData=EventData})
self:T2(self.lid..string.format("BIRTH: unit = %s", tostring(EventData.IniUnitName)))
self:T2(self.lid..string.format("BIRTH: group = %s", tostring(EventData.IniGroupName)))
self:I(self.lid..string.format("BIRTH: unit = %s", tostring(EventData.IniUnitName)))
self:I(self.lid..string.format("BIRTH: group = %s", tostring(EventData.IniGroupName)))
if EventData and EventData.IniGroupName and EventData.Place and EventData.Place:GetName()==self.airbasename then
-- We delay this, to have all elements of the group in the game.
self:ScheduleOnce(0.1, self._CreateFlightGroup, self, EventData.IniGroup)
end
end
@@ -407,21 +425,34 @@ function FLIGHTCONTROL:_CheckQueues()
-- Message.
local text=string.format("Flight %s, you are cleared to land.", flight.groupname)
MESSAGE:New(text, 5, "FLIGHTCONTROL"):ToAll()
flight:FlightLanding()
self:_LandAI(flight)
-- Give AI the landing signal.
-- TODO: Humans have to confirm via F10 menu.
if flight.ai then
flight:FlightLanding()
self:_LandAI(flight)
end
else
-- Message.
local text=string.format("Flight %s, you are cleared to taxi to runway.", flight.groupname)
MESSAGE:New(text, 5, "FLIGHTCONTROL"):ToAll()
-- Check if flight is AI. Humans have to request taxi via F10 menu.
if flight.ai then
flight.group:StartUncontrolled()
flight:_UpdateRoute(1)
self:_RemoveFlightFromQueue(self.Qparking, flight, "parking")
-- Message.
-- TODO: Which runway!
local text=string.format("Flight %s, you are cleared to taxi to runway.", flight.groupname)
self:I(self.lid..text)
MESSAGE:New(text, 5, "FLIGHTCONTROL"):ToAll()
flight.group:StartUncontrolled()
flight:_UpdateRoute(1)
self:_RemoveFlightFromQueue(self.Qparking, flight, "parking")
self:_AddFlightToTakeoffQueue(flight)
end
end
@@ -512,9 +543,9 @@ function FLIGHTCONTROL:_GetNextFightHolding()
-- Return flight waiting longest.
table.sort(self.Qwaiting, _sortByTholding)
table.sort(self.Qwaiting, _sortByTholding)
return self.Qwaiting[1]
end
@@ -886,6 +917,52 @@ end
-- ATC Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Human Player Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create player menu.
-- @param #FLIGHTCONTROL self
-- @param Ops.FlightGroup#FLIGHTGROUP flight Flight group.
function FLIGHTCONTROL:_CreatePlayerMenu(flight)
local group=flight.group
local gid=group:GetID()
if not self.playermenu[gid] then
self.playermenu[gid]={}
end
local playermenu=self.playermenu[gid] --#FLIGHTCONTROL.PlayerMenu
group:SmokeRed()
playermenu.root=MENU_GROUP:New(group, "ATC")
playermenu.RequestTaxi=MENU_GROUP_COMMAND:New(group, "Request Taxi", playermenu.root, self._PlayerRequestTaxi, flight.groupname)
end
--- Create player menu.
-- @param #FLIGHTCONTROL self
-- @param #string groupname Name of the flight group.
function FLIGHTCONTROL:_PlayerRequestTaxi(groupname)
MESSAGE:New("Request taxi to runway", 5):ToAll()
MESSAGE:New("You are cleared to taxi", 5):ToAll()
local flight=_DATABASE:GetFlightGroup(groupname)
if flight then
for _,_element in pairs(flight.elements) do
local element=_element --Ops.FlightGroup#FLIGHTGROUP.Element
flight:ElementTaxiing(element)
end
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Flight and Element Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -898,6 +975,7 @@ function FLIGHTCONTROL:_CreateFlightGroup(group)
-- Check if not already in flights
if self:_InQueue(self.flights, group) then
self:E(self.lid..string.format("WARNING: Flight group %s does already exist!", group:GetName()))
return
end
@@ -915,64 +993,17 @@ function FLIGHTCONTROL:_CreateFlightGroup(group)
if flight.destination and flight.destination:GetName()==self.airbasename then
flight:SetFlightControl(self)
end
--[[
-- New flight.
local flight={} --Ops.FlightGroup#FLIGHTGROUP
-- Flight group name
local groupname=group:GetName()
local human, playername=self:_IsHuman(group)
-- Queue table item.
flight.group=group
flight.groupname=group:GetName()
flight.nunits=#group:GetUnits()
flight.time=timer.getAbsTime()
flight.dist0=group:GetCoordinate():Get2DDistance(self:GetCoordinate())
flight.flag=-100
flight.ai=not human
flight.actype=group:GetTypeName()
flight.onboardnumbers=self:_GetOnboardNumbers(group)
flight.inzone=flight.group:IsCompletelyInZone(self.zoneAirbase)
flight.holding=nil
-- Flight elements.
local text=string.format("Flight elements of group %s:", flight.groupname)
flight.elements={}
local units=group:GetUnits()
for i,_unit in pairs(units) do
local unit=_unit --Wrapper.Unit#UNIT
local element={} --#FLIGHTCONTROL.FlightElement
element.unit=unit
element.unitname=unit:GetName()
element.onboard=flight.onboardnumbers[element.unitname]
element.sizemax=unit:GetObjectSize()
element.ai=not self:_IsHumanUnit(unit)
-- Debug text.
text=text..string.format("\n[%d] %s onboard #%s, AI=%s", i, element.unitname, tostring(element.onboard), tostring(element.ai))
-- Add to table.
table.insert(flight.elements, element)
end
self:T(self.lid..text)
-- Onboard.
if flight.ai then
local onboard=flight.onboardnumbers[flight.seclead]
flight.onboard=onboard
else
flight.onboard=self:_GetOnboardNumberPlayer(group)
end
]]
-- Add to known flights.
table.insert(self.flights, flight)
-- Create player menu.
if flight.ai then
self:E("FF AI no player menu")
else
self:E("FF Not purly AI ==> player menu")
self:_CreatePlayerMenu(flight)
end
return flight
end
+55 -29
View File
@@ -342,7 +342,7 @@ function FLIGHTGROUP:New(groupname)
-- Debug trace.
if false then
if true then
self.Debug=true
BASE:TraceOnOff(true)
BASE:TraceClass(self.ClassName)
@@ -362,7 +362,8 @@ function FLIGHTGROUP:New(groupname)
_DATABASE:AddFlightGroup(self)
-- Autostart.
self:__Start(0.1)
--self:__Start(0.1)
self:Start()
return self
end
@@ -664,19 +665,25 @@ function FLIGHTGROUP:onafterStart(From, Event, To)
if group and group:IsAlive() then
-- Set group object.
env.info("FF setting self.group object")
self.group=group
-- Get units of group.
local units=group:GetUnits()
-- Debug info.
self:I(self.sid..string.format("FF Found alive group %s at start with %d units", group:GetName(), #units))
for _,_unit in pairs(units) do
local unit=_unit --Wrapper.Unit#UNIT
-- Add elemets.
for _,unit in pairs(units) do
local element=self:AddElementByName(unit:GetName())
-- Trigger Spawned event.
self:ElementSpawned(element)
end
-- Trigger spawned event for all elements.
for _,element in pairs(self.elements) do
self:ElementSpawned(element)
end
end
-- Handle events:
@@ -866,9 +873,9 @@ function FLIGHTGROUP:OnEventBirth(EventData)
element=self:AddElementByName(unitname)
end
self:T3(self.sid..string.format("EVENT: Element %s born ==> spawned", element.name))
self:ElementSpawned(element)
-- Set element to spawned state.
self:T(self.sid..string.format("EVENT: Element %s born ==> spawned", element.name))
self:ElementSpawned(element)
end
@@ -890,9 +897,15 @@ function FLIGHTGROUP:OnEventEngineStartup(EventData)
if element then
if self:IsAirborne() or self:IsHolding() then
-- TODO: what?
else
self:T3(self.sid..string.format("EVENT: Element %s started engines ==> taxiing", element.name))
self:ElementTaxiing(element)
self:T(self.sid..string.format("EVENT: Element %s started engines ==> taxiing (if AI)", element.name))
-- TODO: could be that this element is part of a human flight group.
-- Problem: when player starts hot, the AI does too and starts to taxi immidiately :(
-- when player starts cold, ?
if self.ai then
self:ElementTaxiing(element)
end
end
end
@@ -1186,7 +1199,7 @@ end
-- @param #string Event Event.
-- @param #string To To state.
function FLIGHTGROUP:onafterFlightSpawned(From, Event, To)
self:I("FF Flight group spawned!")
self:I(string.format("FF Flight group %s spawned!", tostring(self.groupname)))
-- Get template of group.
self.template=self.group:GetTemplate()
@@ -1202,17 +1215,23 @@ function FLIGHTGROUP:onafterFlightSpawned(From, Event, To)
self.ceiling=self.descriptors.Hmax
self.ai=self:_IsHuman(self.group)
self.ai=not self:_IsHuman(self.group)
for _,_element in pairs(self.elements) do
local element=_element --#FLIGHTGROUP.Element
element.ai=self:_IsHumanUnit(element.unit)
element.ai=self:_IsHumanUnit(element.unit)
end
-- Init waypoints.
if not self.waypoints then
self:InitWaypoints()
end
if not self.ai then
if self.flightcontrol then
--self.flightcontrol:_CreatePlayerMenu(self)
end
end
end
@@ -2045,6 +2064,9 @@ function FLIGHTGROUP:AddElementByName(unitname)
element.ai=true
end
local text=string.format("Adding element %s: status=%s, skill=%s, modex=%s, fuelmass=%.1f, category=%d, categoryname=%s, callsign=%s, ai=%s",
element.name, element.status, element.skill, element.modex, element.fuelmass, element.category, element.categoryname, element.callsign, tostring(element.ai))
self:I(self.sid..text)
-- Add element to table.
table.insert(self.elements, element)
@@ -2203,6 +2225,7 @@ end
-- @param #table wp Waypoint table.
-- @return Core.Point#COORDINATE Coordinate of the next waypoint.
function FLIGHTGROUP:GetWaypointCoordinate(wp)
-- TODO: move this to COORDINATE class.
return COORDINATE:New(wp.x, wp.alt, wp.y)
end
@@ -2239,7 +2262,7 @@ function FLIGHTGROUP:_UpdateRoute(n)
-- Get destination airbase from waypoints.
self.destination=self:GetDestinationFromWaypoints() or self.destination
if self.destination and #wp>0 and _DATABASE:GetFlightControl(self.destination:GetName())then
if self.destination and #wp>0 and _DATABASE:GetFlightControl(self.destination:GetName()) then
-- Task to hold.
local TaskOverhead=self.group:TaskFunction("FLIGHTGROUP._DestinationOverhead", self, self.destination)
@@ -2493,16 +2516,18 @@ function FLIGHTGROUP:_AllSimilarStatus(status)
if status==FLIGHTGROUP.ElementStatus.SPAWNED then
-- Element SPAWNED: Nothing to check.
if element.status~=status then
-- Element SPAWNED: Check that others are not still IN UTERO
if element.status~=status and
element.status==FLIGHTGROUP.ElementStatus.INUTERO then
return false
end
elseif status==FLIGHTGROUP.ElementStatus.PARKING then
-- Element PARKING: Check that the other are not stil SPAWNED
if element.status~=status and
element.status==FLIGHTGROUP.ElementStatus.SPAWNED then
if element.status~=status or
(element.status==FLIGHTGROUP.ElementStatus.INUTERO or
element.status==FLIGHTGROUP.ElementStatus.SPAWNED) then
return false
end
@@ -2510,7 +2535,8 @@ function FLIGHTGROUP:_AllSimilarStatus(status)
-- Element TAXIING: Check that the other are not stil SPAWNED or PARKING
if element.status~=status and
(element.status==FLIGHTGROUP.ElementStatus.SPAWNED or
(element.status==FLIGHTGROUP.ElementStatus.INUTERO or
element.status==FLIGHTGROUP.ElementStatus.SPAWNED or
element.status==FLIGHTGROUP.ElementStatus.PARKING) then
return false
end
@@ -2519,7 +2545,8 @@ function FLIGHTGROUP:_AllSimilarStatus(status)
-- Element TAKEOFF: Check that the other are not stil SPAWNED, PARKING or TAXIING
if element.status~=status and
(element.status==FLIGHTGROUP.ElementStatus.SPAWNED or
(element.status==FLIGHTGROUP.ElementStatus.INUTERO or
element.status==FLIGHTGROUP.ElementStatus.SPAWNED or
element.status==FLIGHTGROUP.ElementStatus.PARKING or
element.status==FLIGHTGROUP.ElementStatus.TAXIING) then
self:T(self.sid..string.format("Status=%s, element %s status=%s ==> returning FALSE", status, element.name, element.status))
@@ -2530,7 +2557,8 @@ function FLIGHTGROUP:_AllSimilarStatus(status)
-- Element AIRBORNE: Check that the other are not stil SPAWNED, PARKING, TAXIING or TAKEOFF
if element.status~=status and
(element.status==FLIGHTGROUP.ElementStatus.SPAWNED or
(element.status==FLIGHTGROUP.ElementStatus.INUTERO or
element.status==FLIGHTGROUP.ElementStatus.SPAWNED or
element.status==FLIGHTGROUP.ElementStatus.PARKING or
element.status==FLIGHTGROUP.ElementStatus.TAXIING or
element.status==FLIGHTGROUP.ElementStatus.TAKEOFF) then
@@ -2564,7 +2592,7 @@ function FLIGHTGROUP:_AllSimilarStatus(status)
end
self:T(self.sid..string.format("Status=%s ==> returning TRUE", status))
self:T(self.sid..string.format("All similar status %s ==> returning TRUE", status))
return true
end
@@ -2582,8 +2610,6 @@ function FLIGHTGROUP:_UpdateStatus(element, newstatus, airbase)
-- Update status of element.
element.status=newstatus
local group=element.group
if newstatus==FLIGHTGROUP.ElementStatus.SPAWNED then
---
-- SPAWNED