This commit is contained in:
Frank
2019-09-11 20:09:55 +02:00
parent af3bf7dece
commit a3067740a3
6 changed files with 385 additions and 216 deletions
+3 -3
View File
@@ -621,7 +621,7 @@ do -- SETTINGS
local text="Messages and Reports"
if self.MenuShort then
text="Messages"
text="Messages & Reports"
end
local MessagesMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
@@ -848,9 +848,9 @@ do -- SETTINGS
local text="Messages and Reports"
if self.MenuShort then
text="Messages"
text="Messages & Reports"
end
local MessagesMenu = MENU_GROUP:New( PlayerGroup, "Messages and Reports", PlayerMenu )
local MessagesMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
local UpdateMessagesMenu = MENU_GROUP:New( PlayerGroup, "Update Messages", MessagesMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "Off", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 0 )
+60 -145
View File
@@ -1,4 +1,4 @@
--- **ATC** - (R2.5) - Manage recovery of aircraft at airdromes and FARPS.
--- **OPS** - (R2.5) - Manage recovery of aircraft at airdromes and FARPS.
--
--
--
@@ -9,8 +9,8 @@
-- ===
--
-- ### Author: **funkyfranky**
-- @module ATC.FlightControl
-- @image ATC_FlightControl.png
-- @module OPS.FlightControl
-- @image OPS_FlightControl.png
--- FLIGHTCONTROL class.
@@ -156,6 +156,9 @@ function FLIGHTCONTROL:New(airbasename)
BASE:TraceLevel(1)
--self.dTstatus=0.1
end
-- Add to data base.
_DATABASE:AddFlightControl(self)
return self
end
@@ -458,36 +461,6 @@ function FLIGHTCONTROL:OnEventTakeoff(EventData)
return
end
-- Get airbase name.
local airbasename=tostring(airbase:GetName())
-- Check if landed at this airbase.
if airbasename==self.airbasename then
-- AI always lands ==> remove unit from flight group and queues.
local flight=self:_ElementTookOff(unit)
if flight then
self:T(self.lid..string.format("Flight element %s took off.", EventData.IniUnitName))
-- Check if everybody is in the air.
local all=true
for _,_elem in pairs(flight.elements) do
local element=_elem --#FLIGHTCONTROL.FlightElement
if not element.tookoff then
all=false
end
end
-- Remove flight.
if all then
self:T(self.lid..string.format("Flight group %s took off.", flight.groupname))
self:_RemoveFlightFromQueue(self.Qtakeoff, flight)
end
end
end
end
--- Event handler for event engine startup.
@@ -506,17 +479,7 @@ function FLIGHTCONTROL:OnEventEngineStartup(EventData)
if not unit then
return
end
-- Get flight element.
local element, idx, flight=self:_GetFlightElement(EventData.IniUnitName)
if element then
local parkingspot=self:_GetElementParkingSpot(element)
if parkingspot then
self:_AddFlightToTakeoffQueue(flight)
end
end
end
--- Event handler for event engine shutdown.
@@ -541,22 +504,12 @@ end
--- Event handler for event crash.
-- @param #FLIGHTCONTROL self
-- @param Core.Event#EVENTDATA EventData
function FLIGHTCONTROL:OnEventEngineCrash(EventData)
function FLIGHTCONTROL:OnEventCrash(EventData)
self:F3({EvendData=EventData})
self:T2(self.lid..string.format("CRASH: unit = %s", tostring(EventData.IniUnitName)))
self:T2(self.lid..string.format("CRASH: group = %s", tostring(EventData.IniGroupName)))
-- Unit that took off.
local unit=EventData.IniUnit
-- Nil check for unit.
if not unit then
return
end
self:_RemoveFlightElement(EventData.IniUnitName)
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -617,9 +570,7 @@ function FLIGHTCONTROL:_CheckParking()
for _,_element in pairs(_flight.elements) do
local element=_element --Ops.FlightGroup#FLIGHTGROUP.Element
local unit=element.unit
if unit and unit:IsAlive() then
if element.unit and element.unit:IsAlive() then
-- Distance to parking spot.
local dist=element.unit:GetCoordinate():Get3DDistance(spot.position)
@@ -632,7 +583,6 @@ function FLIGHTCONTROL:_CheckParking()
else
self:E(self.lid..string.format("ERROR: Element %s is not alive any more!", element.unitname))
self:_RemoveFlightElement(element.unitname)
end
end
@@ -651,19 +601,9 @@ function FLIGHTCONTROL:_GetNextWaitingFight()
for _,_flight in pairs(self.Qwaiting) do
local flight=_flight --Ops.FlightGroup#FLIGHTGROUP
-- Current stack.
local stack=flight.flag
-- TODO: Sort by fuel, holding time.
-- Total marshal time in seconds.
local Tmarshal=timer.getAbsTime()-flight.time
-- Min time in marshal stack.
local TmarshalMin=3*60 --Three minutes for human players.
-- Check if conditions are right.
if flight.holding~=nil and Tmarshal>=TmarshalMin then
return flight
end
return flight
end
@@ -687,12 +627,12 @@ function FLIGHTCONTROL:_PrintQueue(queue, name)
local flight=_flight --Ops.FlightGroup#FLIGHTGROUP
-- Gather info.
local clock=UTILS.SecondsToClock(timer.getAbsTime()-flight.time)
local clock="0:0" --UTILS.SecondsToClock(timer.getAbsTime()-flight.time)
local fuel=flight.group:GetFuelMin()*100
local ai=tostring(flight.ai)
local actype=flight.actype
local actype=tostring(flight.actype)
local holding=tostring(flight.holding)
local nunits=flight.nunits
local nunits=flight.nunits or 1
-- Main info.
text=text..string.format("\n[%d] %s (%s*%d): ai=%s, timestamp=%s, fuel=%d, inzone=%s, holding=%s",
@@ -700,11 +640,11 @@ function FLIGHTCONTROL:_PrintQueue(queue, name)
-- Elements info.
for j,_element in pairs(flight.elements) do
local element=_element --#FLIGHTCONTROL.FlightElement
local element=_element --Ops.FlightGroup#FLIGHTGROUP.Element
local life=element.unit:GetLife()
local life0=element.unit:GetLife0()
text=text..string.format("\n (%d) %s (%s): ai=%s, parking=%s, recovered=%s, tookoff=%s, airborne=%s life=%.1f/%.1f",
j, element.onboard, element.unitname, tostring(element.ai), tostring(element.parking), tostring(element.recovered), tostring(element.tookoff), tostring(element.unit:InAir()), life, life0)
text=text..string.format("\n (%d) %s (%s): ai=%s, status=%s,, airborne=%s life=%.1f/%.1f",
j, tostring(element.modex), element.name, tostring(element.ai) ,tostring(element.status), tostring(element.unit:InAir()), life, life0)
end
end
end
@@ -727,12 +667,13 @@ function FLIGHTCONTROL:_RemoveFlightFromQueue(queue, flight)
-- Check for name.
if qflight.groupname==flight.groupname then
self:T(self.lid..string.format("Removing flight group %s from queue.", flight.groupname))
self:I(self.lid..string.format("Removing flight group %s from queue.", flight.groupname))
table.remove(queue, i)
return true, i
end
end
self:I(self.lid..string.format("Could NOT remove flight group %s from queue.", flight.groupname))
return false, nil
end
@@ -822,7 +763,7 @@ end
-- Flight and Element Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new flight group. Usually when a flight appears in the CCA.
--- Create a new flight group.
-- @param #FLIGHTCONTROL self
-- @param Wrapper.Group#GROUP group Aircraft group.
-- @return Ops.FlightGroup#FLIGHTGROUP Flight group.
@@ -834,7 +775,20 @@ function FLIGHTCONTROL:_CreateFlightGroup(group)
end
-- Debug info.
self:T(self.lid..string.format("Creating new flight for group %s of aircraft type %s.", group:GetName(), group:GetTypeName()))
self:I(self.lid..string.format("Creating new flight for group %s of aircraft type %s.", group:GetName(), group:GetTypeName()))
-- Get flightgroup from data base.
local flight=_DATABASE:GetFlightGroup(group:GetName())
-- If it does not exist yet, create one.
if not flight then
flight=FLIGHTGROUP:New(group:GetName())
flight:__Start(1)
end
flight:SetFlightControl(self)
--[[
-- New flight.
local flight={} --Ops.FlightGroup#FLIGHTGROUP
@@ -887,6 +841,8 @@ function FLIGHTCONTROL:_CreateFlightGroup(group)
flight.onboard=self:_GetOnboardNumberPlayer(group)
end
]]
-- Add to known flights.
table.insert(self.flights, flight)
@@ -958,24 +914,6 @@ function FLIGHTCONTROL:_GetFlightElement(unitname)
return nil, nil, nil
end
--- Remove element from flight.
-- @param #FLIGHTCONTROL self
-- @param #string unitname Name of the unit.
-- @return #boolean If true, element could be removed or nil otherwise.
function FLIGHTCONTROL:_RemoveFlightElement(unitname)
-- Get table index.
local element,idx, flight=self:_GetFlightElement(unitname)
if idx then
table.remove(flight.elements, idx)
return true
else
self:T("WARNING: Flight element could not be removed from flight group. Index=nil!")
return nil
end
end
--- Get parking spot of flight element.
-- @param #FLIGHTCONTROL self
-- @param Ops.FlightGroup#FLIGHTGROUP.Element element Element of flight group.
@@ -1040,12 +978,12 @@ function FLIGHTCONTROL:_CheckInbound()
local unit=_unit --Wrapper.Unit#UNIT
-- Necessary conditions to be met:
local airborne=unit:IsAir()
local aircraft=unit:IsAir()
local inzone=unit:IsInZone(self.zoneAirbase)
local friendly=self:GetCoalition()==unit:GetCoalition()
-- Check if this an aircraft and that it is airborne and closing in.
if airborne and inzone and friendly then
-- Check if this an aircraft and that it is inside the airbase zone and friendly.
if aircraft and inzone and friendly then
local group=unit:GetGroup()
local groupname=group:GetName()
@@ -1058,7 +996,7 @@ function FLIGHTCONTROL:_CheckInbound()
end
end
-- Find new flights that are inside CCA.
-- Find new flights that are inside the airbase zone.
for groupname,_group in pairs(insideZone) do
local group=_group --Wrapper.Group#GROUP
self:_CreateFlightGroup(group)
@@ -1067,47 +1005,16 @@ function FLIGHTCONTROL:_CheckInbound()
for _,_flight in pairs(self.flights) do
local flight=_flight --Ops.FlightGroup#FLIGHTGROUP
local inzone=flight.group:IsCompletelyInZone(self.zoneAirbase)
if inzone and not flight.inzone then
flight.inzone=true
flight.dist0=flight.group:GetCoordinate():Get2DDistance(self:GetCoordinate())
end
-- Set currently in zone or not.
flight.inzone=inzone
end
for _,_flight in pairs(self.flights) do
local flight=_flight --Ops.FlightGroup#FLIGHTGROUP
--TODO: Check if aircraft has a landing waypoint for this airbase.
-- Get distance to carrier.
local dist=flight.group:GetCoordinate():Get2DDistance(self:GetCoordinate())
-- Close in distance. Is >0 if AC comes closer wrt to first detected distance d0.
local closein=flight.dist0-dist
-- TODO refine for current case.
-- Flight closed in.
if closein>UTILS.NMToMeters(5) and flight.group:IsAirborne(true) then
-- Debug info.
self:T3(self.lid..string.format("AI flight group %s closed in by %.1f NM", flight.groupname, UTILS.MetersToNM(closein)))
-- Send AI to orbit outside 10 NM zone and wait until the next Marshal stack is available.
if flight and flight.destination and flight.destination:GetName()==self.airbasename then
-- Send AI to orbit outside 10 NM zone and wait until the next Marshal stack is available.
if not (self:_InQueue(self.Qwaiting, flight.group) or self:_InQueue(self.Qlanding, flight.group)) then
self:_WaitAI(flight, 1, true)
end
-- Break the loop to not have all flights at once! Spams the message screen.
break
end
end
end
end
end
@@ -1124,6 +1031,17 @@ function FLIGHTCONTROL:_WaitAI(flight, stack, respawn)
-- Add AI flight to waiting queue.
table.insert(self.Qwaiting, flight)
-- Holding point.
local holding=self:_GetHoldingpoint(flight)
local altitude=holding.pos0.y
local angels=UTILS.MetersToFeet(altitude)/1000
flight:Hold(holding, altitude)
if true then
return
end
-- Flight group name.
local group=flight.group
local groupname=flight.groupname
@@ -1154,10 +1072,7 @@ function FLIGHTCONTROL:_WaitAI(flight, stack, respawn)
-- Task function when arriving at the holding zone. This will set flight.holding=true.
local TaskHolding=flight.group:TaskFunction("FLIGHTCONTROL._ReachedHoldingZone", self, flight)
-- Holding point.
local holding=self:_GetHoldingpoint(flight)
local altitude=holding.pos0.y
local angels=UTILS.MetersToFeet(altitude)/1000
-- Set orbit task.
local TaskOrbit=group:TaskOrbit(holding.pos0, altitude, speedOrbitMps, holding.pos1)
+286 -55
View File
@@ -40,6 +40,7 @@
-- @field #boolean fuelcriticalrtb RTB on critical fuel switch.
-- @field Ops.Squadron#SQUADRON squadron The squadron the flight group belongs to.
-- @field Ops.FlightControl#FLIGHTCONTROL flightcontrol The flightcontrol handling this group.
-- @field Core.UserFlag#USERFLAG flaghold Flag for holding.
-- @extends Core.Fsm#FSM
--- Be surprised!
@@ -81,6 +82,7 @@ FLIGHTGROUP = {
fuelcriticalrtb = false,
squadron = nil,
flightcontrol = nil,
flaghold = nil,
}
@@ -90,7 +92,8 @@ FLIGHTGROUP = {
-- @field #string SPAWNED Element was spawned into the world.
-- @field #string PARKING Element is parking after spawned on ramp.
-- @field #string TAXIING Element is taxiing after engine startup.
-- @field #string AIRBORNE Element is airborne after take off.
-- @field #string TAKEOFF Element took of after takeoff event.
-- @field #string AIRBORNE Element is airborne. Either after takeoff or after air start.
-- @field #string LANDED Element landed and is taxiing to its parking spot.
-- @field #string ARRIVED Element arrived at its parking spot and shut down its engines.
-- @field #string DEAD Element is dead after it crashed, pilot ejected or pilot dead events.
@@ -99,6 +102,7 @@ FLIGHTGROUP.ElementStatus={
SPAWNED="spawned",
PARKING="parking",
TAXIING="taxiing",
TAKEOFF="takeoff",
AIRBORNE="airborne",
LANDED="landed",
ARRIVED="arrived",
@@ -176,7 +180,7 @@ FLIGHTGROUP.TaskType={
--- FLIGHTGROUP class version.
-- @field #string version
FLIGHTGROUP.version="0.0.9"
FLIGHTGROUP.version="0.1.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@@ -225,11 +229,11 @@ function FLIGHTGROUP:New(groupname)
-- Add FSM transitions.
-- From State --> Event --> To State
self:AddTransition("Stopped", "Start", "Running") -- Start FSM.
-- From State --> Event --> To State
self:AddTransition("Stopped", "Start", "Running") -- Start FSM.
self:AddTransition("*", "FlightStatus", "*") -- FLIGHTGROUP status update.
self:AddTransition("*", "QueueUpdate", "*") -- Update task queue.
self:AddTransition("*", "FlightStatus", "*") -- FLIGHTGROUP status update.
self:AddTransition("*", "QueueUpdate", "*") -- Update task queue.
self:AddTransition("*", "DetectedUnit", "*") -- Add a newly detected unit to the detected units set.
@@ -260,6 +264,7 @@ function FLIGHTGROUP:New(groupname)
self:AddTransition("*", "ElementSpawned", "*") -- An element was spawned.
self:AddTransition("*", "ElementParking", "*") -- An element was spawned.
self:AddTransition("*", "ElementTaxiing", "*") -- An element spooled up the engines.
self:AddTransition("*", "ElementTakeoff", "*") -- An element took off.
self:AddTransition("*", "ElementAirborne", "*") -- An element took off.
self:AddTransition("*", "ElementLanded", "*") -- An element landed.
self:AddTransition("*", "ElementArrived", "*") -- An element arrived.
@@ -270,6 +275,7 @@ function FLIGHTGROUP:New(groupname)
self:AddTransition("*", "FlightSpawned", "Spawned") -- The whole flight group was spawned.
self:AddTransition("*", "FlightParking", "Parking") -- The whole flight group is parking.
self:AddTransition("*", "FlightTaxiing", "Taxiing") -- The whole flight group is taxiing.
self:AddTransition("*", "FlightTakeoff", "Airborne") -- The whole flight group is airborne.
self:AddTransition("*", "FlightAirborne", "Airborne") -- The whole flight group is airborne.
self:AddTransition("*", "FlightLanded", "Landed") -- The whole flight group has landed.
self:AddTransition("*", "FlightArrived", "Arrived") -- The whole flight group has arrived.
@@ -319,6 +325,9 @@ function FLIGHTGROUP:New(groupname)
self.taskcurrent=0
self.taskcounter=0
self.flaghold=USERFLAG:New(string.format("%s_FlagHold", self.groupname))
self.flaghold:Set(0)
-- Add to data base.
_DATABASE:AddFlightGroup(self)
@@ -413,6 +422,7 @@ end
-- @param Ops.Squadron#SQUADRON squadron The squadron object.
-- @return #FLIGHTGROUP self
function FLIGHTGROUP:SetSquadron(squadron)
self:I(self.sid..string.format("Add flight to SQUADRON %s", squadron.squadronname))
self.squadron=squadron
return self
end
@@ -424,6 +434,23 @@ function FLIGHTGROUP:GetSquadron()
return self.squadron
end
--- Set the FLIGHTCONTROL controlling this flight group.
-- @param #FLIGHTGROUP self
-- @param Ops.FlightControl#FLIGHTCONTROL flightcontrol The FLIGHTCONTROL object.
-- @return #FLIGHTGROUP self
function FLIGHTGROUP:SetFlightControl(flightcontrol)
self:I(self.sid..string.format("Setting FLIGHTCONTROL to airbase %s", flightcontrol.airbasename))
self.flightcontrol=flightcontrol
return self
end
--- Get the FLIGHTCONTROL controlling this flight group.
-- @param #FLIGHTGROUP self
-- @return Ops.FlightControl#FLIGHTCONTROL The FLIGHTCONTROL object.
function FLIGHTGROUP:GetFlightControl()
return self.flightcontrol
end
--- Set low fuel threshold. Triggers event "FuelLow" and calls event function "OnAfterFuelLow".
-- @param #FLIGHTGROUP self
-- @param #number threshold Fuel threshold in percent. Default 25 %.
@@ -608,7 +635,8 @@ function FLIGHTGROUP:onafterFlightStatus(From, Event, To)
self:_CheckDetectedUnits()
-- Short info.
local text=string.format("Flight status %s [%d/%d]. Task=%d/%d. Waypoint=%d/%d. Detected=%d", fsmstate, #self.elements, #self.elements, self.taskcurrent, #self.taskqueue, self.currentwp or 0, #self.waypoints or 0, self.detectedunits:Count())
local text=string.format("Flight status %s [%d/%d]. Task=%d/%d. Waypoint=%d/%d. Detected=%d. FC=%s. Destination=%s",
fsmstate, #self.elements, #self.elements, self.taskcurrent, #self.taskqueue, self.currentwp or 0, #self.waypoints or 0, self.detectedunits:Count(), self.flightcontrol and self.flightcontrol.airbasename or "none", self.destination and self.destination:GetName() or "unknown")
self:I(self.sid..text)
-- Element status.
@@ -803,7 +831,7 @@ function FLIGHTGROUP:OnEventTakeOff(EventData)
if element then
self:I(self.sid..string.format("EVENT: Element %s took off ==> airborne", element.name))
self:ElementAirborne(element)
self:ElementTakeoff(element, EventData.Place)
end
end
@@ -833,7 +861,7 @@ function FLIGHTGROUP:OnEventLanding(EventData)
if element then
self:I(self.sid..string.format("EVENT: Element %s landed at %s ==> landed", element.name, airbasename))
self:ElementLanded(element, airbase)
self:ElementLanded(element, airbase)
end
end
@@ -875,7 +903,7 @@ function FLIGHTGROUP:OnEventEngineShutdown(EventData)
else
self:I(self.sid..string.format("Element %s shut down engines (bug is not alive) ==> dead", element.name))
self:ElementDead(element)
--self:ElementDead(element)
end
@@ -959,6 +987,20 @@ function FLIGHTGROUP:onafterElementTaxiing(From, Event, To, Element)
self:_UpdateStatus(Element, FLIGHTGROUP.ElementStatus.TAXIING)
end
--- On after "ElementTakeoff" event.
-- @param #FLIGHTGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #FLIGHTGROUP.Element Element The flight group element.
-- @param Wrapper.Airbase#AIRBASE airbase The airbase if applicable or nil.
function FLIGHTGROUP:onafterElementTakeoff(From, Event, To, Element, airbase)
self:I(self.sid..string.format("Element airborne %s.", Element.name))
-- Set element status.
self:_UpdateStatus(Element, FLIGHTGROUP.ElementStatus.TAKEOFF, airbase)
end
--- On after "ElementAirborne" event.
-- @param #FLIGHTGROUP self
-- @param #string From From state.
@@ -978,11 +1020,12 @@ end
-- @param #string Event Event.
-- @param #string To To state.
-- @param #FLIGHTGROUP.Element Element The flight group element.
function FLIGHTGROUP:onafterElementLanded(From, Event, To, Element)
-- @param Wrapper.Airbase#AIRBASE airbase The airbase if applicable or nil.
function FLIGHTGROUP:onafterElementLanded(From, Event, To, Element, airbase)
self:I(self.sid..string.format("Element landed %s.", Element.name))
-- Set element status.
self:_UpdateStatus(Element, FLIGHTGROUP.ElementStatus.LANDED)
self:_UpdateStatus(Element, FLIGHTGROUP.ElementStatus.LANDED, airbase)
end
--- On after "ElementArrived" event.
@@ -998,6 +1041,19 @@ function FLIGHTGROUP:onafterElementArrived(From, Event, To, Element)
self:_UpdateStatus(Element, FLIGHTGROUP.ElementStatus.ARRIVED)
end
--- On after "ElementDead" event.
-- @param #FLIGHTGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #FLIGHTGROUP.Element Element The flight group element.
function FLIGHTGROUP:onafterElementDead(From, Event, To, Element)
self:I(self.sid..string.format("Element dead %s.", Element.name))
-- Set element status.
self:_UpdateStatus(Element, FLIGHTGROUP.ElementStatus.DEAD)
end
--- On after "FlightSpawned" event. Sets the template, initializes the waypoints.
-- @param #FLIGHTGROUP self
@@ -1005,8 +1061,7 @@ end
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Group#GROUP Group The group object.
function FLIGHTGROUP:onafterFlightSpawned(From, Event, To, Group)
function FLIGHTGROUP:onafterFlightSpawned(From, Event, To)
-- Get template of group.
self.template=self.group:GetTemplate()
@@ -1014,8 +1069,48 @@ function FLIGHTGROUP:onafterFlightSpawned(From, Event, To, Group)
-- Init waypoints.
self:_InitWaypoints()
-- Update route.
self:_UpdateRoute(1)
-- Route flight group but now with passing waypoint tasks.
self.group:Route(self.waypoints)
--self.group:Route(self.waypoints)
end
--- On after "FlightTaxiing" event.
-- @param #FLIGHTGROUP self
-- @param Wrapper.Group#GROUP Group Flight group.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function FLIGHTGROUP:onafterFlightTaxiing(From, Event, To)
self:I(self.sid..string.format("Flight is taxxing %s.", self.groupname))
-- TODO: need a better check for the airbase.
local airbase=self.group:GetCoordinate():GetClosestAirbase(nil, self.group:GetCoalition())
if self.flightcontrol and airbase and self.flightcontrol.airbasename==airbase:GetName() then
self.flightcontrol:_AddFlightToTakeoffQueue(self)
end
end
--- On after "FlightTakeoff" event.
-- @param #FLIGHTGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Airbase#AIRBASE airbase The airbase the flight landed.
function FLIGHTGROUP:onafterFlightTakeoff(From, Event, To, airbase)
self:I(self.sid..string.format("Flight takeoff %s at %s.", self.groupname, airbase and airbase:GetName() or "unknown airbase"))
if self.flightcontrol and airbase and self.flightcontrol.airbasename==airbase:GetName() then
self.flightcontrol:_RemoveFlightFromQueue(self.flightcontrol.Qtakeoff, self)
end
-- Update
self:FlightAirborne(airbase)
--self:__QueueUpdate(-1)
end
--- On after "FlightAirborne" event.
@@ -1025,7 +1120,7 @@ end
-- @param #string To To state.
-- @param Wrapper.Airbase#AIRBASE airbase The airbase the flight landed.
function FLIGHTGROUP:onafterFlightAirborne(From, Event, To, airbase)
self:I(self.sid..string.format("Flight airborne %s.", self.groupname))
self:I(self.sid..string.format("Flight airborne %s at %s.", self.groupname,airbase and airbase:GetName() or "unknown airbase"))
if self.flightcontrol and airbase and self.flightcontrol.airbasename==airbase:GetName() then
self.flightcontrol:_RemoveFlightFromQueue(self.flightcontrol.Qtakeoff, self)
@@ -1043,7 +1138,7 @@ end
-- @param #string To To state.
-- @param Wrapper.Airbase#AIRBASE airbase The airbase the flight landed.
function FLIGHTGROUP:onafterFlightLanded(From, Event, To, airbase)
self:I(self.sid..string.format("Flight landed %s.", self.groupname))
self:I(self.sid..string.format("Flight landed %s at %s.", self.groupname, airbase and airbase:GetName() or "unknown airbase"))
if self.flightcontrol and airbase and self.flightcontrol.airbasename==airbase:GetName() then
self.flightcontrol:_RemoveFlightFromQueue(self.flightcontrol.Qlanding, self)
@@ -1158,21 +1253,88 @@ end
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Core.Point#COORDINATE Coord Coordinate where to orbit.
-- @param #number Altitude Altitude in meters.
-- @param #number Speed Speed in km/h.
function FLIGHTGROUP:onafterHold(From, Event, To, Coord, Altitude, Speed)
-- @param Wrapper.Airbase#AIRBASE airbase The airbase to hold at.
-- @param #number SpeedTo Speed used for travelling from current position to holding point in knots.
-- @param #number SpeedHold Holding speed in knots.
function FLIGHTGROUP:onafterHold(From, Event, To, airbase, SpeedTo, SpeedHold)
-- Debug message.
local text=string.format("Flight group set to hold at altitude %d m and speed %.1f km/h", Altitude, Speed)
local text=string.format("Flight group set to hold at airbase %s", airbase:GetName())
MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug)
self:I(self.sid..text)
self.group:ClearTasks()
local Coord=airbase:GetZone():GetRandomCoordinate():SetAltitude(UTILS.FeetToMeters(6000))
if self.flightcontrol then
Coord=self.flightcontrol:_GetHoldingpoint(self)
end
local TaskOrbit=self.group:TaskOrbit(Coord, Altitude, UTILS.KmphToMps(Speed))
self.flaghold:Set(333)
local TaskArrived=self.group:TaskFunction("FLIGHTGROUP._ReachedHolding", self)
self.group:SetTask(TaskOrbit)
local wp=airbase:GetCoordinate():WaypointAir(nil , COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.FlyoverPoint,SpeedTo, true , nil, {}, "Holding Point")
local Task2Hold=self.group:TaskRoute(wp)
local TaskOrbit=self.group:TaskOrbit(Coord)
local TaskStop=self.group:TaskCondition(nil, self.flaghold.UserFlagName, 1)
--local TaskStop=self.group:TaskCondition(nil, nil, nil, nil, 30*60)
local wp=airbase:GetCoordinate():WaypointAirLanding(SpeedHold, airbase, {}, "Landing")
local TaskLand=self.group:TaskRoute(wp)
local TaskControlled=self.group:TaskControlled(TaskOrbit, TaskStop)
local TaskCombo=self.group:TaskCombo({Task2Hold, TaskArrived, TaskControlled, TaskLand})
local TaskCombo=self.group:TaskCombo({Task2Hold, TaskArrived, TaskLand})
--self.group:SetTask(TaskCombo)
local coordAB=airbase:GetCoordinate()
local wp={}
wp[1]=self.group:GetCoordinate():WaypointAir(nil, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.FlyoverPoint,SpeedTo, true , nil, {}, "Current Pos")
wp[2]=coordAB:WaypointAir(nil, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.FlyoverPoint,SpeedTo, true , nil, {TaskArrived, TaskControlled}, "Holding Point")
wp[3]=coordAB:Translate(50000, 270):WaypointAir(nil, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.FlyoverPoint,SpeedTo, true , nil, {}, "Test 50 km")
wp[4]=coordAB:WaypointAirLanding(SpeedHold, airbase, {}, "Landing")
local respawn=true
if respawn then
-- Get group template.
local Template=self.group:GetTemplate()
-- Set route points.
Template.route.points=wp
MESSAGE:New("Respawning group"):ToAll()
--Respawn the group.
self.group=self.group:Respawn(Template, nil)
end
self.group:Route(wp, 0.1)
--self:RouteRTB(RTBAirbase,Speed,Altitude,TaskOverhead)
end
--- On after TaskPause event.
-- @param Wrapper.Group#GROUP group
-- @param #FLIGHTGROUP flightgroup
function FLIGHTGROUP._ReachedHolding(group, flightgroup)
env.info(string.format("FF group %s reached holding point", group:GetName()))
group:GetCoordinate():MarkToAll("Holding Point Reached")
--TODO: add flight to FC waiting queue.
flightgroup.flaghold:Set(666)
end
--- On after TaskExecute event.
@@ -1187,6 +1349,11 @@ function FLIGHTGROUP:onafterTaskExecute(From, Event, To, Task)
local text=string.format("Task %s ID=%d execute.", Task.description, Task.id)
MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug)
self:I(self.sid..text)
-- Cancel current task if there is any.
if self.taskcurrent>0 then
self:TaskCancel()
end
-- Set current task.
self.taskcurrent=Task.id
@@ -1300,20 +1467,6 @@ function FLIGHTGROUP:onafterDetectedUnit(From, Event, To, Unit)
self.detectedunits:AddUnit(Unit)
end
--- On after "ElementDead" event.
-- @param #FLIGHTGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #FLIGHTGROUP.Element Element The flight group element.
function FLIGHTGROUP:onafterElementDead(From, Event, To, Element)
self:I(self.sid..string.format("Element dead %s.", Element.name))
-- Set element status.
self:_UpdateStatus(Element, FLIGHTGROUP.ElementStatus.DEAD)
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Task functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -1428,7 +1581,8 @@ end
-- @param Wrapper.Airbase#AIRBASE RTBAirbase
-- @param #number Speed Speed in km/h.
-- @param #number Altitude Altitude in meters.
function FLIGHTGROUP:RouteRTB(RTBAirbase, Speed, Altitude)
-- @param #table TaskOverhead Task to execute when reaching overhead waypoint.
function FLIGHTGROUP:RouteRTB(RTBAirbase, Speed, Altitude, TaskOverhead)
-- If speed is not given take 80% of max speed.
local Speed=Speed or self.group:GetSpeedMax()*0.8
@@ -1444,7 +1598,7 @@ function FLIGHTGROUP:RouteRTB(RTBAirbase, Speed, Altitude)
local PointFrom=coord:WaypointAirTurningPoint(nil, Speed, {}, "Current")
-- Overhead pass.
local PointOverhead=RTBAirbase:GetCoordinate():SetAltitude(Altitude or coord.y):WaypointAirTurningPoint(nil, Speed, {}, "Overhead Pass")
local PointOverhead=RTBAirbase:GetCoordinate():SetAltitude(Altitude or coord.y):WaypointAirTurningPoint(nil, Speed, TaskOverhead, "Overhead Pass")
-- Landing waypoint.
local PointLanding=RTBAirbase:GetCoordinate():SetAltitude(20):WaypointAirLanding(Speed, RTBAirbase, {}, "Landing")
@@ -1458,12 +1612,29 @@ function FLIGHTGROUP:RouteRTB(RTBAirbase, Speed, Altitude)
-- Set route points.
Template.route.points=Points
-- Respawn the group.
self.group=self.group:Respawn(Template, true)
--self.group=self.group:Respawn(Template, true)
local TaskRTB=self.group:TaskRoute(Points)
--[[
self.taskcounter=self.taskcounter+1
local task={} --#FLIGHTGROUP.Task
task.dcstask=TaskRTB
task.description="RTB"
task.id=self.taskcounter
task.type=FLIGHTGROUP.TaskType.SCHEDULED
task.prio=0
task.time=timer.getAbsTime()
]]
self:AddTask("RTB", TaskRTB, 0)
self:TaskCancel()
-- Route the group or this will not work.
self.group:Route(Points, 1)
--self.group:Route(Points, 1)
end
@@ -1568,6 +1739,33 @@ function FLIGHTGROUP:GetElementByName(unitname)
return nil
end
--- Check if a unit is and element of the flightgroup.
-- @param #FLIGHTGROUP self
-- @return Wrapper.Airbase#AIRBASE Final destination airbase or #nil.
function FLIGHTGROUP:GetHomebaseFromWaypoints()
local wp=self:GetWaypoint(1)
if wp then
if wp and wp.action and wp.action==COORDINATE.WaypointAction.Landing then
-- Get airbase ID depending on airbase category.
local airbaseID=wp.airdromeId or wp.helipadId
local airbase=AIRBASE:FindByID(airbaseID)
return airbase
end
--TODO: Handle case where e.g. only one WP but that is not landing.
--TODO: Probably other cases need to be taken care of.
end
return nil
end
--- Check if a unit is and element of the flightgroup.
-- @param #FLIGHTGROUP self
-- @return Wrapper.Airbase#AIRBASE Final destination airbase or #nil.
@@ -1683,9 +1881,20 @@ function FLIGHTGROUP:_UpdateRoute(n)
table.insert(wp, self.waypoints[i])
end
-- Get destination airbase from waypoints.
self.homebase=self:GetHomebaseFromWaypoints() or self.homebase
-- Get destination airbase from waypoints.
self.destination=self:GetDestinationFromWaypoints() or self.destination
if self.destination and #wp>0 then
local wpoverhead=self.destination:GetCoordinate():WaypointAir(nil, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.FlyoverPoint, 500, false, nil, {}, "Destination Overhead")
self:I(self.sid..string.format("Adding overhead waypoint as #%d", #wp))
table.insert(wp, #wp, wpoverhead)
end
self:I(self.sid..string.format("Updating route: #WP=%d homebase=%s destination=%s", #wp, self.homebase and self.homebase:GetName() or "unknown", self.destination and self.destination:GetName() or "unknown"))
if #wp>0 then
-- Route group to all defined waypoints remaining.
@@ -1912,7 +2121,7 @@ function FLIGHTGROUP:_AllSimilarStatus(status)
return false
end
elseif status==FLIGHTGROUP.ElementStatus.AIRBORNE then
elseif status==FLIGHTGROUP.ElementStatus.TAKEOFF then
-- Element AIRBORNE: Check that the other are not stil SPAWNED, PARKING or TAXIING
if element.status~=status and
@@ -1922,6 +2131,17 @@ function FLIGHTGROUP:_AllSimilarStatus(status)
return false
end
elseif status==FLIGHTGROUP.ElementStatus.AIRBORNE then
-- Element AIRBORNE: 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.PARKING or
element.status==FLIGHTGROUP.ElementStatus.TAXIING or
element.status==FLIGHTGROUP.ElementStatus.TAKEOFF then
return false
end
elseif status==FLIGHTGROUP.ElementStatus.LANDED then
-- Element LANDED: check that the others are not stil AIRBORNE
@@ -1959,7 +2179,8 @@ end
-- @param #FLIGHTGROUP self
-- @param #FLIGHTGROUP.Element element Element.
-- @param #string newstatus New status of element
function FLIGHTGROUP:_UpdateStatus(element, newstatus)
-- @param Wrapper.Airbase#AIRBASE airbase Airbase if applicable.
function FLIGHTGROUP:_UpdateStatus(element, newstatus, airbase)
-- Old status.
local oldstatus=element.status
@@ -1975,7 +2196,7 @@ function FLIGHTGROUP:_UpdateStatus(element, newstatus)
---
if self:_AllSimilarStatus(newstatus) then
self:FlightSpawned(group)
self:FlightSpawned()
end
--[[
@@ -1992,7 +2213,7 @@ function FLIGHTGROUP:_UpdateStatus(element, newstatus)
---
if self:_AllSimilarStatus(newstatus) then
self:FlightParking(group)
self:FlightParking()
end
elseif newstatus==FLIGHTGROUP.ElementStatus.TAXIING then
@@ -2001,7 +2222,17 @@ function FLIGHTGROUP:_UpdateStatus(element, newstatus)
---
if self:_AllSimilarStatus(newstatus) then
self:FlightTaxiing(group)
self:FlightTaxiing()
end
elseif newstatus==FLIGHTGROUP.ElementStatus.TAKEOFF then
---
-- TAKEOFF
---
if self:_AllSimilarStatus(newstatus) then
self:FlightTakeoff(airbase)
--TODO: also trigger Airborne() ?
end
elseif newstatus==FLIGHTGROUP.ElementStatus.AIRBORNE then
@@ -2012,14 +2243,14 @@ function FLIGHTGROUP:_UpdateStatus(element, newstatus)
if self:_AllSimilarStatus(newstatus) then
if self:IsTaxiing() then
self:FlightAirborne(group)
self:FlightAirborne()
elseif self:IsParking() then
--self:FlightTaxiing(group)
self:FlightAirborne(group)
self:FlightAirborne()
elseif self:IsSpawned() then
--self:FlightParking(group)
--self:FlightTaxiing(group)
self:FlightAirborne(group)
self:FlightAirborne()
end
end
@@ -2041,10 +2272,10 @@ function FLIGHTGROUP:_UpdateStatus(element, newstatus)
if self:_AllSimilarStatus(newstatus) then
if self:IsLanded() then
self:FlightArrived(group)
self:FlightArrived()
elseif self:IsAirborne() then
self:FlightLanded(group)
self:FlightArrived(group)
self:FlightLanded()
self:FlightArrived()
end
end
@@ -2055,7 +2286,7 @@ function FLIGHTGROUP:_UpdateStatus(element, newstatus)
---
if self:_AllSimilarStatus(newstatus) then
self:FlightDead(group)
self:FlightDead()
end
end
+1 -1
View File
@@ -433,7 +433,7 @@ UTILS.tostringLL = function( lat, lon, acc, DMS)
secFrmtStr = '%02d'
else
local width = 3 + acc -- 01.310 - that's a width of 6, for example. Acc is limited to 2 for DMS!
secFrmtStr = '%0' .. width .. '.' .. math.min(acc, 2) .. 'f'
secFrmtStr = '%0' .. width .. '.' .. acc .. 'f'
end
-- 024° 23' 12"N or 024° 23' 12.03"N
@@ -442,12 +442,12 @@ end
--- Return a condition section for a controlled task.
-- @param #CONTROLLABLE self
-- @param DCS#Time time
-- @param #string userFlag
-- @param #boolean userFlagValue
-- @param #string condition
-- @param DCS#Time duration
-- @param #number lastWayPoint
-- @param DCS#Time time DCS mission time.
-- @param #string userFlag Name of the user flag.
-- @param #boolean userFlagValue User flag value *true* or *false*. Could also be numeric, i.e. either 0=*false* or 1=*true*. Other numeric values don't work!
-- @param #string condition Lua string.
-- @param DCS#Time duration Duration in seconds.
-- @param #number lastWayPoint Last waypoint.
-- return DCS#Task
function CONTROLLABLE:TaskCondition( time, userFlag, userFlagValue, condition, duration, lastWayPoint )
self:F2( { time, userFlag, userFlagValue, condition, duration, lastWayPoint } )
@@ -1079,8 +1079,8 @@ end
--- (AIR) Orbit at a position with at a given altitude and speed. Optionally, a race track pattern can be specified.
-- @param #CONTROLLABLE self
-- @param Core.Point#COORDINATE Coord Coordinate at which the CONTROLLABLE orbits.
-- @param #number Altitude Altitude in meters of the orbit pattern.
-- @param #number Speed Speed [m/s] flying the orbit pattern.
-- @param #number Altitude Altitude in meters of the orbit pattern. Default y component of Coord.
-- @param #number Speed Speed [m/s] flying the orbit pattern. Default 250 knots.
-- @param Core.Point#COORDINATE CoordRaceTrack (Optional) If this coordinate is specified, the CONTROLLABLE will fly a race-track pattern using this and the initial coordinate.
-- @return #CONTROLLABLE self
function CONTROLLABLE:TaskOrbit(Coord, Altitude, Speed, CoordRaceTrack)
@@ -1100,8 +1100,8 @@ function CONTROLLABLE:TaskOrbit(Coord, Altitude, Speed, CoordRaceTrack)
pattern = Pattern,
point = P1,
point2 = P2,
speed = Speed,
altitude = Altitude,
speed = Speed or UTILS.KnotsToMps(250),
altitude = Altitude or Coord.y,
}
}
+25 -2
View File
@@ -1683,7 +1683,7 @@ function GROUP:Respawn( Template, Reset )
end
end
else -- Reset=false or nil
elseif Reset==false then -- Reset=false or nil
-- Loop over template units.
for UnitID, TemplateUnitData in pairs( Template.units ) do
@@ -1725,7 +1725,30 @@ function GROUP:Respawn( Template, Reset )
self:F( { UnitID, Template.units[UnitID], Template.units[UnitID] } )
end
end
else
local units=self:GetUnits()
-- Loop over template units.
for UnitID, Unit in pairs(Template.units) do
for _,_unit in pairs(units) do
local unit=_unit --Wrapper.Unit#UNIT
if unit:GetName()==Unit.name then
local coord=unit:GetCoordinate()
local heading=unit:GetHeading()
Unit.x=coord.x
Unit.z=coord.y
Unit.alt=coord.alt
Unit.heading=math.rad(heading)
Unit.psi=-Unit.heading
end
end
end
end
end