diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index dcd5e46ed..3bffa6b66 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1169,7 +1169,10 @@ function AUFTRAG:NewARTY(Target, Nshots, Radius) mission.optionROE=ENUMS.ROE.OpenFire -- Ground/naval need open fire! mission.optionAlarm=0 - mission.missionFraction=0.1 + mission.missionFraction=0.0 + + -- Evaluate after 8 min. + mission.dTevaluate=8*60 mission.DCStask=mission:GetDCSMissionTask() @@ -1185,30 +1188,11 @@ function AUFTRAG:NewTargetAir(Target) local mission=nil --#AUFTRAG self.engageTarget=Target - - --[[ - if Target.category==TARGET.Category.GROUND then - - - elseif Target.category==TARGET.Category.AIRCRAFT then - - mission=AUFTRAG:NewINTERCEPT(Target) - - elseif Target.category==TARGET.Category.AIRBASE then - - mission=AUFTRAG:NewBOMBRUNWAY(Airdrome,Altitude) - - elseif Target.category==TARGET.Category.COORDINATE then - - - end - ]] - + local target=self.engageTarget:GetObject() local mission=self:NewAUTO(target) - if mission then mission:SetPriority(10, true) end @@ -2133,6 +2117,9 @@ function AUFTRAG:Evaluate() local Ntargets=self:CountMissionTargets() local Ntargets0=self:GetTargetInitialNumber() + local Life=self:GetTargetLife() + local Life0=self:GetTargetInitialLife() + if Ntargets0>0 then @@ -2196,6 +2183,7 @@ function AUFTRAG:Evaluate() text=text..string.format("Own losses = %.1f %%\n", owndamage) 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) diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index f708d2c86..025fdb905 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -708,6 +708,41 @@ end -- @param #FLIHGTGROUP self function FLIGHTGROUP:onbeforeStatus(From, Event, To) + -- First we check if elements are still alive. Could be that they were despawned without notice, e.g. when landing on a too small airbase. + for i,_element in pairs(self.elements) do + local element=_element --#FLIGHTGROUP.Element + + -- Check that element is not already dead or not yet alive. + if element.status~=OPSGROUP.ElementStatus.DEAD and element.status~=OPSGROUP.ElementStatus.INUTERO then + + -- Unit shortcut. + local unit=element.unit + + local isdead=false + if unit and unit:IsAlive() then + + -- Get life points. + local life=unit:GetLife() or 0 + + -- Units with life <=1 are dead. + if life<=1 then + isdead=true + end + + else + -- Not alive any more. + 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) + end + + end + end + if self:IsDead() then self:T(self.lid..string.format("Onbefore Status DEAD ==> false")) return false @@ -1327,18 +1362,27 @@ end -- @param Wrapper.Airbase#AIRBASE airbase The airbase if applicable or nil. function FLIGHTGROUP:onafterElementLanded(From, Event, To, Element, airbase) self:T2(self.lid..string.format("Element landed %s at %s airbase", Element.name, airbase and airbase:GetName() or "unknown")) + + if self.despawnAfterLanding then + + -- Despawn the element. + self:DespawnElement(Element) + + else - -- Helos with skids land directly on parking spots. - if self.ishelo then - - local Spot=self:GetParkingSpot(Element, 10, airbase) - - self:_SetElementParkingAt(Element, Spot) - + -- Helos with skids land directly on parking spots. + if self.ishelo then + + local Spot=self:GetParkingSpot(Element, 10, airbase) + + self:_SetElementParkingAt(Element, Spot) + + end + + -- Set element status. + self:_UpdateStatus(Element, OPSGROUP.ElementStatus.LANDED, airbase) + end - - -- Set element status. - self:_UpdateStatus(Element, OPSGROUP.ElementStatus.LANDED, airbase) end --- On after "ElementArrived" event. @@ -1410,6 +1454,9 @@ function FLIGHTGROUP:onafterSpawned(From, Event, To) -- Set ROT. self:SwitchROT(self.option.ROT) + + -- Set Formation + self:SwitchFormation(self.option.Formation) -- Turn TACAN beacon on. if self.tacan.On then @@ -1572,10 +1619,6 @@ function FLIGHTGROUP:onafterLanded(From, Event, To, airbase) -- Add flight to taxiinb queue. self.flightcontrol:SetFlightStatus(self, FLIGHTCONTROL.FlightStatus.TAXIINB) end - - if self.despawnAfterLanding then - self:Despawn() - end end @@ -1603,9 +1646,9 @@ function FLIGHTGROUP:onafterArrived(From, Event, To) self.flightcontrol:SetFlightStatus(self, FLIGHTCONTROL.FlightStatus.ARRIVED) end - -- Stop and despawn in 5 min. + -- Despawn in 5 min. if not self.airwing then - self:__Stop(5*60) + self:Despawn(5*60) end end @@ -1731,9 +1774,11 @@ function FLIGHTGROUP:onafterUpdateRoute(From, Event, To, n) -- Set current waypoint or we get problem that the _PassingWaypoint function is triggered too early, i.e. right now and not when passing the next WP. local current=self.group:GetCoordinate():WaypointAir(COORDINATE.WaypointAltType.BARO, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, speed, true, nil, {}, "Current") table.insert(wp, current) + + local Nwp=self.waypoints and #self.waypoints or 0 -- Add remaining waypoints to route. - for i=n, #self.waypoints do + for i=n, Nwp do table.insert(wp, self.waypoints[i]) end @@ -2437,9 +2482,6 @@ function FLIGHTGROUP:onafterStop(From, Event, To) end end - -- Destroy group. No event is generated. - -- DISABLED for now. Should use :Despawn() or :Destroy() which then calls stop. - --self.group:Destroy(false) end -- Handle events: diff --git a/Moose Development/Moose/Ops/NavyGroup.lua b/Moose Development/Moose/Ops/NavyGroup.lua index 7ae587da8..a8d1b91e7 100644 --- a/Moose Development/Moose/Ops/NavyGroup.lua +++ b/Moose Development/Moose/Ops/NavyGroup.lua @@ -575,7 +575,7 @@ function NAVYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Depth) n=n or self:GetWaypointIndexNext() -- Debug info. - self:T(self.lid..string.format("FF Update route n=%d", n)) + self:T(self.lid..string.format("Update route n=%d", n)) -- Update waypoint tasks, i.e. inject WP tasks into waypoint table. self:_UpdateWaypointTasks(n) @@ -784,6 +784,7 @@ end -- @param #string Event Event. -- @param #string To To state. function NAVYGROUP:onafterFullStop(From, Event, To) + self:T(self.lid.."Full stop ==> holding") -- Get current position. local pos=self:GetCoordinate() diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 37b4d5dcd..800ca42bf 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -669,16 +669,37 @@ function OPSGROUP:Destroy(Delay) return self end ---- Despawn a unit. +--- Despawn an element/unit of the group. -- @param #OPSGROUP self +-- @param #OPSGROUP.Element Element The element that will be despawned. +-- @param #number Delay Delay in seconds before the element will be despawned. Default immediately. +-- @param #boolean NoEventRemoveUnit If true, no event "Remove Unit" is generated. -- @return #OPSGROUP self -function OPSGROUP:DespawnUnit(UnitName) +function OPSGROUP:DespawnElement(Element, Delay, NoEventRemoveUnit) - local DCSGroup=self:GetDCSGroup() + if Delay and Delay>0 then + self:ScheduleOnce(Delay, OPSGROUP.DespawnElement, self, Element, 0, NoEventRemoveUnit) + else + + if Element then + + -- Get DCS unit object. + local DCSunit=Unit.getByName(Element.name) - if DCSGroup then - DCSGroup:destroy() - self:CreateEventRemoveUnit(timer.getTime(), DCSObject) + if DCSunit then + + -- Destroy object. + DCSunit:destroy() + + -- Create a remove unit event. + if not NoEventRemoveUnit then + self:CreateEventRemoveUnit(timer.getTime(), DCSunit) + end + + end + + end + end return self @@ -1082,7 +1103,7 @@ end function OPSGROUP:GetWaypointIndex(uid) if uid then - for i,_waypoint in pairs(self.waypoints) do + for i,_waypoint in pairs(self.waypoints or {}) do local waypoint=_waypoint --#OPSGROUP.Waypoint if waypoint.uid==uid then return i @@ -2241,12 +2262,7 @@ function OPSGROUP:onafterMissionExecute(From, Event, To, Mission) -- Set mission status to EXECUTING. Mission:Executing() - - -- Formation - if Mission.optionFormation then - self:SwitchFormation(Mission.optionFormation) - end - + end --- On after "PauseMission" event. @@ -2371,7 +2387,7 @@ function OPSGROUP:onafterMissionDone(From, Event, To, Mission) -- Remove mission waypoint. local wpidx=Mission:GetGroupWaypointIndex(self) if wpidx then - self:RemoveWaypoint(wpidx) + self:RemoveWaypointByID(wpidx) end -- Decrease patrol data. @@ -2380,6 +2396,27 @@ function OPSGROUP:onafterMissionDone(From, Event, To, Mission) AIRWING.UpdatePatrolPointMarker(Mission.patroldata) end + -- ROE to default. + if Mission.optionROE then + self:SwitchROE() + end + -- ROT to default + if Mission.optionROT then + self:SwitchROT() + end + -- Alarm state to default. + if Mission.optionAlarm then + self:SwitchAlarmstate() + end + -- Formation to default. + if Mission.optionFormation then + self:SwitchFormation() + end + -- Radio freq and modu to last used. + if Mission.radio and self.radioLast then + self:SwitchRadio(self.radioLast.Freq, self.radioLast.Modu) + end + -- TACAN if Mission.tacan then @@ -2399,23 +2436,8 @@ function OPSGROUP:onafterMissionDone(From, Event, To, Mission) asset.tacan=nil end end - - -- TODO: reset mission specific parameters like radio, ROE etc. - if Mission.radio and self.radioLast then - self:SwitchRadio(self.radioLast.Freq, self.radioLast.Modu) - end - if Mission.optionROE then - self:SwitchROE() - end - - if Mission.optionROT then - self:SwitchROT() - end - - if Mission.optionAlarm then - self:SwitchAlarmstate() - end + -- TODO: reset ICLS settings. -- Check if group is done. self:_CheckGroupDone(1) @@ -2482,17 +2504,21 @@ function OPSGROUP:RouteToMission(mission, delay) -- Check if we are within range. if dist>weapondata.RangeMax then - local d=dist-weapondata.RangeMax - d=(1.1)*d + + local d=(dist-weapondata.RangeMax)*1.1 -- New waypoint coord. waypointcoord=self:GetCoordinate():Translate(d, heading) + + self:T(self.lid..string.format("Out of max range = %.1f km for weapon %d", weapondata.RangeMax/1000, mission.engageWeaponType)) elseif dist Trigger "DetectedUnitKnown" event. + self:DetectedUnitKnown(Unit) + else + -- Unit is was not detected ==> Trigger "DetectedUnitNew" event. + self:DetectedUnitNew(Unit) + end + end --- On after "DetectedUnitNew" event. @@ -2747,6 +2791,9 @@ end -- @param Wrapper.Unit#UNIT Unit The detected unit. function OPSGROUP:onafterDetectedUnitNew(From, Event, To, Unit) self:T(self.lid..string.format("Detected New unit %s", Unit:GetName())) + + -- Add unit to detected unit set. + self.detectedunits:AddUnit(Unit) end --- On after "EnterZone" event. Sets self.inzones[zonename]=true. @@ -2851,9 +2898,11 @@ function OPSGROUP:onafterStop(From, Event, To) -- Stop FSM scheduler. self.CallScheduler:Clear() - if self:IsAlive() then + if self:IsAlive() and not (self:IsDead() or self:IsStopped()) then local life, life0=self:GetLifePoints() - self:E(self.lid..string.format("WARNING: Group is still alive! Life points=%d/%d. Use OPSGROUP:Destroy() or OPSGROUP:Despawn() for a clean stop", life, life0)) + local state=self:GetState() + local text=string.format("WARNING: Group is still alive! Current state=%s. Life points=%d/%d. Use OPSGROUP:Destroy() or OPSGROUP:Despawn() for a clean stop", state, life, life0) + self:E(self.lid..text) end -- Debug output. @@ -2931,6 +2980,8 @@ function OPSGROUP:_CheckDetectedUnits() local DetectedObject=Detection.object -- DCS#Object if DetectedObject and DetectedObject:isExist() and DetectedObject.id_<50000000 then + + -- Unit. local unit=UNIT:Find(DetectedObject) if unit and unit:IsAlive() then @@ -2941,17 +2992,9 @@ function OPSGROUP:_CheckDetectedUnits() -- Add unit to detected table of this run. table.insert(detected, unit) - -- Trigger detected unit event. + -- Trigger detected unit event ==> This also triggers the DetectedUnitNew and DetectedUnitKnown events. self:DetectedUnit(unit) - if self.detectedunits:FindUnit(unitname) then - -- Unit is already in the detected unit set ==> Trigger "DetectedUnitKnown" event. - self:DetectedUnitKnown(unit) - else - -- Unit is was not detected ==> Trigger "DetectedUnitNew" event. - self:DetectedUnitNew(unit) - end - end end end @@ -3059,6 +3102,8 @@ function OPSGROUP:_CheckGroupDone(delay) --- No waypoints left -- No further waypoints. Command a full stop. + self:T(self.lid..string.format("No waypoints left ==> Full Stop")) + self:__FullStop(-1) end @@ -3197,7 +3242,15 @@ function OPSGROUP:_AddWaypoint(waypoint, wpnumber) table.insert(self.waypoints, wpnumber, waypoint) -- Debug info. - self:T2(self.lid..string.format("Adding waypoint at index=%d id=%d", wpnumber, waypoint.uid)) + self:T(self.lid..string.format("Adding waypoint at index=%d id=%d", wpnumber, waypoint.uid)) + + -- Now we obviously did not pass the final waypoint. + self.passedfinalwp=false + + -- Switch to cruise mode. + if self:IsHolding() then + self:Cruise() + end end --- Initialize Mission Editor waypoints. @@ -3288,7 +3341,7 @@ end -- @param #number n Waypoint function OPSGROUP:_UpdateWaypointTasks(n) - local waypoints=self.waypoints + local waypoints=self.waypoints or {} local nwaypoints=#waypoints for i,_wp in pairs(waypoints) do