mirror of
https://github.com/iTracerFacer/DCS_MissionDev.git
synced 2025-12-03 04:14:46 +00:00
503 lines
20 KiB
Lua
503 lines
20 KiB
Lua
--[[
|
|
Script: Moose_DynamicGroundBattle_Plugin.lua
|
|
Written by: [F99th-TracerFacer]
|
|
Version: 1.0.0
|
|
Date: 15 November 2024
|
|
Description: Warehouse-driven ground unit spawning system that works as a plugin
|
|
with Moose_DualCoalitionZoneCapture.lua
|
|
|
|
This script handles:
|
|
- Warehouse-based reinforcement system
|
|
- Dynamic spawn frequency based on warehouse survival
|
|
- Automated AI tasking to patrol nearest enemy zones
|
|
- Optional infantry patrol control
|
|
- Warehouse status intel markers
|
|
- CTLD troop integration
|
|
|
|
What this script DOES NOT do:
|
|
- Zone capture logic (handled by Moose_DualCoalitionZoneCapture.lua)
|
|
- Win conditions (handled by Moose_DualCoalitionZoneCapture.lua)
|
|
- Zone coloring/messaging (handled by Moose_DualCoalitionZoneCapture.lua)
|
|
|
|
Load Order (in Mission Editor Triggers):
|
|
1. DO SCRIPT FILE Moose_.lua
|
|
2. DO SCRIPT FILE Moose_DualCoalitionZoneCapture.lua
|
|
3. DO SCRIPT FILE Moose_DynamicGroundBattle_Plugin.lua <-- This file
|
|
4. DO SCRIPT FILE CTLD.lua (optional)
|
|
5. DO SCRIPT FILE CSAR.lua (optional)
|
|
|
|
Requirements:
|
|
- MOOSE framework must be loaded first
|
|
- Moose_DualCoalitionZoneCapture.lua must be loaded BEFORE this script
|
|
- Zone configuration comes from DualCoalitionZoneCapture's ZONE_CONFIG
|
|
- Groups and warehouses must exist in mission editor (see below)
|
|
|
|
Warehouse System & Spawn Frequency Behavior:
|
|
1. Each side has warehouses defined in `redWarehouses` and `blueWarehouses` tables
|
|
2. Spawn frequency dynamically adjusts based on alive warehouses:
|
|
- 100% alive = 100% spawn rate (base frequency)
|
|
- 50% alive = 50% spawn rate (2x delay)
|
|
- 0% alive = no spawns (critical attrition)
|
|
3. Map markers show warehouse locations and nearby units
|
|
4. Updated every UPDATE_MARK_POINTS_SCHED seconds
|
|
|
|
AI Task Assignment:
|
|
- Groups spawn in friendly zones, then patrol toward nearest enemy zone
|
|
- Reassignment occurs every ASSIGN_TASKS_SCHED seconds
|
|
- Only stationary units get new orders (moving units are left alone)
|
|
- CTLD-dropped troops automatically integrate
|
|
|
|
Groups to Create in Mission Editor (all LATE ACTIVATE):
|
|
RED SIDE:
|
|
- Infantry Templates: RedInfantry1, RedInfantry2, RedInfantry3, RedInfantry4, RedInfantry5, RedInfantry6
|
|
- Armor Templates: RedArmor1, RedArmor2, RedArmor3, RedArmor4, RedArmor5, RedArmor6
|
|
- Warehouses (Static Objects): RedWarehouse1-1, RedWarehouse2-1, RedWarehouse3-1, etc.
|
|
|
|
BLUE SIDE:
|
|
- Infantry Templates: BlueInfantry1, BlueInfantry2, BlueInfantry3, BlueInfantry4, BlueInfantry5, BlueInfantry6
|
|
- Armor Templates: BlueArmor1, BlueArmor2, BlueArmor3, BlueArmor4, BlueArmor5
|
|
- Warehouses (Static Objects): BlueWarehouse1-1, BlueWarehouse2-1, BlueWarehouse3-1, etc.
|
|
|
|
NOTE: Warehouse names use the static "Unit Name" in mission editor, not the "Name" field!
|
|
|
|
Integration with DualCoalitionZoneCapture:
|
|
- This script reads zoneCaptureObjects and zoneNames from DualCoalitionZoneCapture
|
|
- Spawns occur in zones controlled by the appropriate coalition
|
|
- AI tasks units to patrol zones from DualCoalitionZoneCapture's ZONE_CONFIG
|
|
--]]
|
|
|
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- USER CONFIGURATION SECTION
|
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
-- Infantry Patrol Settings
|
|
local MOVING_INFANTRY_PATROLS = false -- Set to false to disable infantry movement (they spawn and hold position)
|
|
|
|
-- Warehouse Marker Settings
|
|
local ENABLE_WAREHOUSE_MARKERS = true -- Enable/disable warehouse map markers (disabled by default if you have other marker systems)
|
|
local UPDATE_MARK_POINTS_SCHED = 300 -- Update warehouse markers every 300 seconds (5 minutes)
|
|
local MAX_WAREHOUSE_UNIT_LIST_DISTANCE = 5000 -- Max distance to search for units near warehouses for markers
|
|
|
|
-- Spawn Frequency and Limits
|
|
local INIT_RED_INFANTRY = 5 -- Initial number of Red Infantry groups
|
|
local MAX_RED_INFANTRY = 100 -- Maximum number of Red Infantry groups
|
|
local SPAWN_SCHED_RED_INFANTRY = 1800 -- Base spawn frequency for Red Infantry (seconds)
|
|
|
|
local INIT_RED_ARMOR = 25 -- Initial number of Red Armor groups
|
|
local MAX_RED_ARMOR = 200 -- Maximum number of Red Armor groups
|
|
local SPAWN_SCHED_RED_ARMOR = 300 -- Base spawn frequency for Red Armor (seconds)
|
|
|
|
local INIT_BLUE_INFANTRY = 5 -- Initial number of Blue Infantry groups
|
|
local MAX_BLUE_INFANTRY = 100 -- Maximum number of Blue Infantry groups
|
|
local SPAWN_SCHED_BLUE_INFANTRY = 1800 -- Base spawn frequency for Blue Infantry (seconds)
|
|
|
|
local INIT_BLUE_ARMOR = 25 -- Initial number of Blue Armor groups
|
|
local MAX_BLUE_ARMOR = 200 -- Maximum number of Blue Armor groups
|
|
local SPAWN_SCHED_BLUE_ARMOR = 300 -- Base spawn frequency for Blue Armor (seconds)
|
|
|
|
local ASSIGN_TASKS_SCHED = 600 -- How often to reassign tasks to idle groups (seconds)
|
|
|
|
-- Define warehouses for each side
|
|
local redWarehouses = {
|
|
STATIC:FindByName("RedWarehouse1-1"),
|
|
STATIC:FindByName("RedWarehouse2-1"),
|
|
STATIC:FindByName("RedWarehouse3-1"),
|
|
STATIC:FindByName("RedWarehouse4-1"),
|
|
STATIC:FindByName("RedWarehouse5-1"),
|
|
STATIC:FindByName("RedWarehouse6-1")
|
|
}
|
|
|
|
local blueWarehouses = {
|
|
STATIC:FindByName("BlueWarehouse1-1"),
|
|
STATIC:FindByName("BlueWarehouse2-1"),
|
|
STATIC:FindByName("BlueWarehouse3-1"),
|
|
STATIC:FindByName("BlueWarehouse4-1"),
|
|
STATIC:FindByName("BlueWarehouse5-1"),
|
|
STATIC:FindByName("BlueWarehouse6-1")
|
|
}
|
|
|
|
-- Define unit templates (these groups must exist in mission editor as LATE ACTIVATE)
|
|
local redInfantryTemplates = {
|
|
"RedInfantry1",
|
|
"RedInfantry2",
|
|
"RedInfantry3",
|
|
"RedInfantry4",
|
|
"RedInfantry5",
|
|
"RedInfantry6"
|
|
}
|
|
|
|
local redArmorTemplates = {
|
|
"RedArmor1",
|
|
"RedArmor2",
|
|
"RedArmor3",
|
|
"RedArmor4",
|
|
"RedArmor5",
|
|
"RedArmor6"
|
|
}
|
|
|
|
local blueInfantryTemplates = {
|
|
"BlueInfantry1",
|
|
"BlueInfantry2",
|
|
"BlueInfantry3",
|
|
"BlueInfantry4",
|
|
"BlueInfantry5",
|
|
"BlueInfantry6"
|
|
}
|
|
|
|
local blueArmorTemplates = {
|
|
"BlueArmor1",
|
|
"BlueArmor2",
|
|
"BlueArmor3",
|
|
"BlueArmor4",
|
|
"BlueArmor5"
|
|
}
|
|
|
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- DO NOT EDIT BELOW THIS LINE
|
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
env.info("[DGB PLUGIN] Dynamic Ground Battle Plugin initializing...")
|
|
|
|
-- Validate that DualCoalitionZoneCapture is loaded
|
|
if not zoneCaptureObjects or not zoneNames then
|
|
env.error("[DGB PLUGIN] ERROR: Moose_DualCoalitionZoneCapture.lua must be loaded BEFORE this plugin!")
|
|
env.error("[DGB PLUGIN] Make sure zoneCaptureObjects and zoneNames are available.")
|
|
return
|
|
end
|
|
|
|
env.info("[DGB PLUGIN] Found " .. #zoneCaptureObjects .. " zones from DualCoalitionZoneCapture")
|
|
|
|
-- Track active markers to prevent memory leaks
|
|
local activeMarkers = {}
|
|
|
|
-- Reusable SET_GROUP to prevent memory leaks from repeated creation
|
|
local cachedAllGroups = nil
|
|
local function getAllGroups()
|
|
if not cachedAllGroups then
|
|
cachedAllGroups = SET_GROUP:New():FilterActive():FilterStart()
|
|
env.info("[DGB PLUGIN] Created cached SET_GROUP for performance")
|
|
end
|
|
return cachedAllGroups
|
|
end
|
|
|
|
-- Function to get zones controlled by a specific coalition
|
|
local function GetZonesByCoalition(targetCoalition)
|
|
local zones = {}
|
|
|
|
for idx, zoneCapture in ipairs(zoneCaptureObjects) do
|
|
if zoneCapture and zoneCapture:GetCoalition() == targetCoalition then
|
|
local zone = zoneCapture:GetZone()
|
|
if zone then
|
|
table.insert(zones, zone)
|
|
end
|
|
end
|
|
end
|
|
|
|
env.info(string.format("[DGB PLUGIN] Found %d zones for coalition %d", #zones, targetCoalition))
|
|
return zones
|
|
end
|
|
|
|
-- Function to calculate spawn frequency based on warehouse survival
|
|
local function CalculateSpawnFrequency(warehouses, baseFrequency)
|
|
local totalWarehouses = #warehouses
|
|
local aliveWarehouses = 0
|
|
|
|
for _, warehouse in ipairs(warehouses) do
|
|
if warehouse then
|
|
local life = warehouse:GetLife()
|
|
if life and life > 0 then
|
|
aliveWarehouses = aliveWarehouses + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
if totalWarehouses == 0 or aliveWarehouses == 0 then
|
|
return math.huge -- Stop spawning if no warehouses remain
|
|
end
|
|
|
|
local frequency = baseFrequency * (totalWarehouses / aliveWarehouses)
|
|
return frequency
|
|
end
|
|
|
|
-- Function to calculate spawn frequency as a percentage
|
|
local function CalculateSpawnFrequencyPercentage(warehouses)
|
|
local totalWarehouses = #warehouses
|
|
local aliveWarehouses = 0
|
|
|
|
for _, warehouse in ipairs(warehouses) do
|
|
if warehouse then
|
|
local life = warehouse:GetLife()
|
|
if life and life > 0 then
|
|
aliveWarehouses = aliveWarehouses + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
if totalWarehouses == 0 then
|
|
return 0
|
|
end
|
|
|
|
local percentage = (aliveWarehouses / totalWarehouses) * 100
|
|
return math.floor(percentage)
|
|
end
|
|
|
|
-- Function to add warehouse markers on the map
|
|
local function addMarkPoints(warehouses, coalition)
|
|
for _, warehouse in ipairs(warehouses) do
|
|
if warehouse then
|
|
local warehousePos = warehouse:GetVec3()
|
|
local details
|
|
|
|
if coalition == 2 then -- Blue viewing
|
|
if warehouse:GetCoalition() == 2 then
|
|
details = "Warehouse: " .. warehouse:GetName() .. "\nThis warehouse needs to be protected.\n"
|
|
else
|
|
details = "Warehouse: " .. warehouse:GetName() .. "\nThis is a primary target as it is directly supplying enemy units.\n"
|
|
end
|
|
elseif coalition == 1 then -- Red viewing
|
|
if warehouse:GetCoalition() == 1 then
|
|
details = "Warehouse: " .. warehouse:GetName() .. "\nThis warehouse needs to be protected.\n"
|
|
else
|
|
details = "Warehouse: " .. warehouse:GetName() .. "\nThis is a primary target as it is directly supplying enemy units.\n"
|
|
end
|
|
end
|
|
|
|
local coordinate = COORDINATE:NewFromVec3(warehousePos)
|
|
local marker = MARKER:New(coordinate, details):ToCoalition(coalition):ReadOnly()
|
|
table.insert(activeMarkers, marker)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Function to update warehouse markers
|
|
local function updateMarkPoints()
|
|
-- Clean up old markers first
|
|
for _, marker in ipairs(activeMarkers) do
|
|
if marker then
|
|
marker:Remove()
|
|
end
|
|
end
|
|
activeMarkers = {}
|
|
|
|
addMarkPoints(redWarehouses, 2) -- Blue coalition sees red warehouses
|
|
addMarkPoints(blueWarehouses, 2) -- Blue coalition sees blue warehouses
|
|
addMarkPoints(redWarehouses, 1) -- Red coalition sees red warehouses
|
|
addMarkPoints(blueWarehouses, 1) -- Red coalition sees blue warehouses
|
|
|
|
env.info("[DGB PLUGIN] Updated warehouse markers")
|
|
end
|
|
|
|
-- Function to check if a group contains infantry units
|
|
local function IsInfantryGroup(group)
|
|
for _, unit in ipairs(group:GetUnits()) do
|
|
local unitTypeName = unit:GetTypeName()
|
|
if unitTypeName:find("Infantry") or unitTypeName:find("Soldier") or unitTypeName:find("Paratrooper") then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- Function to assign tasks to a group
|
|
local function AssignTasks(group)
|
|
if not group or not group.GetCoalition or not group.GetCoordinate or not group.GetVelocityVec3 then
|
|
return
|
|
end
|
|
|
|
-- Don't reassign if already moving
|
|
local velocity = group:GetVelocityVec3()
|
|
local speed = math.sqrt(velocity.x^2 + velocity.y^2 + velocity.z^2)
|
|
if speed > 0.5 then
|
|
return
|
|
end
|
|
|
|
local groupCoalition = group:GetCoalition()
|
|
local groupCoordinate = group:GetCoordinate()
|
|
local closestZone = nil
|
|
local closestDistance = math.huge
|
|
|
|
-- Find nearest enemy zone
|
|
for idx, zoneCapture in ipairs(zoneCaptureObjects) do
|
|
local zoneCoalition = zoneCapture:GetCoalition()
|
|
|
|
if zoneCoalition ~= groupCoalition and zoneCoalition ~= coalition.side.NEUTRAL then
|
|
local zone = zoneCapture:GetZone()
|
|
if zone then
|
|
local zoneCoordinate = zone:GetCoordinate()
|
|
local distance = groupCoordinate:Get2DDistance(zoneCoordinate)
|
|
|
|
if distance < closestDistance then
|
|
closestDistance = distance
|
|
closestZone = zone
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if closestZone then
|
|
env.info(string.format("[DGB PLUGIN] %s patrolling %s", group:GetName(), closestZone:GetName()))
|
|
group:PatrolZones({closestZone}, 20, "Cone", 30, 60)
|
|
end
|
|
end
|
|
|
|
-- Function to assign tasks to all groups
|
|
local function AssignTasksToGroups()
|
|
env.info("[DGB PLUGIN] Starting task assignment cycle...")
|
|
local allGroups = getAllGroups()
|
|
local tasksAssigned = 0
|
|
|
|
allGroups:ForEachGroup(function(group)
|
|
if group and group:IsAlive() then
|
|
-- Check if group is in a friendly zone
|
|
local groupCoalition = group:GetCoalition()
|
|
local inFriendlyZone = false
|
|
|
|
for idx, zoneCapture in ipairs(zoneCaptureObjects) do
|
|
if zoneCapture:GetCoalition() == groupCoalition then
|
|
local zone = zoneCapture:GetZone()
|
|
if zone and group:IsCompletelyInZone(zone) then
|
|
inFriendlyZone = true
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
if inFriendlyZone then
|
|
-- Skip infantry if movement is disabled
|
|
if IsInfantryGroup(group) and not MOVING_INFANTRY_PATROLS then
|
|
return
|
|
end
|
|
|
|
AssignTasks(group)
|
|
tasksAssigned = tasksAssigned + 1
|
|
end
|
|
end
|
|
end)
|
|
|
|
env.info(string.format("[DGB PLUGIN] Task assignment complete. %d groups tasked.", tasksAssigned))
|
|
end
|
|
|
|
-- Function to monitor and announce warehouse status
|
|
local function MonitorWarehouses()
|
|
local blueWarehousesAlive = 0
|
|
local redWarehousesAlive = 0
|
|
|
|
for _, warehouse in ipairs(blueWarehouses) do
|
|
if warehouse and warehouse:IsAlive() then
|
|
blueWarehousesAlive = blueWarehousesAlive + 1
|
|
end
|
|
end
|
|
|
|
for _, warehouse in ipairs(redWarehouses) do
|
|
if warehouse and warehouse:IsAlive() then
|
|
redWarehousesAlive = redWarehousesAlive + 1
|
|
end
|
|
end
|
|
|
|
local redSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(redWarehouses)
|
|
local blueSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(blueWarehouses)
|
|
|
|
local msg = "[Warehouse Status]\n"
|
|
msg = msg .. "Red warehouses alive: " .. redWarehousesAlive .. " Reinforcements: " .. redSpawnFrequencyPercentage .. "%\n"
|
|
msg = msg .. "Blue warehouses alive: " .. blueWarehousesAlive .. " Reinforcements: " .. blueSpawnFrequencyPercentage .. "%\n"
|
|
MESSAGE:New(msg, 30):ToAll()
|
|
|
|
env.info(string.format("[DGB PLUGIN] Warehouse status - Red: %d/%d (%d%%), Blue: %d/%d (%d%%)",
|
|
redWarehousesAlive, #redWarehouses, redSpawnFrequencyPercentage,
|
|
blueWarehousesAlive, #blueWarehouses, blueSpawnFrequencyPercentage))
|
|
end
|
|
|
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- INITIALIZATION
|
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
-- Get initial zone lists for each coalition
|
|
local redZones = GetZonesByCoalition(coalition.side.RED)
|
|
local blueZones = GetZonesByCoalition(coalition.side.BLUE)
|
|
|
|
-- Calculate initial spawn frequencies
|
|
local redInfantrySpawnFrequency = CalculateSpawnFrequency(redWarehouses, SPAWN_SCHED_RED_INFANTRY)
|
|
local redArmorSpawnFrequency = CalculateSpawnFrequency(redWarehouses, SPAWN_SCHED_RED_ARMOR)
|
|
local blueInfantrySpawnFrequency = CalculateSpawnFrequency(blueWarehouses, SPAWN_SCHED_BLUE_INFANTRY)
|
|
local blueArmorSpawnFrequency = CalculateSpawnFrequency(blueWarehouses, SPAWN_SCHED_BLUE_ARMOR)
|
|
|
|
-- Calculate and display initial spawn frequency percentages
|
|
local redSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(redWarehouses)
|
|
local blueSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(blueWarehouses)
|
|
|
|
MESSAGE:New("Red reinforcement capacity: " .. redSpawnFrequencyPercentage .. "%", 30):ToRed()
|
|
MESSAGE:New("Blue reinforcement capacity: " .. blueSpawnFrequencyPercentage .. "%", 30):ToBlue()
|
|
|
|
-- Initialize spawners
|
|
env.info("[DGB PLUGIN] Initializing spawn systems...")
|
|
|
|
-- Note: Spawn zones will be dynamically updated based on zone capture states
|
|
-- We'll use a function to get current friendly zones on each spawn
|
|
local function GetRedZones()
|
|
return GetZonesByCoalition(coalition.side.RED)
|
|
end
|
|
|
|
local function GetBlueZones()
|
|
return GetZonesByCoalition(coalition.side.BLUE)
|
|
end
|
|
|
|
-- Red Infantry Spawner
|
|
redInfantrySpawn = SPAWN:New("RedInfantryGroup")
|
|
:InitRandomizeTemplate(redInfantryTemplates)
|
|
:InitLimit(INIT_RED_INFANTRY, MAX_RED_INFANTRY)
|
|
|
|
-- Red Armor Spawner
|
|
redArmorSpawn = SPAWN:New("RedArmorGroup")
|
|
:InitRandomizeTemplate(redArmorTemplates)
|
|
:InitLimit(INIT_RED_ARMOR, MAX_RED_ARMOR)
|
|
|
|
-- Blue Infantry Spawner
|
|
blueInfantrySpawn = SPAWN:New("BlueInfantryGroup")
|
|
:InitRandomizeTemplate(blueInfantryTemplates)
|
|
:InitLimit(INIT_BLUE_INFANTRY, MAX_BLUE_INFANTRY)
|
|
|
|
-- Blue Armor Spawner
|
|
blueArmorSpawn = SPAWN:New("BlueArmorGroup")
|
|
:InitRandomizeTemplate(blueArmorTemplates)
|
|
:InitLimit(INIT_BLUE_ARMOR, MAX_BLUE_ARMOR)
|
|
|
|
-- Custom spawn function that updates zones dynamically
|
|
local function SpawnWithDynamicZones()
|
|
local currentRedZones = GetRedZones()
|
|
local currentBlueZones = GetBlueZones()
|
|
|
|
if #currentRedZones > 0 then
|
|
local randomRedZone = currentRedZones[math.random(#currentRedZones)]
|
|
redInfantrySpawn:SpawnInZone(randomRedZone, false)
|
|
redArmorSpawn:SpawnInZone(randomRedZone, false)
|
|
end
|
|
|
|
if #currentBlueZones > 0 then
|
|
local randomBlueZone = currentBlueZones[math.random(#currentBlueZones)]
|
|
blueInfantrySpawn:SpawnInZone(randomBlueZone, false)
|
|
blueArmorSpawn:SpawnInZone(randomBlueZone, false)
|
|
end
|
|
end
|
|
|
|
-- Schedule spawns
|
|
SCHEDULER:New(nil, SpawnWithDynamicZones, {}, 10, math.max(SPAWN_SCHED_RED_INFANTRY, SPAWN_SCHED_BLUE_INFANTRY))
|
|
|
|
-- Schedule warehouse marker updates
|
|
if ENABLE_WAREHOUSE_MARKERS then
|
|
SCHEDULER:New(nil, updateMarkPoints, {}, 10, UPDATE_MARK_POINTS_SCHED)
|
|
end
|
|
|
|
-- Schedule warehouse monitoring
|
|
SCHEDULER:New(nil, MonitorWarehouses, {}, 30, 120)
|
|
|
|
-- Schedule task assignments
|
|
SCHEDULER:New(nil, AssignTasksToGroups, {}, 120, ASSIGN_TASKS_SCHED)
|
|
|
|
-- Add F10 menu for manual checks
|
|
local missionMenu = MENU_MISSION:New("Ground Battle")
|
|
MENU_MISSION_COMMAND:New("Check Warehouse Status", missionMenu, MonitorWarehouses)
|
|
|
|
env.info("[DGB PLUGIN] Dynamic Ground Battle Plugin initialized successfully!")
|
|
env.info(string.format("[DGB PLUGIN] Infantry movement: %s", MOVING_INFANTRY_PATROLS and "ENABLED" or "DISABLED"))
|
|
env.info(string.format("[DGB PLUGIN] Warehouse markers: %s", ENABLE_WAREHOUSE_MARKERS and "ENABLED" or "DISABLED"))
|