OPS Escort

- Refined functions to recruit escort assets.
This commit is contained in:
Frank 2021-09-19 22:10:52 +02:00
parent 73940fffc6
commit 7148bd1d42
7 changed files with 532 additions and 70 deletions

View File

@ -815,7 +815,7 @@ function AIRWING:onafterStatus(From, Event, To)
local mission=_mission --Ops.Auftrag#AUFTRAG
local prio=string.format("%d/%s", mission.prio, tostring(mission.importance)) ; if mission.urgent then prio=prio.." (!)" end
local assets=string.format("%d/%d", mission:CountOpsGroups(), mission.nassets)
local assets=string.format("%d/%d", mission:CountOpsGroups(), mission:GetNumberOfRequiredAssets())
local target=string.format("%d/%d Damage=%.1f", mission:CountMissionTargets(), mission:GetTargetInitialNumber(), mission:GetTargetDamage())
local mystatus=mission:GetLegionStatus(self)

View File

@ -32,6 +32,7 @@
-- @field #string lid Class id string for output to DCS log file.
-- @field #number auftragsnummer Auftragsnummer.
-- @field #string type Mission type.
-- @field #table categories Mission categories.
-- @field #string status Mission status.
-- @field #table legions Assigned legions.
-- @field #table statusLegion Mission status of all assigned LEGIONs.
@ -95,15 +96,23 @@
-- @field #number artyRadius Radius in meters.
-- @field #number artyShots Number of shots fired.
--
-- @field #string alert5MissionType Alert 5 mission type. This is the mission type, the alerted assets will be able to carry out.
--
-- @field Ops.Chief#CHIEF chief The CHIEF managing this mission.
-- @field Ops.Commander#COMMANDER commander The COMMANDER managing this mission.
-- @field #table assets Warehouse assets assigned for this mission.
-- @field #number nassets Number of required warehouse assets.
-- @field #table Nassets Number of required warehouse assets for each assigned legion.
-- @field #number NassetsMin Min. number of required warehouse assets.
-- @field #number NassetsMax Max. number of required warehouse assets.
-- @field #number NescortMin Min. number of required escort assets for each group the mission is assigned to.
-- @field #number NescortMax Max. number of required escort assets for each group the mission is assigned to.
-- @field #number Nassets Number of requested warehouse assets.
-- @field #table NassetsLegMin Number of required warehouse assets for each assigned legion.
-- @field #table NassetsLegMax Number of required warehouse assets for each assigned legion.
-- @field #table requestID The ID of the queued warehouse request. Necessary to cancel the request if the mission was cancelled before the request is processed.
-- @field #table specialLegions User specified legions assigned for this mission. Only these will be considered for the job!
-- @field #table specialCohorts User specified cohorts assigned for this mission. Only these will be considered for the job!
-- @field #table squadrons User specified airwing squadrons assigned for this mission. Only these will be considered for the job!
-- @field #table payloads User specified airwing payloads for this mission. Only these will be considered for the job!
-- @field #table mylegions User specified legions for this mission. Only these will be considered for the job!
-- @field Ops.AirWing#AIRWING.PatrolData patroldata Patrol data.
--
-- @field #string missionTask Mission task. See `ENUMS.MissionTask`.
@ -244,9 +253,11 @@
--
-- An arty mission can be created with the @{#AUFTRAG.NewARTY}() function.
--
--
-- # Options and Parameters
--
--
--
-- # Assigning Missions
--
-- An AUFTRAG can be assigned to groups, airwings or wingcommanders
@ -261,13 +272,19 @@
--
-- Assigning an AUFTRAG to a navy groups is done via the @{Ops.NavyGroup#NAVYGROUP.AddMission} function. See NAVYGROUP docs for details.
--
-- ## Airwing Level
-- ## Legion Level
--
-- Adding an AUFTRAG to an airwing is done via the @{Ops.AirWing#AIRWING.AddMission} function. See AIRWING docs for further details.
-- Similarly, an AUFTRAG can be added to a brigade via the @{Ops.Brigade#BRIGADE.AddMission} function
--
-- ## Wing Commander Level
-- ## Commander Level
--
-- Assigning an AUFTRAG to acommander is done via the @{Ops.Commander#COMMANDER.AddMission} function. See COMMADER docs for details.
--
-- ## Chief Level
--
-- Assigning an AUFTRAG to a wing commander is done via the @{Ops.Chief#CHIEF.AddMission} function. See CHIEF docs for details.
--
-- Assigning an AUFTRAG to a wing commander is done via the @{Ops.WingCommander#WINGCOMMANDER.AddMission} function. See WINGCOMMADER docs for details.
--
--
-- # Events
@ -289,7 +306,8 @@ AUFTRAG = {
statusLegion = {},
requestID = {},
assets = {},
Nassets = {},
NassetsLegMin = {},
NassetsLegMax = {},
missionFraction = 0.5,
enrouteTasks = {},
marker = nil,
@ -444,6 +462,22 @@ AUFTRAG.TargetType={
SETUNIT="SetUnit",
}
--- Mission category.
-- @type AUFTRAG.Category
-- @field #string AIRCRAFT Airplanes and helicopters.
-- @field #string AIRPLANE Airplanes.
-- @field #string HELICOPTER Helicopter.
-- @field #string GROUND Ground troops.
-- @field #string NAVAL Naval grous.
AUFTRAG.Category={
ALL="All",
AIRCRAFT="Aircraft",
AIRPLANE="Airplane",
HELICOPTER="Helicopter",
GROUND="Ground",
NAVAL="Naval",
}
--- Target data.
-- @type AUFTRAG.TargetData
-- @field Wrapper.Positionable#POSITIONABLE Target Target Object.
@ -483,7 +517,7 @@ AUFTRAG.TargetType={
--- AUFTRAG class version.
-- @field #string version
AUFTRAG.version="0.8.0"
AUFTRAG.version="0.8.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@ -493,6 +527,7 @@ AUFTRAG.version="0.8.0"
-- TODO: Mission success options damaged, destroyed.
-- TODO: F10 marker to create new missions.
-- TODO: Add recovery tanker mission for boat ops.
-- DONE: Added auftrag category.
-- DONE: Missions can be assigned to multiple legions.
-- DONE: Option to assign a specific payload for the mission (requires an AIRWING).
-- NOPE: Clone mission. How? Deepcopy? ==> Create a new auftrag.
@ -621,6 +656,8 @@ function AUFTRAG:NewANTISHIP(Target, Altitude)
mission.optionROE=ENUMS.ROE.OpenFire
mission.optionROT=ENUMS.ROT.EvadeFire
mission.categories={AUFTRAG.Category.AIRCRAFT}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -663,6 +700,8 @@ function AUFTRAG:NewORBIT(Coordinate, Altitude, Speed, Heading, Leg)
mission.optionROE=ENUMS.ROE.ReturnFire
mission.optionROT=ENUMS.ROT.PassiveDefense
mission.categories={AUFTRAG.Category.AIRCRAFT}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -722,6 +761,8 @@ function AUFTRAG:NewGCICAP(Coordinate, Altitude, Speed, Heading, Leg)
mission.missionTask=ENUMS.MissionTask.INTERCEPT
mission.optionROT=ENUMS.ROT.PassiveDefense
mission.categories={AUFTRAG.Category.AIRCRAFT}
return mission
end
@ -751,6 +792,8 @@ function AUFTRAG:NewTANKER(Coordinate, Altitude, Speed, Heading, Leg, RefuelSyst
mission.optionROE=ENUMS.ROE.WeaponHold
mission.optionROT=ENUMS.ROT.PassiveDefense
mission.categories={AUFTRAG.Category.AIRCRAFT}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -779,6 +822,8 @@ function AUFTRAG:NewAWACS(Coordinate, Altitude, Speed, Heading, Leg)
mission.optionROE=ENUMS.ROE.WeaponHold
mission.optionROT=ENUMS.ROT.PassiveDefense
mission.categories={AUFTRAG.Category.AIRCRAFT}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -802,6 +847,8 @@ function AUFTRAG:NewINTERCEPT(Target)
mission.optionROE=ENUMS.ROE.OpenFire
mission.optionROT=ENUMS.ROT.EvadeFire
mission.categories={AUFTRAG.Category.AIRCRAFT}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -842,6 +889,8 @@ function AUFTRAG:NewCAP(ZoneCAP, Altitude, Speed, Coordinate, Heading, Leg, Targ
mission.optionROE=ENUMS.ROE.OpenFire
mission.optionROT=ENUMS.ROT.EvadeFire
mission.categories={AUFTRAG.Category.AIRCRAFT}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -882,6 +931,8 @@ function AUFTRAG:NewCAS(ZoneCAS, Altitude, Speed, Coordinate, Heading, Leg, Targ
mission.optionROE=ENUMS.ROE.OpenFire
mission.optionROT=ENUMS.ROT.EvadeFire
mission.categories={AUFTRAG.Category.AIRCRAFT}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -916,6 +967,8 @@ function AUFTRAG:NewFACA(Target, Designation, DataLink, Frequency, Modulation)
mission.optionROE=ENUMS.ROE.ReturnFire
mission.optionROT=ENUMS.ROT.PassiveDefense
mission.categories={AUFTRAG.Category.AIRCRAFT}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -945,6 +998,8 @@ function AUFTRAG:NewBAI(Target, Altitude)
mission.optionROE=ENUMS.ROE.OpenFire
mission.optionROT=ENUMS.ROT.PassiveDefense
mission.categories={AUFTRAG.Category.AIRCRAFT}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -974,6 +1029,8 @@ function AUFTRAG:NewSEAD(Target, Altitude)
mission.optionROT=ENUMS.ROT.EvadeFire
--mission.optionROT=ENUMS.ROT.AllowAbortMission
mission.categories={AUFTRAG.Category.AIRCRAFT}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -1002,6 +1059,8 @@ function AUFTRAG:NewSTRIKE(Target, Altitude)
mission.optionROE=ENUMS.ROE.OpenFire
mission.optionROT=ENUMS.ROT.PassiveDefense
mission.categories={AUFTRAG.Category.AIRCRAFT}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -1033,6 +1092,8 @@ function AUFTRAG:NewBOMBING(Target, Altitude)
-- Evaluate result after 5 min. We might need time until the bombs have dropped and targets have been detroyed.
mission.dTevaluate=5*60
mission.categories={AUFTRAG.Category.AIRCRAFT}
-- Get DCS task.
mission.DCStask=mission:GetDCSMissionTask()
@ -1069,6 +1130,8 @@ function AUFTRAG:NewBOMBRUNWAY(Airdrome, Altitude)
-- Evaluate result after 5 min.
mission.dTevaluate=5*60
mission.categories={AUFTRAG.Category.AIRCRAFT}
-- Get DCS task.
mission.DCStask=mission:GetDCSMissionTask()
@ -1105,6 +1168,8 @@ function AUFTRAG:NewBOMBCARPET(Target, Altitude, CarpetLength)
-- Evaluate result after 5 min.
mission.dTevaluate=5*60
mission.categories={AUFTRAG.Category.AIRCRAFT}
-- Get DCS task.
mission.DCStask=mission:GetDCSMissionTask()
@ -1123,7 +1188,13 @@ function AUFTRAG:NewESCORT(EscortGroup, OffsetVector, EngageMaxDistance, TargetT
local mission=AUFTRAG:New(AUFTRAG.Type.ESCORT)
mission:_TargetFromObject(EscortGroup)
-- If only a string is passed we set a variable and check later if the group exists.
if type(EscortGroup)=="string" then
mission.escortGroupName=EscortGroup
mission:_TargetFromObject()
else
mission:_TargetFromObject(EscortGroup)
end
-- DCS task parameters:
mission.escortVec3=OffsetVector or {x=-100, y=0, z=200}
@ -1137,6 +1208,8 @@ function AUFTRAG:NewESCORT(EscortGroup, OffsetVector, EngageMaxDistance, TargetT
mission.optionROE=ENUMS.ROE.OpenFire -- TODO: what's the best ROE here? Make dependent on ESCORT or FOLLOW!
mission.optionROT=ENUMS.ROT.PassiveDefense
mission.categories={AUFTRAG.Category.AIRCRAFT}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -1158,13 +1231,15 @@ function AUFTRAG:NewRESCUEHELO(Carrier)
mission.optionROE=ENUMS.ROE.WeaponHold
mission.optionROT=ENUMS.ROT.NoReaction
mission.categories={AUFTRAG.Category.HELICOPTER}
mission.DCStask=mission:GetDCSMissionTask()
return mission
end
--- **[AIR ROTARY]** Create a TROOP TRANSPORT mission.
--- **[AIR ROTARY, GROUND]** Create a TROOP TRANSPORT mission.
-- @param #AUFTRAG self
-- @param Core.Set#SET_GROUP TransportGroupSet The set group(s) to be transported.
-- @param Core.Point#COORDINATE DropoffCoordinate Coordinate where the helo will land drop off the the troops.
@ -1197,6 +1272,8 @@ function AUFTRAG:NewTROOPTRANSPORT(TransportGroupSet, DropoffCoordinate, PickupC
mission.optionROE=ENUMS.ROE.ReturnFire
mission.optionROT=ENUMS.ROT.PassiveDefense
mission.categories={AUFTRAG.Category.HELICOPTER, AUFTRAG.Category.GROUND}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -1231,6 +1308,8 @@ function AUFTRAG:NewOPSTRANSPORT(CargoGroupSet, PickupZone, DeployZone)
mission.optionROE=ENUMS.ROE.ReturnFire
mission.optionROT=ENUMS.ROT.PassiveDefense
mission.categories={AUFTRAG.Category.ALL}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -1262,6 +1341,8 @@ function AUFTRAG:NewARTY(Target, Nshots, Radius)
-- Evaluate after 8 min.
mission.dTevaluate=8*60
mission.categories={AUFTRAG.Category.GROUND}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -1292,6 +1373,8 @@ function AUFTRAG:NewPATROLZONE(Zone, Speed, Altitude)
mission.missionSpeed=Speed and UTILS.KnotsToKmph(Speed) or nil
mission.missionAltitude=Altitude and UTILS.FeetToMeters(Altitude) or nil
mission.categories={AUFTRAG.Category.ALL}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -1319,6 +1402,8 @@ function AUFTRAG:NewRECON(ZoneSet, Speed, Altitude, Adinfinitum, Randomly)
mission.missionSpeed=Speed and UTILS.KnotsToKmph(Speed) or nil
mission.missionAltitude=Altitude and UTILS.FeetToMeters(Altitude) or UTILS.FeetToMeters(2000)
mission.categories={AUFTRAG.Category.ALL}
mission.DCStask=mission:GetDCSMissionTask()
mission.DCStask.params.adinfitum=Adinfinitum
mission.DCStask.params.randomly=Randomly
@ -1341,6 +1426,8 @@ function AUFTRAG:NewAMMOSUPPLY(Zone)
mission.missionFraction=0.9
mission.categories={AUFTRAG.Category.GROUND}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -1361,6 +1448,8 @@ function AUFTRAG:NewFUELSUPPLY(Zone)
mission.missionFraction=0.9
mission.categories={AUFTRAG.Category.GROUND}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -1384,6 +1473,8 @@ function AUFTRAG:NewALERT5(MissionType)
mission.missionFraction=1.0
mission.categories={AUFTRAG.Category.AIRCRAFT}
mission.DCStask=mission:GetDCSMissionTask()
return mission
@ -1686,28 +1777,58 @@ function AUFTRAG:SetRepeatOnSuccess(Nrepeat)
return self
end
--- Define how many assets are required to do the job. Only valid if the mission is handled by a LEGION (AIRWING, BRIGADE, ...) or higher level.
--- Define how many assets are required to do the job. Only used if the mission is handled by a **LEGION** (AIRWING, BRIGADE, ...) or higher level.
-- @param #AUFTRAG self
-- @param #number Nassets Number of asset groups. Default 1.
-- @param #number NassetsMin Minimum number of asset groups. Default 1.
-- @param #number NassetsMax Maximum Number of asset groups. Default is same as `NassetsMin`.
-- @return #AUFTRAG self
function AUFTRAG:SetRequiredAssets(Nassets)
self.nassets=Nassets or 1
function AUFTRAG:SetRequiredAssets(NassetsMin, NassetsMax)
self.NassetsMin=NassetsMin or 1
self.NassetsMax=NassetsMax or self.NassetsMin
-- Ensure that max is at least equal to min.
if self.NassetsMax<self.NassetsMin then
self.NassetsMax=self.NassetsMin
end
return self
end
--- Get number of required assets.
-- @param #AUFTRAG self
-- @param Ops.Legion#Legion Legion (Optional) Only get the required assets for a specific legion. If required assets for this legion are not defined, the total number is returned.
-- @return #number Number of required assets.
-- @return #number Min. number of required assets.
-- @return #number Max. number of required assets.
function AUFTRAG:GetRequiredAssets(Legion)
local N=self.nassets
--local N=self.nassets
if Legion and self.Nassets[Legion.alias] then
N=self.Nassets[Legion.alias]
--if Legion and self.Nassets[Legion.alias] then
-- N=self.Nassets[Legion.alias]
--end
return self.NassetsMin, self.NassetsMax
end
--- Define how many assets are required to do the job. Only used if the mission is handled by a **LEGION** (AIRWING, BRIGADE, ...) or higher level.
-- @param #AUFTRAG self
-- @param #number NescortMin Minimum number of asset groups. Default 1.
-- @param #number NescortMax Maximum Number of asset groups. Default is same as `NassetsMin`.
-- @return #AUFTRAG self
function AUFTRAG:SetRequiredEscorts(NescortMin, NescortMax)
self.NescortMin=NescortMin or 1
self.NescortMax=NescortMax or self.NescortMin
-- Ensure that max is at least equal to min.
if self.NescortMax<self.NescortMin then
self.NescortMax=self.NescortMin
end
return N
return self
end
--- Set mission name.
@ -2039,7 +2160,7 @@ end
-- @param #AUFTRAG self
-- @return #number Numer of required assets.
function AUFTRAG:GetNumberOfRequiredAssets()
return self.nassets
return self.Nassets or self.NassetsMin
end
--- Get mission priority.
@ -2167,6 +2288,8 @@ function AUFTRAG:_AssignCohort(Cohort)
self.squadrons=self.squadrons or {}
self:T3(self.lid..string.format("Assigning cohort %s", tostring(Cohort.name)))
-- Add cohort to table.
table.insert(self.squadrons, Cohort)
return self
@ -2338,6 +2461,67 @@ function AUFTRAG:IsNotOver()
return not self:IsOver()
end
--- Check if mission is for aircarft (airplanes and/or helicopters).
-- @param #AUFTRAG self
-- @return #boolean If `true`, mission is for aircraft.
function AUFTRAG:IsAircraft()
for _,category in pairs(self.categories) do
if category==AUFTRAG.Category.AIRCRAFT or category==AUFTRAG.Category.AIRPLANE or category==AUFTRAG.Category.HELICOPTER then
return true
end
end
return false
end
--- Check if mission is for airplanes.
-- @param #AUFTRAG self
-- @return #boolean If `true`, mission is for airplanes.
function AUFTRAG:IsAirplane()
for _,category in pairs(self.categories) do
if category==AUFTRAG.Category.AIRPLANE then
return true
end
end
return false
end
--- Check if mission is for helicopters.
-- @param #AUFTRAG self
-- @return #boolean If `true`, mission is for helicopters.
function AUFTRAG:IsHelicopters()
for _,category in pairs(self.categories) do
if category==AUFTRAG.Category.HELICOPTER then
return true
end
end
return false
end
--- Check if mission is for ground units.
-- @param #AUFTRAG self
-- @return #boolean If `true`, mission is for ground units.
function AUFTRAG:IsGround()
for _,category in pairs(self.categories) do
if category==AUFTRAG.Category.GROUND then
return true
end
end
return false
end
--- Check if mission is for naval units.
-- @param #AUFTRAG self
-- @return #boolean If `true`, mission is for naval units.
function AUFTRAG:IsNaval()
for _,category in pairs(self.categories) do
if category==AUFTRAG.Category.NAVAL then
return true
end
end
return false
end
--- Check if mission is ready to be started.
-- * Mission start time passed.
-- * Mission stop time did not pass already.
@ -2496,6 +2680,26 @@ function AUFTRAG:onafterStatus(From, Event, To)
-- Current abs. mission time.
local Tnow=timer.getAbsTime()
-- ESCORT: Check if only the group NAME of an escort had been specified.
if self.escortGroupName then
-- Try to find the group.
local group=GROUP:FindByName(self.escortGroupName)
if group and group:IsAlive() then
-- Debug info.
self:T(self.lid..string.format("ESCORT group %s is now alive. Updating DCS task and adding group to TARGET", tostring(self.escortGroupName)))
-- Add TARGET object.
self.engageTarget:AddObject(group)
-- Update DCS task with the known group ID.
self.DCStask=self:GetDCSMissionTask()
-- Set value to nil so we do not do this again in the next cycle.
self.escortGroupName=nil
end
end
-- Number of alive mission targets.
local Ntargets=self:CountMissionTargets()
local Ntargets0=self:GetTargetInitialNumber()
@ -3337,7 +3541,7 @@ end
-- @param #string To To state.
function AUFTRAG:onbeforeRepeat(From, Event, To)
if not (self.chief or self.commander or #self.legions==0) then
if not (self.chief or self.commander or #self.legions>0) then
self:E(self.lid.."ERROR: Mission can only be repeated by a CHIEF, COMMANDER or LEGION! Stopping AUFTRAG")
self:Stop()
return false
@ -3498,7 +3702,7 @@ function AUFTRAG:_TargetFromObject(Object)
if not self.engageTarget then
if Object:IsInstanceOf("TARGET") then
if Object and Object:IsInstanceOf("TARGET") then
self.engageTarget=Object
@ -3848,7 +4052,7 @@ function AUFTRAG:UpdateMarker()
local text=string.format("%s %s: %s", self.name, self.type:upper(), self.status:upper())
text=text..string.format("\n%s", self:GetTargetName())
text=text..string.format("\nTargets %d/%d, Life Points=%d/%d", self:CountMissionTargets(), self:GetTargetInitialNumber(), self:GetTargetLife(), self:GetTargetInitialLife())
text=text..string.format("\nFlights %d/%d", self:CountOpsGroups(), self.nassets)
text=text..string.format("\nOpsGroups %d/%d", self:CountOpsGroups(), self.nassets)
if not self.marker then

View File

@ -694,16 +694,27 @@ function COMMANDER:CheckMissionQueue()
mission:AddAsset(asset)
end
-- Assign mission to legion(s).
for _,_legion in pairs(legions) do
local legion=_legion --Ops.Legion#LEGION
-- Recruit asset for escorting recruited mission assets.
local EscortAvail=self:RecruitAssetsForEscort(mission, assets)
-- Debug message.
self:I(self.lid..string.format("Assigning mission %s [%s] to legion %s", mission:GetName(), mission:GetType(), legion.alias))
-- Add mission to legion.
self:MissionAssign(legion, mission)
if EscortAvail then
-- Assign mission to legion(s).
for _,_legion in pairs(legions) do
local legion=_legion --Ops.Legion#LEGION
-- Debug message.
self:I(self.lid..string.format("Assigning mission %s [%s] to legion %s", mission:GetName(), mission:GetType(), legion.alias))
-- Add mission to legion.
self:MissionAssign(legion, mission)
end
else
-- Recruited assets but no requested escort available. Unrecruit assets!
LEGION.UnRecruitAssets(assets, mission)
end
-- Only ONE mission is assigned.
@ -745,8 +756,7 @@ function COMMANDER:RecruitAssetsForMission(Mission)
end
-- Number of required assets.
local NreqMin=Mission:GetRequiredAssets()
local NreqMax=NreqMin
local NreqMin, NreqMax=Mission:GetRequiredAssets()
-- Target position.
local TargetVec2=Mission:GetTargetVec2()
@ -760,6 +770,111 @@ function COMMANDER:RecruitAssetsForMission(Mission)
return recruited, assets, legions
end
--- Recruit assets performing an escort mission for a given asset.
-- @param #COMMANDER self
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
-- @param #table Assets Table of assets.
-- @return #boolean If `true`, enough assets could be recruited or no escort was required in the first place.
function COMMANDER:RecruitAssetsForEscort(Mission, Assets)
-- Cohorts.
local Cohorts=Mission.squadrons
if not Cohorts then
Cohorts={}
for _,_legion in pairs(Mission.mylegions or self.legions) do
local legion=_legion --Ops.Legion#LEGION
-- Loops over cohorts.
for _,_cohort in pairs(legion.cohorts) do
local cohort=_cohort --Ops.Cohort#COHORT
table.insert(Cohorts, cohort)
end
end
end
-- Is an escort requested in the first place?
if Mission.NescortMin and Mission.NescortMax and (Mission.NescortMin>0 or Mission.NescortMax>0) then
-- Debug info.
self:I(self.lid..string.format("Reqested escort for mission %s [%s]. Required assets=%d-%d", Mission:GetName(), Mission:GetType(), Mission.NescortMin,Mission.NescortMax))
-- Escorts for each asset.
local Escorts={}
local EscortAvail=true
for _,_asset in pairs(Assets) do
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
-- Recruit escort asset for the mission asset.
local Erecruited, eassets, elegions=LEGION.RecruitCohortAssets(Cohorts, AUFTRAG.Type.ESCORT, nil, Mission.NescortMin, Mission.NescortMax)
if Erecruited then
Escorts[asset.spawngroupname]={EscortLegions=elegions, EscortAssets=eassets}
else
-- Could not find escort for this asset ==> Escort not possible ==> Break the loop.
EscortAvail=false
break
end
end
-- ALL escorts could be recruited.
if EscortAvail then
local N=0
for groupname,value in pairs(Escorts) do
local Elegions=value.EscortLegions
local Eassets=value.EscortAssets
for _,_legion in pairs(Elegions) do
local legion=_legion --Ops.Legion#LEGION
-- Create and ESCORT mission for this asset.
local escort=AUFTRAG:NewESCORT(groupname)
-- Reserve assts and add to mission.
for _,_asset in pairs(Eassets) do
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
asset.isReserved=true
escort:AddAsset(asset)
N=N+1
end
-- Add mission.
legion:AddMission(escort)
-- Request mission.
legion:MissionRequest(escort)
end
end
-- Debug info.
self:I(self.lid..string.format("Recruited %d escort assets for mission %s [%s]", N, Mission:GetName(), Mission:GetType()))
-- Yup!
return true
else
-- Debug info.
self:I(self.lid..string.format("Could not get at least one escort for mission %s [%s]! Unrecruit all recruited assets", Mission:GetName(), Mission:GetType()))
-- Could not get at least one escort. Unrecruit all recruited ones.
for groupname,value in pairs(Escorts) do
local Eassets=value.EscortAssets
LEGION.UnRecruitAssets(Eassets)
end
-- No,no!
return false
end
else
-- No escort required.
return true
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Transport Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -476,14 +476,27 @@ function LEGION:_GetNextMission()
-- Did we find enough assets?
if recruited then
-- Reserve assets and add to mission.
for _,_asset in pairs(assets) do
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
asset.isReserved=true
mission:AddAsset(asset)
end
return mission
end
-- Recruit asset for escorting recruited mission assets.
local EscortAvail=self:RecruitAssetsForEscort(mission, assets)
-- Is escort required and available?
if EscortAvail then
-- Got a missin.
return mission
else
-- Recruited assets but no requested escort available. Unrecruit assets!
LEGION.UnRecruitAssets(assets, mission)
end
end -- recruited mission assets
end -- mission due?
end -- mission loop
@ -1627,8 +1640,7 @@ end
function LEGION:RecruitAssetsForMission(Mission)
-- Get required assets.
local NreqMin=Mission:GetRequiredAssets()
local NreqMax=NreqMin
local NreqMin, NreqMax=Mission:GetRequiredAssets()
-- Target position vector.
local TargetVec2=Mission:GetTargetVec2()
@ -1686,6 +1698,97 @@ function LEGION:RecruitAssetsForTransport(Transport)
return recruited, assets, legions
end
--- Recruit assets performing an escort mission for a given asset.
-- @param #LEGION self
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
-- @param #table Assets Table of assets.
-- @return #boolean If `true`, enough assets could be recruited or no escort was required in the first place.
function LEGION:RecruitAssetsForEscort(Mission, Assets)
-- Is an escort requested in the first place?
if Mission.NescortMin and Mission.NescortMax and (Mission.NescortMin>0 or Mission.NescortMax>0) then
-- Debug info.
self:I(self.lid..string.format("Reqested escort for mission %s [%s]. Required assets=%d-%d", Mission:GetName(), Mission:GetType(), Mission.NescortMin,Mission.NescortMax))
-- Escorts for each asset.
local Escorts={}
local EscortAvail=true
for _,_asset in pairs(Assets) do
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
-- Recruit escort asset for the mission asset.
local Erecruited, eassets, elegions=LEGION.RecruitCohortAssets(self.cohorts, AUFTRAG.Type.ESCORT, nil, Mission.NescortMin, Mission.NescortMax)
if Erecruited then
Escorts[asset.spawngroupname]={EscortLegions=elegions, EscortAssets=eassets}
else
-- Could not find escort for this asset ==> Escort not possible ==> Break the loop.
EscortAvail=false
break
end
end
-- ALL escorts could be recruited.
if EscortAvail then
local N=0
for groupname,value in pairs(Escorts) do
local Elegions=value.EscortLegions
local Eassets=value.EscortAssets
for _,_legion in pairs(Elegions) do
local legion=_legion --Ops.Legion#LEGION
-- Create and ESCORT mission for this asset.
local escort=AUFTRAG:NewESCORT(groupname)
-- Reserve assts and add to mission.
for _,_asset in pairs(Eassets) do
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
asset.isReserved=true
escort:AddAsset(asset)
N=N+1
end
-- Add mission.
legion:AddMission(escort)
-- Request mission.
legion:MissionRequest(escort)
end
end
-- Debug info.
self:I(self.lid..string.format("Recruited %d escort assets for mission %s [%s]", N, Mission:GetName(), Mission:GetType()))
-- Yup!
return true
else
-- Debug info.
self:I(self.lid..string.format("Could not get at least one escort for mission %s [%s]! Unrecruit all recruited assets", Mission:GetName(), Mission:GetType()))
-- Could not get at least one escort. Unrecruit all recruited ones.
for groupname,value in pairs(Escorts) do
local Eassets=value.EscortAssets
LEGION.UnRecruitAssets(Eassets)
end
-- No,no!
return false
end
else
-- No escort required.
return true
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Recruiting and Optimization Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -1827,6 +1930,30 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
return false, {}, {}
end
--- Unrecruit assets. Set `isReserved` to false, return payload to airwing and (optionally) remove from assigned mission.
-- @param #table Assets List of assets.
-- @param Ops.Auftrag#AUFTRAG Mission (Optional) The mission from which the assets will be deleted.
function LEGION.UnRecruitAssets(Assets, Mission)
-- Return payloads of assets.
for i=1,#Assets do
local asset=Assets[i] --Functional.Warehouse#WAREHOUSE.Assetitem
-- Not reserved any more.
asset.isReserved=false
-- Return payload.
if asset.legion:IsAirwing() and not asset.spawned then
asset.legion:T2(asset.legion.lid..string.format("Returning payload from asset %s", asset.spawngroupname))
asset.legion:ReturnPayloadFromAsset(asset)
end
-- Remove from mission.
if Mission then
Mission:DelAsset(asset)
end
end
end
--- Calculate the mission score of an asset.
-- @param Functional.Warehouse#WAREHOUSE.Assetitem asset Asset

View File

@ -3763,9 +3763,6 @@ function OPSGROUP:_GetNextMission()
end
table.sort(self.missionqueue, _sort)
-- Current time.
local time=timer.getAbsTime()
-- Look for first mission that is SCHEDULED.
local vip=math.huge
for _,_mission in pairs(self.missionqueue) do
@ -3795,8 +3792,22 @@ function OPSGROUP:_GetNextMission()
-- TODO: One could think of opsgroup specific start conditions. A legion also checks if "ready" but it can be other criteria for the group to actually start the mission.
-- Good example is the above transport. The legion should start the mission but the group should only start after the transport is finished.
-- Escort mission. Check that escorted group is alive.
local isEscort=true
if mission.type==AUFTRAG.Type.ESCORT then
local target=mission:GetTargetData()
if not target:IsAlive() then
isEscort=false
end
end
local isScheduled=mission:GetGroupStatus(self)==AUFTRAG.GroupStatus.SCHEDULED
local isReadyToGo=(mission:IsReadyToGo() or self.legion)
local isImportant=(mission.importance==nil or mission.importance<=vip)
local isTransport=transport
-- Check necessary conditions.
if mission:GetGroupStatus(self)==AUFTRAG.GroupStatus.SCHEDULED and (mission:IsReadyToGo() or self.legion) and (mission.importance==nil or mission.importance<=vip) and transport then
if isScheduled and isReadyToGo and isImportant and isTransport and isEscort then
return mission
end

View File

@ -130,13 +130,14 @@ _TARGETID=0
--- TARGET class version.
-- @field #string version
TARGET.version="0.5.1"
TARGET.version="0.5.2"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Add pseudo functions.
-- DONE: Initial object can be nil.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
@ -157,29 +158,19 @@ function TARGET:New(TargetObject)
-- Set UID.
self.uid=_TARGETID
-- Add object.
self:AddObject(TargetObject)
if TargetObject then
-- Get first target.
local Target=self.targets[1] --#TARGET.Object
-- Add object.
self:AddObject(TargetObject)
if not Target then
self:E("ERROR: No valid TARGET!")
return nil
end
-- Defaults.
self:SetPriority()
self:SetImportance()
-- Target Name.
self.name=self:GetTargetName(Target)
-- Target category.
self.category=self:GetTargetCategory(Target)
-- Log ID.
self.lid=string.format("TARGET #%03d [%s] | ", _TARGETID, tostring(self.category))
self.lid=string.format("TARGET #%03d | ", _TARGETID)
-- Start state.
self:SetStartState("Stopped")
@ -317,8 +308,15 @@ end
-- @param #TARGET self
-- @return #boolean If true, target is alive.
function TARGET:IsAlive()
local is=self:Is("Alive")
return is
for _,_target in pairs(self.targets) do
local target=_target --Ops.Target#TARGET.Object
if target.Status==TARGET.ObjectStatus.ALIVE then
return true
end
end
return false
end
--- Check if TARGET is destroyed.
@ -757,6 +755,13 @@ function TARGET:_AddObject(Object)
table.insert(self.targets, target)
if self.name==nil then
self.name=self:GetTargetName(target)
end
if self.category==nil then
self.category=self:GetTargetCategory(target)
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -1051,7 +1056,7 @@ end
-- @param #TARGET self
-- @return #string Name of the target usually the first object.
function TARGET:GetName()
return self.name
return self.name or "Unknown"
end
--- Get 2D vector.

View File

@ -1407,7 +1407,7 @@ function CONTROLLABLE:TaskEscort( FollowControllable, Vec3, LastWaypointIndex, E
DCSTask = {
id = 'Escort',
params = {
groupId = FollowControllable:GetID(),
groupId = FollowControllable and FollowControllable:GetID() or nil,
pos = Vec3,
lastWptIndexFlag = LastWaypointIndex and true or false,
lastWptIndex = LastWaypointIndex,