This commit is contained in:
Frank
2020-03-06 17:29:43 +01:00
parent fd730206a6
commit 2eb4e87d32
7 changed files with 538 additions and 236 deletions
@@ -1894,19 +1894,26 @@ function WAREHOUSE:New(warehouse, alias)
-- From State --> Event --> To State
self:AddTransition("NotReadyYet", "Load", "Loaded") -- Load the warehouse state from scatch.
self:AddTransition("Stopped", "Load", "Loaded") -- Load the warehouse state stopped state.
self:AddTransition("NotReadyYet", "Start", "Running") -- Start the warehouse from scratch.
self:AddTransition("Loaded", "Start", "Running") -- Start the warehouse when loaded from disk.
self:AddTransition("*", "Status", "*") -- Status update.
self:AddTransition("*", "AddAsset", "*") -- Add asset to warehouse stock.
self:AddTransition("*", "NewAsset", "*") -- New asset was added to warehouse stock.
self:AddTransition("*", "AddRequest", "*") -- New request from other warehouse.
self:AddTransition("Running", "Request", "*") -- Process a request. Only in running mode.
self:AddTransition("Running", "RequestSpawned", "*") -- Assets of request were spawned.
self:AddTransition("Attacked", "Request", "*") -- Process a request. Only in running mode.
self:AddTransition("*", "Unloaded", "*") -- Cargo has been unloaded from the carrier (unused ==> unnecessary?).
self:AddTransition("*", "AssetSpawned", "*") -- Asset has been spawned into the world.
self:AddTransition("*", "AssetLowFuel", "*") -- Asset is low on fuel.
self:AddTransition("*", "Arrived", "*") -- Cargo or transport group has arrived.
self:AddTransition("*", "Delivered", "*") -- All cargo groups of a request have been delivered to the requesting warehouse.
self:AddTransition("Running", "SelfRequest", "*") -- Request to warehouse itself. Requested assets are only spawned but not delivered anywhere.
self:AddTransition("Attacked", "SelfRequest", "*") -- Request to warehouse itself. Also possible when warehouse is under attack!
@@ -5933,8 +5940,9 @@ end
--- Get a warehouse request from its unique id.
-- @param #WAREHOUSE self
-- @param #number id Asset ID.
-- @return #WAREHOUSE.Pendingitem The warehouse requested - either queued or pending. #boolean If *true*, request is queued, if *false*, request is pending, if *nil*, request could not be found.
-- @param #number id Request ID.
-- @return #WAREHOUSE.Pendingitem The warehouse requested - either queued or pending.
-- @return #boolean If *true*, request is queued, if *false*, request is pending, if *nil*, request could not be found.
function WAREHOUSE:GetRequestByID(id)
if id then
@@ -8092,7 +8100,6 @@ end
-- @param #number qitemID ID of queue item to be removed.
-- @param #table queue The queue from which the item should be deleted.
function WAREHOUSE:_DeleteQueueItemByID(qitemID, queue)
self:F({qitem=qitem, queue=queue})
for i=1,#queue do
local _item=queue[i] --#WAREHOUSE.Queueitem
+250 -87
View File
@@ -27,6 +27,8 @@
-- @field #number nflightsCAP Number of CAP flights constantly in the air.
-- @field #number nflightsTANKER Number of TANKER flights constantly in the air.
-- @field #number nflightsAWACS Number of AWACS flights constantly in the air.
-- @field #table cappoints Table of CAP points.
-- @field Ops.WingCommander#WINGCOMMANDER wingcommander The wing commander responsible for this airwing.
-- @extends Functional.Warehouse#WAREHOUSE
--- Be surprised!
@@ -49,6 +51,7 @@ AIRWING = {
missionqueue = {},
payloads = {},
cappoints = {},
wingcommander = nil,
}
--- Squadron data.
@@ -366,6 +369,25 @@ function AIRWING:AddMission(Mission)
return self
end
--- Remove mission from queue.
-- @param #AIRWING self
-- @param Ops.Auftrag#AUFTRAG Mission Mission to be removed.
-- @return #AIRWING self
function AIRWING:RemoveMission(Mission)
for i,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
if mission.auftragsnummer==Mission.auftragsnummer then
table.remove(self.missionqueue, i)
break
end
end
return self
end
--- Set CAP zones.
-- @param #AIRWING self
-- @param #number n Number of flights. Default 1.
@@ -375,11 +397,11 @@ function AIRWING:SetCAPflights(n)
return self
end
--- Add a CAP zone.
--- Add a patrol Point for CAP missions.
-- @param #AIRWING self
-- @param Core.Zone#ZONE AcceptZone Add a zone to the CAP zone set.
-- @return #AIRWING self
function AIRWING:AddCAPPoint(Coordinate, Heading, Leg, Speed)
function AIRWING:AddPatrolPointCAP(Coordinate, Heading, Leg, Speed)
local cappoint={} --#AIRWING.PatrolData
cappoint.coord=Coordinate
@@ -430,6 +452,13 @@ function AIRWING:onafterStatus(From, Event, To)
local fsmstate=self:GetState()
-- Check CAP missions.
self:CheckCAP()
self:CheckTANKER()
self:CheckAWACS()
------------------
-- Mission Info --
------------------
@@ -487,6 +516,58 @@ function AIRWING:onafterStatus(From, Event, To)
end
--- Get patrol data
-- @param #AIRWING self
-- @param #table PatrolPoints Patrol data points.
-- @return #AIRWING.PatrolData
function AIRWING:_GetPatrolData(PatrolPoints)
local function sort(a,b)
return a.noccuied<b.noccuied
end
if PatrolPoints then
-- Sort data wrt number of flights at that point.
table.sort(PatrolPoints, sort)
return PatrolPoints[1]
else
local point={} --#AIRWING.PatrolData
point.coord=self:GetCoordinate()
point.speed=math.random(250, 350)
point.heading=math.random(360)
point.occupied=false
end
end
--- Get next mission.
-- @param #AIRWING self
-- @return Ops.Auftrag#AUFTRAG Next mission or *nil*.
function AIRWING:_CheckCAP()
local Ncap=self:CountAssetsOnMission(AUFTRAG.Type.PATROL)
for i=1,self.nflightsCAP-Ncap do
local patrol=self:_GetPatrolData(self.cappoints)
local missionCAP=AUFTRAG:NewPATROL(patrol.coord, patrol.speed, patrol.heading, patrol.leg)
missionCAP.patroldata=patrol
self:AddMission(missionCAP)
end
end
--- Get next mission.
-- @param #AIRWING self
-- @return Ops.Auftrag#AUFTRAG Next mission or *nil*.
@@ -528,9 +609,13 @@ function AIRWING:_GetNextMission()
if can then
-- Optimize the asset selection. Most useful assets will come first.
-- TODO: This could be moved to AUFTRAG, right?
--self:_OptimizeAssetSelection(assets, mission)
-- TODO: check that mission.assets table is clean.
-- Check that mission.assets table is clean.
if mission.assets and #mission.assets>0 then
self:E(self.lid..string.format("ERROR: mission %s of type %s has already assets attached!", mission.name, mission.type))
end
mission.assets={}
-- Assign assets to mission.
@@ -544,7 +629,7 @@ function AIRWING:_GetNextMission()
self:E("No payload for asset! This should not happen!")
end
table.insert(mission.assets, asset)
mission:AddAsset(asset)
end
return mission
@@ -608,61 +693,6 @@ end
-- FSM Events
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- On after "NewAsset" event. Asset is added to the given squadron (asset assignment).
-- @param #AIRWING self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Functional.Warehouse#WAREHOUSE.Assetitem asset The asset that has just been added.
-- @param #string assignment The (optional) assignment for the asset.
function AIRWING:onafterNewAsset(From, Event, To, asset, assignment)
-- Call parent warehouse function first.
self:GetParent(self).onafterNewAsset(self, From, Event, To, asset, assignment)
-- Get squadron.
local squad=self:GetSquadron(asset.assignment)
-- Check if asset is already part of the squadron. If an asset returns, it will be added again! We check that asset.assignment is also assignment.
if squad and asset.assignment==assignment then
-- Debug text.
local text=string.format("Adding asset to squadron %s: assignment=%s, type=%s, attribute=%s", squad.name, assignment, asset.unittype, asset.attribute)
self:I(self.lid..text)
-- Add asset to squadron.
table.insert(squad.assets, asset)
end
end
--- On after "MissionCancel" event.
-- @param #AIRWING self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Ops.Auftrag#AUFTRAG Mission The mission to be cancelled.
function AIRWING:onafterMissionCancel(From, Event, To, Mission)
self:I(self.lid..string.format("Cancel mission %s", Mission.name))
for _,_asset in pairs(Mission.assets) do
local asset=_asset --#AIRWING.SquadronAsset
local flightgroup=asset.flightgroup
if flightgroup then
flightgroup:MissionCancel(Mission)
end
end
-- Remove queued request (if any).
if Mission.requestID then
self:_DeleteQueueItemByID(Mission.requestID, self.queue)
end
end
--- On after "MissionRequest" event. Performs a self request to the warehouse for the mission assets. Sets mission status to REQUESTED.
-- @param #AIRWING self
-- @param #string From From state.
@@ -713,6 +743,132 @@ function AIRWING:onafterMissionRequest(From, Event, To, Mission)
end
--- On after "MissionCancel" event. Cancels the missions of all flightgroups. Deletes request from warehouse queue.
-- @param #AIRWING self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Ops.Auftrag#AUFTRAG Mission The mission to be cancelled.
function AIRWING:onafterMissionCancel(From, Event, To, Mission)
self:I(self.lid..string.format("Cancel mission %s", Mission.name))
for _,_asset in pairs(Mission.assets) do
local asset=_asset --#AIRWING.SquadronAsset
local flightgroup=asset.flightgroup
if flightgroup then
flightgroup:MissionCancel(Mission)
end
end
-- Remove queued request (if any).
if Mission.requestID then
self:_DeleteQueueItemByID(Mission.requestID, self.queue)
end
end
--- On after "NewAsset" event. Asset is added to the given squadron (asset assignment).
-- @param #AIRWING self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Functional.Warehouse#WAREHOUSE.Assetitem asset The asset that has just been added.
-- @param #string assignment The (optional) assignment for the asset.
function AIRWING:onafterNewAsset(From, Event, To, asset, assignment)
-- Call parent warehouse function first.
self:GetParent(self).onafterNewAsset(self, From, Event, To, asset, assignment)
-- Get squadron.
local squad=self:GetSquadron(asset.assignment)
-- Check if asset is already part of the squadron. If an asset returns, it will be added again! We check that asset.assignment is also assignment.
if squad then
if asset.assignment==assignment then
-- Debug text.
local text=string.format("Adding asset to squadron %s: assignment=%s, type=%s, attribute=%s", squad.name, assignment, asset.unittype, asset.attribute)
self:I(self.lid..text)
-- Add asset to squadron.
table.insert(squad.assets, asset)
else
local mission=self:GetMissionByID(assignment)
if mission then
local text=string.format("Asset %s returned from %s mission %s", asset.spawngroupname, mission.type, mission.name)
self:I(self.lid..text)
else
self:E(self.lid.."ERROR: new asset not beloning to any s")
end
end
end
end
--- On after "AssetSpawned" event triggered when an asset group is spawned into the cruel world.
-- Creates a new flightgroup element and adds the mission to the flightgroup queue.
-- @param #AIRWING self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Group#GROUP group The group spawned.
-- @param #AIRWING.SquadronAsset asset The asset that was spawned.
-- @param Functional.Warehouse#WAREHOUSE.Pendingitem request The request of the dead asset.
function AIRWING:onafterAssetSpawned(From, Event, To, group, asset, request)
-- Call parent warehouse function first.
self:GetParent(self).onafterAssetSpawned(self, From, Event, To, group, asset, request)
-- Create a flight group.
asset.flightgroup=self:_CreateFlightGroup(asset)
-- Get Mission (if any).
local mission=self:GetMissionByID(request.assignment)
-- Add mission to flightgroup queue.
if mission then
-- Add mission to flightgroup queue.
asset.flightgroup:AddMission(mission)
end
-- Add group to the detection set of the WINGCOMMANDER.
if self.wingcommander then
self.wingcommander.detectionset:AddGroup(asset.flightgroup.group)
end
end
--- On after "AssetDead" event triggered when an asset group died.
-- @param #AIRWING self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #AIRWING.SquadronAsset asset The asset that is dead.
-- @param Functional.Warehouse#WAREHOUSE.Pendingitem request The request of the dead asset.
function AIRWING:onafterAssetDead(From, Event, To, asset, request)
-- Call parent warehouse function first.
self:GetParent(self).onafterAssetDead(From, Event, To, asset, request)
-- Add group to the detection set of the WINGCOMMANDER.
if self.wingcommander then
self.wingcommander.detectionset:RemoveGroupsByName({asset.spawngroupname})
end
end
--- On after "Request" event.
-- @param #AIRWING self
-- @param #string From From state.
@@ -741,34 +897,6 @@ function AIRWING:onafterRequest(From, Event, To, Request)
end
--- On after "AssetSpawned" event triggered when an asset group is spawned into the cruel world. Creates a new flightgroup element and adds the mission to the flightgroup queue.
-- @param #AIRWING self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Group#GROUP group The group spawned.
-- @param #AIRWING.SquadronAsset asset The asset that was spawned.
-- @param Functional.Warehouse#WAREHOUSE.Pendingitem request The request of the dead asset.
function AIRWING:onafterAssetSpawned(From, Event, To, group, asset, request)
-- Call parent warehouse function first.
self:GetParent(self).onafterAssetSpawned(self, From, Event, To, group, asset, request)
-- Create a flight group.
asset.flightgroup=self:_CreateFlightGroup(asset)
-- Get Mission (if any).
local mission=self:GetMissionByID(request.assignment)
-- Add mission to flightgroup queue.
if mission then
-- Add mission to flightgroup queue.
asset.flightgroup:AddMission(mission)
end
end
--- On after "SelfRequest" event.
-- @param #AIRWING self
-- @param #string From From state.
@@ -972,6 +1100,41 @@ function AIRWING:GetAssetCurrentMission(asset)
end
--- Count assets on mission.
-- @param #AIRWING self
-- @param #table MissionTypes Types on mission to be checked. Default all.
-- @return #number Number of pending and queued assets.
-- @return #number Number of pending assets.
-- @return #number Number of queued assets.
function AIRWING:CountAssetsOnMission(MissionTypes)
local Nq=0
local Np=0
for _,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
-- Check if this mission type is requested.
if self:CheckMissionType(mission.type, MissionTypes) then
for _,_asset in pairs(mission.assets or {}) do
local asset=_asset --#AIRWING.SquadronAsset
local request, isqueued=self:GetRequestByID(mission.requestID)
if isqueued then
Nq=Nq+1
else
Np=Np+1
end
end
end
end
return Np+Nq, Np, Nq
end
--- Check if assets for a given mission type are available.
-- @param #AIRWING self
-- @param #string MissionType Type of mission.
+103 -7
View File
@@ -97,6 +97,7 @@ AUFTRAG = {
lid = nil,
auftragsnummer = nil,
flightdata = {},
assets = {},
}
--- Global mission counter.
@@ -116,6 +117,7 @@ _AUFTRAGSNR=0
-- @param #string FERRY Ferry flight mission.
-- @param #string INTERCEPT Intercept mission.
-- @param #string ORBIT Orbit mission.
-- @param #string PATROL Similar to CAP but no auto engage targets.
-- @param #string RECON Recon mission.
-- @param #string SEAD Suppression/destruction of enemy air defences.
-- @param #string STRIKE Strike mission.
@@ -133,6 +135,7 @@ AUFTRAG.Type={
FERRY="Ferry Flight",
INTERCEPT="Intercept",
ORBIT="Orbit",
PATROL="Patrol",
RECON="Recon",
SEAD="SEAD",
STRIKE="Strike",
@@ -291,6 +294,29 @@ function AUFTRAG:NewORBIT(Coordinate, Speed, Heading, Leg)
return auftrag
end
--- Create a PATROL 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 #number Altitude Orbit altitude in feet.
-- @return #AUFTRAG self
function AUFTRAG:NewPATROL(OrbitCoordinate, OrbitSpeed, Heading, Leg, Altitude)
-- Create ORBIT first.
local mission=self:NewORBIT(OrbitCoordinate, OrbitSpeed, Heading, Leg)
if Altitude then
mission.orbitCoord.y=UTILS.FeetToMeters(Altitude)
end
-- CAP paramters.
mission.type=AUFTRAG.Type.PATROL
return mission
end
--- Create a CAP mission.
-- @param #AUFTRAG self
-- @param Core.Point#COORDINATE OrbitCoordinate Where to orbit. Altitude is also taken from the coordinate.
@@ -562,7 +588,7 @@ end
--- Check if mission is done.
-- @param #AUFTRAG self
-- @return #boolean If true, mission is done.
function AUFTRAG:IsCancelled()
function AUFTRAG:IsDone()
return self.status==AUFTRAG.Status.DONE
end
@@ -640,6 +666,16 @@ function AUFTRAG:onafterStatus(From, Event, To)
end
end
--- Set flightgroup mission status.
-- @param #AUFTRAG self
-- @return #string status New status.
function AUFTRAG:Evaluate()
local Ntargets=self:CountMissionTargets()
end
--- Set flightgroup mission status.
-- @param #AUFTRAG self
-- @param Ops.FlightGroup#FLIGHTGROUP flightgroup The flight group.
@@ -735,7 +771,7 @@ end
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function AUFTRAG:onafterRequested(From, Event, TO)
function AUFTRAG:onafterRequested(From, Event, To)
self.status=AUFTRAG.Status.REQUESTED
self:I(self.lid..string.format("New mission status=%s", self.status))
end
@@ -802,7 +838,8 @@ function AUFTRAG:onafterCancel(From, Event, To)
self:I(self.lid..string.format("New mission status=%s", self.status))
if self.airwing then
-- Airwing will cancel all flight missions and remove queued request from warehouse queue.
self.airwing:MissionCancel(self)
else
@@ -811,11 +848,12 @@ function AUFTRAG:onafterCancel(From, Event, To)
local flightdata=_flightdata --#AUFTRAG.FlightData
flightdata.flightgroup:MissionCancel(self)
end
end
end
--- On after "Stop" event.
--- On after "Stop" event. Remove mission from AIRWING and FLIGHTGROUP mission queues.
-- @param #AUFTRAG self
-- @param #string From From state.
-- @param #string Event Event.
@@ -823,6 +861,19 @@ end
function AUFTRAG:onafterStop(From, Event, To)
-- TODO: remove missions from queues in WINGCOMMANDER, AIRWING and FLIGHGROUPS!
if self.wingcommander then
end
if self.airwing then
self.airwing:RemoveMission(self)
end
for _,_flightdata in pairs(self.flightdata) do
local flightdata=_flightdata --#AUFTRAG.FlightData
flightdata.flightgroup:RemoveMission(self)
end
self.CallScheduler:Clear()
end
@@ -831,15 +882,60 @@ end
-- Misc Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Add asset to mission.
-- @param #AUFTRAG self
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The asset to be added to the mission.
-- @return #AIRWING self
function AUFTRAG:AddAsset(Asset)
self.assets=self.assets or {}
table.insert(self.assets, Asset)
return self
end
--- Delete asset from mission.
-- @param #AUFTRAG self
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The asset to be removed.
-- @return #AIRWING self
function AUFTRAG:DelAsset(Asset)
for i,_asset in pairs(self.assets or {}) do
local asset=_asset --Ops.AirWing#AIRWING.SquadronAsset
if asset.uid==Asset.uid then
table.remove(self.assets, i)
end
end
end
--- Count alive mission targets.
-- @param #AUFTRAG self
-- @return #number Number of alive targets.
-- @return #number Number of alive target units.
function AUFTRAG:CountMissionTargets()
local N=0
if self.engageTargetGroupset then
local n=self.engageTargetGroupset:CountAlive()
N=N+n
--local n=self.engageTargetGroupset:CountAlive()
for _,_group in pairs(self.engageTargetGroupset.Set) do
local group=_group --Wrapper.Group#GROUP
if group and group:IsAlive() then
for _,_unit in pairs(group:GetUnits()) do
local unit=_unit --Wrapper.Unit#UNIT
if unit and unit:IsAlive() then
N=N+1
end
end
end
end
end
if self.engageTargetUnitset then
@@ -679,6 +679,25 @@ function FLIGHTGROUP:AddMission(Mission)
return self
end
--- Remove mission from queue.
-- @param #FLIGHTGROUP self
-- @param Ops.Auftrag#AUFTRAG Mission Mission to be removed.
-- @return #FLIGHTGROUP self
function FLIGHTGROUP:RemoveMission(Mission)
for i,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
if mission.auftragsnummer==Mission.auftragsnummer then
table.remove(self.missionqueue, i)
break
end
end
return self
end
--- Set AIRWING the flight group belongs to.
-- @param #FLIGHTGROUP self
-- @param Ops.AirWing#AIRWING airwing The AIRWING object.
+32 -13
View File
@@ -71,10 +71,11 @@ INTEL.version="0.0.3"
-- ToDo list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Accept and reject zones.
-- TODO: SetAttributeZone --> return groups of generalized attributes in a zone.
-- TODO: Loose units only if they remain undetected for a given time interval. We want to avoid fast oscillation between detected/lost states. Maybe 1-5 min would be a good time interval?!
-- TODO: Combine units to groups for all, new and lost.
-- DONE: Accept zones.
-- TODO: Reject zones.
-- NOGO: SetAttributeZone --> return groups of generalized attributes in a zone.
-- DONE: Loose units only if they remain undetected for a given time interval. We want to avoid fast oscillation between detected/lost states. Maybe 1-5 min would be a good time interval?!
-- DONE: Combine units to groups for all, new and lost.
-- TODO: process detected set asynchroniously for better performance.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -243,7 +244,7 @@ function INTEL:onafterStatus(From, Event, To)
local Ncontacts=#self.Contacts
-- Short info.
local text=string.format("Status %s: Agents=%s, Contacts=%d, New=%d, Lost=%d", fsmstate, self.detectionset:CountAlive(), Ncontacts, #self.ContactsUnknown, #self.ContactsLost)
local text=string.format("Status %s [Agents=%s]: Contacts=%d, New=%d, Lost=%d", fsmstate, self.detectionset:CountAlive(), Ncontacts, #self.ContactsUnknown, #self.ContactsLost)
self:I(self.lid..text)
-- Detailed info.
@@ -277,22 +278,39 @@ function INTEL:UpdateIntel()
-- Get set of detected units.
local detectedunitset=recce:GetDetectedUnitSet()
-- Add detected units to all set.
DetectedSet=DetectedSet:GetSetUnion(detectedunitset)
end
end
end
-- TODO: Filter units from accept/reject zones.
-- TODO: Filter units from reject zones.
-- TODO: Filter unit types.
-- TODO: Filter detection methods?
for _,_zone in pairs(self.acceptzoneset.Set) do
local zone=_zone --Core.Zone#ZONE
local remove={}
for _,_unit in pairs(DetectedSet.Set) do
local unit=_unit --Wrapper.Unit#UNIT
-- Check if unit is in any of the accept zones.
local inzone=false
for _,_zone in pairs(self.acceptzoneset.Set) do
local zone=_zone --Core.Zone#ZONE
if unit:IsInZone(zone) then
inzone=true
break
end
end
-- Unit is not in accept zone ==> remove!
if not inzone then
table.insert(remove, unit:GetName())
end
end
-- Remove filtered units.
DetectedSet:RemoveUnitsByName(remove)
-- Create detected contacts.
self:CreateDetectedItems(DetectedSet)
@@ -305,6 +323,7 @@ function INTEL:CreateDetectedItems(detectedunitset)
local detectedgroupset=SET_GROUP:New()
-- Convert detected UNIT set to detected GROUP set.
for _,_unit in pairs(detectedunitset:GetSet()) do
local unit=_unit --Wrapper.Unit#UNIT
@@ -374,9 +393,9 @@ function INTEL:CreateDetectedItems(detectedunitset)
local group=detectedgroupset:FindGroup(item.groupname)
-- Check if deltaT>Tforget. We dont want quick oszillations between detected and undetected states.
-- Check if deltaT>Tforget. We dont want quick oscillations between detected and undetected states.
if self:CheckContactLost(item) then
-- Trigger LostContact event.
-- Trigger LostContact event. This also adds the contact to the self.ContactsLost table.
self:LostContact(item)
-- Remove contact from table.
self:RemoveContact(item)
@@ -412,7 +431,7 @@ function INTEL:onafterLostContact(From, Event, To, Contact)
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Misc Fuctions
-- Misc Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create detected items.
+26 -67
View File
@@ -1,4 +1,4 @@
--- **Ops** - (R2.5) - AI Squadron for Ops.
--- **Ops** - Airwing Squadron.
--
-- **Main Features:**
--
@@ -15,9 +15,9 @@
-- @type SQUADRON
-- @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 lid Class id string for output to DCS log file.
-- @field #string livery Livery of the squadron.
-- @field #table flights Table of flight groups.
-- @field #table assets Table of assets.
-- @extends Core.Fsm#FSM
--- Be surprised!
@@ -34,10 +34,13 @@
SQUADRON = {
ClassName = "SQUADRON",
Debug = nil,
sid = nil,
flights = {},
tasks = {},
livery = nil,
lid = nil,
name = nil,
templatename = nil,
assets = {},
livery = nil,
skill = nil,
airwing = nil,
}
--- Flight group element.
@@ -64,13 +67,13 @@ SQUADRON.version="0.0.1"
-- @param #string SquadName Name of the squadron, e.g. "VFA-37".
-- @param #table tasks Table of squadron tasks, e.g. `{SQUADRON.Task.INTERCEPT, SQUADRON.Task.SEAD}`.
-- @return #SQUADRON self
function SQUADRON:New(squadronname)
function SQUADRON:New(SquadronName, TemplateGroupName)
-- Inherit everything from FSM class.
local self=BASE:Inherit(self, FSM:New()) -- #SQUADRON
--self.flightgroup=AIGroup
self.squadronname=tostring(squadronname)
self.name=tostring(SquadronName)
-- Set home airbase.
self.homebase=airbase
@@ -90,7 +93,6 @@ function SQUADRON:New(squadronname)
-- Add FSM transitions.
-- From State --> Event --> To State
self:AddTransition("Stopped", "Start", "Running") -- Start FSM.
self:AddTransition("*", "Status", "*") -- SQUADRON status update
@@ -150,57 +152,15 @@ function SQUADRON:SetLivery(liveryname)
self.livery=liveryname
end
--- Set home airbase.
--- Set airwing.
-- @param #SQUADRON self
-- @param Wrapper.Airbase#AIRBASE airbase Home airbase object of the squadron.
-- @param Ops.AirWing#AIRWING Airwing The airwing.
-- @return #SQUADRON self
function SQUADRON:SetHomeBase(airbase)
self.homebase=airbase
function SQUADRON:SetAirwing(Airwing)
self.airwing=Airwing
end
--- Add a group to the squadron.
-- @param #SQUADRON self
-- @param #string groupname Name of the group as defined in the mission editor.
-- @param #number n Number of groups that is added.
-- @return #SQUADRON self
function SQUADRON:AddGroup(groupname, n)
end
--- Add flight group(s) to squadron.
-- @param #SQUADRON self
-- @param Ops.FlightGroup#FLIGHTGROUP flightgroup Flight group.
-- @return #SQUADRON self
function SQUADRON:AddFlightGroup(flightgroup)
local text=string.format("Adding flight group %s to squadron", flightgroup:GetName())
self:I(self.sid..text)
-- Set squadron.
flightgroup:SetSquadron(self)
table.insert(self.flightgroups, flightgroup)
function flightgroup:OnAfterDetectedUnit(From,Event,To,Unit)
self:GetSquadron():DetectedUnit(Unit)
end
function flightgroup:OnAfterFlightAirborne(From,Event,To)
self:GetSquadron():FlightAirborne(self)
end
function flightgroup:OnAfterFlightDead(From,Event,To)
self:GetSquadron():FlightDead(self)
end
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Start & Status
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -214,41 +174,40 @@ end
function SQUADRON:onafterStart(From, Event, To)
-- Short info.
local text=string.format("Starting flight group %s.", self.groupname)
self:I(self.sid..text)
local text=string.format("Starting SQUADRON %s.", self.name)
self:I(self.lid..text)
-- Start the status monitoring.
self:__SquadronStatus(-1)
self:__Status(-1)
end
--- On after "FlightStatus" event.
--- On after "Status" event.
-- @param #SQUADRON self
-- @param Wrapper.Group#GROUP Group Flight group.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function SQUADRON:onafterSquadronStatus(From, Event, To)
function SQUADRON:onafterStatus(From, Event, To)
-- FSM state.
local fsmstate=self:GetState()
-- Check if group has detected any units.
self:_CheckFlightStatus()
self:_CheckAssetStatus()
-- Short info.
local text=string.format("Flight status %s [%d/%d]. Task=%d/%d. Waypoint=%d/%d. Detected=%d", fsmstate, #self.element, #self.element, self.taskcurrent, #self.taskqueue, self.currentwp or 0, #self.waypoints or 0, self.detectedunits:Count())
self:I(self.sid..text)
end
--- On after "FlightStatus" event.
--- Check asset status.
-- @param #SQUADRON self
function SQUADRON:_CheckFlightstatus()
function SQUADRON:_CheckAssetStatus()
for _,_flight in pairs(self.flights) do
local flight=_flight --#SQUADRON.Flight
for _,_assets in pairs(self.assets) do
local asset=_asset --#SQUADRON.Flight
flight.flightgroup:IsSpawned()
+98 -59
View File
@@ -54,14 +54,17 @@ WINGCOMMANDER = {
--- WINGCOMMANDER class version.
-- @field #string version
WINGCOMMANDER.version="0.0.2"
WINGCOMMANDER.version="0.0.3"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Add tasks.
-- TODO:
-- DONE: Add/remove spawned flightgroups to detection set.
-- TODO: Define A2A and A2G parameters. Engagedistance, etc.
-- TODO: Borderzones.
-- TODO: Improve airwing selection. Look at CAP flights near by etc.
-- TODO: Maybe it's possible to preselect the assets for the mission.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
@@ -144,6 +147,35 @@ function WINGCOMMANDER:AddAirwing(Airwing)
return self
end
--- Add mission to mission queue.
-- @param #WINGCOMMANDER self
-- @param Ops.Auftrag#AUFTRAG Mission Mission to be added.
-- @return #WINGCOMMANDER self
function WINGCOMMANDER:AddMission(Mission)
table.insert(self.missionqueue, Mission)
return self
end
--- Remove mission from queue.
-- @param #WINGCOMMANDER self
-- @param Ops.Auftrag#AUFTRAG Mission Mission to be removed.
-- @return #WINGCOMMANDER self
function WINGCOMMANDER:RemoveMission(Mission)
for i,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
if mission.auftragsnummer==Mission.auftragsnummer then
table.remove(self.missionqueue, i)
break
end
end
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Start & Status
@@ -174,7 +206,7 @@ function WINGCOMMANDER:onafterStart(From, Event, To)
end
--- On after "Sitrep" event.
--- On after "Status" event.
-- @param #WINGCOMMANDER self
-- @param Wrapper.Group#GROUP Group Flight group.
-- @param #string From From state.
@@ -193,7 +225,11 @@ function WINGCOMMANDER:onafterStatus(From, Event, To)
for _,_contact in pairs(self.ContactsLost) do
local contact=_contact --#WINGCOMMANDER.Contact
if contact.mission and contact.mission.airwing then
if contact.mission then
local text=string.format("Lost contact to target! %s mission %s will be cancelled.", contact.mission.type:upper(), contact.mission.name)
MESSAGE:New(text, 120, "WINGCOMMANDER"):ToAll()
self:I(self.lid..text)
-- Cancel this mission.
contact.mission:Cancel()
@@ -248,7 +284,7 @@ function WINGCOMMANDER:onafterStatus(From, Event, To)
-- Add mission to queue.
if mission then
mission.nassets=1
table.insert(self.missionqueue, mission)
self:AddMission(mission)
end
end
@@ -296,48 +332,10 @@ function WINGCOMMANDER:CheckMissionQueue()
-- PLANNNED Mission
---
-- Table of airwings that can do the mission.
local airwings={}
-- Loop over all airwings.
for _,_airwing in pairs(self.airwings) do
local airwing=_airwing --Ops.AirWing#AIRWING
local airwing=self:GetAirwingForMission(mission)
-- Check if airwing can do this mission.
local can,assets=airwing:CanMission(mission.type, mission.nassets)
-- Can it?
if can then
-- Get coordinate of the target.
local coord=mission:GetTargetCoordinate()
if coord then
-- Distance from airwing to target.
local dist=coord:Get2DDistance(airwing:GetCoordinate())
-- Add airwing to table of airwings that can.
table.insert(airwings, {airwing=airwing, dist=dist, targetcoord=coord})
end
end
end
if airwing then
-- Can anyone?
if #airwings>0 then
-- Sort table wrt distace
local function sortdist(a,b)
return a.dist<b.dist
end
table.sort(airwings, sortdist)
-- This is the closest airwing to the target.
local airwing=airwings[1].airwing --Ops.AirWing#AIRWING
-- Add mission to airwing.
self:MissionAssign(airwing, mission)
@@ -356,6 +354,59 @@ function WINGCOMMANDER:CheckMissionQueue()
end
--- Check all airwings if they are able to do a specific mission type at a certain location with a given number of assets.
-- @param #WINGCOMMANDER self
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
-- @return Ops.AirWing#AIRWING The airwing best for this mission.
function WINGCOMMANDER:GetAirwingForMission(Mission)
-- Table of airwings that can do the mission.
local airwings={}
-- Loop over all airwings.
for _,_airwing in pairs(self.airwings) do
local airwing=_airwing --Ops.AirWing#AIRWING
-- Check if airwing can do this mission.
local can,assets=airwing:CanMission(Mission.type, Mission.nassets)
-- Can it?
if can then
-- Get coordinate of the target.
local coord=Mission:GetTargetCoordinate()
if coord then
-- Distance from airwing to target.
local dist=coord:Get2DDistance(airwing:GetCoordinate())
-- Add airwing to table of airwings that can.
table.insert(airwings, {airwing=airwing, dist=dist, targetcoord=coord})
end
end
end
-- Can anyone?
if #airwings>0 then
-- Sort table wrt distace
local function sortdist(a,b)
return a.dist<b.dist
end
table.sort(airwings, sortdist)
-- This is the closest airwing to the target.
local airwing=airwings[1].airwing --Ops.AirWing#AIRWING
return airwing
end
return nil
end
--- Check resources.
-- @param #WINGCOMMANDER self
@@ -380,16 +431,4 @@ function WINGCOMMANDER:CheckResources()
end
return capabilities
end
--- Check all airwings if they are able to do a specific mission type at a certain location with a given number of assets.
-- @param #WINGCOMMANDER self
-- @return Ops.AirWing#AIRWING The airwing object best for this mission.
function WINGCOMMANDER:GetAirwingForMission(MissionType, Coordinate, Nassets)
--TODO: run over all airwings. sort by distance and available assets.
end
end