Feature/mission refactor (#26)
* Refactored Mission classes to add Missions other than trigger zone missions. (eg. Runway Strikes, Resupply etc.) * Runway strike initial POC Co-authored-by: dutchie032 <dutchie032>
This commit is contained in:
@@ -10,6 +10,8 @@
|
||||
---@field groupsByName table<string, CapGroup>
|
||||
---@field PrimaryGroups Array<CapGroup>
|
||||
---@field BackupGroups Array<CapGroup>
|
||||
---@field private runwayBombingTracker RunwayBombingTracker
|
||||
---@field private runwayStrikeMissions table<string, RunwayStrikeMission>
|
||||
local CapBase = {}
|
||||
|
||||
|
||||
@@ -23,14 +25,17 @@ end
|
||||
---@param logger table
|
||||
---@param capConfig table
|
||||
---@param stageConfig table
|
||||
---@param runwayBombingTracker RunwayBombingTracker
|
||||
---@return CapBase
|
||||
function CapBase.new(airbaseName, database, logger, capConfig, stageConfig)
|
||||
function CapBase.new(airbaseName, database, logger, capConfig, stageConfig, runwayBombingTracker)
|
||||
|
||||
CapBase.__index = CapBase
|
||||
local self = setmetatable({}, { __index = CapBase }) --[[@as CapBase]]
|
||||
|
||||
self.groupNames = database:getCapGroupsAtAirbase(airbaseName)
|
||||
self.database = database
|
||||
self.runwayBombingTracker = runwayBombingTracker
|
||||
self.runwayStrikeMissions = {}
|
||||
|
||||
self.airbaseName = airbaseName
|
||||
self.logger = logger
|
||||
@@ -44,7 +49,7 @@ function CapBase.new(airbaseName, database, logger, capConfig, stageConfig)
|
||||
self.BackupGroups = {}
|
||||
|
||||
for key, name in pairs(self.groupNames) do
|
||||
local capGroup = Spearhead.internal.CapGroup.new(name, airbaseName, logger, database, capConfig)
|
||||
local capGroup = Spearhead.classes.capClasses.CapGroup.new(name, airbaseName, logger, database, capConfig)
|
||||
if capGroup then
|
||||
self.groupsByName[name] = capGroup
|
||||
|
||||
@@ -57,21 +62,40 @@ function CapBase.new(airbaseName, database, logger, capConfig, stageConfig)
|
||||
capGroup:AddOnStateUpdatedListener(self)
|
||||
end
|
||||
end
|
||||
logger:info("Airbase with name '" .. airbaseName .. "' has a total of " .. Spearhead.Util.tableLength(self.groupsByName) .. "cap flights registered")
|
||||
logger:info("Airbase with name '" .. airbaseName .. "' has a total of " .. Spearhead.Util.tableLength(self.groupsByName) .. " cap flights registered")
|
||||
|
||||
self:CreateRunwayStrikeMission()
|
||||
|
||||
Spearhead.Events.AddStageNumberChangedListener(self)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
---@private
|
||||
function CapBase:CreateRunwayStrikeMission()
|
||||
|
||||
local airbase = Airbase.getByName(self.airbaseName)
|
||||
if not airbase then
|
||||
self.logger:debug("Could not find a airbase with name to create runway mission" .. self.airbaseName)
|
||||
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.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.internal.CapGroup.GroupState.INTRANSIT
|
||||
or capGroup.state == Spearhead.internal.CapGroup.GroupState.ONSTATION
|
||||
or capGroup.state == Spearhead.internal.CapGroup.GroupState.REARMING
|
||||
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
|
||||
end
|
||||
@@ -84,7 +108,7 @@ function CapBase:SpawnIfApplicable()
|
||||
|
||||
local targetStage = capGroup:GetTargetZone(self.activeStage)
|
||||
|
||||
if targetStage ~= nil and capGroup.state == Spearhead.internal.CapGroup.GroupState.UNSPAWNED then
|
||||
if targetStage ~= nil and capGroup.state == Spearhead.classes.capClasses.CapGroup.GroupState.UNSPAWNED then
|
||||
capGroup:SpawnOnTheRamp()
|
||||
end
|
||||
end
|
||||
@@ -99,7 +123,7 @@ function CapBase:CheckAndScheduleCAP()
|
||||
|
||||
--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.internal.CapGroup.GroupState.INTRANSIT or backupGroup.state == Spearhead.internal.CapGroup.GroupState.ONSTATION then
|
||||
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
|
||||
@@ -113,7 +137,7 @@ function CapBase:CheckAndScheduleCAP()
|
||||
else
|
||||
backupGroup:SendRTBAndDespawn()
|
||||
end
|
||||
elseif backupGroup.state == Spearhead.internal.CapGroup.GroupState.RTBINTEN and backupGroup:GetTargetZone(self.activeStage) ~= backupGroup.assignedStageNumber then
|
||||
elseif backupGroup.state == Spearhead.classes.capClasses.CapGroup.GroupState.RTBINTEN and backupGroup:GetTargetZone(self.activeStage) ~= backupGroup.assignedStageNumber then
|
||||
backupGroup:SendRTB()
|
||||
end
|
||||
end
|
||||
@@ -133,12 +157,12 @@ function CapBase:CheckAndScheduleCAP()
|
||||
|
||||
requiredPerStage[supposedTargetStage] = requiredPerStage[supposedTargetStage] + 1
|
||||
|
||||
if primaryGroup.state == Spearhead.internal.CapGroup.GroupState.READYONRAMP then
|
||||
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.internal.CapGroup.GroupState.INTRANSIT or primaryGroup.state == Spearhead.internal.CapGroup.GroupState.ONSTATION then
|
||||
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)
|
||||
@@ -148,7 +172,7 @@ function CapBase:CheckAndScheduleCAP()
|
||||
end
|
||||
end
|
||||
countPerStage[supposedTargetStage] = countPerStage[supposedTargetStage] + 1
|
||||
elseif primaryGroup.state == Spearhead.internal.CapGroup.GroupState.RTBINTEN and primaryGroup:GetTargetZone(self.activeStage) ~= primaryGroup.assignedStageNumber then
|
||||
elseif primaryGroup.state == Spearhead.classes.capClasses.CapGroup.GroupState.RTBINTEN and primaryGroup:GetTargetZone(self.activeStage) ~= primaryGroup.assignedStageNumber then
|
||||
primaryGroup:SendRTB()
|
||||
end
|
||||
else
|
||||
@@ -157,7 +181,7 @@ function CapBase:CheckAndScheduleCAP()
|
||||
end
|
||||
|
||||
for _, backupGroup in pairs(self.BackupGroups) do
|
||||
if backupGroup.state == Spearhead.internal.CapGroup.GroupState.READYONRAMP then
|
||||
if backupGroup.state == Spearhead.classes.capClasses.CapGroup.GroupState.READYONRAMP then
|
||||
local supposedTargetStage = backupGroup:GetTargetZone(self.activeStage)
|
||||
if supposedTargetStage then
|
||||
if countPerStage[supposedTargetStage] == nil then
|
||||
@@ -177,6 +201,13 @@ function CapBase:CheckAndScheduleCAP()
|
||||
|
||||
function CapBase:OnStageNumberChanged(number)
|
||||
self.activeStage = number
|
||||
|
||||
if self:IsBaseActiveWhenStageIsActive(number) == true then
|
||||
for _, mission in pairs(self.runwayStrikeMissions) do
|
||||
mission:SpawnActive()
|
||||
end
|
||||
end
|
||||
|
||||
self:SpawnIfApplicable()
|
||||
timer.scheduleFunction(CheckReschedulingAsync, self, timer.getTime() + 5)
|
||||
end
|
||||
@@ -195,5 +226,7 @@ function CapBase:IsBaseActiveWhenStageIsActive(stageNumber)
|
||||
end
|
||||
|
||||
|
||||
if not Spearhead.internal then Spearhead.internal = {} end
|
||||
Spearhead.internal.CapAirbase = CapBase
|
||||
if not Spearhead then Spearhead = {} end
|
||||
if not Spearhead.classes then Spearhead.classes = {} end
|
||||
if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end
|
||||
Spearhead.classes.capClasses.CapAirbase = CapBase
|
||||
|
||||
@@ -261,6 +261,11 @@ function CapGroup:SendToStage(stageZoneNumber)
|
||||
local controller = group:getController()
|
||||
local capPoints = self.database:getCapRouteInZone(stageZoneNumber, self.airbaseName)
|
||||
|
||||
if not capPoints then
|
||||
self.logger:error("No CAP route found for group " .. self.groupName .. " in zone " .. stageZoneNumber)
|
||||
return
|
||||
end
|
||||
|
||||
local altitude = math.random(self.capConfig:getMinAlt(), self.capConfig:getMaxAlt())
|
||||
local speed = math.random(self.capConfig:getMinSpeed(), self.capConfig:getMaxSpeed())
|
||||
local attackHelos = false
|
||||
@@ -418,5 +423,7 @@ function CapGroup:OnUnitLost(initiatorUnit)
|
||||
end
|
||||
|
||||
|
||||
if not Spearhead.internal then Spearhead.internal = {} end
|
||||
Spearhead.internal.CapGroup = CapGroup
|
||||
if not Spearhead then Spearhead = {} end
|
||||
if not Spearhead.classes then Spearhead.classes = {} end
|
||||
if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end
|
||||
Spearhead.classes.capClasses.CapGroup = CapGroup
|
||||
|
||||
@@ -9,12 +9,15 @@ do
|
||||
|
||||
---comment
|
||||
---@param database Database
|
||||
---@param capConfig any
|
||||
---@param stageConfig any
|
||||
function GlobalCapManager.start(database, capConfig, stageConfig)
|
||||
---@param capConfig table
|
||||
---@param stageConfig StageConfig
|
||||
---@param logLevel LogLevel
|
||||
function GlobalCapManager.start(database, capConfig, stageConfig, logLevel)
|
||||
if initiated == true then return end
|
||||
|
||||
local logger = Spearhead.LoggerTemplate.new("AirbaseManager", capConfig.logLevel)
|
||||
local logger = Spearhead.LoggerTemplate.new("AirbaseManager", logLevel)
|
||||
local bombTrackLogger = Spearhead.LoggerTemplate.new("RunwayBombingTracker", logLevel)
|
||||
local runwayBombingTracker = Spearhead.classes.capClasses.runwayBombing.RunwayBombingTracker.new(bombTrackLogger)
|
||||
|
||||
local zones = database:getStagezoneNames()
|
||||
if zones then
|
||||
@@ -27,8 +30,8 @@ do
|
||||
if airbaseNames then
|
||||
for _, airbaseName in pairs(airbaseNames) do
|
||||
if airbaseName then
|
||||
local airbaseSpecificLogger = Spearhead.LoggerTemplate.new("CAP_" .. airbaseName, capConfig.logLevel)
|
||||
local airbase = Spearhead.internal.CapAirbase.new(airbaseName, database, airbaseSpecificLogger, capConfig, stageConfig)
|
||||
local airbaseSpecificLogger = Spearhead.LoggerTemplate.new("CAP_" .. airbaseName, logLevel)
|
||||
local airbase = Spearhead.classes.capClasses.CapAirbase.new(airbaseName, database, airbaseSpecificLogger, capConfig, stageConfig, runwayBombingTracker)
|
||||
if airbase then
|
||||
table.insert(airbasesPerStage[stageName], airbase)
|
||||
allAirbasesByName[airbaseName] = airbase
|
||||
@@ -61,5 +64,9 @@ do
|
||||
end
|
||||
end
|
||||
|
||||
if not Spearhead.internal then Spearhead.internal = {} end
|
||||
Spearhead.internal.GlobalCapManager = GlobalCapManager
|
||||
|
||||
|
||||
if not Spearhead then Spearhead = {} end
|
||||
if not Spearhead.classes then Spearhead.classes = {} end
|
||||
if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end
|
||||
Spearhead.classes.capClasses.GlobalCapManager = GlobalCapManager
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
---@class RunwayBombingTracker : OnWeaponFiredListener
|
||||
---@field trackedRunways table<Runway, RunwayStrikeMission>
|
||||
---@field private _logger Logger
|
||||
local RunwayBombingTracker = {}
|
||||
RunwayBombingTracker.__index = RunwayBombingTracker
|
||||
|
||||
--- Constructor
|
||||
--- @param logger Logger
|
||||
--- @return RunwayBombingTracker
|
||||
function RunwayBombingTracker.new(logger)
|
||||
local self = setmetatable({}, RunwayBombingTracker)
|
||||
|
||||
self._logger = logger
|
||||
|
||||
Spearhead.Events.AddWeaponFiredListener(self)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
---comment
|
||||
---@param weapon Weapon
|
||||
function RunwayBombingTracker:OnWeaponFired(unit, weapon, target)
|
||||
|
||||
if weapon == nil then
|
||||
return
|
||||
end
|
||||
|
||||
self._logger:debug("Tracking weapon for runway impact onWeaponFired")
|
||||
|
||||
local desc = weapon:getDesc()
|
||||
|
||||
local isTrackable = desc.category == Weapon.Category.BOMB or (desc.category == Weapon.Category.MISSILE and desc.missileCategory == Weapon.MissileCategory.CRUISE)
|
||||
|
||||
if isTrackable == true then
|
||||
|
||||
---@type WeaponTrackingArgs
|
||||
local weaponTrackingArgs = {
|
||||
weapon = weapon,
|
||||
self = self
|
||||
}
|
||||
|
||||
timer.scheduleFunction(RunwayBombingTracker.trackWeaponTask, weaponTrackingArgs, timer.getTime() + 1)
|
||||
end
|
||||
end
|
||||
|
||||
function RunwayBombingTracker:RegisterRunway(runway, strikeMission)
|
||||
if not self.trackedRunways then
|
||||
self.trackedRunways = {}
|
||||
end
|
||||
|
||||
if not self.trackedRunways[runway] then
|
||||
self.trackedRunways[runway] = strikeMission
|
||||
end
|
||||
end
|
||||
|
||||
---@class WeaponTrackingArgs
|
||||
---@field weapon Weapon
|
||||
---@field self RunwayBombingTracker
|
||||
|
||||
---@private
|
||||
---@param weaponTrackingArgs WeaponTrackingArgs
|
||||
function RunwayBombingTracker.trackWeaponTask(weaponTrackingArgs, time)
|
||||
|
||||
local weapon = weaponTrackingArgs.weapon
|
||||
local self = weaponTrackingArgs.self
|
||||
|
||||
if not weapon then return nil end
|
||||
|
||||
local pos = weapon:getPoint()
|
||||
local velocity = weapon:getVelocity()
|
||||
local ground = land.getHeight({ x = pos.x, y = pos.z })
|
||||
local MpS = velocity.y -- increase the speed to make sure you don't miss it.
|
||||
|
||||
if MpS > 0 then
|
||||
return time + 3
|
||||
end
|
||||
|
||||
local nextInterval = (pos.y - ground) / math.abs(MpS)
|
||||
|
||||
if nextInterval < 1 then
|
||||
|
||||
-- Calculate the impact point of the weapon
|
||||
---@type Vec2
|
||||
local impactPoint = {
|
||||
x = pos.x + velocity.x * nextInterval,
|
||||
y = pos.z + velocity.z * nextInterval
|
||||
}
|
||||
|
||||
|
||||
self:OnWeaponImpact(weapon:getDesc(), impactPoint)
|
||||
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
if nextInterval > 5 then
|
||||
nextInterval = 5
|
||||
end
|
||||
|
||||
return time + (nextInterval /2)
|
||||
end
|
||||
|
||||
|
||||
---comment
|
||||
---@param weaponDesc table
|
||||
---@param impactPoint Vec2
|
||||
function RunwayBombingTracker:OnWeaponImpact(weaponDesc, impactPoint)
|
||||
|
||||
self._logger:debug("RunwayBombingTracker:OnWeaponImpact")
|
||||
|
||||
local warhead = weaponDesc.warhead
|
||||
local explosiveMass = warhead.explosiveMass or warhead.shapedExplosiveMass
|
||||
|
||||
for runway, strikeMission in pairs(self.trackedRunways) do
|
||||
|
||||
local zone= strikeMission:GetRunwayZone()
|
||||
|
||||
if Spearhead.Util.is3dPointInZone({ x = impactPoint.x, z = impactPoint.y, y = 0 }, zone) then
|
||||
strikeMission:RunwayHit(impactPoint, explosiveMass)
|
||||
end
|
||||
end
|
||||
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
|
||||
if not Spearhead.classes.capClasses.runwayBombing then Spearhead.classes.capClasses.runwayBombing = {} end
|
||||
Spearhead.classes.capClasses.runwayBombing.RunwayBombingTracker = RunwayBombingTracker
|
||||
Reference in New Issue
Block a user