From 9cddca1af590c801c0e93fefacf274d4d849e955 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 8 Feb 2022 08:52:47 +0100 Subject: [PATCH 1/2] AUFTRAG and WAREHOUSE - Added check for AUFTRAG that if it is executing and all groups are dead, it's done - Added check in WAREHOUSE find parking that units need to be alive --- .../Moose/Functional/Warehouse.lua | 27 ++++++++++++------- Moose Development/Moose/Ops/Auftrag.lua | 20 ++++++++++++++ 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index f38c71d8e..5b66b13d2 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -7850,7 +7850,9 @@ function WAREHOUSE:_FindParkingForAssets(airbase, assets) local _coord=unit:GetVec3() local _size=self:_GetObjectSize(unit:GetDCSObject()) local _name=unit:GetName() - table.insert(obstacles, {coord=_coord, size=_size, name=_name, type="unit"}) + if unit and unit:IsAlive() then + table.insert(obstacles, {coord=_coord, size=_size, name=_name, type="unit"}) + end end -- Check all statics. @@ -7892,6 +7894,9 @@ function WAREHOUSE:_FindParkingForAssets(airbase, assets) -- Loop over all units - each one needs a spot. for i=1,_asset.nunits do + + -- Asset name + local assetname=_asset.spawngroupname.."-"..tostring(i) -- Loop over all parking spots. local gotit=false @@ -7916,13 +7921,13 @@ function WAREHOUSE:_FindParkingForAssets(airbase, assets) -- Spot is blocked. if not safe then - --env.info(string.format("FF asset=%s (id=%d): spot id=%d dist=%.1fm is NOT SAFE", _asset.templatename, _asset.uid, _termid, dist)) + self:T3(self.lid..string.format("FF asset=%s (id=%d): spot id=%d dist=%.1fm is NOT SAFE", assetname, _asset.uid, _termid, dist)) free=false problem=obstacle problem.dist=dist break else - --env.info(string.format("FF asset=%s (id=%d): spot id=%d dist=%.1fm is SAFE", _asset.templatename, _asset.uid, _termid, dist)) + --env.info(string.format("FF asset=%s (id=%d): spot id=%d dist=%.1fm is SAFE", assetname, _asset.uid, _termid, dist)) end end @@ -7934,32 +7939,36 @@ function WAREHOUSE:_FindParkingForAssets(airbase, assets) table.insert(parking[_asset.uid], parkingspot) -- Debug - self:T(self.lid..string.format("Parking spot %d is free for asset id=%d!", _termid, _asset.uid)) + self:T(self.lid..string.format("Parking spot %d is free for asset %s [id=%d]!", _termid, assetname, _asset.uid)) -- Add the unit as obstacle so that this spot will not be available for the next unit. - table.insert(obstacles, {coord=_spot, size=_asset.size, name=_asset.templatename, type="asset"}) + table.insert(obstacles, {coord=_spot, size=_asset.size, name=assetname, type="asset"}) gotit=true break else - -- Debug output for occupied spots. - self:T(self.lid..string.format("Parking spot %d is occupied or not big enough!", _termid)) + -- Debug output for occupied spots. if self.Debug then local coord=problem.coord --Core.Point#COORDINATE - local text=string.format("Obstacle blocking spot #%d is %s type %s with size=%.1f m and distance=%.1f m.", _termid, problem.name, problem.type, problem.size, problem.dist) + local text=string.format("Obstacle %s [type=%s] blocking spot=%d! Size=%.1f m and distance=%.1f m.", problem.name, problem.type, _termid, problem.size, problem.dist) + self:I(self.lid..text) coord:MarkToAll(string.format(text)) + else + self:T(self.lid..string.format("Parking spot %d is occupied or not big enough!", _termid)) end end + else + self:T2(self.lid..string.format("Terminal ID=%d: type=%s not supported", parkingspot.TerminalID, parkingspot.TerminalType)) end -- check terminal type end -- loop over parking spots -- No parking spot for at least one asset :( if not gotit then - self:I(self.lid..string.format("WARNING: No free parking spot for asset id=%d",_asset.uid)) + self:I(self.lid..string.format("WARNING: No free parking spot for asset %s [id=%d]", assetname, _asset.uid)) return nil end end -- loop over asset units diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 87b24efaf..f41e01e1b 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -3227,6 +3227,26 @@ function AUFTRAG:onafterStatus(From, Event, To) -- Cancel mission if mission targets are gone (if there were any in the beginning). -- TODO: I commented this out for some reason but I forgot why... self:Cancel() + + elseif self:IsExecuting() then + + -- Had the case that mission was in state Executing but all assigned groups were dead. + -- TODO: might need to loop over all assigned groups + if Ngroups==0 then + self:Done() + else + local done=true + for groupname,data in pairs(self.groupdata or {}) do + local groupdata=data --#AUFTRAG.GroupData + local opsgroup=groupdata.opsgroup + if opsgroup:IsAlive() then + done=false + end + end + if done then + self:Done() + end + end end From 9d703c0af6bf4ed2c9bf5c7fb2aa0d8cacac19c1 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 25 Mar 2022 12:50:45 +0100 Subject: [PATCH 2/2] OPS - CHIEF: added tactical overview --- Moose Development/Moose/Ops/Chief.lua | 92 +++++++++++++++++++++-- Moose Development/Moose/Ops/Commander.lua | 20 +++++ Moose Development/Moose/Ops/OpsZone.lua | 9 ++- 3 files changed, 112 insertions(+), 9 deletions(-) diff --git a/Moose Development/Moose/Ops/Chief.lua b/Moose Development/Moose/Ops/Chief.lua index 0b49d5b0c..de7c143a8 100644 --- a/Moose Development/Moose/Ops/Chief.lua +++ b/Moose Development/Moose/Ops/Chief.lua @@ -32,6 +32,7 @@ -- @field #string Defcon Defence condition. -- @field #string strategy Strategy of the CHIEF. -- @field Ops.Commander#COMMANDER commander Commander of assigned legions. +-- @field #boolean tacview Tactical overview. -- @extends Ops.Intelligence#INTEL --- *In preparing for battle I have always found that plans are useless, but planning is indispensable* -- Dwight D Eisenhower @@ -134,6 +135,7 @@ CHIEF = { borderzoneset = nil, yellowzoneset = nil, engagezoneset = nil, + tacview = false, } --- Defence condition. @@ -601,6 +603,23 @@ function CHIEF:GetDefcon(Defcon) return self.Defcon end +--- Set tactical overview on. +-- @param #CHIEF self +-- @return #CHIEF self +function CHIEF:SetTacticalOverviewOn() + self.tacview=true + return self +end + +--- Set tactical overview off. +-- @param #CHIEF self +-- @return #CHIEF self +function CHIEF:SetTacticalOverviewOff() + self.tacview=false + return self +end + + --- Set strategy. -- @param #CHIEF self -- @param #string Strategy Strategy. See @{#CHIEF.strategy}, e.g. `CHIEF.Strategy.DEFENSIVE` (default). @@ -1114,7 +1133,7 @@ function CHIEF:onafterStatus(From, Event, To) --- -- Create TARGETs for all new contacts. - local Nborder=0 ; local Nconflict=0 ; local Nattack=0 + self.Nborder=0 ; self.Nconflict=0 ; self.Nattack=0 for _,_contact in pairs(self.Contacts) do local contact=_contact --Ops.Intelligence#INTEL.Contact local group=contact.group --Wrapper.Group#GROUP @@ -1122,19 +1141,19 @@ function CHIEF:onafterStatus(From, Event, To) -- Check if contact inside of our borders. local inred=self:CheckGroupInBorder(group) if inred then - Nborder=Nborder+1 + self.Nborder=self.Nborder+1 end -- Check if contact is in the conflict zones. local inyellow=self:CheckGroupInConflict(group) if inyellow then - Nconflict=Nconflict+1 + self.Nconflict=self.Nconflict+1 end -- Check if contact is in the attack zones. local inattack=self:CheckGroupInAttack(group) if inattack then - Nattack=Nattack+1 + self.Nattack=self.Nattack+1 end @@ -1162,9 +1181,9 @@ function CHIEF:onafterStatus(From, Event, To) --- -- TODO: Need to introduce time check to avoid fast oscillation between different defcon states in case groups move in and out of the zones. - if Nborder>0 then + if self.Nborder>0 then self:SetDefcon(CHIEF.DEFCON.RED) - elseif Nconflict>0 then + elseif self.Nconflict>0 then self:SetDefcon(CHIEF.DEFCON.YELLOW) else self:SetDefcon(CHIEF.DEFCON.GREEN) @@ -1182,7 +1201,11 @@ function CHIEF:onafterStatus(From, Event, To) --- -- Check target queue and assign missions to new targets. - self:CheckOpsZoneQueue() + self:CheckOpsZoneQueue() + + + -- Display tactival overview. + self:_TacticalOverview() --- -- Info General @@ -1196,7 +1219,7 @@ function CHIEF:onafterStatus(From, Event, To) -- Info message local text=string.format("Defcon=%s Strategy=%s: Assets=%d, Contacts=%d [Border=%d, Conflict=%d, Attack=%d], Targets=%d, Missions=%d", - self.Defcon, self.strategy, Nassets, Ncontacts, Nborder, Nconflict, Nattack, Ntargets, Nmissions) + self.Defcon, self.strategy, Nassets, Ncontacts, self.Nborder, self.Nconflict, self.Nattack, Ntargets, Nmissions) self:I(self.lid..text) end @@ -1470,6 +1493,59 @@ end -- Target Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- Display tactical overview. +-- @param #CHIEF self +function CHIEF:_TacticalOverview() + + if self.tacview then + + local NassetsTotal=self.commander:CountAssets() + local NassetsStock=self.commander:CountAssets(true) + local Ncontacts=#self.Contacts + local Nmissions=#self.commander.missionqueue + local Ntargets=#self.targetqueue + local Nzones=#self.zonequeue + + -- Info message + local text=string.format("Tactical Overview\n") + text=text..string.format("=================\n") + + text=text..string.format("Strategy: %s - Defcon: %s\n", self.strategy, self.Defcon) + + text=text..string.format("Contacts: %d [Border=%d, Conflict=%d, Attack=%d]\n", Ncontacts, self.Nborder, self.Nconflict, self.Nattack) + + text=text..string.format("Targets: %d\n", Ntargets) + + text=text..string.format("Missions: %d\n", Nmissions) + for _,mtype in pairs(AUFTRAG.Type) do + local n=self.commander:CountMissions(mtype) + if n>0 then + text=text..string.format(" - %s: %d\n", mtype, n) + end + end + + text=text..string.format("Assets: %d [Stock %d]\n", NassetsTotal, NassetsStock) + + text=text..string.format("Strategic Zones: %d\n", Nzones) + for _,_stratzone in pairs(self.zonequeue) do + local stratzone=_stratzone --#CHIEF.StrategicZone + local owner=stratzone.opszone:GetOwnerName() + text=text..string.format(" - %s: %s - %s [I=%d, P=%d]\n", stratzone.opszone:GetName(), owner, stratzone.opszone:GetState(), stratzone.importance, stratzone.prio) + end + + -- Message to coalition. + MESSAGE:New(text, 60, nil, true):ToCoalition(self.coalition) + + -- Output to log. + if self.verbose>=4 then + self:I(self.lid..text) + end + + end + +end + + --- Check target queue and assign ONE valid target by adding it to the mission queue of the COMMANDER. -- @param #CHIEF self function CHIEF:CheckTargetQueue() diff --git a/Moose Development/Moose/Ops/Commander.lua b/Moose Development/Moose/Ops/Commander.lua index 5627d2082..1896674d0 100644 --- a/Moose Development/Moose/Ops/Commander.lua +++ b/Moose Development/Moose/Ops/Commander.lua @@ -1411,6 +1411,26 @@ function COMMANDER:CountAssets(InStock, MissionTypes, Attributes) return N end +--- Count assets of all assigned legions. +-- @param #COMMANDER self +-- @param #table MissionTypes (Optional) Count only missions of these types. Default is all types. +-- @return #number Amount missions. +function COMMANDER:CountMissions(MissionTypes) + + local N=0 + 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 + N=N+1 + end + end + + + return N +end + --- Count assets of all assigned legions. -- @param #COMMANDER self -- @param #boolean InStock If true, only assets that are in the warehouse stock/inventory are counted. diff --git a/Moose Development/Moose/Ops/OpsZone.lua b/Moose Development/Moose/Ops/OpsZone.lua index b5f624d52..002ac00cc 100644 --- a/Moose Development/Moose/Ops/OpsZone.lua +++ b/Moose Development/Moose/Ops/OpsZone.lua @@ -413,6 +413,13 @@ function OPSZONE:GetOwner() return self.ownerCurrent end +--- Get coalition name of current owner of the zone. +-- @param #OPSZONE self +-- @return #string Owner coalition. +function OPSZONE:GetOwnerName() + return UTILS.GetCoalitionName(self.ownerCurrent) +end + --- Get coordinate of zone. -- @param #OPSZONE self -- @return Core.Point#COORDINATE Coordinate of the zone. @@ -421,7 +428,7 @@ function OPSZONE:GetCoordinate() return coordinate end ---- Get name. +--- Get zone name. -- @param #OPSZONE self -- @return #string Name of the zone. function OPSZONE:GetName()