Enhanced OPERATION and FLIGHTCONTROL features.
This commit is contained in:
Frank 2022-06-06 22:05:57 +02:00
parent 9b3f2ae3c7
commit a53595a055
14 changed files with 443 additions and 106 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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
---------------------

View File

@ -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

View File

@ -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()

View File

@ -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
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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".

View File

@ -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

View File

@ -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