diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 3a5160f86..1b2603f00 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -744,7 +744,7 @@ do -- COORDINATE -- @return #string MGRS coordinates. function COORDINATE:GetName() local name=self:ToStringMGRS() - return rname + return name end --- Return velocity text of the COORDINATE. @@ -1751,9 +1751,9 @@ do -- COORDINATE self:F2( { ExplosionIntensity } ) ExplosionIntensity=ExplosionIntensity or 100 if Delay and Delay>0 then - SCHEDULER:New(nil, self.Explosion, {self,ExplosionIntensity}, Delay) + self:ScheduleOnce(Delay, self.Explosion, self, ExplosionIntensity) else - trigger.action.explosion( self:GetVec3(), ExplosionIntensity ) + trigger.action.explosion(self:GetVec3(), ExplosionIntensity) end return self end diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 1153ba5f6..dce4fe3be 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -47,6 +47,7 @@ -- @field #number markerCoaliton Coalition to which the marker is dispayed. -- @field #table DCStask DCS task structure. -- @field #number Ncasualties Number of own casualties during mission. +-- @field #number Nkills Number of (enemy) units killed by assets of this mission. -- @field #number Nelements Number of elements (units) assigned to mission. -- @field #number dTevaluate Time interval in seconds before the mission result is evaluated after mission is over. -- @field #number Tover Mission abs. time stamp, when mission was over. @@ -504,8 +505,9 @@ function AUFTRAG:New(Type) self.NrepeatFailure=0 self.NrepeatSuccess=0 self.nassets=1 - self.dTevaluate=0 + self.dTevaluate=5 self.Ncasualties=0 + self.Nkills=0 self.Nelements=0 -- FMS start state is PLANNED. @@ -1697,6 +1699,14 @@ function AUFTRAG:GetCasualties() return self.Ncasualties or 0 end +--- Get kills, i.e. number of units that were destroyed by assets of this mission. +-- @param #AUFTRAG self +-- @return #number Number of units destroyed. +function AUFTRAG:GetKills() + return self.Nkills or 0 +end + + --- Check if mission is "urgent". -- @param #AUFTRAG self -- @return #boolean If `true`, mission is "urgent". @@ -2101,6 +2111,11 @@ function AUFTRAG:onafterStatus(From, Event, To) -- Ready to evaluate mission outcome? local ready2evaluate=self.Tover and Tnow-self.Tover>=self.dTevaluate or false + + --env.info("FF Tover="..tostring(self.Tover)) + --if self.Tover then + -- env.info("FF Tnow-Tover="..tostring(Tnow-self.Tover)) + --end -- Check if mission is OVER (done or cancelled) and enough time passed to evaluate the result. if self:IsOver() and ready2evaluate then @@ -2199,13 +2214,12 @@ function AUFTRAG:Evaluate() local text=string.format("Evaluating mission:\n") text=text..string.format("Own casualties = %d/%d\n", self.Ncasualties, self.Nelements) text=text..string.format("Own losses = %.1f %%\n", owndamage) + text=text..string.format("Killed units = %d\n", self.Nkills) text=text..string.format("--------------------------\n") text=text..string.format("Targets left = %d/%d\n", Ntargets, Ntargets0) text=text..string.format("Targets life = %.1f/%.1f\n", Life, Life0) text=text..string.format("Enemy losses = %.1f %%\n", targetdamage) text=text..string.format("--------------------------\n") - --text=text..string.format("Loss ratio = %.1f %%\n", targetdamage) - --text=text..string.format("--------------------------\n") text=text..string.format("Success Cond = %s\n", tostring(successCondition)) text=text..string.format("Failure Cond = %s\n", tostring(failureCondition)) text=text..string.format("--------------------------\n") @@ -2563,6 +2577,8 @@ function AUFTRAG:onafterAssetDead(From, Event, To, Asset) -- Number of groups alive. local N=self:CountOpsGroups() + self:I(self.lid..string.format("Asset %s dead! Number of ops groups remaining %d", tostring(Asset.spawngroupname), N)) + -- All assets dead? if N==0 then @@ -3045,7 +3061,7 @@ function AUFTRAG:CountOpsGroups() local N=0 for _,_groupdata in pairs(self.groupdata) do local groupdata=_groupdata --#AUFTRAG.GroupData - if groupdata and groupdata.opsgroup and groupdata.opsgroup:IsAlive() then + if groupdata and groupdata.opsgroup and groupdata.opsgroup:IsAlive() and not groupdata.opsgroup:IsDead() then N=N+1 end end diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 87e207d8f..1080e01fe 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -336,6 +336,7 @@ function FLIGHTGROUP:New(group) self:HandleEvent(EVENTS.Crash, self.OnEventCrash) self:HandleEvent(EVENTS.RemoveUnit, self.OnEventRemoveUnit) self:HandleEvent(EVENTS.UnitLost, self.OnEventUnitLost) + self:HandleEvent(EVENTS.Kill, self.OnEventKill) -- Init waypoints. self:InitWaypoints() @@ -715,6 +716,12 @@ function FLIGHTGROUP:GetFuelMin() return fuelmin*100 end +--- Get number of kills of this group. +-- @param #FLIGHTGROUP self +-- @return #number Number of units killed. +function FLIGHTGROUP:GetKills() + return self.Nkills +end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Status ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -741,18 +748,22 @@ function FLIGHTGROUP:onbeforeStatus(From, Event, To) -- Units with life <=1 are dead. if life<=1 then + --env.info(string.format("FF unit %s: live<=1 in status at T=%.3f", unit:GetName(), timer.getTime())) isdead=true end else -- Not alive any more. + --env.info(string.format("FF unit %s: NOT alive in status at T=%.3f", unit:GetName(), timer.getTime())) isdead=true end -- This one is dead. if isdead then - self:E(self.lid..string.format("Element %s is dead! Probably despawned without notice or landed at a too small airbase", tostring(element.name))) - self:ElementDead(element) + local text=string.format("Element %s is dead at t=%.3f! Maybe despawned without notice or landed at a too small airbase. Calling ElementDead in 60 sec to give other events a chance", + tostring(element.name), timer.getTime()) + self:E(self.lid..text) + self:__ElementDead(60, element) end end @@ -854,9 +865,9 @@ function FLIGHTGROUP:onafterStatus(From, Event, To) local parking=element.parking and tostring(element.parking.TerminalID) or "X" -- Check if element is not dead and we missed an event. - if life<=0 and element.status~=OPSGROUP.ElementStatus.DEAD and element.status~=OPSGROUP.ElementStatus.INUTERO then - self:ElementDead(element) - end + --if life<=0 and element.status~=OPSGROUP.ElementStatus.DEAD and element.status~=OPSGROUP.ElementStatus.INUTERO then + -- self:ElementDead(element) + --end -- Get ammo. local ammo=self:GetAmmoElement(element) @@ -1177,9 +1188,9 @@ function FLIGHTGROUP:OnEventCrash(EventData) -- Get element. local element=self:GetElementByName(unitname) - if element then - self:T3(self.lid..string.format("EVENT: Element %s crashed ==> dead", element.name)) - self:ElementDead(element) + if element and element.status~=OPSGROUP.ElementStatus.DEAD then + self:I(self.lid..string.format("EVENT: Element %s crashed ==> destroyed", element.name)) + self:ElementDestroyed(element) end end @@ -1193,7 +1204,7 @@ function FLIGHTGROUP:OnEventUnitLost(EventData) -- Check that this is the right group. if EventData and EventData.IniGroup and EventData.IniUnit and EventData.IniGroupName and EventData.IniGroupName==self.groupname then - self:T(self.lid..string.format("EVENT: Unit %s lost!", EventData.IniUnitName)) + self:I(self.lid..string.format("EVENT: Unit %s lost at t=%.3f", EventData.IniUnitName, timer.getTime())) local unit=EventData.IniUnit local group=EventData.IniGroup @@ -1202,8 +1213,8 @@ function FLIGHTGROUP:OnEventUnitLost(EventData) -- Get element. local element=self:GetElementByName(unitname) - if element then - self:T3(self.lid..string.format("EVENT: Element %s unit lost ==> destroyed", element.name)) + if element and element.status~=OPSGROUP.ElementStatus.DEAD then + self:I(self.lid..string.format("EVENT: Element %s unit lost ==> destroyed t=%.3f", element.name, timer.getTime())) self:ElementDestroyed(element) end @@ -1211,6 +1222,30 @@ function FLIGHTGROUP:OnEventUnitLost(EventData) end +--- Flightgroup event function handling the crash of a unit. +-- @param #FLIGHTGROUP self +-- @param Core.Event#EVENTDATA EventData Event data. +function FLIGHTGROUP:OnEventKill(EventData) + + -- Check that this is the right group. + if EventData and EventData.IniGroup and EventData.IniUnit and EventData.IniGroupName and EventData.IniGroupName==self.groupname then + self:I(self.lid..string.format("EVENT: Unit %s killed unit %s!", tostring(EventData.IniUnitName), tostring(EventData.TgtUnitName))) + + local unit=EventData.IniUnit + local group=EventData.IniGroup + local unitname=EventData.IniUnitName + + self.Nkills=self.Nkills+1 + + local mission=self:GetMissionCurrent() + if mission then + mission.Nkills=mission.Nkills+1 + end + + end + +end + --- Flightgroup event function handling the crash of a unit. -- @param #FLIGHTGROUP self -- @param Core.Event#EVENTDATA EventData Event data. diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index bfc737cf7..bf6683de1 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -55,6 +55,7 @@ -- @field #boolean detectionOn If true, detected units of the group are analyzed. -- @field Ops.Auftrag#AUFTRAG missionpaused Paused mission. -- @field #number Ndestroyed Number of destroyed units. +-- @field #number Nkills Number kills of this groups. -- -- @field Core.Point#COORDINATE coordinate Current coordinate. -- @@ -88,7 +89,7 @@ -- -- @field #OPSGROUP.Spot spot Laser and IR spot. -- --- @field #OPSGROUP.Ammo ammo Initial ammuont of ammo. +-- @field #OPSGROUP.Ammo ammo Initial ammount of ammo. -- -- @extends Core.Fsm#FSM @@ -142,6 +143,7 @@ OPSGROUP = { icls = {}, callsign = {}, Ndestroyed = 0, + Nkills = 0, } @@ -352,9 +354,16 @@ function OPSGROUP:New(Group) self.group=Group self.groupname=Group:GetName() end - + -- Set some string id for output to DCS.log file. - self.lid=string.format("OPSGROUP %s | ", self.groupname) + self.lid=string.format("OPSGROUP %s | ", tostring(self.groupname)) + + if self.group then + if not self:IsExist() then + self:E(self.lid.."ERROR: GROUP does not exist! Returning nil") + return nil + end + end -- Init set of detected units. self.detectedunits=SET_UNIT:New() @@ -531,7 +540,11 @@ end -- @return #OPSGROUP self function OPSGROUP:SetLaser(Code, CheckLOS, IROff, UpdateTime) self.spot.Code=Code or 1688 - self.spot.CheckLOS=CheckLOS and CheckLOS or true + if CheckLOS~=nil then + self.spot.CheckLOS=CheckLOS + else + self.spot.CheckLOS=true + end self.spot.IRon=not IROff self.spot.dt=UpdateTime or 0.5 return self @@ -1303,7 +1316,7 @@ end -- @return #OPSGROUP.Waypoint Waypoint data. function OPSGROUP:GetWaypointByID(uid) - for _,_waypoint in pairs(self.waypoints) do + for _,_waypoint in pairs(self.waypoints or {}) do local waypoint=_waypoint --#OPSGROUP.Waypoint if waypoint.uid==uid then return waypoint @@ -2190,11 +2203,16 @@ function OPSGROUP:onafterTaskCancel(From, Event, To, Task) -- Set stop flag. When the flag is true, the _TaskDone function is executed and calls :TaskDone() Task.stopflag:Set(1) + local done=false if Task.dcstask.id=="Formation" then Task.formation:Stop() - self:TaskDone(Task) - elseif stopflag==1 or not self:IsAlive() then + done=true + elseif stopflag==1 or (not self:IsAlive()) or self:IsDead() or self:IsStopped() then -- Manual call TaskDone if setting flag to one was not successful. + done=true + end + + if done then self:TaskDone(Task) end @@ -3173,7 +3191,7 @@ function OPSGROUP:onbeforeLaserOn(From, Event, To, Target) self.spot.element=element -- Height offset. No offset for aircraft. We take the height for ground or naval. - local offsetY=0 + local offsetY=0 if self.isGround or self.isNaval then offsetY=element.height end @@ -3480,6 +3498,10 @@ function OPSGROUP:SetLaserTarget(Target) -- Coordinate as target. self.spot.TargetType=0 self.spot.offsetTarget={x=0, y=0, z=0} + elseif Target:IsInstanceOf("SCENERY") then + -- Coordinate as target. + self.spot.TargetType=0 + self.spot.offsetTarget={x=0, y=1, z=0} else self:E(self.lid.."ERROR: LASER target should be a POSITIONABLE (GROUP, UNIT or STATIC) or a COORDINATE object!") return @@ -3625,7 +3647,7 @@ end -- @param #string To To state. -- @param #OPSGROUP.Element Element The flight group element. function OPSGROUP:onafterElementDead(From, Event, To, Element) - self:T(self.lid..string.format("Element dead %s", Element.name)) + self:T(self.lid..string.format("Element dead %s at t=%.3f", Element.name, timer.getTime())) -- Set element status. self:_UpdateStatus(Element, OPSGROUP.ElementStatus.DEAD) @@ -3672,7 +3694,7 @@ end -- @param #string Event Event. -- @param #string To To state. function OPSGROUP:onafterDead(From, Event, To) - self:T(self.lid..string.format("Group dead!")) + 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 @@ -3682,6 +3704,8 @@ function OPSGROUP:onafterDead(From, Event, To) for _,_mission in pairs(self.missionqueue) do local mission=_mission --Ops.Auftrag#AUFTRAG + self:T(self.lid.."Cancelling mission because group is dead! Mission name "..tostring(mission:GetName())) + self:MissionCancel(mission) mission:GroupDead(self) @@ -3713,7 +3737,7 @@ function OPSGROUP:onafterStop(From, Event, To) end -- Debug output. - self:T(self.lid.."STOPPED! Unhandled events, cleared scheduler and removed from database.") + self:I(self.lid.."STOPPED! Unhandled events, cleared scheduler and removed from database.") end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Moose Development/Moose/Ops/Target.lua b/Moose Development/Moose/Ops/Target.lua index b6f9c396c..a89f023a5 100644 --- a/Moose Development/Moose/Ops/Target.lua +++ b/Moose Development/Moose/Ops/Target.lua @@ -525,12 +525,12 @@ function TARGET:_AddObject(Object) elseif Object:IsInstanceOf("COORDINATE") then - local coord=Object --Core.Point#COORDINATE + local coord=UTILS.DeepCopy(Object) --Core.Point#COORDINATE target.Type=TARGET.ObjectType.COORDINATE target.Name=coord:ToStringMGRS() - target.Coordinate=Object + target.Coordinate=coord target.Life0=1 target.Life=1