diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua index bdedec8a1..854252cbc 100644 --- a/Moose Development/Moose/Core/Base.lua +++ b/Moose Development/Moose/Core/Base.lua @@ -717,6 +717,22 @@ function BASE:CreateEventCrash( EventTime, Initiator ) world.onEvent( Event ) end +--- Creation of a Crash Event. +-- @param #BASE self +-- @param DCS#Time EventTime The time stamp of the event. +-- @param DCS#Object Initiator The initiating object of the event. +function BASE:CreateEventUnitLost(EventTime, Initiator) + self:F( { EventTime, Initiator } ) + + local Event = { + id = world.event.S_EVENT_UNIT_LOST, + time = EventTime, + initiator = Initiator, + } + + world.onEvent( Event ) +end + --- Creation of a Dead Event. -- @param #BASE self -- @param DCS#Time EventTime The time stamp of the event. diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index 9f1f6a9b3..a2c2e2fd4 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -14,7 +14,6 @@ --- AIRWING class. -- @type AIRWING -- @field #string ClassName Name of the class. --- @field #boolean Debug Debug mode. Messages to all about status. -- @field #number verbose Verbosity of output. -- @field #string lid Class id string for output to DCS log file. -- @field #table menu Table of menu items. @@ -109,7 +108,6 @@ -- @field #AIRWING AIRWING = { ClassName = "AIRWING", - Debug = false, verbose = 0, lid = nil, menu = nil, @@ -394,7 +392,7 @@ function AIRWING:FetchPayloadFromStock(UnitType, MissionType, Payloads) end -- Debug. - if self.Debug then + if self.verbose>=4 then self:I(self.lid..string.format("Looking for payload for unit type=%s and mission type=%s", UnitType, MissionType)) for i,_payload in pairs(self.payloads) do local payload=_payload --#AIRWING.Payload @@ -456,7 +454,7 @@ function AIRWING:FetchPayloadFromStock(UnitType, MissionType, Payloads) end -- Debug. - if self.Debug then + if self.verbose>=4 then self:I(self.lid..string.format("Sorted payloads for mission type X and aircraft type=Y:")) for _,_payload in ipairs(self.payloads) do local payload=_payload --#AIRWING.Payload @@ -576,7 +574,7 @@ end --- Remove asset from squadron. -- @param #AIRWING self --- @param #AIRWING.SquadronAsset Asset +-- @param #AIRWING.SquadronAsset Asset The squad asset. function AIRWING:RemoveAssetFromSquadron(Asset) local squad=self:GetSquadronOfAsset(Asset) if squad then @@ -1541,7 +1539,9 @@ function AIRWING:onafterSquadAssetReturned(From, Event, To, Squadron, Asset) self:T(self.lid..string.format("Asset %s from squadron %s returned! asset.assignment=\"%s\"", Asset.spawngroupname, Squadron.name, tostring(Asset.assignment))) -- Stop flightgroup. - Asset.flightgroup:Stop() + if Asset.flightgroup and not Asset.flightgroup:IsStopped() then + Asset.flightgroup:Stop() + end -- Return payload. self:ReturnPayloadFromAsset(Asset) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 5339dd03f..b3d25e27b 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -2552,10 +2552,8 @@ end -- @param #string To To state. -- @param Ops.AirWing#AIRWING.SquadronAsset Asset The asset. function AUFTRAG:onafterAssetDead(From, Event, To, Asset) - - -- Remove opsgroup from mission. - --self:DelOpsGroup(Asset.opsgroup) - + + -- Number of groups alive. local N=self:CountOpsGroups() -- All assets dead? @@ -2568,15 +2566,22 @@ function AUFTRAG:onafterAssetDead(From, Event, To, Asset) else - self:E(self.lid.."ERROR: All assets are dead not but mission was already over... Investigate!") + --self:E(self.lid.."ERROR: All assets are dead not but mission was already over... Investigate!") -- Now this can happen, because when a opsgroup dies (sometimes!), the mission is DONE end end - -- Remove asset from airwing. + -- Asset belonged to an airwing. if self.airwing then - self.airwing:RemoveAssetFromSquadron(Asset) + + if self.Ncasualties==self.Nelements then + -- All elements were destroyed ==> Asset is gone. + self.airwing:RemoveAssetFromSquadron(Asset) + else + -- Not all assets were destroyed (despawn) ==> Add asset back to airwing. + self.airwing:AddAsset(Asset.flightgroup.group, 1) + end end -- Delete asset from mission. diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 38de11853..886eee119 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -46,6 +46,7 @@ -- @field #boolean ishelo If true, the is a helicopter group. -- @field #number callsignName Callsign name. -- @field #number callsignNumber Callsign number. +-- @field #number Ndestroyed Number of destroyed units. -- -- @extends Ops.OpsGroup#OPSGROUP @@ -132,6 +133,7 @@ FLIGHTGROUP = { Tparking = nil, menu = nil, ishelo = nil, + Ndestroyed = 0, } @@ -1346,15 +1348,9 @@ end -- @param #string To To state. -- @param #FLIGHTGROUP.Element Element The flight group element. function FLIGHTGROUP:onafterElementDestroyed(From, Event, To, Element) - self:T(self.lid..string.format("Element dead %s.", Element.name)) - - -- Cancel all missions. - for _,_mission in pairs(self.missionqueue) do - local mission=_mission --Ops.Auftrag#AUFTRAG - mission:ElementDestroyed(self, Element) - - end + -- Call OPSGROUP function. + self:GetParent(self).onafterElementDestroyed(self, From, Event, To, Element) end @@ -1365,7 +1361,9 @@ end -- @param #string To To state. -- @param #FLIGHTGROUP.Element Element The flight group element. function FLIGHTGROUP:onafterElementDead(From, Event, To, Element) - self:T(self.lid..string.format("Element dead %s.", Element.name)) + + -- Call OPSGROUP function. + self:GetParent(self).onafterElementDead(self, From, Event, To, Element) if self.flightcontrol and Element.parking then self.flightcontrol:SetParkingFree(Element.parking) @@ -1373,9 +1371,7 @@ function FLIGHTGROUP:onafterElementDead(From, Event, To, Element) -- Not parking any more. Element.parking=nil - - -- Set element status. - self:_UpdateStatus(Element, OPSGROUP.ElementStatus.DEAD) + end @@ -1569,7 +1565,6 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. --- @param Wrapper.Airbase#AIRBASE airbase The airbase the flight landed. function FLIGHTGROUP:onafterLandedAt(From, Event, To) self:I(self.lid..string.format("Flight landed at")) end @@ -1601,11 +1596,6 @@ end -- @param #string Event Event. -- @param #string To To state. function FLIGHTGROUP:onafterDead(From, Event, To) - self:T(self.lid..string.format("Flight dead!")) - - -- Delete waypoints so they are re-initialized at the next spawn. - self.waypoints=nil - self.groupinitialized=false -- Remove flight from all FC queues. if self.flightcontrol then @@ -1613,17 +1603,9 @@ function FLIGHTGROUP:onafterDead(From, Event, To) self.flightcontrol=nil end - -- Cancel all missions. - for _,_mission in pairs(self.missionqueue) do - local mission=_mission --Ops.Auftrag#AUFTRAG - - self:MissionCancel(mission) - mission:GroupDead(self) - - end - - -- Stop - self:Stop() + -- Call OPSGROUP function. + self:GetParent(self).onafterDead(self, From, Event, To) + end diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 91d0168ba..7fe4b81d5 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -491,12 +491,20 @@ function OPSGROUP:GetDCSGroup() return DCSGroup end ---- Get DCS GROUP object. +--- Get MOOSE UNIT object. -- @param #OPSGROUP self --- @return DCS#Group DCS group object. +-- @param #number UnitNumber Number of the unit in the group. Default first unit. +-- @return Wrapper.Unit#UNIT The MOOSE UNIT object. function OPSGROUP:GetUnit(UnitNumber) - local DCSGroup=Group.getByName(self.groupname) - return DCSGroup + + local DCSUnit=self:GetDCSUnit(UnitNumber) + + if DCSUnit then + local unit=UNIT:Find(DCSUnit) + return unit + end + + return nil end --- Get DCS GROUP object. @@ -515,15 +523,68 @@ function OPSGROUP:GetDCSUnit(UnitNumber) return nil end ---- Despawn group. +--- Get DCS units. -- @param #OPSGROUP self --- @return #OPSGROUP self -function OPSGROUP:DespawnGroup() +-- @return #list DCS units. +function OPSGROUP:GetDCSUnits() local DCSGroup=self:GetDCSGroup() if DCSGroup then + local units=DCSGroup:getUnits() + return units + end + + return nil +end + +--- Despawn the group. The whole group is despawned and (optionally) a "Remove Unit" event is generated for all current units of the group. +-- @param #OPSGROUP self +-- @return #OPSGROUP self +function OPSGROUP:Despawn() + + local DCSGroup=self:GetDCSGroup() + + if DCSGroup then + + -- Destroy DCS group. DCSGroup:destroy() + + -- Get all units. + local units=self:GetDCSUnits() + + -- Create a "Remove Unit" event. + local EventTime=timer.getTime() + for i=1,#units do + self:CreateEventRemoveUnit(EventTime, units[i]) + end + end + + return self +end + +--- Destroy group. The whole group is despawned and a "Unit Lost" event is generated for all current units. +-- @param #OPSGROUP self +-- @return #OPSGROUP self +function OPSGROUP:Destroy() + + local DCSGroup=self:GetDCSGroup() + + if DCSGroup then + + self:I(self.lid.."Destroying group ") + + -- Destroy DCS group. + DCSGroup:destroy() + + -- Get all units. + local units=self:GetDCSUnits() + + -- Create a "Unit Lost" event. + local EventTime=timer.getTime() + for i=1,#units do + self:CreateEventUnitLost(EventTime, units[i]) + end end return self @@ -538,6 +599,7 @@ function OPSGROUP:DespawnUnit(UnitName) if DCSGroup then DCSGroup:destroy() + self:CreateEventRemoveUnit(timer.getTime(), DCSObject) end return self @@ -2347,7 +2409,7 @@ function OPSGROUP:_QueueUpdate() --- -- First check if group is alive? Late activated groups are activated and uncontrolled units are started automatically. - if self:IsAlive()~=nil then + if self:IsExist() then local mission=self:_GetNextMission() @@ -2564,6 +2626,67 @@ function OPSGROUP:onafterLeaveZone(From, Event, To, Zone) self.inzones:Remove(zonename, true) end + +--- On after "ElementDestroyed" event. +-- @param #OPSGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #OPSGROUP.Element Element The flight group element. +function OPSGROUP:onafterElementDestroyed(From, Event, To, Element) + self:I(self.lid..string.format("Element destroyed %s", Element.name)) + + -- Cancel all missions. + for _,_mission in pairs(self.missionqueue) do + local mission=_mission --Ops.Auftrag#AUFTRAG + + mission:ElementDestroyed(self, Element) + + end + + -- Set element status. + self:_UpdateStatus(Element, OPSGROUP.ElementStatus.DEAD) + +end + +--- On after "ElementDead" event. +-- @param #OPSGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #OPSGROUP.Element Element The flight group element. +function OPSGROUP:onafterElementDead(From, Event, To, Element) + self:I(self.lid..string.format("Element dead %s", Element.name)) + + -- Set element status. + self:_UpdateStatus(Element, OPSGROUP.ElementStatus.DEAD) +end + +--- On after "Dead" event. +-- @param #OPSGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function OPSGROUP:onafterDead(From, Event, To) + self:T(self.lid..string.format("Flight dead!")) + + -- Delete waypoints so they are re-initialized at the next spawn. + self.waypoints=nil + self.groupinitialized=false + + -- Cancel all missions. + for _,_mission in pairs(self.missionqueue) do + local mission=_mission --Ops.Auftrag#AUFTRAG + + self:MissionCancel(mission) + mission:GroupDead(self) + + end + + -- Stop + self:Stop() +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Internal Check Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -3427,6 +3550,7 @@ function OPSGROUP:GetTACAN() return self.tacan.Channel, self.tacan.Morse, self.tacan.Band, self.tacan.On, self.tacan.BeaconName end + --- Activate/switch ICLS beacon settings. -- @param #OPSGROUP self -- @param #OPSGROUP.Beacon Icls ICLS data table. @@ -3628,6 +3752,8 @@ function OPSGROUP:TurnOffRadio() return self end + + --- Set default formation. -- @param #OPSGROUP self -- @param #number Formation The formation the groups flies in. @@ -3673,6 +3799,8 @@ function OPSGROUP:SwitchFormation(Formation) return self end + + --- Set default formation. -- @param #OPSGROUP self -- @param #number CallsignName Callsign name. diff --git a/Moose Development/Moose/Ops/Squadron.lua b/Moose Development/Moose/Ops/Squadron.lua index a711f754c..bb620d089 100644 --- a/Moose Development/Moose/Ops/Squadron.lua +++ b/Moose Development/Moose/Ops/Squadron.lua @@ -17,7 +17,6 @@ --- SQUADRON class. -- @type SQUADRON -- @field #string ClassName Name of the class. --- @field #boolean Debug Debug mode. Messages to all about status. -- @field #number verbose Verbosity level. -- @field #string lid Class id string for output to DCS log file. -- @field #string name Name of the squadron. @@ -63,8 +62,7 @@ -- @field #SQUADRON SQUADRON = { ClassName = "SQUADRON", - Debug = nil, - verbose = 0, + verbose = 3, lid = nil, name = nil, templatename = nil, @@ -199,7 +197,6 @@ function SQUADRON:New(TemplateGroupName, Ngroups, SquadronName) -- Debug trace. if false then - self.Debug=true BASE:TraceOnOff(true) BASE:TraceClass(self.ClassName) BASE:TraceLevel(1) @@ -658,7 +655,7 @@ function SQUADRON:_CheckAssetStatus() local asset=_asset --Ops.AirWing#AIRWING.SquadronAsset -- Text. - text=text..string.format("\n-[%d] %s*%d: ", j, asset.unittype, asset.nunits) + text=text..string.format("\n-[%d] %s (%s*%d): ", j, asset.spawngroupname, asset.unittype, asset.nunits) if asset.spawned then @@ -670,7 +667,7 @@ function SQUADRON:_CheckAssetStatus() local mission=self.airwing and self.airwing:GetAssetCurrentMission(asset) or false if mission then local distance=asset.flightgroup and UTILS.MetersToNM(mission:GetTargetDistance(asset.flightgroup.group:GetCoordinate())) or 0 - text=text..string.format(" Mission %s - %s: Status=%s, Dist=%.1f NM", mission.name, mission.type, mission.status, distance) + text=text..string.format("Mission %s - %s: Status=%s, Dist=%.1f NM", mission.name, mission.type, mission.status, distance) else text=text.."Mission None" end @@ -708,15 +705,24 @@ function SQUADRON:_CheckAssetStatus() --- -- In Stock --- + + text=text..string.format("In Stock") + + if self:IsRepaired(asset) then + text=text.." and Combat Ready" + else + + text=text..string.format(", Repaired in %d sec", self:GetRepairTime(asset)) + + if asset.damage then + text=text..string.format(" (Damage=%.1f)", asset.damage) + end + end if asset.Treturned then local T=timer.getAbsTime()-asset.Treturned - text=text..string.format(" Treturn=%d sec", T) + text=text..string.format(", Returned for %d sec", T) end - if asset.damage then - text=text..string.format(" Damage=%.1f", asset.damage) - end - text=text..string.format(" Repaired=%s T=%d sec", tostring(self:IsRepaired(asset)), self:GetRepairTime(asset)) end end