Cap rework (#48)
- Refactored all CAP classes. - Improved timing - Zones are now not tied to MissionStages - CAPROUTE_<routeID>_<free> - routeID is now what is used in the naming convention. - Units taxi back to their spawn parking space and rearm there. (Units destroyed while in the Rearming or Repairing state are not taken into account)
This commit is contained in:
+156
-144
@@ -1,22 +1,18 @@
|
||||
---@class CapBase : OnStageChangedListener
|
||||
---@field groupNames Array<string>
|
||||
---@field database Database
|
||||
---@field airbaseName string
|
||||
---@field logger table
|
||||
---@field activeStage number
|
||||
---@field capConfig table
|
||||
---@field activeCapStages number
|
||||
---@field lastStatesByName table<string, string>
|
||||
---@field groupsByName table<string, CapGroup>
|
||||
---@field PrimaryGroups Array<CapGroup>
|
||||
---@field BackupGroups Array<CapGroup>
|
||||
---@field private airbaseName string
|
||||
---@field private logger table
|
||||
---@field private database Database
|
||||
---@field private activeStage number
|
||||
---@field private capConfig table
|
||||
---@field private capGroupsByName table<string, CapGroup>
|
||||
---@field private runwayBombingTracker RunwayBombingTracker
|
||||
---@field private runwayStrikeMissions table<string, RunwayStrikeMission>
|
||||
local CapBase = {}
|
||||
|
||||
|
||||
local CheckReschedulingAsync = function(self, time)
|
||||
local CheckStateContinuous = function(self, time)
|
||||
self:CheckAndScheduleCAP()
|
||||
return time + 15
|
||||
end
|
||||
|
||||
---comment
|
||||
@@ -28,181 +24,201 @@ end
|
||||
---@param runwayBombingTracker RunwayBombingTracker
|
||||
---@return CapBase
|
||||
function CapBase.new(airbaseName, database, logger, capConfig, stageConfig, runwayBombingTracker)
|
||||
|
||||
CapBase.__index = CapBase
|
||||
local self = setmetatable({}, { __index = CapBase }) --[[@as CapBase]]
|
||||
|
||||
local baseData = database:getAirbaseDataForZone(airbaseName)
|
||||
local groupNames = {}
|
||||
if baseData then groupNames = baseData.CapGroups or {} end
|
||||
|
||||
self.groupNames = groupNames
|
||||
self.database = database
|
||||
self.runwayBombingTracker = runwayBombingTracker
|
||||
self.runwayStrikeMissions = {}
|
||||
|
||||
|
||||
self.airbaseName = airbaseName
|
||||
self.logger = logger
|
||||
self.activeStage = 0
|
||||
self.capConfig = capConfig
|
||||
self.activeCapStages = (stageConfig or {}).capActiveStages or 10
|
||||
self.database = database
|
||||
self.capGroupsByName = {}
|
||||
|
||||
self.lastStatesByName = {}
|
||||
self.groupsByName = {}
|
||||
self.PrimaryGroups = {}
|
||||
self.BackupGroups = {}
|
||||
|
||||
for key, name in pairs(self.groupNames) do
|
||||
local capGroup = Spearhead.classes.capClasses.CapGroup.new(name, airbaseName, logger, database, capConfig)
|
||||
if capGroup then
|
||||
self.groupsByName[name] = capGroup
|
||||
|
||||
if capGroup.isBackup ==true then
|
||||
table.insert(self.BackupGroups, capGroup)
|
||||
else
|
||||
table.insert(self.PrimaryGroups, capGroup)
|
||||
local baseData = database:getAirbaseDataForZone(airbaseName)
|
||||
if baseData and baseData.CapGroups then
|
||||
for key, name in pairs(baseData.CapGroups) do
|
||||
local capGroup = Spearhead.classes.capClasses.airGroups.CapGroup.New(name, capConfig, logger)
|
||||
if capGroup then
|
||||
self.capGroupsByName[name] = capGroup
|
||||
end
|
||||
|
||||
capGroup:AddOnStateUpdatedListener(self)
|
||||
end
|
||||
end
|
||||
logger:info("Airbase with name '" .. airbaseName .. "' has a total of " .. Spearhead.Util.tableLength(self.groupsByName) .. " cap flights registered")
|
||||
|
||||
self:CreateRunwayStrikeMission()
|
||||
logger:info("Airbase with name '" ..
|
||||
airbaseName .. "' has a total of " .. Spearhead.Util.tableLength(self.capGroupsByName) .. " cap flights registered")
|
||||
|
||||
self:CreateRunwayStrikeMission(database)
|
||||
|
||||
Spearhead.Events.AddStageNumberChangedListener(self)
|
||||
|
||||
return self
|
||||
timer.scheduleFunction(CheckStateContinuous, self, timer.getTime() + 15)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
---@private
|
||||
function CapBase:CreateRunwayStrikeMission()
|
||||
|
||||
---@param database Database
|
||||
function CapBase:CreateRunwayStrikeMission(database)
|
||||
local airbase = Airbase.getByName(self.airbaseName)
|
||||
if not airbase then
|
||||
if not airbase then
|
||||
self.logger:debug("Could not find a airbase with name to create runway mission" .. self.airbaseName)
|
||||
return
|
||||
return
|
||||
end
|
||||
|
||||
for _, runway in pairs(airbase:getRunways()) do
|
||||
if runway then
|
||||
self.logger:debug("Runway " .. runway.Name .. " at airbase " .. self.airbaseName .. " with heading " .. runway.course .. " and length " .. runway.length .. " and width " .. runway.width)
|
||||
local mission = Spearhead.classes.stageClasses.missions.RunwayStrikeMission.new(runway, self.airbaseName, self.database, self.logger, self.runwayBombingTracker)
|
||||
self.logger:debug("Runway " ..
|
||||
runway.Name ..
|
||||
" at airbase " ..
|
||||
self.airbaseName ..
|
||||
" with heading " .. runway.course .. " and length " .. runway.length .. " and width " .. runway.width)
|
||||
local mission = Spearhead.classes.stageClasses.missions.RunwayStrikeMission.new(runway, self.airbaseName,
|
||||
database, self.logger, self.runwayBombingTracker)
|
||||
self.runwayStrikeMissions[runway.Name] = mission
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function CapBase:onGroupStateUpdated(capGroup)
|
||||
--[[
|
||||
There is no update needed for INTRANSIT, ONSTATION or REARMING as the PREVIOUS state already was checked and nothing changes in the actual overal state.
|
||||
]]--
|
||||
if capGroup.state == Spearhead.classes.capClasses.CapGroup.GroupState.INTRANSIT
|
||||
or capGroup.state == Spearhead.classes.capClasses.CapGroup.GroupState.ONSTATION
|
||||
or capGroup.state == Spearhead.classes.capClasses.CapGroup.GroupState.REARMING
|
||||
then
|
||||
return
|
||||
function CapBase:SpawnIfApplicable()
|
||||
self.logger:debug("Check spawns for airbase " .. self.airbaseName)
|
||||
for groupName, capGroup in pairs(self.capGroupsByName) do
|
||||
local targetStage = capGroup:GetZoneIDWhenStageID(tostring(self.activeStage))
|
||||
|
||||
if targetStage ~= nil and capGroup:GetState() == "UnSpawned" then
|
||||
capGroup:Spawn()
|
||||
end
|
||||
end
|
||||
timer.scheduleFunction(CheckReschedulingAsync, self, timer.getTime() + 1)
|
||||
end
|
||||
|
||||
function CapBase:SpawnIfApplicable()
|
||||
self.logger:debug("Check spawns for airbase " .. self.airbaseName )
|
||||
for groupName, capGroup in pairs(self.groupsByName) do
|
||||
|
||||
local targetStage = capGroup:GetTargetZone(self.activeStage)
|
||||
function CapBase:CheckAndScheduleCAP()
|
||||
self.logger:debug("Check taskings for airbase " .. self.airbaseName)
|
||||
|
||||
if targetStage ~= nil and capGroup.state == Spearhead.classes.capClasses.CapGroup.GroupState.UNSPAWNED then
|
||||
capGroup:SpawnOnTheRamp()
|
||||
end
|
||||
end
|
||||
local countPerStage = {}
|
||||
local requiredPerStage = {}
|
||||
|
||||
local airbase = Airbase.getByName(self.airbaseName)
|
||||
if not airbase then
|
||||
return nil
|
||||
end
|
||||
|
||||
function CapBase:CheckAndScheduleCAP()
|
||||
local activeStageID = tostring(self.activeStage)
|
||||
|
||||
self.logger:debug("Check taskings for airbase " .. self.airbaseName )
|
||||
|
||||
local countPerStage = {}
|
||||
local requiredPerStage = {}
|
||||
--Count back up groups that are active or reassign to the new zone if that's needed
|
||||
for _, group in pairs(self.capGroupsByName) do
|
||||
if group:IsBackup() == true then
|
||||
local state = group:GetState()
|
||||
if state == "InTransit" or state == "OnStation" or state == "RtbInTen" then
|
||||
|
||||
local supposedTargetZoneID = group:GetZoneIDWhenStageID(activeStageID)
|
||||
local currentTargetZone = group:GetCurrentTargetZoneID()
|
||||
|
||||
--Count back up groups that are active or reassign to the new zone if that's needed
|
||||
for _, backupGroup in pairs(self.BackupGroups) do
|
||||
if backupGroup.state == Spearhead.classes.capClasses.CapGroup.GroupState.INTRANSIT or backupGroup.state == Spearhead.classes.capClasses.CapGroup.GroupState.ONSTATION then
|
||||
local supposedTargetStage = backupGroup:GetTargetZone(self.activeStage)
|
||||
if supposedTargetStage then
|
||||
if supposedTargetStage ~= backupGroup.assignedStageNumber then
|
||||
backupGroup:SendToStage(supposedTargetStage)
|
||||
end
|
||||
|
||||
if countPerStage[supposedTargetStage] == nil then
|
||||
countPerStage[supposedTargetStage] = 0
|
||||
end
|
||||
countPerStage[supposedTargetStage] = countPerStage[supposedTargetStage] + 1
|
||||
if supposedTargetZoneID == nil then
|
||||
self.logger:debug("CapGroup " .. group:GetName() .. " has no target zone for stage " .. activeStageID)
|
||||
group:SendRTB(airbase)
|
||||
else
|
||||
backupGroup:SendRTBAndDespawn()
|
||||
end
|
||||
elseif backupGroup.state == Spearhead.classes.capClasses.CapGroup.GroupState.RTBINTEN and backupGroup:GetTargetZone(self.activeStage) ~= backupGroup.assignedStageNumber then
|
||||
backupGroup:SendRTB()
|
||||
end
|
||||
end
|
||||
|
||||
--Schedule or reassign primary units if applicable
|
||||
for _, primaryGroup in pairs(self.PrimaryGroups) do
|
||||
local supposedTargetStage = primaryGroup:GetTargetZone(self.activeStage)
|
||||
if supposedTargetStage then
|
||||
if requiredPerStage[supposedTargetStage] == nil then
|
||||
requiredPerStage[supposedTargetStage] = 0
|
||||
end
|
||||
|
||||
if countPerStage[supposedTargetStage] == nil
|
||||
then
|
||||
countPerStage[supposedTargetStage] = 0
|
||||
end
|
||||
|
||||
requiredPerStage[supposedTargetStage] = requiredPerStage[supposedTargetStage] + 1
|
||||
|
||||
if primaryGroup.state == Spearhead.classes.capClasses.CapGroup.GroupState.READYONRAMP then
|
||||
if countPerStage[supposedTargetStage] < requiredPerStage[supposedTargetStage] then
|
||||
primaryGroup:SendToStage(supposedTargetStage)
|
||||
countPerStage[supposedTargetStage] = countPerStage[supposedTargetStage] + 1
|
||||
end
|
||||
elseif primaryGroup.state == Spearhead.classes.capClasses.CapGroup.GroupState.INTRANSIT or primaryGroup.state == Spearhead.classes.capClasses.CapGroup.GroupState.ONSTATION then
|
||||
if supposedTargetStage ~= primaryGroup.assignedStageNumber then
|
||||
if countPerStage[supposedTargetStage] < requiredPerStage[supposedTargetStage] then
|
||||
primaryGroup:SendToStage(supposedTargetStage)
|
||||
if supposedTargetZoneID and supposedTargetZoneID ~= currentTargetZone then
|
||||
if state == "RtbInTen" then
|
||||
self.logger:debug("CapGroup " .. group:GetName() .. " is RTB in 10 minutes, sending to RTB already")
|
||||
group:SendRTB(airbase)
|
||||
else
|
||||
countPerStage[supposedTargetStage] = countPerStage[supposedTargetStage] + 1
|
||||
primaryGroup:SendRTB()
|
||||
local triggerZone = self.database:GetCapZoneForZoneID(supposedTargetZoneID)
|
||||
if triggerZone then
|
||||
group:SendToZone(triggerZone, supposedTargetZoneID, airbase)
|
||||
else
|
||||
self.logger:debug("CapGroup " .. group:GetName() .. " has no trigger zone for stage " .. activeStageID)
|
||||
group:SendRTB(airbase)
|
||||
end
|
||||
end
|
||||
end
|
||||
countPerStage[supposedTargetStage] = countPerStage[supposedTargetStage] + 1
|
||||
elseif primaryGroup.state == Spearhead.classes.capClasses.CapGroup.GroupState.RTBINTEN and primaryGroup:GetTargetZone(self.activeStage) ~= primaryGroup.assignedStageNumber then
|
||||
primaryGroup:SendRTB()
|
||||
end
|
||||
else
|
||||
primaryGroup:SendRTBAndDespawn()
|
||||
end
|
||||
end
|
||||
|
||||
if countPerStage[supposedTargetZoneID] == nil then
|
||||
countPerStage[supposedTargetZoneID] = 0
|
||||
end
|
||||
|
||||
for _, backupGroup in pairs(self.BackupGroups) do
|
||||
if backupGroup.state == Spearhead.classes.capClasses.CapGroup.GroupState.READYONRAMP then
|
||||
local supposedTargetStage = backupGroup:GetTargetZone(self.activeStage)
|
||||
if supposedTargetStage then
|
||||
if countPerStage[supposedTargetStage] == nil then
|
||||
countPerStage[supposedTargetStage] = 0
|
||||
if supposedTargetZoneID == group:GetCurrentTargetZoneID() and (state == "OnStation" or state =="InTransit") then
|
||||
countPerStage[supposedTargetZoneID] = countPerStage[supposedTargetZoneID] + 1
|
||||
end
|
||||
|
||||
if countPerStage[supposedTargetStage] < requiredPerStage[supposedTargetStage] then
|
||||
backupGroup:SendToStage(supposedTargetStage)
|
||||
countPerStage[supposedTargetStage] = countPerStage[supposedTargetStage] + 1
|
||||
end
|
||||
else
|
||||
backupGroup:SendRTBAndDespawn()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Schedule or reassign primary units if applicable
|
||||
for _, group in pairs(self.capGroupsByName) do
|
||||
if group:IsBackup() == false then
|
||||
local state = group:GetState()
|
||||
local supposedZone = group:GetZoneIDWhenStageID(activeStageID)
|
||||
if supposedZone then
|
||||
if requiredPerStage[supposedZone] == nil then
|
||||
requiredPerStage[supposedZone] = 0
|
||||
end
|
||||
|
||||
if countPerStage[supposedZone] == nil then
|
||||
countPerStage[supposedZone] = 0
|
||||
end
|
||||
|
||||
requiredPerStage[supposedZone] = requiredPerStage[supposedZone] + 1
|
||||
|
||||
if state == "ReadyOnTheRamp" then
|
||||
if countPerStage[supposedZone] < requiredPerStage[supposedZone] then
|
||||
local triggerZone = self.database:GetCapZoneForZoneID(supposedZone)
|
||||
if triggerZone then
|
||||
group:SendToZone(triggerZone, supposedZone, airbase)
|
||||
end
|
||||
|
||||
countPerStage[supposedZone] = countPerStage[supposedZone] + 1
|
||||
end
|
||||
elseif state == "InTransit" or state == "OnStation" then
|
||||
|
||||
if supposedZone ~= group:GetCurrentTargetZoneID() then
|
||||
if countPerStage[supposedZone] < requiredPerStage[supposedZone] then
|
||||
local triggerZone = self.database:GetCapZoneForZoneID(supposedZone)
|
||||
if triggerZone then
|
||||
group:SendToZone(triggerZone, supposedZone, airbase)
|
||||
else
|
||||
group:SendRTB(airbase)
|
||||
end
|
||||
end
|
||||
end
|
||||
countPerStage[supposedZone] = countPerStage[supposedZone] + 1
|
||||
elseif state == "RtbInTen" and supposedZone ~= group:GetCurrentTargetZoneID() then
|
||||
group:SendRTB(airbase)
|
||||
end
|
||||
else
|
||||
if state == "InTransit" or state == "OnStation" or state == "RtbInTen" then
|
||||
-- If the group is in transit or on station but has no target zone, send it back to base
|
||||
group:SendRTB(airbase)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, group in pairs(self.capGroupsByName) do
|
||||
if group:IsBackup() == true then
|
||||
if group:GetState() == "ReadyOnTheRamp" then
|
||||
local supposedZone = group:GetZoneIDWhenStageID(activeStageID)
|
||||
if supposedZone then
|
||||
if countPerStage[supposedZone] == nil then
|
||||
countPerStage[supposedZone] = 0
|
||||
end
|
||||
|
||||
if countPerStage[supposedZone] < requiredPerStage[supposedZone] then
|
||||
local triggerZone = self.database:GetCapZoneForZoneID(supposedZone)
|
||||
if triggerZone then
|
||||
group:SendToZone(triggerZone, supposedZone, airbase)
|
||||
end
|
||||
|
||||
countPerStage[supposedZone] = countPerStage[supposedZone] + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function CapBase:OnStageNumberChanged(number)
|
||||
self.activeStage = number
|
||||
|
||||
@@ -211,25 +227,21 @@ function CapBase:OnStageNumberChanged(number)
|
||||
mission:SpawnActive()
|
||||
end
|
||||
end
|
||||
|
||||
self:SpawnIfApplicable()
|
||||
timer.scheduleFunction(CheckReschedulingAsync, self, timer.getTime() + 5)
|
||||
end
|
||||
|
||||
|
||||
---@param stageNumber number
|
||||
---@return boolean
|
||||
function CapBase:IsBaseActiveWhenStageIsActive(stageNumber)
|
||||
for _, group in pairs(self.PrimaryGroups) do
|
||||
local target = group:GetTargetZone(stageNumber)
|
||||
if target ~= nil then
|
||||
for _, group in pairs(self.capGroupsByName) do
|
||||
local target = group:GetZoneIDWhenStageID(tostring(stageNumber))
|
||||
if group:IsBackup() == false and target ~= nil then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
if not Spearhead then Spearhead = {} end
|
||||
if not Spearhead.classes then Spearhead.classes = {} end
|
||||
if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end
|
||||
|
||||
Reference in New Issue
Block a user