First 1.0 release of TADC

This commit is contained in:
iTracerFacer 2025-10-15 15:03:05 -05:00
parent b267cb1f70
commit 38a79238c5
5 changed files with 2171 additions and 66 deletions

Binary file not shown.

View File

@ -0,0 +1,194 @@
-- ================================================================
-- UNIVERSAL MOOSE SPAWNER UTILITY MENU
-- ================================================================
-- Allows spawning any group template (fighter, cargo, etc.) at any airbase
-- for either coalition, with options for cold/hot/runway start.
-- Includes cleanup and status commands.
-- ================================================================
-- List of available airbases (Caucasus map, add/remove as needed)
local AIRBASES = {
"Kutaisi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler",
"Krymsk", "Anapa-Vityazevo", "Krasnodar-Pashkovsky", "Mineralnye Vody",
"Nalchik", "Mozdok", "Beslan"
}
-- List of example templates (add your own as needed)
local TEMPLATES = {
"CARGO", "CARGO_RU", "Kutaisi CAP", "Sukhumi CAP", "Batumi CAP", "Gudauta CAP"
-- Add more fighter/cargo templates here
}
-- Coalition options
local COALITIONS = {
{name = "Blue", side = coalition.side.BLUE},
{name = "Red", side = coalition.side.RED}
}
-- Start types
local START_TYPES = {
{name = "Cold Start", value = SPAWN.Takeoff.Cold},
{name = "Hot Start", value = SPAWN.Takeoff.Hot},
{name = "Runway", value = SPAWN.Takeoff.Runway}
}
-- Track spawned groups for cleanup
local spawnedGroups = {}
-- Utility: Add group to cleanup tracking
local function TrackGroup(group)
if group and group:IsAlive() then
table.insert(spawnedGroups, group)
end
end
-- Utility: Cleanup all spawned groups
local function CleanupAll()
local cleaned = 0
for _, group in ipairs(spawnedGroups) do
if group and group:IsAlive() then
group:Destroy()
cleaned = cleaned + 1
end
end
spawnedGroups = {}
MESSAGE:New("Cleaned up " .. cleaned .. " spawned groups", 10):ToAll()
end
-- Utility: Show status of spawned groups
local function ShowStatus()
local alive = 0
for _, group in ipairs(spawnedGroups) do
if group and group:IsAlive() then alive = alive + 1 end
end
MESSAGE:New("Spawner Status:\nAlive groups: " .. alive .. "\nTotal spawned: " .. #spawnedGroups, 15):ToAll()
end
-- Main menu
local MenuRoot = MENU_MISSION:New("Universal Spawner")
-- Submenus for coalition
local MenuBlue = MENU_MISSION:New("Spawn for BLUE", MenuRoot)
local MenuRed = MENU_MISSION:New("Spawn for RED", MenuRoot)
-- For each coalition, create template/airbase/start type menus
for _, coalitionData in ipairs(COALITIONS) do
local menuCoalition = (coalitionData.side == coalition.side.BLUE) and MenuBlue or MenuRed
for _, templateName in ipairs(TEMPLATES) do
local menuTemplate = MENU_MISSION:New("Template: " .. templateName, menuCoalition)
for _, airbaseName in ipairs(AIRBASES) do
local menuAirbase = MENU_MISSION:New("Airbase: " .. airbaseName, menuTemplate)
for _, startType in ipairs(START_TYPES) do
local menuStartType = MENU_MISSION:New(startType.name, menuAirbase)
for numToSpawn = 1, 5 do
MENU_MISSION_COMMAND:New(
"Spawn " .. numToSpawn,
menuStartType,
function()
local airbase = AIRBASE:FindByName(airbaseName)
if not airbase then
MESSAGE:New("Airbase not found: " .. airbaseName, 10):ToAll()
return
end
local spawnObj = SPAWN:New(templateName)
spawnObj:InitLimit(10, 20)
local spawned = 0
for i = 1, numToSpawn do
local group = spawnObj:SpawnAtAirbase(airbase, startType.value)
if group then
TrackGroup(group)
spawned = spawned + 1
end
end
if spawned > 0 then
MESSAGE:New("Spawned " .. spawned .. " '" .. templateName .. "' at " .. airbaseName .. " (" .. startType.name .. ")", 10):ToAll()
else
MESSAGE:New("Failed to spawn '" .. templateName .. "' at " .. airbaseName, 10):ToAll()
end
end
)
end
end
end
end
end
-- Quick spawn (first template, first airbase, cold start)
MENU_MISSION_COMMAND:New(
"Quick Spawn (" .. TEMPLATES[1] .. ")",
MenuRoot,
function()
local airbase = AIRBASE:FindByName(AIRBASES[1])
local spawnObj = SPAWN:New(TEMPLATES[1])
spawnObj:InitLimit(10, 20)
local spawned = 0
for i = 1, 1 do
local group = spawnObj:SpawnAtAirbase(airbase, SPAWN.Takeoff.Cold)
if group then
TrackGroup(group)
spawned = spawned + 1
end
end
if spawned > 0 then
MESSAGE:New("Quick spawned '" .. TEMPLATES[1] .. "' at " .. AIRBASES[1], 10):ToAll()
else
MESSAGE:New("Failed to quick spawn '" .. TEMPLATES[1] .. "' at " .. AIRBASES[1], 10):ToAll()
end
end
)
-- Status and cleanup commands
MENU_MISSION_COMMAND:New("Show Spawner Status", MenuRoot, ShowStatus)
MENU_MISSION_COMMAND:New("Cleanup All Spawned Groups", MenuRoot, CleanupAll)
-- ================================================================
-- CONFIGURATION
-- ================================================================
-- Menu configuration
local MENU_CONFIG = {
rootMenuText = "CARGO OPERATIONS",
coalitionSide = coalition.side.BLUE, -- Change to RED if needed
debugMode = true
}
-- Spawn configuration
local SPAWN_CONFIG = {
templateName = "CARGO", -- Template name in mission editor
maxActive = 3, -- Maximum active aircraft
maxSpawns = 10, -- Maximum total spawns
cleanupTime = 300, -- Cleanup time in seconds (5 minutes)
spawnAirbase = "Kutaisi", -- Default spawn airbase
takeoffType = SPAWN.Takeoff.Cold -- Cold start by default
}
-- Available airbases for spawning (Caucasus map)
local AVAILABLE_AIRBASES = {
"Kutaisi",
"Senaki-Kolkhi",
"Sukhumi-Babushara",
"Gudauta",
"Sochi-Adler",
"Krymsk",
"Anapa-Vityazevo",
"Krasnodar-Pashkovsky",
"Mineralnye Vody",
"Nalchik",
"Mozdok",
"Beslan"
}
-- ================================================================
-- GLOBAL VARIABLES
-- ================================================================
-- Spawn object
local CargoSpawn = nil
-- Menu objects
local MenuRoot = nil
local MenuSpawn = nil

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -246,9 +246,9 @@ local RED_SQUADRON_CONFIG = {
-- ADD YOUR RED SQUADRONS HERE
{
templateName = "RED_CAP_SQUADRON_1", -- Change to your RED template name
displayName = "RED Squadron 1", -- Change to your preferred name
airbaseName = "YOUR_RED_AIRBASE_1", -- Change to your RED airbase
templateName = "Sukhumi CAP", -- Change to your RED template name
displayName = "Sukhumi CAP", -- Change to your preferred name
airbaseName = "Sukhumi-Babushara", -- Change to your RED airbase
aircraft = 12, -- Adjust aircraft count
skill = AI.Skill.GOOD, -- AVERAGE, GOOD, HIGH, EXCELLENT
altitude = 20000, -- Patrol altitude (feet)
@ -257,7 +257,7 @@ local RED_SQUADRON_CONFIG = {
type = "FIGHTER",
-- Zone-based Areas of Responsibility (optional - leave nil for global response)
primaryZone = nil, -- Main responsibility area (zone name from mission editor)
primaryZone = "RED_BORDER", -- Main responsibility area (zone name from mission editor)
secondaryZone = nil, -- Secondary coverage area (zone name)
tertiaryZone = nil, -- Emergency/fallback zone (zone name)
@ -273,33 +273,7 @@ local RED_SQUADRON_CONFIG = {
}
},
{
templateName = "RED_CAP_SQUADRON_2", -- Change to your RED template name
displayName = "RED Squadron 2", -- Change to your preferred name
airbaseName = "YOUR_RED_AIRBASE_2", -- Change to your RED airbase
aircraft = 16, -- Adjust aircraft count
skill = AI.Skill.GOOD, -- AVERAGE, GOOD, HIGH, EXCELLENT
altitude = 25000, -- Patrol altitude (feet)
speed = 400, -- Patrol speed (knots)
patrolTime = 30, -- Time on station (minutes)
type = "FIGHTER",
-- Zone-based Areas of Responsibility (optional - leave nil for global response)
primaryZone = nil, -- Main responsibility area (zone name from mission editor)
secondaryZone = nil, -- Secondary coverage area (zone name)
tertiaryZone = nil, -- Emergency/fallback zone (zone name)
-- Zone behavior settings (optional - uses defaults if not specified)
zoneConfig = {
primaryResponse = 1.0, -- Intercept ratio multiplier in primary zone
secondaryResponse = 0.6, -- Intercept ratio multiplier in secondary zone
tertiaryResponse = 1.4, -- Intercept ratio multiplier in tertiary zone
maxRange = 200, -- Maximum engagement range from airbase (nm)
enableFallback = false, -- Auto-switch to tertiary when base threatened
priorityThreshold = 4, -- Min aircraft count for "major threat"
ignoreLowPriority = false, -- Ignore threats below threshold in secondary zones
}
},
}
-- ═══════════════════════════════════════════════════════════════════════════
@ -322,38 +296,11 @@ local BLUE_SQUADRON_CONFIG = {
]]
-- ADD YOUR BLUE SQUADRONS HERE
{
templateName = "BLUE_CAP_SQUADRON_1", -- Change to your BLUE template name
displayName = "BLUE Squadron 1", -- Change to your preferred name
airbaseName = "YOUR_BLUE_AIRBASE_1", -- Change to your BLUE airbase
aircraft = 14, -- Adjust aircraft count
skill = AI.Skill.GOOD, -- AVERAGE, GOOD, HIGH, EXCELLENT
altitude = 22000, -- Patrol altitude (feet)
speed = 380, -- Patrol speed (knots)
patrolTime = 28, -- Time on station (minutes)
type = "FIGHTER",
-- Zone-based Areas of Responsibility (optional - leave nil for global response)
primaryZone = nil, -- Main responsibility area (zone name from mission editor)
secondaryZone = nil, -- Secondary coverage area (zone name)
tertiaryZone = nil, -- Emergency/fallback zone (zone name)
-- Zone behavior settings (optional - uses defaults if not specified)
zoneConfig = {
primaryResponse = 1.0, -- Intercept ratio multiplier in primary zone
secondaryResponse = 0.6, -- Intercept ratio multiplier in secondary zone
tertiaryResponse = 1.4, -- Intercept ratio multiplier in tertiary zone
maxRange = 200, -- Maximum engagement range from airbase (nm)
enableFallback = false, -- Auto-switch to tertiary when base threatened
priorityThreshold = 4, -- Min aircraft count for "major threat"
ignoreLowPriority = false, -- Ignore threats below threshold in secondary zones
}
},
{
templateName = "BLUE_CAP_SQUADRON_2", -- Change to your BLUE template name
displayName = "BLUE Squadron 2", -- Change to your preferred name
airbaseName = "YOUR_BLUE_AIRBASE_2", -- Change to your BLUE airbase
templateName = "Kutaisi CAP", -- Change to your BLUE template name
displayName = "Kutaisi CAP", -- Change to your preferred name
airbaseName = "Kutaisi", -- Change to your BLUE airbase
aircraft = 18, -- Adjust aircraft count
skill = AI.Skill.EXCELLENT, -- AVERAGE, GOOD, HIGH, EXCELLENT
altitude = 18000, -- Patrol altitude (feet)
@ -362,7 +309,7 @@ local BLUE_SQUADRON_CONFIG = {
type = "FIGHTER",
-- Zone-based Areas of Responsibility (optional - leave nil for global response)
primaryZone = nil, -- Main responsibility area (zone name from mission editor)
primaryZone = "BLUE_BORDER", -- Main responsibility area (zone name from mission editor)
secondaryZone = nil, -- Secondary coverage area (zone name)
tertiaryZone = nil, -- Emergency/fallback zone (zone name)
@ -496,7 +443,22 @@ local function isInZone(coordinate, zoneName)
if zone then
return zone:IsCoordinateInZone(coordinate)
else
log("Warning: Zone '" .. zoneName .. "' not found in mission", true)
-- Try to create polygon zone from helicopter group waypoints if not found
local group = GROUP:FindByName(zoneName)
if group then
-- Create polygon zone using the group's waypoints as vertices
zone = ZONE_POLYGON:NewFromGroupName(zoneName, zoneName)
if zone then
log("Created polygon zone '" .. zoneName .. "' from helicopter waypoints")
return zone:IsCoordinateInZone(coordinate)
else
log("Warning: Could not create polygon zone from group '" .. zoneName .. "' - check waypoints")
end
else
log("Warning: No group named '" .. zoneName .. "' found for zone creation")
end
log("Warning: Zone '" .. zoneName .. "' not found in mission and could not create from helicopter group", true)
return false
end
end
@ -643,7 +605,12 @@ local function validateConfiguration()
for _, zoneName in ipairs(zones) do
local zoneObj = ZONE:FindByName(zoneName)
if not zoneObj then
table.insert(errors, prefix .. "zone '" .. zoneName .. "' not found in mission")
-- Check if there's a helicopter unit/group with this name for zone creation
local unit = UNIT:FindByName(zoneName)
local group = GROUP:FindByName(zoneName)
if not unit and not group then
table.insert(errors, prefix .. "zone '" .. zoneName .. "' not found in mission (no zone or helicopter unit named '" .. zoneName .. "')")
end
end
end
end
@ -705,7 +672,12 @@ local function validateConfiguration()
for _, zoneName in ipairs(zones) do
local zoneObj = ZONE:FindByName(zoneName)
if not zoneObj then
table.insert(errors, prefix .. "zone '" .. zoneName .. "' not found in mission")
-- Check if there's a helicopter unit/group with this name for zone creation
local unit = UNIT:FindByName(zoneName)
local group = GROUP:FindByName(zoneName)
if not unit and not group then
table.insert(errors, prefix .. "zone '" .. zoneName .. "' not found in mission (no zone or helicopter unit named '" .. zoneName .. "')")
end
end
end
end
@ -1476,6 +1448,47 @@ end
local function initializeSystem()
log("Universal Dual-Coalition TADC starting...")
-- Create zones from late-activated helicopter units (MOOSE method)
-- This allows using helicopters named "RED_BORDER", "BLUE_BORDER" etc. as zone markers
-- Uses the helicopter's waypoints as polygon vertices (standard MOOSE method)
local function createZoneFromUnit(unitName)
-- Try to find as a group first (this is the standard MOOSE way)
local group = GROUP:FindByName(unitName)
if group then
-- Create polygon zone using the group's waypoints as vertices
local zone = ZONE_POLYGON:NewFromGroupName(unitName, unitName)
if zone then
log("Created polygon zone '" .. unitName .. "' from helicopter waypoints")
return zone
else
log("Warning: Could not create polygon zone from group '" .. unitName .. "' - check waypoints")
end
else
log("Warning: No group named '" .. unitName .. "' found for zone creation")
end
return nil
end
-- Try to create zones for all configured zone names
local zoneNames = {}
for _, squadron in pairs(RED_SQUADRON_CONFIG) do
if squadron.primaryZone then table.insert(zoneNames, squadron.primaryZone) end
if squadron.secondaryZone then table.insert(zoneNames, squadron.secondaryZone) end
if squadron.tertiaryZone then table.insert(zoneNames, squadron.tertiaryZone) end
end
for _, squadron in pairs(BLUE_SQUADRON_CONFIG) do
if squadron.primaryZone then table.insert(zoneNames, squadron.primaryZone) end
if squadron.secondaryZone then table.insert(zoneNames, squadron.secondaryZone) end
if squadron.tertiaryZone then table.insert(zoneNames, squadron.tertiaryZone) end
end
-- Create zones from helicopters
for _, zoneName in ipairs(zoneNames) do
if not ZONE:FindByName(zoneName) then
createZoneFromUnit(zoneName)
end
end
-- Validate configuration
if not validateConfiguration() then
log("System startup aborted due to configuration errors!")