mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-07-17 07:33:56 +00:00
Ops
This commit is contained in:
@@ -5601,7 +5601,7 @@ function WAREHOUSE:_SpawnAssetAircraft(alias, asset, request, parking, uncontrol
|
||||
end
|
||||
|
||||
if asset.payload then
|
||||
unit.payload=asset.payload
|
||||
unit.payload.pylons=asset.payload.pylons
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
--- **Ops** - (R2.5) - Aerial refueling tanker.
|
||||
--
|
||||
-- **Main Features:**
|
||||
--
|
||||
-- * Monitor flight status of elements or entire group.
|
||||
-- * Create a mission queue.
|
||||
-- * Inherits FLIGHTGROUP class.
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **funkyfranky**
|
||||
-- @module Ops.AwacsGroup
|
||||
-- @image OPS_AwacsGroup.png
|
||||
|
||||
|
||||
--- AWACSGROUP class.
|
||||
-- @type AWACSGROUP
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #boolean Debug Debug mode. Messages to all about status.
|
||||
-- @field #string lid Class id string for output to DCS log file.
|
||||
-- @extends Ops.FlightGroup#FLIGHTGROUP
|
||||
|
||||
--- *To invent an airplane is nothing. To build one is something. To fly is everything.* -- Otto Lilienthal
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # The AWACSGROUP Concept
|
||||
--
|
||||
-- # Events
|
||||
--
|
||||
--
|
||||
-- # Tasking
|
||||
--
|
||||
--
|
||||
-- # Examples
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
-- @field #AWACSGROUP
|
||||
AWACSGROUP = {
|
||||
ClassName = "AWACSGROUP",
|
||||
Debug = false,
|
||||
lid = nil,
|
||||
awacszones = nil,
|
||||
missionqueue = {},
|
||||
currentmission = nil,
|
||||
missioncounter = nil,
|
||||
}
|
||||
|
||||
--- Tanker mission table.
|
||||
-- @type AWACSGROUP.Mission
|
||||
-- @field #string name Name of the mission.
|
||||
-- @field #number mid ID of the mission.
|
||||
-- @field #number tid ID of the assigned FLIGHTGROUP task.
|
||||
-- @field Core.Zone#ZONE zone Mission zone.
|
||||
-- @field #number duration Duration of mission.
|
||||
-- @field #number altitude Altitude of orbit in meters ASL.
|
||||
-- @field #number distance Length of orbit leg in meters.
|
||||
-- @field #number heading Heading of orbit in degrees.
|
||||
-- @field #number speed Speed in m/s.
|
||||
-- @field #number Tadded Time the mission was added.
|
||||
-- @field #number Tstart Start time in seconds.
|
||||
-- @field #number Tstarted Time the mission was started.
|
||||
-- @field #number Tstop Time the mission is stopped.
|
||||
-- @field #number Tsopped Time the mission was stopped.
|
||||
|
||||
--- AWACSGROUP class version.
|
||||
-- @field #string version
|
||||
AWACSGROUP.version="0.0.1"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Add orbit task.
|
||||
-- TODO: Add client queue.
|
||||
-- TODO: Add menu?
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Create a new AWACSGROUP object and start the FSM.
|
||||
-- @param #AWACSGROUP self
|
||||
-- @param #string groupname Name of the group.
|
||||
-- @return #AWACSGROUP self
|
||||
function AWACSGROUP:New(groupname)
|
||||
|
||||
|
||||
end
|
||||
@@ -20,7 +20,6 @@
|
||||
-- @field #table menu Table of menu items.
|
||||
-- @field #table squadrons Table of squadrons.
|
||||
-- @field #table missionqueue Mission queue table.
|
||||
-- @field #table missioncounter Running index counting the added missions.
|
||||
-- @field #table payloads Playloads for specific aircraft and mission types.
|
||||
-- @extends Functional.Warehouse#WAREHOUSE
|
||||
|
||||
@@ -42,7 +41,6 @@ AIRWING = {
|
||||
menu = nil,
|
||||
squadrons = nil,
|
||||
missionqueue = {},
|
||||
missioncounter = nil,
|
||||
payloads = {},
|
||||
}
|
||||
|
||||
@@ -57,24 +55,18 @@ AIRWING = {
|
||||
|
||||
--- Squadron asset.
|
||||
-- @type AIRWING.SquadronAsset
|
||||
-- @field #AIRWING.Missiondata mission The assigned mission.
|
||||
-- @field #AIRWING.Payload payload The payload of the asset.
|
||||
-- @field Ops.Auftrag#AUFTRAG mission The assigned mission.
|
||||
-- @field Ops.FlightGroup#FLIGHTGROUP flightgroup The flightgroup object.
|
||||
-- @extends Functional.Warehouse#WAREHOUSE.Assetitem
|
||||
|
||||
--- Mission data.
|
||||
-- @type AIRWING.Missiondata
|
||||
-- @extends Ops.FlightGroup#FLIGHTGROUP.Mission
|
||||
-- @field #number MID Mission ID.
|
||||
-- @field #string squadname Name of the assigned squadron.
|
||||
-- @field #table assets Assets assigned for this mission.
|
||||
-- @field #number nassets Number of required assets.
|
||||
|
||||
--- Payload data.
|
||||
-- @type AIRWING.Payload
|
||||
-- @field #string aircrafttype Type of aircraft, which can use this payload.
|
||||
-- @field #table missiontypes Mission types for which this payload can be used.
|
||||
-- @field #table pylons Pylon data extracted for the unit template.
|
||||
-- @field #number navail Number of available payloads of this type.
|
||||
-- @field #number nreserved Number of payloads reserved.
|
||||
|
||||
|
||||
--- AIRWING class version.
|
||||
@@ -112,15 +104,12 @@ function AIRWING:New(warehousename, airwingname)
|
||||
return nil
|
||||
end
|
||||
|
||||
self.warehousename=warehousename
|
||||
|
||||
-- Squadrons.
|
||||
self.squadrons={}
|
||||
|
||||
self.missioncounter=0
|
||||
|
||||
|
||||
-- Set some string id for output to DCS.log file.
|
||||
self.lid=string.format("AIRWING %s | ", airwingname)
|
||||
self.lid=string.format("AIRWING %s | ", self.alias)
|
||||
|
||||
-- Add FSM transitions.
|
||||
-- From State --> Event --> To State
|
||||
@@ -153,9 +142,9 @@ function AIRWING:New(warehousename, airwingname)
|
||||
-- Debug trace.
|
||||
if false then
|
||||
self.Debug=true
|
||||
BASE:TraceOnOff(true)
|
||||
BASE:TraceClass(self.ClassName)
|
||||
BASE:TraceLevel(1)
|
||||
self:TraceOnOff(true)
|
||||
self:TraceClass(self.ClassName)
|
||||
self:TraceLevel(1)
|
||||
end
|
||||
|
||||
return self
|
||||
@@ -189,42 +178,46 @@ end
|
||||
|
||||
--- Add a payload to air wing resources.
|
||||
-- @param #AIRWING self
|
||||
-- @param #string UnitName Name of the (template) unit from which the payload is extracted.
|
||||
-- @param #number Npayloads Number of payloads to add to the airwing resources. Default 99 (which should be enough for most scenarios).
|
||||
-- @param #string AircraftType Type of aircraft which can use this payload.
|
||||
-- @param #table Pylons The pylons table from UNIT:FindByName("Unitname"):GetTemplatePylons().
|
||||
-- @param #table MissionTypes Mission types this payload can be used for.
|
||||
function AIRWING:AddPayload(UnitName, Npayloads, MissionTypes)
|
||||
-- @param #number Npayloads Number of payloads to add to the airwing resources. Default 99 (which should be enough for most scenarios).
|
||||
function AIRWING:AddPayload(AircraftType, Pylons, MissionTypes, Npayloads)
|
||||
|
||||
local payload=self:GetPayloadByName(UnitName)
|
||||
|
||||
if payload then
|
||||
|
||||
-- Payload already exists. Increase the number.
|
||||
payload.navail=payload.navail+Npayloads
|
||||
|
||||
--TODO: maybe check if mission types given now are different from before.
|
||||
|
||||
else
|
||||
|
||||
local unit=UNIT:FindByName(UnitName)
|
||||
|
||||
if unit then
|
||||
|
||||
payload={} --#AIRWING.Payload
|
||||
|
||||
payload.navail=Npayloads
|
||||
payload.missiontypes=MissionTypes
|
||||
payload.aircrafttype=unit:GetTypeName()
|
||||
payload.pylons=unit:GetTemplatePylons()
|
||||
|
||||
--TODO: maybe add fuel, chaff and gun?
|
||||
|
||||
--table.insert(self.payloads, payload)
|
||||
self.payloads[UnitName]=payload
|
||||
local payload=nil --#AIRWING.Payload
|
||||
if self.payloads[AircraftType] then
|
||||
payload=self.payloads[AircraftType]
|
||||
else
|
||||
payload={}
|
||||
payload.navail=Npayloads or 99
|
||||
payload.navail=Npayloads or 99
|
||||
payload.missiontypes=MissionTypes
|
||||
payload.aircrafttype=AircraftType
|
||||
payload.pylons=Pylons
|
||||
payload.nreserved=0
|
||||
self.payloads[AircraftType]=payload
|
||||
end
|
||||
|
||||
|
||||
|
||||
--[[
|
||||
payload={} --#AIRWING.Payload
|
||||
|
||||
payload.navail=Npayloads or 99
|
||||
payload.missiontypes=MissionTypes
|
||||
payload.aircrafttype=unit:GetTypeName()
|
||||
payload.pylons=unit:GetTemplatePylons()
|
||||
payload.nreserved=0
|
||||
|
||||
--TODO: maybe add fuel, chaff and gun?
|
||||
|
||||
self.payloads[UnitName]=payload
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
]]
|
||||
end
|
||||
|
||||
--- Add a payload to air wing resources.
|
||||
@@ -235,6 +228,15 @@ function AIRWING:GetPayloadByName(UnitName)
|
||||
return self.payloads[UnitName]
|
||||
end
|
||||
|
||||
--- Add a payload to air wing resources.
|
||||
-- @param #AIRWING self
|
||||
-- @param #AIRWING.SquadronAsset asset The squadron asset.
|
||||
-- @param #string MissionType The mission type.
|
||||
-- @return #AIRWING.Payload
|
||||
function AIRWING:GetPayloadForAsset(asset, MissionType)
|
||||
return self.payloads[UnitName]
|
||||
end
|
||||
|
||||
|
||||
--- Add flight group(s) to squadron.
|
||||
-- @param #AIRWING self
|
||||
@@ -279,45 +281,29 @@ function AIRWING:GetSquadron(SquadronName)
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Create a CAP mission.
|
||||
-- @param #AIRWING self
|
||||
-- @param Core.Point#COORDINATE OrbitCoordinate Where to orbit. Altitude is also taken from the coordinate.
|
||||
-- @param #number OrbitSpeed Orbit speed in knots. Default 350 kts.
|
||||
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
||||
-- @param #number Leg Length of race-track in NM. Default 10 NM.
|
||||
-- @param Core.Zone#ZONE_RADIUS ZoneCAP Circular CAP zone. Detected targets in this zone will be engaged.
|
||||
-- @param #table TargetTypes Table of target types. Default {"Air"}.
|
||||
-- @return Ops.FlightGroup#FLIGHTGROUP.MissionCAP The CAP mission table.
|
||||
function AIRWING:CreateMissionCAP(OrbitCoordinate, OrbitSpeed, Heading, Leg, ZoneCap, TargetTypes)
|
||||
|
||||
local mission=FLIGHTGROUP.CreateMissionCAP(self, OrbitCoordinate, OrbitSpeed, Heading, Leg, ZoneCap, TargetTypes)
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
--- Add mission to queue.
|
||||
-- @param #AIRWING self
|
||||
-- @param #AIRWING.Missiondata Mission for this group.
|
||||
-- @param Ops.Auftrag#AUFTRAG Mission for this group.
|
||||
-- @param #number Nassets Number of required assets for this mission. Default 1.
|
||||
-- @param Core.Point#COORDINATE WaypointCoordinate Coordinate of the mission waypoint.
|
||||
-- @param #string ClockStart Time the mission is started, e.g. "05:00" for 5 am. If specified as a #number, it will be relative (in seconds) to the current mission time. Default is 5 seconds after mission was added.
|
||||
-- @param #string ClockStop Time the mission is stopped, e.g. "13:00" for 1 pm. If mission could not be started at that time, it will be removed from the queue. If specified as a #number it will be relative (in seconds) to the current mission time.
|
||||
-- @param #number Prio Priority of the mission, i.e. a number between 1 and 100. Default 50.
|
||||
-- @param #string Name Mission name. Default "Aerial Refueling #00X", where "#00X" is a running mission counter index starting at "#001".
|
||||
-- @return #AIRWING.Missiondata The mission table.
|
||||
function AIRWING:AddMission(Mission, Nassets, WaypointCoordinate, ClockStart, ClockStop, Prio, Name)
|
||||
|
||||
-- TODO: need to check that this call increases the correct mission counter and adds it to the mission queue.
|
||||
local mission=FLIGHTGROUP.AddMission(self, Mission, WaypointCoordinate, nil, ClockStart, ClockStop, Prio, Name)
|
||||
-- @return #AIRWING self
|
||||
function AIRWING:AddMission(Mission, Nassets, WaypointCoordinate)
|
||||
|
||||
mission.nassets=Nassets or 1
|
||||
|
||||
-- Mission needs the correct MID.
|
||||
mission.mid=nil
|
||||
mission.MID=self.missioncounter
|
||||
-- Number of assets.
|
||||
Mission.nassets=Nassets or 1
|
||||
|
||||
return mission
|
||||
Mission.waypointcoordinate=WaypointCoordinate
|
||||
Mission.waypointindex=nil
|
||||
|
||||
-- Add mission to queue.
|
||||
table.insert(self.missionqueue, Mission)
|
||||
|
||||
-- Info text.
|
||||
local text=string.format("Added %s mission %s at waypoint #%s. Starting at %s. Stopping at %s",
|
||||
tostring(Mission.type), tostring(Mission.name), tostring(Mission.waypointindex), UTILS.SecondsToClock(Mission.Tstart, true), Mission.Tstop and UTILS.SecondsToClock(Mission.Tstop, true) or "never")
|
||||
self:I(self.lid..text)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -332,7 +318,7 @@ function AIRWING:onafterStart(From, Event, To)
|
||||
self:GetParent(self).onafterStart(self, From, Event, To)
|
||||
|
||||
-- Info.
|
||||
self:I(self.lid..string.format("Starting AIRWING v%s %s (%s)", AIRWING.version, self.alias, self.warehousename))
|
||||
self:I(self.lid..string.format("Starting AIRWING v%s", AIRWING.version))
|
||||
|
||||
-- Add F10 radio menu.
|
||||
self:_SetMenuCoalition()
|
||||
@@ -429,8 +415,8 @@ function AIRWING:_GetNextMission()
|
||||
|
||||
-- Sort results table wrt times they have already been engaged.
|
||||
local function _sort(a, b)
|
||||
local taskA=a --#AIRWING.Missiondata
|
||||
local taskB=b --#AIRWING.Missiondata
|
||||
local taskA=a --Ops.Auftrag#AUFTRAG
|
||||
local taskB=b --Ops.Auftrag#AUFTRAG
|
||||
--TODO: probably sort by prio first and then by time as only missions for T>Tstart are executed. That would ensure that the highest prio mission is carried out first!
|
||||
return (taskA.Tstart<taskB.Tstart) or (taskA.Tstart==taskB.Tstart and taskA.prio<taskB.prio)
|
||||
end
|
||||
@@ -441,23 +427,30 @@ function AIRWING:_GetNextMission()
|
||||
|
||||
-- Look for first task that is not accomplished.
|
||||
for _,_mission in pairs(self.missionqueue) do
|
||||
local mission=_mission --#AIRWING.Missiondata
|
||||
local mission=_mission --Ops.Auftrag#AUFTRAG
|
||||
|
||||
-- Check if airwing can do the mission and gather required assets.
|
||||
local can, assets=self:CanMission(mission.type, mission.nassets)
|
||||
|
||||
-- Debug output.
|
||||
self:T3({self.lid.."Mission check:", MissionStatusScheduled=mission.status==FLIGHTGROUP.MissionStatus.SCHEDULED, TstartPassed=time>=mission.Tstart, CanMission=can, Nassets=#assets})
|
||||
self:T3({self.lid.."Mission check:", MissionStatusScheduled=mission.status==AUFTRAG.Status.SCHEDULED, TstartPassed=time>=mission.Tstart, CanMission=can, Nassets=#assets})
|
||||
|
||||
-- Check that mission is still scheduled, time has passed and enough assets are available.
|
||||
if mission.status==FLIGHTGROUP.MissionStatus.SCHEDULED and time>=mission.Tstart and can then
|
||||
if mission.status==AUFTRAG.Status.SCHEDULED and time>=mission.Tstart and can then
|
||||
|
||||
-- TODO: check that mission.assets table is clean.
|
||||
mission.assets=mission.assets or {}
|
||||
|
||||
-- Assign assets to mission.
|
||||
for i=1,mission.nassets do
|
||||
|
||||
local asset=assets[i] --#AIRWING.SquadronAsset
|
||||
|
||||
asset.payload=self:GetPayloadForAsset(asset, mission.type)
|
||||
if not asset.payload then
|
||||
self:E("No payload for asset! This should not happen!")
|
||||
end
|
||||
|
||||
table.insert(mission.assets, asset)
|
||||
asset.mission=mission
|
||||
end
|
||||
@@ -469,6 +462,41 @@ function AIRWING:_GetNextMission()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get next mission.
|
||||
-- @param #AIRWING self
|
||||
-- @param #table assets Table of (unoptimized) assets.
|
||||
-- @return #AIRWING.Missiondata Next mission or *nil*.
|
||||
function AIRWING:_OptimizeAssetSelection(assets, Mission)
|
||||
|
||||
local TargetCoordinate=Mission:GetTargetCoordinate()
|
||||
|
||||
local dStock=self:GetCoordinate():Get2DDistance(TargetCoordinate)
|
||||
|
||||
-- Sort results table wrt distacance.
|
||||
local function _sort(a, b)
|
||||
local assetA=a --#AIRWING.SquadronAsset
|
||||
local assetB=b --#AIRWING.SquadronAsset
|
||||
|
||||
local dA=dStock
|
||||
if assetA.spawned then
|
||||
local group=GROUP:FindByName(assetA.spawngroupname)
|
||||
dA=group:GetCoordinate():Get2DDistance(TargetCoordinate)
|
||||
end
|
||||
|
||||
local dB=dStock
|
||||
if assetB.spawned then
|
||||
local group=GROUP:FindByName(assetA.spawngroupname)
|
||||
dB=group:GetCoordinate():Get2DDistance(TargetCoordinate)
|
||||
end
|
||||
|
||||
|
||||
return (dA<dB) or (dA==dB and taskA.prio<taskB.prio)
|
||||
end
|
||||
table.sort(assets, _sort)
|
||||
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- FSM Events
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -519,14 +547,14 @@ end
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #AIRWING.Missiondata Mission The requested mission.
|
||||
-- @param Ops.Auftrag#AUFTRAG Mission The requested mission.
|
||||
function AIRWING:onafterMissionRequest(From, Event, To, Mission)
|
||||
|
||||
-- Set mission status to ASSIGNED.
|
||||
Mission.status=FLIGHTGROUP.MissionStatus.ASSIGNED
|
||||
Mission.status=AUFTRAG.Status.ASSIGNED
|
||||
|
||||
--TODO: Check that mission prio is same as warehouse prio (small=high or the other way around).
|
||||
self:AddRequest(self, WAREHOUSE.Descriptor.ASSETLIST, Mission.assets, Mission.nassets, nil, nil, Mission.prio, tostring(Mission.MID))
|
||||
self:AddRequest(self, WAREHOUSE.Descriptor.ASSETLIST, Mission.assets, Mission.nassets, nil, nil, Mission.prio, tostring(Mission.auftragsnummer))
|
||||
|
||||
end
|
||||
|
||||
@@ -548,7 +576,7 @@ function AIRWING:onafterRequest(From, Event, To, Request)
|
||||
for _,_asset in pairs(assets) do
|
||||
local asset=_asset --#AIRWING.SquadronAsset
|
||||
|
||||
asset.payload=Mission.payload
|
||||
--asset.payload=Mission.payload
|
||||
|
||||
end
|
||||
|
||||
@@ -679,13 +707,9 @@ function AIRWING:SquadronCanMission(Squadron, MissionType, Nassets)
|
||||
local cando=true
|
||||
local assets={}
|
||||
|
||||
local gotit=false
|
||||
for _,canmission in pairs(Squadron.missiontypes) do
|
||||
if canmission==MissionType then
|
||||
gotit=true
|
||||
break
|
||||
end
|
||||
end
|
||||
-- WARNING: This assumes that all assets of the squad can do the same mission types!
|
||||
-- TODO: we could make the mission type as a parameter of the assets! Then we can have heterogenious squads as well!
|
||||
local gotit=self:CheckMissionType(MissionType, Squadron.missiontypes)
|
||||
|
||||
if not gotit then
|
||||
-- This squad cannot do this mission.
|
||||
@@ -697,7 +721,25 @@ function AIRWING:SquadronCanMission(Squadron, MissionType, Nassets)
|
||||
|
||||
-- Check if has already a mission assigned.
|
||||
if asset.mission==nil then
|
||||
table.insert(assets, asset)
|
||||
if asset.spawned then
|
||||
if self:CheckMissionType(MissionType, asset.payload.missiontypes) then
|
||||
table.insert(assets, asset)
|
||||
end
|
||||
else
|
||||
|
||||
-- Check if we got a payload and reserve it for this asset.
|
||||
local reserved=self:ReservePayloadForAsset(asset, MissionType)
|
||||
if reserved then
|
||||
table.insert(assets, asset)
|
||||
end
|
||||
end
|
||||
elseif asset.mission==AUFTRAG.Type.ORBIT then
|
||||
|
||||
-- Check if the payload of this asset is compatible with the mission.
|
||||
if self:CheckMissionType(MissionType, asset.payload.missiontypes) then
|
||||
-- TODO: check if asset actually has weapons left!
|
||||
table.insert(assets, asset)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -745,28 +787,49 @@ function AIRWING:CanMission(MissionType, Nassets)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Now clear all reserved payloads.
|
||||
for _,_asset in pairs(Assets) do
|
||||
local asset=_asset --#AIRWING.SquadronAsset
|
||||
self:UnReservePayloadForAsset(asset)
|
||||
end
|
||||
|
||||
return Can, Assets
|
||||
end
|
||||
|
||||
|
||||
--- Returns the mission for a given mission ID (MID).
|
||||
--- Returns the mission for a given mission ID (Autragsnummer).
|
||||
-- @param #AIRWING self
|
||||
-- @param #number mid Mission ID.
|
||||
-- @return #AIRWING.Missiondata Mission table.
|
||||
-- @param #string MissionType The requested mission type.
|
||||
-- @param #table PossibleTypes A table with possible mission types.
|
||||
-- @return #boolean If true, the requested mission type is part of the possible mission types.
|
||||
function AIRWING:CheckMissionType(MissionType, PossibleTypes)
|
||||
|
||||
for _,canmission in pairs(PossibleTypes) do
|
||||
if canmission==MissionType then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--- Returns the mission for a given mission ID (Autragsnummer).
|
||||
-- @param #AIRWING self
|
||||
-- @param #number mid Mission ID (Auftragsnummer).
|
||||
-- @return Ops.Auftrag#AUFTRAG Mission table.
|
||||
function AIRWING:GetMissionByID(mid)
|
||||
|
||||
for _,_mission in pairs(self.missionqueue) do
|
||||
local mission=_mission --#AIRWING.Missiondata
|
||||
local mission=_mission --Ops.Auftrag#AUFTRAG
|
||||
|
||||
if mission.MID==tonumber(mid) then
|
||||
if mission.auftragsnummer==tonumber(mid) then
|
||||
return mission
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--return self.missionqueue[mid]
|
||||
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,569 @@
|
||||
--- **Ops** - Auftrag (mission) for Ops.
|
||||
--
|
||||
-- **Main Features:**
|
||||
--
|
||||
-- * Create mission for ops.
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **funkyfranky**
|
||||
-- @module Ops.Auftrag
|
||||
-- @image OPS_Auftrag.png
|
||||
|
||||
|
||||
--- AUFTRAG class.
|
||||
-- @type AUFTRAG
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #boolean Debug Debug mode. Messages to all about status.
|
||||
-- @field #string lid Class id string for output to DCS log file.
|
||||
-- @field #number auftragsnummer Auftragsnummer.
|
||||
-- @field #string type Mission type.
|
||||
-- @field #string status Mission status.
|
||||
-- @field #string name Mission name.
|
||||
-- @field #number mid Mission ID.
|
||||
-- @field #number prio Mission priority.
|
||||
-- @field #number Tstart Mission start time in seconds.
|
||||
-- @field #number Tstop Mission stop time in seconds.
|
||||
-- @field #number duration Mission duration in seconds.
|
||||
-- @field #table DCStask DCS task structure.
|
||||
-- @field Core.Point#COORDINATE waypointcoord Coordinate of the waypoint task.
|
||||
-- @field Ops.FlightGroup#AUFTRAG.Task waypointtask Waypoint task.
|
||||
-- @field #number waypointindex Waypoint number at which the task is executed.
|
||||
-- @field #number marker F10 map marker ID.
|
||||
-- @field Core.Point#COORDINATE coordOrbit Coordinate where to orbit.
|
||||
-- @field #number speedOrbit Orbit speed in m/s.
|
||||
-- @field #number heading Heading in degrees.
|
||||
-- @field #number leg Length of leg in meters.
|
||||
-- @field Core.Zone#ZONE_RADIUS zoneEngage *Circular* engagement zone.
|
||||
-- @field #table typeTargets Table of target types that are engaged in the engagement zone.
|
||||
-- @field Core.Point#COORDINATE coordTarget Coordinate of target location.
|
||||
-- @field Core.Set#SET_GROUP groupsetTargets Set of target groups to attack.
|
||||
-- @field #string squadname Name of the assigned squadron.
|
||||
-- @field #table assets Assets assigned for this mission.
|
||||
-- @field #number nassets Number of required assets.
|
||||
-- @extends Ops.FlightGroup#AUFTRAG
|
||||
|
||||
--- *To invent an airplane is nothing. To build one is something. To fly is everything.* -- Otto Lilienthal
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # The AUFTRAG Concept
|
||||
--
|
||||
-- # Events
|
||||
--
|
||||
--
|
||||
-- # Tasking
|
||||
--
|
||||
--
|
||||
-- # Examples
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
-- @field #AUFTRAG
|
||||
AUFTRAG = {
|
||||
ClassName = "AUFTRAG",
|
||||
Debug = false,
|
||||
lid = nil,
|
||||
auftragsnummer = nil,
|
||||
}
|
||||
|
||||
--- Global mission counter.
|
||||
_AUFTRAGSNR=0
|
||||
|
||||
|
||||
--- Mission types.
|
||||
-- @type AUFTRAG.Type
|
||||
-- @param #string ANTISHIP Anti-ship mission.
|
||||
-- @param #string AWACS AWACS mission.
|
||||
-- @param #string BAI Battlefield Air Interdiction.
|
||||
-- @param #string BOMBING Bombing mission.
|
||||
-- @param #string CAP Combat Air Patrol.
|
||||
-- @param #string CAS Close Air Support.
|
||||
-- @param #string ESCORT Escort mission.
|
||||
-- @param #string FACA Forward AirController airborne mission.
|
||||
-- @param #string FERRY Ferry flight mission.
|
||||
-- @param #string INTERCEPT Intercept mission.
|
||||
-- @param #string ORBIT Orbit mission.
|
||||
-- @param #string RECON Recon mission.
|
||||
-- @param #string SEAD Suppression/destruction of enemy air defences.
|
||||
-- @param #string STRIKE Strike mission.
|
||||
-- @param #string TANKER Tanker mission.
|
||||
-- @param #string TRANSPORT Transport mission.
|
||||
AUFTRAG.Type={
|
||||
ANTISHIP="Anti Ship",
|
||||
AWACS="AWACS",
|
||||
BAI="BAI",
|
||||
BOMBING="Bombing",
|
||||
CAP="CAP",
|
||||
CAS="CAS",
|
||||
ESCORT="Escort",
|
||||
FACA="FAC-A",
|
||||
FERRY="Ferry Flight",
|
||||
INTERCEPT="Intercept",
|
||||
ORBIT="Orbit",
|
||||
RECON="Recon",
|
||||
SEAD="SEAD",
|
||||
STRIKE="Strike",
|
||||
TANKER="Tanker",
|
||||
TRANSPORT="Transport",
|
||||
}
|
||||
|
||||
--- Mission status.
|
||||
-- @type AUFTRAG.Status
|
||||
-- @field #string SCHEDULED Mission is scheduled.
|
||||
-- @field #string ASSIGNED Mission was assigned.
|
||||
-- @field #string EXECUTING Mission is being executed.
|
||||
-- @field #string ACCOMPLISHED Mission is accomplished.
|
||||
AUFTRAG.Status={
|
||||
SCHEDULED="scheduled",
|
||||
ASSIGNED="assigned",
|
||||
EXECUTING="executing",
|
||||
ACCOMPLISHED="accomplished",
|
||||
FAILED="failed",
|
||||
}
|
||||
|
||||
|
||||
--- AUFTRAG class version.
|
||||
-- @field #string version
|
||||
AUFTRAG.version="0.0.1"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: A lot
|
||||
-- TODO: mission roe, rot
|
||||
-- TODO: mission formation
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Create a new AUFTRAG object and start the FSM.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #string Type Mission type.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:New(Type)
|
||||
|
||||
-- Inherit everything from FSM class.
|
||||
local self=BASE:Inherit(self, FSM:New()) -- #AUFTRAG
|
||||
|
||||
-- Increase global counter.
|
||||
_AUFTRAGSNR=_AUFTRAGSNR+1
|
||||
|
||||
self.type=Type
|
||||
self.auftragsnummer=_AUFTRAGSNR
|
||||
|
||||
self:AddTransition("*", "Start", "*") -- Mission has started.
|
||||
self:AddTransition("*", "Update", "*") -- Mission is updated with latest data.
|
||||
self:AddTransition("*", "Done", "*") -- Mission is over.
|
||||
self:AddTransition("*", "Abort", "*") -- Mission is aborted.
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create a new AUFTRAG object and start the FSM.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Point#COORDINATE OrbitCoordinate Where to orbit. Altitude is also taken from the coordinate.
|
||||
-- @param #number OrbitSpeed Orbit speed in knots. Default 350 kts.
|
||||
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
||||
-- @param #number Leg Length of race-track in NM. Default 10 NM.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:NewORBIT(OrbitCoordinate, OrbitSpeed, Heading, Leg)
|
||||
|
||||
local auftrag=AUFTRAG:New(AUFTRAG.Type.ORBIT)
|
||||
|
||||
auftrag.coordOrbit=OrbitCoordinate
|
||||
auftrag.speedOrbit=UTILS.KnotsToMps(OrbitSpeed or 350)
|
||||
auftrag.heading=Heading or 270
|
||||
auftrag.leg=UTILS.NMToMeters(Leg or 10)
|
||||
|
||||
mission.DCStask=self:GetDCSMissionTask()
|
||||
|
||||
return auftrag
|
||||
end
|
||||
|
||||
--- Create a CAP mission.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Point#COORDINATE OrbitCoordinate Where to orbit. Altitude is also taken from the coordinate.
|
||||
-- @param #number OrbitSpeed Orbit speed in knots. Default 350 kts.
|
||||
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
||||
-- @param #number Leg Length of race-track in NM. Default 10 NM.
|
||||
-- @param Core.Zone#ZONE_RADIUS ZoneCAP Circular CAP zone. Detected targets in this zone will be engaged.
|
||||
-- @param #table TargetTypes Table of target types. Default {"Air"}.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:NewCAP(OrbitCoordinate, OrbitSpeed, Heading, Leg, ZoneCAP, TargetTypes)
|
||||
|
||||
-- Ensure given TargetTypes parameter is a table.
|
||||
if TargetTypes then
|
||||
if type(TargetTypes)~="table" then
|
||||
TargetTypes={TargetTypes}
|
||||
end
|
||||
end
|
||||
|
||||
-- Create ORBIT first.
|
||||
local mission=self:NewORBIT(OrbitCoordinate, OrbitSpeed, Heading, Leg)
|
||||
|
||||
-- CAP paramters.
|
||||
mission.type=AUFTRAG.Type.CAP
|
||||
mission.zoneEngage=ZoneCAP or ZONE_RADIUS:New("CAP Zone", OrbitCoordinate:GetVec2(), mission.leg)
|
||||
mission.typeTargets=TargetTypes or {"Air"}
|
||||
|
||||
mission.DCStask=self:GetDCSMissionTask()
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
--- Create a CAS mission.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Point#COORDINATE OrbitCoordinate Where to orbit. Altitude is also taken from the coordinate.
|
||||
-- @param #number OrbitSpeed Orbit speed in knots. Default 350 kts.
|
||||
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
||||
-- @param #number Leg Length of race-track in NM. Default 10 NM.
|
||||
-- @param Core.Zone#ZONE_RADIUS ZoneCAS Circular CAS zone. Detected targets in this zone will be engaged.
|
||||
-- @param #table TargetTypes Table of target types. Default {"Helicopters", "Ground Units", "Light armed ships"}.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:NewCAS(OrbitCoordinate, OrbitSpeed, Heading, Leg, ZoneCAS, TargetTypes)
|
||||
|
||||
-- Ensure given TargetTypes parameter is a table.
|
||||
if TargetTypes then
|
||||
if type(TargetTypes)~="table" then
|
||||
TargetTypes={TargetTypes}
|
||||
end
|
||||
end
|
||||
|
||||
-- Create ORBIT first.
|
||||
local mission=self:NewORBIT(OrbitCoordinate, OrbitSpeed, Heading, Leg)
|
||||
|
||||
-- CAS paramters.
|
||||
mission.type=AUFTRAG.Type.CAS
|
||||
mission.zoneEngage=ZoneCAS or ZONE_RADIUS:New("CAS Zone", OrbitCoordinate:GetVec2(), Leg)
|
||||
mission.typeTargets=TargetTypes or {"Helicopters", "Ground Units", "Light armed ships"}
|
||||
|
||||
mission.DCStask=self:GetDCSMissionTask()
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Create a STRIKE mission. Flight will attack a specified coordinate.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Point#COORDINATE Coordinate Target Coordinate.
|
||||
-- @param #number Altitude Attack altitude in feet. Default 1000.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:NewSTRIKE(TargetCoordinate, Altitude)
|
||||
|
||||
local mission=AUFTRAG:New(AUFTRAG.Type.STRIKE)
|
||||
|
||||
mission.coordTarget=TargetCoordinate
|
||||
mission.altitude=UTILS.FeetToMeters(Altitude or 1000)
|
||||
|
||||
mission.DCStask=self:GetDCSMissionTask()
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
--- Create an INTERCEPT mission.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Set#SET_GROUP TargetGroupSet The set of target groups to intercept.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:NewINTERCEPT(TargetGroupSet)
|
||||
|
||||
if TargetGroupSet:IsInstanceOf("GROUP") then
|
||||
env.info("Converting group to set!")
|
||||
TargetGroupSet=SET_GROUP:New():AddGroup(TargetGroupSet)
|
||||
end
|
||||
|
||||
local mission=AUFTRAG:New(AUFTRAG.Type.INTERCEPT)
|
||||
|
||||
mission.groupsetTargets=TargetGroupSet
|
||||
mission.groupsetTargets:FilterDeads():FilterCrashes()
|
||||
|
||||
mission.DCStask=self:GetDCSMissionTask()
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
--- Create a BAI mission.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Set#SET_GROUP TargetGroupSet The set of target groups to attack. Instead of a SET an ordinary GROUP object can also be given if only a single group needs to be attacked.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:NewBAI(TargetGroupSet)
|
||||
|
||||
if TargetGroupSet:IsInstanceOf("GROUP") then
|
||||
env.info("Converting group to set!")
|
||||
TargetGroupSet=SET_GROUP:New():AddGroup(TargetGroupSet)
|
||||
end
|
||||
|
||||
local mission=AUFTRAG:New(AUFTRAG.Type.BAI)
|
||||
|
||||
mission.groupsetTargets=TargetGroupSet
|
||||
mission.groupsetTargets:FilterDeads():FilterCrashes()
|
||||
|
||||
mission.DCStask=self:GetDCSMissionTask()
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- User API Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Set mission start and stop time.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #string ClockStart Time the mission is started, e.g. "05:00" for 5 am. If specified as a #number, it will be relative (in seconds) to the current mission time. Default is 5 seconds after mission was added.
|
||||
-- @param #string ClockStop (Optional) Time the mission is stopped, e.g. "13:00" for 1 pm. If mission could not be started at that time, it will be removed from the queue. If specified as a #number it will be relative (in seconds) to the current mission time.
|
||||
-- @param #AUFTRAG self
|
||||
function AUFTRAG:SetMissionTime(ClockStart, ClockStop)
|
||||
|
||||
-- Current mission time.
|
||||
local Tnow=timer.getAbsTime()
|
||||
|
||||
-- Set start time. Default in 5 sec.
|
||||
local Tstart=Tnow+5
|
||||
if ClockStart and type(ClockStart)=="number" then
|
||||
Tstart=Tnow+ClockStart
|
||||
elseif ClockStart and type(ClockStart)=="string" then
|
||||
Tstart=UTILS.ClockToSeconds(ClockStart)
|
||||
end
|
||||
|
||||
-- Set stop time. Default nil.
|
||||
local Tstop=nil
|
||||
if ClockStop and type(ClockStop)=="number" then
|
||||
Tstop=Tnow+ClockStop
|
||||
elseif ClockStop and type(ClockStop)=="string" then
|
||||
Tstop=UTILS.ClockToSeconds(ClockStop)
|
||||
end
|
||||
|
||||
self.Tstart=Tstart
|
||||
self.Tstop=Tstop
|
||||
|
||||
if Tstop then
|
||||
self.duration=self.Tstop-self.Tstart
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set mission priority.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number Prio Priority 1=high, 100=low. Default 50
|
||||
-- @param #AUFTRAG self
|
||||
function AUFTRAG:SetPriority(Prio)
|
||||
self.prio=Prio or 50
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set mission name.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #string Name Name of the mission.
|
||||
-- @param #AUFTRAG self
|
||||
function AUFTRAG:SetName(Name)
|
||||
self.name=Name or string.format("Auftragsnummer %d", self.auftragsnummer)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Misc Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Count alive mission targets.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number Number of alive targets.
|
||||
function AUFTRAG:CountMissionTargets()
|
||||
|
||||
local N=0
|
||||
if self.groupsetTargets then
|
||||
local n=self.groupsetTargets:CountAlive()
|
||||
N=N+n
|
||||
end
|
||||
|
||||
if self.unitsetTargets then
|
||||
local n=self.unitsetTargets:CountAlive()
|
||||
N=N+n
|
||||
end
|
||||
|
||||
return N
|
||||
end
|
||||
|
||||
--- Count alive mission targets.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Point#COORDINATE The target coordinate or nil.
|
||||
function AUFTRAG:GetTargetCoordinate()
|
||||
|
||||
if self.groupsetTargets then
|
||||
local group=self.groupsetTargets:GetFirst() --Wrapper.Group#GROUP
|
||||
return group:GetCoordinate()
|
||||
elseif self.unitsetTargets then
|
||||
local unit=self.unitsetTargets:GetFirst() --Wraper.Unit#UNIT
|
||||
return unit:GetCoordinate()
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get DCS task table for the given mission.
|
||||
-- @param #AUFTRAG self
|
||||
-- @return DCS#Task The DCS task table. If multiple tasks are necessary, this is returned as a combo task.
|
||||
function AUFTRAG:GetDCSMissionTask()
|
||||
|
||||
local DCStasks={}
|
||||
|
||||
-- Create DCS task based on current self.
|
||||
if self.type==AUFTRAG.Type.ANTISHIP then
|
||||
|
||||
----------------------
|
||||
-- ANTISHIP Mission --
|
||||
----------------------
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskAttackUnit(nil, AttackUnit, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, WeaponType)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.AWACS then
|
||||
|
||||
-------------------
|
||||
-- AWACS Mission --
|
||||
-------------------
|
||||
|
||||
elseif self.type==AUFTRAG.Type.BAI then
|
||||
|
||||
-----------------
|
||||
-- BAI Mission --
|
||||
-----------------
|
||||
|
||||
for _,_group in pairs(self.groupsetTargets:GetSet()) do
|
||||
local TargetGroup=_group
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskAttackGroup(nil, TargetGroup, ENUMS.WeaponFlag.Auto, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit)
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
end
|
||||
|
||||
elseif self.type==AUFTRAG.Type.BOMBING then
|
||||
|
||||
---------------------
|
||||
-- BOMBING Mission --
|
||||
---------------------
|
||||
|
||||
elseif self.type==AUFTRAG.Type.CAP then
|
||||
|
||||
-----------------
|
||||
-- CAP Mission --
|
||||
-----------------
|
||||
|
||||
local CoordRaceTrack=self.coordOrbit:Translate(self.leg, self.heading, true)
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskOrbit(nil, self.coordOrbit, self.coordOrbit.y, self.speedOrbit, CoordRaceTrack)
|
||||
|
||||
-- TODO! Could be added in the same task!
|
||||
self:AddTaskEnrouteEngageTargetsInZone(self.zoneEngage, self.typeTargets, self.prio)
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.CAS then
|
||||
|
||||
-----------------
|
||||
-- CAS Mission --
|
||||
-----------------
|
||||
|
||||
local CoordRaceTrack=self.coordOrbit:Translate(self.leg, self.heading, true)
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskOrbit(nil, self.coordOrbit, self.coordOrbit.y, self.speedOrbit, CoordRaceTrack)
|
||||
|
||||
self:AddTaskEnrouteEngageTargetsInZone(self.zoneEngage, self.typeTargets, self.prio)
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.ESCORT then
|
||||
|
||||
--------------------
|
||||
-- ESCORT Mission --
|
||||
--------------------
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskEscort(nil, FollowControllable, Vec3, LastWaypointIndex, EngagementDistance, TargetTypes)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.FACA then
|
||||
|
||||
-----------------
|
||||
-- FAC Mission --
|
||||
-----------------
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskFAC_AttackGroup(nil, AttackGroup, WeaponType, Designation, Datalink)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.FERRY then
|
||||
|
||||
-------------------
|
||||
-- FERRY Mission --
|
||||
-------------------
|
||||
|
||||
elseif self.type==AUFTRAG.Type.INTERCEPT then
|
||||
|
||||
-----------------------
|
||||
-- INTERCEPT Mission --
|
||||
-----------------------
|
||||
|
||||
for _,_group in pairs(self.groupsetTargets:GetSet()) do
|
||||
local TargetGroup=_group
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskAttackGroup(nil, TargetGroup, ENUMS.WeaponFlag.Auto, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit)
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
end
|
||||
|
||||
elseif self.type==AUFTRAG.Type.ORBIT then
|
||||
|
||||
-------------------
|
||||
-- ORBIT Mission --
|
||||
-------------------
|
||||
|
||||
local CoordRaceTrack=self.coordOrbit:Translate(self.leg, self.heading, true)
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskOrbit(nil, self.coordOrbit, self.coordOrbit.y, self.speedOrbit, CoordRaceTrack)
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.RECON then
|
||||
|
||||
-------------------
|
||||
-- RECON Mission --
|
||||
-------------------
|
||||
|
||||
elseif self.type==AUFTRAG.Type.STRIKE then
|
||||
|
||||
-------------------
|
||||
-- STIKE Mission --
|
||||
-------------------
|
||||
|
||||
local Vec2=self.coordtarget:GetVec2()
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskAttackMapObject(nil, Vec2, GroupAttack, WeaponExpend, AttackQty, Direction, self.altitude, WeaponType)
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.TANKER then
|
||||
|
||||
--------------------
|
||||
-- TANKER Mission --
|
||||
--------------------
|
||||
|
||||
elseif self.type==AUFTRAG.Type.TRANSPORT then
|
||||
|
||||
else
|
||||
self:E(self.lid..string.format("ERROR: Unknown mission task!"))
|
||||
return nil
|
||||
end
|
||||
|
||||
if #DCStasks==1 then
|
||||
return DCStasks[1]
|
||||
else
|
||||
return CONTROLLABLE.TaskCombo(nil, DCStasks)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -1,629 +0,0 @@
|
||||
--- **Ops** - (R2.5) - Carrier Air Wing (CVW) Warehouse.
|
||||
--
|
||||
-- **Main Features:**
|
||||
--
|
||||
-- * Manage squadrons.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **funkyfranky**
|
||||
-- @module Ops.CVW
|
||||
-- @image OPS_CarrierAirWing.png
|
||||
|
||||
|
||||
--- CVW class.
|
||||
-- @type CVW
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #boolean Debug Debug mode. Messages to all about status.
|
||||
-- @field #string sid Class id string for output to DCS log file.
|
||||
-- @field #string carriername The name of the carrier unit.
|
||||
-- @field #table menu Table of menu items.
|
||||
-- @field #table squadrons Table of squadrons.
|
||||
-- @extends Functional.Warehouse#WAREHOUSE
|
||||
|
||||
--- Be surprised!
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # The CVW Concept
|
||||
--
|
||||
--
|
||||
--
|
||||
-- @field #CVW
|
||||
CVW = {
|
||||
ClassName = "CVW",
|
||||
sid = nil,
|
||||
carriername = nil,
|
||||
menu = nil,
|
||||
squadrons = nil,
|
||||
taskqueue = {},
|
||||
}
|
||||
|
||||
--- Squadron
|
||||
-- @type CVW.Squadron
|
||||
-- @field #string name Name of the squadron.
|
||||
-- @field #table assets Assets of the squadron.
|
||||
-- @field #table tasks Task(s) of the squadron.
|
||||
-- @field #string livery Livery of the squadron.
|
||||
-- @field DCS#Coalition.Side coalition Coalition side.
|
||||
-- @field #number threadlevel Thread level of intruder.
|
||||
-- @field #string threadtext Thread text.
|
||||
-- @field #number category Group category.
|
||||
-- @field #string categoryname Group category name.
|
||||
-- @field #string typename Type name of group.
|
||||
-- @field #table menu The squadron menu entries.
|
||||
|
||||
|
||||
--- Squadron tasks.
|
||||
-- @type CVW.Task
|
||||
-- @param #string INTERCEPT Intercept task.
|
||||
-- @param #string CAP Combat Air Patrol task.s
|
||||
-- @param #string BAI Battlefield Air Interdiction task.
|
||||
-- @param #string SEAD Suppression/destruction of enemy air defences.
|
||||
-- @param #string STRIKE Strike task.
|
||||
-- @param #string AWACS AWACS task.
|
||||
-- @param #string TANKER Tanker task.
|
||||
CVW.Task={
|
||||
INTERCEPT="Intercept",
|
||||
CAP="CAP",
|
||||
BAI="BAI",
|
||||
SEAD="SEAD",
|
||||
STRIKE="Strike",
|
||||
CAS="CAS",
|
||||
AWACS="AWACS",
|
||||
TANKER="Tanker",
|
||||
}
|
||||
|
||||
--- CVW class version.
|
||||
-- @field #string version
|
||||
CVW.version="0.0.5"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: A lot!
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Create a new CVW class object for a specific aircraft carrier unit.
|
||||
-- @param #CVW self
|
||||
-- @param #string carriername Name of the carrier unit.
|
||||
-- @param #string cvwname Name of the carrier air wing, e.g. "CVW-8".
|
||||
-- @return #CVW self
|
||||
function CVW:New(carriername, cvwname)
|
||||
|
||||
-- Inherit everything from WAREHOUSE class.
|
||||
local self=BASE:Inherit(self, WAREHOUSE:New(carriername, cvwname)) -- #CVW
|
||||
|
||||
if not self then
|
||||
BASE:E(string.format("ERROR: Could not find carrier %s!", carriername))
|
||||
return nil
|
||||
end
|
||||
|
||||
self.carriername=carriername
|
||||
|
||||
self.squadrons={}
|
||||
|
||||
|
||||
-- Set some string id for output to DCS.log file.
|
||||
self.sid=string.format("CVW %s |", self.carriername)
|
||||
|
||||
-- Add FSM transitions.
|
||||
-- From State --> Event --> To State
|
||||
self:AddTransition("*", "AirwingStatus", "*") -- CVW status update.
|
||||
self:AddTransition("*", "RequestCAP", "*") -- Request CAP flight.
|
||||
self:AddTransition("*", "RequestIntercept", "*") -- Request Intercept.
|
||||
self:AddTransition("*", "RequestCAS", "*") -- Request CAS.
|
||||
self:AddTransition("*", "RequestSEAD", "*") -- Request SEAD.
|
||||
|
||||
------------------------
|
||||
--- Pseudo Functions ---
|
||||
------------------------
|
||||
|
||||
--- Triggers the FSM event "Start". Starts the CVW. Initializes parameters and starts event handlers.
|
||||
-- @function [parent=#CVW] Start
|
||||
-- @param #CVW self
|
||||
|
||||
--- Triggers the FSM event "Start" after a delay. Starts the CVW. Initializes parameters and starts event handlers.
|
||||
-- @function [parent=#CVW] __Start
|
||||
-- @param #CVW self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
--- Triggers the FSM event "Stop". Stops the CVW and all its event handlers.
|
||||
-- @param #CVW self
|
||||
|
||||
--- Triggers the FSM event "Stop" after a delay. Stops the CVW and all its event handlers.
|
||||
-- @function [parent=#CVW] __Stop
|
||||
-- @param #CVW self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
--- Triggers the FSM event "SkipperStatus".
|
||||
-- @function [parent=#CVW] AirwingStatus
|
||||
-- @param #CVW self
|
||||
|
||||
--- Triggers the FSM event "SkipperStatus" after a delay.
|
||||
-- @function [parent=#CVW] __AirwingStatus
|
||||
-- @param #CVW self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
|
||||
--- Triggers the FSM event "RequestCAP".
|
||||
-- @function [parent=#CVW] RequestCAP
|
||||
-- @param #CVW self
|
||||
-- @param Core.Point#COORDINATE coordinate
|
||||
-- @param #number altitude Altitude
|
||||
-- @param #number leg Race track length.
|
||||
-- @param #number heading Heading in degrees.
|
||||
-- @param #number speed Speed in knots.
|
||||
-- @param #CVW.Squadron squadron Explicitly request a specific squadron.
|
||||
|
||||
|
||||
-- Debug trace.
|
||||
if true then
|
||||
self.Debug=true
|
||||
BASE:TraceOnOff(true)
|
||||
BASE:TraceClass(self.ClassName)
|
||||
BASE:TraceLevel(1)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- User Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Optimized F10 radio menu for a single carrier. The menu entries will be stored directly under F10 Other/Skipper/ and not F10 Other/Skipper/"Carrier Alias"/.
|
||||
-- **WARNING**: If you use this with two CVW objects/carriers, the radio menu will be screwed up!
|
||||
-- @param #CVW self
|
||||
-- @param #boolean switch If true or nil single menu is enabled. If false, menu is for multiple carriers in the mission.
|
||||
-- @return #CVW self
|
||||
function CVW:SetMenuSingleCarrier(switch)
|
||||
if switch==true or switch==nil then
|
||||
self.menusingle=true
|
||||
else
|
||||
self.menusingle=false
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a squadron to the carrier air wing.
|
||||
-- @param #CVW self
|
||||
-- @param #string name Name of the squadron, e.g. "VFA-37".
|
||||
-- @param #table tasks Table of tasks the squadron is supposed to do.
|
||||
-- @param #string livery The livery for all added flight group. Default is the livery of the template group.
|
||||
-- @return #CVW.Squadron The squadron object.
|
||||
function CVW:AddSquadron(name, tasks, livery)
|
||||
|
||||
local squadron={} --#CVW.Squadron
|
||||
|
||||
squadron.name=name
|
||||
squadron.assets={}
|
||||
squadron.tasks=tasks or {}
|
||||
squadron.livery=livery
|
||||
|
||||
table.insert(self.squadrons, squadron)
|
||||
|
||||
return squadron
|
||||
end
|
||||
|
||||
--- Add flight group(s) to squadron.
|
||||
-- @param #CVW self
|
||||
-- @param #CVW.Squadron squadron The squadron object.
|
||||
-- @param Wrapper.Group#GROUP flightgroup The flight group object.
|
||||
-- @param #number ngroups Number of groups to add.
|
||||
-- @return #CVW self
|
||||
function CVW:AddFlightToSquadron(squadron, flightgroup, ngroups)
|
||||
|
||||
local text=string.format("FF Adding asset %s to squadron %s", flightgroup:GetName(), squadron.name)
|
||||
env.info(text)
|
||||
|
||||
function self:OnAfterNewAsset(From, Event, To, asset, assignment)
|
||||
local text=string.format("FF assignment=%s, squadron=%s", assignment, squadron.name)
|
||||
env.info(text)
|
||||
if assignment==squadron.name then
|
||||
table.insert(squadron.assets, asset)
|
||||
end
|
||||
end
|
||||
|
||||
self:AddAsset(flightgroup, ngroups, nil, nil, nil, nil, nil, {squadron.livery}, squadron.name)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get squadron by name
|
||||
-- @param #CVW self
|
||||
-- @param #string name Name of the squadron, e.g. "VFA-37".
|
||||
-- @return #CVW self or nil.
|
||||
function CVW:GetSquadron(name)
|
||||
|
||||
for _,_squadron in pairs(self.squadrons) do
|
||||
if _squadron.name==name then
|
||||
return _squadron
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Start & Status
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Start CVW FSM.
|
||||
-- @param #CVW self
|
||||
function CVW:onafterStart(From, Event, To)
|
||||
|
||||
-- Start parent Warehouse.
|
||||
self:GetParent(self).onafterStart(self, From, Event, To)
|
||||
|
||||
-- Info.
|
||||
self:I(self.sid..string.format("Starting CVW v%s for carrier %s", CVW.version, self.carriername))
|
||||
|
||||
-- Add F10 radio menu.
|
||||
self:_SetMenuCoalition()
|
||||
|
||||
for _,_squadron in pairs(self.squadrons) do
|
||||
local squadron=_squadron --#CVW.Squadron
|
||||
self:_AddSquadonMenu(squadron)
|
||||
end
|
||||
|
||||
-- Init status updates.
|
||||
self:__AirwingStatus(-1)
|
||||
end
|
||||
|
||||
--- Update status.
|
||||
-- @param #CVW self
|
||||
function CVW:onafterAirwingStatus(From, Event, To)
|
||||
|
||||
local fsmstate=self:GetState()
|
||||
|
||||
-- Info text.
|
||||
local text=string.format("State %s", fsmstate)
|
||||
self:I(self.sid..text)
|
||||
|
||||
local text="Squadrons:"
|
||||
for i,_squadron in pairs(self.squadrons) do
|
||||
local squadron=_squadron --#CVW.Squadron
|
||||
|
||||
|
||||
text=text..string.format("\n %s", squadron.name)
|
||||
|
||||
for j,_asset in pairs(squadron.assets) do
|
||||
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
|
||||
local assignment=asset.assignment or "none"
|
||||
local name=asset.templatename
|
||||
local task=asset.CVWtask or "none"
|
||||
local spawned=tostring(asset.spawned)
|
||||
local groupname=asset.spawngroupname
|
||||
local group=nil --Wrapper.Group#GROUP
|
||||
local typename=asset.unittype
|
||||
local fuel=100
|
||||
if groupname then
|
||||
group=GROUP:FindByName(groupname)
|
||||
fuel=group:GetFuelMin()
|
||||
end
|
||||
|
||||
text=text..string.format("\n-[%d] %s*%d: spawned=%s, task=%s, fuel=%d", j, typename, asset.nunits, task)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
self:__AirwingStatus(-30)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- FSM Events
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Request CAP.
|
||||
-- @param #CVW self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Core.Point#COORDINATE coordinate
|
||||
-- @param #number altitude Altitude
|
||||
-- @param #number leg Race track length.
|
||||
-- @param #number heading Heading in degrees.
|
||||
-- @param #number speed Speed in knots.
|
||||
-- @param #CVW.Squadron squadron Explicitly request a specific squadron.
|
||||
function CVW:onafterRequestCAP(From, Event, To, coordinate, altitude, leg, heading, speed, squadron)
|
||||
|
||||
local n=self:GetNumberOfAssets(WAREHOUSE.Descriptor.ASSIGNMENT, squadron.name, false)
|
||||
|
||||
if n>0 then
|
||||
|
||||
self:__AddRequest(1, self, WAREHOUSE.Descriptor.ASSIGNMENT, squadron.name, 1, nil, nil, nil, CVW.Task.CAP)
|
||||
|
||||
function self:OnAfterSelfRequest(From,Event,To,Groupset,Request)
|
||||
local request=Request --Functional.Warehouse#WAREHOUSE.Pendingitem
|
||||
local groupset=Groupset --Core.Set#SET_GROUP
|
||||
|
||||
for _,_asset in pairs(request.assets) do
|
||||
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
|
||||
|
||||
local a=asset.cargobay
|
||||
end
|
||||
|
||||
if Request.assignment==CVW.Task.CAP then
|
||||
|
||||
for _,_group in pairs(groupset:GetSet()) do
|
||||
local group=_group --Wrapper.Group#GROUP
|
||||
|
||||
self:LaunchCAP(group, coordinate, altitude, leg, speed, heading)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
MESSAGE:New("No CAP planes currently available", 5, "CVW"):ToCoalition(self:GetCoalition())
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Launch a CAP flight.
|
||||
-- @param #CVW self
|
||||
-- @param Wrapper.Group#GROUP group Flight group.
|
||||
-- @param Core.Point#COORDINATE capcoord Coordinate of CAP.
|
||||
-- @param #number alt Altitude in feet. Default 20000 ft.
|
||||
-- @param #number leg Length of race track pattern leg. Default 15 NM.
|
||||
-- @param #number heading Heading of race track in degrees. Default 180° i.e. from North to South.
|
||||
-- @param #number speed Speed in knots.
|
||||
function CVW:LaunchCAP(group, capcoord, alt, leg, heading, speed)
|
||||
|
||||
alt=UTILS.FeetToMeters(alt or 20000)
|
||||
|
||||
speed=speed or 350
|
||||
leg=leg or 15
|
||||
|
||||
-- Task orbit.
|
||||
local taskOrbit=group:TaskOrbit(capcoord, alt, UTILS.KnotsToMps(speed+50), capcoord:Translate(UTILS.NMToMeters(leg), heading))
|
||||
|
||||
local wp={}
|
||||
wp[1]=self:GetCoordinate():WaypointAirTakeOffParking()
|
||||
wp[2]=self:GetCoordinate():SetAltitude(alt):WaypointAirTurningPoint(COORDINATE.WaypointAltType.BARO, UTILS.KnotsToKmph(speed), {taskOrbit}, "CAP")
|
||||
|
||||
-- Start uncontrolled group.
|
||||
group:StartUncontrolled()
|
||||
|
||||
--airboss:SetExcludeAI()
|
||||
|
||||
-- Route group.
|
||||
group:Route(wp)
|
||||
end
|
||||
|
||||
--- Create a new task name.
|
||||
-- @param #CVW self
|
||||
-- @param #string task Task of type @{#CVW.Task}.
|
||||
-- @string Task name, e.g. Task0001_CAP, Task0002_BAI, Task0003_INTERCEPT, ...
|
||||
function CVW:_NewTaskName(task)
|
||||
|
||||
self.ntasks=self.ntasks+1
|
||||
|
||||
local taskname=string.format("Task#%04d_%s", self.ntasks, task)
|
||||
|
||||
return taskname
|
||||
end
|
||||
|
||||
|
||||
--- Request Intercept.
|
||||
-- @param #CVW self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Wrapper.Group#GROUP bandits Group of bandits to intercept.
|
||||
-- @param #CVW.Squadron squadron Explicitly request a specific squadron.
|
||||
function CVW:onafterRequestIntercept(From, Event, To, bandits, squadron)
|
||||
|
||||
local n=self:GetNumberOfAssets(WAREHOUSE.Descriptor.ASSIGNMENT, squadron.name, false)
|
||||
|
||||
if n>0 then
|
||||
|
||||
self:__AddRequest(1, self, WAREHOUSE.Descriptor.ASSIGNMENT, squadron.name, 1, nil, nil, nil, CVW.Task.INTERCEPT)
|
||||
|
||||
function self:OnAfterSelfRequest(From,Event,To,Groupset,Request)
|
||||
local request=Request --Functional.Warehouse#WAREHOUSE.Pendingitem
|
||||
local groupset=Groupset --Core.Set#SET_GROUP
|
||||
|
||||
if Request.assignment==CVW.Task.INTERCEPT then
|
||||
|
||||
for _,_group in pairs(groupset:GetSet()) do
|
||||
local group=_group --Wrapper.Group#GROUP
|
||||
|
||||
self:LaunchIntercept(group)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
MESSAGE:New("No INTERCEPT fighters currently available", 5, "CVW"):ToCoalition(self:GetCoalition())
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function CVW:OnAfterSelfRequest(From,Event,To,groupset,request)
|
||||
|
||||
end
|
||||
|
||||
--- Launch a flight group to intercept an intruder.
|
||||
-- @param #CVW self
|
||||
-- @param Wrapper.Group#GROUP group Interceptor flight group.
|
||||
-- @param Wrapper.Group#GROUP bandits Bandit group.
|
||||
function CVW:LaunchIntercept(group, bandit)
|
||||
|
||||
-- Task orbit.
|
||||
local tasks={}
|
||||
|
||||
for _,unit in pairs(bandit:GetUnits()) do
|
||||
tasks[#tasks+1]=group:TaskAttackUnit(unit)
|
||||
end
|
||||
|
||||
local speed=group:GetSpeedMax()
|
||||
local altitude=bandit:GetAltitude()
|
||||
|
||||
-- Create waypoints.
|
||||
local wp={}
|
||||
wp[1]=self:GetCoordinate():WaypointAirTakeOffParking()
|
||||
wp[2]=self:GetCoordinate():SetAltitude(altitude):WaypointAirTurningPoint(COORDINATE.WaypointAltType.BARO, speed, {tasks}, "Intercept")
|
||||
|
||||
-- Start uncontrolled group.
|
||||
group:StartUncontrolled()
|
||||
|
||||
--airboss:SetExcludeAI()
|
||||
|
||||
-- Route group
|
||||
group:Route(wp)
|
||||
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Misc Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Menu Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Patrol carrier.
|
||||
-- @param #CVW self
|
||||
-- @return #CVW self
|
||||
function CVW:_SetMenuCoalition()
|
||||
|
||||
-- Get coalition.
|
||||
local Coalition=self:GetCoalition()
|
||||
|
||||
-- Init menu table.
|
||||
self.menu=self.menu or {}
|
||||
|
||||
-- Init menu coalition table.
|
||||
self.menu[Coalition]=self.menu[Coalition] or {}
|
||||
|
||||
-- Shortcut.
|
||||
local menu=self.menu[Coalition]
|
||||
|
||||
if self.menusingle then
|
||||
-- F10/Skipper/...
|
||||
if not menu.CVW then
|
||||
menu.CVW=MENU_COALITION:New(Coalition, "CVW")
|
||||
end
|
||||
else
|
||||
-- F10/Skipper/<Carrier Alias>/...
|
||||
if not menu.Root then
|
||||
menu.Root=MENU_COALITION:New(Coalition, "CVW")
|
||||
end
|
||||
menu.CVW=MENU_COALITION:New(Coalition, self.alias, menu.Root)
|
||||
end
|
||||
|
||||
-------------------
|
||||
-- Squadron Menu --
|
||||
-------------------
|
||||
|
||||
menu.Squadron={}
|
||||
menu.Squadron.Main= MENU_COALITION:New(Coalition, "Squadrons", menu.CVW)
|
||||
|
||||
menu.Warehouse={}
|
||||
menu.Warehouse.Main = MENU_COALITION:New(Coalition, "Warehouse", menu.CVW)
|
||||
menu.Warehouse.Reports = MENU_COALITION_COMMAND:New(Coalition, "Reports On/Off", menu.Warehouse.Main, self.WarehouseReportsToggle, self)
|
||||
menu.Warehouse.Assets = MENU_COALITION_COMMAND:New(Coalition, "Report Assets", menu.Warehouse.Main, self.ReportWarehouseStock, self)
|
||||
|
||||
menu.ReportSquadrons = MENU_COALITION_COMMAND:New(Coalition, "Report Squadrons", menu.CVW, self.ReportSquadrons, self)
|
||||
|
||||
end
|
||||
|
||||
--- Report squadron status.
|
||||
-- @param #CVW self
|
||||
function CVW:ReportSquadrons()
|
||||
|
||||
local text="Squadron Report:"
|
||||
|
||||
for i,_squadron in pairs(self.squadrons) do
|
||||
local squadron=_squadron --#CVW.Squadron
|
||||
|
||||
local name=squadron.name
|
||||
|
||||
local nspawned=0
|
||||
local nstock=0
|
||||
for _,_asset in pairs(squadron.assets) do
|
||||
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
|
||||
--env.info(string.format("Asset name=%s", asset.spawngroupname))
|
||||
|
||||
local n=asset.nunits
|
||||
|
||||
if asset.spawned then
|
||||
nspawned=nspawned+n
|
||||
else
|
||||
nstock=nstock+n
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
text=string.format("\n%s: AC on duty=%d, in stock=%d", name, nspawned, nstock)
|
||||
|
||||
end
|
||||
|
||||
self:I(self.sid..text)
|
||||
MESSAGE:New(text, 10, "CVW", true):ToCoalition(self:GetCoalition())
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Add sub menu for this intruder.
|
||||
-- @param #CVW self
|
||||
-- @param #CVW.Squadron squadron The squadron data.
|
||||
function CVW:_AddSquadonMenu(squadron)
|
||||
|
||||
local Coalition=self:GetCoalition()
|
||||
|
||||
local root=self.menu[Coalition].Squadron.Main
|
||||
|
||||
local menu=MENU_COALITION:New(Coalition, squadron.name, root)
|
||||
|
||||
MENU_COALITION_COMMAND:New(Coalition, "Report", menu, self._ReportSq, self, squadron)
|
||||
MENU_COALITION_COMMAND:New(Coalition, "Launch CAP", menu, self._LaunchCAP, self, squadron)
|
||||
|
||||
-- Set menu.
|
||||
squadron.menu=menu
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Report squadron status.
|
||||
-- @param #CVW self
|
||||
-- @param #CVW.Squadron squadron The squadron object.
|
||||
function CVW:_ReportSq(squadron)
|
||||
|
||||
local text=string.format("%s: %s assets:", squadron.name, tostring(squadron.categoryname))
|
||||
for i,_asset in pairs(squadron.assets) do
|
||||
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
|
||||
text=text..string.format("%d.) ")
|
||||
end
|
||||
end
|
||||
|
||||
--- Warehouse reports on/off.
|
||||
-- @param #CVW self
|
||||
function CVW:WarehouseReportsToggle()
|
||||
self.Report=not self.Report
|
||||
MESSAGE:New(string.format("Warehouse reports are now %s", tostring(self.Report)), 10, "CVW", true):ToCoalition(self:GetCoalition())
|
||||
end
|
||||
|
||||
|
||||
--- Report warehouse stock.
|
||||
-- @param #CVW self
|
||||
function CVW:ReportWarehouseStock()
|
||||
local text=self:_GetStockAssetsText(false)
|
||||
MESSAGE:New(text, 10, "CVW", true):ToCoalition(self:GetCoalition())
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -316,109 +316,6 @@ FLIGHTGROUP.TaskType={
|
||||
-- @field #number WaypointIndex Waypoint number at which the enroute task is added.
|
||||
|
||||
|
||||
--- Mission types.
|
||||
-- @type FLIGHTGROUP.MissionType
|
||||
-- @param #string ANTISHIP Anti-ship mission.
|
||||
-- @param #string AWACS AWACS mission.
|
||||
-- @param #string BAI Battlefield Air Interdiction.
|
||||
-- @param #string BOMBING Bombing mission.
|
||||
-- @param #string CAP Combat Air Patrol.
|
||||
-- @param #string CAS Close Air Support.
|
||||
-- @param #string ESCORT Escort mission.
|
||||
-- @param #string FACA Forward AirController airborne mission.
|
||||
-- @param #string FERRY Ferry flight mission.
|
||||
-- @param #string INTERCEPT Intercept mission.
|
||||
-- @param #string ORBIT Orbit mission.
|
||||
-- @param #string RECON Recon mission.
|
||||
-- @param #string SEAD Suppression/destruction of enemy air defences.
|
||||
-- @param #string STRIKE Strike mission.
|
||||
-- @param #string TANKER Tanker mission.
|
||||
-- @param #string TRANSPORT Transport mission.
|
||||
FLIGHTGROUP.MissionType={
|
||||
ANTISHIP="Anti Ship",
|
||||
AWACS="AWACS",
|
||||
BAI="BAI",
|
||||
BOMBING="Bombing",
|
||||
CAP="CAP",
|
||||
CAS="CAS",
|
||||
ESCORT="Escort",
|
||||
FACA="FAC-A",
|
||||
FERRY="Ferry Flight",
|
||||
INTERCEPT="Intercept",
|
||||
ORBIT="Orbit",
|
||||
RECON="Recon",
|
||||
SEAD="SEAD",
|
||||
STRIKE="Strike",
|
||||
TANKER="Tanker",
|
||||
TRANSPORT="Transport",
|
||||
}
|
||||
|
||||
--- Mission status.
|
||||
-- @type FLIGHTGROUP.MissionStatus
|
||||
-- @field #string SCHEDULED Mission is scheduled.
|
||||
-- @field #string ASSIGNED Mission was assigned.
|
||||
-- @field #string EXECUTING Mission is being executed.
|
||||
-- @field #string ACCOMPLISHED Mission is accomplished.
|
||||
FLIGHTGROUP.MissionStatus={
|
||||
SCHEDULED="scheduled",
|
||||
ASSIGNED="assigned",
|
||||
EXECUTING="executing",
|
||||
ACCOMPLISHED="accomplished",
|
||||
FAILED="failed",
|
||||
}
|
||||
|
||||
--- Generic mission.
|
||||
-- @type FLIGHTGROUP.Mission
|
||||
-- @field #string type Mission Type.
|
||||
-- @field #string status Mission status.
|
||||
-- @field #string name Mission name.
|
||||
-- @field #number mid Mission ID.
|
||||
-- @field #number prio Mission priority.
|
||||
-- @field #number Tstart Mission start time in seconds.
|
||||
-- @field #number Tstop Mission stop time in seconds.
|
||||
-- @field #number duration Mission duration in seconds.
|
||||
-- @field #table DCStask DCS task structure.
|
||||
-- @field Core.Point#COORDINATE waypointcoord Coordinate of the waypoint task.
|
||||
-- @field #FLIGHTGROUP.Task waypointtask Waypoint task.
|
||||
-- @field #number waypointindex Waypoint number at which the task is executed.
|
||||
-- @field #number marker F10 map marker ID.
|
||||
|
||||
--- ORBIT mission. Basis for other missions like TANKER, AWACS, CAP.
|
||||
-- @type FLIGHTGROUP.MissionORBIT
|
||||
-- @field Core.Point#COORDINATE coordOrbit Coordinate where to orbit.
|
||||
-- @field #number speedOrbit Orbit speed in m/s.
|
||||
-- @field #number heading Heading in degrees.
|
||||
-- @field #number leg Length of leg in meters.
|
||||
-- @extends #FLIGHTGROUP.Mission
|
||||
|
||||
--- CAP mission.
|
||||
-- @type FLIGHTGROUP.MissionCAP
|
||||
-- @field Core.Zone#ZONE_RADIUS zoneEngage *Circular* engagement zone.
|
||||
-- @field #table typeTargets Table of target types that are engaged in the engagement zone. Default is {"Air"}.
|
||||
-- @extends #FLIGHTGROUP.MissionORBIT
|
||||
|
||||
--- CAS mission.
|
||||
-- @type FLIGHTGROUP.MissionCAS
|
||||
-- @field Core.Zone#ZONE_RADIUS zoneEngage *Circular* engagement zone.
|
||||
-- @field #table typeTargets Table of target types that are engaged in the engagement zone. Default is {"LightArmoredUnits"}.
|
||||
-- @extends #FLIGHTGROUP.MissionORBIT
|
||||
|
||||
--- STRIKE mission.
|
||||
-- @type FLIGHTGROUP.MissionSTRIKE
|
||||
-- @field Core.Point#COORDINATE coordTarget Coordinate of target location.
|
||||
-- @field #number altitude Attack altitude in meters.
|
||||
-- @extends #FLIGHTGROUP.Mission
|
||||
|
||||
--- BAI mission.
|
||||
-- @type FLIGHTGROUP.MissionBAI
|
||||
-- @field Core.Set#SET_GROUP groupsetTargets Set of target groups to attack.
|
||||
-- @extends #FLIGHTGROUP.Mission
|
||||
|
||||
--- INTERCEPT mission.
|
||||
-- @type FLIGHTGROUP.MissionINTERCEPT
|
||||
-- @field Core.Set#SET_GROUP groupsetTargets Set of target groups to intercept.
|
||||
-- @extends #FLIGHTGROUP.Mission
|
||||
|
||||
--- FLIGHTGROUP class version.
|
||||
-- @field #string version
|
||||
FLIGHTGROUP.version="0.3.2"
|
||||
@@ -429,7 +326,6 @@ FLIGHTGROUP.version="0.3.2"
|
||||
|
||||
-- DONE: Add tasks.
|
||||
-- DONE: Waypoints, read, add, insert, detour.
|
||||
|
||||
-- DONE: Get ammo.
|
||||
-- DONE: Get pylons.
|
||||
-- DONE: Fuel threshhold ==> RTB.
|
||||
@@ -532,7 +428,9 @@ function FLIGHTGROUP:New(groupname, autostart)
|
||||
self:AddTransition("*", "MissionUpdate", "*") -- Mission is updated with latest data.
|
||||
self:AddTransition("*", "MissionDone", "*") -- Mission is over.
|
||||
self:AddTransition("*", "MissionAbort", "*") -- Mission is aborted.
|
||||
|
||||
|
||||
self:AddTransition("Airborne", "EngageTarget", "Engaging") -- Pause current task.
|
||||
self:AddTransition("Engaging", "Disengage", "Airborne") -- Pause current task.
|
||||
|
||||
self:AddTransition("*", "ElementSpawned", "*") -- An element was spawned.
|
||||
self:AddTransition("*", "ElementParking", "*") -- An element is parking.
|
||||
@@ -761,6 +659,28 @@ function FLIGHTGROUP:RemoveTask(taskid)
|
||||
|
||||
end
|
||||
|
||||
--- Add mission to queue.
|
||||
-- @param #FLIUGHTGROUP self
|
||||
-- @param Ops.Auftrag#AUFTRAG.Mission Mission Mission for this group.
|
||||
-- @param Core.Point#COORDINATE WaypointCoordinate Coordinate of the mission waypoint
|
||||
-- @param #number WaypointIndex The waypoint number. Default is after all current air waypoints.
|
||||
-- @return #FLIGHTGROUP self
|
||||
function FLIGHTGROUP:AddMission(Mission, WaypointCoordinate, WaypointIndex)
|
||||
|
||||
Mission.waypointcoordinate=WaypointCoordinate
|
||||
Mission.waypointindex=WaypointIndex
|
||||
|
||||
-- Add mission to queue.
|
||||
table.insert(self.missionqueue, Mission)
|
||||
|
||||
-- Info text.
|
||||
local text=string.format("Added %s mission %s at waypoint #%s. Starting at %s. Stopping at %s",
|
||||
tostring(Mission.type), tostring(Mission.name), tostring(Mission.waypointindex), UTILS.SecondsToClock(Mission.Tstart, true), Mission.Tstop and UTILS.SecondsToClock(Mission.Tstop, true) or "never")
|
||||
self:I(self.lid..text)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set squadron the flight group belongs to.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @param #boolean If true or nil, group get enroute task tanker. If false, not.
|
||||
@@ -1180,384 +1100,7 @@ function FLIGHTGROUP:Route(waypoints)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create an ORBIT mission. This is also used as template for other mission types, e.g. TANKER, AWACS, CAP.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @param Core.Point#COORDINATE OrbitCoordinate Where to orbit. Altitude is also taken from the coordinate.
|
||||
-- @param #number OrbitSpeed Orbit speed in knots. Default 350 kts.
|
||||
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
||||
-- @param #number Leg Length of race-track in NM. Default 10 NM.
|
||||
-- @return #FLIGHTGROUP.MissionORBIT The ORBIT mission table.
|
||||
function FLIGHTGROUP:CreateMissionORBIT(OrbitCoordinate, OrbitSpeed, Heading, Leg)
|
||||
|
||||
local mission={} --#FLIGHTGROUP.MissionORBIT
|
||||
|
||||
mission.type=FLIGHTGROUP.MissionType.ORBIT
|
||||
mission.coordOrbit=OrbitCoordinate
|
||||
mission.speedOrbit=UTILS.KnotsToMps(OrbitSpeed or 350)
|
||||
mission.heading=Heading or 270
|
||||
mission.leg=UTILS.NMToMeters(Leg or 10)
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
|
||||
--- Create a CAP mission.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @param Core.Point#COORDINATE OrbitCoordinate Where to orbit. Altitude is also taken from the coordinate.
|
||||
-- @param #number OrbitSpeed Orbit speed in knots. Default 350 kts.
|
||||
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
||||
-- @param #number Leg Length of race-track in NM. Default 10 NM.
|
||||
-- @param Core.Zone#ZONE_RADIUS ZoneCAP Circular CAP zone. Detected targets in this zone will be engaged.
|
||||
-- @param #table TargetTypes Table of target types. Default {"Air"}.
|
||||
-- @return #FLIGHTGROUP.MissionCAP The CAP mission table.
|
||||
function FLIGHTGROUP:CreateMissionCAP(OrbitCoordinate, OrbitSpeed, Heading, Leg, ZoneCAP, TargetTypes)
|
||||
|
||||
local mission=self:CreateMissionORBIT(OrbitCoordinate, OrbitSpeed, Heading, Leg) --#FLIGHTGROUP.MissionCAP
|
||||
|
||||
mission.type=FLIGHTGROUP.MissionType.CAP
|
||||
mission.zoneEngage=ZoneCAP or ZONE_RADIUS:New("CAP Zone", OrbitCoordinate:GetVec2(), mission.leg)
|
||||
mission.typeTargets=TargetTypes or {"Air"}
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
--- Create a CAS mission.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @param Core.Point#COORDINATE OrbitCoordinate Where to orbit. Altitude is also taken from the coordinate.
|
||||
-- @param #number OrbitSpeed Orbit speed in knots. Default 350 kts.
|
||||
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
||||
-- @param #number Leg Length of race-track in NM. Default 10 NM.
|
||||
-- @param Core.Zone#ZONE_RADIUS ZoneCAS Circular CAS zone. Detected targets in this zone will be engaged.
|
||||
-- @param #table TargetTypes Table of target types. Default {"Helicopters", "Ground Units", "Light armed ships"}.
|
||||
-- @return #FLIGHTGROUP.MissionCAP The CAP mission table.
|
||||
function FLIGHTGROUP:CreateMissionCAS(OrbitCoordinate, OrbitSpeed, Heading, Leg, ZoneCAS, TargetTypes)
|
||||
|
||||
-- Ensure given TargetTypes parameter is a table.
|
||||
if TargetTypes then
|
||||
if type(TargetTypes)~="table" then
|
||||
TargetTypes={TargetTypes}
|
||||
end
|
||||
end
|
||||
|
||||
TargetTypes=TargetTypes or {"Helicopters", "Ground Units", "Light armed ships"}
|
||||
ZoneCAS=ZoneCAS or ZONE_RADIUS:New("CAS Zone", OrbitCoordinate:GetVec2(), Leg)
|
||||
|
||||
local mission=self:CreateMissionCAP(OrbitCoordinate, OrbitSpeed, Heading, Leg, ZoneCAS, TargetTypes) --#FLIGHTGROUP.MissionCAP
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Create a STRIKE mission. Flight will attack a specified coordinate.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @param Core.Point#COORDINATE Coordinate Target Coordinate.
|
||||
-- @param #number Altitude Attack altitude in feet. Default 1000.
|
||||
-- @return #FLIGHTGROUP.MissionSTRIKE The STRIKE mission table.
|
||||
function FLIGHTGROUP:CreateMissionSTRIKE(TargetCoordinate, Altitude)
|
||||
|
||||
local mission={} --#FLIGHTGROUP.MissionSTRIKE
|
||||
|
||||
mission.type=FLIGHTGROUP.MissionType.STIKE
|
||||
mission.coordTarget=TargetCoordinate
|
||||
mission.altitude=UTILS.FeetToMeters(Altitude or 1000)
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
--- Create an INTERCEPT mission.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @param Core.Set#SET_GROUP TargetGroupSet The set of target groups to intercept.
|
||||
function FLIGHTGROUP:CreateMissionINTERCEPT(TargetGroupSet)
|
||||
|
||||
local mission={} --#FLIGHTGROUP.MissionINTERCEPT
|
||||
|
||||
if TargetGroupSet:IsInstanceOf("GROUP") then
|
||||
env.info("Converting group to set!")
|
||||
TargetGroupSet=SET_GROUP:New():AddGroup(TargetGroupSet)
|
||||
end
|
||||
|
||||
mission.type=FLIGHTGROUP.MissionType.INTERCEPT
|
||||
mission.groupsetTargets=TargetGroupSet
|
||||
|
||||
mission.groupsetTargets:FilterDeads():FilterCrashes()
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
--- Create a BAI mission.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @param Core.Set#SET_GROUP TargetGroupSet The set of target groups to attack. Instead of a SET an ordinary GROUP object can also be given if only a single group needs to be attacked.
|
||||
function FLIGHTGROUP:CreateMissionBAI(TargetGroupSet)
|
||||
|
||||
local mission={} --#FLIGHTGROUP.MissionBAI
|
||||
|
||||
if TargetGroupSet:IsInstanceOf("GROUP") then
|
||||
env.info("Converting group to set!")
|
||||
TargetGroupSet=SET_GROUP:New():AddGroup(TargetGroupSet)
|
||||
end
|
||||
|
||||
mission.type=FLIGHTGROUP.MissionType.BAI
|
||||
mission.groupsetTargets=TargetGroupSet
|
||||
|
||||
mission.groupsetTargets:FilterDeads():FilterCrashes()
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
--- Create a BAI mission.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @param #FLIGHTGROUP.Mission mission The mission.
|
||||
-- @param #number Number of alive targets.
|
||||
function FLIGHTGROUP:CountMissionTargets(mission)
|
||||
|
||||
local N=0
|
||||
if mission.groupsetTargets then
|
||||
local n=mission.groupsetTargets:CountAlive()
|
||||
N=N+n
|
||||
end
|
||||
|
||||
if mission.unitsetTargets then
|
||||
local n=mission.unitsetTargets:CountAlive()
|
||||
N=N+n
|
||||
end
|
||||
|
||||
return N
|
||||
end
|
||||
|
||||
--- Add mission to queue.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @param #FLIGHTGROUP.Mission Mission Mission for this group.
|
||||
-- @param Core.Point#COORDINATE WaypointCoordinate Coordinate of the mission waypoint
|
||||
-- @param #number WaypointIndex The waypoint number. Default is after all current air waypoints.
|
||||
-- @param #string ClockStart Time the mission is started, e.g. "05:00" for 5 am. If specified as a #number, it will be relative (in seconds) to the current mission time. Default is 5 seconds after mission was added.
|
||||
-- @param #string ClockStop Time the mission is stopped, e.g. "13:00" for 1 pm. If mission could not be started at that time, it will be removed from the queue. If specified as a #number it will be relative (in seconds) to the current mission time.
|
||||
-- @param #number Prio Priority of the mission, i.e. a number between 1 and 100. Default 50.
|
||||
-- @param #string Name Mission name. Default "Aerial Refueling #00X", where "#00X" is a running mission counter index starting at "#001".
|
||||
-- @return #FLIGHTGROUP.Mission The mission table. This is a deep copy of the input mission with adjusted parameters for the mission type.
|
||||
function FLIGHTGROUP:AddMission(Mission, WaypointCoordinate, WaypointIndex, ClockStart, ClockStop, Prio, Name)
|
||||
|
||||
-- Increase mission counter.
|
||||
self.missioncounter=self.missioncounter+1
|
||||
|
||||
-- Create copy of Mission template.
|
||||
local mission=UTILS.DeepCopy(Mission) --#FLIGHTGROUP.Mission
|
||||
|
||||
-- Current mission time.
|
||||
local Tnow=timer.getAbsTime()
|
||||
|
||||
-- Set start time. Default in 5 sec.
|
||||
local Tstart=Tnow+5
|
||||
if ClockStart and type(ClockStart)=="number" then
|
||||
Tstart=Tnow+ClockStart
|
||||
elseif ClockStart and type(ClockStart)=="string" then
|
||||
Tstart=UTILS.ClockToSeconds(ClockStart)
|
||||
end
|
||||
|
||||
-- Set stop time. Default nil.
|
||||
local Tstop=nil
|
||||
if ClockStop and type(ClockStop)=="number" then
|
||||
Tstop=Tnow+ClockStop
|
||||
elseif ClockStop and type(ClockStop)=="string" then
|
||||
Tstop=UTILS.ClockToSeconds(ClockStop)
|
||||
end
|
||||
|
||||
-- Make mission table.
|
||||
mission.mid=self.missioncounter
|
||||
mission.waypointcoord=WaypointCoordinate
|
||||
mission.waypointindex=WaypointIndex
|
||||
mission.waypointtask=nil
|
||||
mission.Tstart=Tstart
|
||||
mission.Tstop=Tstop
|
||||
mission.status=FLIGHTGROUP.MissionStatus.SCHEDULED
|
||||
if Tstop then
|
||||
mission.duration=mission.Tstop-mission.Tstart
|
||||
end
|
||||
mission.prio=Prio or 50
|
||||
mission.name=Name or string.format("%s mission ID%03d", mission.type, mission.mid)
|
||||
mission.DCStask=self:GetDCSMissionTask(mission)
|
||||
|
||||
|
||||
-- Add mission to queue.
|
||||
table.insert(self.missionqueue, mission)
|
||||
|
||||
-- Info text.
|
||||
local text=string.format("Added %s mission %s at waypoint #%s. Starting at %s. Stopping at %s",
|
||||
tostring(mission.type), tostring(mission.name), tostring(mission.waypointindex), UTILS.SecondsToClock(mission.Tstart, true), mission.Tstop and UTILS.SecondsToClock(mission.Tstop, true) or "never")
|
||||
self:I(self.lid..text)
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
--- Get DCS task table for the given mission.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @param #FLIGHTGROUP.Mission Mission Mission for this group.
|
||||
-- @return DCS#Task The DCS task table. If multiple tasks are necessary, this is returned as a combo task.
|
||||
function FLIGHTGROUP:GetDCSMissionTask(Mission)
|
||||
|
||||
local DCStasks={}
|
||||
|
||||
-- Create DCS task based on current mission.
|
||||
if Mission.type==FLIGHTGROUP.MissionType.ANTISHIP then
|
||||
|
||||
----------------------
|
||||
-- ANTISHIP Mission --
|
||||
----------------------
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskAttackUnit(self.group, AttackUnit, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, WeaponType)
|
||||
|
||||
elseif Mission.type==FLIGHTGROUP.MissionType.AWACS then
|
||||
|
||||
-------------------
|
||||
-- AWACS Mission --
|
||||
-------------------
|
||||
|
||||
elseif Mission.type==FLIGHTGROUP.MissionType.BAI then
|
||||
|
||||
-----------------
|
||||
-- BAI Mission --
|
||||
-----------------
|
||||
|
||||
local mission=Mission --#FLIGHTGROUP.MissionBAI
|
||||
|
||||
for _,_group in pairs(mission.groupsetTargets:GetSet()) do
|
||||
local TargetGroup=_group
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskAttackGroup(self.group, TargetGroup, ENUMS.WeaponFlag.Auto, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit)
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
end
|
||||
|
||||
elseif Mission.type==FLIGHTGROUP.MissionType.BOMBING then
|
||||
|
||||
---------------------
|
||||
-- BOMBING Mission --
|
||||
---------------------
|
||||
|
||||
elseif Mission.type==FLIGHTGROUP.MissionType.CAP then
|
||||
|
||||
-----------------
|
||||
-- CAP Mission --
|
||||
-----------------
|
||||
|
||||
local mission=Mission --#FLIGHTGROUP.MissionCAP
|
||||
|
||||
local CoordRaceTrack=mission.coordOrbit:Translate(mission.leg, mission.heading, true)
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskOrbit(self.group, mission.coordOrbit, mission.coordOrbit.y, mission.speedOrbit, CoordRaceTrack)
|
||||
|
||||
self:AddTaskEnrouteEngageTargetsInZone(mission.zoneEngage, mission.typeTargets, mission.prio)
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif Mission.type==FLIGHTGROUP.MissionType.CAS then
|
||||
|
||||
-----------------
|
||||
-- CAS Mission --
|
||||
-----------------
|
||||
|
||||
local mission=Mission --#FLIGHTGROUP.MissionCAS
|
||||
|
||||
local CoordRaceTrack=mission.coordOrbit:Translate(mission.leg, mission.heading, true)
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskOrbit(self.group, mission.coordOrbit, mission.coordOrbit.y, mission.speedOrbit, CoordRaceTrack)
|
||||
|
||||
self:AddTaskEnrouteEngageTargetsInZone(mission.zoneEngage, mission.typeTargets, mission.prio)
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif Mission.type==FLIGHTGROUP.MissionType.ESCORT then
|
||||
|
||||
--------------------
|
||||
-- ESCORT Mission --
|
||||
--------------------
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskEscort(self.group, FollowControllable, Vec3, LastWaypointIndex, EngagementDistance, TargetTypes)
|
||||
|
||||
elseif Mission.type==FLIGHTGROUP.MissionType.FACA then
|
||||
|
||||
-----------------
|
||||
-- FAC Mission --
|
||||
-----------------
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskFAC_AttackGroup(self.group, AttackGroup, WeaponType, Designation, Datalink)
|
||||
|
||||
elseif Mission.type==FLIGHTGROUP.MissionType.FERRY then
|
||||
|
||||
-------------------
|
||||
-- FERRY Mission --
|
||||
-------------------
|
||||
|
||||
elseif Mission.type==FLIGHTGROUP.MissionType.INTERCEPT then
|
||||
|
||||
-----------------------
|
||||
-- INTERCEPT Mission --
|
||||
-----------------------
|
||||
|
||||
local mission=Mission --#FLIGHTGROUP.MissionINTERCEPT
|
||||
|
||||
for _,_group in pairs(mission.groupsetTargets:GetSet()) do
|
||||
local TargetGroup=_group
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskAttackGroup(self.group, TargetGroup, ENUMS.WeaponFlag.Auto, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit)
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
end
|
||||
|
||||
elseif Mission.type==FLIGHTGROUP.MissionType.ORBIT then
|
||||
|
||||
-------------------
|
||||
-- ORBIT Mission --
|
||||
-------------------
|
||||
|
||||
local mission=Mission --#FLIGHTGROUP.MissionORBIT
|
||||
|
||||
local CoordRaceTrack=mission.coordOrbit:Translate(mission.leg, mission.heading, true)
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskOrbit(self.group, mission.coordOrbit, mission.coordOrbit.y, mission.speedOrbit, CoordRaceTrack)
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif Mission.type==FLIGHTGROUP.MissionType.RECON then
|
||||
|
||||
-------------------
|
||||
-- RECON Mission --
|
||||
-------------------
|
||||
|
||||
elseif Mission.type==FLIGHTGROUP.MissionType.STRIKE then
|
||||
|
||||
-------------------
|
||||
-- STIKE Mission --
|
||||
-------------------
|
||||
|
||||
local mission=Mission --#FLIGHTGROUP.MissionSTRIKE
|
||||
|
||||
local Vec2=mission.coordtarget:GetVec2()
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskAttackMapObject(self.group, Vec2, GroupAttack, WeaponExpend, AttackQty, Direction, mission.altitude, WeaponType)
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif Mission.type==FLIGHTGROUP.MissionType.TANKER then
|
||||
|
||||
--------------------
|
||||
-- TANKER Mission --
|
||||
--------------------
|
||||
|
||||
elseif Mission.type==FLIGHTGROUP.MissionType.TRANSPORT then
|
||||
|
||||
else
|
||||
self:E(self.lid..string.format("ERROR: Unknown mission task!"))
|
||||
return nil
|
||||
end
|
||||
|
||||
if #DCStasks==1 then
|
||||
return DCStasks[1]
|
||||
else
|
||||
return CONTROLLABLE.TaskCombo(self.group, DCStasks)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Start & Status
|
||||
@@ -3125,7 +2668,7 @@ function FLIGHTGROUP:onafterTaskExecute(From, Event, To, Task)
|
||||
|
||||
-- Cancel current task if there is any.
|
||||
if self.taskcurrent>0 then
|
||||
--self:TaskCancel()
|
||||
self:TaskCancel()
|
||||
end
|
||||
|
||||
-- Set current task.
|
||||
@@ -3139,10 +2682,6 @@ function FLIGHTGROUP:onafterTaskExecute(From, Event, To, Task)
|
||||
|
||||
-- If task is scheduled (not waypoint) set task.
|
||||
if Task.type==FLIGHTGROUP.TaskType.SCHEDULED then
|
||||
|
||||
-- Clear all tasks.
|
||||
--self.group:ClearTasks()
|
||||
|
||||
|
||||
local DCStasks={}
|
||||
if Task.dcstask.id=='ComboTask' then
|
||||
@@ -3158,24 +2697,15 @@ function FLIGHTGROUP:onafterTaskExecute(From, Event, To, Task)
|
||||
local TaskDone=self.group:TaskFunction("FLIGHTGROUP._TaskDone", self, Task)
|
||||
table.insert(DCStasks, TaskDone)
|
||||
|
||||
env.info("FF DCS task combo")
|
||||
for i,DCStask in pairs(DCStasks) do
|
||||
self:I{{DCStask=DCStask}}
|
||||
end
|
||||
|
||||
-- Combo task.
|
||||
local TaskCombo=self.group:TaskCombo(DCStasks)
|
||||
|
||||
|
||||
-- Stop condition!
|
||||
local TaskCondition=self.group:TaskCondition(nil, Task.stopflag:GetName(), 1)
|
||||
|
||||
-- Controlled task.
|
||||
local TaskControlled=self.group:TaskControlled(TaskCombo, TaskCondition)
|
||||
|
||||
env.info("FF executing controlled Task:")
|
||||
self:I({task=TaskControlled})
|
||||
|
||||
|
||||
-- Set task for group.
|
||||
self:SetTask(TaskControlled, 1)
|
||||
|
||||
|
||||
@@ -1,412 +0,0 @@
|
||||
--- **Ops** - (R2.5) - Aerial refueling tanker.
|
||||
--
|
||||
-- **Main Features:**
|
||||
--
|
||||
-- * Monitor flight status of elements or entire group.
|
||||
-- * Create a mission queue.
|
||||
-- * Inherits FLIGHTGROUP class.
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **funkyfranky**
|
||||
-- @module Ops.TankerGroup
|
||||
-- @image OPS_TankerGroup.png
|
||||
|
||||
|
||||
--- TANKERGROUP class.
|
||||
-- @type TANKERGROUP
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #boolean Debug Debug mode. Messages to all about status.
|
||||
-- @field #string lid Class id string for output to DCS log file.
|
||||
-- @field #table Qmissions Mission queue.
|
||||
-- @field #table Qclients Client queue.
|
||||
-- @field #TANKERGROUP.Mission currentmission Currently assigned mission.
|
||||
-- @field #number missioncounter Counter of total missions.
|
||||
-- @field Core.Scheduler#SCHEDULER Statusupdater Scheduler to update tanker status.
|
||||
-- @extends Ops.FlightGroup#FLIGHTGROUP
|
||||
|
||||
--- *To invent an airplane is nothing. To build one is something. To fly is everything.* -- Otto Lilienthal
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # The TANKERGROUP Concept
|
||||
--
|
||||
-- # Events
|
||||
--
|
||||
--
|
||||
-- # Tasking
|
||||
--
|
||||
--
|
||||
-- # Examples
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
-- @field #TANKERGROUP
|
||||
TANKERGROUP = {
|
||||
ClassName = "TANKERGROUP",
|
||||
Debug = false,
|
||||
lid = nil,
|
||||
Qmissions = {},
|
||||
Qclients = {},
|
||||
currentmission = nil,
|
||||
missioncounter = nil,
|
||||
Statusupdater = nil,
|
||||
}
|
||||
|
||||
--- Tanker mission table.
|
||||
-- @type TANKERGROUP.Mission
|
||||
-- @field #string name Name of the mission.
|
||||
-- @field #number mid ID of the mission.
|
||||
-- @field #string status Mission status.
|
||||
-- @field Ops.FlightGroup#FLIGHTGROUP.Task task Task of mission.
|
||||
-- @field Core.Zone#ZONE zone Mission zone.
|
||||
-- @field #number duration Duration of mission.
|
||||
-- @field #number altitude Altitude of orbit in meters ASL.
|
||||
-- @field #number distance Length of orbit leg in meters.
|
||||
-- @field #number heading Heading of orbit in degrees.
|
||||
-- @field #number speed Speed in m/s.
|
||||
-- @field #number Tadded Time the mission was added.
|
||||
-- @field #number Tstart Start time in seconds.
|
||||
-- @field #number Tstarted Time the mission was started.
|
||||
-- @field #number Tstop Time the mission is stopped.
|
||||
-- @field #number Tsopped Time the mission was stopped.
|
||||
-- @field #number prio Priority of the mission.
|
||||
|
||||
--- Mission status.
|
||||
-- @type TANKERGROUP.MissionStatus
|
||||
-- @field #string SCHEDULED Mission is scheduled.
|
||||
-- @field #string EXECUTING Mission is being executed.
|
||||
-- @field #string ASSIGNED Mission was assigned.
|
||||
-- @field #string ACCOMPLISHED Mission is accomplished.
|
||||
TANKERGROUP.MissionStatus={
|
||||
SCHEDULED="scheduled",
|
||||
EXECUTING="executing",
|
||||
ASSIGNED="assigned",
|
||||
ACCOMPLISHED="accomplished",
|
||||
FAILED="failed",
|
||||
}
|
||||
--- TANKERGROUP class version.
|
||||
-- @field #string version
|
||||
TANKERGROUP.version="0.0.2"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Add orbit task.
|
||||
-- TODO: Add client queue.
|
||||
-- TODO: Add menu?
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Create a new TANKERGROUP object and start the FSM.
|
||||
-- @param #TANKERGROUP self
|
||||
-- @param #string groupname Name of the group.
|
||||
-- @return #TANKERGROUP self
|
||||
function TANKERGROUP:New(groupname)
|
||||
|
||||
-- Create flight group.
|
||||
local fg=FLIGHTGROUP:New(groupname, false)
|
||||
|
||||
-- Inherit everything from TANKERGROUP class.
|
||||
local self=BASE:Inherit(self, fg) -- #TANKERGROUP
|
||||
|
||||
-- Init mission counter.
|
||||
self.missioncounter=0
|
||||
|
||||
-- Log id.
|
||||
self.lid=string.format("FLIGHTGROUP %s (TANKER) | ", groupname)
|
||||
|
||||
if false then
|
||||
BASE:TraceOn()
|
||||
BASE:TraceLevel(3)
|
||||
BASE:TraceClass(self.ClassName)
|
||||
BASE:TraceClass("FLIGHTGROUP")
|
||||
end
|
||||
|
||||
-- Add FSM transitions.
|
||||
-- From State --> Event --> To State
|
||||
self:AddTransition("*", "TankerState", "*") -- Tanker is on station and ready to refuel.
|
||||
self:AddTransition("*", "OnStation", "Ready2Refuel") -- Tanker is on station and ready to refuel.
|
||||
self:AddTransition("*", "MissionStart", "*") -- Tanker is on station and ready to refuel.
|
||||
self:AddTransition("*", "MissionAccomplished", "*") -- Tanker is on station and ready to refuel.
|
||||
|
||||
|
||||
-- Call status update.
|
||||
self:__TankerState(-5)
|
||||
|
||||
-- Start FSM.
|
||||
self:Start()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- User API functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Add mission for tanker.
|
||||
-- @param #TANKERGROUP self
|
||||
-- @param Core.Zone#ZONE Zone The mission zone. Orbit is picked at a random location.
|
||||
-- @param #number Altitude Orbit altitude in feet. Default is 10000 ft.
|
||||
-- @param #number Distance Length of the race-track pattern leg in NM.
|
||||
-- @param #number Heading Heading of the race-track pattern in degrees. Default is 90, i.e. from West to East.
|
||||
-- @param #number SpeedOrbit Orbit speed in knots. Default is 280 knots.
|
||||
-- @param #string ClockStart Time the mission is started, e.g. "05:00" for 5 am. If specified as a #number, it will be relative (in seconds) to the current mission time.
|
||||
-- @param #string ClockStop Time the mission is stopped, e.g. "13:00" for 1 pm. If mission could not be started at that time, it will be removed from the queue. If specified as a #number it will be relative (in seconds) to the current mission time.
|
||||
-- @param #number Prio Priority of the mission, i.e. a number between 1 and 100. Default 50.
|
||||
-- @param #string Name Mission name. Default "Aerial Refueling #00X", where "#00X" is a running mission counter index starting at "#001".
|
||||
-- @return #TANKERGROUP.Mission The mission table.
|
||||
function TANKERGROUP:AddMission(Zone, Altitude, Distance, Heading, SpeedOrbit, ClockStart, ClockStop, Prio, Name)
|
||||
|
||||
-- Increase mission counter.
|
||||
self.missioncounter=self.missioncounter+1
|
||||
|
||||
-- Current mission time.
|
||||
local Tnow=timer.getAbsTime()
|
||||
|
||||
-- Set start time. Default in 5 sec.
|
||||
local Tstart=Tnow+5
|
||||
if ClockStart and type(ClockStart)=="number" then
|
||||
Tstart=Tnow+ClockStart
|
||||
elseif ClockStart and type(ClockStart)=="string" then
|
||||
Tstart=UTILS.ClockToSeconds(ClockStart)
|
||||
end
|
||||
|
||||
-- Set stop time. Default nil.
|
||||
local Tstop=nil
|
||||
if ClockStop and type(ClockStop)=="number" then
|
||||
Tstop=Tnow+ClockStop
|
||||
elseif ClockStop and type(ClockStop)=="string" then
|
||||
Tstop=UTILS.ClockToSeconds(ClockStop)
|
||||
end
|
||||
|
||||
-- Make mission table.
|
||||
local mission={} --#TANKERGROUP.Mission
|
||||
mission.zone=Zone
|
||||
mission.mid=self.missioncounter
|
||||
mission.altitude=UTILS.FeetToMeters(Altitude or 10000)
|
||||
mission.distance=UTILS.NMToMeters(Distance or 25)
|
||||
mission.name=Name or string.format("Aerial Refueling #%03d", mission.mid)
|
||||
mission.speed=UTILS.KnotsToMps(SpeedOrbit or 280)
|
||||
mission.heading=Heading or 270
|
||||
mission.Tadded=Tnow
|
||||
mission.Tstart=Tstart
|
||||
mission.Tstop=Tstop
|
||||
mission.status=TANKERGROUP.MissionStatus.SCHEDULED
|
||||
if Tstop then
|
||||
mission.duration=mission.Tstop-mission.Tstart
|
||||
end
|
||||
mission.prio=Prio or 50
|
||||
mission.task=nil
|
||||
|
||||
-- Add mission to queue.
|
||||
table.insert(self.Qmissions, mission)
|
||||
|
||||
local text=string.format("Added mission %s at zone %s. Starting at %s. Stopping at %s. Altitude=%d ft, Leg=%s NM, Heading=%03d, Speed=%d kts",
|
||||
mission.zone:GetName(), mission.name, UTILS.SecondsToClock(mission.Tstart, true), mission.Tstop and UTILS.SecondsToClock(mission.Tstop, true) or "never",
|
||||
UTILS.MetersToFeet(mission.altitude), UTILS.MetersToNM(mission.distance), mission.heading, UTILS.MpsToKnots(mission.speed))
|
||||
self:I(self.lid..text)
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- FSM functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- On after "TankerStatus" event.
|
||||
-- @param #TANKERGROUP self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
function TANKERGROUP:onafterTankerState(From, Event, To)
|
||||
|
||||
-- FSM state.
|
||||
local fsmstate=self:GetState()
|
||||
|
||||
-- First check if group is alive?
|
||||
if self:IsAlive()~=nil and not self.currentmission then
|
||||
|
||||
local mission=self:_GetNextMission()
|
||||
|
||||
if mission then
|
||||
|
||||
env.info("FF starting mission")
|
||||
self:MissionStart(mission)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-- Current mission name.
|
||||
local mymission=self.currentmission and self.currentmission.name or "N/A"
|
||||
|
||||
-- Current status.
|
||||
local text=string.format("Tanker Status %s: Mission=%s (%d)", fsmstate, mymission, #self.Qmissions)
|
||||
for i,_mission in pairs(self.Qmissions) do
|
||||
local mission=_mission --#TANKERGROUP.Mission
|
||||
text=text..string.format("\n[%d] %s status=%s", i, tostring(mission.name), tostring(mission.status))
|
||||
end
|
||||
self:I(self.lid..text)
|
||||
|
||||
-- Nest status update in 30 sec.
|
||||
self:__TankerState(-30)
|
||||
end
|
||||
|
||||
--- On after "MissionStart" event.
|
||||
-- @param #TANKERGROUP self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #TANKERGROUP.Mission Mission The mission table.
|
||||
function TANKERGROUP:onafterMissionStart(From, Event, To, Mission)
|
||||
|
||||
-- TODO: need to handle case that group is spawned at a later point in time!
|
||||
|
||||
-- Delay for route to mission. Group needs to be activated and controlled.
|
||||
local delay=nil
|
||||
|
||||
-- Check if group is spawned.
|
||||
if self:IsInUtero() then
|
||||
|
||||
-- Activate group if it is late activated.
|
||||
if self:IsLateActivated() then
|
||||
self:Activate()
|
||||
delay=1
|
||||
end
|
||||
|
||||
-- Activate group if it is uncontrolled.
|
||||
if self:IsUncontrolled() then
|
||||
self:StartUncontrolled(5)
|
||||
delay=6
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Set current mission.
|
||||
self.currentmission=Mission
|
||||
|
||||
-- Set Tstarted time stamp.
|
||||
self.currentmission.Tstarted=timer.getAbsTime()
|
||||
|
||||
-- Set mission status.
|
||||
self.currentmission.status=TANKERGROUP.MissionStatus.EXECUTING
|
||||
|
||||
-- Route flight to mission zone.
|
||||
self:RouteToMission(Mission, delay)
|
||||
|
||||
end
|
||||
|
||||
--- On after "TaskDone" event.
|
||||
-- @param #TANKERGROUP self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param Ops.FlightGroup#FLIGHTGROUP.Task Task.
|
||||
function TANKERGROUP:onafterTaskDone(From, Event, To, Task)
|
||||
|
||||
-- First call flight status.
|
||||
self:GetParent(self).onafterTaskDone(self, From, Event, To, Task)
|
||||
|
||||
if self.currentmission then
|
||||
|
||||
local missiontask=self.currentmission.task
|
||||
|
||||
if missiontask.id==Task.id then
|
||||
self:MissionAccomplished(self.currentmission)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--- On after "MissionAccomplished" event.
|
||||
-- @param #TANKERGROUP self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #TANKERGROUP.Mission Mission
|
||||
function TANKERGROUP:onafterMissionAccomplished(From, Event, To, Mission)
|
||||
|
||||
Mission.status=TANKERGROUP.MissionStatus.ACCOMPLISHED
|
||||
self.currentmission=nil
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- MISC functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Get next mission.
|
||||
-- @param #TANKERGROUP self
|
||||
-- @return #TANKERGROUP.Mission Next mission or *nil*.
|
||||
function TANKERGROUP:_GetNextMission()
|
||||
|
||||
-- Number of missions.
|
||||
local Nmissions=#self.Qmissions
|
||||
|
||||
-- Treat special cases.
|
||||
if Nmissions==0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Sort results table wrt times they have already been engaged.
|
||||
local function _sort(a, b)
|
||||
local taskA=a --#TANKERGROUP.Mission
|
||||
local taskB=b --#TANKERGROUP.Mission
|
||||
return (taskA.Tstart<taskB.Tstart) or (taskA.Tstart==taskB.Tstart and taskA.prio<taskB.prio)
|
||||
end
|
||||
table.sort(self.Qmissions, _sort)
|
||||
|
||||
-- Current time.
|
||||
local time=timer.getAbsTime()
|
||||
|
||||
-- Look for first task that is not accomplished.
|
||||
for _,_mission in pairs(self.Qmissions) do
|
||||
local mission=_mission --#TANKERGROUP.Mission
|
||||
if mission.status==TANKERGROUP.MissionStatus.SCHEDULED and time>=mission.Tstart then
|
||||
return mission
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Route group to mission. Also sets the
|
||||
-- @param #TANKERGROUP self
|
||||
-- @param #TANKERGROUP.Mission mission The mission table.
|
||||
-- @param #number delay Delay in seconds.
|
||||
function TANKERGROUP:RouteToMission(mission, delay)
|
||||
|
||||
if delay and delay>0 then
|
||||
-- Delay call.
|
||||
self:ScheduleOnce(delay, TANKERGROUP.RouteToMission, self, mission)
|
||||
else
|
||||
|
||||
-- Get random coordinate in mission zone.
|
||||
local Coordinate=mission.zone:GetRandomCoordinate():SetAltitude(mission.altitude, true)
|
||||
|
||||
-- Set second coordinate for race track pattern.
|
||||
local CoordRaceTrack=Coordinate:Translate(mission.distance, mission.heading, true)
|
||||
|
||||
Coordinate:MarkToAll("Orbit 1")
|
||||
CoordRaceTrack:MarkToAll("Orbit 2")
|
||||
|
||||
-- Add waypoint.
|
||||
self:AddWaypointAir(Coordinate, nil, self.speedmax*0.8)
|
||||
|
||||
-- Create task to orbit.
|
||||
local taskorbit=self.group:TaskOrbit(Coordinate, mission.altitude, mission.speed, CoordRaceTrack)
|
||||
|
||||
-- Add waypoint task.
|
||||
-- TODO: find last AIR waypoint! We dont want this at landing waypoints.
|
||||
mission.task=self:AddTaskWaypoint(taskorbit, #self.waypoints, mission.name, 10, mission.duration)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -52,7 +52,6 @@ WINGCOMMANDER = {
|
||||
-- @field #number Nonmission Number of assets currently on mission.
|
||||
|
||||
|
||||
|
||||
--- WINGCOMMANDER class version.
|
||||
-- @field #string version
|
||||
WINGCOMMANDER.version="0.0.1"
|
||||
@@ -257,7 +256,7 @@ function WINGCOMMANDER:CheckResources()
|
||||
|
||||
local capabilities={}
|
||||
|
||||
for _,MissionType in pairs(FLIGHTGROUP.MissionType) do
|
||||
for _,MissionType in pairs(AUFTRAG.Type) do
|
||||
capabilities[MissionType]=0
|
||||
|
||||
for _,_airwing in pairs(self.airwings) do
|
||||
|
||||
Reference in New Issue
Block a user