This commit is contained in:
Frank
2022-12-20 23:51:18 +01:00
parent 0adca414ce
commit 30e6542887
9 changed files with 1311 additions and 342 deletions

View File

@@ -665,9 +665,24 @@ function LEGION:CheckMissionQueue()
-- Look for first task that is not accomplished.
for _,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
-- Check if reinforcement is necessary.
local reinforce=false
if mission:IsExecuting() and mission.reinforce and mission.reinforce>0 then
local N=mission:CountOpsGroups()
local Nmin, Nmax=mission:GetRequiredAssets()
if N<Nmin then
reinforce=true
end
end
mission:CountOpsGroups()
-- Firstly, check if mission is due?
if mission:IsQueued(self) and mission:IsReadyToGo() and (mission.importance==nil or mission.importance<=vip) then
if (mission:IsQueued(self) or reinforce) and mission:IsReadyToGo() and (mission.importance==nil or mission.importance<=vip) then
-- Recruit best assets for the job.
local recruited, assets, legions=self:RecruitAssetsForMission(mission)
@@ -693,8 +708,11 @@ function LEGION:CheckMissionQueue()
-- Recruit carrier assets for transport.
local Transport=nil
if mission.NcarriersMin then
-- Transport legions.
local Legions=mission.transportLegions or {self}
-- Assign carrier assets for transport.
TransportAvail, Transport=self:AssignAssetsForTransport(Legions, assets, mission.NcarriersMin, mission.NcarriersMax, mission.transportDeployZone, mission.transportDisembarkZone)
end
@@ -706,8 +724,10 @@ function LEGION:CheckMissionQueue()
end
if EscortAvail and TransportAvail then
-- Got a mission.
self:MissionRequest(mission)
return true
else
-- Recruited assets but no requested escort available. Unrecruit assets!
@@ -2133,29 +2153,39 @@ function LEGION:RecruitAssetsForMission(Mission)
-- Payloads.
local Payloads=Mission.payloads
-- Get special escort legions and/or cohorts.
local Cohorts={}
for _,_legion in pairs(Mission.specialLegions or {}) do
local legion=_legion --Ops.Legion#LEGION
for _,_cohort in pairs(legion.cohorts) do
local cohort=_cohort --Ops.Cohort#COHORT
table.insert(Cohorts, cohort)
end
end
for _,_cohort in pairs(Mission.specialCohorts or {}) do
local cohort=_cohort --Ops.Cohort#COHORT
table.insert(Cohorts, cohort)
end
-- No escort cohorts/legions given ==> take own cohorts.
if #Cohorts==0 then
Cohorts=self.cohorts
end
-- Largest cargo bay available of available carrier assets if mission assets need to be transported.
local MaxWeight=nil
if Mission.NcarriersMin then
-- Get transport cohorts.
local Cohorts=LEGION._GetCohorts(Mission.transportLegions or {self}, Mission.transportCohorts or self.cohorts)
-- Filter cohorts that can actually perform transport missions.
local transportcohorts={}
for _,_cohort in pairs(Cohorts) do
local cohort=_cohort --Ops.Cohort#COHORT
-- Check if cohort can perform transport to target.
--TODO: Option to filter transport carrier asset categories, attributes and/or properties.
local can=LEGION._CohortCan(cohort, AUFTRAG.Type.OPSTRANSPORT, Categories, Attributes, Properties, nil, TargetVec2)
-- MaxWeight of cargo assets is limited by the largets available cargo bay. We don't want to select, e.g., tanks that cannot be transported by APCs or helos.
if can and (MaxWeight==nil or cohort.cargobayLimit>MaxWeight) then
MaxWeight=cohort.cargobayLimit
end
end
self:T(self.lid..string.format("Largest cargo bay available=%.1f", MaxWeight))
end
-- Get cohorts.
local Cohorts=LEGION._GetCohorts(Mission.specialLegions or {self}, Mission.specialCohorts or self.cohorts, Operation, OpsQueue)
-- Recuit assets.
local recruited, assets, legions=LEGION.RecruitCohortAssets(Cohorts, Mission.type, Mission.alert5MissionType, NreqMin, NreqMax, TargetVec2, Payloads,
Mission.engageRange, Mission.refuelSystem, nil, nil, nil, Mission.attributes, Mission.properties, {Mission.engageWeaponType})
Mission.engageRange, Mission.refuelSystem, nil, nil, MaxWeight, nil, Mission.attributes, Mission.properties, {Mission.engageWeaponType})
return recruited, assets, legions
end
@@ -2249,42 +2279,118 @@ function LEGION:RecruitAssetsForEscort(Mission, Assets)
return true
end
--- Get cohorts.
-- @param #table Legions Special legions.
-- @param #table Cohorts Special cohorts.
-- @param Ops.Operation#OPERATION Operation Operation.
-- @param #table OpsQueue Queue of operations.
-- @return #table Cohorts.
function LEGION._GetCohorts(Legions, Cohorts, Operation, OpsQueue)
OpsQueue=OpsQueue or {}
--- Function that check if a legion or cohort is part of an operation.
local function CheckOperation(LegionOrCohort)
-- No operations ==> no problem!
if #OpsQueue==0 then
return true
end
-- Cohort is not dedicated to a running(!) operation. We assume so.
local isAvail=true
-- Only available...
if Operation then
isAvail=false
end
for _,_operation in pairs(OpsQueue) do
local operation=_operation --Ops.Operation#OPERATION
-- Legion is assigned to this operation.
local isOps=operation:IsAssignedCohortOrLegion(LegionOrCohort)
if isOps and operation:IsRunning() then
-- Is dedicated.
isAvail=false
if Operation==nil then
-- No Operation given and this is dedicated to at least one operation.
return false
else
if Operation.uid==operation.uid then
-- Operation given and is part of it.
return true
end
end
end
end
return isAvail
end
-- Chosen cohorts.
local cohorts={}
-- Check if there are any special legions and/or cohorts.
if (Legions and #Legions>0) or (Cohorts and #Cohorts>0) then
-- Add cohorts of special legions.
for _,_legion in pairs(Legions or {}) do
local legion=_legion --Ops.Legion#LEGION
-- Check that runway is operational.
local Runway=legion:IsAirwing() and legion:IsRunwayOperational() or true
-- Legion has to be running.
if legion:IsRunning() and Runway then
-- Add cohorts of legion.
for _,_cohort in pairs(legion.cohorts) do
local cohort=_cohort --Ops.Cohort#COHORT
if (CheckOperation(cohort.legion) or CheckOperation(cohort)) and not UTILS.IsInTable(cohorts, cohort, "name") then
table.insert(cohorts, cohort)
end
end
end
end
-- Add special cohorts.
for _,_cohort in pairs(Cohorts or {}) do
local cohort=_cohort --Ops.Cohort#COHORT
if CheckOperation(cohort) and not UTILS.IsInTable(cohorts, cohort, "name") then
table.insert(cohorts, cohort)
end
end
end
return cohorts
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Recruiting and Optimization Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Recruit assets from Cohorts for the given parameters. **NOTE** that we set the `asset.isReserved=true` flag so it cant be recruited by anyone else.
-- @param #table Cohorts Cohorts included.
-- @param #string MissionTypeRecruit Mission type for recruiting the cohort assets.
-- @param #string MissionTypeOpt Mission type for which the assets are optimized. Default is the same as `MissionTypeRecruit`.
-- @param #number NreqMin Minimum number of required assets.
-- @param #number NreqMax Maximum number of required assets.
-- @param DCS#Vec2 TargetVec2 Target position as 2D vector.
-- @param #table Payloads Special payloads.
-- @param #number RangeMax Max range in meters.
-- @param #number RefuelSystem Refuelsystem.
-- @param #number CargoWeight Cargo weight for recruiting transport carriers.
-- @param #number TotalWeight Total cargo weight in kg.
-- @param #table Categories Group categories.
-- @param Ops.Cohort#COHORT Cohort The Cohort.
-- @param #string MissionType Misson type(s).
-- @param #table Categories Group categories.
-- @param #table Attributes Group attributes. See `GROUP.Attribute.`
-- @param #table Properties DCS attributes.
-- @param #table WeaponTypes Bit of weapon types.
-- @return #boolean If `true` enough assets could be recruited.
-- @return #table Recruited assets. **NOTE** that we set the `asset.isReserved=true` flag so it cant be recruited by anyone else.
-- @return #table Legions of recruited assets.
function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt, NreqMin, NreqMax, TargetVec2, Payloads, RangeMax, RefuelSystem, CargoWeight, TotalWeight, Categories, Attributes, Properties, WeaponTypes)
-- @param DCS#Vec2 TargetVec2 Target position.
-- @param RangeMax Max range in meters.
-- @param #number RefuelSystem Refueling system (boom or probe).
-- @param #number CargoWeight Cargo weight [kg]. This checks the cargo bay of the cohort assets and ensures that it is large enough to carry the given cargo weight.
-- @param #number MaxWeight Max weight [kg]. This checks whether the cohort asset group is not too heavy.
-- @return #boolean Returns `true` if given cohort can meet all requirements.
function LEGION._CohortCan(Cohort, MissionType, Categories, Attributes, Properties, WeaponTypes, TargetVec2, RangeMax, RefuelSystem, CargoWeight, MaxWeight)
-- The recruited assets.
local Assets={}
-- Legions of recruited assets.
local Legions={}
-- Set MissionTypeOpt to Recruit if nil.
if MissionTypeOpt==nil then
MissionTypeOpt=MissionTypeRecruit
end
--- Function to check category.
local function CheckCategory(_cohort)
local cohort=_cohort --Ops.Cohort#COHORT
@@ -2350,9 +2456,9 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
return true
end
end
-- Loops over cohorts.
for _,_cohort in pairs(Cohorts) do
--- Function to check range.
local function CheckRange(_cohort)
local cohort=_cohort --Ops.Cohort#COHORT
-- Distance to target.
@@ -2362,50 +2468,175 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
local Rmax=cohort:GetMissionRange(WeaponTypes)
local InRange=(RangeMax and math.max(RangeMax, Rmax) or Rmax) >= TargetDistance
return InRange
end
--- Function to check weapon type.
local function CheckRefueling(_cohort)
local cohort=_cohort --Ops.Cohort#COHORT
-- Has the requested refuelsystem?
local Refuel=RefuelSystem~=nil and (RefuelSystem==cohort.tankerSystem) or true
--local Refuel=RefuelSystem~=nil and (RefuelSystem==cohort.tankerSystem) or true
-- STRANGE: Why did the above line did not give the same result?! Above Refuel is always true!
local Refuel=true
if RefuelSystem then
if cohort.tankerSystem then
Refuel=RefuelSystem==cohort.tankerSystem
return RefuelSystem==cohort.tankerSystem
else
Refuel=false
return false
end
else
return true
end
end
--- Function to check cargo weight.
local function CheckCargoWeight(_cohort)
local cohort=_cohort --Ops.Cohort#COHORT
if CargoWeight~=nil then
return cohort.cargobayLimit>=CargoWeight
else
return true
end
end
--- Function to check cargo weight.
local function CheckMaxWeight(_cohort)
local cohort=_cohort --Ops.Cohort#COHORT
if MaxWeight~=nil then
cohort:I(string.format("Cohort weight=%.1f | max weight=%.1f", cohort.weightAsset, MaxWeight))
return cohort.weightAsset<=MaxWeight
else
return true
end
end
-- Is capable of the mission type?
local can=AUFTRAG.CheckMissionCapability(MissionType, Cohort.missiontypes)
if can then
can=CheckCategory(Cohort)
else
env.info(string.format("Cohort %s cannot because of mission types", Cohort.name))
return false
end
if can then
if MissionType==AUFTRAG.Type.RELOCATECOHORT then
can=Cohort:IsRelocating()
else
can=Cohort:IsOnDuty()
end
-- Is capable of the mission type?
local Capable=AUFTRAG.CheckMissionCapability({MissionTypeRecruit}, cohort.missiontypes)
else
env.info(string.format("Cohort %s cannot because of category", Cohort.name))
BASE:I(Categories)
BASE:I(Cohort.category)
return false
end
if can then
can=CheckAttribute(Cohort)
else
env.info(string.format("Cohort %s cannot because of readyiness", Cohort.name))
return false
end
if can then
can=CheckProperty(Cohort)
else
env.info(string.format("Cohort %s cannot because of attribute", Cohort.name))
return false
end
if can then
can=CheckWeapon(Cohort)
else
env.info(string.format("Cohort %s cannot because of property", Cohort.name))
return false
end
if can then
can=CheckRange(Cohort)
else
env.info(string.format("Cohort %s cannot because of weapon type", Cohort.name))
return false
end
if can then
can=CheckRefueling(Cohort)
else
env.info(string.format("Cohort %s cannot because of range", Cohort.name))
return false
end
if can then
can=CheckCargoWeight(Cohort)
else
env.info(string.format("Cohort %s cannot because of refueling system", Cohort.name))
return false
end
if can then
can=CheckMaxWeight(Cohort)
else
env.info(string.format("Cohort %s cannot because of cargo weight", Cohort.name))
return false
end
if can then
return true
else
env.info(string.format("Cohort %s cannot because of max weight", Cohort.name))
return false
end
return nil
end
--- Recruit assets from Cohorts for the given parameters. **NOTE** that we set the `asset.isReserved=true` flag so it cant be recruited by anyone else.
-- @param #table Cohorts Cohorts included.
-- @param #string MissionTypeRecruit Mission type for recruiting the cohort assets.
-- @param #string MissionTypeOpt Mission type for which the assets are optimized. Default is the same as `MissionTypeRecruit`.
-- @param #number NreqMin Minimum number of required assets.
-- @param #number NreqMax Maximum number of required assets.
-- @param DCS#Vec2 TargetVec2 Target position as 2D vector.
-- @param #table Payloads Special payloads.
-- @param #number RangeMax Max range in meters.
-- @param #number RefuelSystem Refuelsystem.
-- @param #number CargoWeight Cargo weight for recruiting transport carriers.
-- @param #number TotalWeight Total cargo weight in kg.
-- @param #number MaxWeight Max weight [kg] of the asset group.
-- @param #table Categories Group categories.
-- @param #table Attributes Group attributes. See `GROUP.Attribute.`
-- @param #table Properties DCS attributes.
-- @param #table WeaponTypes Bit of weapon types.
-- @return #boolean If `true` enough assets could be recruited.
-- @return #table Recruited assets. **NOTE** that we set the `asset.isReserved=true` flag so it cant be recruited by anyone else.
-- @return #table Legions of recruited assets.
function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt, NreqMin, NreqMax, TargetVec2, Payloads, RangeMax, RefuelSystem, CargoWeight, TotalWeight, MaxWeight, Categories, Attributes, Properties, WeaponTypes)
-- The recruited assets.
local Assets={}
-- Legions of recruited assets.
local Legions={}
-- Set MissionTypeOpt to Recruit if nil.
if MissionTypeOpt==nil then
MissionTypeOpt=MissionTypeRecruit
end
-- Can carry the cargo?
local CanCarry=CargoWeight and cohort.cargobayLimit>=CargoWeight or true
-- Loops over cohorts.
for _,_cohort in pairs(Cohorts) do
local cohort=_cohort --Ops.Cohort#COHORT
-- Right category.
local RightCategory=CheckCategory(cohort)
-- Right attribute.
local RightAttribute=CheckAttribute(cohort)
-- Right property (DCS attribute).
local RightProperty=CheckProperty(cohort)
-- Right weapon type.
local RightWeapon=CheckWeapon(cohort)
-- Cohort ready to execute mission.
local Ready=cohort:IsOnDuty()
if MissionTypeRecruit==AUFTRAG.Type.RELOCATECOHORT then
Ready=cohort:IsRelocating()
Capable=true
end
-- Debug info.
cohort:T(cohort.lid..string.format("State=%s: Capable=%s, InRange=%s, Refuel=%s, CanCarry=%s, Category=%s, Attribute=%s, Property=%s, Weapon=%s",
cohort:GetState(), tostring(Capable), tostring(InRange), tostring(Refuel), tostring(CanCarry), tostring(RightCategory), tostring(RightAttribute), tostring(RightProperty), tostring(RightWeapon)))
-- Check if cohort can do the mission.
local can=LEGION._CohortCan(cohort, MissionTypeRecruit, Categories, Attributes, Properties, WeaponTypes, TargetVec2, RangeMax, RefuelSystem, CargoWeight, MaxWeight)
-- Check OnDuty, capable, in range and refueling type (if TANKER).
if Ready and Capable and InRange and Refuel and CanCarry and RightCategory and RightAttribute and RightProperty and RightWeapon then
if can then
-- Recruit assets from cohort.
local assets, npayloads=cohort:RecruitAssets(MissionTypeRecruit, 999)
@@ -2456,23 +2687,30 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
-- Found enough assets
---
-- Add assets to mission.
-- Total cargo bay of all carrier assets.
local cargobay=0
-- Add assets to mission.
for i=1,Nassets do
local asset=Assets[i] --Functional.Warehouse#WAREHOUSE.Assetitem
-- Asset is reserved and will not be picked for other missions.
asset.isReserved=true
-- Add legion.
Legions[asset.legion.alias]=asset.legion
-- Check if total cargo weight was given.
if TotalWeight then
-- Number of
local N=math.floor(asset.cargobaytot/asset.nunits / CargoWeight)*asset.nunits
--env.info(string.format("cargobaytot=%d, cargoweight=%d ==> N=%d", asset.cargobaytot, CargoWeight, N))
-- Sum up total cargo bay of all carrier assets.
cargobay=cargobay + N*CargoWeight
-- Check if enough carrier assets were found to transport all cargo.
if cargobay>=TotalWeight then
--env.info(string.format("FF found enough assets to transport all cargo! N=%d [%d], cargobay=%.1f >= %.1f kg total weight", i, Nassets, cargobay, TotalWeight))
Nassets=i
@@ -2580,7 +2818,7 @@ function LEGION:AssignAssetsForEscort(Cohorts, Assets, NescortMin, NescortMax, M
TargetTypes=TargetTypes or targetTypes
-- Recruit escort asset for the mission asset.
local Erecruited, eassets, elegions=LEGION.RecruitCohortAssets(Cohorts, AUFTRAG.Type.ESCORT, MissionType, NescortMin, NescortMax, TargetVec2, nil, nil, nil, nil, nil, Categories)
local Erecruited, eassets, elegions=LEGION.RecruitCohortAssets(Cohorts, AUFTRAG.Type.ESCORT, MissionType, NescortMin, NescortMax, TargetVec2, nil, nil, nil, nil, nil, nil, Categories)
if Erecruited then
Escorts[asset.spawngroupname]={EscortLegions=elegions, EscortAssets=eassets, ecategory=asset.category}
@@ -2685,24 +2923,8 @@ function LEGION:AssignAssetsForTransport(Legions, CargoAssets, NcarriersMin, Nca
-- Is an escort requested in the first place?
if NcarriersMin and NcarriersMax and (NcarriersMin>0 or NcarriersMax>0) then
-- Cohorts.
local Cohorts={}
for _,_legion in pairs(Legions) do
local legion=_legion --Ops.Legion#LEGION
-- Check that runway is operational.
local Runway=legion:IsAirwing() and legion:IsRunwayOperational() or true
if legion:IsRunning() and Runway then
-- Loops over cohorts.
for _,_cohort in pairs(legion.cohorts) do
local cohort=_cohort --Ops.Cohort#COHORT
table.insert(Cohorts, cohort)
end
end
end
-- Get cohorts.
local Cohorts=LEGION._GetCohorts(Legions)
-- Get all legions and heaviest cargo group weight
local CargoLegions={} ; local CargoWeight=nil ; local TotalWeight=0
@@ -2714,13 +2936,17 @@ function LEGION:AssignAssetsForTransport(Legions, CargoAssets, NcarriersMin, Nca
end
TotalWeight=TotalWeight+asset.weight
end
-- Debug info.
self:T(self.lid..string.format("Cargo weight=%.1f", CargoWeight))
self:T(self.lid..string.format("Total weight=%.1f", TotalWeight))
-- Target is the deploy zone.
local TargetVec2=DeployZone:GetVec2()
-- Recruit assets and legions.
local TransportAvail, CarrierAssets, CarrierLegions=
LEGION.RecruitCohortAssets(Cohorts, AUFTRAG.Type.OPSTRANSPORT, nil, NcarriersMin, NcarriersMax, TargetVec2, nil, nil, nil, CargoWeight, TotalWeight, Categories, Attributes, Properties)
LEGION.RecruitCohortAssets(Cohorts, AUFTRAG.Type.OPSTRANSPORT, nil, NcarriersMin, NcarriersMax, TargetVec2, nil, nil, nil, CargoWeight, TotalWeight, nil, Categories, Attributes, Properties)
if TransportAvail then
@@ -2922,7 +3148,7 @@ function LEGION._OptimizeAssetSelection(assets, MissionType, TargetVec2, Include
local text=string.format("Optimized %d assets for %s mission/transport (payload=%s):", #assets, MissionType, tostring(IncludePayload))
for i,Asset in pairs(assets) do
local asset=Asset --Functional.Warehouse#WAREHOUSE.Assetitem
text=text..string.format("\n%s %s: score=%d", asset.squadname, asset.spawngroupname, asset.score)
text=text..string.format("\n%s %s: score=%d", asset.squadname, asset.spawngroupname, asset.score or -1)
asset.score=nil
end
env.info(text)