diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 7483f7435..c6c301994 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -91,7 +91,13 @@ -- @field Core.Set#SET_GROUP transportGroupSet Groups to be transported. -- @field Core.Point#COORDINATE transportPickup Coordinate where to pickup the cargo. -- @field Core.Point#COORDINATE transportDropoff Coordinate where to drop off the cargo. +-- -- @field Ops.OpsTransport#OPSTRANSPORT opstransport OPS transport assignment. +-- @field #number NcarriersMin Min number of required carrier assets. +-- @field #number NcarriersMax Max number of required carrier assets. +-- @field Core.Zone#ZONE transportDeployZone Deploy zone of an OPSTRANSPORT. +-- @field Core.Zone#ZONE transportDisembarkZone Disembark zone of an OPSTRANSPORT. +-- @field #table transportLegions Legions explicitly requested for providing carrier assets. -- -- @field #number artyRadius Radius in meters. -- @field #number artyShots Number of shots fired. @@ -588,7 +594,7 @@ function AUFTRAG:New(Type) self:SetPriority() self:SetTime() self:SetRequiredAssets() - self:SetRequiredCarriers() + --self:SetRequiredCarriers() self.engageAsGroup=true self.dTevaluate=5 @@ -2182,14 +2188,11 @@ end -- @param #number NcarriersMin Number of carriers *at least* required. Default 1. -- @param #number NcarriersMax Number of carriers *at most* used for transportation. Default is same as `NcarriersMin`. -- @return #AUFTRAG self -function AUFTRAG:SetTransportForAssets(DeployZone, DisembarkZone, NcarriersMin, NcarriersMax) +function AUFTRAG:SetRequiredTransport(DeployZone, DisembarkZone, NcarriersMin, NcarriersMax) -- OPS transport from pickup to deploy zone. - self.opstransport=OPSTRANSPORT:New(nil, nil, DeployZone) - - if DisembarkZone then - self.opstransport:SetDisembarkZone(DisembarkZone) - end + self.transportDeployZone=DeployZone + self.transportDisembarkZone=DisembarkZone -- Set required carriers. self:SetRequiredCarriers(NcarriersMin, NcarriersMax) @@ -2226,18 +2229,13 @@ end -- @return #AUFTRAG self function AUFTRAG:SetRequiredCarriers(NcarriersMin, NcarriersMax) - self.nCarriersMin=NcarriersMin or 1 + self.NcarriersMin=NcarriersMin or 1 - self.nCarriersMax=NcarriersMax or self.nCarriersMin + self.NcarriersMax=NcarriersMax or self.NcarriersMin -- Ensure that max is at least equal to min. - if self.nCarriersMax %s", self.strategy, Strategy)) end @@ -1563,80 +1563,31 @@ function CHIEF:RecruitAssetsForZone(OpsZone, MissionType, NassetsMin, NassetsMax if recruitedInf then env.info(string.format("Recruited %d assets from for PATROL mission", #assetsInf)) - - -- Get max weight. - local weightMax=nil - for _,_asset in pairs(assetsInf) do - local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem - if weightMax==nil or weightMax<=asset.weight then - weightMax=asset.weight - end - end - - -- Recruite carrier assets. This need to be ground or helicopters to deploy at a zone. - local recruitedTrans, assetsTrans, legionsTrans= - LEGION.RecruitCohortAssets(Cohorts, AUFTRAG.Type.OPSTRANSPORT, nil, 1, 1, TargetVec2, nil, nil, nil, weightMax, {Group.Category.HELICOPTER, Group.Category.GROUND}) - - local transport=nil --Ops.OpsTransport#OPSTRANSPORT - if recruitedTrans then - env.info(string.format("Recruited %d assets for OPSTRANSPORT mission", #assetsTrans)) - - -- Create an OPSTRANSPORT assignment. - transport=OPSTRANSPORT:New(nil, nil, OpsZone.zone) - - -- Add cargo assets to transport. - for _,_legion in pairs(legionsInf) do - local legion=_legion --Ops.Legion#LEGION - -- Pickup at spawnzone or at airbase if the legion warehouse has one. - local pickupzone=legion.spawnzone - if legion.airbase and legion:IsRunwayOperational() then - pickupzone=ZONE_AIRBASE:New(legion.airbasename, 4000) - end - - local tpz=transport:AddTransportZoneCombo(pickupzone, OpsZone.zone) - - for _,_asset in pairs(assetsInf) do - local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem - if asset.legion.alias==legion.alias then - transport:AddAssetCargo(asset, tpz) - end - end - end - - -- Add carrier assets. - for _,_asset in pairs(assetsTrans) do - local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem - transport:AddAsset(asset) - end - - - -- Assign TRANSPORT to legions. This also sends the request for the assets. - for _,_legion in pairs(legionsTrans) do - local legion=_legion --Ops.Legion#LEGION - self.commander:TransportAssign(legion, transport) - end - - else - -- Uncrecruite - LEGION.UnRecruitAssets(assetsTrans) - end + -- Recruit transport assets for infantry. + local recruitedTrans, transport=LEGION.AssignAssetsForTransport(self.commander, self.commander.legions, assetsInf, 1, 1, OpsZone.zone, nil, {Group.Category.HELICOPTER, Group.Category.GROUND}) + -- Create Patrol zone mission. local mission=AUFTRAG:NewPATROLZONE(OpsZone.zone) mission:SetEngageDetected() + -- Add assets to mission. for _,asset in pairs(assetsInf) do mission:AddAsset(asset) end + -- Attach OPS transport to mission. mission.opstransport=transport + -- Assign mission to legions. for _,_legion in pairs(legionsInf) do local legion=_legion --Ops.Legion#LEGION self.commander:MissionAssign(legion, mission) end + -- Attach mission to ops zone. + -- TODO: Need a better way! OpsZone.missionPatrol=mission return true diff --git a/Moose Development/Moose/Ops/Commander.lua b/Moose Development/Moose/Ops/Commander.lua index e73e9381d..d57bab942 100644 --- a/Moose Development/Moose/Ops/Commander.lua +++ b/Moose Development/Moose/Ops/Commander.lua @@ -645,9 +645,6 @@ end -- @param #COMMANDER self function COMMANDER:CheckMissionQueue() - -- TODO: Sort mission queue. wrt what? Threat level? - -- Currently, we sort wrt to priority. So that should reflect the threat level of the mission target. - -- Number of missions. local Nmissions=#self.missionqueue @@ -708,69 +705,18 @@ function COMMANDER:CheckMissionQueue() -- Escort requested and available. if EscortAvail then - -- Check if mission assets need a transport. - if mission.opstransport then + -- Check if mission assets need a transport. + if mission.NcarriersMin then - -- Weight of the heaviest cargo group. Necessary condition that this fits into on carrier unit! - local weightGroup=0 - - -- Calculate the max weight of the cargo assets. - for _,_asset in pairs(assets) do - local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem - local weight=asset.weight - if weight>weightGroup then - weightGroup=weight - end - end + -- Recruit carrier assets for transport. + local Transport=nil + local Legions=mission.transportLegions or self.legions - env.info(string.format("FF mission requires transport for cargo weight %d", weightGroup)) + TransportAvail, Transport=LEGION.AssignAssetsForTransport(self, Legions, assets, mission.NcarriersMin, mission.NcarriersMax, mission.transportDeployZone, mission.transportDisembarkZone) - -- Recruit transport assets. - local TransportAvail, assetsTrans, legionsTrans=self:RecruitAssetsForTransport(mission.opstransport, weightGroup) - - if TransportAvail then - - env.info(string.format("FF Transport available with %d carrier assets", #assetsTrans)) - - -- Add cargo assets to transport. - for _,_legion in pairs(legions) do - local legion=_legion --Ops.Legion#LEGION - - -- Set pickup zone to spawn zone or airbase if the legion has one that is operational. - local pickupzone=legion.spawnzone - if legion.airbase and legion:IsRunwayOperational() then - pickupzone=ZONE_AIRBASE:New(legion.airbasename, 4000) - end - - -- Add TZC from legion spawn zone to deploy zone. - local tpz=mission.opstransport:AddTransportZoneCombo(pickupzone, mission.opstransport:GetDeployZone()) - mission.opstransport:SetEmbarkZone(legion.spawnzone, tpz) - - -- Add cargo assets to transport. - for _,_asset in pairs(assets) do - local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem - if asset.legion.alias==legion.alias then - mission.opstransport:AddAssetCargo(asset, tpz) - end - end - end - - -- Add carrier assets. - for _,_asset in pairs(assetsTrans) do - local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem - mission.opstransport:AddAsset(asset) - end - - - -- Assign TRANSPORT to legions. This also sends the request for the assets. - for _,_legion in pairs(legionsTrans) do - local legion=_legion --Ops.Legion#LEGION - self:TransportAssign(legion, mission.opstransport) - end - - else - -- Uncrecruit transport assets. - LEGION.UnRecruitAssets(assetsTrans) + -- Add opstransport to mission. + if TransportAvail and Transport then + mission.opstransport=Transport end end @@ -856,102 +802,34 @@ 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. +-- @param #table Assets Table of assets to be escorted. -- @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.specialLegions 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 - - -- Assign mission to legion. - self:MissionAssign(legion, escort) + + -- Cohorts. + local Cohorts=Mission.squadrons + if not Cohorts then + Cohorts={} + for _,_legion in pairs(Mission.specialLegions 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 - - -- 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 end - else - -- No escort required. - return true - end + -- Call LEGION function but provide COMMANDER as self. + local assigned=LEGION.AssignAssetsForEscort(self, Cohorts, Assets, Mission.NescortMin, Mission.NescortMin) + + return assigned + end + return true end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1072,7 +950,7 @@ end -- @return #table Legions that have recruited assets. function COMMANDER:RecruitAssetsForTransport(Transport, CargoWeight) - if weightGroup==0 then + if CargoWeight==0 then -- No cargo groups! return false, {}, {} end @@ -1221,6 +1099,30 @@ function COMMANDER:GetLegionsForMission(Mission) return legions end +--- Get assets on given mission or missions. +-- @param #COMMANDER self +-- @param #table MissionTypes Types on mission to be checked. Default all. +-- @return #table Assets on pending requests. +function COMMANDER:GetAssetsOnMission(MissionTypes) + + local assets={} + + for _,_mission in pairs(self.missionqueue) do + local mission=_mission --Ops.Auftrag#AUFTRAG + + -- Check if this mission type is requested. + if AUFTRAG.CheckMissionType(mission.type, MissionTypes) then + + for _,_asset in pairs(mission.assets or {}) do + local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem + table.insert(assets, asset) + end + end + end + + return assets +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/Moose Development/Moose/Ops/Legion.lua b/Moose Development/Moose/Ops/Legion.lua index d908e11a5..ee8d7e74d 100644 --- a/Moose Development/Moose/Ops/Legion.lua +++ b/Moose Development/Moose/Ops/Legion.lua @@ -83,9 +83,11 @@ function LEGION:New(WarehouseName, LegionName) -- From State --> Event --> To State self:AddTransition("*", "MissionRequest", "*") -- Add a (mission) request to the warehouse. self:AddTransition("*", "MissionCancel", "*") -- Cancel mission. + self:AddTransition("*", "MissionAssign", "*") -- Recruit assets, add to queue and request immediately. self:AddTransition("*", "TransportRequest", "*") -- Add a (mission) request to the warehouse. self:AddTransition("*", "TransportCancel", "*") -- Cancel transport. + self:AddTransition("*", "TransportAssign", "*") -- Recruit assets, add to queue and request immediately. self:AddTransition("*", "OpsOnMission", "*") -- An OPSGROUP was send on a Mission (AUFTRAG). @@ -118,18 +120,27 @@ function LEGION:New(WarehouseName, LegionName) -- @param #LEGION self -- @param Ops.Auftrag#AUFTRAG Mission The mission. - --- Triggers the FSM event "MissionCancel" after a delay. - -- @function [parent=#LEGION] __MissionCancel + + --- Triggers the FSM event "MissionAssign". + -- @function [parent=#LEGION] MissionAssign -- @param #LEGION self - -- @param #number delay Delay in seconds. + -- @param Ops.Legion#LEGION Legion The legion from which the mission assets are requested. -- @param Ops.Auftrag#AUFTRAG Mission The mission. - --- On after "MissionCancel" event. - -- @function [parent=#LEGION] OnAfterMissionCancel + --- Triggers the FSM event "MissionAssign" after a delay. + -- @function [parent=#LEGION] __MissionAssign + -- @param #LEGION self + -- @param #number delay Delay in seconds. + -- @param Ops.Legion#LEGION Legion The legion from which the mission assets are requested. + -- @param Ops.Auftrag#AUFTRAG Mission The mission. + + --- On after "MissionAssign" event. + -- @function [parent=#LEGION] OnAfterMissionAssign -- @param #LEGION self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. + -- @param Ops.Legion#LEGION Legion The legion from which the mission assets are requested. -- @param Ops.Auftrag#AUFTRAG Mission The mission. @@ -153,6 +164,44 @@ function LEGION:New(WarehouseName, LegionName) -- @param Ops.Auftrag#AUFTRAG Mission The mission. + --- Triggers the FSM event "MissionCancel" after a delay. + -- @function [parent=#LEGION] __MissionCancel + -- @param #LEGION self + -- @param #number delay Delay in seconds. + -- @param Ops.Auftrag#AUFTRAG Mission The mission. + + --- On after "MissionCancel" event. + -- @function [parent=#LEGION] OnAfterMissionCancel + -- @param #LEGION self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.Auftrag#AUFTRAG Mission The mission. + + + --- Triggers the FSM event "TransportAssign". + -- @function [parent=#LEGION] TransportAssign + -- @param #LEGION self + -- @param Ops.Legion#LEGION Legion The legion from which the transport assets are requested. + -- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. + + --- Triggers the FSM event "TransportAssign" after a delay. + -- @function [parent=#LEGION] __TransportAssign + -- @param #LEGION self + -- @param #number delay Delay in seconds. + -- @param Ops.Legion#LEGION Legion The legion from which the transport assets are requested. + -- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. + + --- On after "TransportAssign" event. + -- @function [parent=#LEGION] OnAfterTransportAssign + -- @param #LEGION self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.Legion#LEGION Legion The legion from which the transport assets are requested. + -- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. + + --- Triggers the FSM event "TransportRequest". -- @function [parent=#LEGION] TransportRequest -- @param #LEGION self @@ -274,30 +323,6 @@ function LEGION:AddMission(Mission) if Mission.type==AUFTRAG.Type.ALERT5 then Mission:_TargetFromObject(self:GetCoordinate()) end - - -- Add ops transport to transport Legions. - if Mission.opstransport and false then - - local PickupZone=self.spawnzone - local DeployZone=Mission.opstransport.tzcDefault.DeployZone - - -- Add a new TZC: from pickup here to the deploy zone. - local tzc=Mission.opstransport:AddTransportZoneCombo(PickupZone, DeployZone) - - --TODO: Depending on "from where to where" the assets need to transported, we need to set ZONE_AIRBASE etc. - - --Mission.opstransport:SetPickupZone(self.spawnzone) - --Mission.opstransport:SetEmbarkZone(self.spawnzone) - - -- Loop over all defined transport legions. - for _,_legion in pairs(Mission.transportLegions) do - local legion=_legion --Ops.Legion#LEGION - - -- Add ops transport to legion. - legion:AddOpsTransport(Mission.opstransport) - end - - end -- Add mission to queue. table.insert(self.missionqueue, Mission) @@ -481,20 +506,38 @@ function LEGION:_GetNextMission() -- 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 - + -- Recruit asset for escorting recruited mission assets. local EscortAvail=self:RecruitAssetsForEscort(mission, assets) + + -- Transport available (or not required). + local TransportAvail=true -- Is escort required and available? if EscortAvail then + + -- Recruit carrier assets for transport. + local Transport=nil + if mission.NcarriersMin then + local Legions=mission.transportLegions or {self} + TransportAvail, Transport=self:AssignAssetsForTransport(Legions, assets, mission.NcarriersMin, mission.NcarriersMax, mission.transportDeployZone, mission.transportDisembarkZone) + end + + -- Add opstransport to mission. + if TransportAvail and Transport then + mission.opstransport=Transport + end + + end + + if EscortAvail and TransportAvail then -- Got a missin. - return mission + return mission else -- Recruited assets but no requested escort available. Unrecruit assets! - LEGION.UnRecruitAssets(assets, mission) + LEGION.UnRecruitAssets(assets, mission) end end -- recruited mission assets @@ -552,7 +595,6 @@ function LEGION:_GetNextTransport() -- Add asset to transport. for _,_asset in pairs(assets) do local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem - asset.isReserved=true transport:AddAsset(asset) end @@ -572,6 +614,27 @@ end -- FSM Events ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- On after "MissionAssign" event. Mission is added to a LEGION mission queue and already requested. Needs assets to be added to the mission already. +-- @param #LEGION self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Ops.Legion#LEGION Legion The LEGION. +-- @param Ops.Auftrag#AUFTRAG Mission The mission. +function LEGION:onafterMissionAssign(From, Event, To, Legion, Mission) + + -- Debug info. + self:I(self.lid..string.format("Assigning mission %s (%s) to legion %s", Mission.name, Mission.type, Legion.alias)) + + -- Add mission to legion. + Legion:AddMission(Mission) + + -- Directly request the mission as the assets have already been selected. + Legion:MissionRequest(Mission) + +end + + --- On after "MissionRequest" event. Performs a self request to the warehouse for the mission assets. Sets mission status to REQUESTED. -- @param #LEGION self -- @param #string From From state. @@ -683,7 +746,27 @@ function LEGION:onafterMissionRequest(From, Event, To, Mission) end ---- On after "MissionRequest" event. Performs a self request to the warehouse for the mission assets. Sets mission status to REQUESTED. +--- On after "TransportAssign" event. Transport is added to a LEGION transport queue and assets are requested from the LEGION warehouse. +-- @param #LEGION self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Ops.Legion#LEGION Legion The LEGION. +-- @param Ops.OpsTransport#OPSTRANSPORT The transport. +function LEGION:onafterTransportAssign(From, Event, To, Legion, Transport) + + -- Debug info. + self:I(self.lid..string.format("Assigning transport %d to legion %s", Transport.uid, Legion.alias)) + + -- Add mission to legion. + Legion:AddOpsTransport(Transport) + + -- Directly request the mission as the assets have already been selected. + Legion:TransportRequest(Transport) + +end + +--- On after "TransportRequest" event. Performs a self request to the warehouse for the transport assets. Sets transport status to REQUESTED. -- @param #LEGION self -- @param #string From From state. -- @param #string Event Event. @@ -987,6 +1070,7 @@ function LEGION:onafterAssetSpawned(From, Event, To, group, asset, request) -- Check if we have a cohort or if this was some other request. if cohort then + -- Debug info. self:I(self.lid..string.format("Cohort asset spawned %s", asset.spawngroupname)) -- Create a flight group. @@ -1666,6 +1750,8 @@ end -- @param #LEGION self -- @param Ops.OpsTransport#OPSTRANSPORT Transport The OPS transport. -- @return #boolean If `true`, enough assets could be recruited. +-- @return #table assets Recruited assets. +-- @return #table legions Legions of recruited assets. function LEGION:RecruitAssetsForTransport(Transport) -- Get all undelivered cargo ops groups. @@ -1716,82 +1802,15 @@ function LEGION:RecruitAssetsForEscort(Mission, Assets) -- 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={} + --TODO: Maybe add escortCohorts as mission option? - 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 + -- Call LEGION function but provide COMMANDER as self. + local assigned=LEGION.AssignAssetsForEscort(self, self.cohorts, Assets, Mission.NescortMin, Mission.NescortMin) - -- 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 + return assigned + end + return true end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -2001,6 +2020,215 @@ function LEGION.UnRecruitAssets(Assets, Mission) end +--- Recruit and assign assets performing an escort mission for a given asset list. Note that each asset gets an escort. +-- @param #LEGION self +-- @param #table Cohorts Cohorts for escorting assets. +-- @param #table Assets Table of assets to be escorted. +-- @param #number NescortMin Min number of escort groups required per escorted asset. +-- @param #number NescortMax Max number of escort groups required per escorted asset. +-- @return #boolean If `true`, enough assets could be recruited or no escort was required in the first place. +function LEGION:AssignAssetsForEscort(Cohorts, Assets, NescortMin, NescortMax) + + -- Is an escort requested in the first place? + if NescortMin and NescortMax and (NescortMin>0 or NescortMax>0) then + + -- Debug info. + self:I(self.lid..string.format("Reqested escort for %d assets from %d cohorts. Required escort assets=%d-%d", #Assets, #Cohorts, NescortMin, NescortMax)) + + -- Escorts for each asset. + local Escorts={} + + local EscortAvail=true + for _,_asset in pairs(Assets) do + local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem + + -- Target vector is the legion of the asset. + local TargetVec2=asset.legion:GetVec2() + + -- We want airplanes for airplanes and helos for everything else. + local Categories={Group.Category.HELICOPTER} + if asset.category==Group.Category.AIRPLANE then + Categories={Group.Category.AIRPLANE} + end + + -- Recruit escort asset for the mission asset. + local Erecruited, eassets, elegions=LEGION.RecruitCohortAssets(Cohorts, AUFTRAG.Type.ESCORT, nil, NescortMin, NescortMax, TargetVec2, nil, nil, nil, nil, Categories) + + 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 + escort:AddAsset(asset) + N=N+1 + end + + -- Assign mission to legion. + self:MissionAssign(legion, escort) + end + end + + -- Debug info. + self:I(self.lid..string.format("Recruited %d escort assets", N)) + + -- Yup! + return true + else + + -- Debug info. + self:I(self.lid..string.format("Could not get at least one escort!")) + + -- 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 + +--- Recruit and assign assets performing an OPSTRANSPORT for a given asset list. +-- @param #LEGION self +-- @param #table Legions Transport legions. +-- @param #table CargoAssets Weight of the heaviest cargo group to be transported. +-- @param #number NcarriersMin Min number of carrier assets. +-- @param #number NcarriersMax Max number of carrier assets. +-- @param Core.Zone#ZONE DeployZone Deploy zone. +-- @param Core.Zone#ZONE DisembarkZone (Optional) Disembark zone. +-- @return #boolean If `true`, enough assets could be recruited and an OPSTRANSPORT object was created. +-- @return Ops.OpsTransport#OPSTRANSPORT Transport The transport. +function LEGION:AssignAssetsForTransport(Legions, CargoAssets, NcarriersMin, NcarriersMax, DeployZone, DisembarkZone, Categories, Attributes) + + -- 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 all legions and heaviest cargo group weight + local CargoLegions={} ; local CargoWeight=nil + for _,_asset in pairs(CargoAssets) do + local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem + CargoLegions[asset.legion.alias]=asset.legion + if CargoWeight==nil or asset.weight>CargoWeight then + CargoWeight=asset.weight + end + end + + -- 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, Categories, Attributes) + + if TransportAvail then + + -- Create and OPSTRANSPORT assignment. + local Transport=OPSTRANSPORT:New(nil, nil, DeployZone) + if DisembarkZone then + Transport:SetDisembarkZone(DisembarkZone) + end + + -- Debug info. + env.info(string.format("FF Transport available with %d carrier assets", #CarrierAssets)) + + -- Add cargo assets to transport. + for _,_legion in pairs(CargoLegions) do + local legion=_legion --Ops.Legion#LEGION + + -- Set pickup zone to spawn zone or airbase if the legion has one that is operational. + local pickupzone=legion.spawnzone + if legion.airbase and legion:IsRunwayOperational() then + pickupzone=ZONE_AIRBASE:New(legion.airbasename, 4000) + end + + -- Add TZC from legion spawn zone to deploy zone. + local tpz=Transport:AddTransportZoneCombo(pickupzone, Transport:GetDeployZone()) + Transport:SetEmbarkZone(legion.spawnzone, tpz) + + -- Add cargo assets to transport. + for _,_asset in pairs(CargoAssets) do + local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem + if asset.legion.alias==legion.alias then + Transport:AddAssetCargo(asset, tpz) + end + end + end + + -- Add carrier assets. + for _,_asset in pairs(CarrierAssets) do + local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem + Transport:AddAsset(asset) + end + + -- Assign TRANSPORT to legions. This also sends the request for the assets. + for _,_legion in pairs(CarrierLegions) do + local legion=_legion --Ops.Legion#LEGION + self:TransportAssign(legion, Transport) + end + + -- Got transport. + return true, Transport + else + -- Uncrecruit transport assets. + LEGION.UnRecruitAssets(CarrierAssets) + return false, nil + end + + return nil, nil + end + + -- No transport requested in the first place. + return true, nil +end + --- Calculate the mission score of an asset. -- @param Functional.Warehouse#WAREHOUSE.Assetitem asset Asset diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 229a1a1b6..3769b30ae 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -2311,6 +2311,43 @@ function OPSGROUP:IsLoaded(CarrierGroupName) return self.cargoStatus==OPSGROUP.CargoStatus.LOADED end +--- Check if the group is currently busy doing something. +-- +-- * Boarding +-- * Rearming +-- * Returning +-- * Pickingup, Loading, Transporting, Unloading +-- * Engageing +-- +-- @param #OPSGROUP self +-- @return #boolean If `true`, group is busy. +function OPSGROUP:IsBusy() + + if self:IsBoarding() then + return true + end + + if self:IsRearming() then + return true + end + + if self:IsReturning() then + return true + end + + -- Busy as carrier? + if self:IsPickingup() or self:IsLoading() or self:IsTransporting() or self:IsUnloading() then + return true + end + + if self:IsEngaging() then + return true + end + + + return false +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Waypoint Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -6995,7 +7032,8 @@ function OPSGROUP:onafterLoading(From, Event, To) if cargo.opsgroup:IsNotCargo(true) and not isCarrier then -- Check if cargo is in embark/pickup zone. - local inzone=cargo.opsgroup:IsInZone(self.cargoTZC.EmbarkZone) + -- Added InUtero here, if embark zone is moving (ship) and cargo has been spawned late activated and its position is not updated. Not sure if that breaks something else! + local inzone=cargo.opsgroup:IsInZone(self.cargoTZC.EmbarkZone) --or cargo.opsgroup:IsInUtero() -- Cargo MUST be inside zone or it will not be loaded! if inzone then @@ -7018,7 +7056,7 @@ function OPSGROUP:onafterLoading(From, Event, To) else -- Debug info. - self:T(self.lid..string.format("Cargo %s NOT in embark zone %s", cargo.opsgroup:GetName(), self.cargoTZC.EmbarkZone:GetName())) + self:T(self.lid..string.format("Cargo %s NOT in embark zone %s (and not InUTERO)", cargo.opsgroup:GetName(), self.cargoTZC.EmbarkZone:GetName())) end end diff --git a/Moose Development/Moose/Ops/OpsTransport.lua b/Moose Development/Moose/Ops/OpsTransport.lua index 8d5ece50d..e3e262d7a 100644 --- a/Moose Development/Moose/Ops/OpsTransport.lua +++ b/Moose Development/Moose/Ops/OpsTransport.lua @@ -864,7 +864,8 @@ function OPSTRANSPORT:_DelCarrier(CarrierGroup) end end - if #self.carriers==0 then + if #self.carriers==0 then + -- TODO: This call can be WRONG! self:DeadCarrierAll() end @@ -1948,18 +1949,24 @@ function OPSTRANSPORT:_CountCargosInZone(Zone, Delivered, Carrier, TransportZone local N=0 for _,_cargo in pairs(cargos) do local cargo=_cargo --Ops.OpsGroup#OPSGROUP - + + -- Is not cargo? local isNotCargo=cargo:IsNotCargo(true) if not isNotCargo then isNotCargo=iscarrier(cargo) - end + end + + -- Is in zone? + local isInZone=cargo:IsInZone(Zone) + -- Is in utero? + local isInUtero=cargo:IsInUtero() + -- Debug info. - --self:T2(self.lid..string.format("Cargo=%s: notcargo=%s, iscarrier=%s inzone=%s, inutero=%s", cargo:GetName(), tostring(cargo:IsNotCargo(true)), tostring(iscarrier(cargo)), tostring(cargo:IsInZone(Zone)), tostring(cargo:IsInUtero()) )) - + self:I(self.lid..string.format("Cargo=%s: notcargo=%s, iscarrier=%s inzone=%s, inutero=%s", cargo:GetName(), tostring(cargo:IsNotCargo(true)), tostring(iscarrier(cargo)), tostring(isInZone), tostring(isInUtero))) -- We look for groups that are not cargo, in the zone or in utero. - if isNotCargo and (cargo:IsInZone(Zone) or cargo:IsInUtero()) then + if isNotCargo and (isInZone or isInUtero) then N=N+1 end end