OPS Generalization

This commit is contained in:
Frank 2021-08-12 00:17:55 +02:00
parent 88e59a2739
commit 93f4b345c5
9 changed files with 107 additions and 2070 deletions

View File

@ -3996,7 +3996,7 @@ function WAREHOUSE:onafterAddAsset(From, Event, To, group, ngroups, forceattribu
local opsgroup=_DATABASE:GetOpsGroup(group:GetName()) local opsgroup=_DATABASE:GetOpsGroup(group:GetName())
if opsgroup then if opsgroup then
opsgroup:Despawn(0) opsgroup:Despawn(0, true)
opsgroup:__Stop(-0.01) opsgroup:__Stop(-0.01)
else else
-- Setting parameter to false, i.e. creating NO dead or remove unit event, seems to not confuse the dispatcher logic. -- Setting parameter to false, i.e. creating NO dead or remove unit event, seems to not confuse the dispatcher logic.

File diff suppressed because it is too large Load Diff

View File

@ -443,7 +443,7 @@ AUFTRAG.TargetType={
-- @field Core.Point#COORDINATE wpegresscoordinate Egress waypoint coordinate. -- @field Core.Point#COORDINATE wpegresscoordinate Egress waypoint coordinate.
-- @field Ops.OpsGroup#OPSGROUP.Task waypointtask Waypoint task. -- @field Ops.OpsGroup#OPSGROUP.Task waypointtask Waypoint task.
-- @field #string status Group mission status. -- @field #string status Group mission status.
-- @field Ops.AirWing#AIRWING.SquadronAsset asset The squadron asset. -- @field Functional.Warehouse#WAREHOUSE.Assetitem asset The warehouse asset.
--- AUFTRAG class version. --- AUFTRAG class version.
@ -2689,7 +2689,7 @@ end
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The asset. -- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The asset.
function AUFTRAG:onafterAssetDead(From, Event, To, Asset) function AUFTRAG:onafterAssetDead(From, Event, To, Asset)
-- Number of groups alive. -- Number of groups alive.
@ -3147,7 +3147,7 @@ end
--- Add asset to mission. --- Add asset to mission.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The asset to be added to the mission. -- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The asset to be added to the mission.
-- @return #AUFTRAG self -- @return #AUFTRAG self
function AUFTRAG:AddAsset(Asset) function AUFTRAG:AddAsset(Asset)
@ -3160,12 +3160,12 @@ end
--- Delete asset from mission. --- Delete asset from mission.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The asset to be removed. -- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The asset to be removed.
-- @return #AUFTRAG self -- @return #AUFTRAG self
function AUFTRAG:DelAsset(Asset) function AUFTRAG:DelAsset(Asset)
for i,_asset in pairs(self.assets or {}) do for i,_asset in pairs(self.assets or {}) do
local asset=_asset --Ops.AirWing#AIRWING.SquadronAsset local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
if asset.uid==Asset.uid then if asset.uid==Asset.uid then
self:T(self.lid..string.format("Removing asset \"%s\" from mission", tostring(asset.spawngroupname))) self:T(self.lid..string.format("Removing asset \"%s\" from mission", tostring(asset.spawngroupname)))
@ -3181,11 +3181,11 @@ end
--- Get asset by its spawn group name. --- Get asset by its spawn group name.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @param #string Name Asset spawn group name. -- @param #string Name Asset spawn group name.
-- @return Ops.AirWing#AIRWING.SquadronAsset -- @return Functional.Warehouse#WAREHOUSE.Assetitem Asset.
function AUFTRAG:GetAssetByName(Name) function AUFTRAG:GetAssetByName(Name)
for i,_asset in pairs(self.assets or {}) do for i,_asset in pairs(self.assets or {}) do
local asset=_asset --Ops.AirWing#AIRWING.SquadronAsset local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
if asset.spawngroupname==Name then if asset.spawngroupname==Name then
return asset return asset
@ -3196,9 +3196,9 @@ function AUFTRAG:GetAssetByName(Name)
return nil return nil
end end
--- Count alive ops groups assigned for this mission. --- Count alive OPS groups assigned for this mission.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @return #number Number of alive flight groups. -- @return #number Number of alive OPS groups.
function AUFTRAG:CountOpsGroups() function AUFTRAG:CountOpsGroups()
local N=0 local N=0
for _,_groupdata in pairs(self.groupdata) do for _,_groupdata in pairs(self.groupdata) do

View File

@ -86,7 +86,7 @@ end
-- @return #BRIGADE self -- @return #BRIGADE self
function BRIGADE:AddPlatoon(Platoon) function BRIGADE:AddPlatoon(Platoon)
-- Add squadron to airwing. -- Add platoon to brigade.
table.insert(self.cohorts, Platoon) table.insert(self.cohorts, Platoon)
-- Add assets to squadron. -- Add assets to squadron.

View File

@ -119,9 +119,6 @@ function COHORT:New(TemplateGroupName, Ngroups, CohortName)
self:SetMissionRange() self:SetMissionRange()
self:SetSkill(AI.Skill.GOOD) self:SetSkill(AI.Skill.GOOD)
-- Everyone can ORBIT.
--self:AddMissionCapability(AUFTRAG.Type.ORBIT)
-- Generalized attribute. -- Generalized attribute.
self.attribute=self.templategroup:GetAttribute() self.attribute=self.templategroup:GetAttribute()
@ -718,9 +715,9 @@ function COHORT:CanMission(Mission)
return false return false
end end
-- Check mission type. WARNING: This assumes that all assets of the squad can do the same mission types! -- Check mission type. WARNING: This assumes that all assets of the cohort can do the same mission types!
if not self:CheckMissionType(Mission.type, self:GetMissionTypes()) then if not self:CheckMissionType(Mission.type, self:GetMissionTypes()) then
self:T(self.lid..string.format("INFO: Squad cannot do mission type %s (%s, %s)", Mission.type, Mission.name, Mission:GetTargetName())) self:T(self.lid..string.format("INFO: Cohort cannot do mission type %s (%s, %s)", Mission.type, Mission.name, Mission:GetTargetName()))
return false return false
end end
@ -742,9 +739,9 @@ function COHORT:CanMission(Mission)
-- Max engage range. -- Max engage range.
local engagerange=Mission.engageRange and math.max(self.engageRange, Mission.engageRange) or self.engageRange local engagerange=Mission.engageRange and math.max(self.engageRange, Mission.engageRange) or self.engageRange
-- Set range is valid. Mission engage distance can overrule the squad engage range. -- Set range is valid. Mission engage distance can overrule the cohort engage range.
if TargetDistance>engagerange then if TargetDistance>engagerange then
self:I(self.lid..string.format("INFO: Squad is not in range. Target dist=%d > %d NM max mission Range", UTILS.MetersToNM(TargetDistance), UTILS.MetersToNM(engagerange))) self:I(self.lid..string.format("INFO: Cohort is not in range. Target dist=%d > %d NM max mission Range", UTILS.MetersToNM(TargetDistance), UTILS.MetersToNM(engagerange)))
return false return false
end end
@ -974,7 +971,7 @@ end
--- Check if the platoon attribute matches the given attribute(s). --- Check if the platoon attribute matches the given attribute(s).
-- @param #COHORT self -- @param #COHORT self
-- @param #table Attributes The requested attributes. See `WAREHOUSE.Attribute` enum. Can also be passed as a single attribute `#string`. -- @param #table Attributes The requested attributes. See `WAREHOUSE.Attribute` enum. Can also be passed as a single attribute `#string`.
-- @return #boolean If true, the squad has the requested attribute. -- @return #boolean If true, the cohort has the requested attribute.
function COHORT:CheckAttribute(Attributes) function COHORT:CheckAttribute(Attributes)
if type(Attributes)~="table" then if type(Attributes)~="table" then

View File

@ -44,8 +44,6 @@
-- @field #boolean fuelcritical Fuel critical switch. -- @field #boolean fuelcritical Fuel critical switch.
-- @field #number fuelcriticalthresh Critical fuel threshold in percent. -- @field #number fuelcriticalthresh Critical fuel threshold in percent.
-- @field #boolean fuelcriticalrtb RTB on critical fuel switch. -- @field #boolean fuelcriticalrtb RTB on critical fuel switch.
-- @field Ops.Squadron#SQUADRON squadron The squadron of this flight group.
-- @field Ops.AirWing#AIRWING airwing The airwing the flight group belongs to.
-- @field Ops.FlightControl#FLIGHTCONTROL flightcontrol The flightcontrol handling this group. -- @field Ops.FlightControl#FLIGHTCONTROL flightcontrol The flightcontrol handling this group.
-- @field Ops.Airboss#AIRBOSS airboss The airboss handling this group. -- @field Ops.Airboss#AIRBOSS airboss The airboss handling this group.
-- @field Core.UserFlag#USERFLAG flaghold Flag for holding. -- @field Core.UserFlag#USERFLAG flaghold Flag for holding.
@ -136,7 +134,6 @@ FLIGHTGROUP = {
fuelcriticalrtb = false, fuelcriticalrtb = false,
outofAAMrtb = false, outofAAMrtb = false,
outofAGMrtb = false, outofAGMrtb = false,
squadron = nil,
flightcontrol = nil, flightcontrol = nil,
flaghold = nil, flaghold = nil,
Tholding = nil, Tholding = nil,
@ -336,21 +333,11 @@ function FLIGHTGROUP:AddTaskEnrouteEngageTargetsInZone(ZoneRadius, TargetTypes,
self:AddTaskEnroute(Task) self:AddTaskEnroute(Task)
end end
--- Set AIRWING the flight group belongs to.
-- @param #FLIGHTGROUP self
-- @param Ops.AirWing#AIRWING airwing The AIRWING object.
-- @return #FLIGHTGROUP self
function FLIGHTGROUP:SetAirwing(airwing)
self:T(self.lid..string.format("Add flight to AIRWING %s", airwing.alias))
self.airwing=airwing
return self
end
--- Get airwing the flight group belongs to. --- Get airwing the flight group belongs to.
-- @param #FLIGHTGROUP self -- @param #FLIGHTGROUP self
-- @return Ops.AirWing#AIRWING The AIRWING object. -- @return Ops.AirWing#AIRWING The AIRWING object.
function FLIGHTGROUP:GetAirWing() function FLIGHTGROUP:GetAirWing()
return self.airwing return self.legion
end end
--- Set if aircraft is VTOL capable. Unfortunately, there is no DCS way to determine this via scripting. --- Set if aircraft is VTOL capable. Unfortunately, there is no DCS way to determine this via scripting.
@ -1892,10 +1879,14 @@ function FLIGHTGROUP:onafterArrived(From, Event, To)
self.flightcontrol:SetFlightStatus(self, FLIGHTCONTROL.FlightStatus.ARRIVED) self.flightcontrol:SetFlightStatus(self, FLIGHTCONTROL.FlightStatus.ARRIVED)
end end
local airwing=self:GetAirWing()
-- Check what to do. -- Check what to do.
if self.airwing then if airwing then
-- Add the asset back to the airwing. -- Add the asset back to the airwing.
self.airwing:AddAsset(self.group, 1) airwing:AddAsset(self.group, 1)
elseif self.isLandingAtAirbase then elseif self.isLandingAtAirbase then
local Template=UTILS.DeepCopy(self.template) --DCS#Template local Template=UTILS.DeepCopy(self.template) --DCS#Template
@ -1991,18 +1982,6 @@ function FLIGHTGROUP:onafterDead(From, Event, To)
self.flightcontrol=nil self.flightcontrol=nil
end end
if self.Ndestroyed==#self.elements then
if self.squadron then
-- All elements were destroyed ==> Asset group is gone.
self.squadron:DelGroup(self.groupname)
end
else
if self.airwing then
-- Not all assets were destroyed (despawn) ==> Add asset back to airwing.
--self.airwing:AddAsset(self.group, 1)
end
end
-- Call OPSGROUP function. -- Call OPSGROUP function.
self:GetParent(self).onafterDead(self, From, Event, To) self:GetParent(self).onafterDead(self, From, Event, To)
@ -2913,10 +2892,12 @@ function FLIGHTGROUP:onafterFuelLow(From, Event, To)
-- Back to destination or home. -- Back to destination or home.
local airbase=self.destbase or self.homebase local airbase=self.destbase or self.homebase
if self.airwing then local airwing=self:GetAirWing()
if airwing then
-- Get closest tanker from airwing that can refuel this flight. -- Get closest tanker from airwing that can refuel this flight.
local tanker=self.airwing:GetTankerForFlight(self) local tanker=airwing:GetTankerForFlight(self)
if tanker and self.fuellowrefuel then if tanker and self.fuellowrefuel then

View File

@ -616,7 +616,7 @@ function LEGION:onafterOpsOnMission(From, Event, To, OpsGroup, Mission)
end end
--- On after "NewAsset" event. Asset is added to the given squadron (asset assignment). --- On after "NewAsset" event. Asset is added to the given cohort (asset assignment).
-- @param #LEGION self -- @param #LEGION self
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
@ -632,26 +632,25 @@ function LEGION:onafterNewAsset(From, Event, To, asset, assignment)
local text=string.format("New asset %s with assignment %s and request assignment %s", asset.spawngroupname, tostring(asset.assignment), tostring(assignment)) local text=string.format("New asset %s with assignment %s and request assignment %s", asset.spawngroupname, tostring(asset.assignment), tostring(assignment))
self:T3(self.lid..text) self:T3(self.lid..text)
-- Get squadron. -- Get cohort.
--local squad=self:GetSquadron(asset.assignment) local cohort=self:_GetCohort(asset.assignment)
local squad=self:_GetCohort(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. -- 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 cohort then
if asset.assignment==assignment then if asset.assignment==assignment then
local nunits=#asset.template.units local nunits=#asset.template.units
-- Debug text. -- Debug text.
local text=string.format("Adding asset to squadron %s: assignment=%s, type=%s, attribute=%s, nunits=%d %s", squad.name, assignment, asset.unittype, asset.attribute, nunits, tostring(squad.ngrouping)) local text=string.format("Adding asset to squadron %s: assignment=%s, type=%s, attribute=%s, nunits=%d %s", cohort.name, assignment, asset.unittype, asset.attribute, nunits, tostring(cohort.ngrouping))
self:T(self.lid..text) self:T(self.lid..text)
-- Adjust number of elements in the group. -- Adjust number of elements in the group.
if squad.ngrouping then if cohort.ngrouping then
local template=asset.template local template=asset.template
local N=math.max(#template.units, squad.ngrouping) local N=math.max(#template.units, cohort.ngrouping)
-- Handle units. -- Handle units.
for i=1,N do for i=1,N do
@ -665,36 +664,36 @@ function LEGION:onafterNewAsset(From, Event, To, asset, assignment)
end end
-- Remove units if original template contains more than in grouping. -- Remove units if original template contains more than in grouping.
if squad.ngrouping<nunits and i>nunits then if cohort.ngrouping<nunits and i>nunits then
unit=nil unit=nil
end end
end end
asset.nunits=squad.ngrouping asset.nunits=cohort.ngrouping
end end
-- Set takeoff type. -- Set takeoff type.
asset.takeoffType=squad.takeoffType asset.takeoffType=cohort.takeoffType
-- Set parking IDs. -- Set parking IDs.
asset.parkingIDs=squad.parkingIDs asset.parkingIDs=cohort.parkingIDs
-- Create callsign and modex (needs to be after grouping). -- Create callsign and modex (needs to be after grouping).
squad:GetCallsign(asset) cohort:GetCallsign(asset)
squad:GetModex(asset) cohort:GetModex(asset)
-- Set spawn group name. This has to include "AID-" for warehouse. -- Set spawn group name. This has to include "AID-" for warehouse.
asset.spawngroupname=string.format("%s_AID-%d", squad.name, asset.uid) asset.spawngroupname=string.format("%s_AID-%d", cohort.name, asset.uid)
-- Add asset to squadron. -- Add asset to squadron.
squad:AddAsset(asset) cohort:AddAsset(asset)
-- TODO -- TODO
--asset.terminalType=AIRBASE.TerminalType.OpenBig --asset.terminalType=AIRBASE.TerminalType.OpenBig
else else
--env.info("FF squad asset returned") --env.info("FF squad asset returned")
self:AssetReturned(squad, asset) self:AssetReturned(cohort, asset)
end end
@ -753,10 +752,10 @@ function LEGION:onafterAssetSpawned(From, Event, To, group, asset, request)
self:GetParent(self, LEGION).onafterAssetSpawned(self, From, Event, To, group, asset, request) self:GetParent(self, LEGION).onafterAssetSpawned(self, From, Event, To, group, asset, request)
-- Get the SQUADRON of the asset. -- Get the SQUADRON of the asset.
local squadron=self:_GetCohortOfAsset(asset) local cohort=self:_GetCohortOfAsset(asset)
-- Check if we have a squadron or if this was some other request. -- Check if we have a squadron or if this was some other request.
if squadron then if cohort then
-- Create a flight group. -- Create a flight group.
local flightgroup=self:_CreateFlightGroup(asset) local flightgroup=self:_CreateFlightGroup(asset)
@ -779,7 +778,7 @@ function LEGION:onafterAssetSpawned(From, Event, To, group, asset, request)
--- ---
-- Get TACAN channel. -- Get TACAN channel.
local Tacan=squadron:FetchTacan() local Tacan=cohort:FetchTacan()
if Tacan then if Tacan then
asset.tacan=Tacan asset.tacan=Tacan
--flightgroup:SetDefaultTACAN(Tacan,Morse,UnitName,Band,OffSwitch) --flightgroup:SetDefaultTACAN(Tacan,Morse,UnitName,Band,OffSwitch)
@ -787,17 +786,17 @@ function LEGION:onafterAssetSpawned(From, Event, To, group, asset, request)
end end
-- Set radio frequency and modulation -- Set radio frequency and modulation
local radioFreq, radioModu=squadron:GetRadio() local radioFreq, radioModu=cohort:GetRadio()
if radioFreq then if radioFreq then
flightgroup:SwitchRadio(radioFreq, radioModu) flightgroup:SwitchRadio(radioFreq, radioModu)
end end
if squadron.fuellow then if cohort.fuellow then
flightgroup:SetFuelLowThreshold(squadron.fuellow) flightgroup:SetFuelLowThreshold(cohort.fuellow)
end end
if squadron.fuellowRefuel then if cohort.fuellowRefuel then
flightgroup:SetFuelLowRefuel(squadron.fuellowRefuel) flightgroup:SetFuelLowRefuel(cohort.fuellowRefuel)
end end
--- ---
@ -858,7 +857,7 @@ function LEGION:onafterAssetDead(From, Event, To, asset, request)
-- Remove asset from squadron same -- Remove asset from squadron same
end end
--- On after "Destroyed" event. Remove assets from squadrons. Stop squadrons. Remove airwing from wingcommander. --- On after "Destroyed" event. Remove assets from cohorts. Stop squadrons.
-- @param #LEGION self -- @param #LEGION self
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
@ -874,11 +873,11 @@ function LEGION:onafterDestroyed(From, Event, To)
mission:Cancel() mission:Cancel()
end end
-- Remove all squadron assets. -- Remove all cohort assets.
for _,_squadron in pairs(self.cohorts) do for _,_cohort in pairs(self.cohorts) do
local squadron=_squadron --Ops.Squadron#SQUADRON local cohort=_cohort --Ops.Cohort#COHORT
-- Stop Squadron. This also removes all assets. -- Stop Cohort. This also removes all assets.
squadron:Stop() cohort:Stop()
end end
-- Call parent warehouse function first. -- Call parent warehouse function first.
@ -964,7 +963,7 @@ function LEGION:_CreateFlightGroup(asset)
flightgroup:_SetLegion(self) flightgroup:_SetLegion(self)
-- Set squadron. -- Set squadron.
flightgroup.squadron=self:_GetCohortOfAsset(asset) flightgroup.cohort=self:_GetCohortOfAsset(asset)
-- Set home base. -- Set home base.
flightgroup.homebase=self.airbase flightgroup.homebase=self.airbase

View File

@ -1329,7 +1329,9 @@ function OPSGROUP:DespawnElement(Element, Delay, NoEventRemoveUnit)
return self return self
end end
--- Despawn the group. The whole group is despawned and (optionally) a "Remove Unit" event is generated for all current units of the group. --- Despawn the group. The whole group is despawned and a "`Remove Unit`" event is generated for all current units of the group.
-- If no `Remove Unit` event should be generated, the second optional parameter needs to be set to `true`.
-- If this group belongs to an AIRWING, BRIGADE or FLEET, it will be added to the warehouse stock if the `NoEventRemoveUnit` parameter is `false` or `nil`.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #number Delay Delay in seconds before the group will be despawned. Default immediately. -- @param #number Delay Delay in seconds before the group will be despawned. Default immediately.
-- @param #boolean NoEventRemoveUnit If `true`, **no** event "Remove Unit" is generated. -- @param #boolean NoEventRemoveUnit If `true`, **no** event "Remove Unit" is generated.
@ -1340,14 +1342,16 @@ function OPSGROUP:Despawn(Delay, NoEventRemoveUnit)
self.scheduleIDDespawn=self:ScheduleOnce(Delay, OPSGROUP.Despawn, self, 0, NoEventRemoveUnit) self.scheduleIDDespawn=self:ScheduleOnce(Delay, OPSGROUP.Despawn, self, 0, NoEventRemoveUnit)
else else
-- Debug info.
self:I(self.lid..string.format("Despawning Group!"))
if self.legion and not NoEventRemoveUnit then if self.legion and not NoEventRemoveUnit then
-- Add asset back in 10 seconds. -- Add asset back in 10 seconds.
self:I(self.lid..string.format("Despawning Group by adding asset to LEGION!"))
self.legion:AddAsset(self.group, 1) self.legion:AddAsset(self.group, 1)
return
end end
-- Debug info.
self:I(self.lid..string.format("Despawning Group!"))
-- DCS group obejct. -- DCS group obejct.
local DCSGroup=self:GetDCSGroup() local DCSGroup=self:GetDCSGroup()
@ -3754,10 +3758,10 @@ function OPSGROUP:onafterMissionDone(From, Event, To, Mission)
-- Switch to default. -- Switch to default.
self:_SwitchTACAN() self:_SwitchTACAN()
-- Return Squadron TACAN channel. -- Return Cohort's TACAN channel.
local squadron=self.squadron --Ops.Squadron#SQUADRON local cohort=self.cohort --Ops.Cohort#COHORT
if squadron then if cohort then
squadron:ReturnTacan(Mission.tacan.Channel) cohort:ReturnTacan(Mission.tacan.Channel)
end end
-- Set asset TACAN to nil. -- Set asset TACAN to nil.
@ -5175,6 +5179,18 @@ function OPSGROUP:onafterDead(From, Event, To)
-- No current cargo transport. -- No current cargo transport.
self.cargoTransport=nil self.cargoTransport=nil
if self.Ndestroyed==#self.elements then
if self.cohort then
-- All elements were destroyed ==> Asset group is gone.
self.cohort:DelGroup(self.groupname)
end
else
if self.airwing then
-- Not all assets were destroyed (despawn) ==> Add asset back to airwing.
--self.airwing:AddAsset(self.group, 1)
end
end
-- Stop in a sec. -- Stop in a sec.
--self:__Stop(-5) --self:__Stop(-5)
end end

View File

@ -36,7 +36,6 @@
-- @field #number modexcounter Counter to incease modex number for assets. -- @field #number modexcounter Counter to incease modex number for assets.
-- @field #string callsignName Callsign name. -- @field #string callsignName Callsign name.
-- @field #number callsigncounter Counter to increase callsign names for new assets. -- @field #number callsigncounter Counter to increase callsign names for new assets.
-- @field Ops.AirWing#AIRWING airwing The AIRWING object the squadron belongs to.
-- @field #number Ngroups Number of asset flight groups this squadron has. -- @field #number Ngroups Number of asset flight groups this squadron has.
-- @field #number engageRange Mission range in meters. -- @field #number engageRange Mission range in meters.
-- @field #string attribute Generalized attribute of the squadron template group. -- @field #string attribute Generalized attribute of the squadron template group.
@ -47,7 +46,7 @@
-- @field #number radioModu Radio modulation the squad uses. -- @field #number radioModu Radio modulation the squad uses.
-- @field #number takeoffType Take of type. -- @field #number takeoffType Take of type.
-- @field #table parkingIDs Parking IDs for this squadron. -- @field #table parkingIDs Parking IDs for this squadron.
-- @extends Core.Fsm#FSM -- @extends Ops.Cohort#COHORT
--- *It is unbelievable what a squadron of twelve aircraft did to tip the balance.* -- Adolf Galland --- *It is unbelievable what a squadron of twelve aircraft did to tip the balance.* -- Adolf Galland
-- --
@ -65,31 +64,17 @@
SQUADRON = { SQUADRON = {
ClassName = "SQUADRON", ClassName = "SQUADRON",
verbose = 0, verbose = 0,
lid = nil,
name = nil,
templatename = nil,
aircrafttype = nil,
assets = {},
missiontypes = {},
repairtime = 0,
maintenancetime= 0,
livery = nil,
skill = nil,
modex = nil, modex = nil,
modexcounter = 0, modexcounter = 0,
callsignName = nil, callsignName = nil,
callsigncounter= 11, callsigncounter= 11,
airwing = nil,
Ngroups = nil,
engageRange = nil,
tankerSystem = nil, tankerSystem = nil,
refuelSystem = nil, refuelSystem = nil,
tacanChannel = {},
} }
--- SQUADRON class version. --- SQUADRON class version.
-- @field #string version -- @field #string version
SQUADRON.version="0.7.0" SQUADRON.version="0.8.0"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -113,37 +98,11 @@ SQUADRON.version="0.7.0"
function SQUADRON:New(TemplateGroupName, Ngroups, SquadronName) function SQUADRON:New(TemplateGroupName, Ngroups, SquadronName)
-- Inherit everything from FSM class. -- Inherit everything from FSM class.
local self=BASE:Inherit(self, FSM:New()) -- #SQUADRON local self=BASE:Inherit(self, COHORT:New(TemplateGroupName, Ngroups, SquadronName)) -- #SQUADRON
-- Name of the template group.
self.templatename=TemplateGroupName
-- Squadron name.
self.name=tostring(SquadronName or TemplateGroupName)
-- Set some string id for output to DCS.log file.
self.lid=string.format("SQUADRON %s | ", self.name)
-- Template group.
self.templategroup=GROUP:FindByName(self.templatename)
-- Check if template group exists.
if not self.templategroup then
self:E(self.lid..string.format("ERROR: Template group %s does not exist!", tostring(self.templatename)))
return nil
end
-- Defaults.
self.Ngroups=Ngroups or 3
self:SetMissionRange()
self:SetSkill(AI.Skill.GOOD)
-- Everyone can ORBIT. -- Everyone can ORBIT.
self:AddMissionCapability(AUFTRAG.Type.ORBIT) self:AddMissionCapability(AUFTRAG.Type.ORBIT)
-- Generalized attribute.
self.attribute=self.templategroup:GetAttribute()
-- Aircraft type. -- Aircraft type.
self.aircrafttype=self.templategroup:GetTypeName() self.aircrafttype=self.templategroup:GetTypeName()
@ -151,58 +110,11 @@ function SQUADRON:New(TemplateGroupName, Ngroups, SquadronName)
self.refuelSystem=select(2, self.templategroup:GetUnit(1):IsRefuelable()) self.refuelSystem=select(2, self.templategroup:GetUnit(1):IsRefuelable())
self.tankerSystem=select(2, self.templategroup:GetUnit(1):IsTanker()) self.tankerSystem=select(2, self.templategroup:GetUnit(1):IsTanker())
-- Start State.
self:SetStartState("Stopped")
-- Add FSM transitions.
-- From State --> Event --> To State
self:AddTransition("Stopped", "Start", "OnDuty") -- Start FSM.
self:AddTransition("*", "Status", "*") -- Status update.
self:AddTransition("OnDuty", "Pause", "Paused") -- Pause squadron.
self:AddTransition("Paused", "Unpause", "OnDuty") -- Unpause squadron.
self:AddTransition("*", "Stop", "Stopped") -- Stop squadron.
------------------------ ------------------------
--- Pseudo Functions --- --- Pseudo Functions ---
------------------------ ------------------------
--- Triggers the FSM event "Start". Starts the SQUADRON. Initializes parameters and starts event handlers. -- See COHORT class
-- @function [parent=#SQUADRON] Start
-- @param #SQUADRON self
--- Triggers the FSM event "Start" after a delay. Starts the SQUADRON. Initializes parameters and starts event handlers.
-- @function [parent=#SQUADRON] __Start
-- @param #SQUADRON self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "Stop". Stops the SQUADRON and all its event handlers.
-- @param #SQUADRON self
--- Triggers the FSM event "Stop" after a delay. Stops the SQUADRON and all its event handlers.
-- @function [parent=#SQUADRON] __Stop
-- @param #SQUADRON self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "Status".
-- @function [parent=#SQUADRON] Status
-- @param #SQUADRON self
--- Triggers the FSM event "Status" after a delay.
-- @function [parent=#SQUADRON] __Status
-- @param #SQUADRON self
-- @param #number delay Delay in seconds.
-- Debug trace.
if false then
BASE:TraceOnOff(true)
BASE:TraceClass(self.ClassName)
BASE:TraceLevel(1)
end
return self return self
end end
@ -211,68 +123,6 @@ end
-- User functions -- User functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Set livery painted on all squadron aircraft.
-- Note that the livery name in general is different from the name shown in the mission editor.
--
-- Valid names are the names of the **livery directories**. Check out the folder in your DCS installation for:
--
-- * Full modules: `DCS World OpenBeta\CoreMods\aircraft\<Aircraft Type>\Liveries\<Aircraft Type>\<Livery Name>`
-- * AI units: `DCS World OpenBeta\Bazar\Liveries\<Aircraft Type>\<Livery Name>`
--
-- The folder name `<Livery Name>` is the string you want.
--
-- Or personal liveries you have installed somewhere in your saved games folder.
--
-- @param #SQUADRON self
-- @param #string LiveryName Name of the livery.
-- @return #SQUADRON self
function SQUADRON:SetLivery(LiveryName)
self.livery=LiveryName
return self
end
--- Set skill level of all squadron team members.
-- @param #SQUADRON self
-- @param #string Skill Skill of all flights.
-- @usage mysquadron:SetSkill(AI.Skill.EXCELLENT)
-- @return #SQUADRON self
function SQUADRON:SetSkill(Skill)
self.skill=Skill
return self
end
--- Set verbosity level.
-- @param #SQUADRON self
-- @param #number VerbosityLevel Level of output (higher=more). Default 0.
-- @return #SQUADRON self
function SQUADRON:SetVerbosity(VerbosityLevel)
self.verbose=VerbosityLevel or 0
return self
end
--- Set turnover and repair time. If an asset returns from a mission to the airwing, it will need some time until the asset is available for further missions.
-- @param #SQUADRON self
-- @param #number MaintenanceTime Time in minutes it takes until a flight is combat ready again. Default is 0 min.
-- @param #number RepairTime Time in minutes it takes to repair a flight for each life point taken. Default is 0 min.
-- @return #SQUADRON self
function SQUADRON:SetTurnoverTime(MaintenanceTime, RepairTime)
self.maintenancetime=MaintenanceTime and MaintenanceTime*60 or 0
self.repairtime=RepairTime and RepairTime*60 or 0
return self
end
--- Set radio frequency and modulation the squad uses.
-- @param #SQUADRON self
-- @param #number Frequency Radio frequency in MHz. Default 251 MHz.
-- @param #number Modulation Radio modulation. Default 0=AM.
-- @usage mysquadron:SetSkill(AI.Skill.EXCELLENT)
-- @return #SQUADRON self
function SQUADRON:SetRadio(Frequency, Modulation)
self.radioFreq=Frequency or 251
self.radioModu=Modulation or radio.modulation.AM
return self
end
--- Set number of units in groups. --- Set number of units in groups.
-- @param #SQUADRON self -- @param #SQUADRON self
-- @param #number nunits Number of units. Must be >=1 and <=4. Default 2. -- @param #number nunits Number of units. Must be >=1 and <=4. Default 2.
@ -330,115 +180,6 @@ function SQUADRON:SetTakeoffHot()
return self return self
end end
--- Set mission types this squadron is able to perform.
-- @param #SQUADRON self
-- @param #table MissionTypes Table of mission types. Can also be passed as a #string if only one type.
-- @param #number Performance Performance describing how good this mission can be performed. Higher is better. Default 50. Max 100.
-- @return #SQUADRON self
function SQUADRON:AddMissionCapability(MissionTypes, Performance)
-- Ensure Missiontypes is a table.
if MissionTypes and type(MissionTypes)~="table" then
MissionTypes={MissionTypes}
end
-- Set table.
self.missiontypes=self.missiontypes or {}
for _,missiontype in pairs(MissionTypes) do
-- Check not to add the same twice.
if self:CheckMissionCapability(missiontype, self.missiontypes) then
self:E(self.lid.."WARNING: Mission capability already present! No need to add it twice.")
-- TODO: update performance.
else
local capability={} --Ops.Auftrag#AUFTRAG.Capability
capability.MissionType=missiontype
capability.Performance=Performance or 50
table.insert(self.missiontypes, capability)
end
end
-- Debug info.
self:T2(self.missiontypes)
return self
end
--- Get mission types this squadron is able to perform.
-- @param #SQUADRON self
-- @return #table Table of mission types. Could be empty {}.
function SQUADRON:GetMissionTypes()
local missiontypes={}
for _,Capability in pairs(self.missiontypes) do
local capability=Capability --Ops.Auftrag#AUFTRAG.Capability
table.insert(missiontypes, capability.MissionType)
end
return missiontypes
end
--- Get mission capabilities of this squadron.
-- @param #SQUADRON self
-- @return #table Table of mission capabilities.
function SQUADRON:GetMissionCapabilities()
return self.missiontypes
end
--- Get mission performance for a given type of misson.
-- @param #SQUADRON self
-- @param #string MissionType Type of mission.
-- @return #number Performance or -1.
function SQUADRON:GetMissionPeformance(MissionType)
for _,Capability in pairs(self.missiontypes) do
local capability=Capability --Ops.Auftrag#AUFTRAG.Capability
if capability.MissionType==MissionType then
return capability.Performance
end
end
return -1
end
--- Set max mission range. Only missions in a circle of this radius around the squadron airbase are executed.
-- @param #SQUADRON self
-- @param #number Range Range in NM. Default 100 NM.
-- @return #SQUADRON self
function SQUADRON:SetMissionRange(Range)
self.engageRange=UTILS.NMToMeters(Range or 100)
return self
end
--- Set call sign.
-- @param #SQUADRON self
-- @param #number Callsign Callsign from CALLSIGN.Aircraft, e.g. "Chevy" for CALLSIGN.Aircraft.CHEVY.
-- @param #number Index Callsign index, Chevy-**1**.
-- @return #SQUADRON self
function SQUADRON:SetCallsign(Callsign, Index)
self.callsignName=Callsign
self.callsignIndex=Index
return self
end
--- Set modex.
-- @param #SQUADRON self
-- @param #number Modex A number like 100.
-- @param #string Prefix A prefix string, which is put before the `Modex` number.
-- @param #string Suffix A suffix string, which is put after the `Modex` number.
-- @return #SQUADRON self
function SQUADRON:SetModex(Modex, Prefix, Suffix)
self.modex=Modex
self.modexPrefix=Prefix
self.modexSuffix=Suffix
return self
end
--- Set low fuel threshold. --- Set low fuel threshold.
-- @param #SQUADRON self -- @param #SQUADRON self
-- @param #number LowFuel Low fuel threshold in percent. Default 25. -- @param #number LowFuel Low fuel threshold in percent. Default 25.
@ -466,208 +207,17 @@ end
-- @param Ops.AirWing#AIRWING Airwing The airwing. -- @param Ops.AirWing#AIRWING Airwing The airwing.
-- @return #SQUADRON self -- @return #SQUADRON self
function SQUADRON:SetAirwing(Airwing) function SQUADRON:SetAirwing(Airwing)
self.airwing=Airwing self.legion=Airwing
return self return self
end end
--- Add airwing asset to squadron. --- Get airwing.
-- @param #SQUADRON self -- @param #SQUADRON self
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The airwing asset. -- @return Ops.AirWing#AIRWING The airwing.
-- @return #SQUADRON self function SQUADRON:GetAirwing(Airwing)
function SQUADRON:AddAsset(Asset) return self.legion
self:T(self.lid..string.format("Adding asset %s of type %s", Asset.spawngroupname, Asset.unittype))
Asset.squadname=self.name
table.insert(self.assets, Asset)
return self
end end
--- Remove airwing asset from squadron.
-- @param #SQUADRON self
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The airwing asset.
-- @return #SQUADRON self
function SQUADRON:DelAsset(Asset)
for i,_asset in pairs(self.assets) do
local asset=_asset --Ops.AirWing#AIRWING.SquadronAsset
if Asset.uid==asset.uid then
self:T2(self.lid..string.format("Removing asset %s", asset.spawngroupname))
table.remove(self.assets, i)
break
end
end
return self
end
--- Remove airwing asset group from squadron.
-- @param #SQUADRON self
-- @param #string GroupName Name of the asset group.
-- @return #SQUADRON self
function SQUADRON:DelGroup(GroupName)
for i,_asset in pairs(self.assets) do
local asset=_asset --Ops.AirWing#AIRWING.SquadronAsset
if GroupName==asset.spawngroupname then
self:T2(self.lid..string.format("Removing asset %s", asset.spawngroupname))
table.remove(self.assets, i)
break
end
end
return self
end
--- Get name of the squadron
-- @param #SQUADRON self
-- @return #string Name of the squadron.
function SQUADRON:GetName()
return self.name
end
--- Get radio frequency and modulation.
-- @param #SQUADRON self
-- @return #number Radio frequency in MHz.
-- @return #number Radio Modulation (0=AM, 1=FM).
function SQUADRON:GetRadio()
return self.radioFreq, self.radioModu
end
--- Create a callsign for the asset.
-- @param #SQUADRON self
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The airwing asset.
-- @return #SQUADRON self
function SQUADRON:GetCallsign(Asset)
if self.callsignName then
Asset.callsign={}
for i=1,Asset.nunits do
local callsign={}
callsign[1]=self.callsignName
callsign[2]=math.floor(self.callsigncounter / 10)
callsign[3]=self.callsigncounter % 10
if callsign[3]==0 then
callsign[3]=1
self.callsigncounter=self.callsigncounter+2
else
self.callsigncounter=self.callsigncounter+1
end
Asset.callsign[i]=callsign
self:T3({callsign=callsign})
--TODO: there is also a table entry .name, which is a string.
end
end
end
--- Create a modex for the asset.
-- @param #SQUADRON self
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The airwing asset.
-- @return #SQUADRON self
function SQUADRON:GetModex(Asset)
if self.modex then
Asset.modex={}
for i=1,Asset.nunits do
Asset.modex[i]=string.format("%03d", self.modex+self.modexcounter)
self.modexcounter=self.modexcounter+1
self:T3({modex=Asset.modex[i]})
end
end
end
--- Add TACAN channels to the squadron. Note that channels can only range from 1 to 126.
-- @param #SQUADRON self
-- @param #number ChannelMin Channel.
-- @param #number ChannelMax Channel.
-- @return #SQUADRON self
-- @usage mysquad:AddTacanChannel(64,69) -- adds channels 64, 65, 66, 67, 68, 69
function SQUADRON:AddTacanChannel(ChannelMin, ChannelMax)
ChannelMax=ChannelMax or ChannelMin
if ChannelMin>126 then
self:E(self.lid.."ERROR: TACAN Channel must be <= 126! Will not add to available channels")
return self
end
if ChannelMax>126 then
self:E(self.lid.."WARNING: TACAN Channel must be <= 126! Adjusting ChannelMax to 126")
ChannelMax=126
end
for i=ChannelMin,ChannelMax do
self.tacanChannel[i]=true
end
return self
end
--- Get an unused TACAN channel.
-- @param #SQUADRON self
-- @return #number TACAN channel or *nil* if no channel is free.
function SQUADRON:FetchTacan()
-- Get the smallest free channel if there is one.
local freechannel=nil
for channel,free in pairs(self.tacanChannel) do
if free then
if freechannel==nil or channel<freechannel then
freechannel=channel
end
end
end
if freechannel then
self:T(self.lid..string.format("Checking out Tacan channel %d", freechannel))
self.tacanChannel[freechannel]=false
end
return freechannel
end
--- "Return" a used TACAN channel.
-- @param #SQUADRON self
-- @param #number channel The channel that is available again.
function SQUADRON:ReturnTacan(channel)
self:T(self.lid..string.format("Returning Tacan channel %d", channel))
self.tacanChannel[channel]=true
end
--- Check if squadron is "OnDuty".
-- @param #SQUADRON self
-- @return #boolean If true, squdron is in state "OnDuty".
function SQUADRON:IsOnDuty()
return self:Is("OnDuty")
end
--- Check if squadron is "Stopped".
-- @param #SQUADRON self
-- @return #boolean If true, squdron is in state "Stopped".
function SQUADRON:IsStopped()
return self:Is("Stopped")
end
--- Check if squadron is "Paused".
-- @param #SQUADRON self
-- @return #boolean If true, squdron is in state "Paused".
function SQUADRON:IsPaused()
return self:Is("Paused")
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Start & Status -- Start & Status
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -706,8 +256,8 @@ function SQUADRON:onafterStatus(From, Event, To)
local NassetsTot=#self.assets local NassetsTot=#self.assets
local NassetsInS=self:CountAssets(true) local NassetsInS=self:CountAssets(true)
local NassetsQP=0 ; local NassetsP=0 ; local NassetsQ=0 local NassetsQP=0 ; local NassetsP=0 ; local NassetsQ=0
if self.airwing then if self.legion then
NassetsQP, NassetsP, NassetsQ=self.airwing:CountAssetsOnMission(nil, self) NassetsQP, NassetsP, NassetsQ=self.legion:CountAssetsOnMission(nil, self)
end end
-- Short info. -- Short info.
@ -725,407 +275,10 @@ function SQUADRON:onafterStatus(From, Event, To)
end end
end end
--- Check asset status.
-- @param #SQUADRON self
function SQUADRON:_CheckAssetStatus()
if self.verbose>=2 and #self.assets>0 then
local text=""
for j,_asset in pairs(self.assets) do
local asset=_asset --Ops.AirWing#AIRWING.SquadronAsset
-- Text.
text=text..string.format("\n[%d] %s (%s*%d): ", j, asset.spawngroupname, asset.unittype, asset.nunits)
if asset.spawned then
---
-- Spawned
---
-- Mission info.
local mission=self.airwing and self.airwing:GetAssetCurrentMission(asset) or false
if mission then
local distance=asset.flightgroup and UTILS.MetersToNM(mission:GetTargetDistance(asset.flightgroup.group:GetCoordinate())) or 0
text=text..string.format("Mission %s - %s: Status=%s, Dist=%.1f NM", mission.name, mission.type, mission.status, distance)
else
text=text.."Mission None"
end
-- Flight status.
text=text..", Flight: "
if asset.flightgroup and asset.flightgroup:IsAlive() then
local status=asset.flightgroup:GetState()
local fuelmin=asset.flightgroup:GetFuelMin()
local fuellow=asset.flightgroup:IsFuelLow()
local fuelcri=asset.flightgroup:IsFuelCritical()
text=text..string.format("%s Fuel=%d", status, fuelmin)
if fuelcri then
text=text.." (Critical!)"
elseif fuellow then
text=text.." (Low)"
end
local lifept, lifept0=asset.flightgroup:GetLifePoints()
text=text..string.format(", Life=%d/%d", lifept, lifept0)
local ammo=asset.flightgroup:GetAmmoTot()
text=text..string.format(", Ammo=%d [G=%d, R=%d, B=%d, M=%d]", ammo.Total,ammo.Guns, ammo.Rockets, ammo.Bombs, ammo.Missiles)
else
text=text.."N/A"
end
-- Payload info.
local payload=asset.payload and table.concat(self.airwing:GetPayloadMissionTypes(asset.payload), ", ") or "None"
text=text..", Payload={"..payload.."}"
else
---
-- In Stock
---
text=text..string.format("In Stock")
if self:IsRepaired(asset) then
text=text..", Combat Ready"
else
text=text..string.format(", Repaired in %d sec", self:GetRepairTime(asset))
if asset.damage then
text=text..string.format(" (Damage=%.1f)", asset.damage)
end
end
if asset.Treturned then
local T=timer.getAbsTime()-asset.Treturned
text=text..string.format(", Returned for %d sec", T)
end
end
end
self:I(self.lid..text)
end
end
--- On after "Stop" event.
-- @param #SQUADRON self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function SQUADRON:onafterStop(From, Event, To)
-- Debug info.
self:I(self.lid.."STOPPING Squadron and removing all assets!")
-- Remove all assets.
for i=#self.assets,1,-1 do
local asset=self.assets[i]
self:DelAsset(asset)
end
-- Clear call scheduler.
self.CallScheduler:Clear()
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Misc Functions -- Misc Functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Check if there is a squadron that can execute a given mission.
-- We check the mission type, the refuelling system, engagement range
-- @param #SQUADRON self
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
-- @return #boolean If true, Squadron can do that type of mission.
function SQUADRON:CanMission(Mission)
local cando=true
-- On duty?=
if not self:IsOnDuty() then
self:T(self.lid..string.format("Squad in not OnDuty but in state %s. Cannot do mission %s with target %s", self:GetState(), Mission.name, Mission:GetTargetName()))
return false
end
-- Check mission type. WARNING: This assumes that all assets of the squad can do the same mission types!
if not self:CheckMissionType(Mission.type, self:GetMissionTypes()) then
self:T(self.lid..string.format("INFO: Squad cannot do mission type %s (%s, %s)", Mission.type, Mission.name, Mission:GetTargetName()))
return false
end
-- Check that tanker mission
if Mission.type==AUFTRAG.Type.TANKER then
if Mission.refuelSystem and Mission.refuelSystem==self.tankerSystem then
-- Correct refueling system.
else
self:T(self.lid..string.format("INFO: Wrong refueling system requested=%s != %s=available", tostring(Mission.refuelSystem), tostring(self.tankerSystem)))
return false
end
end
-- Distance to target.
local TargetDistance=Mission:GetTargetDistance(self.airwing:GetCoordinate())
-- Max engage range.
local engagerange=Mission.engageRange and math.max(self.engageRange, Mission.engageRange) or self.engageRange
-- Set range is valid. Mission engage distance can overrule the squad engage range.
if TargetDistance>engagerange then
self:I(self.lid..string.format("INFO: Squad is not in range. Target dist=%d > %d NM max mission Range", UTILS.MetersToNM(TargetDistance), UTILS.MetersToNM(engagerange)))
return false
end
return true
end
--- Count assets in airwing (warehous) stock.
-- @param #SQUADRON self
-- @param #boolean InStock If true, only assets that are in the warehouse stock/inventory are counted.
-- @param #table MissionTypes (Optional) Count only assest that can perform certain mission type(s). Default is all types.
-- @param #table Attributes (Optional) Count only assest that have a certain attribute(s), e.g. `WAREHOUSE.Attribute.AIR_BOMBER`.
-- @return #number Number of assets.
function SQUADRON:CountAssets(InStock, MissionTypes, Attributes)
local N=0
for _,_asset in pairs(self.assets) do
local asset=_asset --Ops.AirWing#AIRWING.SquadronAsset
if MissionTypes==nil or self:CheckMissionCapability(MissionTypes, self.missiontypes) then
if Attributes==nil or self:CheckAttribute(Attributes) then
if asset.spawned then
if not InStock then
N=N+1 --Spawned but we also count the spawned ones.
end
else
N=N+1 --This is in stock.
end
end
end
end
return N
end
--- Get assets for a mission.
-- @param #SQUADRON self
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
-- @param #number Nplayloads Number of payloads available.
-- @return #table Assets that can do the required mission.
function SQUADRON:RecruitAssets(Mission, Npayloads)
-- Number of payloads available.
Npayloads=Npayloads or self.airwing:CountPayloadsInStock(Mission.type, self.aircrafttype, Mission.payloads)
local assets={}
-- Loop over assets.
for _,_asset in pairs(self.assets) do
local asset=_asset --Ops.AirWing#AIRWING.SquadronAsset
-- Check if asset is currently on a mission (STARTED or QUEUED).
if self.airwing:IsAssetOnMission(asset) then
---
-- Asset is already on a mission.
---
-- Check if this asset is currently on a GCICAP mission (STARTED or EXECUTING).
if self.airwing:IsAssetOnMission(asset, AUFTRAG.Type.GCICAP) and Mission.type==AUFTRAG.Type.INTERCEPT then
-- Check if the payload of this asset is compatible with the mission.
-- Note: we do not check the payload as an asset that is on a GCICAP mission should be able to do an INTERCEPT as well!
self:I(self.lid.."Adding asset on GCICAP mission for an INTERCEPT mission")
table.insert(assets, asset)
end
else
---
-- Asset as NO current mission
---
if asset.spawned then
---
-- Asset is already SPAWNED (could be uncontrolled on the airfield or inbound after another mission)
---
local flightgroup=asset.flightgroup
-- Firstly, check if it has the right payload.
if self:CheckMissionCapability(Mission.type, asset.payload.capabilities) and flightgroup and flightgroup:IsAlive() then
-- Assume we are ready and check if any condition tells us we are not.
local combatready=true
if Mission.type==AUFTRAG.Type.INTERCEPT then
combatready=flightgroup:CanAirToAir()
else
local excludeguns=Mission.type==AUFTRAG.Type.BOMBING or Mission.type==AUFTRAG.Type.BOMBRUNWAY or Mission.type==AUFTRAG.Type.BOMBCARPET or Mission.type==AUFTRAG.Type.SEAD or Mission.type==AUFTRAG.Type.ANTISHIP
combatready=flightgroup:CanAirToGround(excludeguns)
end
-- No more attacks if fuel is already low. Safety first!
if flightgroup:IsFuelLow() then
combatready=false
end
-- Check if in a state where we really do not want to fight any more.
if flightgroup:IsHolding() or flightgroup:IsLanding() or flightgroup:IsLanded() or flightgroup:IsArrived() or flightgroup:IsDead() or flightgroup:IsStopped() then
combatready=false
end
-- This asset is "combatready".
if combatready then
self:I(self.lid.."Adding SPAWNED asset to ANOTHER mission as it is COMBATREADY")
table.insert(assets, asset)
end
end
else
---
-- Asset is still in STOCK
---
-- Check that asset is not already requested for another mission.
if Npayloads>0 and self:IsRepaired(asset) and (not asset.requested) then
-- Add this asset to the selection.
table.insert(assets, asset)
-- Reduce number of payloads so we only return the number of assets that could do the job.
Npayloads=Npayloads-1
end
end
end
end -- loop over assets
return assets
end
--- Get the time an asset needs to be repaired.
-- @param #SQUADRON self
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The asset.
-- @return #number Time in seconds until asset is repaired.
function SQUADRON:GetRepairTime(Asset)
if Asset.Treturned then
local t=self.maintenancetime
t=t+Asset.damage*self.repairtime
-- Seconds after returned.
local dt=timer.getAbsTime()-Asset.Treturned
local T=t-dt
return T
else
return 0
end
end
--- Checks if a mission type is contained in a table of possible types.
-- @param #SQUADRON self
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The asset.
-- @return #boolean If true, the requested mission type is part of the possible mission types.
function SQUADRON:IsRepaired(Asset)
if Asset.Treturned then
local Tnow=timer.getAbsTime()
local Trepaired=Asset.Treturned+self.maintenancetime
if Tnow>=Trepaired then
return true
else
return false
end
else
return true
end
end
--- Checks if a mission type is contained in a table of possible types.
-- @param #SQUADRON self
-- @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 SQUADRON:CheckMissionType(MissionType, PossibleTypes)
if type(PossibleTypes)=="string" then
PossibleTypes={PossibleTypes}
end
for _,canmission in pairs(PossibleTypes) do
if canmission==MissionType then
return true
end
end
return false
end
--- Check if a mission type is contained in a list of possible capabilities.
-- @param #SQUADRON self
-- @param #table MissionTypes The requested mission type. Can also be passed as a single mission type `#string`.
-- @param #table Capabilities A table with possible capabilities.
-- @return #boolean If true, the requested mission type is part of the possible mission types.
function SQUADRON:CheckMissionCapability(MissionTypes, Capabilities)
if type(MissionTypes)~="table" then
MissionTypes={MissionTypes}
end
for _,cap in pairs(Capabilities) do
local capability=cap --Ops.Auftrag#AUFTRAG.Capability
for _,MissionType in pairs(MissionTypes) do
if capability.MissionType==MissionType then
return true
end
end
end
return false
end
--- Check if the squadron attribute matches the given attribute(s).
-- @param #SQUADRON self
-- @param #table Attributes The requested attributes. See `WAREHOUSE.Attribute` enum. Can also be passed as a single attribute `#string`.
-- @return #boolean If true, the squad has the requested attribute.
function SQUADRON:CheckAttribute(Attributes)
if type(Attributes)~="table" then
Attributes={Attributes}
end
for _,attribute in pairs(Attributes) do
if attribute==self.attribute then
return true
end
end
return false
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------