mirror of
https://github.com/iTracerFacer/DCS_MissionDev.git
synced 2025-12-03 04:14:46 +00:00
Updated to support automated external cargo dispatcher.
This commit is contained in:
@@ -50,17 +50,18 @@ Zone response behaviors include:
|
|||||||
|
|
||||||
REPLENISHMENT SYSTEM:
|
REPLENISHMENT SYSTEM:
|
||||||
• Automated cargo aircraft detection system that monitors for transport aircraft
|
• Automated cargo aircraft detection system that monitors for transport aircraft
|
||||||
landings to replenish squadron aircraft counts (fixed wing only):
|
flyovers to replenish squadron aircraft counts (fixed wing only):
|
||||||
• Detects cargo aircraft by name patterns (CARGO, TRANSPORT, C130, C-130, AN26, AN-26)
|
• Detects cargo aircraft by name patterns (CARGO, TRANSPORT, C130, C-130, AN26, AN-26)
|
||||||
• Monitors landing status based on velocity and proximity to friendly airbases
|
• Monitors flyover proximity to friendly airbases (no landing required)
|
||||||
• Replenishes squadron aircraft up to maximum capacity per airbase
|
• Replenishes squadron aircraft up to maximum capacity per airbase
|
||||||
• Prevents duplicate processing of the same cargo delivery
|
• Prevents duplicate processing of the same cargo delivery
|
||||||
• Coalition-specific replenishment amounts configurable independently
|
• Coalition-specific replenishment amounts configurable independently
|
||||||
• Supports sustained operations over extended mission duration
|
• Supports sustained operations over extended mission duration
|
||||||
|
|
||||||
*** This system does not spawn or manage cargo aircraft - it only detects when
|
*** This system does not spawn or manage cargo aircraft - it only detects when
|
||||||
your existing cargo aircraft complete deliveries. Create and route your own
|
your existing cargo aircraft complete deliveries via flyover. Create and route your own
|
||||||
transport missions to maintain squadron strength. ***
|
transport missions to maintain squadron strength. Aircraft can deliver supplies by
|
||||||
|
flying within 3000m of any configured airbase without needing to land. ***
|
||||||
|
|
||||||
INTERCEPT RATIO SYSTEM:
|
INTERCEPT RATIO SYSTEM:
|
||||||
Sophisticated threat response calculation with zone-based modifiers:
|
Sophisticated threat response calculation with zone-based modifiers:
|
||||||
@@ -211,7 +212,8 @@ local ADVANCED_SETTINGS = {
|
|||||||
-- Cargo aircraft detection patterns (aircraft with these names will replenish squadrons (Currently only fixed wing aircraft supported))
|
-- Cargo aircraft detection patterns (aircraft with these names will replenish squadrons (Currently only fixed wing aircraft supported))
|
||||||
cargoPatterns = {"CARGO", "TRANSPORT", "C130", "C-130", "AN26", "AN-26"},
|
cargoPatterns = {"CARGO", "TRANSPORT", "C130", "C-130", "AN26", "AN-26"},
|
||||||
|
|
||||||
-- Distance from airbase to consider cargo "landed" (meters)
|
-- Distance from airbase to consider cargo "delivered" via flyover (meters)
|
||||||
|
-- Aircraft flying within this range will count as supply delivery (no landing required)
|
||||||
cargoLandingDistance = 3000,
|
cargoLandingDistance = 3000,
|
||||||
|
|
||||||
-- Velocity below which aircraft is considered "landed" (km/h)
|
-- Velocity below which aircraft is considered "landed" (km/h)
|
||||||
@@ -252,7 +254,7 @@ local squadronCooldowns = {
|
|||||||
red = {},
|
red = {},
|
||||||
blue = {}
|
blue = {}
|
||||||
}
|
}
|
||||||
local squadronAircraftCounts = {
|
squadronAircraftCounts = {
|
||||||
red = {},
|
red = {},
|
||||||
blue = {}
|
blue = {}
|
||||||
}
|
}
|
||||||
@@ -638,7 +640,95 @@ local function validateConfiguration()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Monitor cargo aircraft landings for squadron replenishment
|
-- Process cargo delivery for a squadron
|
||||||
|
local function processCargoDelivery(cargoGroup, squadron, coalitionSide, coalitionKey)
|
||||||
|
-- Initialize processed deliveries table
|
||||||
|
if not _G.processedDeliveries then
|
||||||
|
_G.processedDeliveries = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create unique delivery key including timestamp to prevent race conditions
|
||||||
|
-- Note: Key doesn't include airbase to prevent double-counting if aircraft moves between airbases
|
||||||
|
local deliveryKey = cargoGroup:GetName() .. "_" .. coalitionKey:upper() .. "_" .. cargoGroup:GetID()
|
||||||
|
|
||||||
|
if not _G.processedDeliveries[deliveryKey] then
|
||||||
|
-- Mark delivery as processed immediately to prevent race conditions
|
||||||
|
_G.processedDeliveries[deliveryKey] = timer.getTime()
|
||||||
|
-- Process replenishment
|
||||||
|
local currentCount = squadronAircraftCounts[coalitionKey][squadron.templateName] or 0
|
||||||
|
local maxCount = squadron.aircraft
|
||||||
|
local newCount = math.min(currentCount + TADC_SETTINGS[coalitionKey].cargoReplenishmentAmount, maxCount)
|
||||||
|
local actualAdded = newCount - currentCount
|
||||||
|
|
||||||
|
if actualAdded > 0 then
|
||||||
|
squadronAircraftCounts[coalitionKey][squadron.templateName] = newCount
|
||||||
|
local msg = coalitionKey:upper() .. " CARGO DELIVERY: " .. cargoGroup:GetName() .. " delivered " .. actualAdded ..
|
||||||
|
" aircraft to " .. squadron.displayName ..
|
||||||
|
" (" .. newCount .. "/" .. maxCount .. ")"
|
||||||
|
log(msg)
|
||||||
|
MESSAGE:New(msg, 20):ToCoalition(coalitionSide)
|
||||||
|
USERSOUND:New("Cargo_Delivered.ogg"):ToCoalition(coalitionSide)
|
||||||
|
-- Notify dispatcher (if available) so it can mark the matching mission completed immediately
|
||||||
|
if type(_G.TDAC_CargoDelivered) == 'function' then
|
||||||
|
pcall(function()
|
||||||
|
_G.TDAC_CargoDelivered(cargoGroup:GetName(), squadron.airbaseName, coalitionKey)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local msg = coalitionKey:upper() .. " CARGO DELIVERY: " .. squadron.displayName .. " already at max capacity"
|
||||||
|
log(msg, true)
|
||||||
|
MESSAGE:New(msg, 15):ToCoalition(coalitionSide)
|
||||||
|
USERSOUND:New("Cargo_Delivered.ogg"):ToCoalition(coalitionSide)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Event handler for cargo aircraft landing (backup for actual landings)
|
||||||
|
local cargoEventHandler = {}
|
||||||
|
function cargoEventHandler:onEvent(event)
|
||||||
|
if event.id == world.event.S_EVENT_LAND then
|
||||||
|
local unit = event.initiator
|
||||||
|
if unit and type(unit) == "table" and unit.IsAlive and unit:IsAlive() then
|
||||||
|
local group = unit:GetGroup()
|
||||||
|
if group and type(group) == "table" and group.IsAlive and group:IsAlive() then
|
||||||
|
local cargoName = group:GetName():upper()
|
||||||
|
local isCargoAircraft = false
|
||||||
|
|
||||||
|
-- Check if aircraft name matches cargo patterns
|
||||||
|
for _, pattern in pairs(ADVANCED_SETTINGS.cargoPatterns) do
|
||||||
|
if string.find(cargoName, pattern) then
|
||||||
|
isCargoAircraft = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if isCargoAircraft then
|
||||||
|
local cargoCoord = unit:GetCoordinate()
|
||||||
|
local coalitionSide = unit:GetCoalition()
|
||||||
|
local coalitionKey = (coalitionSide == coalition.side.RED) and "red" or "blue"
|
||||||
|
|
||||||
|
-- Check which airbase it's near
|
||||||
|
local squadronConfig = getSquadronConfig(coalitionSide)
|
||||||
|
for _, squadron in pairs(squadronConfig) do
|
||||||
|
local airbase = AIRBASE:FindByName(squadron.airbaseName)
|
||||||
|
if airbase and airbase:GetCoalition() == coalitionSide then
|
||||||
|
local airbaseCoord = airbase:GetCoordinate()
|
||||||
|
local distance = cargoCoord:Get2DDistance(airbaseCoord)
|
||||||
|
|
||||||
|
-- If within configured distance of airbase, consider it a landing delivery
|
||||||
|
if distance < ADVANCED_SETTINGS.cargoLandingDistance then
|
||||||
|
log("LANDING DELIVERY: " .. cargoName .. " landed and delivered at " .. squadron.airbaseName .. " (distance: " .. math.floor(distance) .. "m)")
|
||||||
|
processCargoDelivery(group, squadron, coalitionSide, coalitionKey)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Monitor cargo aircraft flyovers for squadron replenishment
|
||||||
local function monitorCargoReplenishment()
|
local function monitorCargoReplenishment()
|
||||||
-- Process RED cargo aircraft
|
-- Process RED cargo aircraft
|
||||||
if TADC_SETTINGS.enableRed then
|
if TADC_SETTINGS.enableRed then
|
||||||
@@ -664,51 +754,24 @@ local function monitorCargoReplenishment()
|
|||||||
if isCargoAircraft then
|
if isCargoAircraft then
|
||||||
local cargoCoord = cargoGroup:GetCoordinate()
|
local cargoCoord = cargoGroup:GetCoordinate()
|
||||||
local cargoVelocity = cargoGroup:GetVelocityKMH()
|
local cargoVelocity = cargoGroup:GetVelocityKMH()
|
||||||
|
-- DEBUG: log candidate details with timestamp for diagnosis
|
||||||
|
if ADVANCED_SETTINGS.enableDetailedLogging then
|
||||||
|
log(string.format("[LOAD2ND DEBUG] Evaluating cargo %s at time=%d vel=%.2f km/h coord=(%.1f,%.1f)",
|
||||||
|
cargoGroup:GetName(), timer.getTime(), cargoVelocity, cargoCoord:GetVec2().x, cargoCoord:GetVec2().y))
|
||||||
|
end
|
||||||
|
|
||||||
-- Consider aircraft "landed" if velocity is very low
|
-- Check for flyover delivery - aircraft within range of airbase (no landing required)
|
||||||
if cargoVelocity < ADVANCED_SETTINGS.cargoLandedVelocity then
|
-- Check which RED airbase it's near
|
||||||
-- Check which RED airbase it's near
|
for _, squadron in pairs(RED_SQUADRON_CONFIG) do
|
||||||
for _, squadron in pairs(RED_SQUADRON_CONFIG) do
|
local airbase = AIRBASE:FindByName(squadron.airbaseName)
|
||||||
local airbase = AIRBASE:FindByName(squadron.airbaseName)
|
if airbase and airbase:GetCoalition() == coalition.side.RED then
|
||||||
if airbase and airbase:GetCoalition() == coalition.side.RED then
|
local airbaseCoord = airbase:GetCoordinate()
|
||||||
local airbaseCoord = airbase:GetCoordinate()
|
local distance = cargoCoord:Get2DDistance(airbaseCoord)
|
||||||
local distance = cargoCoord:Get2DDistance(airbaseCoord)
|
|
||||||
|
|
||||||
-- If within configured distance of airbase, consider it a delivery
|
-- If within configured distance of airbase, consider it a flyover delivery
|
||||||
if distance < ADVANCED_SETTINGS.cargoLandingDistance then
|
if distance < ADVANCED_SETTINGS.cargoLandingDistance then
|
||||||
-- Initialize processed deliveries table
|
log("FLYOVER DELIVERY: " .. cargoName .. " delivered supplies to " .. squadron.airbaseName .. " (distance: " .. math.floor(distance) .. "m, altitude: " .. math.floor(cargoCoord.y/0.3048) .. " ft)")
|
||||||
if not _G.processedDeliveries then
|
processCargoDelivery(cargoGroup, squadron, coalition.side.RED, "red")
|
||||||
_G.processedDeliveries = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Create unique delivery key including timestamp to prevent race conditions
|
|
||||||
local deliveryKey = cargoName .. "_RED_" .. squadron.airbaseName .. "_" .. cargoGroup:GetID()
|
|
||||||
|
|
||||||
if not _G.processedDeliveries[deliveryKey] then
|
|
||||||
-- Mark delivery as processed immediately to prevent race conditions
|
|
||||||
_G.processedDeliveries[deliveryKey] = timer.getTime()
|
|
||||||
-- Process replenishment
|
|
||||||
local currentCount = squadronAircraftCounts.red[squadron.templateName] or 0
|
|
||||||
local maxCount = squadron.aircraft
|
|
||||||
local newCount = math.min(currentCount + TADC_SETTINGS.red.cargoReplenishmentAmount, maxCount)
|
|
||||||
local actualAdded = newCount - currentCount
|
|
||||||
|
|
||||||
if actualAdded > 0 then
|
|
||||||
squadronAircraftCounts.red[squadron.templateName] = newCount
|
|
||||||
local msg = "RED CARGO DELIVERY: " .. cargoName .. " delivered " .. actualAdded ..
|
|
||||||
" aircraft to " .. squadron.displayName ..
|
|
||||||
" (" .. newCount .. "/" .. maxCount .. ")"
|
|
||||||
log(msg)
|
|
||||||
MESSAGE:New(msg, 20):ToCoalition(coalition.side.RED)
|
|
||||||
USERSOUND:New("Cargo_Delivered.ogg"):ToCoalition(coalition.side.RED)
|
|
||||||
else
|
|
||||||
local msg = "RED CARGO DELIVERY: " .. squadron.displayName .. " already at max capacity"
|
|
||||||
log(msg, true)
|
|
||||||
MESSAGE:New(msg, 15):ToCoalition(coalition.side.RED)
|
|
||||||
USERSOUND:New("Cargo_Delivered.ogg"):ToCoalition(coalition.side.RED)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -742,50 +805,18 @@ local function monitorCargoReplenishment()
|
|||||||
local cargoCoord = cargoGroup:GetCoordinate()
|
local cargoCoord = cargoGroup:GetCoordinate()
|
||||||
local cargoVelocity = cargoGroup:GetVelocityKMH()
|
local cargoVelocity = cargoGroup:GetVelocityKMH()
|
||||||
|
|
||||||
-- Consider aircraft "landed" if velocity is very low
|
-- Check for flyover delivery - aircraft within range of airbase (no landing required)
|
||||||
if cargoVelocity < ADVANCED_SETTINGS.cargoLandedVelocity then
|
-- Check which BLUE airbase it's near
|
||||||
-- Check which BLUE airbase it's near
|
for _, squadron in pairs(BLUE_SQUADRON_CONFIG) do
|
||||||
for _, squadron in pairs(BLUE_SQUADRON_CONFIG) do
|
local airbase = AIRBASE:FindByName(squadron.airbaseName)
|
||||||
local airbase = AIRBASE:FindByName(squadron.airbaseName)
|
if airbase and airbase:GetCoalition() == coalition.side.BLUE then
|
||||||
if airbase and airbase:GetCoalition() == coalition.side.BLUE then
|
local airbaseCoord = airbase:GetCoordinate()
|
||||||
local airbaseCoord = airbase:GetCoordinate()
|
local distance = cargoCoord:Get2DDistance(airbaseCoord)
|
||||||
local distance = cargoCoord:Get2DDistance(airbaseCoord)
|
|
||||||
|
|
||||||
-- If within configured distance of airbase, consider it a delivery
|
-- If within configured distance of airbase, consider it a flyover delivery
|
||||||
if distance < ADVANCED_SETTINGS.cargoLandingDistance then
|
if distance < ADVANCED_SETTINGS.cargoLandingDistance then
|
||||||
-- Initialize processed deliveries table
|
log("FLYOVER DELIVERY: " .. cargoName .. " delivered supplies to " .. squadron.airbaseName .. " (distance: " .. math.floor(distance) .. "m, altitude: " .. math.floor(cargoCoord.y/0.3048) .. " ft)")
|
||||||
if not _G.processedDeliveries then
|
processCargoDelivery(cargoGroup, squadron, coalition.side.BLUE, "blue")
|
||||||
_G.processedDeliveries = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Create unique delivery key including timestamp to prevent race conditions
|
|
||||||
local deliveryKey = cargoName .. "_BLUE_" .. squadron.airbaseName .. "_" .. cargoGroup:GetID()
|
|
||||||
|
|
||||||
if not _G.processedDeliveries[deliveryKey] then
|
|
||||||
-- Mark delivery as processed immediately to prevent race conditions
|
|
||||||
_G.processedDeliveries[deliveryKey] = timer.getTime()
|
|
||||||
-- Process replenishment
|
|
||||||
local currentCount = squadronAircraftCounts.blue[squadron.templateName] or 0
|
|
||||||
local maxCount = squadron.aircraft
|
|
||||||
local newCount = math.min(currentCount + TADC_SETTINGS.blue.cargoReplenishmentAmount, maxCount)
|
|
||||||
local actualAdded = newCount - currentCount
|
|
||||||
|
|
||||||
if actualAdded > 0 then
|
|
||||||
squadronAircraftCounts.blue[squadron.templateName] = newCount
|
|
||||||
local msg = "BLUE CARGO DELIVERY: " .. cargoName .. " delivered " .. actualAdded ..
|
|
||||||
" aircraft to " .. squadron.displayName ..
|
|
||||||
" (" .. newCount .. "/" .. maxCount .. ")"
|
|
||||||
log(msg)
|
|
||||||
MESSAGE:New(msg, 20):ToCoalition(coalition.side.BLUE)
|
|
||||||
USERSOUND:New("Cargo_Delivered.ogg"):ToCoalition(coalition.side.BLUE)
|
|
||||||
else
|
|
||||||
local msg = "BLUE CARGO DELIVERY: " .. squadron.displayName .. " already at max capacity"
|
|
||||||
log(msg, true)
|
|
||||||
MESSAGE:New(msg, 15):ToCoalition(coalition.side.BLUE)
|
|
||||||
USERSOUND:New("Cargo_Delivered.ogg"):ToCoalition(coalition.side.BLUE)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1472,6 +1503,9 @@ local function initializeSystem()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Start schedulers
|
-- Start schedulers
|
||||||
|
-- Set up event handler for cargo landing detection
|
||||||
|
world.addEventHandler(cargoEventHandler)
|
||||||
|
|
||||||
SCHEDULER:New(nil, detectThreats, {}, 5, TADC_SETTINGS.checkInterval)
|
SCHEDULER:New(nil, detectThreats, {}, 5, TADC_SETTINGS.checkInterval)
|
||||||
SCHEDULER:New(nil, monitorInterceptors, {}, 10, TADC_SETTINGS.monitorInterval)
|
SCHEDULER:New(nil, monitorInterceptors, {}, 10, TADC_SETTINGS.monitorInterval)
|
||||||
SCHEDULER:New(nil, checkAirbaseStatus, {}, 30, TADC_SETTINGS.statusReportInterval)
|
SCHEDULER:New(nil, checkAirbaseStatus, {}, 30, TADC_SETTINGS.statusReportInterval)
|
||||||
|
|||||||
Reference in New Issue
Block a user