mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
OPS
Enhanced OPERATION and FLIGHTCONTROL features.
This commit is contained in:
parent
9b3f2ae3c7
commit
a53595a055
@ -6311,7 +6311,7 @@ do -- SET_OPSGROUP
|
||||
|
||||
--- Creates a new SET_OPSGROUP object, building a set of groups belonging to a coalitions, categories, countries, types or with defined prefix names.
|
||||
-- @param #SET_OPSGROUP self
|
||||
-- @return #SET_OPSGROUP
|
||||
-- @return #SET_OPSGROUP self
|
||||
function SET_OPSGROUP:New()
|
||||
|
||||
-- Inherit SET_BASE.
|
||||
|
||||
@ -2667,6 +2667,26 @@ function RANGE:_DisplayRangeInfo( _unitname )
|
||||
text = text .. string.format( "Max strafing alt AGL: %s\n", tstrafemaxalt )
|
||||
text = text .. string.format( "# of strafe targets: %d\n", self.nstrafetargets )
|
||||
text = text .. string.format( "# of bomb targets: %d\n", self.nbombtargets )
|
||||
if self.instructor then
|
||||
local alive = "N/A"
|
||||
if self.instructorrelayname then
|
||||
local relay = UNIT:FindByName( self.instructorrelayname )
|
||||
if relay then
|
||||
alive = tostring( relay:IsAlive() )
|
||||
end
|
||||
end
|
||||
text = text .. string.format( "Instructor %.3f MHz (Relay=%s)\n", self.instructorfreq, alive )
|
||||
end
|
||||
if self.rangecontrol then
|
||||
local alive = "N/A"
|
||||
if self.rangecontrolrelayname then
|
||||
local relay = UNIT:FindByName( self.rangecontrolrelayname )
|
||||
if relay then
|
||||
alive = tostring( relay:IsAlive() )
|
||||
end
|
||||
end
|
||||
text = text .. string.format( "Control %.3f MHz (Relay=%s)\n", self.rangecontrolfreq, alive )
|
||||
end
|
||||
text = text .. texthit
|
||||
text = text .. textbomb
|
||||
text = text .. textdelay
|
||||
|
||||
@ -1137,15 +1137,19 @@ end
|
||||
-- @param #number Port SRS port. Default 5002.
|
||||
-- @return #ATIS self
|
||||
function ATIS:SetSRS(PathToSRS, Gender, Culture, Voice, Port)
|
||||
self.useSRS=true
|
||||
self.msrs=MSRS:New(PathToSRS, self.frequency, self.modulation)
|
||||
self.msrs:SetGender(Gender)
|
||||
self.msrs:SetCulture(Culture)
|
||||
self.msrs:SetVoice(Voice)
|
||||
self.msrs:SetPort(Port)
|
||||
self.msrs:SetCoalition(self:GetCoalition())
|
||||
if self.dTQueueCheck<=10 then
|
||||
self:SetQueueUpdateTime(90)
|
||||
if PathToSRS then
|
||||
self.useSRS=true
|
||||
self.msrs=MSRS:New(PathToSRS, self.frequency, self.modulation)
|
||||
self.msrs:SetGender(Gender)
|
||||
self.msrs:SetCulture(Culture)
|
||||
self.msrs:SetVoice(Voice)
|
||||
self.msrs:SetPort(Port)
|
||||
self.msrs:SetCoalition(self:GetCoalition())
|
||||
if self.dTQueueCheck<=10 then
|
||||
self:SetQueueUpdateTime(90)
|
||||
end
|
||||
else
|
||||
self:E(self.lid..string.format("ERROR: No SRS path specified!"))
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
@ -137,7 +137,7 @@ function ARMYGROUP:New(group)
|
||||
|
||||
self:AddTransition("*", "Rearm", "Rearm") -- Group is send to a coordinate and waits until ammo is refilled.
|
||||
self:AddTransition("Rearm", "Rearming", "Rearming") -- Group has arrived at the rearming coodinate and is waiting to be fully rearmed.
|
||||
self:AddTransition("Rearming", "Rearmed", "Cruising") -- Group was rearmed.
|
||||
self:AddTransition("*", "Rearmed", "Cruising") -- Group was rearmed.
|
||||
|
||||
------------------------
|
||||
--- Pseudo Functions ---
|
||||
@ -1381,9 +1381,22 @@ end
|
||||
-- @param #string To To state.
|
||||
function ARMYGROUP:onafterRearmed(From, Event, To)
|
||||
self:T(self.lid.."Group rearmed")
|
||||
|
||||
-- Get Current mission.
|
||||
local mission=self:GetMissionCurrent()
|
||||
|
||||
-- Check if this is a rearming mission.
|
||||
if mission and mission.type==AUFTRAG.Type.REARMING then
|
||||
-- Rearmed ==> Mission Done! This also checks if the group is done.
|
||||
self:MissionDone(mission)
|
||||
|
||||
else
|
||||
|
||||
-- Check group done.
|
||||
self:_CheckGroupDone(1)
|
||||
|
||||
end
|
||||
|
||||
-- Check group done.
|
||||
self:_CheckGroupDone(1)
|
||||
end
|
||||
|
||||
--- On before "RTZ" event.
|
||||
|
||||
@ -418,6 +418,7 @@ _AUFTRAGSNR=0
|
||||
-- @field #string AIRDEFENSE Air defense.
|
||||
-- @field #string EWR Early Warning Radar.
|
||||
-- @field #string RECOVERYTANKER Recovery tanker.
|
||||
-- @filed #string REARMING Rearming mission.
|
||||
-- @field #string NOTHING Nothing.
|
||||
AUFTRAG.Type={
|
||||
ANTISHIP="Anti Ship",
|
||||
@ -459,6 +460,7 @@ AUFTRAG.Type={
|
||||
AIRDEFENSE="Air Defence",
|
||||
EWR="Early Warning Radar",
|
||||
RECOVERYTANKER="Recovery Tanker",
|
||||
REARMING="Rearming",
|
||||
NOTHING="Nothing",
|
||||
}
|
||||
|
||||
@ -480,6 +482,7 @@ AUFTRAG.Type={
|
||||
-- @field #string AIRDEFENSE Air defense.
|
||||
-- @field #string EWR Early Warning Radar.
|
||||
-- @field #string RECOVERYTANKER Recovery tanker.
|
||||
-- @field #string REARMING Rearming.
|
||||
-- @field #string NOTHING Nothing.
|
||||
AUFTRAG.SpecialTask={
|
||||
FORMATION="Formation",
|
||||
@ -499,6 +502,7 @@ AUFTRAG.SpecialTask={
|
||||
AIRDEFENSE="Air Defense",
|
||||
EWR="Early Warning Radar",
|
||||
RECOVERYTANKER="Recovery Tanker",
|
||||
REARMING="Rearming",
|
||||
NOTHING="Nothing",
|
||||
}
|
||||
|
||||
@ -2009,6 +2013,30 @@ function AUFTRAG:NewFUELSUPPLY(Zone)
|
||||
return mission
|
||||
end
|
||||
|
||||
--- **[GROUND]** Create a REARMING mission.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Zone#ZONE Zone The zone, where units go and look for ammo supply.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:NewREARMING(Zone)
|
||||
|
||||
local mission=AUFTRAG:New(AUFTRAG.Type.REARMING)
|
||||
|
||||
mission:_TargetFromObject(Zone)
|
||||
|
||||
mission.optionROE=ENUMS.ROE.WeaponHold
|
||||
mission.optionAlarm=ENUMS.AlarmState.Auto
|
||||
|
||||
mission.missionFraction=1.0
|
||||
|
||||
mission.missionWaypointRadius=0
|
||||
|
||||
mission.categories={AUFTRAG.Category.GROUND}
|
||||
|
||||
mission.DCStask=mission:GetDCSMissionTask()
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
|
||||
--- **[AIR]** Create an ALERT 5 mission. Aircraft will be spawned uncontrolled and wait for an assignment. You must specify **one** mission type which is performed.
|
||||
-- This determines the payload and the DCS mission task which are used when the aircraft is spawned.
|
||||
@ -5710,6 +5738,24 @@ function AUFTRAG:GetDCSMissionTask()
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.AMMOSUPPLY then
|
||||
|
||||
----------------------
|
||||
-- REARMING Mission --
|
||||
----------------------
|
||||
|
||||
local DCStask={}
|
||||
|
||||
DCStask.id=AUFTRAG.SpecialTask.REARMING
|
||||
|
||||
-- We create a "fake" DCS task and pass the parameters to the OPSGROUP.
|
||||
local param={}
|
||||
param.zone=self:GetObjective()
|
||||
|
||||
DCStask.params=param
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.ALERT5 then
|
||||
|
||||
---------------------
|
||||
|
||||
@ -2117,7 +2117,7 @@ function CHIEF:CheckTargetQueue()
|
||||
self:T2(self.lid..string.format("Recruiting assets for mission type %s [performance=%d] of target %s", mp.MissionType, mp.Performance, target:GetName()))
|
||||
|
||||
-- Recruit assets.
|
||||
local recruited, assets, legions=self:RecruitAssetsForTarget(target, mp.MissionType, NassetsMin, NassetsMax)
|
||||
local recruited, assets, legions=self.commander:RecruitAssetsForTarget(target, mp.MissionType, NassetsMin, NassetsMax)
|
||||
|
||||
if recruited then
|
||||
|
||||
@ -2649,29 +2649,6 @@ function CHIEF:_GetMissionTypeForGroupAttribute(Attribute)
|
||||
return missionperf
|
||||
end
|
||||
|
||||
--- Recruit assets for a given TARGET.
|
||||
-- @param #CHIEF self
|
||||
-- @param Ops.Target#TARGET Target The target.
|
||||
-- @param #string MissionType Mission Type.
|
||||
-- @param #number NassetsMin Min number of required assets.
|
||||
-- @param #number NassetsMax Max number of required assets.
|
||||
-- @return #boolean If `true` enough assets could be recruited.
|
||||
-- @return #table Assets that have been recruited from all legions.
|
||||
-- @return #table Legions that have recruited assets.
|
||||
function CHIEF:RecruitAssetsForTarget(Target, MissionType, NassetsMin, NassetsMax)
|
||||
|
||||
-- Cohorts.
|
||||
local Cohorts=self.commander:_GetCohorts()
|
||||
|
||||
-- Target position.
|
||||
local TargetVec2=Target:GetVec2()
|
||||
|
||||
-- Recruite assets.
|
||||
local recruited, assets, legions=LEGION.RecruitCohortAssets(Cohorts, MissionType, nil, NassetsMin, NassetsMax, TargetVec2)
|
||||
|
||||
|
||||
return recruited, assets, legions
|
||||
end
|
||||
|
||||
--- Recruit assets for a given OPS zone.
|
||||
-- @param #CHIEF self
|
||||
|
||||
@ -787,7 +787,7 @@ end
|
||||
function COHORT:onafterStart(From, Event, To)
|
||||
|
||||
-- Short info.
|
||||
local text=string.format("Starting %s v%s %s", self.ClassName, self.version, self.name)
|
||||
local text=string.format("Starting %s v%s %s [%s]", self.ClassName, self.version, self.name, self.attribute)
|
||||
self:I(self.lid..text)
|
||||
|
||||
-- Start the status monitoring.
|
||||
@ -993,7 +993,7 @@ end
|
||||
-- @param #COHORT self
|
||||
-- @param #table MissionTypes (Optional) Count only assest that can perform certain mission type(s). Default is all types.
|
||||
-- @param #table Attributes (Optional) Count only assest that have a certain attribute(s), e.g. `WAREHOUSE.Attribute.AIR_BOMBER`.
|
||||
-- @return Core.Set#SET_OPSGROUPS Ops groups set.
|
||||
-- @return Core.Set#SET_OPSGROUP Ops groups set.
|
||||
function COHORT:GetOpsGroups(MissionTypes, Attributes)
|
||||
|
||||
local set=SET_OPSGROUP:New()
|
||||
|
||||
@ -1254,6 +1254,23 @@ function COMMANDER:CheckOpsQueue()
|
||||
|
||||
if operation:IsRunning() then
|
||||
|
||||
-- Loop over missions.
|
||||
for _,_mission in pairs(operation.missions or {}) do
|
||||
local mission=_mission --Ops.Auftrag#AUFTRAG
|
||||
|
||||
if mission.phase==nil or (mission.phase and mission.phase==operation.phase) and mission:IsPlanned() then
|
||||
self:AddMission(mission)
|
||||
end
|
||||
end
|
||||
|
||||
-- Loop over targets.
|
||||
for _,_target in pairs(operation.targets or {}) do
|
||||
local target=_target --Ops.Target#TARGET
|
||||
|
||||
if (target.phase==nil or (target.phase and target.phase==operation.phase)) and (not self:IsTarget(target)) then
|
||||
self:AddTarget(target)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -1352,6 +1369,9 @@ function COMMANDER:CheckTargetQueue()
|
||||
mission:SetRequiredAttribute(resource.Attributes)
|
||||
mission:SetRequiredProperty(resource.Properties)
|
||||
|
||||
-- Set operation (if any).
|
||||
mission.operation=target.operation
|
||||
|
||||
-- Set resource mission.
|
||||
resource.mission=mission
|
||||
|
||||
@ -1651,6 +1671,30 @@ function COMMANDER:RecruitAssetsForEscort(Mission, Assets)
|
||||
return true
|
||||
end
|
||||
|
||||
--- Recruit assets for a given TARGET.
|
||||
-- @param #COMMANDER self
|
||||
-- @param Ops.Target#TARGET Target The target.
|
||||
-- @param #string MissionType Mission Type.
|
||||
-- @param #number NassetsMin Min number of required assets.
|
||||
-- @param #number NassetsMax Max number of required assets.
|
||||
-- @return #boolean If `true` enough assets could be recruited.
|
||||
-- @return #table Assets that have been recruited from all legions.
|
||||
-- @return #table Legions that have recruited assets.
|
||||
function COMMANDER:RecruitAssetsForTarget(Target, MissionType, NassetsMin, NassetsMax)
|
||||
|
||||
-- Cohorts.
|
||||
local Cohorts=self:_GetCohorts()
|
||||
|
||||
-- Target position.
|
||||
local TargetVec2=Target:GetVec2()
|
||||
|
||||
-- Recruite assets.
|
||||
local recruited, assets, legions=LEGION.RecruitCohortAssets(Cohorts, MissionType, nil, NassetsMin, NassetsMax, TargetVec2)
|
||||
|
||||
|
||||
return recruited, assets, legions
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Transport Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -12,7 +12,15 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ## Example Missions:
|
||||
--
|
||||
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20FlightControl).
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **funkyfranky**
|
||||
--
|
||||
-- ===
|
||||
-- @module OPS.FlightControl
|
||||
-- @image OPS_FlightControl.png
|
||||
|
||||
@ -62,7 +70,10 @@
|
||||
-- # The FLIGHTCONTROL Concept
|
||||
--
|
||||
-- This class implements an ATC for human and AI controlled aircraft. It gives permission for take-off and landing based on a sophisticated queueing system.
|
||||
-- Therefore, it solves (or reduces) a lot of common problems with the DCS implementation (which is barly existing at this point).
|
||||
-- Therefore, it solves (or reduces) a lot of common problems with the DCS implementation.
|
||||
--
|
||||
-- You might be familiar with the `AIRBOSS` class. This class is the analogue for land based airfields. One major difference is that no pre-recorded sound files are
|
||||
-- necessary. The radio transmissions use the SRS text-to-speech feature.
|
||||
--
|
||||
-- ## Prerequisites
|
||||
--
|
||||
@ -77,7 +88,54 @@
|
||||
-- * Only one player/client per group as we can create menus only for a group and not for a specific unit.
|
||||
-- * Only FLIGHTGROUPS are controlled. This means some older classes, *e.g.* RAT are not supported (yet).
|
||||
-- * So far only airdromes are handled, *i.e.* no FARPs or ships.
|
||||
-- * Only fixed wing aircraft are handled until now, *i.e.* no helos.
|
||||
-- * Helicopters are not treated differently from fixed wing aircraft until now.
|
||||
-- * The active runway can only be determined by the wind direction. So at least set a very light wind speed in your mission.
|
||||
--
|
||||
-- # Basic Usage
|
||||
--
|
||||
-- A flight control for a given airdrome can be created with the @{#FLIGHTCONTROL.New}(*AirbaseName, Frequency, Modulation, PathToSRS*) function. You need to specify the name of the airbase, the
|
||||
-- tower radio frequency, its modulation and the path, where SRS is located on the machine that is running this mission.
|
||||
--
|
||||
-- For the FC to be operating, it needs to be started with the @{#FLIGHTCONTROL.Start}() function.
|
||||
--
|
||||
-- ## Simple Script
|
||||
--
|
||||
-- The simplest script looks like
|
||||
--
|
||||
-- local FC_BATUMI=FLIGHTCONTROL:New(AIRBASE.Caucasus.Batumi, 251, nil, "D:\\SomeDirectory\\_SRS")
|
||||
-- FC_BATUMI:Start()
|
||||
--
|
||||
-- This will start the FC for at the Batumi airbase with tower frequency 251 MHz AM. SRS needs to be in the given directory.
|
||||
--
|
||||
-- Like this, a default holding pattern (see below) is parallel to the direction of the active runway.
|
||||
--
|
||||
-- # Holding Patterns
|
||||
--
|
||||
-- Holding pattern are air spaces where incoming aircraft are guided to and have to hold until they get landing clearance.
|
||||
--
|
||||
-- You can add a holding pattern with the @{#FLIGHTCONTROL.AddHoldingPattern}(*ArrivalZone, Heading, Length, FlightlevelMin, FlightlevelMax, Prio*) function, where
|
||||
--
|
||||
-- * `ArrivalZone` is the zone where the aircraft enter the pattern.
|
||||
-- * `Heading` is the direction into which the aircraft have to fly from the arrival zone.
|
||||
-- * `Length` is the length of the pattern.
|
||||
-- * `FlightLevelMin` is the lowest altitude at which aircraft can hold.
|
||||
-- * `FlightLevelMax` is the highest altitude at which aircraft can hold.
|
||||
-- * `Prio` is the priority of this holdig stacks. If multiple patterns are defined, patterns with higher prio will be filled first.
|
||||
--
|
||||
-- # Parking Guard
|
||||
--
|
||||
-- # Taxi Limits
|
||||
--
|
||||
-- You can define limits on how many aircraft are simultaniously landing and taking off. This avoids (DCS) problems where taxiing aircraft cause a "traffic jam" on the taxi way(s)
|
||||
-- and bring the whole airbase effectively to a stand still.
|
||||
--
|
||||
-- ## Landing Limits
|
||||
--
|
||||
--
|
||||
-- ## Takeoff Limits
|
||||
--
|
||||
-- Note that the limits here are only affecting AI aircraft groups. Human players are assumed to be a lot more well behaved and capable as they are able to taxi around obstacles, *e.g.*
|
||||
-- other aircraft etc.
|
||||
--
|
||||
--
|
||||
-- @field #FLIGHTCONTROL
|
||||
@ -102,7 +160,7 @@ FLIGHTCONTROL = {
|
||||
Nlanding = nil,
|
||||
dTlanding = nil,
|
||||
Nparkingspots = nil,
|
||||
holdingpatterns = {},
|
||||
holdingpatterns = {},
|
||||
hpcounter = 0,
|
||||
}
|
||||
|
||||
@ -170,20 +228,20 @@ FLIGHTCONTROL.FlightStatus={
|
||||
|
||||
--- FlightControl class version.
|
||||
-- @field #string version
|
||||
FLIGHTCONTROL.version="0.5.2"
|
||||
FLIGHTCONTROL.version="0.5.3"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
|
||||
-- TODO: Runway destroyed.
|
||||
-- TODO: Support airwings. Dont give clearance for Alert5 or if mission has not started.
|
||||
-- TODO: Switch to enable/disable AI messages.
|
||||
-- TODO: Improve ATC TTS messages.
|
||||
-- TODO: Talk me down option.
|
||||
-- TODO: ATIS option.
|
||||
-- TODO: Check runways and clean up.
|
||||
-- TODO: Accept and forbit parking spots.
|
||||
-- TODO: Add FARPS?
|
||||
-- DONE: Accept and forbit parking spots. DONE via AIRBASE black/white lists and airwing features.
|
||||
-- DONE: Support airwings. Dont give clearance for Alert5 or if mission has not started.
|
||||
-- DONE: Define holding zone.
|
||||
-- DONE: Basic ATC voice overs.
|
||||
-- DONE: Add SRS TTS.
|
||||
@ -234,6 +292,9 @@ function FLIGHTCONTROL:New(AirbaseName, Frequency, Modulation, PathToSRS)
|
||||
|
||||
-- 5 NM zone around the airbase.
|
||||
self.zoneAirbase=ZONE_RADIUS:New("FC", self:GetCoordinate():GetVec2(), UTILS.NMToMeters(5))
|
||||
|
||||
-- Add backup holding pattern.
|
||||
self:_AddHoldingPatternBackup()
|
||||
|
||||
-- Set alias.
|
||||
self.alias=self.airbasename.." Tower"
|
||||
@ -331,7 +392,17 @@ function FLIGHTCONTROL:SetFrequency(Frequency, Modulation)
|
||||
|
||||
self.frequency=Frequency or 305
|
||||
self.modulation=Modulation or radio.modulation.AM
|
||||
|
||||
if self.msrsPilot then
|
||||
self.msrsPilot:SetFrequencies(Frequency)
|
||||
self.msrsPilot:SetModulations(Modulation)
|
||||
end
|
||||
|
||||
if self.msrsTower then
|
||||
self.msrsTower:SetFrequencies(Frequency)
|
||||
self.msrsTower:SetModulations(Modulation)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@ -398,8 +469,9 @@ end
|
||||
-- @param #number Length Length in nautical miles. Default 15 NM.
|
||||
-- @param #number FlightlevelMin Min flight level. Default 5.
|
||||
-- @param #number FlightlevelMax Max flight level. Default 15.
|
||||
-- @param #number Prio Priority. Lower is higher. Default 50.
|
||||
-- @return #FLIGHTCONTROL.HoldingPattern Holding pattern table.
|
||||
function FLIGHTCONTROL:AddHoldingPattern(ArrivalZone, Heading, Length, FlightlevelMin, FlightlevelMax)
|
||||
function FLIGHTCONTROL:AddHoldingPattern(ArrivalZone, Heading, Length, FlightlevelMin, FlightlevelMax, Prio)
|
||||
|
||||
-- Get ZONE if passed as string.
|
||||
if type(ArrivalZone)=="string" then
|
||||
@ -410,13 +482,14 @@ function FLIGHTCONTROL:AddHoldingPattern(ArrivalZone, Heading, Length, Flightlev
|
||||
self.hpcounter=self.hpcounter+1
|
||||
|
||||
local hp={} --#FLIGHTCONTROL.HoldingPattern
|
||||
hp.arrivalzone=ArrivalZone
|
||||
hp.uid=self.hpcounter
|
||||
hp.arrivalzone=ArrivalZone
|
||||
hp.name=string.format("%s-%d", ArrivalZone:GetName(), hp.uid)
|
||||
hp.pos0=ArrivalZone:GetCoordinate()
|
||||
hp.pos1=hp.pos0:Translate(UTILS.NMToMeters(Length or 15), Heading)
|
||||
hp.angelsmin=FlightlevelMin or 5
|
||||
hp.angelsmax=FlightlevelMax or 15
|
||||
hp.prio=Prio or 50
|
||||
|
||||
hp.stacks={}
|
||||
for i=hp.angelsmin, hp.angelsmax do
|
||||
@ -438,6 +511,50 @@ function FLIGHTCONTROL:AddHoldingPattern(ArrivalZone, Heading, Length, Flightlev
|
||||
hp.pos0:ArrowToAll(hp.pos1, nil, {1,0,0}, 1, {1,1,0}, 0.5, 2, true)
|
||||
ArrivalZone:DrawZone()
|
||||
|
||||
local function _sort(a,b)
|
||||
return a.prio<b.prio
|
||||
end
|
||||
table.sort(self.holdingpatterns, _sort)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a holding pattern.
|
||||
-- @param #FLIGHTCONTROL self
|
||||
-- @return #FLIGHTCONTROL.HoldingPattern Holding pattern table.
|
||||
function FLIGHTCONTROL:_AddHoldingPatternBackup()
|
||||
|
||||
local runway=self:GetActiveRunway()
|
||||
|
||||
local heading=runway.heading
|
||||
|
||||
local vec2=self.airbase:GetVec2()
|
||||
|
||||
local Vec2=UTILS.Vec2Translate(vec2, UTILS.NMToMeters(5), heading+90)
|
||||
|
||||
local ArrivalZone=ZONE_RADIUS:New("Arrival Zone", Vec2, 5000)
|
||||
|
||||
-- Add holding pattern with very low priority.
|
||||
self.holdingBackup=self:AddHoldingPattern(ArrivalZone, heading, 15, 5, 25, 999)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Remove a holding pattern.
|
||||
-- @param #FLIGHTCONTROL self
|
||||
-- @param #FLIGHTCONTROL.HoldingPattern HoldingPattern Holding pattern to be removed.
|
||||
-- @param #FLIGHTCONTROL self
|
||||
function FLIGHTCONTROL:RemoveHoldingPattern(HoldingPattern)
|
||||
|
||||
for i,_holdingpattern in pairs(self.holdingpatterns) do
|
||||
local hp=_holdingpattern --#FLIGHTCONTROL.HoldingPattern
|
||||
|
||||
if hp.uid==HoldingPattern.uid then
|
||||
table.remove(self.holdingpatterns, i)
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@ -470,6 +587,36 @@ function FLIGHTCONTROL:SetParkingGuardStatic(TemplateStaticName)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set ATIS.
|
||||
-- @param #FLIGHTCONTROL self
|
||||
-- @param Ops.Atis#ATIS Atis ATIS.
|
||||
-- @return #FLIGHTCONTROL self
|
||||
function FLIGHTCONTROL:SetATIS(Atis)
|
||||
self.atis=Atis
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get coordinate of the airbase.
|
||||
-- @param #FLIGHTCONTROL self
|
||||
-- @return Core.Point#COORDINATE Coordinate of the airbase.
|
||||
function FLIGHTCONTROL:GetCoordinate()
|
||||
return self.airbase:GetCoordinate()
|
||||
end
|
||||
|
||||
--- Get coalition of the airbase.
|
||||
-- @param #FLIGHTCONTROL self
|
||||
-- @return #number Coalition ID.
|
||||
function FLIGHTCONTROL:GetCoalition()
|
||||
return self.airbase:GetCoalition()
|
||||
end
|
||||
|
||||
--- Get country of the airbase.
|
||||
-- @param #FLIGHTCONTROL self
|
||||
-- @return #number Country ID.
|
||||
function FLIGHTCONTROL:GetCountry()
|
||||
return self.airbase:GetCountry()
|
||||
end
|
||||
|
||||
--- Is flight in queue of this flightcontrol.
|
||||
-- @param #FLIGHTCONTROL self
|
||||
-- @param Ops.FlightGroup#FLIGHTGROUP Flight Flight group.
|
||||
@ -507,6 +654,7 @@ function FLIGHTCONTROL:onafterStart()
|
||||
self:HandleEvent(EVENTS.Land)
|
||||
self:HandleEvent(EVENTS.EngineShutdown)
|
||||
self:HandleEvent(EVENTS.Crash)
|
||||
self:HandleEvent(EVENTS.Kill)
|
||||
|
||||
-- Init status updates.
|
||||
self:__Status(-1)
|
||||
@ -2036,6 +2184,8 @@ function FLIGHTCONTROL:_PlayerInfoATIS(groupname)
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
text=text.." Not defined"
|
||||
end
|
||||
|
||||
-- Message to flight
|
||||
@ -2148,7 +2298,7 @@ function FLIGHTCONTROL:_PlayerRequestInbound(groupname)
|
||||
|
||||
if dist<UTILS.NMToMeters(50) then
|
||||
|
||||
-- Call RTB event. This also sets the flight control and flight status to INBOUND and updates the menu.
|
||||
-- Call RTB event. This only sets the FC for AI.
|
||||
flight:RTB(self.airbase)
|
||||
|
||||
-- Get holding point.
|
||||
@ -2176,8 +2326,22 @@ function FLIGHTCONTROL:_PlayerRequestInbound(groupname)
|
||||
|
||||
-- Send message.
|
||||
self:TransmissionTower(text, flight, 15)
|
||||
|
||||
-- Set flightcontrol for this flight. This also updates the menu.
|
||||
flight:SetFlightControl(self)
|
||||
|
||||
-- Add flight to inbound queue.
|
||||
self:SetFlightStatus(flight, FLIGHTCONTROL.FlightStatus.INBOUND)
|
||||
|
||||
else
|
||||
|
||||
-- Message text.
|
||||
local text=string.format("Negative, could not get a holding stack for you! Try again later...")
|
||||
|
||||
-- Send message.
|
||||
self:TextMessageToFlight(text, flight, 10)
|
||||
|
||||
-- Debug message.
|
||||
self:E(self.lid..string.format("WARNING: Could not get holding stack for flight %s", flight:GetName()))
|
||||
end
|
||||
|
||||
@ -3023,12 +3187,13 @@ function FLIGHTCONTROL:_RemoveFlight(Flight)
|
||||
if not flight.isAI then
|
||||
flight:_UpdateMenu(0.5)
|
||||
end
|
||||
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
self:E(self.lid..string.format("WARNING: Could NOT remove flight group %s from %s queue", flight.groupname, queuename))
|
||||
-- Debug message.
|
||||
self:E(self.lid..string.format("WARNING: Could NOT remove flight group %s", Flight.groupname))
|
||||
end
|
||||
|
||||
--- Get flight from group.
|
||||
@ -3222,22 +3387,6 @@ end
|
||||
-- @return #FLIGHTCONTROL.HoldingStack Holding point.
|
||||
function FLIGHTCONTROL:_GetHoldingStack(flight)
|
||||
|
||||
--[[
|
||||
local holdingpattern={} --#FLIGHTCONTROL.HoldingPattern
|
||||
|
||||
local runway=self:GetActiveRunway()
|
||||
|
||||
local hdg=runway.heading+90
|
||||
local dx=UTILS.NMToMeters(5)
|
||||
local dz=UTILS.NMToMeters(1)
|
||||
|
||||
local angels=UTILS.FeetToMeters(math.random(6,10)*1000)
|
||||
|
||||
holdingpattern.pos0=runway.position:Translate(dx, hdg):SetAltitude(angels)
|
||||
holdingpattern.pos1=holdingpattern.pos0:Translate(dz, runway.heading):SetAltitude(angels)
|
||||
|
||||
]]
|
||||
|
||||
-- Debug message.
|
||||
self:T(self.lid..string.format("Getting holding point for flight %s", flight:GetName()))
|
||||
|
||||
@ -3416,27 +3565,6 @@ function FLIGHTCONTROL:RemoveParkingGuard(spot, delay)
|
||||
end
|
||||
|
||||
|
||||
--- Get coordinate of the airbase.
|
||||
-- @param #FLIGHTCONTROL self
|
||||
-- @return Core.Point#COORDINATE Coordinate of the airbase.
|
||||
function FLIGHTCONTROL:GetCoordinate()
|
||||
return self.airbase:GetCoordinate()
|
||||
end
|
||||
|
||||
--- Get coalition of the airbase.
|
||||
-- @param #FLIGHTCONTROL self
|
||||
-- @return #number Coalition ID.
|
||||
function FLIGHTCONTROL:GetCoalition()
|
||||
return self.airbase:GetCoalition()
|
||||
end
|
||||
|
||||
--- Get country of the airbase.
|
||||
-- @param #FLIGHTCONTROL self
|
||||
-- @return #number Country ID.
|
||||
function FLIGHTCONTROL:GetCountry()
|
||||
return self.airbase:GetCountry()
|
||||
end
|
||||
|
||||
--- Returns the unit of a player and the player name. If the unit does not belong to a player, nil is returned.
|
||||
-- @param #FLIGHTCONTROL self
|
||||
-- @param #string unitName Name of the player unit.
|
||||
|
||||
@ -1695,7 +1695,7 @@ function FLIGHTGROUP:onafterParking(From, Event, To)
|
||||
end
|
||||
|
||||
else
|
||||
env.info("FF no flight control!")
|
||||
self:E(self.lid.."ERROR: FF no flight control in onAfterParking!")
|
||||
end
|
||||
end
|
||||
|
||||
@ -2328,6 +2328,9 @@ end
|
||||
-- @param #number SpeedHold Holding speed in knots.
|
||||
function FLIGHTGROUP:onbeforeRTB(From, Event, To, airbase, SpeedTo, SpeedHold)
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("RTB: before event=%s: %s --> %s to %s", Event, From, To, airbase and airbase:GetName() or "None"))
|
||||
|
||||
if self:IsAlive() then
|
||||
|
||||
local allowed=true
|
||||
@ -4296,7 +4299,7 @@ function FLIGHTGROUP:_PlayerMyStatus(groupname)
|
||||
local text=string.format("My Status:")
|
||||
text=text..string.format("\nCallsign: %s", tostring(flight:GetCallsignName()))
|
||||
text=text..string.format("\nFlight status: %s", tostring(flight:GetState()))
|
||||
text=text..string.format("\nFlight control: %s status=%s", tostring(fc and fc.airbasename or "N/A"), tostring(fc and fc:GetFlightStatus(flight) or "N/A"))
|
||||
text=text..string.format("\nFlight control: %s [%s]", tostring(fc and fc.airbasename or "N/A"), tostring(fc and fc:GetFlightStatus(flight) or "N/A"))
|
||||
|
||||
-- Send message.
|
||||
--self:TextMessageToFlight(text, flight, 10, true)
|
||||
|
||||
@ -1869,8 +1869,9 @@ function LEGION:GetOpsGroups(MissionTypes, Attributes)
|
||||
|
||||
for _,_cohort in pairs(self.cohorts) do
|
||||
local cohort=_cohort --Ops.Cohort#COHORT
|
||||
local setcohort=cohort:GetOpsGroups(MissionTypes, Attributes)
|
||||
setLegion:AddSet(setcohort)
|
||||
local setCohort=cohort:GetOpsGroups(MissionTypes, Attributes)
|
||||
self:I(self.lid..string.format("Found %d opsgroups of cohort %s", setCohort:Count(), cohort.name))
|
||||
setLegion:AddSet(setCohort)
|
||||
end
|
||||
|
||||
return setLegion
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
-- @field #number counterPhase Running number counting the phases.
|
||||
-- @field #OPERATION.Phase phase Currently active phase (if any).
|
||||
-- @field #table targets Targets.
|
||||
-- @field #table missions Missions.
|
||||
--
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
@ -54,6 +55,7 @@ OPERATION = {
|
||||
phases = {},
|
||||
counterPhase = 0,
|
||||
targets = {},
|
||||
missions = {},
|
||||
}
|
||||
|
||||
--- Global mission counter.
|
||||
@ -136,16 +138,15 @@ function OPERATION:New(Name)
|
||||
--- Pseudo Functions ---
|
||||
------------------------
|
||||
|
||||
--- Triggers the FSM event "StatusUpdate".
|
||||
-- @function [parent=#OPERATION] StatusUpdate
|
||||
--- Triggers the FSM event "Start".
|
||||
-- @function [parent=#OPERATION] Start
|
||||
-- @param #OPERATION self
|
||||
|
||||
--- Triggers the FSM event "Status" after a delay.
|
||||
-- @function [parent=#OPERATION] __StatusUpdate
|
||||
--- Triggers the FSM event "Start" after a delay.
|
||||
-- @function [parent=#OPERATION] __Start
|
||||
-- @param #OPERATION self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
|
||||
--- Triggers the FSM event "Stop".
|
||||
-- @function [parent=#OPERATION] Stop
|
||||
-- @param #OPERATION self
|
||||
@ -155,6 +156,15 @@ function OPERATION:New(Name)
|
||||
-- @param #OPERATION self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
--- Triggers the FSM event "StatusUpdate".
|
||||
-- @function [parent=#OPERATION] StatusUpdate
|
||||
-- @param #OPERATION self
|
||||
|
||||
--- Triggers the FSM event "Status" after a delay.
|
||||
-- @function [parent=#OPERATION] __StatusUpdate
|
||||
-- @param #OPERATION self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
|
||||
--- Triggers the FSM event "PhaseChange".
|
||||
-- @function [parent=#OPERATION] PhaseChange
|
||||
@ -243,6 +253,36 @@ function OPERATION:AddPhase(Name)
|
||||
return phase
|
||||
end
|
||||
|
||||
--- Add mission to operation.
|
||||
-- @param #OPERATION self
|
||||
-- @param Ops.Auftrag#AUFTRAG Mission The mission to add.
|
||||
-- @param #OPERATION.Phase Phase (Optional) The phase in which the mission should be executed. If no phase is given, it will be exectuted ASAP.
|
||||
function OPERATION:AddMission(Mission, Phase)
|
||||
|
||||
Mission.phase=Phase
|
||||
Mission.operation=self
|
||||
|
||||
table.insert(self.missions, Mission)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add Target to operation.
|
||||
-- @param #OPERATION self
|
||||
-- @param Ops.Target#TARGET Target The target to add.
|
||||
-- @param #OPERATION.Phase Phase (Optional) The phase in which the target should be attacked. If no phase is given, it will be attacked ASAP.
|
||||
function OPERATION:AddTarget(Target, Phase)
|
||||
|
||||
Target.phase=Phase
|
||||
Target.operation=self
|
||||
|
||||
table.insert(self.targets, Target)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Get a phase by its name.
|
||||
-- @param #OPERATION self
|
||||
-- @param #string Name Name of the phase. Default "Phase-01" where the last number is a running number.
|
||||
@ -310,6 +350,14 @@ function OPERATION:IsAssignedCohort(Cohort)
|
||||
self:T(self.lid..string.format("Cohort %s is assigned to this operation", Cohort.name))
|
||||
return true
|
||||
else
|
||||
|
||||
-- Check if legion of this cohort was assigned.
|
||||
local Legion=Cohort.legion
|
||||
if Legion and self:IsAssignedLegion(Legion) then
|
||||
self:T(self.lid..string.format("Legion %s of Cohort %s is assigned to this operation", Legion.alias, Cohort.name))
|
||||
return true
|
||||
end
|
||||
|
||||
self:T(self.lid..string.format("Cohort %s is NOT assigned to this operation", Cohort.name))
|
||||
return false
|
||||
end
|
||||
@ -460,6 +508,22 @@ function OPERATION:GetPhaseActive()
|
||||
return self.phase
|
||||
end
|
||||
|
||||
--- Get name of a phase.
|
||||
-- @param #OPERATION self
|
||||
-- @param #OPERATION.Phase Phase The phase of which the name is returned.
|
||||
-- @return #string The name of the phase.
|
||||
function OPERATION:GetPhaseName(Phase)
|
||||
|
||||
Phase=Phase or self.phase
|
||||
|
||||
if Phase then
|
||||
return Phase.name
|
||||
else
|
||||
return "None"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Check if a phase is the currently active one.
|
||||
-- @param #OPERATION self
|
||||
-- @param #OPERATION.Phase Phase The phase to check.
|
||||
@ -509,6 +573,24 @@ function OPERATION:CountPhases(Status)
|
||||
return N
|
||||
end
|
||||
|
||||
--- Count targets alive.
|
||||
-- @param #OPERATION self
|
||||
-- @param #OPERATION.Phase Phase (Optional) Only count targets set for this phase.
|
||||
-- @return #number Number of phases
|
||||
function OPERATION:CountTargets(Phase)
|
||||
|
||||
local N=0
|
||||
for _,_target in pairs(self.targets) do
|
||||
local target=_target --Ops.Target#TARGET
|
||||
|
||||
if target:IsAlive() and (Phase==nil or target.phase==Phase) then
|
||||
N=N+1
|
||||
end
|
||||
end
|
||||
|
||||
return N
|
||||
end
|
||||
|
||||
--- Check if operation is in FSM state "Planned".
|
||||
-- @param #OPERATION self
|
||||
-- @return #boolean If `true`, operation is "Planned".
|
||||
|
||||
@ -4162,6 +4162,17 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
|
||||
---
|
||||
|
||||
-- Just stay put and wait until something happens.
|
||||
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.REARMING then
|
||||
|
||||
---
|
||||
-- Task "Rearming"
|
||||
---
|
||||
|
||||
-- Check if ammo is full.
|
||||
|
||||
local rearmed=self:_CheckAmmoFull()
|
||||
|
||||
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.ALERT5 then
|
||||
|
||||
@ -4483,8 +4494,10 @@ function OPSGROUP:onafterTaskCancel(From, Event, To, Task)
|
||||
done=true
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.AMMOSUPPLY then
|
||||
done=true
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.FUELSUPPLY then
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.FUELSUPPLY then
|
||||
done=true
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.REARMING then
|
||||
done=true
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.ALERT5 then
|
||||
done=true
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.ONGUARD or Task.dcstask.id==AUFTRAG.SpecialTask.ARMOREDGUARD then
|
||||
@ -4944,7 +4957,12 @@ function OPSGROUP:onbeforeMissionStart(From, Event, To, Mission)
|
||||
|
||||
-- Startup group if it is uncontrolled. Alert 5 aircraft will not be started though!
|
||||
if self:IsFlightgroup() and self:IsUncontrolled() and Mission.type~=AUFTRAG.Type.ALERT5 then
|
||||
self:StartUncontrolled(delay)
|
||||
local fc=FLIGHTGROUP.GetFlightControl(self)
|
||||
if fc and fc:IsControlling(self) then
|
||||
FLIGHTGROUP.SetReadyForTakeoff(self, true)
|
||||
else
|
||||
self:StartUncontrolled(delay)
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
@ -4972,9 +4990,9 @@ function OPSGROUP:onafterMissionStart(From, Event, To, Mission)
|
||||
Mission:__Started(3)
|
||||
|
||||
-- Set ready for takeoff in case of FLIGHTCONTROL.
|
||||
if self.isFlightgroup and Mission.type~=AUFTRAG.Type.ALERT5 then
|
||||
FLIGHTGROUP.SetReadyForTakeoff(self, true)
|
||||
end
|
||||
--if self.isFlightgroup and Mission.type~=AUFTRAG.Type.ALERT5 then
|
||||
-- FLIGHTGROUP.SetReadyForTakeoff(self, true)
|
||||
--end
|
||||
|
||||
-- Route group to mission zone.
|
||||
if self.speedMax>3.6 or true then
|
||||
@ -5399,8 +5417,9 @@ function OPSGROUP:RouteToMission(mission, delay)
|
||||
|
||||
elseif mission.type==AUFTRAG.Type.PATROLZONE or
|
||||
mission.type==AUFTRAG.Type.BARRAGE or
|
||||
mission.type==AUFTRAG.Type.AMMOSUPPLY or
|
||||
mission.type==AUFTRAG.Type.FUELSUPPLY or
|
||||
mission.type==AUFTRAG.Type.AMMOSUPPLY or
|
||||
mission.type==AUFTRAG.Type.FUELSUPPLY or
|
||||
mission.type==AUFTRAG.Type.REARMING or
|
||||
mission.type==AUFTRAG.Type.AIRDEFENSE or
|
||||
mission.type==AUFTRAG.Type.EWR then
|
||||
---
|
||||
@ -5540,8 +5559,6 @@ function OPSGROUP:RouteToMission(mission, delay)
|
||||
|
||||
if inRange then
|
||||
|
||||
env.info("FF in range!")
|
||||
|
||||
waypointcoord=self:GetCoordinate(true)
|
||||
|
||||
else
|
||||
|
||||
@ -100,6 +100,7 @@ end
|
||||
-- Start & Status
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--[[
|
||||
--- On after Start event. Starts the FLIGHTGROUP FSM and event handlers.
|
||||
-- @param #PLATOON self
|
||||
-- @param #string From From state.
|
||||
@ -114,6 +115,7 @@ function PLATOON:onafterStart(From, Event, To)
|
||||
-- Start the status monitoring.
|
||||
self:__Status(-1)
|
||||
end
|
||||
]]
|
||||
|
||||
--- On after "Status" event.
|
||||
-- @param #PLATOON self
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user