Dcs lua tool (#66)
* custom drawings and animations for video * wip * Work in progress refactor for toolkit * wip * Refactored everything for Lua Compile Tool * Trying out the github action * updated the github action ref * initial working version --------- Co-authored-by: ex61wi <tim.rorije@ing.com> Co-authored-by: dutchie031 <dutchie031>
This commit is contained in:
committed by
GitHub
co-authored by
ex61wi
dutchie031 <dutchie031>
parent
c027921527
commit
128aed1d2b
@@ -0,0 +1,434 @@
|
||||
local Util = require("classes.util.Util")
|
||||
local CapGroup = require("classes.capClasses.airGroups.CapGroup")
|
||||
local SweepGroup = require("classes.capClasses.airGroups.SweepGroup")
|
||||
local InterceptGroup = require("classes.capClasses.airGroups.InterceptGroup")
|
||||
local RunwayBombingTracker = require("classes.capClasses.runwayBombing.RunwayBombingTracker")
|
||||
local SpearheadEvents = require("classes.spearhead_events")
|
||||
local RunwayStrikeMission = require("classes.stageClasses.missions.RunwayStrikeMission")
|
||||
|
||||
---@class CapBase : OnStageChangedListener
|
||||
---@field private airbaseName string
|
||||
---@field private logger table
|
||||
---@field private database Database
|
||||
---@field private detectionManager DetectionManager
|
||||
---@field private activeStage number
|
||||
---@field private capConfig table
|
||||
---@field private capGroupsByName table<string, CapGroup>
|
||||
---@field private sweepGroupsByName table<string, SweepGroup>
|
||||
---@field private interceptGroupsByName table<string, InterceptGroup>
|
||||
---@field private runwayBombingTracker RunwayBombingTracker
|
||||
---@field private runwayStrikeMissions table<string, RunwayStrikeMission>
|
||||
local CapBase = {}
|
||||
|
||||
|
||||
---comment
|
||||
---@param self CapBase
|
||||
---@param time number
|
||||
---@return number?
|
||||
local CheckStateContinuous = function(self, time)
|
||||
self:CheckAndScheduleCAP()
|
||||
self:CheckAndScheduleSweep()
|
||||
self:CheckAndScheduleIntercept()
|
||||
return time + 15
|
||||
end
|
||||
|
||||
---comment
|
||||
---@param airbaseName string
|
||||
---@param database Database
|
||||
---@param logger table
|
||||
---@param capConfig table
|
||||
---@param stageConfig table
|
||||
---@param runwayBombingTracker RunwayBombingTracker
|
||||
---@param detectionManager DetectionManager
|
||||
---@param spawnManager SpawnManager
|
||||
---@return CapBase
|
||||
function CapBase.new(airbaseName, database, logger, capConfig, stageConfig, runwayBombingTracker, detectionManager, spawnManager)
|
||||
CapBase.__index = CapBase
|
||||
local self = setmetatable({}, { __index = CapBase }) --[[@as CapBase]]
|
||||
|
||||
self.runwayBombingTracker = runwayBombingTracker
|
||||
self.runwayStrikeMissions = {}
|
||||
|
||||
self.airbaseName = airbaseName
|
||||
self.logger = logger
|
||||
self.activeStage = 0
|
||||
self.capConfig = capConfig
|
||||
self.database = database
|
||||
self.capGroupsByName = {}
|
||||
self.sweepGroupsByName = {}
|
||||
self.interceptGroupsByName = {}
|
||||
self.detectionManager = detectionManager
|
||||
|
||||
local baseData = database:getAirbaseDataForZone(airbaseName)
|
||||
if baseData and baseData.CapGroups then
|
||||
for key, name in pairs(baseData.CapGroups) do
|
||||
local capGroup = CapGroup.New(name, capConfig, logger, spawnManager)
|
||||
if capGroup then
|
||||
self.capGroupsByName[name] = capGroup
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if baseData and baseData.SweepGroups then
|
||||
for key, name in pairs(baseData.SweepGroups) do
|
||||
local sweepGroup = SweepGroup.New(name, capConfig, logger, spawnManager)
|
||||
if sweepGroup then
|
||||
self.sweepGroupsByName[name] = sweepGroup
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if baseData and baseData.InterceptGroups then
|
||||
for key, name in pairs(baseData.InterceptGroups) do
|
||||
local interceptGroup = InterceptGroup.New(name, capConfig, logger, detectionManager, spawnManager)
|
||||
if interceptGroup then
|
||||
self.interceptGroupsByName[name] = interceptGroup
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local capFlights = Util.tableLength(self.capGroupsByName)
|
||||
local sweepFlights = Util.tableLength(self.sweepGroupsByName)
|
||||
local interceptFlights = Util.tableLength(self.interceptGroupsByName)
|
||||
|
||||
logger:info(airbaseName .. " : " .. capFlights .." CAP | " .. sweepFlights .. " SWEEP | " .. interceptFlights .. " INTERCEPT")
|
||||
|
||||
self:CreateRunwayStrikeMission(database)
|
||||
SpearheadEvents.AddStageNumberChangedListener(self)
|
||||
|
||||
timer.scheduleFunction(CheckStateContinuous, self, timer.getTime() + 15)
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param database Database
|
||||
function CapBase:CreateRunwayStrikeMission(database)
|
||||
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 = RunwayStrikeMission.new(runway, self.airbaseName,
|
||||
database, self.logger, self.runwayBombingTracker)
|
||||
self.runwayStrikeMissions[runway.Name] = mission
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
for groupName, sweepGroup in pairs(self.sweepGroupsByName) do
|
||||
local targetStage = sweepGroup:GetZoneIDWhenStageID(tostring(self.activeStage))
|
||||
|
||||
if targetStage ~= nil and sweepGroup:GetState() == "UnSpawned" then
|
||||
sweepGroup:Spawn()
|
||||
end
|
||||
end
|
||||
|
||||
for groupName, interceptGroup in pairs(self.interceptGroupsByName) do
|
||||
local targetStage = interceptGroup:GetZoneIDWhenStageID(tostring(self.activeStage))
|
||||
|
||||
if targetStage ~= nil and interceptGroup:GetState() == "UnSpawned" then
|
||||
interceptGroup:Spawn()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function CapBase:CheckAndScheduleCAP()
|
||||
self.logger:debug("Check taskings for airbase " .. self.airbaseName)
|
||||
|
||||
local countPerStage = {}
|
||||
local requiredPerStage = {}
|
||||
|
||||
local airbase = Airbase.getByName(self.airbaseName)
|
||||
if not airbase then
|
||||
return nil
|
||||
end
|
||||
|
||||
local activeStageID = tostring(self.activeStage)
|
||||
|
||||
--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()
|
||||
|
||||
if supposedTargetZoneID == nil then
|
||||
self.logger:debug("CapGroup " .. group:GetName() .. " has no target zone for stage " .. activeStageID)
|
||||
group:SendRTB(airbase)
|
||||
else
|
||||
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
|
||||
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
|
||||
|
||||
if countPerStage[supposedTargetZoneID] == nil then
|
||||
countPerStage[supposedTargetZoneID] = 0
|
||||
end
|
||||
|
||||
if supposedTargetZoneID == group:GetCurrentTargetZoneID() and (state == "OnStation" or state =="InTransit") then
|
||||
countPerStage[supposedTargetZoneID] = countPerStage[supposedTargetZoneID] + 1
|
||||
end
|
||||
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 requiredPerStage[supposedZone] == nil then
|
||||
requiredPerStage[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:CheckAndScheduleSweep()
|
||||
self.logger:debug("Check sweep taskings for airbase " .. self.airbaseName)
|
||||
|
||||
local airbase = Airbase.getByName(self.airbaseName)
|
||||
if not airbase then
|
||||
return nil
|
||||
end
|
||||
|
||||
local activeStageID = tostring(self.activeStage)
|
||||
|
||||
for _, group in pairs(self.sweepGroupsByName) do
|
||||
local targetZoneID = group:GetZoneIDWhenStageID(activeStageID)
|
||||
if targetZoneID then
|
||||
local triggerZone = self.database:GetCapZoneForZoneID(targetZoneID)
|
||||
if triggerZone then
|
||||
if group:GetState() == "ReadyOnTheRamp" then
|
||||
group:SendToZone(triggerZone, targetZoneID, airbase)
|
||||
end
|
||||
else
|
||||
self.logger:debug("SweepGroup " .. group:GetName() .. " has no trigger zone for stage " .. activeStageID)
|
||||
group:SendRTB(airbase)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function CapBase:CheckAndScheduleIntercept()
|
||||
|
||||
self.logger:debug("Check intercept taskings for airbase " .. self.airbaseName)
|
||||
|
||||
local interceptZoneIDs = {}
|
||||
|
||||
local interceptZoneIDs = {}
|
||||
|
||||
local airbase = Airbase.getByName(self.airbaseName)
|
||||
if not airbase then
|
||||
return nil
|
||||
end
|
||||
|
||||
for name, group in pairs(self.interceptGroupsByName) do
|
||||
local targetZoneID = group:GetZoneIDWhenStageID(tostring(self.activeStage))
|
||||
if targetZoneID then
|
||||
interceptZoneIDs[targetZoneID] = true
|
||||
end
|
||||
end
|
||||
|
||||
---@type table<string, Array<string>>
|
||||
local unitsToInterceptPerZone = {}
|
||||
|
||||
local detectedUnits = self.detectionManager:GetDetectedUnitsBy(coalition.side.RED)
|
||||
for targetZoneID, _ in pairs(interceptZoneIDs) do
|
||||
local zones = self.database:GetInterceptZonesForZoneID(targetZoneID)
|
||||
if zones then
|
||||
for _, zone in pairs(zones) do
|
||||
|
||||
self.logger:debug("Check intercept zone " .. zone.name .. " for airbase " .. self.airbaseName)
|
||||
|
||||
for _, unitName in pairs(detectedUnits) do
|
||||
self.logger:debug("Check unit " .. unitName .. " for intercept in zone " .. zone.name)
|
||||
|
||||
local unit = Unit.getByName(unitName)
|
||||
if unit and unit:isExist() then
|
||||
local unitPos = unit:getPoint()
|
||||
if Util.is3dPointInZone(unitPos, zone) == true then
|
||||
if not unitsToInterceptPerZone[zone.name] then
|
||||
unitsToInterceptPerZone[zone.name] = {}
|
||||
end
|
||||
|
||||
table.insert(unitsToInterceptPerZone[zone.name], unitName)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---RATIO. Amount of enemy fighters required per zone before another group gets added.
|
||||
local ratio = 4 -- Ratio of units to intercept per zone, can be adjusted
|
||||
|
||||
for name, targets in pairs(unitsToInterceptPerZone) do
|
||||
local required = 0
|
||||
local nrTargets = Util.tableLength(targets)
|
||||
if targets and nrTargets > 0 then
|
||||
required = math.ceil(nrTargets / ratio)
|
||||
end
|
||||
|
||||
local total = 0
|
||||
for _, group in pairs(self.interceptGroupsByName) do
|
||||
if group:GetState() == "OnStation" and group:GetCurrentTargetZone() == name then
|
||||
group:SetTargetUnits(targets)
|
||||
total = total + 1
|
||||
end
|
||||
end
|
||||
|
||||
if total < required then
|
||||
for _, group in pairs(self.interceptGroupsByName) do
|
||||
if total < required then
|
||||
local zoneID = group:GetZoneIDWhenStageID(tostring(self.activeStage))
|
||||
if group:GetState() == "ReadyOnTheRamp" then
|
||||
group:SendToInterceptUnits(targets, name, airbase)
|
||||
total = total + 1
|
||||
|
||||
self.logger:debug("Intercept group " .. group:GetName() .. " sent to intercept zone " .. name )
|
||||
elseif group:GetState() == "InTransit" or group:GetState() == "OnStation" then
|
||||
group:SetTargetUnits(targets)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
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()
|
||||
end
|
||||
|
||||
---@param stageNumber number
|
||||
---@return boolean
|
||||
function CapBase:IsBaseActiveWhenStageIsActive(stageNumber)
|
||||
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
|
||||
|
||||
for _, group in pairs(self.sweepGroupsByName) do
|
||||
local target = group:GetZoneIDWhenStageID(tostring(stageNumber))
|
||||
if target ~= nil then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
for _, group in pairs(self.interceptGroupsByName) do
|
||||
local target = group:GetZoneIDWhenStageID(tostring(stageNumber))
|
||||
if target ~= nil then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
return CapBase
|
||||
Reference in New Issue
Block a user