From e9e6a63e6a4090a169dd71d0139c580b60dd0cad Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 18 Aug 2020 01:35:24 +0200 Subject: [PATCH] Ops --- .../Moose/Functional/Warehouse.lua | 14 ++-- Moose Development/Moose/Ops/AirWing.lua | 80 +++++++++++++------ Moose Development/Moose/Ops/ArmyGroup.lua | 1 + Moose Development/Moose/Ops/Auftrag.lua | 68 +++++++++++----- Moose Development/Moose/Ops/FlightGroup.lua | 4 +- Moose Development/Moose/Ops/OpsGroup.lua | 12 +-- Moose Development/Moose/Ops/Squadron.lua | 5 +- Moose Development/Moose/Ops/Target.lua | 1 + .../Moose/Utilities/Profiler.lua | 36 ++++----- 9 files changed, 143 insertions(+), 78 deletions(-) diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 6f228c997..82d09a386 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -46,7 +46,7 @@ -- @type WAREHOUSE -- @field #string ClassName Name of the class. -- @field #boolean Debug If true, send debug messages to all. --- @field #number verbose Verbosity level. +-- @field #number verbosity Verbosity level. -- @field #string wid Identifier of the warehouse printed before other output to DCS.log file. -- @field #boolean Report If true, send status messages to coalition. -- @field Wrapper.Static#STATIC warehouse The phyical warehouse structure. @@ -1890,7 +1890,7 @@ function WAREHOUSE:New(warehouse, alias) -- Defaults self:SetMarker(true) self:SetReportOff() - self:SetVerbosity(0) + self:SetVerbosityLevel(0) -- Add warehouse to database. _WAREHOUSEDB.Warehouses[self.uid]=self @@ -2556,8 +2556,8 @@ end -- @param #WAREHOUSE self -- @param #number VerbosityLevel Level of output (higher=more). Default 0. -- @return #WAREHOUSE self -function WAREHOUSE:SetVerbosity(VerbosityLevel) - self.verbose=VerbosityLevel or 0 +function WAREHOUSE:SetVerbosityLevel(VerbosityLevel) + self.verbosity=VerbosityLevel or 0 return self end @@ -3403,7 +3403,7 @@ end function WAREHOUSE:onafterStatus(From, Event, To) -- General info. - if self.verbose>=1 then + if self.verbosity>=1 then local FSMstate=self:GetState() @@ -8289,7 +8289,7 @@ end -- @param #string name Name of the queue for info reasons. function WAREHOUSE:_PrintQueue(queue, name) - if self.verbose>=2 then + if self.verbosity>=2 then local total="Empty" if #queue>0 then @@ -8360,7 +8360,7 @@ end --- Display status of warehouse. -- @param #WAREHOUSE self function WAREHOUSE:_DisplayStatus() - if self.verbose>=3 then + if self.verbosity>=3 then local text=string.format("\n------------------------------------------------------\n") text=text..string.format("Warehouse %s status: %s\n", self.alias, self:GetState()) text=text..string.format("------------------------------------------------------\n") diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index e2633f33c..fa3e963a5 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -154,7 +154,7 @@ AIRWING = { --- AIRWING class version. -- @field #string version -AIRWING.version="0.2.1" +AIRWING.version="0.3.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -204,7 +204,7 @@ function AIRWING:New(warehousename, airwingname) self:AddTransition("*", "FlightOnMission", "*") -- Flight was spawned with a mission. -- Defaults: - self:SetVerbosity(0) + self:SetVerbosity(2) self.nflightsCAP=0 self.nflightsAWACS=0 self.nflightsTANKERboom=0 @@ -341,8 +341,8 @@ function AIRWING:NewPayload(Unit, Npayloads, MissionTypes, Performance) end -- Info - self:I(self.lid..string.format("Adding new payload from unit %s for aircraft type %s: N=%d (unlimited=%s), performance=%d, missions: %s", - payload.unitname, payload.aircrafttype, payload.navail, tostring(payload.unlimited), Performance, table.concat(MissionTypes, ", "))) + self:I(self.lid..string.format("Adding new payload from unit %s for aircraft type %s: ID=%d, N=%d (unlimited=%s), performance=%d, missions: %s", + payload.unitname, payload.aircrafttype, payload.uid, payload.navail, tostring(payload.unlimited), Performance, table.concat(MissionTypes, ", "))) -- Add payload table.insert(self.payloads, payload) @@ -438,13 +438,13 @@ function AIRWING:FetchPayloadFromStock(UnitType, MissionType, Payloads) local function _checkPayloads(payload) if Payloads then for _,Payload in pairs(Payloads) do - if Payload.uid==payload.id then + if Payload.uid==payload.uid then return true end end else -- Payload was not specified. - return true + return nil end return false end @@ -453,7 +453,13 @@ function AIRWING:FetchPayloadFromStock(UnitType, MissionType, Payloads) local payloads={} for _,_payload in pairs(self.payloads) do local payload=_payload --#AIRWING.Payload - if payload.aircrafttype==UnitType and self:CheckMissionCapability(MissionType, payload.capabilities) and payload.navail>0 and _checkPayloads(payload) then + + local specialpayload=_checkPayloads(payload) + local compatible=self:CheckMissionCapability(MissionType, payload.capabilities) + + local goforit = specialpayload or (specialpayload==nil and compatible) + + if payload.aircrafttype==UnitType and payload.navail>0 and goforit then table.insert(payloads, payload) end end @@ -807,15 +813,18 @@ function AIRWING:onafterStatus(From, Event, To) if self.verbose>=1 then -- Count missions not over yet. - local nmissions=self:CountMissionsInQueue() + local Nmissions=self:CountMissionsInQueue() -- Count ALL payloads in stock. If any payload is unlimited, this gives 999. local Npayloads=self:CountPayloadsInStock(AUFTRAG.Type) - - -- TODO: assets total - + + -- Assets tot + local Npq, Np, Nq=self:CountAssetsOnMission() + + local assets=string.format("%d [Mission=%d (Active=%d, Queued=%d)]", self:CountAssets(), Npq, Np, Nq) + -- Output. - local text=string.format("%s: Missions=%d, Payloads=%d (%d), Squads=%d", fsmstate, nmissions, Npayloads, #self.payloads, #self.squadrons) + local text=string.format("%s: Missions=%d, Payloads=%d (%d), Squads=%d, Assets=%s", fsmstate, Nmissions, Npayloads, #self.payloads, #self.squadrons, assets) self:I(self.lid..text) end @@ -826,7 +835,12 @@ function AIRWING:onafterStatus(From, Event, To) local text=string.format("Missions Total=%d:", #self.missionqueue) for i,_mission in pairs(self.missionqueue) do local mission=_mission --Ops.Auftrag#AUFTRAG - text=text..string.format("\n[%d] %s: Status=%s, Nassets=%d, Prio=%d, ID=%d (%s)", i, mission.type, mission.status, mission.nassets, mission.prio, mission.auftragsnummer, mission.name) + + local prio=string.format("%d/%d", mission.prio, mission.importance) ; if mission.urgent then prio=prio.." (!)" end + local assets=string.format("%d/%d", mission:CountOpsGroups(), mission.nassets) + local target=string.format("%d/%d Damage=%.1f", mission:CountMissionTargets(), mission:GetTargetInitialNumber(), mission:GetTargetDamage()) + + text=text..string.format("\n[%d] %s %s: Status=%s, Prio=%s, Assets=%s, Targets=%s", i, mission.name, mission.type, mission.status, prio, assets, target) end self:I(self.lid..text) end @@ -1110,13 +1124,13 @@ function AIRWING:_GetNextMission() table.sort(self.missionqueue, _sort) -- Look for first mission that is SCHEDULED. - local importance=math.huge + local vip=math.huge for _,_mission in pairs(self.missionqueue) do local mission=_mission --Ops.Auftrag#AUFTRAG - if mission.importance (QUEUED) --> (REQUESTED) --> SCHEDULED --> STARTED --> EXECUTING --> DONE + self:AddTransition("*", "Planned", AUFTRAG.Status.PLANNED) -- Mission is in planning stage. self:AddTransition(AUFTRAG.Status.PLANNED, "Queued", AUFTRAG.Status.QUEUED) -- Mission is in queue of an AIRWING. self:AddTransition(AUFTRAG.Status.QUEUED, "Requested", AUFTRAG.Status.REQUESTED) -- Mission assets have been requested from the warehouse. self:AddTransition(AUFTRAG.Status.REQUESTED, "Scheduled", AUFTRAG.Status.SCHEDULED) -- Mission added to the first ops group queue. @@ -1406,12 +1406,12 @@ end -- @param #AUFTRAG self -- @param #number Prio Priority 1=high, 100=low. Default 50. -- @param #boolean Urgent If *true*, another running mission might be cancelled if it has a lower priority. --- @param #number Importance Number 1-10. If missions with lower value are in the queue, these have to be finished first. +-- @param #number Importance Number 1-10. If missions with lower value are in the queue, these have to be finished first. Default is 5. -- @return #AUFTRAG self -function AUFTRAG:SetPriority(Prio, Urgent) +function AUFTRAG:SetPriority(Prio, Urgent, Importance) self.prio=Prio or 50 self.urgent=Urgent - self.importance=5 + self.importance=Importance or 5 return self end @@ -1730,15 +1730,15 @@ function AUFTRAG:AssignSquadrons(Squadrons) self.squadrons=Squadrons end ---- Set the required payload for this mission. Only available for use with an AIRWING. +--- Add a required payload for this mission. Only these payloads will be used for this mission. If they are not available, the mission cannot start. Only available for use with an AIRWING. -- @param #AUFTRAG self --- @param Ops.AirWing#AIRWING.Payload Required payload +-- @param Ops.AirWing#AIRWING.Payload Payload Required payload. -- @return #AUFTRAG self function AUFTRAG:AddRequiredPayload(Payload) self.payloads=self.payloads or {} - table.insert(self.payload, Payload) + table.insert(self.payloads, Payload) end @@ -1985,6 +1985,7 @@ function AUFTRAG:onafterStatus(From, Event, To) -- Number of alive mission targets. local Ntargets=self:CountMissionTargets() + local Ntargets0=self:GetTargetInitialNumber() -- Number of alive groups attached to this mission. local Ngroups=self:CountOpsGroups() @@ -1997,7 +1998,7 @@ function AUFTRAG:onafterStatus(From, Event, To) -- All groups have reported MISSON DONE. self:Done() - elseif (self.Tstop and Tnow>self.Tstop+10) or (self.Ntargets>0 and Ntargets==0) then + elseif (self.Tstop and Tnow>self.Tstop+10) or (Ntargets0>0 and Ntargets==0) then -- Cancel mission if stop time passed. self:Cancel() @@ -2075,8 +2076,10 @@ function AUFTRAG:Evaluate() -- Current number of mission targets. local Ntargets=self:CountMissionTargets() + local Ntargets0=self:GetTargetInitialNumber() - if self.Ntargets>0 then + + if Ntargets0>0 then --- -- Mission had targets @@ -2085,7 +2088,7 @@ function AUFTRAG:Evaluate() -- Number of current targets is still >0 ==> Not everything was destroyed. if self.type==AUFTRAG.Type.TROOPTRANSPORT then - if Ntargets Queued() - self:Queued(self.airwing) + self:Queued(self.airwing) else self:E(self.lid.."ERROR: Mission can only be repeated by a CHIEF, WINGCOMMANDER or AIRWING! Stopping AUFTRAG") @@ -2721,11 +2740,8 @@ function AUFTRAG:_TargetFromObject(Object) end - -- TODO: get rid of this. - self.Ntargets=self.engageTarget.Ntargets0 - -- Debug info. - self:T(self.lid..string.format("Mission Target %s Type=%s, Ntargets=%d, Lifepoints=%d", self.engageTarget.lid, self.engageTarget.lid, self.Ntargets, self.engageTarget:GetLife())) + self:T(self.lid..string.format("Mission Target %s Type=%s, Ntargets=%d, Lifepoints=%d", self.engageTarget.lid, self.engageTarget.lid, self.engageTarget.Ntargets0, self.engageTarget:GetLife())) return self end @@ -2733,9 +2749,8 @@ end --- Count alive mission targets. -- @param #AUFTRAG self --- @param #AUFTRAG.TargetData Target (Optional) The target object. -- @return #number Number of alive target units. -function AUFTRAG:CountMissionTargets(Target) +function AUFTRAG:CountMissionTargets() if self.engageTarget then return self.engageTarget:CountTargets() @@ -2745,6 +2760,19 @@ function AUFTRAG:CountMissionTargets(Target) end +--- Get initial number of targets. +-- @param #AUFTRAG self +-- @return #number Number of initial life points when mission was planned. +function AUFTRAG:GetTargetInitialNumber() + local target=self:GetTargetData() + if target then + return target.Ntargets0 + else + return 0 + end +end + + --- Get target life points. -- @param #AUFTRAG self -- @return #number Number of initial life points when mission was planned. @@ -2999,7 +3027,7 @@ function AUFTRAG:UpdateMarker() -- Marker text. local text=string.format("%s %s: %s", self.name, self.type:upper(), self.status:upper()) text=text..string.format("\n%s", self:GetTargetName()) - text=text..string.format("\nTargets %d/%d, Life Points=%d/%d", self:CountMissionTargets(), self.Ntargets, self:GetTargetLife(), self:GetTargetInitialLife()) + text=text..string.format("\nTargets %d/%d, Life Points=%d/%d", self:CountMissionTargets(), self:GetTargetInitialNumber(), self:GetTargetLife(), self:GetTargetInitialLife()) text=text..string.format("\nFlights %d/%d", self:CountOpsGroups(), self.nassets) if not self.marker then diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 2b15fb846..5ac377611 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -248,7 +248,7 @@ function FLIGHTGROUP:New(group) 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. - self:AddTransition("*", "Wait", "Waiting") -- Group is orbiting. + self:AddTransition("*", "Wait", "*") -- Group is orbiting. self:AddTransition("*", "FuelLow", "*") -- Fuel state of group is low. Default ~25%. self:AddTransition("*", "FuelCritical", "*") -- Fuel state of group is critical. Default ~10%. @@ -2119,9 +2119,9 @@ function FLIGHTGROUP:onafterRefuel(From, Event, To, Coordinate) self:I(self.lid..text) --TODO: set ROE passive. introduce roe event/state/variable. - --TODO: cancel current task + -- Pause current mission if there is any. self:PauseMission() -- Refueling task. diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index a4cf182ab..d6fb149fa 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -1766,11 +1766,11 @@ function OPSGROUP:_GetNextMission() local time=timer.getAbsTime() -- Look for first mission that is SCHEDULED. - local importance=math.huge + local vip=math.huge for _,_mission in pairs(self.missionqueue) do local mission=_mission --Ops.Auftrag#AUFTRAG - if mission.importanceengagerange then - self:I(self.lid..string.format("INFO: Squad is not in range. Target dist=%d > %d NM max engage Range", UTILS.MetersToNM(TargetDistance), UTILS.MetersToNM(engagerange))) + self:I(self.lid..string.format("INFO: Squad is not in range. Target dist=%d > %d NM max mission Range", UTILS.MetersToNM(TargetDistance), UTILS.MetersToNM(engagerange))) return false end @@ -833,7 +833,8 @@ function SQUADRON:RecruitAssets(Mission, Npayloads) if Mission.type==AUFTRAG.Type.INTERCEPT then combatready=flightgroup:CanAirToAir() else - combatready=flightgroup:CanAirToGround() + local excludeguns=Mission.type==AUFTRAG.Type.BOMBING or Mission.type==AUFTRAG.Type.BOMBRUNWAY or Mission.type==AUFTRAG.Type.BOMBCARPET + combatready=flightgroup:CanAirToGround(excludeguns) end -- No more attacks if fuel is already low. Safety first! diff --git a/Moose Development/Moose/Ops/Target.lua b/Moose Development/Moose/Ops/Target.lua index 9f37e0b7f..e5b2f3a22 100644 --- a/Moose Development/Moose/Ops/Target.lua +++ b/Moose Development/Moose/Ops/Target.lua @@ -104,6 +104,7 @@ TARGET.ObjectStatus={ -- @field #number Life0 Life points of completely healthy target. -- @field #string Status Status "Alive" or "Dead". +--- Global target ID counter. _TARGETID=0 --- TARGET class version. diff --git a/Moose Development/Moose/Utilities/Profiler.lua b/Moose Development/Moose/Utilities/Profiler.lua index a5b2d9bbf..639e7174a 100644 --- a/Moose Development/Moose/Utilities/Profiler.lua +++ b/Moose Development/Moose/Utilities/Profiler.lua @@ -111,24 +111,24 @@ PROFILER = { -- @param #number Duration Duration in (game) seconds before the profiler is stopped. Default is when mission ends. function PROFILER.Start(Delay, Duration) + -- Check if os and lfs are available. + local go=true + if not os then + error("Profiler needs os to be desanitized") + go=false + end + if not lfs then + error("Profiler needs lfs to be desanitized") + go=false + end + if not go then + return + end + if Delay and Delay>0 then BASE:ScheduleOnce(Delay, PROFILER.Start, 0, Duration) else - -- Check if os and lfs are available. - local go=true - if not os then - error("Profiler needs os to be desanitized") - go=false - end - if not lfs then - error("Profiler needs lfs to be desanitized") - go=false - end - if not go then - return - end - -- Set start time. PROFILER.TstartGame=timer.getTime() PROFILER.TstartOS=os.clock() @@ -149,12 +149,12 @@ function PROFILER.Start(Delay, Duration) -- Info in log. env.info('############################ Profiler Started ############################') if Duration then - env.info(string.format("Duration %d seconds", Duration)) + env.info(string.format("- Will be running for %d seconds", Duration)) else - env.info(string.format("Stopped when mission ends")) + env.info(string.format("- Will be stopped when mission ends")) end - env.info(string.format("Calls per second threshold %.3f/sec", PROFILER.lowCpsThres)) - env.info(string.format("Log file \"%s.%s\"", PROFILER.fileNamePrefix, PROFILER.fileNameSuffix)) + env.info(string.format("- Calls per second threshold %.3f/sec", PROFILER.lowCpsThres)) + env.info(string.format("- Output file \"%s\" in your DCS log file folder", PROFILER.getfilename())) env.info('###############################################################################')