diff --git a/Moose Development/Moose/Ops/ArmyGroup.lua b/Moose Development/Moose/Ops/ArmyGroup.lua index f758ff079..7660edc0f 100644 --- a/Moose Development/Moose/Ops/ArmyGroup.lua +++ b/Moose Development/Moose/Ops/ArmyGroup.lua @@ -540,6 +540,10 @@ function ARMYGROUP:onafterSpawned(From, Event, To) -- Update position. self:_UpdatePosition() + + -- Not dead or destroyed yet. + self.isDead=false + self.isDestroyed=false if self.isAI then diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index cb03b0085..8472b6ad0 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -1529,6 +1529,10 @@ function FLIGHTGROUP:onafterSpawned(From, Event, To) -- Update position. self:_UpdatePosition() + + -- Not dead or destroyed yet. + self.isDead=false + self.isDestroyed=false if self.isAI then @@ -2067,12 +2071,15 @@ function FLIGHTGROUP:_CheckGroupDone(delay) -- Number of cargo transports remaining. local nTransports=self:CountRemainingTransports() + + -- Debug info. + self:T(self.lid..string.format("Remaining (final=%s): missions=%d, tasks=%d, transports=%d", tostring(self.passedfinalwp), nMissions, nTasks, nTransports)) -- Final waypoint passed? if self.passedfinalwp then -- Got current mission or task? - if self.currentmission==nil and self.taskcurrent==0 then + if self.currentmission==nil and self.taskcurrent==0 and self.cargoTransport==nil then -- Number of remaining tasks/missions? if nTasks==0 and nMissions==0 and nTransports==0 then @@ -2082,10 +2089,10 @@ function FLIGHTGROUP:_CheckGroupDone(delay) -- Send flight to destination. if destbase then - self:T(self.lid.."Passed Final WP and No current and/or future missions/task ==> RTB!") + self:T(self.lid.."Passed Final WP and No current and/or future missions/tasks/transports ==> RTB!") self:__RTB(-3, destbase) elseif destzone then - self:T(self.lid.."Passed Final WP and No current and/or future missions/task ==> RTZ!") + self:T(self.lid.."Passed Final WP and No current and/or future missions/tasks/transports ==> RTZ!") self:__RTZ(-3, destzone) else self:T(self.lid.."Passed Final WP and NO Tasks/Missions left. No DestBase or DestZone ==> Wait!") diff --git a/Moose Development/Moose/Ops/NavyGroup.lua b/Moose Development/Moose/Ops/NavyGroup.lua index 9f8f4ba9d..8c78e0ede 100644 --- a/Moose Development/Moose/Ops/NavyGroup.lua +++ b/Moose Development/Moose/Ops/NavyGroup.lua @@ -660,6 +660,10 @@ function NAVYGROUP:onafterSpawned(From, Event, To) -- Update position. self:_UpdatePosition() + + -- Not dead or destroyed yet. + self.isDead=false + self.isDestroyed=false if self.isAI then diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 3f3dc427b..3dacfb5f3 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -32,6 +32,8 @@ -- @field #boolean isAircraft If true, group is airplane or helicopter. -- @field #boolean isNaval If true, group is ships or submarine. -- @field #boolean isGround If true, group is some ground unit. +-- @field #boolean isDestroyed If true, the whole group was destroyed. +-- @field #boolean isDead If true, the whole group is dead. -- @field #table waypoints Table of waypoints. -- @field #table waypoints0 Table of initial waypoints. -- @field Wrapper.Airbase#AIRBASE homebase The home base of the flight group. @@ -1537,7 +1539,18 @@ end -- @param #OPSGROUP self -- @return #boolean If true, all units/elements of the group are dead. function OPSGROUP:IsDead() - return self:Is("Dead") + if self.isDead then + return true + else + return self:Is("Dead") + end +end + +--- Check if group was destroyed. +-- @param #OPSGROUP self +-- @return #boolean If true, all units/elements of the group were destroyed. +function OPSGROUP:IsDestroyed() + return self.isDestroyed end --- Check if FSM is stopped. @@ -2994,6 +3007,7 @@ end -- @param #OPSGROUP self -- @return #number Number of unfinished transports in the queue. function OPSGROUP:CountRemainingTransports() + env.info("FF Count remaining transports="..#self.cargoqueue) local N=0 @@ -3001,14 +3015,17 @@ function OPSGROUP:CountRemainingTransports() for _,_transport in pairs(self.cargoqueue) do local transport=_transport --Ops.OpsTransport#OPSTRANSPORT + self:I(self.lid..string.format("Transport status=%s [%s]", transport:GetCarrierTransportStatus(self), transport:GetState())) + -- Count not delivered (executing or scheduled) assignments. - if transport and transport.status~=OPSGROUP.TransportStatus.DELIVERED then + if transport and transport:GetCarrierTransportStatus(self)==OPSTRANSPORT.Status.SCHEDULED and transport:GetState()~=OPSTRANSPORT.Status.DELIVERED then N=N+1 end end + env.info("FF Count remaining transports="..N) return N end @@ -4532,6 +4549,16 @@ function OPSGROUP:_Respawn(Delay, Template, Reset) return self end +--- On after "Destroyed" event. +-- @param #OPSGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function OPSGROUP:onafterDestroyed(From, Event, To) + self:T(self.lid..string.format("Group destroyed at t=%.3f", timer.getTime())) + self.isDestroyed=true +end + --- On before "Dead" event. -- @param #OPSGROUP self -- @param #string From From state. @@ -4550,10 +4577,9 @@ end -- @param #string To To state. function OPSGROUP:onafterDead(From, Event, To) self:T(self.lid..string.format("Group dead at t=%.3f", timer.getTime())) - - -- Delete waypoints so they are re-initialized at the next spawn. - self.waypoints=nil - self.groupinitialized=false + + -- Is dead now. + self.isDead=true -- Cancel all missions. for _,_mission in pairs(self.missionqueue) do @@ -4565,6 +4591,10 @@ function OPSGROUP:onafterDead(From, Event, To) mission:GroupDead(self) end + + -- Delete waypoints so they are re-initialized at the next spawn. + self.waypoints=nil + self.groupinitialized=false -- Stop in a sec. self:__Stop(-5) @@ -4922,6 +4952,7 @@ function OPSGROUP:AddOpsTransport(OpsTransport) --Add to cargo queue table.insert(self.cargoqueue, OpsTransport) + self:I(self.lid.."FF adding transport to carrier, #self.cargoqueue="..#self.cargoqueue) end --- Delete a cargo transport assignment from the cargo queue @@ -5654,6 +5685,9 @@ function OPSGROUP:onafterUnloading(From, Event, To) -- Cargo was delivered (somehow). cargo.delivered=true + -- Increase number of delivered cargos. + self.cargoTransport.Ndelivered=self.cargoTransport.Ndelivered+1 + if carrierGroup then --- @@ -5902,12 +5936,14 @@ function OPSGROUP:onafterDelivered(From, Event, To, CargoTransport) elseif self:IsLandedAt() then local Task=self:GetTaskCurrent() self:TaskCancel(Task) - end + end + else + -- Army & Navy: give Cruise command to "wake up" from waiting status. + self:__Cruise(0.1) end -- Check group done. self:I(self.lid.."All cargo delivered ==> check group done") - self:__Cruise(0.1) self:_CheckGroupDone(0.2) -- No current transport any more. @@ -7504,7 +7540,7 @@ end -- @return #OPSGROUP self function OPSGROUP:_UpdatePosition() - if self:IsAlive()~=nil then + if self:IsExist() then -- Backup last state to monitor differences. self.positionLast=self.position or self:GetVec3() diff --git a/Moose Development/Moose/Ops/OpsTransport.lua b/Moose Development/Moose/Ops/OpsTransport.lua index c354ff996..6f098e30d 100644 --- a/Moose Development/Moose/Ops/OpsTransport.lua +++ b/Moose Development/Moose/Ops/OpsTransport.lua @@ -38,8 +38,11 @@ -- @field Core.Zone#ZONE embarkzone (Optional) Zone where the cargo is supposed to embark. Default is the pickup zone. -- @field Core.Zone#ZONE disembarkzone (Optional) Zone where the cargo is disembarked. Default is the deploy zone. -- @field Ops.OpsGroup#OPSGROUP carrierGroup The new carrier group. --- @field disembarkActivation Activation setting when group is disembared from carrier. --- @field disembarkInUtero Do not spawn the group in any any state but leave it "*in utero*". For example, to directly load it into another carrier. +-- @field #boolean disembarkActivation Activation setting when group is disembared from carrier. +-- @field #boolean disembarkInUtero Do not spawn the group in any any state but leave it "*in utero*". For example, to directly load it into another carrier. +-- @field #number Ncargo Total number of cargo groups. +-- @field #number Ncarrier Total number of assigned carriers. +-- @field #number Ndelivered Total number of cargo groups delivered. -- @extends Core.Fsm#FSM --- *Victory is the beautiful, bright-colored flower. Transport is the stem without which it could never have blossomed.* -- Winston Churchill @@ -118,6 +121,9 @@ function OPSTRANSPORT:New(GroupSet, Pickupzone, Deployzone) self.carrierGroup=nil self.cargos={} self.carriers={} + self.Ncargo=0 + self.Ncarrier=0 + self.Ndelivered=0 self:SetPriority() @@ -168,6 +174,7 @@ function OPSTRANSPORT:AddCargoGroups(GroupSet, Pickupzone, Deployzone) if cargo then --and self:CanCargo(cargo.opsgroup) table.insert(self.cargos, cargo) + self.Ncargo=self.Ncargo+1 end else @@ -180,6 +187,7 @@ function OPSTRANSPORT:AddCargoGroups(GroupSet, Pickupzone, Deployzone) if cargo then table.insert(self.cargos, cargo) + self.Ncargo=self.Ncargo+1 end end @@ -249,6 +257,21 @@ function OPSTRANSPORT:SetDisembarkInUtero(InUtero) return self end +--- Check if an OPS group is assigned as carrier for this transport. +-- @param #OPSTRANSPORT self +-- @param Ops.OpsGroup#OPSGROUP CarrierGroup Potential carrier OPSGROUP. +-- @return #boolean If true, group is an assigned carrier. +function OPSTRANSPORT:IsCarrier(CarrierGroup) + + for _,_carrier in pairs(self.carriers) do + local carrier=_carrier --Ops.OpsGroup#OPSGROUP + if carrier.groupname==CarrierGroup.groupname then + return true + end + end + + return false +end --- Add a carrier assigned for this transport. -- @param #OPSTRANSPORT self @@ -256,11 +279,19 @@ end -- @return #OPSTRANSPORT self function OPSTRANSPORT:_AddCarrier(CarrierGroup) - self:SetCarrierTransportStatus(CarrierGroup, OPSTRANSPORT.Status.SCHEDULED) + if not self:IsCarrier(CarrierGroup) then - self:Scheduled() - - table.insert(self.carriers, CarrierGroup) + -- Increase carrier count. + self.Ncarrier=self.Ncarrier+1 + + -- Set trans + self:SetCarrierTransportStatus(CarrierGroup, OPSTRANSPORT.Status.SCHEDULED) + + self:Scheduled() + + table.insert(self.carriers, CarrierGroup) + + end return self end @@ -390,9 +421,11 @@ end -- @param #string To To state. function OPSTRANSPORT:onafterStatus(From, Event, To) + -- Current FSM state. local fsmstate=self:GetState() + - local text=string.format("State=%s: %s --> %s", fsmstate, self.pickupzone:GetName(), self.deployzone:GetName()) + local text=string.format("%s [%s --> %s]: Ncargo=%d/%d, Ncarrier=%d", fsmstate:upper(), self.pickupzone:GetName(), self.deployzone:GetName(), self.Ncargo, self.Ndelivered, self.Ncarrier) text=text..string.format("\nCargos:") for _,_cargo in pairs(self.cargos) do @@ -483,20 +516,34 @@ end function OPSTRANSPORT:_CheckDelivered() local done=true + local dead=true for _,_cargo in pairs(self.cargos) do local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup if cargo.delivered then -- This one is delivered. - elseif cargo.opsgroup==nil or cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped() then + dead=false + elseif cargo.opsgroup==nil then + -- This one is nil?! + dead=false + elseif cargo.opsgroup:IsDestroyed() then + -- This one was destroyed. + elseif cargo.opsgroup:IsDead() then -- This one is dead. + dead=false + elseif cargo.opsgroup:IsStopped() then + -- This one is stopped. + dead=false else done=false --Someone is not done! + dead=false end end - if done then + if dead then + --self:CargoDead() + elseif done then self:Delivered() end