From b87930738a37ceae17fc5ed5e1c58ca7d5fc8cce Mon Sep 17 00:00:00 2001 From: Frank Date: Wed, 20 Nov 2024 11:15:05 +0100 Subject: [PATCH 1/2] TARGET v0.7 - Bug fixes - Improved FSM function docs --- Moose Development/Moose/Ops/Target.lua | 135 ++++++++++++++++++++----- 1 file changed, 112 insertions(+), 23 deletions(-) diff --git a/Moose Development/Moose/Ops/Target.lua b/Moose Development/Moose/Ops/Target.lua index 5f72742d6..46e370af0 100644 --- a/Moose Development/Moose/Ops/Target.lua +++ b/Moose Development/Moose/Ops/Target.lua @@ -153,13 +153,13 @@ _TARGETID=0 --- TARGET class version. -- @field #string version -TARGET.version="0.6.0" +TARGET.version="0.7.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- TODO: Had cases where target life was 0 but target was not dead. Need to figure out why! +-- DONE: Had cases where target life was 0 but target was not dead. Need to figure out why! <== This is due to delayed dead event. -- DONE: Add pseudo functions. -- DONE: Initial object can be nil. @@ -243,6 +243,36 @@ function TARGET:New(TargetObject) -- @function [parent=#TARGET] __Status -- @param #TARGET self -- @param #number delay Delay in seconds. + + + --- Triggers the FSM event "ObjectDamaged". + -- @function [parent=#TARGET] ObjectDamaged + -- @param #TARGET self + -- @param #TARGET.Object Target Target object. + + --- Triggers the FSM event "ObjectDestroyed". + -- @function [parent=#TARGET] ObjectDestroyed + -- @param #TARGET self + -- @param #TARGET.Object Target Target object. + + --- Triggers the FSM event "ObjectDead". + -- @function [parent=#TARGET] ObjectDead + -- @param #TARGET self + -- @param #TARGET.Object Target Target object. + + + --- Triggers the FSM event "Damaged". + -- @function [parent=#TARGET] Damaged + -- @param #TARGET self + + --- Triggers the FSM event "Destroyed". + -- @function [parent=#TARGET] Destroyed + -- @param #TARGET self + + --- Triggers the FSM event "Dead". + -- @function [parent=#TARGET] Dead + -- @param #TARGET self + --- On After "ObjectDamaged" event. A (sub-) target object has been damaged, e.g. a UNIT of a GROUP, or an object of a SET -- @function [parent=#TARGET] OnAfterObjectDamaged @@ -267,22 +297,23 @@ function TARGET:New(TargetObject) -- @param #string Event Event. -- @param #string To To state. -- @param #TARGET.Object Target Target object. + - --- On After "Damaged" event. The (whole) target object has been damaged. + --- On After "Damaged" event. Any of the target objects has been damaged. -- @function [parent=#TARGET] OnAfterDamaged -- @param #TARGET self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. - --- On After "ObjectDestroyed" event. The (whole) target object has been destroyed. + --- On After "Destroyed" event. All target objects have been destroyed. -- @function [parent=#TARGET] OnAfterDestroyed -- @param #TARGET self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. - --- On After "ObjectDead" event. The (whole) target object is dead. + --- On After "Dead" event. All target objects are dead. -- @function [parent=#TARGET] OnAfterDead -- @param #TARGET self -- @param #string From From state. @@ -290,7 +321,7 @@ function TARGET:New(TargetObject) -- @param #string To To state. -- Start. - self:__Start(-1) + self:__Start(-0.1) return self end @@ -527,6 +558,11 @@ function TARGET:IsAlive() for _,_target in pairs(self.targets) do local target=_target --Ops.Target#TARGET.Object if target.Status~=TARGET.ObjectStatus.DEAD then + if self.isDestroyed then + self:E(self.lid..string.format("ERROR: target is DESTROYED but target object status is not DEAD but %s for object %s", target.Status, target.Name)) + elseif self:IsDead() then + self:E(self.lid..string.format("ERROR: target is DEAD but target object status is not DEAD but %s for object %s", target.Status, target.Name)) + end return true end end @@ -550,6 +586,25 @@ function TARGET:IsDead() return is end +--- Check if target object is dead. +-- @param #TARGET self +-- @param #TARGET.Object TargetObject The target object. +-- @return #boolean If true, target is dead. +function TARGET:IsTargetDead(TargetObject) + local isDead=TargetObject.Status==TARGET.ObjectStatus.DEAD + return isDead +end + +--- Check if target object is alive. +-- @param #TARGET self +-- @param #TARGET.Object TargetObject The target object. +-- @return #boolean If true, target is dead. +function TARGET:IsTargetAlive(TargetObject) + local isAlive=TargetObject.Status==TARGET.ObjectStatus.ALIVE + return isAlive +end + + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Start & Status ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -581,7 +636,8 @@ end -- @param #string Event Event. -- @param #string To To state. function TARGET:onafterStatus(From, Event, To) - self:T({From, Event, To}) + --self:T({From, Event, To}) + -- FSM state. local fsmstate=self:GetState() @@ -592,6 +648,7 @@ function TARGET:onafterStatus(From, Event, To) -- old life local life=target.Life + -- curr life target.Life=self:GetTargetLife(target) @@ -603,13 +660,14 @@ function TARGET:onafterStatus(From, Event, To) self.life0 = self.life0+delta end + -- Check if life decreased ==> damaged if target.Life object dead now for target object %s!", tostring(target.Name))) self:ObjectDead(target) damaged = true @@ -624,11 +682,12 @@ function TARGET:onafterStatus(From, Event, To) -- Log output verbose=1. if self.verbose>=1 then - local text=string.format("%s: Targets=%d/%d Life=%.1f/%.1f Damage=%.1f", fsmstate, self:CountTargets(), self.N0, self:GetLife(), self:GetLife0(), self:GetDamage()) + local text=string.format("%s: Targets=%d/%d [%d, %d], Life=%.1f/%.1f, Damage=%.1f", + fsmstate, self:CountTargets(), self.N0, self.Ndestroyed, self.Ndead, self:GetLife(), self:GetLife0(), self:GetDamage()) if self:CountTargets() == 0 or self:GetDamage() >= 100 then - text=text.." Dead!" + text=text.." - Dead!" elseif damaged then - text=text.." Damaged!" + text=text.." - Damaged!" end self:I(self.lid..text) end @@ -639,19 +698,35 @@ function TARGET:onafterStatus(From, Event, To) for i,_target in pairs(self.targets) do local target=_target --#TARGET.Object local damage=(1-target.Life/target.Life0)*100 - text=text..string.format("\n[%d] %s %s %s: Life=%.1f/%.1f, Damage=%.1f", i, target.Type, target.Name, target.Status, target.Life, target.Life0, damage) + text=text..string.format("\n[%d] %s %s %s: Life=%.1f/%.1f, Damage=%.1f, N0=%d, Ndestroyed=%d, Ndead=%d", + i, target.Type, target.Name, target.Status, target.Life, target.Life0, damage, target.N0, target.Ndestroyed, target.Ndead) end self:I(self.lid..text) end - if self:CountTargets() == 0 or self:GetDamage() >= 100 then + -- Consitency check if target is still alive but all target objects are dead + if self:IsAlive() and (self:CountTargets()==0 or self:GetDamage()>=100) then self:Dead() end + -- Quick sanity check + for i,_target in pairs(self.targets) do + local target=_target --#TARGET.Object + if target.Ndestroyed>target.N0 then + self:E(self.lid..string.format("ERROR: Number of destroyed target objects greater than number of initial target objects: %d>%d!", target.Ndestroyed, target.N0)) + end + if target.Ndestroyed>target.N0 then + self:E(self.lid..string.format("ERROR: Number of dead target objects greater than number of initial target objects: %d>%d!", target.Ndead, target.N0)) + end + end + -- Update status again in 30 sec. if self:IsAlive() then self:__Status(-self.TStatus) + else + self:I(self.lid..string.format("Target is not alive any more ==> no further status updates are carried out")) end + return self end @@ -687,6 +762,10 @@ function TARGET:onafterObjectDestroyed(From, Event, To, Target) -- Increase destroyed counter. self.Ndestroyed=self.Ndestroyed+1 + Target.Ndestroyed=Target.Ndestroyed+1 + + Target.Life=0 + -- Call object dead event. self:ObjectDead(Target) @@ -707,6 +786,12 @@ function TARGET:onafterObjectDead(From, Event, To, Target) -- Set target status. Target.Status=TARGET.ObjectStatus.DEAD + -- Increase dead object counter + Target.Ndead=Target.Ndead+1 + + -- Set target object life to 0. + Target.Life=0 + -- Increase dead counter. self.Ndead=self.Ndead+1 @@ -716,6 +801,7 @@ function TARGET:onafterObjectDead(From, Event, To, Target) local target=_target --#TARGET.Object if target.Status==TARGET.ObjectStatus.ALIVE then dead=false + break -- break the loop because we now we are not dead end end @@ -759,7 +845,6 @@ end -- @param #string Event Event. -- @param #string To To state. function TARGET:onafterDestroyed(From, Event, To) - self:T({From, Event, To}) self:T(self.lid..string.format("TARGET destroyed")) @@ -813,23 +898,27 @@ function TARGET:OnEventUnitDeadOrLost(EventData) -- Check if we could find a target object. if target then + local Ndead=target.Ndead + local Ndestroyed=target.Ndestroyed if EventData.id==EVENTS.RemoveUnit then - target.Ndead=target.Ndead+1 + Ndead=Ndead+1 else - target.Ndestroyed=target.Ndestroyed+1 - target.Ndead=target.Ndead+1 + Ndestroyed=Ndestroyed+1 + Ndead=Ndead+1 end - if target.Ndead==target.N0 then - if target.Ndestroyed>=target.N0 then + -- Check if ALL objects are dead + if Ndead==target.N0 then + + if Ndestroyed>=target.N0 then -- Debug message. self:T2(self.lid..string.format("EVENT ID=%d: target %s dead/lost ==> destroyed", EventData.id, tostring(target.Name))) target.Life = 0 - -- Trigger object destroyed event. + -- Trigger object destroyed event. This sets the Life to zero and increases Ndestroyed self:ObjectDestroyed(target) else @@ -839,7 +928,7 @@ function TARGET:OnEventUnitDeadOrLost(EventData) target.Life = 0 - -- Trigger object dead event. + -- Trigger object dead event. This sets the Life to zero and increases Ndead counter self:ObjectDead(target) end From 6022a3905f58ee7537c6b18e94588feb18fa4c9d Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 23 Nov 2024 22:10:26 +0100 Subject: [PATCH 2/2] TARGET v0.7.1 - Fixed bug if TARGET is a COORDINATE or ZONE, where we cannot check if it is alive or dead. The count alive previously did not count coordinates or zones. Now it does, which is more consistent as we set life=1 and alive=true for these. --- Moose Development/Moose/Ops/Target.lua | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Ops/Target.lua b/Moose Development/Moose/Ops/Target.lua index 46e370af0..e0b750679 100644 --- a/Moose Development/Moose/Ops/Target.lua +++ b/Moose Development/Moose/Ops/Target.lua @@ -153,7 +153,7 @@ _TARGETID=0 --- TARGET class version. -- @field #string version -TARGET.version="0.7.0" +TARGET.version="0.7.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -1068,6 +1068,8 @@ function TARGET:_AddObject(Object) target.Life0=1 target.Life=1 + + target.N0=target.N0+1 elseif Object:IsInstanceOf("ZONE_BASE") then @@ -1081,6 +1083,8 @@ function TARGET:_AddObject(Object) target.Life0=1 target.Life=1 + + target.N0=target.N0+1 elseif Object:IsInstanceOf("OPSZONE") then @@ -2008,12 +2012,16 @@ function TARGET:CountObjectives(Target, Coalitions) elseif Target.Type==TARGET.ObjectType.COORDINATE then - -- No target we can check! + -- No target, where we can check the alive status, so we assume it is alive. Changed this because otherwise target count is 0 if we pass a coordinate. + -- This is also more consitent with the life and is alive status. + N=N+1 elseif Target.Type==TARGET.ObjectType.ZONE then - -- No target we can check! - + -- No target, where we can check the alive status, so we assume it is alive. Changed this because otherwise target count is 0 if we pass a coordinate. + -- This is also more consitent with the life and is alive status. + N=N+1 + elseif Target.Type==TARGET.ObjectType.OPSZONE then local target=Target.Object --Ops.OpsZone#OPSZONE