This commit is contained in:
Frank 2020-08-18 01:35:24 +02:00
parent 2a4f6020c2
commit e9e6a63e6a
9 changed files with 143 additions and 78 deletions

View File

@ -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")

View File

@ -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<importance then
importance=mission.importance
if mission.importance<vip then
vip=mission.importance
end
end
end
-- Current time.
local time=timer.getAbsTime()
@ -1126,7 +1140,7 @@ function AIRWING:_GetNextMission()
local mission=_mission --Ops.Auftrag#AUFTRAG
-- Firstly, check if mission is due?
if mission:IsQueued() and mission:IsReadyToGo() and mission.importance<=importance then
if mission:IsQueued() and mission:IsReadyToGo() and mission.importance<=vip then
-- Check if airwing can do the mission and gather required assets.
local can, assets=self:CanMission(mission)
@ -1505,7 +1519,7 @@ function AIRWING:onafterNewAsset(From, Event, To, asset, assignment)
--asset.terminalType=AIRBASE.TerminalType.OpenBig
else
env.info("FF squad asset returned")
--env.info("FF squad asset returned")
self:SquadAssetReturned(squad, asset)
end
@ -1864,13 +1878,13 @@ function AIRWING:CountPayloadsInStock(MissionTypes, UnitTypes, 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
@ -1881,7 +1895,12 @@ function AIRWING:CountPayloadsInStock(MissionTypes, UnitTypes, Payloads)
for _,MissionType in pairs(MissionTypes) do
if self:CheckMissionCapability(MissionType, payload.capabilities) and _checkUnitTypes(payload) and _checkPayloads(payload) then
local specialpayload=_checkPayloads(payload)
local compatible=self:CheckMissionCapability(MissionType, payload.capabilities)
local goforit = specialpayload or (specialpayload==nil and compatible)
if goforit and _checkUnitTypes(payload) then
if payload.unlimited then
-- Payload is unlimited. Return a BIG number.
@ -1920,6 +1939,21 @@ function AIRWING:CountMissionsInQueue(MissionTypes)
return N
end
--- Count total number of assets. This is the sum of all squadron assets.
-- @param #AIRWING self
-- @return #number Amount of asset groups.
function AIRWING:CountAssets()
local N=0
for _,_squad in pairs(self.squadrons) do
local squad=_squad --Ops.Squadron#SQUADRON
N=N+#squad.assets
end
return N
end
--- Count assets on mission.
-- @param #AIRWING self
-- @param #table MissionTypes Types on mission to be checked. Default all.
@ -1957,7 +1991,7 @@ function AIRWING:CountAssetsOnMission(MissionTypes, Squadron)
end
end
env.info(string.format("FF N=%d Np=%d, Nq=%d", Np+Nq, Np, Nq))
--env.info(string.format("FF N=%d Np=%d, Nq=%d", Np+Nq, Np, Nq))
return Np+Nq, Np, Nq
end

View File

@ -874,6 +874,7 @@ function ARMYGROUP:SwitchFormation(Formation, Permanently)
-- Set current formation.
self.option.Formation=Formation
-- Update route with the new formation.
self:__UpdateRoute(-1, nil, nil, Formation)
-- Debug info.

View File

@ -38,7 +38,6 @@
-- @field #boolean markerOn If true, display marker on F10 map with the AUFTRAG status.
-- @field #number markerCoaliton Coalition to which the marker is dispayed.
-- @field #table DCStask DCS task structure.
-- @field #number Ntargets Number of mission targets.
-- @field #number Ncasualties Number of own casualties during 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.
@ -499,6 +498,7 @@ function AUFTRAG:New(Type)
-- PLANNED --> (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<self.Ntargets then
if Ntargets<Ntargets0 then
failed=true
end
@ -2128,7 +2131,7 @@ function AUFTRAG:Evaluate()
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("--------------------------\n")
text=text..string.format("Targets left = %d/%d\n", Ntargets, self.Ntargets)
text=text..string.format("Targets left = %d/%d\n", Ntargets, Ntargets0)
text=text..string.format("Enemy losses = %.1f %%\n", targetdamage)
text=text..string.format("--------------------------\n")
--text=text..string.format("Loss ratio = %.1f %%\n", targetdamage)
@ -2365,6 +2368,17 @@ end
-- FSM Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- On after "Planned" event.
-- @param #AUFTRAG self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function AUFTRAG:onafterPlanned(From, Event, To)
self.status=AUFTRAG.Status.PLANNED
self:T(self.lid..string.format("New mission status=%s", self.status))
end
--- On after "Queue" event. Mission is added to the mission queue of an AIRWING.
-- @param #AUFTRAG self
-- @param #string From From state.
@ -2627,15 +2641,20 @@ function AUFTRAG:onafterRepeat(From, Event, To)
self.repeated=self.repeated+1
if self.chief then
--TODO
elseif self.wingcommander then
-- Remove mission from airwing because WC will assign it again but maybe to a different wing.
if self.airwing then
self.airwing:RemoveMission(self)
end
elseif self.airwing then
-- Already at the airwing ==> 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

View File

@ -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.

View File

@ -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.importance<importance then
importance=mission.importance
if mission.importance<vip then
vip=mission.importance
end
end
@ -1778,7 +1778,7 @@ function OPSGROUP:_GetNextMission()
for _,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
if mission:GetGroupStatus(self)==AUFTRAG.Status.SCHEDULED and (mission:IsReadyToGo() or self.airwing) and mission.importance<=importance then
if mission:GetGroupStatus(self)==AUFTRAG.Status.SCHEDULED and (mission:IsReadyToGo() or self.airwing) and mission.importance<=vip then
return mission
end
end
@ -2918,7 +2918,7 @@ function OPSGROUP._PassingWaypoint(group, opsgroup, uid)
-- Debug message.
local text=string.format("Group passing waypoint uid=%d", uid)
opsgroup:I(opsgroup.lid..text)
opsgroup:T2(opsgroup.lid..text)
-- Trigger PassingWaypoint event.
if not (waypoint.astar or waypoint.detour) then
@ -3223,7 +3223,7 @@ function OPSGROUP:TurnOffTACAN()
end
self:I(self.lid..string.format("Switching TACAN OFF"))
self.tacanOn=false
self.tacan.On=false
end

View File

@ -751,7 +751,7 @@ function SQUADRON:CanMission(Mission)
-- Set range is valid. Mission engage distance can overrule the squad engage range.
if TargetDistance>engagerange 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!

View File

@ -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.

View File

@ -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('###############################################################################')