Automatically detect when bases are captured

Stop dispatching cargo to captured bases
Stop using captured squadrons for intercepts
Display clear status information to players showing which bases are operational vs captured
Treat base capture as normal mission state, not an error condition
This commit is contained in:
iTracerFacer 2025-10-20 08:21:48 -05:00
parent ed662a6289
commit 4b18037c32
6 changed files with 352 additions and 2762 deletions

View File

@ -404,8 +404,8 @@ local function dispatchCargo(squadron, coalitionKey)
local destCoalition = destAirbase:GetCoalition()
if destCoalition ~= coalitionSide then
log("WARNING: Destination airbase '" .. destination .. "' is not controlled by " .. coalitionKey .. " coalition (currently coalition " .. tostring(destCoalition) .. "). This will cause RAT to fail with 'Airbase doesn't exist' error. Skipping dispatch.")
announceToCoalition(coalitionKey, "Resupply mission to " .. destination .. " aborted (airbase captured by enemy)!")
log("INFO: Destination airbase '" .. destination .. "' captured by enemy - cargo dispatch skipped (normal mission state).", true)
-- No announcement to coalition - this is expected behavior when base is captured
-- Mark mission as failed and cleanup immediately
mission.status = "failed"
return
@ -423,10 +423,8 @@ local function dispatchCargo(squadron, coalitionKey)
local originCoalition = originAirbase:GetCoalition()
if originCoalition ~= coalitionSide then
log("WARNING: Origin airbase '" .. origin .. "' is not controlled by " .. coalitionKey .. " coalition (currently coalition " .. tostring(originCoalition) .. "). This will cause RAT to fail. Skipping dispatch.")
announceToCoalition(coalitionKey, "Resupply mission from " .. origin .. " failed (origin airbase captured by enemy)!")
-- Mark mission as failed and cleanup immediately
mission.status = "failed"
log("INFO: Origin airbase '" .. origin .. "' captured by enemy - trying another supply source.", true)
-- Don't announce or mark as failed - the dispatcher will try another origin
return
end
@ -581,12 +579,17 @@ end
--------------------------------------------------------------------------
Checks all squadrons for each coalition. If a squadron is below the resupply threshold and has no active cargo mission,
triggers a supply request and dispatches a cargo aircraft.
Skips squadrons that are captured or not operational.
]]
local function monitorSquadrons()
for _, coalitionKey in ipairs({"red", "blue"}) do
local config = CARGO_SUPPLY_CONFIG[coalitionKey]
local squadrons = (coalitionKey == "red") and RED_SQUADRON_CONFIG or BLUE_SQUADRON_CONFIG
for _, squadron in ipairs(squadrons) do
-- Skip non-operational squadrons (captured, destroyed, etc.)
if squadron.state and squadron.state ~= "operational" then
log("Squadron " .. squadron.displayName .. " (" .. coalitionKey .. ") is " .. squadron.state .. " - skipping cargo dispatch", true)
else
local current, max, ratio = getSquadronStatus(squadron, coalitionKey)
log("Squadron status: " .. squadron.displayName .. " (" .. coalitionKey .. ") " .. current .. "/" .. max .. " ratio: " .. string.format("%.2f", ratio))
if ratio <= config.threshold and not hasActiveCargoMission(coalitionKey, squadron.airbaseName) then
@ -597,6 +600,7 @@ local function monitorSquadrons()
end
end
end
end
--[[
monitorCargoMissions()

View File

@ -319,7 +319,11 @@ end
-- Squadron resource summary generator
local function getSquadronResourceSummary(coalitionSide)
local function getStatus(remaining, max)
local function getStatus(remaining, max, state)
if state == "captured" then return "[CAPTURED]" end
if state == "destroyed" then return "[DESTROYED]" end
if state ~= "operational" then return "[OFFLINE]" end
local percent = (remaining / max) * 100
if percent <= 10 then return "[CRITICAL]" end
if percent <= 25 then return "[LOW]" end
@ -336,19 +340,21 @@ local function getSquadronResourceSummary(coalitionSide)
for _, squadron in pairs(RED_SQUADRON_CONFIG) do
local remaining = squadronAircraftCounts.red[squadron.templateName] or 0
local max = squadron.aircraft or 0
local status = getStatus(remaining, max)
local state = squadron.state or "operational"
local status = getStatus(remaining, max, state)
table.insert(lines, string.format("| %-13s | %2d / %-15d | %-11s |", squadron.displayName or squadron.templateName, remaining, max, status))
end
elseif coalitionSide == coalition.side.BLUE then
for _, squadron in pairs(BLUE_SQUADRON_CONFIG) do
local remaining = squadronAircraftCounts.blue[squadron.templateName] or 0
local max = squadron.aircraft or 0
local status = getStatus(remaining, max)
local state = squadron.state or "operational"
local status = getStatus(remaining, max, state)
table.insert(lines, string.format("| %-13s | %2d / %-15d | %-11s |", squadron.displayName or squadron.templateName, remaining, max, status))
end
end
table.insert(lines, "\n- [LOW]: Below 25%\n- [CRITICAL]: Below 10%\n- OK: Above 25%")
table.insert(lines, "\n- [CAPTURED]: Airbase captured by enemy\n- [LOW]: Below 25%\n- [CRITICAL]: Below 10%\n- OK: Above 25%")
return table.concat(lines, "\n")
end
@ -1404,8 +1410,20 @@ local function findBestSquadron(threatCoord, threatSize, coalitionSide)
local squadronAvailable = true
local unavailableReason = ""
-- Check squadron state first
if squadron.state and squadron.state ~= "operational" then
squadronAvailable = false
if squadron.state == "captured" then
unavailableReason = "airbase captured by enemy"
elseif squadron.state == "destroyed" then
unavailableReason = "airbase destroyed"
else
unavailableReason = "squadron not operational (state: " .. tostring(squadron.state) .. ")"
end
end
-- Check cooldown
if squadronCooldowns[coalitionKey][squadron.templateName] then
if squadronAvailable and squadronCooldowns[coalitionKey][squadron.templateName] then
local cooldownEnd = squadronCooldowns[coalitionKey][squadron.templateName]
if currentTime < cooldownEnd then
local timeLeft = math.ceil((cooldownEnd - currentTime) / 60)
@ -1808,12 +1826,36 @@ local function checkAirbaseStatus()
if TADC_SETTINGS.enableRed then
log("=== RED COALITION STATUS ===")
for _, squadron in pairs(RED_SQUADRON_CONFIG) do
local usable, status = isAirbaseUsable(squadron.airbaseName, coalition.side.RED)
-- Add aircraft count to status
local airbase = AIRBASE:FindByName(squadron.airbaseName)
local aircraftCount = squadronAircraftCounts.red[squadron.templateName] or 0
local maxAircraft = squadron.aircraft
local aircraftStatus = " Aircraft: " .. aircraftCount .. "/" .. maxAircraft
-- Determine status based on squadron state
local statusPrefix = ""
local statusText = ""
local usable = false
if squadron.state == "operational" then
statusPrefix = ""
statusText = "Operational: " .. aircraftCount .. "/" .. maxAircraft .. " aircraft"
usable = true
elseif squadron.state == "captured" then
-- Determine who captured it
local capturedBy = "enemy"
if airbase and airbase:IsAlive() then
local airbaseCoalition = airbase:GetCoalition()
if airbaseCoalition == coalition.side.BLUE then
capturedBy = "Blue"
elseif airbaseCoalition == coalition.side.NEUTRAL then
capturedBy = "neutral forces"
end
end
statusText = "Captured by " .. capturedBy .. ": " .. aircraftCount .. "/" .. maxAircraft .. " aircraft"
elseif squadron.state == "destroyed" then
statusText = "Destroyed: " .. aircraftCount .. "/" .. maxAircraft .. " aircraft"
else
statusText = "Unknown state: " .. aircraftCount .. "/" .. maxAircraft .. " aircraft"
end
-- Add zone information if configured
local zoneStatus = ""
@ -1825,9 +1867,9 @@ local function checkAirbaseStatus()
zoneStatus = " Zones: " .. table.concat(zones, " ")
end
-- Check if squadron is on cooldown
-- Check if squadron is on cooldown (only show for operational squadrons)
local cooldownStatus = ""
if squadronCooldowns.red[squadron.templateName] then
if squadron.state == "operational" and squadronCooldowns.red[squadron.templateName] then
local cooldownEnd = squadronCooldowns.red[squadron.templateName]
if currentTime < cooldownEnd then
local timeLeft = math.ceil((cooldownEnd - currentTime) / 60)
@ -1835,14 +1877,13 @@ local function checkAirbaseStatus()
end
end
local fullStatus = status .. aircraftStatus .. zoneStatus .. cooldownStatus
local fullStatus = statusText .. zoneStatus .. cooldownStatus
if usable and cooldownStatus == "" and aircraftCount > 0 then
redUsableCount = redUsableCount + 1
log("" .. squadron.airbaseName .. " - " .. fullStatus)
else
log("" .. squadron.airbaseName .. " - " .. fullStatus)
end
log(statusPrefix .. " " .. squadron.airbaseName .. " - " .. fullStatus)
end
log("RED Status: " .. redUsableCount .. "/" .. #RED_SQUADRON_CONFIG .. " airbases operational")
end
@ -1851,12 +1892,36 @@ local function checkAirbaseStatus()
if TADC_SETTINGS.enableBlue then
log("=== BLUE COALITION STATUS ===")
for _, squadron in pairs(BLUE_SQUADRON_CONFIG) do
local usable, status = isAirbaseUsable(squadron.airbaseName, coalition.side.BLUE)
-- Add aircraft count to status
local airbase = AIRBASE:FindByName(squadron.airbaseName)
local aircraftCount = squadronAircraftCounts.blue[squadron.templateName] or 0
local maxAircraft = squadron.aircraft
local aircraftStatus = " Aircraft: " .. aircraftCount .. "/" .. maxAircraft
-- Determine status based on squadron state
local statusPrefix = ""
local statusText = ""
local usable = false
if squadron.state == "operational" then
statusPrefix = ""
statusText = "Operational: " .. aircraftCount .. "/" .. maxAircraft .. " aircraft"
usable = true
elseif squadron.state == "captured" then
-- Determine who captured it
local capturedBy = "enemy"
if airbase and airbase:IsAlive() then
local airbaseCoalition = airbase:GetCoalition()
if airbaseCoalition == coalition.side.RED then
capturedBy = "Red"
elseif airbaseCoalition == coalition.side.NEUTRAL then
capturedBy = "neutral forces"
end
end
statusText = "Captured by " .. capturedBy .. ": " .. aircraftCount .. "/" .. maxAircraft .. " aircraft"
elseif squadron.state == "destroyed" then
statusText = "Destroyed: " .. aircraftCount .. "/" .. maxAircraft .. " aircraft"
else
statusText = "Unknown state: " .. aircraftCount .. "/" .. maxAircraft .. " aircraft"
end
-- Add zone information if configured
local zoneStatus = ""
@ -1868,9 +1933,9 @@ local function checkAirbaseStatus()
zoneStatus = " Zones: " .. table.concat(zones, " ")
end
-- Check if squadron is on cooldown
-- Check if squadron is on cooldown (only show for operational squadrons)
local cooldownStatus = ""
if squadronCooldowns.blue[squadron.templateName] then
if squadron.state == "operational" and squadronCooldowns.blue[squadron.templateName] then
local cooldownEnd = squadronCooldowns.blue[squadron.templateName]
if currentTime < cooldownEnd then
local timeLeft = math.ceil((cooldownEnd - currentTime) / 60)
@ -1878,13 +1943,13 @@ local function checkAirbaseStatus()
end
end
local fullStatus = status .. aircraftStatus .. zoneStatus .. cooldownStatus
local fullStatus = statusText .. zoneStatus .. cooldownStatus
if usable and cooldownStatus == "" and aircraftCount > 0 then
blueUsableCount = blueUsableCount + 1
log("" .. squadron.airbaseName .. " - " .. fullStatus)
else
log(" " .. squadron.airbaseName .. " - " .. fullStatus)
end
log(statusPrefix .. " " .. squadron.airbaseName .. " - " .. fullStatus)
end
end
log("BLUE Status: " .. blueUsableCount .. "/" .. #BLUE_SQUADRON_CONFIG .. " airbases operational")
@ -1911,6 +1976,63 @@ local function cleanupOldDeliveries()
end
end
-- Update squadron states based on airbase coalition control
local function updateSquadronStates()
-- Update RED squadrons
for _, squadron in pairs(RED_SQUADRON_CONFIG) do
local airbase = AIRBASE:FindByName(squadron.airbaseName)
if airbase and airbase:IsAlive() then
local airbaseCoalition = airbase:GetCoalition()
if airbaseCoalition == coalition.side.RED then
-- Only update to operational if not already operational (avoid spam)
if squadron.state ~= "operational" then
squadron.state = "operational"
log("RED Squadron " .. squadron.displayName .. " at " .. squadron.airbaseName .. " is now operational")
end
else
-- Airbase captured
if squadron.state ~= "captured" then
squadron.state = "captured"
log("RED Squadron " .. squadron.displayName .. " at " .. squadron.airbaseName .. " has been captured by enemy")
end
end
else
-- Airbase destroyed or not found
if squadron.state ~= "destroyed" then
squadron.state = "destroyed"
log("RED Squadron " .. squadron.displayName .. " at " .. squadron.airbaseName .. " airbase destroyed or not found")
end
end
end
-- Update BLUE squadrons
for _, squadron in pairs(BLUE_SQUADRON_CONFIG) do
local airbase = AIRBASE:FindByName(squadron.airbaseName)
if airbase and airbase:IsAlive() then
local airbaseCoalition = airbase:GetCoalition()
if airbaseCoalition == coalition.side.BLUE then
-- Only update to operational if not already operational (avoid spam)
if squadron.state ~= "operational" then
squadron.state = "operational"
log("BLUE Squadron " .. squadron.displayName .. " at " .. squadron.airbaseName .. " is now operational")
end
else
-- Airbase captured
if squadron.state ~= "captured" then
squadron.state = "captured"
log("BLUE Squadron " .. squadron.displayName .. " at " .. squadron.airbaseName .. " has been captured by enemy")
end
end
else
-- Airbase destroyed or not found
if squadron.state ~= "destroyed" then
squadron.state = "destroyed"
log("BLUE Squadron " .. squadron.displayName .. " at " .. squadron.airbaseName .. " airbase destroyed or not found")
end
end
end
end
-- System initialization
local function initializeSystem()
log("Universal Dual-Coalition TADC starting...")
@ -1962,6 +2084,15 @@ local function initializeSystem()
return false
end
-- Initialize squadron states
for _, squadron in pairs(RED_SQUADRON_CONFIG) do
squadron.state = "operational"
end
for _, squadron in pairs(BLUE_SQUADRON_CONFIG) do
squadron.state = "operational"
end
log("Squadron states initialized")
-- Log enabled coalitions
local enabledCoalitions = {}
if TADC_SETTINGS.enableRed then
@ -2037,6 +2168,7 @@ local function initializeSystem()
SCHEDULER:New(nil, detectThreats, {}, 5, TADC_SETTINGS.checkInterval)
SCHEDULER:New(nil, monitorInterceptors, {}, 10, TADC_SETTINGS.monitorInterval)
SCHEDULER:New(nil, checkAirbaseStatus, {}, 30, TADC_SETTINGS.statusReportInterval)
SCHEDULER:New(nil, updateSquadronStates, {}, 15, 30) -- Update squadron states every 30 seconds
SCHEDULER:New(nil, cleanupOldDeliveries, {}, 60, 3600) -- Cleanup old delivery records every hour
-- Start periodic squadron summary broadcast

View File

@ -404,8 +404,8 @@ local function dispatchCargo(squadron, coalitionKey)
local destCoalition = destAirbase:GetCoalition()
if destCoalition ~= coalitionSide then
log("WARNING: Destination airbase '" .. destination .. "' is not controlled by " .. coalitionKey .. " coalition (currently coalition " .. tostring(destCoalition) .. "). This will cause RAT to fail with 'Airbase doesn't exist' error. Skipping dispatch.")
announceToCoalition(coalitionKey, "Resupply mission to " .. destination .. " aborted (airbase captured by enemy)!")
log("INFO: Destination airbase '" .. destination .. "' captured by enemy - cargo dispatch skipped (normal mission state).", true)
-- No announcement to coalition - this is expected behavior when base is captured
-- Mark mission as failed and cleanup immediately
mission.status = "failed"
return
@ -423,10 +423,8 @@ local function dispatchCargo(squadron, coalitionKey)
local originCoalition = originAirbase:GetCoalition()
if originCoalition ~= coalitionSide then
log("WARNING: Origin airbase '" .. origin .. "' is not controlled by " .. coalitionKey .. " coalition (currently coalition " .. tostring(originCoalition) .. "). This will cause RAT to fail. Skipping dispatch.")
announceToCoalition(coalitionKey, "Resupply mission from " .. origin .. " failed (origin airbase captured by enemy)!")
-- Mark mission as failed and cleanup immediately
mission.status = "failed"
log("INFO: Origin airbase '" .. origin .. "' captured by enemy - trying another supply source.", true)
-- Don't announce or mark as failed - the dispatcher will try another origin
return
end
@ -581,12 +579,17 @@ end
--------------------------------------------------------------------------
Checks all squadrons for each coalition. If a squadron is below the resupply threshold and has no active cargo mission,
triggers a supply request and dispatches a cargo aircraft.
Skips squadrons that are captured or not operational.
]]
local function monitorSquadrons()
for _, coalitionKey in ipairs({"red", "blue"}) do
local config = CARGO_SUPPLY_CONFIG[coalitionKey]
local squadrons = (coalitionKey == "red") and RED_SQUADRON_CONFIG or BLUE_SQUADRON_CONFIG
for _, squadron in ipairs(squadrons) do
-- Skip non-operational squadrons (captured, destroyed, etc.)
if squadron.state and squadron.state ~= "operational" then
log("Squadron " .. squadron.displayName .. " (" .. coalitionKey .. ") is " .. squadron.state .. " - skipping cargo dispatch", true)
else
local current, max, ratio = getSquadronStatus(squadron, coalitionKey)
log("Squadron status: " .. squadron.displayName .. " (" .. coalitionKey .. ") " .. current .. "/" .. max .. " ratio: " .. string.format("%.2f", ratio))
if ratio <= config.threshold and not hasActiveCargoMission(coalitionKey, squadron.airbaseName) then
@ -597,6 +600,7 @@ local function monitorSquadrons()
end
end
end
end
--[[
monitorCargoMissions()

View File

@ -319,7 +319,11 @@ end
-- Squadron resource summary generator
local function getSquadronResourceSummary(coalitionSide)
local function getStatus(remaining, max)
local function getStatus(remaining, max, state)
if state == "captured" then return "[CAPTURED]" end
if state == "destroyed" then return "[DESTROYED]" end
if state ~= "operational" then return "[OFFLINE]" end
local percent = (remaining / max) * 100
if percent <= 10 then return "[CRITICAL]" end
if percent <= 25 then return "[LOW]" end
@ -336,19 +340,21 @@ local function getSquadronResourceSummary(coalitionSide)
for _, squadron in pairs(RED_SQUADRON_CONFIG) do
local remaining = squadronAircraftCounts.red[squadron.templateName] or 0
local max = squadron.aircraft or 0
local status = getStatus(remaining, max)
local state = squadron.state or "operational"
local status = getStatus(remaining, max, state)
table.insert(lines, string.format("| %-13s | %2d / %-15d | %-11s |", squadron.displayName or squadron.templateName, remaining, max, status))
end
elseif coalitionSide == coalition.side.BLUE then
for _, squadron in pairs(BLUE_SQUADRON_CONFIG) do
local remaining = squadronAircraftCounts.blue[squadron.templateName] or 0
local max = squadron.aircraft or 0
local status = getStatus(remaining, max)
local state = squadron.state or "operational"
local status = getStatus(remaining, max, state)
table.insert(lines, string.format("| %-13s | %2d / %-15d | %-11s |", squadron.displayName or squadron.templateName, remaining, max, status))
end
end
table.insert(lines, "\n- [LOW]: Below 25%\n- [CRITICAL]: Below 10%\n- OK: Above 25%")
table.insert(lines, "\n- [CAPTURED]: Airbase captured by enemy\n- [LOW]: Below 25%\n- [CRITICAL]: Below 10%\n- OK: Above 25%")
return table.concat(lines, "\n")
end
@ -1404,8 +1410,20 @@ local function findBestSquadron(threatCoord, threatSize, coalitionSide)
local squadronAvailable = true
local unavailableReason = ""
-- Check squadron state first
if squadron.state and squadron.state ~= "operational" then
squadronAvailable = false
if squadron.state == "captured" then
unavailableReason = "airbase captured by enemy"
elseif squadron.state == "destroyed" then
unavailableReason = "airbase destroyed"
else
unavailableReason = "squadron not operational (state: " .. tostring(squadron.state) .. ")"
end
end
-- Check cooldown
if squadronCooldowns[coalitionKey][squadron.templateName] then
if squadronAvailable and squadronCooldowns[coalitionKey][squadron.templateName] then
local cooldownEnd = squadronCooldowns[coalitionKey][squadron.templateName]
if currentTime < cooldownEnd then
local timeLeft = math.ceil((cooldownEnd - currentTime) / 60)
@ -1808,12 +1826,36 @@ local function checkAirbaseStatus()
if TADC_SETTINGS.enableRed then
log("=== RED COALITION STATUS ===")
for _, squadron in pairs(RED_SQUADRON_CONFIG) do
local usable, status = isAirbaseUsable(squadron.airbaseName, coalition.side.RED)
-- Add aircraft count to status
local airbase = AIRBASE:FindByName(squadron.airbaseName)
local aircraftCount = squadronAircraftCounts.red[squadron.templateName] or 0
local maxAircraft = squadron.aircraft
local aircraftStatus = " Aircraft: " .. aircraftCount .. "/" .. maxAircraft
-- Determine status based on squadron state
local statusPrefix = ""
local statusText = ""
local usable = false
if squadron.state == "operational" then
statusPrefix = ""
statusText = "Operational: " .. aircraftCount .. "/" .. maxAircraft .. " aircraft"
usable = true
elseif squadron.state == "captured" then
-- Determine who captured it
local capturedBy = "enemy"
if airbase and airbase:IsAlive() then
local airbaseCoalition = airbase:GetCoalition()
if airbaseCoalition == coalition.side.BLUE then
capturedBy = "Blue"
elseif airbaseCoalition == coalition.side.NEUTRAL then
capturedBy = "neutral forces"
end
end
statusText = "Captured by " .. capturedBy .. ": " .. aircraftCount .. "/" .. maxAircraft .. " aircraft"
elseif squadron.state == "destroyed" then
statusText = "Destroyed: " .. aircraftCount .. "/" .. maxAircraft .. " aircraft"
else
statusText = "Unknown state: " .. aircraftCount .. "/" .. maxAircraft .. " aircraft"
end
-- Add zone information if configured
local zoneStatus = ""
@ -1825,9 +1867,9 @@ local function checkAirbaseStatus()
zoneStatus = " Zones: " .. table.concat(zones, " ")
end
-- Check if squadron is on cooldown
-- Check if squadron is on cooldown (only show for operational squadrons)
local cooldownStatus = ""
if squadronCooldowns.red[squadron.templateName] then
if squadron.state == "operational" and squadronCooldowns.red[squadron.templateName] then
local cooldownEnd = squadronCooldowns.red[squadron.templateName]
if currentTime < cooldownEnd then
local timeLeft = math.ceil((cooldownEnd - currentTime) / 60)
@ -1835,14 +1877,13 @@ local function checkAirbaseStatus()
end
end
local fullStatus = status .. aircraftStatus .. zoneStatus .. cooldownStatus
local fullStatus = statusText .. zoneStatus .. cooldownStatus
if usable and cooldownStatus == "" and aircraftCount > 0 then
redUsableCount = redUsableCount + 1
log("" .. squadron.airbaseName .. " - " .. fullStatus)
else
log("" .. squadron.airbaseName .. " - " .. fullStatus)
end
log(statusPrefix .. " " .. squadron.airbaseName .. " - " .. fullStatus)
end
log("RED Status: " .. redUsableCount .. "/" .. #RED_SQUADRON_CONFIG .. " airbases operational")
end
@ -1851,12 +1892,36 @@ local function checkAirbaseStatus()
if TADC_SETTINGS.enableBlue then
log("=== BLUE COALITION STATUS ===")
for _, squadron in pairs(BLUE_SQUADRON_CONFIG) do
local usable, status = isAirbaseUsable(squadron.airbaseName, coalition.side.BLUE)
-- Add aircraft count to status
local airbase = AIRBASE:FindByName(squadron.airbaseName)
local aircraftCount = squadronAircraftCounts.blue[squadron.templateName] or 0
local maxAircraft = squadron.aircraft
local aircraftStatus = " Aircraft: " .. aircraftCount .. "/" .. maxAircraft
-- Determine status based on squadron state
local statusPrefix = ""
local statusText = ""
local usable = false
if squadron.state == "operational" then
statusPrefix = ""
statusText = "Operational: " .. aircraftCount .. "/" .. maxAircraft .. " aircraft"
usable = true
elseif squadron.state == "captured" then
-- Determine who captured it
local capturedBy = "enemy"
if airbase and airbase:IsAlive() then
local airbaseCoalition = airbase:GetCoalition()
if airbaseCoalition == coalition.side.RED then
capturedBy = "Red"
elseif airbaseCoalition == coalition.side.NEUTRAL then
capturedBy = "neutral forces"
end
end
statusText = "Captured by " .. capturedBy .. ": " .. aircraftCount .. "/" .. maxAircraft .. " aircraft"
elseif squadron.state == "destroyed" then
statusText = "Destroyed: " .. aircraftCount .. "/" .. maxAircraft .. " aircraft"
else
statusText = "Unknown state: " .. aircraftCount .. "/" .. maxAircraft .. " aircraft"
end
-- Add zone information if configured
local zoneStatus = ""
@ -1868,9 +1933,9 @@ local function checkAirbaseStatus()
zoneStatus = " Zones: " .. table.concat(zones, " ")
end
-- Check if squadron is on cooldown
-- Check if squadron is on cooldown (only show for operational squadrons)
local cooldownStatus = ""
if squadronCooldowns.blue[squadron.templateName] then
if squadron.state == "operational" and squadronCooldowns.blue[squadron.templateName] then
local cooldownEnd = squadronCooldowns.blue[squadron.templateName]
if currentTime < cooldownEnd then
local timeLeft = math.ceil((cooldownEnd - currentTime) / 60)
@ -1878,13 +1943,13 @@ local function checkAirbaseStatus()
end
end
local fullStatus = status .. aircraftStatus .. zoneStatus .. cooldownStatus
local fullStatus = statusText .. zoneStatus .. cooldownStatus
if usable and cooldownStatus == "" and aircraftCount > 0 then
blueUsableCount = blueUsableCount + 1
log("" .. squadron.airbaseName .. " - " .. fullStatus)
else
log(" " .. squadron.airbaseName .. " - " .. fullStatus)
end
log(statusPrefix .. " " .. squadron.airbaseName .. " - " .. fullStatus)
end
end
log("BLUE Status: " .. blueUsableCount .. "/" .. #BLUE_SQUADRON_CONFIG .. " airbases operational")
@ -1911,6 +1976,63 @@ local function cleanupOldDeliveries()
end
end
-- Update squadron states based on airbase coalition control
local function updateSquadronStates()
-- Update RED squadrons
for _, squadron in pairs(RED_SQUADRON_CONFIG) do
local airbase = AIRBASE:FindByName(squadron.airbaseName)
if airbase and airbase:IsAlive() then
local airbaseCoalition = airbase:GetCoalition()
if airbaseCoalition == coalition.side.RED then
-- Only update to operational if not already operational (avoid spam)
if squadron.state ~= "operational" then
squadron.state = "operational"
log("RED Squadron " .. squadron.displayName .. " at " .. squadron.airbaseName .. " is now operational")
end
else
-- Airbase captured
if squadron.state ~= "captured" then
squadron.state = "captured"
log("RED Squadron " .. squadron.displayName .. " at " .. squadron.airbaseName .. " has been captured by enemy")
end
end
else
-- Airbase destroyed or not found
if squadron.state ~= "destroyed" then
squadron.state = "destroyed"
log("RED Squadron " .. squadron.displayName .. " at " .. squadron.airbaseName .. " airbase destroyed or not found")
end
end
end
-- Update BLUE squadrons
for _, squadron in pairs(BLUE_SQUADRON_CONFIG) do
local airbase = AIRBASE:FindByName(squadron.airbaseName)
if airbase and airbase:IsAlive() then
local airbaseCoalition = airbase:GetCoalition()
if airbaseCoalition == coalition.side.BLUE then
-- Only update to operational if not already operational (avoid spam)
if squadron.state ~= "operational" then
squadron.state = "operational"
log("BLUE Squadron " .. squadron.displayName .. " at " .. squadron.airbaseName .. " is now operational")
end
else
-- Airbase captured
if squadron.state ~= "captured" then
squadron.state = "captured"
log("BLUE Squadron " .. squadron.displayName .. " at " .. squadron.airbaseName .. " has been captured by enemy")
end
end
else
-- Airbase destroyed or not found
if squadron.state ~= "destroyed" then
squadron.state = "destroyed"
log("BLUE Squadron " .. squadron.displayName .. " at " .. squadron.airbaseName .. " airbase destroyed or not found")
end
end
end
end
-- System initialization
local function initializeSystem()
log("Universal Dual-Coalition TADC starting...")
@ -1962,6 +2084,15 @@ local function initializeSystem()
return false
end
-- Initialize squadron states
for _, squadron in pairs(RED_SQUADRON_CONFIG) do
squadron.state = "operational"
end
for _, squadron in pairs(BLUE_SQUADRON_CONFIG) do
squadron.state = "operational"
end
log("Squadron states initialized")
-- Log enabled coalitions
local enabledCoalitions = {}
if TADC_SETTINGS.enableRed then
@ -2037,6 +2168,7 @@ local function initializeSystem()
SCHEDULER:New(nil, detectThreats, {}, 5, TADC_SETTINGS.checkInterval)
SCHEDULER:New(nil, monitorInterceptors, {}, 10, TADC_SETTINGS.monitorInterval)
SCHEDULER:New(nil, checkAirbaseStatus, {}, 30, TADC_SETTINGS.statusReportInterval)
SCHEDULER:New(nil, updateSquadronStates, {}, 15, 30) -- Update squadron states every 30 seconds
SCHEDULER:New(nil, cleanupOldDeliveries, {}, 60, 3600) -- Cleanup old delivery records every hour
-- Start periodic squadron summary broadcast

Binary file not shown.