diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 98bce2200..213805a8d 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -3825,7 +3825,7 @@ function WAREHOUSE:onafterAddAsset(From, Event, To, group, ngroups, forceattribu -- Destroy group if it is alive. if group:IsAlive()==true then - asset.damage=group:GetDamage() + asset.damage=asset.life0-group:GetLife() end -- Add asset to stock. @@ -3871,6 +3871,7 @@ function WAREHOUSE:onafterAddAsset(From, Event, To, group, ngroups, forceattribu if group:IsAlive()==true then self:_DebugMessage(string.format("Removing group %s", group:GetName()), 5) -- Setting parameter to false, i.e. creating NO dead or remove unit event, seems to not confuse the dispatcher logic. + -- TODO: It would be nice, however, to have the remove event. group:Destroy(false) end @@ -3997,6 +3998,7 @@ function WAREHOUSE:_RegisterAsset(group, ngroups, forceattribute, forcecargobay, asset.skill=skill asset.assignment=assignment asset.spawned=false + asset.life0=group:GetLife0() asset.damage=0 asset.spawngroupname=string.format("%s_AID-%d", templategroupname, asset.uid) @@ -4797,22 +4799,8 @@ function WAREHOUSE:onafterArrived(From, Event, To, group) group:RouteGroundTo(warehouse:GetCoordinate(), group:GetSpeedMax()*0.3, "Off Road") end - -- NOTE: This is done in the AddAsset() function. Dont know, why we do it also here. - --[[ - if istransport==true then - request.ntransporthome=request.ntransporthome+1 - request.transportgroupset:Remove(group:GetName(), true) - self:T2(warehouse.lid..string.format("Transport %d of %s returned home.", request.ntransporthome, tostring(request.ntransport))) - elseif istransport==false then - request.ndelivered=request.ndelivered+1 - request.cargogroupset:Remove(self:_GetNameWithOut(group), true) - self:T2(warehouse.lid..string.format("Cargo %d of %s delivered.", request.ndelivered, tostring(request.nasset))) - else - self:E(warehouse.lid..string.format("ERROR: Group %s is neither cargo nor transport!", group:GetName())) - end - ]] - -- Move asset from pending queue into new warehouse. + env.info("FF asset arrived in wh. adding in 60 sec") warehouse:__AddAsset(60, group) end @@ -6267,7 +6255,6 @@ function WAREHOUSE:_OnEventArrived(EventData) local istransport=self:_GroupIsTransport(group, request) -- Get closest airbase. - -- Note, this crashed at somepoint when the Tarawa was in the mission. Don't know why. Deleting the Tarawa and adding it again solved the problem. local closest=group:GetCoordinate():GetClosestAirbase() -- Check if engine shutdown happend at right airbase because the event is also triggered in other situations. @@ -6276,15 +6263,17 @@ function WAREHOUSE:_OnEventArrived(EventData) -- Check that group is cargo and not transport. if istransport==false and rightairbase then - -- Debug info. - local text=string.format("Air asset group %s from warehouse %s arrived at its destination.", group:GetName(), self.alias) - self:_InfoMessage(text) - -- Trigger arrived event for this group. Note that each unit of a group will trigger this event. So the onafterArrived function needs to take care of that. -- Actually, we only take the first unit of the group that arrives. If it does, we assume the whole group arrived, which might not be the case, since -- some units might still be taxiing or whatever. Therefore, we add 10 seconds for each additional unit of the group until the first arrived event is triggered. local nunits=#group:GetUnits() local dt=10*(nunits-1)+1 -- one unit = 1 sec, two units = 11 sec, three units = 21 sec before we call the group arrived. + + -- Debug info. + local text=string.format("Air asset group %s from warehouse %s arrived at its destination. Trigger Arrived event in %d sec", group:GetName(), self.alias, dt) + self:_InfoMessage(text) + + self:__Arrived(dt, group) end diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index 2d2d28ae7..0138f78b4 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -193,9 +193,13 @@ function AIRWING:New(warehousename, airwingname) self.lid=string.format("AIRWING %s | ", self.alias) -- Add FSM transitions. - -- From State --> Event --> To State - self:AddTransition("*", "MissionRequest", "*") -- Add a (mission) request to the warehouse. - self:AddTransition("*", "MissionCancel", "*") -- Cancel mission. + -- From State --> Event --> To State + self:AddTransition("*", "MissionRequest", "*") -- Add a (mission) request to the warehouse. + self:AddTransition("*", "MissionCancel", "*") -- Cancel mission. + + self:AddTransition("*", "SquadAssetReturned", "*") -- Flight was spawned with a mission. + + self:AddTransition("*", "FlightOnMission", "*") -- Flight was spawned with a mission. -- Defaults: self.nflightsCAP=0 @@ -286,14 +290,9 @@ function AIRWING:NewPayload(Unit, Npayloads, MissionTypes, Performance) if type(Unit)=="string" then local name=Unit - env.info("unit as string "..Unit) Unit=UNIT:FindByName(name) if not Unit then - env.info("no UNIT trying group") Unit=GROUP:FindByName(name) - if not Unit then - env.info("no GROUP either!") - end end end @@ -808,7 +807,7 @@ function AIRWING:onafterStatus(From, Event, To) text=text..string.format("\n* %s %s: %s*%d/%d, Callsign=%s, Modex=%d, Skill=%s", squadron.name, squadron:GetState(), squadron.aircrafttype, squadron:CountAssetsInStock(), #squadron.assets, callsign, modex, skill) -- Loop over all assets. - if self.verbose>0 then + if self.verbose>1 then for j,_asset in pairs(squadron.assets) do local asset=_asset --#AIRWING.SquadronAsset local assignment=asset.assignment or "none" @@ -1062,7 +1061,11 @@ function AIRWING:GetTankerForFlight(flightgroup) local dist=assetcoord:Get2DDistance(tankercoord) - table.insert(tankeropt, {tanker=tanker, dist=dist}) + -- Ensure that the flight does not find itself. Asset could be a tanker! + if dist>5 then + table.insert(tankeropt, {tanker=tanker, dist=dist}) + end + end end @@ -1070,7 +1073,11 @@ function AIRWING:GetTankerForFlight(flightgroup) table.sort(tankeropt, function(a,b) return a.dist0 then + return tankeropt[1].tanker + else + return nil + end end return nil @@ -1218,7 +1225,9 @@ function AIRWING:CalculateAssetMissionScore(asset, Mission, includePayload) local score=0 -- Prefer highly skilled assets. - if asset.skill==AI.Skill.GOOD then + if asset.skill==AI.Skill.AVERAGE then + score=score+0 + elseif asset.skill==AI.Skill.GOOD then score=score+10 elseif asset.skill==AI.Skill.HIGH then score=score+20 @@ -1337,7 +1346,7 @@ function AIRWING:onafterMissionRequest(From, Event, To, Mission) -- Need to dived to set into spawned and instock assets and handle the other --- - -- Assets to be requested + -- Assets to be requested. local Assetlist={} for _,_asset in pairs(Mission.assets) do @@ -1350,6 +1359,9 @@ function AIRWING:onafterMissionRequest(From, Event, To, Mission) -- Add new mission. asset.flightgroup:AddMission(Mission) + -- Trigger event. + self:FlightOnMission(asset.flightgroup, Mission) + else self:E(self.lid.."ERROR: flight group for asset does NOT exist!") end @@ -1438,7 +1450,7 @@ function AIRWING:onafterNewAsset(From, Event, To, asset, assignment) -- Debug text. local text=string.format("New asset %s with assignment %s and request assignment %s", asset.spawngroupname, tostring(asset.assignment), tostring(assignment)) - self:T3(self.lid..text) + self:I(self.lid..text) -- Get squadron. local squad=self:GetSquadron(asset.assignment) @@ -1454,10 +1466,7 @@ function AIRWING:onafterNewAsset(From, Event, To, asset, assignment) local text=string.format("Adding asset to squadron %s: assignment=%s, type=%s, attribute=%s, nunits=%d %s", squad.name, assignment, asset.unittype, asset.attribute, nunits, tostring(squad.ngrouping)) self:I(self.lid..text) - -- Create callsign and modex. - squad:GetCallsign(asset) - squad:GetModex(asset) - + -- Adjust number of elements in the group. if squad.ngrouping then local template=asset.template @@ -1471,7 +1480,7 @@ function AIRWING:onafterNewAsset(From, Event, To, asset, assignment) -- If grouping is larger than units present, copy first unit. if i>nunits then - table.insert(template.units, UTILS.DeepCopy(template.units[1])) + table.insert(template.units, UTILS.DeepCopy(template.units[1])) end -- Remove units if original template contains more than in grouping. @@ -1483,24 +1492,48 @@ function AIRWING:onafterNewAsset(From, Event, To, asset, assignment) asset.nunits=squad.ngrouping end + -- Create callsign and modex (needs to be after grouping). + squad:GetCallsign(asset) + squad:GetModex(asset) + + -- Set spawn group name. This has to include "AID-" for warehouse. + asset.spawngroupname=string.format("%s_AID-%d", squad.name, asset.uid) + -- Add asset to squadron. squad:AddAsset(asset) - --asset.terminalType=AIRBASE.TerminalType.OpenBig + -- TODO + --asset.terminalType=AIRBASE.TerminalType.OpenBig else - self:I(self.lid..string.format("Asset %s from squadron %s returned! asset.assignment=\"%s\", assignment=\"%s\"", asset.spawngroupname, squad.name, tostring(asset.assignment), tostring(assignment))) - self:ReturnPayloadFromAsset(asset) - - -- Set timestamp. - asset.Treturned=timer.getAbsTime() + env.info("FF squad asset returned") + self:SquadAssetReturned(squad, asset) end end end - +--- On after "AssetReturned" event. Triggered when an asset group returned to its airwing. +-- @param #AIRWING self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Ops.Squadron#SQUADRON Squadron The asset squadron. +-- @param #AIRWING.SquadronAsset Asset The asset that returned. +function AIRWING:onafterSquadAssetReturned(From, Event, To, Squadron, Asset) + -- Debug message. + self:I(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() + + -- Return payload. + self:ReturnPayloadFromAsset(Asset) + + -- Set timestamp. + Asset.Treturned=timer.getAbsTime() +end --- On after "AssetSpawned" event triggered when an asset group is spawned into the cruel world. @@ -1519,10 +1552,7 @@ function AIRWING:onafterAssetSpawned(From, Event, To, group, asset, request) -- Create a flight group. local flightgroup=self:_CreateFlightGroup(asset) - - -- Set RTB on fuel critical. - flightgroup:SetFuelCriticalThreshold(nil, true) - + -- Set airwing. flightgroup:SetAirwing(self) @@ -1547,6 +1577,12 @@ function AIRWING:onafterAssetSpawned(From, Event, To, group, asset, request) -- Not requested any more. asset.requested=nil + -- Did not return yet. + asset.Treturned=nil + + -- Set RTB on fuel critical. + flightgroup:SetFuelCriticalThreshold() + -- Get Mission (if any). local mission=self:GetMissionByID(request.assignment) @@ -1555,11 +1591,15 @@ function AIRWING:onafterAssetSpawned(From, Event, To, group, asset, request) -- RTB on low fuel if on GCCAP. if mission.type==AUFTRAG.Type.GCCAP then - flightgroup:SetFuelLowThreshold(nil, true) + flightgroup:SetFuelLowThreshold(25) + flightgroup:SetFuelLowRTB(true) end -- Add mission to flightgroup queue. asset.flightgroup:AddMission(mission) + + -- Trigger event. + self:FlightOnMission(flightgroup, mission) end -- Add group to the detection set of the WINGCOMMANDER. @@ -1869,10 +1909,11 @@ end --- Count assets on mission. -- @param #AIRWING self -- @param #table MissionTypes Types on mission to be checked. Default all. +-- @param Ops.Squadron#SQUADRON Squadron Only count assets of this squadron. Default count assets of all squadrons. -- @return #number Number of pending and queued assets. -- @return #number Number of pending assets. -- @return #number Number of queued assets. -function AIRWING:CountAssetsOnMission(MissionTypes) +function AIRWING:CountAssetsOnMission(MissionTypes, Squadron) local Nq=0 local Np=0 @@ -1881,17 +1922,21 @@ function AIRWING:CountAssetsOnMission(MissionTypes) local mission=_mission --Ops.Auftrag#AUFTRAG -- Check if this mission type is requested. - if self:CheckMissionType(mission.type, MissionTypes) then + if self:CheckMissionType(mission.type, MissionTypes or AUFTRAG.Type) then for _,_asset in pairs(mission.assets or {}) do local asset=_asset --#AIRWING.SquadronAsset - local request, isqueued=self:GetRequestByID(mission.requestID) + if Squadron==nil or Squadron.name==asset.squadname then - if isqueued then - Nq=Nq+1 - else - Np=Np+1 + local request, isqueued=self:GetRequestByID(mission.requestID) + + if isqueued then + Nq=Nq+1 + else + Np=Np+1 + end + end end diff --git a/Moose Development/Moose/Ops/ArmyGroup.lua b/Moose Development/Moose/Ops/ArmyGroup.lua index e22ba147e..0c6d1577d 100644 --- a/Moose Development/Moose/Ops/ArmyGroup.lua +++ b/Moose Development/Moose/Ops/ArmyGroup.lua @@ -703,6 +703,9 @@ function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation -- Add waypoint to table. self:_AddWaypoint(waypoint, wpnumber) + -- Get closest point to road. + waypoint.roadcoord=Coordinate:GetClosestPointToRoad(false) + -- Debug info. self:T(self.lid..string.format("Adding GROUND waypoint #%d, speed=%.1f knots. Last waypoint passed was #%s. Total waypoints #%d", wpnumber, Speed, self.currentwp, #self.waypoints)) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index cb7944935..4c02e8cb7 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -659,7 +659,7 @@ end -- @param #number Speed Orbit speed in knots. Default 350 kts. -- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West). -- @param #number Leg Length of race-track in NM. Default 10 NM. --- @param #number RefuelSystem Refueling system. +-- @param #number RefuelSystem Refueling system (0=boom, 1=probe). This info is *only* for AIRWINGs so they launch the right tanker type. -- @return #AUFTRAG self function AUFTRAG:NewTANKER(Coordinate, Altitude, Speed, Heading, Leg, RefuelSystem) diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 34aaaa818..b4b3e0ce9 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -242,8 +242,8 @@ function FLIGHTGROUP:New(group) self:AddTransition("*", "RTZ", "Inbound") -- Group is returning to destination zone. Not implemented yet! self:AddTransition("Inbound", "Holding", "Holding") -- Group is in holding pattern. - self:AddTransition("*", "Refuel", "Going4Fuel") -- Group is send to refuel at a tanker. Not implemented yet! - self:AddTransition("Going4Fuel", "Refueled", "Airborne") -- Group is send to refuel at a tanker. Not implemented yet! + self:AddTransition("*", "Refuel", "Going4Fuel") -- Group is send to refuel at a tanker. + self:AddTransition("Going4Fuel", "Refueled", "Airborne") -- Group finished refueling. self:AddTransition("*", "LandAt", "LandingAt") -- Helo group is ordered to land at a specific point. self:AddTransition("LandingAt", "LandedAt", "LandedAt") -- Helo group landed landed at a specific point. @@ -449,11 +449,22 @@ end --- Set fuel critical threshold. Triggers event "FuelCritical" and event function "OnAfterFuelCritical". -- @param #FLIGHTGROUP self -- @param #number threshold Fuel threshold in percent. Default 10 %. --- @param #boolean rtb If true, RTB on fuel critical event. -- @return #FLIGHTGROUP self -function FLIGHTGROUP:SetFuelCriticalThreshold(threshold, rtb) +function FLIGHTGROUP:SetFuelCriticalThreshold(threshold) self.fuelcriticalthresh=threshold or 10 - self.fuelcriticalrtb=rtb + return self +end + +--- Set if critical fuel threshold is reached, flight goes RTB. +-- @param #FLIGHTGROUP self +-- @param #boolean switch If true or nil, flight goes RTB. If false, turn this off. +-- @return #FLIGHTGROUP self +function FLIGHTGROUP:SetFuelCriticalRTB(switch) + if switch==false then + self.fuelcriticalrtb=false + else + self.fuelcriticalrtb=true + end return self end @@ -1593,7 +1604,9 @@ function FLIGHTGROUP:onafterArrived(From, Event, To) end -- Stop and despawn in 5 min. - self:__Stop(5*60) + if not self.airwing then + self:__Stop(5*60) + end end --- On after "Dead" event. @@ -1930,6 +1943,12 @@ function FLIGHTGROUP:onafterRTB(From, Event, To, airbase, SpeedTo, SpeedHold, Sp -- Clear holding time in any case. self.Tholding=nil + + -- Cancel all missions. + for _,_mission in pairs(self.missionqueue) do + local mission=_mission --Ops.Auftrag#AUFTRAG + self:MissionCancel(mission) + end -- Defaults: SpeedTo=SpeedTo or UTILS.KmphToKnots(self.speedCruise) @@ -2326,9 +2345,14 @@ function FLIGHTGROUP:onafterFuelLow(From, Event, To) local tanker=self.airwing:GetTankerForFlight(self) if tanker then + + self:I(self.lid..string.format("Send to refuel at tanker %s", tanker.flightgroup:GetName())) + + -- Get a coordinate towards the tanker. + local coordinate=self:GetCoordinate():GetIntermediateCoordinate(tanker.flightgroup:GetCoordinate(), 0.75) -- Send flight to tanker with refueling task. - self:Refuel(tanker.flightgroup:GetCoordinate()) + self:Refuel(coordinate) else @@ -2349,7 +2373,10 @@ function FLIGHTGROUP:onafterFuelLow(From, Event, To) self:I(self.lid..string.format("Send to refuel at tanker %s", tanker:GetName())) - self:Refuel() + -- Get a coordinate towards the tanker. + local coordinate=self:GetCoordinate():GetIntermediateCoordinate(tanker.flightgroup:GetCoordinate(), 0.75) + + self:Refuel(coordinate) return end @@ -2736,7 +2763,7 @@ end --- Find the nearest tanker. -- @param #FLIGHTGROUP self -- @param #number Radius Search radius in NM. Default 50 NM. --- @return Wrapper.Group#GROUP Closest tanker group #nil. +-- @return Wrapper.Group#GROUP Closest tanker group or `nil` if no tanker is in the given radius. function FLIGHTGROUP:FindNearestTanker(Radius) Radius=UTILS.NMToMeters(Radius or 50) diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 0ce61fdc7..14b8db4e8 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -245,7 +245,7 @@ OPSGROUP.TaskType={ -- @field #number speed Speed in m/s. -- @field #number alt Altitude in meters. For submaries use negative sign for depth. -- @field #string action Waypoint action (turning point, etc.). Ground groups have the formation here. --- @field #table task Waypoint task combo. +-- @field #table task Waypoint DCS task combo. -- @field #string type Waypoint type. -- @field #string name Waypoint description. Shown in the F10 map. -- @field #number x Waypoint x-coordinate. @@ -254,6 +254,7 @@ OPSGROUP.TaskType={ -- @field #boolean intowind If true, this waypoint is a turn into wind route point. -- @field #boolean astar If true, this waypint was found by A* pathfinding algorithm. -- @field Core.Point#COORDINATE coordinate Waypoint coordinate. +-- @field Core.Point#COORDINATE roadcoord Closest point to road. -- @field Wrapper.Marker#MARKER marker Marker on the F10 map. --- NavyGroup version. @@ -417,8 +418,9 @@ function OPSGROUP:GetSpeedCruise() end --- Set detection on or off. +-- If detection is on, detected targets of the group will be evaluated and FSM events triggered. -- @param #OPSGROUP self --- @param #boolean Switch If true, detection is on. If false or nil, detection is off. Default is off. +-- @param #boolean Switch If `true`, detection is on. If `false` or `nil`, detection is off. Default is off. -- @return #OPSGROUP self function OPSGROUP:SetDetection(Switch) self.detectionOn=Switch diff --git a/Moose Development/Moose/Ops/RecoveryTanker.lua b/Moose Development/Moose/Ops/RecoveryTanker.lua index e43cd9cc7..c368c7418 100644 --- a/Moose Development/Moose/Ops/RecoveryTanker.lua +++ b/Moose Development/Moose/Ops/RecoveryTanker.lua @@ -1345,7 +1345,6 @@ function RECOVERYTANKER:OnEventEngineShutdown(EventData) group:InitModex(self.modex) -- Respawn tanker. Delaying respawn due to DCS bug https://github.com/FlightControl-Master/MOOSE/issues/1076 - --SCHEDULER:New(nil , group.RespawnAtCurrentAirbase, {group}, 1) self:ScheduleOnce(1, GROUP.RespawnAtCurrentAirbase, group) -- Create tanker beacon and activate TACAN. @@ -1364,7 +1363,6 @@ function RECOVERYTANKER:OnEventEngineShutdown(EventData) end -- Initial route. - --SCHEDULER:New(nil, self._InitRoute, {self, -self.distStern+UTILS.NMToMeters(3)}, 2) self:ScheduleOnce(2, RECOVERYTANKER._InitRoute, self, -self.distStern+UTILS.NMToMeters(3)) end diff --git a/Moose Development/Moose/Ops/Squadron.lua b/Moose Development/Moose/Ops/Squadron.lua index 88261aa7c..0c1939570 100644 --- a/Moose Development/Moose/Ops/Squadron.lua +++ b/Moose Development/Moose/Ops/Squadron.lua @@ -18,6 +18,7 @@ -- @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. -- @field #string templatename Name of the template group. @@ -63,6 +64,7 @@ SQUADRON = { ClassName = "SQUADRON", Debug = nil, + verbose = 0, lid = nil, name = nil, templatename = nil, @@ -563,14 +565,23 @@ function SQUADRON:onafterStatus(From, Event, To) -- FSM state. local fsmstate=self:GetState() + + local callsign=self.callsignName and UTILS.GetCallsignName(self.callsignName) or "N/A" + local modex=self.modex and self.modex or -1 + local skill=self.skill and tostring(self.skill) or "N/A" - -- Check if group has detected any units. - --self:_CheckAssetStatus() + local NassetsTot=#self.assets + local NassetsInS=self:CountAssetsInStock() + local NassetsQP, NassetsP, NassetsQ=self.airwing and self.airwing:CountAssetsOnMission(nil, self) or 0,0,0 -- Short info. - local text=string.format("Status %s: Assets %d", fsmstate, #self.assets) + local text=string.format("%s [Type=%s, Callsign=%s, Modex=%d, Skill=%s]: Assets Total=%d, InStock=%d, OnMission=%d [P=%d, Q=%d]", + fsmstate, self.aircrafttype, callsign, modex, skill, NassetsTot, NassetsInS, NassetsQP, NassetsP, NassetsQ) self:I(self.lid..text) + -- Check if group has detected any units. + self:_CheckAssetStatus() + if not self:IsStopped() then self:__Status(-30) end @@ -581,9 +592,74 @@ end -- @param #SQUADRON self function SQUADRON:_CheckAssetStatus() - for _,_asset in pairs(self.assets) do - local asset=_asset - + if self.verbose>=0 then + local text="" + for j,_asset in pairs(self.assets) do + local asset=_asset --Ops.AirWing#AIRWING.SquadronAsset + + -- Text. + text=text..string.format("\n-[%d] %s*%d: ", j, asset.unittype, asset.nunits) + + if asset.spawned then + + --- + -- Spawned + --- + + -- Mission info. + 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) + end + + -- Flight status. + text=text..", Flight: " + if asset.flightgroup and asset.flightgroup:IsAlive() then + local status=asset.flightgroup:GetState() + local fuelmin=asset.flightgroup:GetFuelMin() + local fuellow=asset.flightgroup:IsFuelLow() + local fuelcri=asset.flightgroup:IsFuelCritical() + + text=text..string.format("%s Fuel=%d", status, fuelmin) + if fuelcri then + text=text.." (Critical!)" + elseif fuellow then + text=text.." (Low)" + end + + local lifept, lifept0=asset.flightgroup:GetLifePoints() + text=text..string.format(", Life=%d/%d", lifept, lifept0) + + local ammo=asset.flightgroup:GetAmmoTot() + text=text..string.format(", Ammo=%d [G=%d, R=%d, B=%d, M=%d]", ammo.Total,ammo.Guns, ammo.Rockets, ammo.Bombs, ammo.Missiles) + else + text=text.."N/A" + end + + -- Payload info. + local payload=asset.payload and table.concat(self.airwing:GetPayloadMissionTypes(asset.payload), ", ") or "None" + text=text..", Payload={"..payload.."}" + + + else + + --- + -- In Stock + --- + + if asset.Treturned then + local T=timer.getAbsTime()-asset.Treturned + text=text..string.format(" Treturn=%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 + self:I(self.lid..text) end end @@ -603,6 +679,8 @@ function SQUADRON:onafterStop(From, Event, To) self:DelAsset(asset) end + self.CallScheduler:Clear() + end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -776,6 +854,30 @@ function SQUADRON:RecruitAssets(Mission) return assets end + +--- Get the time an asset needs to be repaired. +-- @param #SQUADRON self +-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The asset. +-- @return #number Time in seconds until asset is repaired. +function SQUADRON:GetRepairTime(Asset) + + if Asset.Treturned then + + local t=self.maintenancetime + t=t+Asset.damage*self.repairtime + + -- Seconds after returned. + local dt=timer.getAbsTime()-Asset.Treturned + + local T=t-dt + + return T + else + return 0 + end + +end + --- Checks if a mission type is contained in a table of possible types. -- @param #SQUADRON self -- @param Ops.AirWing#AIRWING.SquadronAsset Asset The asset. @@ -784,7 +886,8 @@ function SQUADRON:IsRepaired(Asset) if Asset.Treturned then local Tnow=timer.getAbsTime() - if Asset.Treturned+self.maintenancetime>=Tnow then + local Trepaired=Asset.Treturned+self.maintenancetime + if Tnow>=Trepaired then return true else return false diff --git a/Moose Development/Moose/Ops/Target.lua b/Moose Development/Moose/Ops/Target.lua index ffbaca4ab..d2e9acc88 100644 --- a/Moose Development/Moose/Ops/Target.lua +++ b/Moose Development/Moose/Ops/Target.lua @@ -2,8 +2,9 @@ -- -- **Main Features:** -- --- * Manages AIRWINGS --- * Events when units get +-- * Manages target, number alive, life points, damage etc. +-- * Events when targets are damaged or destroyed +-- * Various target objects: UNIT, GROUP, STATIC, SET_UNIT, AIRBASE, COORDINATE, SET_GROUP, SET_UNIT -- -- === -- @@ -35,7 +36,9 @@ -- -- # The TARGET Concept -- --- A wing commander is the head of airwings. He will find the best AIRWING to perform an assigned TARGET (mission). +-- Define a target of your mission and monitor its status. Events are triggered when the target is damaged or destroyed. +-- +-- A target can consist of one or multiple "objects". -- -- -- @field #TARGET @@ -247,7 +250,7 @@ function TARGET:onafterStart(From, Event, To) -- Short info. local text=string.format("Starting Target") - self:I(self.lid..text) + self:T(self.lid..text) self:HandleEvent(EVENTS.Dead, self.OnEventUnitDeadOrLost) self:HandleEvent(EVENTS.UnitLost, self.OnEventUnitDeadOrLost) @@ -272,12 +275,16 @@ function TARGET:onafterStatus(From, Event, To) local damaged=false for i,_target in pairs(self.targets) do local target=_target --#TARGET.Object + local life=target.Life + target.Life=self:GetTargetLife(target) + if target.Life=1 then + local text=string.format("%s: Targets=%d/%d Life=%.1f/%.1f Damage=%.1f", fsmstate, self:CountTargets(), self.Ntargets0, self:GetLife(), self:GetLife0(), self:GetDamage()) + if damaged then + text=text.." Damaged!" + end + self:I(self.lid..text) + end - -- Verbose output. - if true then + -- Log output verbose=2. + if self.verbose>=2 then local text="Target:" for i,_target in pairs(self.targets) do local target=_target --#TARGET.Object diff --git a/Moose Development/Moose/Utilities/Profiler.lua b/Moose Development/Moose/Utilities/Profiler.lua index c61a079da..7dabbb068 100644 --- a/Moose Development/Moose/Utilities/Profiler.lua +++ b/Moose Development/Moose/Utilities/Profiler.lua @@ -82,8 +82,8 @@ PROFILER = { } PROFILER.sortBy=1 -- Sort reports by 0=Count, 1=Total time by function -PROFILER.logUnknown=false -- Log unknown functions -PROFILER.lowCpsThres=5 -- Skip results with less than X calls per second +PROFILER.logUnknown=true -- Log unknown functions +PROFILER.lowCpsThres=1 -- Skip results with less than X calls per second PROFILER.fileName="_LuaProfiler.txt" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -252,7 +252,7 @@ function PROFILER.showInfo() local file=lfs.writedir()..[[Logs\]]..PROFILER.fileName local f=io.open(file, 'w') - BASE:I(string.format("### Profiler: Writing result to file ", file)) + BASE:I(string.format("### Profiler: Writing result to file %s", file)) -- Gather data. local t={} diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 322df4137..9dded0f5a 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -243,8 +243,7 @@ end --- Returns the initial health. -- @param #CONTROLLABLE self --- @return #number The controllable health value (unit or group average). --- @return #nil The controllable is not existing or alive. +-- @return #number The controllable health value (unit or group average) or `nil` if the controllable does not exist. function CONTROLLABLE:GetLife0() self:F2( self.ControllableName ) @@ -296,7 +295,6 @@ end -- @return #nil The CONTROLLABLE is not existing or alive. function CONTROLLABLE:GetFuel() self:F( self.ControllableName ) - return nil end