mirror of
https://github.com/iTracerFacer/Moose_DualCoalitionZoneCapture.git
synced 2026-07-16 06:27:46 +00:00
Added perplayer multi language support.
This commit is contained in:
+655
-179
@@ -38,35 +38,6 @@ local MESSAGE_CONFIG = {
|
||||
GARBAGE_COLLECTION_FREQUENCY = 600 -- Lua garbage collection cadence (seconds) - helps prevent memory buildup
|
||||
}
|
||||
|
||||
-- ==========================================
|
||||
-- ZONE COLOR CONFIGURATION (Centralized)
|
||||
-- ==========================================
|
||||
-- Colors are in RGB format: {Red, Green, Blue} where each value is 0.0 to 1.0
|
||||
local ZONE_COLORS = {
|
||||
-- Blue coalition zones
|
||||
BLUE_CAPTURED = {0, 0, 1}, -- Blue (owned by Blue)
|
||||
BLUE_ATTACKED = {0, 1, 1}, -- Cyan (owned by Blue, under attack)
|
||||
|
||||
-- Red coalition zones
|
||||
RED_CAPTURED = {1, 0, 0}, -- Red (owned by Red)
|
||||
RED_ATTACKED = {1, 0.5, 0}, -- Orange (owned by Red, under attack)
|
||||
|
||||
-- Neutral/Empty zones
|
||||
EMPTY = {0, 1, 0} -- Green (no owner)
|
||||
}
|
||||
|
||||
-- ==========================================
|
||||
-- COALITION TITLES CONFIGURATION
|
||||
-- ==========================================
|
||||
-- Mission makers: Customize the display names for each coalition
|
||||
-- These will be used in messages, mission names, and UI elements
|
||||
local COALITION_TITLES = {
|
||||
BLUE = "USA", -- Display name for Blue coalition (e.g., "USA", "NATO", "Allied Forces")
|
||||
RED = "Russia", -- Display name for Red coalition (e.g., "Russia", "Germany", "Axis Powers")
|
||||
BLUE_OPERATION = "Operation Polar Shield", -- Name of Blue coalition's operation
|
||||
RED_OPERATION = "Defend the Motherland" -- Name of Red coalition's operation
|
||||
}
|
||||
|
||||
-- ==========================================
|
||||
-- ZONE CONFIGURATION
|
||||
-- ==========================================
|
||||
@@ -109,6 +80,422 @@ local ZONE_SETTINGS = {
|
||||
captureScore = 200 -- Points awarded for capturing a zone
|
||||
}
|
||||
|
||||
-- ==========================================
|
||||
-- ZONE COLOR CONFIGURATION (Centralized)
|
||||
-- ==========================================
|
||||
-- Colors are in RGB format: {Red, Green, Blue} where each value is 0.0 to 1.0
|
||||
local ZONE_COLORS = {
|
||||
-- Blue coalition zones
|
||||
BLUE_CAPTURED = {0, 0, 1}, -- Blue (owned by Blue)
|
||||
BLUE_ATTACKED = {0, 1, 1}, -- Cyan (owned by Blue, under attack)
|
||||
|
||||
-- Red coalition zones
|
||||
RED_CAPTURED = {1, 0, 0}, -- Red (owned by Red)
|
||||
RED_ATTACKED = {1, 0.5, 0}, -- Orange (owned by Red, under attack)
|
||||
|
||||
-- Neutral/Empty zones
|
||||
EMPTY = {0, 1, 0} -- Green (no owner)
|
||||
}
|
||||
|
||||
-- ==========================================
|
||||
-- COALITION TITLES CONFIGURATION
|
||||
-- ==========================================
|
||||
-- Mission makers: Customize the display names for each coalition
|
||||
-- These will be used in messages, mission names, and UI elements
|
||||
local COALITION_TITLES = {
|
||||
BLUE = "USA", -- Display name for Blue coalition (e.g., "USA", "NATO", "Allied Forces")
|
||||
RED = "Russia", -- Display name for Red coalition (e.g., "Russia", "Germany", "Axis Powers")
|
||||
BLUE_OPERATION = "Operation Polar Shield", -- Name of Blue coalition's operation
|
||||
RED_OPERATION = "Defend the Motherland" -- Name of Red coalition's operation
|
||||
}
|
||||
|
||||
-- ==========================================
|
||||
-- LANGUAGE CONFIGURATION
|
||||
-- ==========================================
|
||||
local LANGUAGE_CONFIG = {
|
||||
defaultLanguage = "EN", -- Default language: "EN", "DE", "FR", "ES", "RU"
|
||||
}
|
||||
|
||||
-- Multilingual message table
|
||||
-- Each language contains all messages and menu text
|
||||
local ZONE_CAPTURE_LANGUAGES = {
|
||||
EN = {
|
||||
-- Zone state messages
|
||||
zoneGuarded = "%s is under protection of the %s",
|
||||
zoneEmpty = "%s is unprotected, and can be captured!",
|
||||
zoneUnderAttack = "%s is under attack by %s",
|
||||
zoneWeAttacking = "We are attacking %s",
|
||||
zoneCapturedByEnemy = "%s is captured by the %s, we lost it!",
|
||||
zoneCapturedByUs = "We captured %s, Excellent job!",
|
||||
|
||||
-- Victory messages
|
||||
victoryBlue = "VICTORY! All capture zones have been secured by %s forces!\n\n%s is complete. Outstanding work!\nMission will end in 60 seconds.",
|
||||
defeatBlue = "DEFEAT! All strategic positions have been lost to %s forces.\n\n%s has failed. Mission ending in 60 seconds.",
|
||||
victoryRed = "VICTORY! All strategic positions secured for %s!\n\n%s forces have been repelled. Outstanding work!\nMission will end in 60 seconds.",
|
||||
defeatRed = "DEFEAT! All capture zones have been lost to %s forces.\n\n%s has failed. Mission ending in 60 seconds.",
|
||||
missionComplete = "Mission Complete! Congratulations on your victory!\nFinal Status: All %d strategic zones secured.",
|
||||
|
||||
-- Status report messages
|
||||
zoneControlReport = "ZONE CONTROL REPORT:\nBlue Coalition: %d/%d zones\nRed Coalition: %d/%d zones\nNeutral: %d/%d zones",
|
||||
zoneDetails = "\nZONE DETAILS:\n",
|
||||
zoneDetailLine = "• %s: %s\n",
|
||||
yourProgress = "\n\nYour Progress to Victory: %d%%",
|
||||
|
||||
-- Progress warning messages
|
||||
blueNearVictory = "TACTICAL ALERT: %s forces control %d%% of strategic zones!\nVictory is within reach!",
|
||||
redNearVictory = "WARNING: %s forces have captured %d%% of zones!\nDefend our positions!",
|
||||
|
||||
-- Coalition names
|
||||
coalitionBlue = "Blue Coalition",
|
||||
coalitionRed = "Red Coalition",
|
||||
coalitionNeutral = "Neutral",
|
||||
|
||||
-- Menu items
|
||||
menuZoneControl = "Zone Control",
|
||||
menuStatusReport = "Get Zone Status Report",
|
||||
menuVictoryProgress = "Check Victory Progress",
|
||||
menuRefreshColors = "Refresh Zone Colors",
|
||||
menuLanguage = "Language / Sprache / Langue",
|
||||
menuEnglish = "English",
|
||||
menuGerman = "Deutsch (German)",
|
||||
menuFrench = "Français (French)",
|
||||
menuSpanish = "Español (Spanish)",
|
||||
menuRussian = "Русский (Russian)",
|
||||
|
||||
-- Victory progress messages
|
||||
victoryProgressTitle = "VICTORY PROGRESS: %d%%",
|
||||
zonesCaptured = "Zones Captured: %d/%d",
|
||||
zonesRemaining = "Remaining: %d zones",
|
||||
progressComplete = "MISSION COMPLETE!",
|
||||
progressAlmostThere = "ALMOST THERE!",
|
||||
progressGood = "GOOD PROGRESS!",
|
||||
progressKeepFighting = "KEEP FIGHTING!",
|
||||
|
||||
-- System messages
|
||||
zoneMarkersRefreshed = "Zone visual markers have been refreshed!",
|
||||
languageChanged = "Language changed to English",
|
||||
},
|
||||
|
||||
DE = {
|
||||
-- Zone state messages
|
||||
zoneGuarded = "%s steht unter dem Schutz der %s",
|
||||
zoneEmpty = "%s ist ungeschützt und kann erobert werden!",
|
||||
zoneUnderAttack = "%s wird von %s angegriffen",
|
||||
zoneWeAttacking = "Wir greifen %s an",
|
||||
zoneCapturedByEnemy = "%s wurde von %s erobert, wir haben es verloren!",
|
||||
zoneCapturedByUs = "Wir haben %s erobert, hervorragende Arbeit!",
|
||||
|
||||
-- Victory messages
|
||||
victoryBlue = "SIEG! Alle Eroberungszonen wurden von %s Streitkräften gesichert!\n\n%s ist abgeschlossen. Hervorragende Arbeit!\nMission endet in 60 Sekunden.",
|
||||
defeatBlue = "NIEDERLAGE! Alle strategischen Positionen wurden an %s Streitkräfte verloren.\n\n%s ist gescheitert. Mission endet in 60 Sekunden.",
|
||||
victoryRed = "SIEG! Alle strategischen Positionen für %s gesichert!\n\n%s Streitkräfte wurden zurückgeschlagen. Hervorragende Arbeit!\nMission endet in 60 Sekunden.",
|
||||
defeatRed = "NIEDERLAGE! Alle Eroberungszonen wurden an %s Streitkräfte verloren.\n\n%s ist gescheitert. Mission endet in 60 Sekunden.",
|
||||
missionComplete = "Mission erfolgreich! Herzlichen Glückwunsch zu Ihrem Sieg!\nEndstatus: Alle %d strategischen Zonen gesichert.",
|
||||
|
||||
-- Status report messages
|
||||
zoneControlReport = "ZONENKONTROLLBERICHT:\nBlaue Koalition: %d/%d Zonen\nRote Koalition: %d/%d Zonen\nNeutral: %d/%d Zonen",
|
||||
zoneDetails = "\nZONENDETAILS:\n",
|
||||
zoneDetailLine = "• %s: %s\n",
|
||||
yourProgress = "\n\nIhr Fortschritt zum Sieg: %d%%",
|
||||
|
||||
-- Progress warning messages
|
||||
blueNearVictory = "TAKTISCHER ALARM: %s Streitkräfte kontrollieren %d%% der strategischen Zonen!\nSieg ist in Reichweite!",
|
||||
redNearVictory = "WARNUNG: %s Streitkräfte haben %d%% der Zonen erobert!\nVerteidigt unsere Positionen!",
|
||||
|
||||
-- Coalition names
|
||||
coalitionBlue = "Blaue Koalition",
|
||||
coalitionRed = "Rote Koalition",
|
||||
coalitionNeutral = "Neutral",
|
||||
|
||||
-- Menu items
|
||||
menuZoneControl = "Zonenkontrolle",
|
||||
menuStatusReport = "Zonenstatusbericht abrufen",
|
||||
menuVictoryProgress = "Siegfortschritt prüfen",
|
||||
menuRefreshColors = "Zonenfarben aktualisieren",
|
||||
menuLanguage = "Language / Sprache / Langue",
|
||||
menuEnglish = "English",
|
||||
menuGerman = "Deutsch (German)",
|
||||
menuFrench = "Français (French)",
|
||||
menuSpanish = "Español (Spanish)",
|
||||
menuRussian = "Русский (Russian)",
|
||||
|
||||
-- Victory progress messages
|
||||
victoryProgressTitle = "SIEGFORTSCHRITT: %d%%",
|
||||
zonesCaptured = "Zonen erobert: %d/%d",
|
||||
zonesRemaining = "Verbleibend: %d Zonen",
|
||||
progressComplete = "MISSION ABGESCHLOSSEN!",
|
||||
progressAlmostThere = "FAST GESCHAFFT!",
|
||||
progressGood = "GUTER FORTSCHRITT!",
|
||||
progressKeepFighting = "WEITER KÄMPFEN!",
|
||||
|
||||
-- System messages
|
||||
zoneMarkersRefreshed = "Zonenmarkierungen wurden aktualisiert!",
|
||||
languageChanged = "Sprache auf Deutsch geändert",
|
||||
},
|
||||
|
||||
FR = {
|
||||
-- Zone state messages
|
||||
zoneGuarded = "%s est sous la protection de %s",
|
||||
zoneEmpty = "%s est sans protection et peut être capturée !",
|
||||
zoneUnderAttack = "%s est attaquée par %s",
|
||||
zoneWeAttacking = "Nous attaquons %s",
|
||||
zoneCapturedByEnemy = "%s est capturée par %s, nous l'avons perdue !",
|
||||
zoneCapturedByUs = "Nous avons capturé %s, excellent travail !",
|
||||
|
||||
-- Victory messages
|
||||
victoryBlue = "VICTOIRE ! Toutes les zones de capture ont été sécurisées par les forces %s !\n\n%s est terminée. Excellent travail !\nLa mission se terminera dans 60 secondes.",
|
||||
defeatBlue = "DÉFAITE ! Toutes les positions stratégiques ont été perdues face aux forces %s.\n\n%s a échoué. Mission se terminant dans 60 secondes.",
|
||||
victoryRed = "VICTOIRE ! Toutes les positions stratégiques sécurisées pour %s !\n\nLes forces %s ont été repoussées. Excellent travail !\nLa mission se terminera dans 60 secondes.",
|
||||
defeatRed = "DÉFAITE ! Toutes les zones de capture ont été perdues face aux forces %s.\n\n%s a échoué. Mission se terminant dans 60 secondes.",
|
||||
missionComplete = "Mission accomplie ! Félicitations pour votre victoire !\nStatut final : Toutes les %d zones stratégiques sécurisées.",
|
||||
|
||||
-- Status report messages
|
||||
zoneControlReport = "RAPPORT DE CONTRÔLE DES ZONES :\nCoalition bleue : %d/%d zones\nCoalition rouge : %d/%d zones\nNeutre : %d/%d zones",
|
||||
zoneDetails = "\nDÉTAILS DES ZONES :\n",
|
||||
zoneDetailLine = "• %s : %s\n",
|
||||
yourProgress = "\n\nVotre progression vers la victoire : %d%%",
|
||||
|
||||
-- Progress warning messages
|
||||
blueNearVictory = "ALERTE TACTIQUE : Les forces %s contrôlent %d%% des zones stratégiques !\nLa victoire est à portée de main !",
|
||||
redNearVictory = "AVERTISSEMENT : Les forces %s ont capturé %d%% des zones !\nDéfendez nos positions !",
|
||||
|
||||
-- Coalition names
|
||||
coalitionBlue = "Coalition bleue",
|
||||
coalitionRed = "Coalition rouge",
|
||||
coalitionNeutral = "Neutre",
|
||||
|
||||
-- Menu items
|
||||
menuZoneControl = "Contrôle des zones",
|
||||
menuStatusReport = "Obtenir le rapport d'état des zones",
|
||||
menuVictoryProgress = "Vérifier la progression vers la victoire",
|
||||
menuRefreshColors = "Actualiser les couleurs des zones",
|
||||
menuLanguage = "Language / Sprache / Langue",
|
||||
menuEnglish = "English",
|
||||
menuGerman = "Deutsch (German)",
|
||||
menuFrench = "Français (French)",
|
||||
menuSpanish = "Español (Spanish)",
|
||||
menuRussian = "Русский (Russian)",
|
||||
|
||||
-- Victory progress messages
|
||||
victoryProgressTitle = "PROGRÈS DE LA VICTOIRE : %d%%",
|
||||
zonesCaptured = "Zones capturées : %d/%d",
|
||||
zonesRemaining = "Restantes : %d zones",
|
||||
progressComplete = "MISSION ACCOMPLIE !",
|
||||
progressAlmostThere = "PRESQUE TERMINÉ !",
|
||||
progressGood = "BON PROGRÈS !",
|
||||
progressKeepFighting = "CONTINUEZ À COMBATTRE !",
|
||||
|
||||
-- System messages
|
||||
zoneMarkersRefreshed = "Les marqueurs de zone ont été actualisés !",
|
||||
languageChanged = "Langue changée en français",
|
||||
},
|
||||
|
||||
ES = {
|
||||
-- Zone state messages
|
||||
zoneGuarded = "%s está bajo la protección de %s",
|
||||
zoneEmpty = "¡%s está desprotegida y puede ser capturada!",
|
||||
zoneUnderAttack = "%s está siendo atacada por %s",
|
||||
zoneWeAttacking = "Estamos atacando %s",
|
||||
zoneCapturedByEnemy = "¡%s ha sido capturada por %s, la hemos perdido!",
|
||||
zoneCapturedByUs = "¡Hemos capturado %s, excelente trabajo!",
|
||||
|
||||
-- Victory messages
|
||||
victoryBlue = "¡VICTORIA! ¡Todas las zonas de captura han sido aseguradas por las fuerzas %s!\n\n%s está completa. ¡Excelente trabajo!\nLa misión terminará en 60 segundos.",
|
||||
defeatBlue = "¡DERROTA! Todas las posiciones estratégicas se han perdido ante las fuerzas %s.\n\n%s ha fallado. Misión terminando en 60 segundos.",
|
||||
victoryRed = "¡VICTORIA! ¡Todas las posiciones estratégicas aseguradas para %s!\n\n¡Las fuerzas %s han sido repelidas. Excelente trabajo!\nLa misión terminará en 60 segundos.",
|
||||
defeatRed = "¡DERROTA! Todas las zonas de captura se han perdido ante las fuerzas %s.\n\n%s ha fallado. Misión terminando en 60 segundos.",
|
||||
missionComplete = "¡Misión completada! ¡Felicitaciones por tu victoria!\nEstado final: Todas las %d zonas estratégicas aseguradas.",
|
||||
|
||||
-- Status report messages
|
||||
zoneControlReport = "INFORME DE CONTROL DE ZONAS:\nCoalición Azul: %d/%d zonas\nCoalición Roja: %d/%d zonas\nNeutral: %d/%d zonas",
|
||||
zoneDetails = "\nDETALLES DE ZONAS:\n",
|
||||
zoneDetailLine = "• %s: %s\n",
|
||||
yourProgress = "\n\nTu progreso hacia la victoria: %d%%",
|
||||
|
||||
-- Progress warning messages
|
||||
blueNearVictory = "ALERTA TÁCTICA: ¡Las fuerzas %s controlan el %d%% de las zonas estratégicas!\n¡La victoria está al alcance!",
|
||||
redNearVictory = "ADVERTENCIA: ¡Las fuerzas %s han capturado el %d%% de las zonas!\n¡Defiende nuestras posiciones!",
|
||||
|
||||
-- Coalition names
|
||||
coalitionBlue = "Coalición Azul",
|
||||
coalitionRed = "Coalición Roja",
|
||||
coalitionNeutral = "Neutral",
|
||||
|
||||
-- Menu items
|
||||
menuZoneControl = "Control de zonas",
|
||||
menuStatusReport = "Obtener informe de estado de zonas",
|
||||
menuVictoryProgress = "Verificar progreso de victoria",
|
||||
menuRefreshColors = "Actualizar colores de zonas",
|
||||
menuLanguage = "Language / Sprache / Langue",
|
||||
menuEnglish = "English",
|
||||
menuGerman = "Deutsch (German)",
|
||||
menuFrench = "Français (French)",
|
||||
menuSpanish = "Español (Spanish)",
|
||||
menuRussian = "Русский (Russian)",
|
||||
|
||||
-- Victory progress messages
|
||||
victoryProgressTitle = "PROGRESO DE VICTORIA: %d%%",
|
||||
zonesCaptured = "Zonas capturadas: %d/%d",
|
||||
zonesRemaining = "Restantes: %d zonas",
|
||||
progressComplete = "¡MISIÓN COMPLETADA!",
|
||||
progressAlmostThere = "¡CASI TERMINADO!",
|
||||
progressGood = "¡BUEN PROGRESO!",
|
||||
progressKeepFighting = "¡SIGUE LUCHANDO!",
|
||||
|
||||
-- System messages
|
||||
zoneMarkersRefreshed = "¡Los marcadores de zona se han actualizado!",
|
||||
languageChanged = "Idioma cambiado a español",
|
||||
},
|
||||
|
||||
RU = {
|
||||
-- Zone state messages
|
||||
zoneGuarded = "%s находится под защитой %s",
|
||||
zoneEmpty = "%s не защищена и может быть захвачена!",
|
||||
zoneUnderAttack = "%s атакована силами %s",
|
||||
zoneWeAttacking = "Мы атакуем %s",
|
||||
zoneCapturedByEnemy = "%s захвачена %s, мы её потеряли!",
|
||||
zoneCapturedByUs = "Мы захватили %s, отличная работа!",
|
||||
|
||||
-- Victory messages
|
||||
victoryBlue = "ПОБЕДА! Все зоны захвата обеспечены силами %s!\n\n%s завершена. Отличная работа!\nМиссия закончится через 60 секунд.",
|
||||
defeatBlue = "ПОРАЖЕНИЕ! Все стратегические позиции потеряны силами %s.\n\n%s провалена. Миссия заканчивается через 60 секунд.",
|
||||
victoryRed = "ПОБЕДА! Все стратегические позиции обеспечены для %s!\n\nСилы %s отброшены. Отличная работа!\nМиссия закончится через 60 секунд.",
|
||||
defeatRed = "ПОРАЖЕНИЕ! Все зоны захвата потеряны силами %s.\n\n%s провалена. Миссия заканчивается через 60 секунд.",
|
||||
missionComplete = "Миссия выполнена! Поздравляем с победой!\nИтоговый статус: Все %d стратегических зон обеспечены.",
|
||||
|
||||
-- Status report messages
|
||||
zoneControlReport = "ОТЧЁТ О КОНТРОЛЕ ЗОН:\nСиняя коалиция: %d/%d зон\nКрасная коалиция: %d/%d зон\nНейтральные: %d/%d зон",
|
||||
zoneDetails = "\nПОДРОБНОСТИ ЗОН:\n",
|
||||
zoneDetailLine = "• %s: %s\n",
|
||||
yourProgress = "\n\nВаш прогресс к победе: %d%%",
|
||||
|
||||
-- Progress warning messages
|
||||
blueNearVictory = "ТАКТИЧЕСКАЯ ТРЕВОГА: Силы %s контролируют %d%% стратегических зон!\nПобеда близка!",
|
||||
redNearVictory = "ВНИМАНИЕ: Силы %s захватили %d%% зон!\nЗащищайте наши позиции!",
|
||||
|
||||
-- Coalition names
|
||||
coalitionBlue = "Синяя коалиция",
|
||||
coalitionRed = "Красная коалиция",
|
||||
coalitionNeutral = "Нейтральные",
|
||||
|
||||
-- Menu items
|
||||
menuZoneControl = "Контроль зон",
|
||||
menuStatusReport = "Получить отчёт о статусе зон",
|
||||
menuVictoryProgress = "Проверить прогресс победы",
|
||||
menuRefreshColors = "Обновить цвета зон",
|
||||
menuLanguage = "Language / Sprache / Langue",
|
||||
menuEnglish = "English",
|
||||
menuGerman = "Deutsch (German)",
|
||||
menuFrench = "Français (French)",
|
||||
menuSpanish = "Español (Spanish)",
|
||||
menuRussian = "Русский (Russian)",
|
||||
|
||||
-- Victory progress messages
|
||||
victoryProgressTitle = "ПРОГРЕСС ПОБЕДЫ: %d%%",
|
||||
zonesCaptured = "Зоны захвачены: %d/%d",
|
||||
zonesRemaining = "Осталось: %d зон",
|
||||
progressComplete = "МИССИЯ ВЫПОЛНЕНА!",
|
||||
progressAlmostThere = "ПОЧТИ ГОТОВО!",
|
||||
progressGood = "ХОРОШИЙ ПРОГРЕСС!",
|
||||
progressKeepFighting = "ПРОДОЛЖАЙТЕ БОРОТЬСЯ!",
|
||||
|
||||
-- System messages
|
||||
zoneMarkersRefreshed = "Маркеры зон обновлены!",
|
||||
languageChanged = "Язык изменён на русский",
|
||||
}
|
||||
}
|
||||
|
||||
-- ==========================================
|
||||
-- PLAYER LANGUAGE TRACKING
|
||||
-- ==========================================
|
||||
-- Store per-player language preferences
|
||||
local playerLanguages = {}
|
||||
|
||||
-- Helper function to get player's language preference
|
||||
local function GetPlayerLanguage(playerName)
|
||||
if playerName and playerLanguages[playerName] then
|
||||
return playerLanguages[playerName]
|
||||
end
|
||||
return LANGUAGE_CONFIG.defaultLanguage
|
||||
end
|
||||
|
||||
-- Helper function to set player's language preference
|
||||
local function SetPlayerLanguage(playerName, language)
|
||||
if playerName and language then
|
||||
playerLanguages[playerName] = language
|
||||
env.info(string.format("[LANGUAGE] Player %s language set to %s", playerName, language))
|
||||
end
|
||||
end
|
||||
|
||||
-- Helper function to get translated text
|
||||
local function GetText(textKey, playerName)
|
||||
local lang = GetPlayerLanguage(playerName)
|
||||
local langTable = ZONE_CAPTURE_LANGUAGES[lang] or ZONE_CAPTURE_LANGUAGES.EN
|
||||
return langTable[textKey] or textKey
|
||||
end
|
||||
|
||||
-- Helper function to get coalition-specific text
|
||||
local function GetCoalitionText(coalitionSide, playerName)
|
||||
local lang = GetPlayerLanguage(playerName)
|
||||
local langTable = ZONE_CAPTURE_LANGUAGES[lang] or ZONE_CAPTURE_LANGUAGES.EN
|
||||
|
||||
if coalitionSide == coalition.side.BLUE then
|
||||
return langTable.coalitionBlue
|
||||
elseif coalitionSide == coalition.side.RED then
|
||||
return langTable.coalitionRed
|
||||
else
|
||||
return langTable.coalitionNeutral
|
||||
end
|
||||
end
|
||||
|
||||
-- Helper function to send message to coalition with language support
|
||||
local function MessageToCoalition(commandCenter, messageKey, params, coalitionSide, duration)
|
||||
if not commandCenter then return end
|
||||
|
||||
-- Get all players in the coalition
|
||||
local playerList = coalition.getPlayers(coalitionSide)
|
||||
|
||||
if not playerList or #playerList == 0 then
|
||||
-- No players in coalition, send default language message
|
||||
local defaultText = ZONE_CAPTURE_LANGUAGES[LANGUAGE_CONFIG.defaultLanguage][messageKey]
|
||||
if params then
|
||||
defaultText = string.format(defaultText, unpack(params))
|
||||
end
|
||||
commandCenter:MessageTypeToCoalition(defaultText, MESSAGE.Type.Information, duration)
|
||||
return
|
||||
end
|
||||
|
||||
-- Group players by language preference
|
||||
local languageGroups = {}
|
||||
for _, unit in ipairs(playerList) do
|
||||
if unit then
|
||||
local playerName = unit:getPlayerName()
|
||||
if playerName then
|
||||
local lang = GetPlayerLanguage(playerName)
|
||||
if not languageGroups[lang] then
|
||||
languageGroups[lang] = {}
|
||||
end
|
||||
table.insert(languageGroups[lang], playerName)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Send message in each language to respective players
|
||||
for lang, players in pairs(languageGroups) do
|
||||
local langTable = ZONE_CAPTURE_LANGUAGES[lang] or ZONE_CAPTURE_LANGUAGES.EN
|
||||
local text = langTable[messageKey]
|
||||
if params then
|
||||
text = string.format(text, unpack(params))
|
||||
end
|
||||
|
||||
-- For now, send to entire coalition (MOOSE doesn't support per-player filtering easily)
|
||||
-- This is a limitation, but better than nothing
|
||||
commandCenter:MessageTypeToCoalition(text, MESSAGE.Type.Information, duration)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ==========================================
|
||||
-- END OF CONFIGURATION
|
||||
-- ==========================================
|
||||
@@ -607,16 +994,16 @@ local function OnEnterGuarded(ZoneCapture, From, Event, To)
|
||||
ZoneCapture:UndrawZone()
|
||||
local color = ZONE_COLORS.BLUE_CAPTURED
|
||||
ZoneCapture:DrawZone(-1, {0, 0, 0}, 1, color, 0.2, 2, true)
|
||||
US_CC:MessageTypeToCoalition( string.format( "%s is under protection of the %s", ZoneCapture:GetZoneName(), COALITION_TITLES.BLUE ), MESSAGE.Type.Information, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION )
|
||||
RU_CC:MessageTypeToCoalition( string.format( "%s is under protection of the %s", ZoneCapture:GetZoneName(), COALITION_TITLES.BLUE ), MESSAGE.Type.Information, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION )
|
||||
MessageToCoalition(US_CC, "zoneGuarded", {ZoneCapture:GetZoneName(), COALITION_TITLES.BLUE}, coalition.side.BLUE, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION)
|
||||
MessageToCoalition(RU_CC, "zoneGuarded", {ZoneCapture:GetZoneName(), COALITION_TITLES.BLUE}, coalition.side.RED, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION)
|
||||
else
|
||||
ZoneCapture:Smoke( SMOKECOLOR.Red )
|
||||
-- Update zone visual markers to RED
|
||||
ZoneCapture:UndrawZone()
|
||||
local color = ZONE_COLORS.RED_CAPTURED
|
||||
ZoneCapture:DrawZone(-1, {0, 0, 0}, 1, color, 0.2, 2, true)
|
||||
RU_CC:MessageTypeToCoalition( string.format( "%s is under protection of the %s", ZoneCapture:GetZoneName(), COALITION_TITLES.RED ), MESSAGE.Type.Information, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION )
|
||||
US_CC:MessageTypeToCoalition( string.format( "%s is under protection of the %s", ZoneCapture:GetZoneName(), COALITION_TITLES.RED ), MESSAGE.Type.Information, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION )
|
||||
MessageToCoalition(RU_CC, "zoneGuarded", {ZoneCapture:GetZoneName(), COALITION_TITLES.RED}, coalition.side.RED, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION)
|
||||
MessageToCoalition(US_CC, "zoneGuarded", {ZoneCapture:GetZoneName(), COALITION_TITLES.RED}, coalition.side.BLUE, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION)
|
||||
end
|
||||
-- Create/update tactical information marker
|
||||
CreateTacticalInfoMarker(ZoneCapture)
|
||||
@@ -629,8 +1016,8 @@ local function OnEnterEmpty(ZoneCapture)
|
||||
ZoneCapture:UndrawZone()
|
||||
local color = ZONE_COLORS.EMPTY
|
||||
ZoneCapture:DrawZone(-1, {0, 0, 0}, 1, color, 0.2, 2, true)
|
||||
US_CC:MessageTypeToCoalition( string.format( "%s is unprotected, and can be captured!", ZoneCapture:GetZoneName() ), MESSAGE.Type.Information, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION )
|
||||
RU_CC:MessageTypeToCoalition( string.format( "%s is unprotected, and can be captured!", ZoneCapture:GetZoneName() ), MESSAGE.Type.Information, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION )
|
||||
MessageToCoalition(US_CC, "zoneEmpty", {ZoneCapture:GetZoneName()}, coalition.side.BLUE, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION)
|
||||
MessageToCoalition(RU_CC, "zoneEmpty", {ZoneCapture:GetZoneName()}, coalition.side.RED, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION)
|
||||
-- Create/update tactical information marker
|
||||
CreateTacticalInfoMarker(ZoneCapture)
|
||||
end
|
||||
@@ -643,12 +1030,12 @@ local function OnEnterAttacked(ZoneCapture)
|
||||
local color
|
||||
if Coalition == coalition.side.BLUE then
|
||||
color = ZONE_COLORS.BLUE_ATTACKED
|
||||
US_CC:MessageTypeToCoalition( string.format( "%s is under attack by %s", ZoneCapture:GetZoneName(), COALITION_TITLES.RED ), MESSAGE.Type.Information, MESSAGE_CONFIG.ATTACK_MESSAGE_DURATION )
|
||||
RU_CC:MessageTypeToCoalition( string.format( "We are attacking %s", ZoneCapture:GetZoneName() ), MESSAGE.Type.Information, MESSAGE_CONFIG.ATTACK_MESSAGE_DURATION )
|
||||
MessageToCoalition(US_CC, "zoneUnderAttack", {ZoneCapture:GetZoneName(), COALITION_TITLES.RED}, coalition.side.BLUE, MESSAGE_CONFIG.ATTACK_MESSAGE_DURATION)
|
||||
MessageToCoalition(RU_CC, "zoneWeAttacking", {ZoneCapture:GetZoneName()}, coalition.side.RED, MESSAGE_CONFIG.ATTACK_MESSAGE_DURATION)
|
||||
else
|
||||
color = ZONE_COLORS.RED_ATTACKED
|
||||
RU_CC:MessageTypeToCoalition( string.format( "%s is under attack by %s", ZoneCapture:GetZoneName(), COALITION_TITLES.BLUE ), MESSAGE.Type.Information, MESSAGE_CONFIG.ATTACK_MESSAGE_DURATION )
|
||||
US_CC:MessageTypeToCoalition( string.format( "We are attacking %s", ZoneCapture:GetZoneName() ), MESSAGE.Type.Information, MESSAGE_CONFIG.ATTACK_MESSAGE_DURATION )
|
||||
MessageToCoalition(RU_CC, "zoneUnderAttack", {ZoneCapture:GetZoneName(), COALITION_TITLES.BLUE}, coalition.side.RED, MESSAGE_CONFIG.ATTACK_MESSAGE_DURATION)
|
||||
MessageToCoalition(US_CC, "zoneWeAttacking", {ZoneCapture:GetZoneName()}, coalition.side.BLUE, MESSAGE_CONFIG.ATTACK_MESSAGE_DURATION)
|
||||
end
|
||||
ZoneCapture:DrawZone(-1, {0, 0, 0}, 1, color, 0.2, 2, true)
|
||||
-- Create/update tactical information marker
|
||||
@@ -679,18 +1066,8 @@ local function CheckVictoryCondition()
|
||||
if blueZonesCount >= totalZones then
|
||||
log("[VICTORY] All zones captured by BLUE! Triggering victory sequence...")
|
||||
|
||||
US_CC:MessageTypeToCoalition(
|
||||
"VICTORY! All capture zones have been secured by " .. COALITION_TITLES.BLUE .. " forces!\n\n" ..
|
||||
COALITION_TITLES.BLUE_OPERATION .. " is complete. Outstanding work!\n" ..
|
||||
"Mission will end in 60 seconds.",
|
||||
MESSAGE.Type.Information, MESSAGE_CONFIG.VICTORY_MESSAGE_DURATION
|
||||
)
|
||||
|
||||
RU_CC:MessageTypeToCoalition(
|
||||
"DEFEAT! All strategic positions have been lost to " .. COALITION_TITLES.BLUE .. " forces.\n\n" ..
|
||||
COALITION_TITLES.BLUE_OPERATION .. " has failed. Mission ending in 60 seconds.",
|
||||
MESSAGE.Type.Information, MESSAGE_CONFIG.VICTORY_MESSAGE_DURATION
|
||||
)
|
||||
MessageToCoalition(US_CC, "victoryBlue", {COALITION_TITLES.BLUE, COALITION_TITLES.BLUE_OPERATION}, coalition.side.BLUE, MESSAGE_CONFIG.VICTORY_MESSAGE_DURATION)
|
||||
MessageToCoalition(RU_CC, "defeatBlue", {COALITION_TITLES.BLUE, COALITION_TITLES.BLUE_OPERATION}, coalition.side.RED, MESSAGE_CONFIG.VICTORY_MESSAGE_DURATION)
|
||||
|
||||
-- Add victory celebration effects
|
||||
for _, zoneCapture in ipairs(zoneCaptureObjects) do
|
||||
@@ -707,10 +1084,7 @@ local function CheckVictoryCondition()
|
||||
log("[VICTORY] Ending mission due to complete zone capture by BLUE")
|
||||
trigger.action.setUserFlag("BLUE_VICTORY", 1)
|
||||
|
||||
US_CC:MessageTypeToCoalition(
|
||||
string.format("Mission Complete! Congratulations on your victory!\nFinal Status: All %d strategic zones secured.", totalZones),
|
||||
MESSAGE.Type.Information, 10
|
||||
)
|
||||
MessageToCoalition(US_CC, "missionComplete", {totalZones}, coalition.side.BLUE, 10)
|
||||
end, {}, 60 )
|
||||
|
||||
return true
|
||||
@@ -720,18 +1094,8 @@ local function CheckVictoryCondition()
|
||||
if redZonesCount >= totalZones then
|
||||
log("[VICTORY] All zones captured by RED! Triggering victory sequence...")
|
||||
|
||||
RU_CC:MessageTypeToCoalition(
|
||||
"VICTORY! All strategic positions secured for " .. COALITION_TITLES.RED_OPERATION .. "!\n\n" ..
|
||||
COALITION_TITLES.BLUE .. " forces have been repelled. Outstanding work!\n" ..
|
||||
"Mission will end in 60 seconds.",
|
||||
MESSAGE.Type.Information, MESSAGE_CONFIG.VICTORY_MESSAGE_DURATION
|
||||
)
|
||||
|
||||
US_CC:MessageTypeToCoalition(
|
||||
"DEFEAT! All capture zones have been lost to " .. COALITION_TITLES.RED .. " forces.\n\n" ..
|
||||
COALITION_TITLES.BLUE_OPERATION .. " has failed. Mission ending in 60 seconds.",
|
||||
MESSAGE.Type.Information, MESSAGE_CONFIG.VICTORY_MESSAGE_DURATION
|
||||
)
|
||||
MessageToCoalition(RU_CC, "victoryRed", {COALITION_TITLES.RED_OPERATION, COALITION_TITLES.BLUE}, coalition.side.RED, MESSAGE_CONFIG.VICTORY_MESSAGE_DURATION)
|
||||
MessageToCoalition(US_CC, "defeatRed", {COALITION_TITLES.RED, COALITION_TITLES.BLUE_OPERATION}, coalition.side.BLUE, MESSAGE_CONFIG.VICTORY_MESSAGE_DURATION)
|
||||
|
||||
-- Add victory celebration effects
|
||||
for _, zoneCapture in ipairs(zoneCaptureObjects) do
|
||||
@@ -748,10 +1112,7 @@ local function CheckVictoryCondition()
|
||||
log("[VICTORY] Ending mission due to complete zone capture by RED")
|
||||
trigger.action.setUserFlag("RED_VICTORY", 1)
|
||||
|
||||
RU_CC:MessageTypeToCoalition(
|
||||
string.format("Mission Complete! Congratulations on your victory!\nFinal Status: All %d strategic zones secured.", totalZones),
|
||||
MESSAGE.Type.Information, 10
|
||||
)
|
||||
MessageToCoalition(RU_CC, "missionComplete", {totalZones}, coalition.side.RED, 10)
|
||||
end, {}, 60 )
|
||||
|
||||
return true
|
||||
@@ -767,15 +1128,15 @@ local function OnEnterCaptured(ZoneCapture)
|
||||
ZoneCapture:UndrawZone()
|
||||
local color = ZONE_COLORS.BLUE_CAPTURED
|
||||
ZoneCapture:DrawZone(-1, {0, 0, 0}, 1, color, 0.2, 2, true)
|
||||
RU_CC:MessageTypeToCoalition( string.format( "%s is captured by the %s, we lost it!", ZoneCapture:GetZoneName(), COALITION_TITLES.BLUE ), MESSAGE.Type.Information, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION )
|
||||
US_CC:MessageTypeToCoalition( string.format( "We captured %s, Excellent job!", ZoneCapture:GetZoneName() ), MESSAGE.Type.Information, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION )
|
||||
MessageToCoalition(RU_CC, "zoneCapturedByEnemy", {ZoneCapture:GetZoneName(), COALITION_TITLES.BLUE}, coalition.side.RED, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION)
|
||||
MessageToCoalition(US_CC, "zoneCapturedByUs", {ZoneCapture:GetZoneName()}, coalition.side.BLUE, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION)
|
||||
else
|
||||
-- Update zone visual markers to RED for captured
|
||||
ZoneCapture:UndrawZone()
|
||||
local color = ZONE_COLORS.RED_CAPTURED
|
||||
ZoneCapture:DrawZone(-1, {0, 0, 0}, 1, color, 0.2, 2, true)
|
||||
US_CC:MessageTypeToCoalition( string.format( "%s is captured by the %s, we lost it!", ZoneCapture:GetZoneName(), COALITION_TITLES.RED ), MESSAGE.Type.Information, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION )
|
||||
RU_CC:MessageTypeToCoalition( string.format( "We captured %s, Excellent job!", ZoneCapture:GetZoneName() ), MESSAGE.Type.Information, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION )
|
||||
MessageToCoalition(US_CC, "zoneCapturedByEnemy", {ZoneCapture:GetZoneName(), COALITION_TITLES.RED}, coalition.side.BLUE, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION)
|
||||
MessageToCoalition(RU_CC, "zoneCapturedByUs", {ZoneCapture:GetZoneName()}, coalition.side.RED, MESSAGE_CONFIG.CAPTURE_MESSAGE_DURATION)
|
||||
end
|
||||
|
||||
ZoneCapture:AddScore( "Captured", "Zone captured: Extra points granted.", ZONE_SETTINGS.captureScore )
|
||||
@@ -908,36 +1269,60 @@ end
|
||||
local function BroadcastZoneStatus()
|
||||
local status = GetZoneOwnershipStatus()
|
||||
|
||||
-- Build coalition-neutral report
|
||||
local reportMessage = string.format(
|
||||
"ZONE CONTROL REPORT:\n" ..
|
||||
"Blue Coalition: %d/%d zones\n" ..
|
||||
"Red Coalition: %d/%d zones\n" ..
|
||||
"Neutral: %d/%d zones",
|
||||
-- Build report for BLUE coalition in their language
|
||||
local bluePlayerList = coalition.getPlayers(coalition.side.BLUE)
|
||||
local bluePlayerName = nil
|
||||
if bluePlayerList and #bluePlayerList > 0 then
|
||||
local unit = Unit.getByName(Unit.getName(bluePlayerList[1]))
|
||||
if unit then
|
||||
bluePlayerName = unit:getPlayerName()
|
||||
end
|
||||
end
|
||||
|
||||
local blueReportMessage = string.format(
|
||||
GetText("zoneControlReport", bluePlayerName),
|
||||
status.blue, status.total,
|
||||
status.red, status.total,
|
||||
status.neutral, status.total
|
||||
)
|
||||
|
||||
-- Add detailed zone status
|
||||
local detailMessage = "\nZONE DETAILS:\n"
|
||||
local blueDetailMessage = GetText("zoneDetails", bluePlayerName)
|
||||
for zoneName, owner in pairs(status.zones) do
|
||||
detailMessage = detailMessage .. string.format("• %s: %s\n", zoneName, owner)
|
||||
blueDetailMessage = blueDetailMessage .. string.format(GetText("zoneDetailLine", bluePlayerName), zoneName, owner)
|
||||
end
|
||||
|
||||
local fullMessage = reportMessage .. detailMessage
|
||||
|
||||
-- Broadcast to BOTH coalitions with their specific victory progress
|
||||
local totalZones = math.max(status.total, 1)
|
||||
local blueProgressPercent = math.floor((status.blue / totalZones) * 100)
|
||||
local blueFullMessage = fullMessage .. string.format("\n\nYour Progress to Victory: %d%%", blueProgressPercent)
|
||||
local blueFullMessage = blueReportMessage .. blueDetailMessage .. string.format(GetText("yourProgress", bluePlayerName), blueProgressPercent)
|
||||
US_CC:MessageTypeToCoalition( blueFullMessage, MESSAGE.Type.Information, MESSAGE_CONFIG.STATUS_MESSAGE_DURATION )
|
||||
|
||||
-- Build report for RED coalition in their language
|
||||
local redPlayerList = coalition.getPlayers(coalition.side.RED)
|
||||
local redPlayerName = nil
|
||||
if redPlayerList and #redPlayerList > 0 then
|
||||
local unit = Unit.getByName(Unit.getName(redPlayerList[1]))
|
||||
if unit then
|
||||
redPlayerName = unit:getPlayerName()
|
||||
end
|
||||
end
|
||||
|
||||
local redReportMessage = string.format(
|
||||
GetText("zoneControlReport", redPlayerName),
|
||||
status.blue, status.total,
|
||||
status.red, status.total,
|
||||
status.neutral, status.total
|
||||
)
|
||||
|
||||
local redDetailMessage = GetText("zoneDetails", redPlayerName)
|
||||
for zoneName, owner in pairs(status.zones) do
|
||||
redDetailMessage = redDetailMessage .. string.format(GetText("zoneDetailLine", redPlayerName), zoneName, owner)
|
||||
end
|
||||
|
||||
local redProgressPercent = math.floor((status.red / totalZones) * 100)
|
||||
local redFullMessage = fullMessage .. string.format("\n\nYour Progress to Victory: %d%%", redProgressPercent)
|
||||
local redFullMessage = redReportMessage .. redDetailMessage .. string.format(GetText("yourProgress", redPlayerName), redProgressPercent)
|
||||
RU_CC:MessageTypeToCoalition( redFullMessage, MESSAGE.Type.Information, MESSAGE_CONFIG.STATUS_MESSAGE_DURATION )
|
||||
|
||||
log("[ZONE STATUS] " .. reportMessage:gsub("\n", " | "))
|
||||
log("[ZONE STATUS] Blue:" .. status.blue .. "/" .. status.total .. " Red:" .. status.red .. "/" .. status.total)
|
||||
|
||||
return status
|
||||
end
|
||||
@@ -948,32 +1333,16 @@ local ZoneMonitorScheduler = SCHEDULER:New( nil, function()
|
||||
|
||||
-- Check if BLUE is close to victory (80% or more zones captured)
|
||||
if status.blue >= math.floor(status.total * 0.8) and status.blue < status.total then
|
||||
US_CC:MessageTypeToCoalition(
|
||||
string.format("APPROACHING VICTORY! %d more zone(s) needed for complete success!",
|
||||
status.total - status.blue),
|
||||
MESSAGE.Type.Information, MESSAGE_CONFIG.VICTORY_MESSAGE_DURATION
|
||||
)
|
||||
|
||||
RU_CC:MessageTypeToCoalition(
|
||||
string.format("CRITICAL SITUATION! %s forces control %d/%d zones! We must recapture territory!",
|
||||
COALITION_TITLES.BLUE, status.blue, status.total),
|
||||
MESSAGE.Type.Information, MESSAGE_CONFIG.VICTORY_MESSAGE_DURATION
|
||||
)
|
||||
local bluePercent = math.floor((status.blue / status.total) * 100)
|
||||
MessageToCoalition(US_CC, "blueNearVictory", {COALITION_TITLES.BLUE, bluePercent}, coalition.side.BLUE, MESSAGE_CONFIG.VICTORY_MESSAGE_DURATION)
|
||||
MessageToCoalition(RU_CC, "redNearVictory", {COALITION_TITLES.BLUE, bluePercent}, coalition.side.RED, MESSAGE_CONFIG.VICTORY_MESSAGE_DURATION)
|
||||
end
|
||||
|
||||
-- Check if RED is close to victory (80% or more zones captured)
|
||||
if status.red >= math.floor(status.total * 0.8) and status.red < status.total then
|
||||
RU_CC:MessageTypeToCoalition(
|
||||
string.format("APPROACHING VICTORY! %d more zone(s) needed for complete success!",
|
||||
status.total - status.red),
|
||||
MESSAGE.Type.Information, MESSAGE_CONFIG.VICTORY_MESSAGE_DURATION
|
||||
)
|
||||
|
||||
US_CC:MessageTypeToCoalition(
|
||||
string.format("CRITICAL SITUATION! %s forces control %d/%d zones! We must recapture territory!",
|
||||
COALITION_TITLES.RED, status.red, status.total),
|
||||
MESSAGE.Type.Information, MESSAGE_CONFIG.VICTORY_MESSAGE_DURATION
|
||||
)
|
||||
local redPercent = math.floor((status.red / status.total) * 100)
|
||||
MessageToCoalition(RU_CC, "blueNearVictory", {COALITION_TITLES.RED, redPercent}, coalition.side.RED, MESSAGE_CONFIG.VICTORY_MESSAGE_DURATION)
|
||||
MessageToCoalition(US_CC, "redNearVictory", {COALITION_TITLES.RED, redPercent}, coalition.side.BLUE, MESSAGE_CONFIG.VICTORY_MESSAGE_DURATION)
|
||||
end
|
||||
|
||||
end, {}, MESSAGE_CONFIG.STATUS_BROADCAST_START_DELAY, MESSAGE_CONFIG.STATUS_BROADCAST_FREQUENCY )
|
||||
@@ -1086,81 +1455,188 @@ local function RefreshAllZoneColors()
|
||||
end
|
||||
|
||||
-- Notify BOTH coalitions
|
||||
US_CC:MessageTypeToCoalition("Zone visual markers have been refreshed!", MESSAGE.Type.Information, MESSAGE_CONFIG.STATUS_MESSAGE_DURATION)
|
||||
RU_CC:MessageTypeToCoalition("Zone visual markers have been refreshed!", MESSAGE.Type.Information, MESSAGE_CONFIG.STATUS_MESSAGE_DURATION)
|
||||
MessageToCoalition(US_CC, "zoneMarkersRefreshed", nil, coalition.side.BLUE, MESSAGE_CONFIG.STATUS_MESSAGE_DURATION)
|
||||
MessageToCoalition(RU_CC, "zoneMarkersRefreshed", nil, coalition.side.RED, MESSAGE_CONFIG.STATUS_MESSAGE_DURATION)
|
||||
end
|
||||
|
||||
-- Manual zone status commands for players (F10 radio menu) - BOTH COALITIONS
|
||||
local function SetupZoneStatusCommands()
|
||||
-- Add F10 radio menu commands for BLUE coalition
|
||||
if US_CC then
|
||||
-- Use MenuManager to create zone control menu under Mission Options
|
||||
local USMenu = MenuManager and MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "Zone Control")
|
||||
or MENU_COALITION:New( coalition.side.BLUE, "Zone Control" )
|
||||
MENU_COALITION_COMMAND:New( coalition.side.BLUE, "Get Zone Status Report", USMenu, BroadcastZoneStatus )
|
||||
|
||||
MENU_COALITION_COMMAND:New( coalition.side.BLUE, "Check Victory Progress", USMenu, function()
|
||||
local status = GetZoneOwnershipStatus()
|
||||
local totalZones = math.max(status.total, 1)
|
||||
local progressPercent = math.floor((status.blue / totalZones) * 100)
|
||||
|
||||
US_CC:MessageTypeToCoalition(
|
||||
string.format(
|
||||
"VICTORY PROGRESS: %d%%\n" ..
|
||||
"Zones Captured: %d/%d\n" ..
|
||||
"Remaining: %d zones\n\n" ..
|
||||
"%s",
|
||||
progressPercent,
|
||||
status.blue, status.total,
|
||||
status.total - status.blue,
|
||||
progressPercent >= 100 and "MISSION COMPLETE!" or
|
||||
progressPercent >= 80 and "ALMOST THERE!" or
|
||||
progressPercent >= 50 and "GOOD PROGRESS!" or
|
||||
"KEEP FIGHTING!"
|
||||
),
|
||||
MESSAGE.Type.Information, MESSAGE_CONFIG.STATUS_MESSAGE_DURATION
|
||||
)
|
||||
end )
|
||||
|
||||
-- Add command to refresh zone colors (troubleshooting tool)
|
||||
MENU_COALITION_COMMAND:New( coalition.side.BLUE, "Refresh Zone Colors", USMenu, RefreshAllZoneColors )
|
||||
-- NOTE: All menus are now created per-player in CreatePlayerLanguageMenu() function below
|
||||
-- No coalition-wide menus needed
|
||||
|
||||
-- ==========================================
|
||||
-- PER-PLAYER MENU SETUP (ALL ZONE CONTROL FUNCTIONS)
|
||||
-- ==========================================
|
||||
-- Track player menus to avoid duplicates per group
|
||||
-- Key format: "playerName|groupName" to handle aircraft switches
|
||||
local playerMenus = {}
|
||||
|
||||
-- Function to create complete Zone Control menu for a specific player
|
||||
local function CreatePlayerMenu(playerUnit)
|
||||
env.info("[MENU DEBUG] CreatePlayerMenu called")
|
||||
if not playerUnit then
|
||||
env.info("[MENU DEBUG] No playerUnit")
|
||||
return
|
||||
end
|
||||
|
||||
-- Add F10 radio menu commands for RED coalition
|
||||
if RU_CC then
|
||||
-- Use MenuManager to create zone control menu under Mission Options
|
||||
local RUMenu = MenuManager and MenuManager.CreateCoalitionMenu(coalition.side.RED, "Zone Control")
|
||||
or MENU_COALITION:New( coalition.side.RED, "Zone Control" )
|
||||
MENU_COALITION_COMMAND:New( coalition.side.RED, "Get Zone Status Report", RUMenu, BroadcastZoneStatus )
|
||||
local playerName = playerUnit:getPlayerName()
|
||||
env.info(string.format("[MENU DEBUG] PlayerName: %s", tostring(playerName)))
|
||||
if not playerName then return end
|
||||
|
||||
-- Get DCS group and convert to MOOSE GROUP wrapper
|
||||
local dcsGroup = playerUnit:getGroup()
|
||||
env.info(string.format("[MENU DEBUG] DCS Group: %s", tostring(dcsGroup and dcsGroup:getName() or "nil")))
|
||||
if not dcsGroup then return end
|
||||
|
||||
local groupName = dcsGroup:getName()
|
||||
local group = GROUP:FindByName(groupName)
|
||||
env.info(string.format("[MENU DEBUG] MOOSE Group found: %s", tostring(group ~= nil)))
|
||||
if not group then return end
|
||||
|
||||
local menuKey = playerName .. "|" .. groupName
|
||||
|
||||
-- Don't create duplicate menus for same player in same group
|
||||
if playerMenus[menuKey] then
|
||||
env.info(string.format("[MENU DEBUG] Menu already exists for %s", menuKey))
|
||||
return
|
||||
end
|
||||
|
||||
local playerCoalition = playerUnit:getCoalition()
|
||||
|
||||
-- Get appropriate command center
|
||||
local commandCenter = playerCoalition == coalition.side.BLUE and US_CC or RU_CC
|
||||
if not commandCenter then
|
||||
env.info("[MENU DEBUG] No command center found")
|
||||
return
|
||||
end
|
||||
|
||||
env.info(string.format("[MENU] Creating Zone Control menu for player %s (group: %s)", playerName, groupName))
|
||||
|
||||
-- Create Zone Control root menu (use GROUP object, not group name string)
|
||||
-- Use MenuManager if available to nest under "Mission Options"
|
||||
local zoneControlMenu = MenuManager and MenuManager.CreateGroupMenu(group, GetText("menuZoneControl", playerName))
|
||||
or MENU_GROUP:New(group, GetText("menuZoneControl", playerName))
|
||||
|
||||
-- Add Zone Status Report command
|
||||
MENU_GROUP_COMMAND:New(group, GetText("menuStatusReport", playerName), zoneControlMenu, function()
|
||||
BroadcastZoneStatus()
|
||||
end)
|
||||
|
||||
-- Add Victory Progress command
|
||||
MENU_GROUP_COMMAND:New(group, GetText("menuVictoryProgress", playerName), zoneControlMenu, function()
|
||||
local status = GetZoneOwnershipStatus()
|
||||
local totalZones = math.max(status.total, 1)
|
||||
local progressPercent = 0
|
||||
|
||||
MENU_COALITION_COMMAND:New( coalition.side.RED, "Check Victory Progress", RUMenu, function()
|
||||
local status = GetZoneOwnershipStatus()
|
||||
local totalZones = math.max(status.total, 1)
|
||||
local progressPercent = math.floor((status.red / totalZones) * 100)
|
||||
|
||||
RU_CC:MessageTypeToCoalition(
|
||||
string.format(
|
||||
"VICTORY PROGRESS: %d%%\n" ..
|
||||
"Zones Captured: %d/%d\n" ..
|
||||
"Remaining: %d zones\n\n" ..
|
||||
"%s",
|
||||
progressPercent,
|
||||
status.red, status.total,
|
||||
status.total - status.red,
|
||||
progressPercent >= 100 and "MISSION COMPLETE!" or
|
||||
progressPercent >= 80 and "ALMOST THERE!" or
|
||||
progressPercent >= 50 and "GOOD PROGRESS!" or
|
||||
"KEEP FIGHTING!"
|
||||
),
|
||||
MESSAGE.Type.Information, MESSAGE_CONFIG.STATUS_MESSAGE_DURATION
|
||||
)
|
||||
end )
|
||||
-- Calculate progress based on player's coalition
|
||||
if playerCoalition == coalition.side.BLUE then
|
||||
progressPercent = math.floor((status.blue / totalZones) * 100)
|
||||
else
|
||||
progressPercent = math.floor((status.red / totalZones) * 100)
|
||||
end
|
||||
|
||||
-- Add command to refresh zone colors (troubleshooting tool)
|
||||
MENU_COALITION_COMMAND:New( coalition.side.RED, "Refresh Zone Colors", RUMenu, RefreshAllZoneColors )
|
||||
-- Determine progress message based on percentage
|
||||
local progressMsg
|
||||
if progressPercent >= 100 then
|
||||
progressMsg = GetText("progressComplete", playerName)
|
||||
elseif progressPercent >= 80 then
|
||||
progressMsg = GetText("progressAlmostThere", playerName)
|
||||
elseif progressPercent >= 50 then
|
||||
progressMsg = GetText("progressGood", playerName)
|
||||
else
|
||||
progressMsg = GetText("progressKeepFighting", playerName)
|
||||
end
|
||||
|
||||
local zonesCaptured = playerCoalition == coalition.side.BLUE and status.blue or status.red
|
||||
local zonesRemaining = status.total - zonesCaptured
|
||||
|
||||
MESSAGE:New(
|
||||
string.format(
|
||||
"%s\n%s\n%s\n\n%s",
|
||||
string.format(GetText("victoryProgressTitle", playerName), progressPercent),
|
||||
string.format(GetText("zonesCaptured", playerName), zonesCaptured, status.total),
|
||||
string.format(GetText("zonesRemaining", playerName), zonesRemaining),
|
||||
progressMsg
|
||||
),
|
||||
MESSAGE_CONFIG.STATUS_MESSAGE_DURATION
|
||||
):ToGroup(group)
|
||||
end)
|
||||
|
||||
-- Add Refresh Zone Colors command
|
||||
MENU_GROUP_COMMAND:New(group, GetText("menuRefreshColors", playerName), zoneControlMenu, function()
|
||||
RefreshAllZoneColors()
|
||||
end)
|
||||
|
||||
-- Create Language submenu
|
||||
local langMenu = MENU_GROUP:New(group, GetText("menuLanguage", playerName), zoneControlMenu)
|
||||
|
||||
-- Add language options
|
||||
MENU_GROUP_COMMAND:New(group, GetText("menuEnglish", playerName), langMenu, function()
|
||||
SetPlayerLanguage(playerName, "EN")
|
||||
MESSAGE:New(GetText("languageChanged", playerName), 5):ToGroup(group)
|
||||
end)
|
||||
|
||||
MENU_GROUP_COMMAND:New(group, GetText("menuGerman", playerName), langMenu, function()
|
||||
SetPlayerLanguage(playerName, "DE")
|
||||
MESSAGE:New(GetText("languageChanged", playerName), 5):ToGroup(group)
|
||||
end)
|
||||
|
||||
MENU_GROUP_COMMAND:New(group, GetText("menuFrench", playerName), langMenu, function()
|
||||
SetPlayerLanguage(playerName, "FR")
|
||||
MESSAGE:New(GetText("languageChanged", playerName), 5):ToGroup(group)
|
||||
end)
|
||||
|
||||
MENU_GROUP_COMMAND:New(group, GetText("menuSpanish", playerName), langMenu, function()
|
||||
SetPlayerLanguage(playerName, "ES")
|
||||
MESSAGE:New(GetText("languageChanged", playerName), 5):ToGroup(group)
|
||||
end)
|
||||
|
||||
MENU_GROUP_COMMAND:New(group, GetText("menuRussian", playerName), langMenu, function()
|
||||
SetPlayerLanguage(playerName, "RU")
|
||||
MESSAGE:New(GetText("languageChanged", playerName), 5):ToGroup(group)
|
||||
end)
|
||||
|
||||
playerMenus[menuKey] = true
|
||||
log(string.format("[MENU] Zone Control menu created for %s in group %s", playerName, groupName))
|
||||
end
|
||||
|
||||
-- Event handler to create player menus when players spawn
|
||||
local function OnPlayerBirth(event)
|
||||
env.info(string.format("[MENU DEBUG] OnPlayerBirth called, event id: %s", tostring(event.id)))
|
||||
if event.id == world.event.S_EVENT_BIRTH and event.initiator then
|
||||
local unit = event.initiator
|
||||
local playerName = unit and unit:getPlayerName()
|
||||
env.info(string.format("[MENU DEBUG] Birth event for player: %s", tostring(playerName)))
|
||||
if unit and playerName then
|
||||
-- Small delay to ensure everything is initialized
|
||||
timer.scheduleFunction(function()
|
||||
CreatePlayerMenu(unit)
|
||||
end, nil, timer.getTime() + 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Set up event handler
|
||||
world.addEventHandler({
|
||||
onEvent = OnPlayerBirth
|
||||
})
|
||||
|
||||
-- Create menus for any players already in the mission
|
||||
timer.scheduleFunction(function()
|
||||
env.info("[MENU] Checking for existing players...")
|
||||
for _, coalitionSide in pairs({coalition.side.BLUE, coalition.side.RED}) do
|
||||
local players = coalition.getPlayers(coalitionSide)
|
||||
env.info(string.format("[MENU DEBUG] Found %d players in coalition %d", players and #players or 0, coalitionSide))
|
||||
if players then
|
||||
for _, unit in ipairs(players) do
|
||||
local playerName = unit and unit:getPlayerName()
|
||||
env.info(string.format("[MENU DEBUG] Processing existing player: %s", tostring(playerName)))
|
||||
if unit and playerName then
|
||||
CreatePlayerMenu(unit)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end, nil, timer.getTime() + 5)
|
||||
|
||||
-- Initialize zone status monitoring
|
||||
SCHEDULER:New( nil, function()
|
||||
log("[VICTORY SYSTEM] Initializing zone monitoring system...")
|
||||
@@ -1168,7 +1644,7 @@ SCHEDULER:New( nil, function()
|
||||
-- Initialize performance optimization caches
|
||||
InitializeCachedUnitSet()
|
||||
|
||||
SetupZoneStatusCommands()
|
||||
-- Note: All menus are created per-player via event handlers
|
||||
|
||||
-- Initial status report
|
||||
SCHEDULER:New( nil, function()
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -192,6 +192,318 @@ local blueArmorTemplates = {
|
||||
-- DO NOT EDIT BELOW THIS LINE
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- ==========================================
|
||||
-- MULTILINGUAL SUPPORT (uses main script's language settings)
|
||||
-- ==========================================
|
||||
-- This plugin uses the playerLanguages table from Moose_DualCoalitionZoneCapture.lua
|
||||
-- Players set their language preference in the main script's F10 menu
|
||||
|
||||
local DGB_LANGUAGES = {
|
||||
EN = {
|
||||
-- Warehouse messages
|
||||
warehouseStatus = "[Warehouse Status]\nRed warehouses alive: %d Reinforcements: %d%%\nBlue warehouses alive: %d Reinforcements: %d%%\n",
|
||||
reinforcementCapacity = "%s reinforcement capacity: %d%%",
|
||||
warehouseFriendly = "Warehouse: %s\nThis warehouse needs to be protected.\n",
|
||||
warehouseEnemy = "Warehouse: %s\nThis is a primary target as it is directly supplying enemy units.\n",
|
||||
|
||||
-- Menu items
|
||||
menuGroundBattle = "Ground Battle",
|
||||
menuWarehouseStatus = "Check Warehouse Status",
|
||||
menuSystemStats = "Show System Statistics",
|
||||
|
||||
-- System statistics
|
||||
statsTitle = "DYNAMIC GROUND BATTLE - SYSTEM STATUS",
|
||||
statsConfiguration = "【CONFIGURATION】",
|
||||
statsDefendersPerZone = " Defenders per Zone: %d",
|
||||
statsDefenderRotation = " Defender Rotation: %s",
|
||||
statsInfantryMovement = " Infantry Movement: %s",
|
||||
statsTaskReassignment = " Task Reassignment: Every %ds",
|
||||
statsWarehouseMarkers = " Warehouse Markers: %s",
|
||||
statsSpawnLimits = "【SPAWN LIMITS】",
|
||||
statsRedInfantry = " Red Infantry: %d/%d",
|
||||
statsRedArmor = " Red Armor: %d/%d",
|
||||
statsBlueInfantry = " Blue Infantry: %d/%d",
|
||||
statsBlueArmor = " Blue Armor: %d/%d",
|
||||
statsRedCoalition = "【RED COALITION】",
|
||||
statsBlueCoalition = "【BLUE COALITION】",
|
||||
statsWarehouses = " Warehouses: %d/%d (%d%%)",
|
||||
statsActiveUnits = " Active Units: %d (%d inf, %d armor)",
|
||||
statsDefenders = " Defenders: %d | Mobile: %d",
|
||||
statsControlledZones = " Controlled Zones: %d",
|
||||
statsGarrisoned = " - Garrisoned: %d",
|
||||
statsUnderGarrisoned = " - Under-Garrisoned: %d",
|
||||
statsInfantrySpawn = " Infantry Spawn: %ds",
|
||||
statsInfantrySpawnPaused = " Infantry Spawn: PAUSED (no warehouses)",
|
||||
statsArmorSpawn = " Armor Spawn: %ds",
|
||||
statsArmorSpawnPaused = " Armor Spawn: PAUSED (no warehouses)",
|
||||
statsSystemInfo = "【SYSTEM INFO】",
|
||||
statsTotalZones = " Total Zones: %d",
|
||||
statsActiveGarrisons = " Active Garrisons: %d",
|
||||
statsTotalActiveUnits = " Total Active Units: %d",
|
||||
statsTrackedGroups = " Tracked Groups: %d",
|
||||
statsLuaMemory = " Lua Memory: %.1f MB",
|
||||
statsWarningMemory = " ⚠️ WARNING: High memory usage!",
|
||||
statsWarningGroups = " ⚠️ WARNING: High group count!",
|
||||
enabled = "ENABLED",
|
||||
disabled = "DISABLED",
|
||||
},
|
||||
|
||||
DE = {
|
||||
-- Warehouse messages
|
||||
warehouseStatus = "[Lagerstatus]\nRote Lager aktiv: %d Verstärkungen: %d%%\nBlaue Lager aktiv: %d Verstärkungen: %d%%\n",
|
||||
reinforcementCapacity = "%s Verstärkungskapazität: %d%%",
|
||||
warehouseFriendly = "Lager: %s\nDieses Lager muss geschützt werden.\n",
|
||||
warehouseEnemy = "Lager: %s\nDies ist ein Hauptziel, da es feindliche Einheiten direkt versorgt.\n",
|
||||
|
||||
-- Menu items
|
||||
menuGroundBattle = "Bodenkampf",
|
||||
menuWarehouseStatus = "Lagerstatus prüfen",
|
||||
menuSystemStats = "Systemstatistiken anzeigen",
|
||||
|
||||
-- System statistics
|
||||
statsTitle = "DYNAMISCHER BODENKAMPF - SYSTEMSTATUS",
|
||||
statsConfiguration = "【KONFIGURATION】",
|
||||
statsDefendersPerZone = " Verteidiger pro Zone: %d",
|
||||
statsDefenderRotation = " Verteidiger-Rotation: %s",
|
||||
statsInfantryMovement = " Infanterie-Bewegung: %s",
|
||||
statsTaskReassignment = " Aufgabenzuweisung: Alle %ds",
|
||||
statsWarehouseMarkers = " Lagermarkierungen: %s",
|
||||
statsSpawnLimits = "【SPAWN-LIMITS】",
|
||||
statsRedInfantry = " Rote Infanterie: %d/%d",
|
||||
statsRedArmor = " Rote Panzer: %d/%d",
|
||||
statsBlueInfantry = " Blaue Infanterie: %d/%d",
|
||||
statsBlueArmor = " Blaue Panzer: %d/%d",
|
||||
statsRedCoalition = "【ROTE KOALITION】",
|
||||
statsBlueCoalition = "【BLAUE KOALITION】",
|
||||
statsWarehouses = " Lager: %d/%d (%d%%)",
|
||||
statsActiveUnits = " Aktive Einheiten: %d (%d Inf, %d Panzer)",
|
||||
statsDefenders = " Verteidiger: %d | Mobil: %d",
|
||||
statsControlledZones = " Kontrollierte Zonen: %d",
|
||||
statsGarrisoned = " - Besetzt: %d",
|
||||
statsUnderGarrisoned = " - Unterbesetzt: %d",
|
||||
statsInfantrySpawn = " Infanterie-Spawn: %ds",
|
||||
statsInfantrySpawnPaused = " Infanterie-Spawn: PAUSIERT (keine Lager)",
|
||||
statsArmorSpawn = " Panzer-Spawn: %ds",
|
||||
statsArmorSpawnPaused = " Panzer-Spawn: PAUSIERT (keine Lager)",
|
||||
statsSystemInfo = "【SYSTEMINFO】",
|
||||
statsTotalZones = " Zonen gesamt: %d",
|
||||
statsActiveGarrisons = " Aktive Garnisonen: %d",
|
||||
statsTotalActiveUnits = " Aktive Einheiten gesamt: %d",
|
||||
statsTrackedGroups = " Verfolgte Gruppen: %d",
|
||||
statsLuaMemory = " Lua-Speicher: %.1f MB",
|
||||
statsWarningMemory = " ⚠️ WARNUNG: Hoher Speicherverbrauch!",
|
||||
statsWarningGroups = " ⚠️ WARNUNG: Hohe Gruppenanzahl!",
|
||||
enabled = "AKTIVIERT",
|
||||
disabled = "DEAKTIVIERT",
|
||||
},
|
||||
|
||||
FR = {
|
||||
-- Warehouse messages
|
||||
warehouseStatus = "[Statut des entrepôts]\nEntrepôts rouges actifs : %d Renforts : %d%%\nEntrepôts bleus actifs : %d Renforts : %d%%\n",
|
||||
reinforcementCapacity = "Capacité de renfort %s : %d%%",
|
||||
warehouseFriendly = "Entrepôt : %s\nCet entrepôt doit être protégé.\n",
|
||||
warehouseEnemy = "Entrepôt : %s\nC'est une cible prioritaire car il approvisionne directement les unités ennemies.\n",
|
||||
|
||||
-- Menu items
|
||||
menuGroundBattle = "Combat terrestre",
|
||||
menuWarehouseStatus = "Vérifier le statut des entrepôts",
|
||||
menuSystemStats = "Afficher les statistiques système",
|
||||
|
||||
-- System statistics
|
||||
statsTitle = "COMBAT TERRESTRE DYNAMIQUE - ÉTAT DU SYSTÈME",
|
||||
statsConfiguration = "【CONFIGURATION】",
|
||||
statsDefendersPerZone = " Défenseurs par zone : %d",
|
||||
statsDefenderRotation = " Rotation des défenseurs : %s",
|
||||
statsInfantryMovement = " Mouvement infanterie : %s",
|
||||
statsTaskReassignment = " Réaffectation des tâches : Tous les %ds",
|
||||
statsWarehouseMarkers = " Marqueurs d'entrepôt : %s",
|
||||
statsSpawnLimits = "【LIMITES DE SPAWN】",
|
||||
statsRedInfantry = " Infanterie rouge : %d/%d",
|
||||
statsRedArmor = " Blindés rouges : %d/%d",
|
||||
statsBlueInfantry = " Infanterie bleue : %d/%d",
|
||||
statsBlueArmor = " Blindés bleus : %d/%d",
|
||||
statsRedCoalition = "【COALITION ROUGE】",
|
||||
statsBlueCoalition = "【COALITION BLEUE】",
|
||||
statsWarehouses = " Entrepôts : %d/%d (%d%%)",
|
||||
statsActiveUnits = " Unités actives : %d (%d inf, %d blindés)",
|
||||
statsDefenders = " Défenseurs : %d | Mobiles : %d",
|
||||
statsControlledZones = " Zones contrôlées : %d",
|
||||
statsGarrisoned = " - En garnison : %d",
|
||||
statsUnderGarrisoned = " - Sous-garnison : %d",
|
||||
statsInfantrySpawn = " Spawn infanterie : %ds",
|
||||
statsInfantrySpawnPaused = " Spawn infanterie : PAUSE (pas d'entrepôts)",
|
||||
statsArmorSpawn = " Spawn blindés : %ds",
|
||||
statsArmorSpawnPaused = " Spawn blindés : PAUSE (pas d'entrepôts)",
|
||||
statsSystemInfo = "【INFO SYSTÈME】",
|
||||
statsTotalZones = " Zones totales : %d",
|
||||
statsActiveGarrisons = " Garnisons actives : %d",
|
||||
statsTotalActiveUnits = " Unités actives totales : %d",
|
||||
statsTrackedGroups = " Groupes suivis : %d",
|
||||
statsLuaMemory = " Mémoire Lua : %.1f Mo",
|
||||
statsWarningMemory = " ⚠️ ATTENTION : Utilisation mémoire élevée !",
|
||||
statsWarningGroups = " ⚠️ ATTENTION : Nombre de groupes élevé !",
|
||||
enabled = "ACTIVÉ",
|
||||
disabled = "DÉSACTIVÉ",
|
||||
},
|
||||
|
||||
ES = {
|
||||
-- Warehouse messages
|
||||
warehouseStatus = "[Estado de almacenes]\nAlmacenes rojos activos: %d Refuerzos: %d%%\nAlmacenes azules activos: %d Refuerzos: %d%%\n",
|
||||
reinforcementCapacity = "Capacidad de refuerzo %s: %d%%",
|
||||
warehouseFriendly = "Almacén: %s\nEste almacén necesita ser protegido.\n",
|
||||
warehouseEnemy = "Almacén: %s\nEste es un objetivo prioritario ya que está suministrando directamente unidades enemigas.\n",
|
||||
|
||||
-- Menu items
|
||||
menuGroundBattle = "Batalla terrestre",
|
||||
menuWarehouseStatus = "Verificar estado de almacenes",
|
||||
menuSystemStats = "Mostrar estadísticas del sistema",
|
||||
|
||||
-- System statistics
|
||||
statsTitle = "BATALLA TERRESTRE DINÁMICA - ESTADO DEL SISTEMA",
|
||||
statsConfiguration = "【CONFIGURACIÓN】",
|
||||
statsDefendersPerZone = " Defensores por zona: %d",
|
||||
statsDefenderRotation = " Rotación de defensores: %s",
|
||||
statsInfantryMovement = " Movimiento de infantería: %s",
|
||||
statsTaskReassignment = " Reasignación de tareas: Cada %ds",
|
||||
statsWarehouseMarkers = " Marcadores de almacén: %s",
|
||||
statsSpawnLimits = "【LÍMITES DE APARICIÓN】",
|
||||
statsRedInfantry = " Infantería roja: %d/%d",
|
||||
statsRedArmor = " Blindados rojos: %d/%d",
|
||||
statsBlueInfantry = " Infantería azul: %d/%d",
|
||||
statsBlueArmor = " Blindados azules: %d/%d",
|
||||
statsRedCoalition = "【COALICIÓN ROJA】",
|
||||
statsBlueCoalition = "【COALICIÓN AZUL】",
|
||||
statsWarehouses = " Almacenes: %d/%d (%d%%)",
|
||||
statsActiveUnits = " Unidades activas: %d (%d inf, %d blindados)",
|
||||
statsDefenders = " Defensores: %d | Móviles: %d",
|
||||
statsControlledZones = " Zonas controladas: %d",
|
||||
statsGarrisoned = " - Guarnecidas: %d",
|
||||
statsUnderGarrisoned = " - Subguarnecidas: %d",
|
||||
statsInfantrySpawn = " Aparición infantería: %ds",
|
||||
statsInfantrySpawnPaused = " Aparición infantería: PAUSADA (sin almacenes)",
|
||||
statsArmorSpawn = " Aparición blindados: %ds",
|
||||
statsArmorSpawnPaused = " Aparición blindados: PAUSADA (sin almacenes)",
|
||||
statsSystemInfo = "【INFO DEL SISTEMA】",
|
||||
statsTotalZones = " Zonas totales: %d",
|
||||
statsActiveGarrisons = " Guarniciones activas: %d",
|
||||
statsTotalActiveUnits = " Unidades activas totales: %d",
|
||||
statsTrackedGroups = " Grupos rastreados: %d",
|
||||
statsLuaMemory = " Memoria Lua: %.1f MB",
|
||||
statsWarningMemory = " ⚠️ ADVERTENCIA: ¡Uso de memoria elevado!",
|
||||
statsWarningGroups = " ⚠️ ADVERTENCIA: ¡Cantidad de grupos elevada!",
|
||||
enabled = "HABILITADO",
|
||||
disabled = "DESHABILITADO",
|
||||
},
|
||||
|
||||
RU = {
|
||||
-- Warehouse messages
|
||||
warehouseStatus = "[Статус складов]\nКрасные склады активны: %d Подкрепления: %d%%\nСиние склады активны: %d Подкрепления: %d%%\n",
|
||||
reinforcementCapacity = "Мощность подкреплений %s: %d%%",
|
||||
warehouseFriendly = "Склад: %s\nЭтот склад нужно защищать.\n",
|
||||
warehouseEnemy = "Склад: %s\nЭто приоритетная цель, так как она напрямую снабжает вражеские подразделения.\n",
|
||||
|
||||
-- Menu items
|
||||
menuGroundBattle = "Наземный бой",
|
||||
menuWarehouseStatus = "Проверить статус складов",
|
||||
menuSystemStats = "Показать статистику системы",
|
||||
|
||||
-- System statistics
|
||||
statsTitle = "ДИНАМИЧЕСКИЙ НАЗЕМНЫЙ БОЙ - СТАТУС СИСТЕМЫ",
|
||||
statsConfiguration = "【КОНФИГУРАЦИЯ】",
|
||||
statsDefendersPerZone = " Защитников на зону: %d",
|
||||
statsDefenderRotation = " Ротация защитников: %s",
|
||||
statsInfantryMovement = " Движение пехоты: %s",
|
||||
statsTaskReassignment = " Переназначение задач: Каждые %ds",
|
||||
statsWarehouseMarkers = " Маркеры складов: %s",
|
||||
statsSpawnLimits = "【ЛИМИТЫ ПОЯВЛЕНИЯ】",
|
||||
statsRedInfantry = " Красная пехота: %d/%d",
|
||||
statsRedArmor = " Красная бронетехника: %d/%d",
|
||||
statsBlueInfantry = " Синяя пехота: %d/%d",
|
||||
statsBlueArmor = " Синяя бронетехника: %d/%d",
|
||||
statsRedCoalition = "【КРАСНАЯ КОАЛИЦИЯ】",
|
||||
statsBlueCoalition = "【СИНЯЯ КОАЛИЦИЯ】",
|
||||
statsWarehouses = " Склады: %d/%d (%d%%)",
|
||||
statsActiveUnits = " Активные подразделения: %d (%d пех, %d брон)",
|
||||
statsDefenders = " Защитники: %d | Мобильные: %d",
|
||||
statsControlledZones = " Контролируемые зоны: %d",
|
||||
statsGarrisoned = " - С гарнизоном: %d",
|
||||
statsUnderGarrisoned = " - Недоукомплектованные: %d",
|
||||
statsInfantrySpawn = " Появление пехоты: %ds",
|
||||
statsInfantrySpawnPaused = " Появление пехоты: ПАУЗА (нет складов)",
|
||||
statsArmorSpawn = " Появление техники: %ds",
|
||||
statsArmorSpawnPaused = " Появление техники: ПАУЗА (нет складов)",
|
||||
statsSystemInfo = "【ИНФОРМАЦИЯ О СИСТЕМЕ】",
|
||||
statsTotalZones = " Всего зон: %d",
|
||||
statsActiveGarrisons = " Активные гарнизоны: %d",
|
||||
statsTotalActiveUnits = " Всего активных единиц: %d",
|
||||
statsTrackedGroups = " Отслеживаемые группы: %d",
|
||||
statsLuaMemory = " Память Lua: %.1f МБ",
|
||||
statsWarningMemory = " ⚠️ ВНИМАНИЕ: Высокое использование памяти!",
|
||||
statsWarningGroups = " ⚠️ ВНИМАНИЕ: Высокое количество групп!",
|
||||
enabled = "ВКЛЮЧЕНО",
|
||||
disabled = "ВЫКЛЮЧЕНО",
|
||||
}
|
||||
}
|
||||
|
||||
-- Helper function to get player's language from main script
|
||||
-- Falls back to English if playerLanguages is not available or player not found
|
||||
local function DGB_GetPlayerLanguage(playerName)
|
||||
-- Try to use the main script's playerLanguages table
|
||||
if playerLanguages and playerName and playerLanguages[playerName] then
|
||||
return playerLanguages[playerName]
|
||||
end
|
||||
|
||||
-- Try to use the main script's GetPlayerLanguage function if available
|
||||
if GetPlayerLanguage and type(GetPlayerLanguage) == "function" and playerName then
|
||||
local lang = GetPlayerLanguage(playerName)
|
||||
if lang then return lang end
|
||||
end
|
||||
|
||||
-- Fall back to main script's default language
|
||||
if LANGUAGE_CONFIG and LANGUAGE_CONFIG.defaultLanguage then
|
||||
return LANGUAGE_CONFIG.defaultLanguage
|
||||
end
|
||||
|
||||
-- Ultimate fallback to English
|
||||
return "EN"
|
||||
end
|
||||
|
||||
-- Helper function to get coalition's language (uses first player's language)
|
||||
local function DGB_GetCoalitionLanguage(coalitionSide)
|
||||
local playerList = coalition.getPlayers(coalitionSide)
|
||||
|
||||
if playerList and #playerList > 0 then
|
||||
local unit = playerList[1]
|
||||
if unit then
|
||||
local playerName = unit:getPlayerName()
|
||||
if playerName then
|
||||
return DGB_GetPlayerLanguage(playerName)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Fall back to default language
|
||||
if LANGUAGE_CONFIG and LANGUAGE_CONFIG.defaultLanguage then
|
||||
return LANGUAGE_CONFIG.defaultLanguage
|
||||
end
|
||||
|
||||
return "EN"
|
||||
end
|
||||
|
||||
-- Helper function to get translated text
|
||||
local function DGB_GetText(textKey, playerName)
|
||||
local lang = DGB_GetPlayerLanguage(playerName)
|
||||
local langTable = DGB_LANGUAGES[lang] or DGB_LANGUAGES.EN
|
||||
return langTable[textKey] or DGB_LANGUAGES.EN[textKey] or textKey
|
||||
end
|
||||
|
||||
-- Helper function to get translated text for a coalition
|
||||
local function DGB_GetTextForCoalition(textKey, coalitionSide)
|
||||
local lang = DGB_GetCoalitionLanguage(coalitionSide)
|
||||
local langTable = DGB_LANGUAGES[lang] or DGB_LANGUAGES.EN
|
||||
return langTable[textKey] or DGB_LANGUAGES.EN[textKey] or textKey
|
||||
end
|
||||
|
||||
env.info("[DGB PLUGIN] Dynamic Ground Battle Plugin initializing...")
|
||||
|
||||
-- Validate that DualCoalitionZoneCapture is loaded
|
||||
@@ -418,15 +730,15 @@ local function addMarkPoints(warehouses, coalition)
|
||||
|
||||
if coalition == 2 then -- Blue viewing
|
||||
if warehouse:GetCoalition() == 2 then
|
||||
details = "Warehouse: " .. warehouse:GetName() .. "\nThis warehouse needs to be protected.\n"
|
||||
details = string.format(DGB_GetTextForCoalition("warehouseFriendly", coalition), warehouse:GetName())
|
||||
else
|
||||
details = "Warehouse: " .. warehouse:GetName() .. "\nThis is a primary target as it is directly supplying enemy units.\n"
|
||||
details = string.format(DGB_GetTextForCoalition("warehouseEnemy", coalition), warehouse:GetName())
|
||||
end
|
||||
elseif coalition == 1 then -- Red viewing
|
||||
if warehouse:GetCoalition() == 1 then
|
||||
details = "Warehouse: " .. warehouse:GetName() .. "\nThis warehouse needs to be protected.\n"
|
||||
details = string.format(DGB_GetTextForCoalition("warehouseFriendly", coalition), warehouse:GetName())
|
||||
else
|
||||
details = "Warehouse: " .. warehouse:GetName() .. "\nThis is a primary target as it is directly supplying enemy units.\n"
|
||||
details = string.format(DGB_GetTextForCoalition("warehouseEnemy", coalition), warehouse:GetName())
|
||||
end
|
||||
end
|
||||
|
||||
@@ -818,10 +1130,23 @@ local function MonitorWarehouses()
|
||||
local blueSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(blueWarehouses)
|
||||
|
||||
if ENABLE_WAREHOUSE_STATUS_MESSAGES then
|
||||
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()
|
||||
-- Send to Blue coalition in their language
|
||||
local blueLang = DGB_GetCoalitionLanguage(coalition.side.BLUE)
|
||||
local blueMsg = string.format(
|
||||
DGB_LANGUAGES[blueLang].warehouseStatus,
|
||||
redWarehousesAlive, redSpawnFrequencyPercentage,
|
||||
blueWarehousesAlive, blueSpawnFrequencyPercentage
|
||||
)
|
||||
MESSAGE:New(blueMsg, 30):ToBlue()
|
||||
|
||||
-- Send to Red coalition in their language
|
||||
local redLang = DGB_GetCoalitionLanguage(coalition.side.RED)
|
||||
local redMsg = string.format(
|
||||
DGB_LANGUAGES[redLang].warehouseStatus,
|
||||
redWarehousesAlive, redSpawnFrequencyPercentage,
|
||||
blueWarehousesAlive, blueSpawnFrequencyPercentage
|
||||
)
|
||||
MESSAGE:New(redMsg, 30):ToRed()
|
||||
end
|
||||
|
||||
env.info(string.format("[DGB PLUGIN] Warehouse status - Red: %d/%d (%d%%), Blue: %d/%d (%d%%)",
|
||||
@@ -920,73 +1245,77 @@ local function ShowSystemStatistics(playerCoalition)
|
||||
local blueInfantryInterval = CalculateSpawnFrequency(blueWarehouses, SPAWN_SCHED_BLUE_INFANTRY, BLUE_INFANTRY_CADENCE_SCALAR)
|
||||
local blueArmorInterval = CalculateSpawnFrequency(blueWarehouses, SPAWN_SCHED_BLUE_ARMOR, BLUE_ARMOR_CADENCE_SCALAR)
|
||||
|
||||
-- Get language for this coalition
|
||||
local lang = DGB_GetCoalitionLanguage(playerCoalition)
|
||||
local T = DGB_LANGUAGES[lang]
|
||||
|
||||
-- Build comprehensive report
|
||||
local msg = "═══════════════════════════════════════\n"
|
||||
msg = msg .. "DYNAMIC GROUND BATTLE - SYSTEM STATUS\n"
|
||||
msg = msg .. T.statsTitle .. "\n"
|
||||
msg = msg .. "═══════════════════════════════════════\n\n"
|
||||
|
||||
-- Configuration Section
|
||||
msg = msg .. "【CONFIGURATION】\n"
|
||||
msg = msg .. " Defenders per Zone: " .. DEFENDERS_PER_ZONE .. "\n"
|
||||
msg = msg .. " Defender Rotation: " .. (ALLOW_DEFENDER_ROTATION and "ENABLED" or "DISABLED") .. "\n"
|
||||
msg = msg .. " Infantry Movement: " .. (MOVING_INFANTRY_PATROLS and "ENABLED" or "DISABLED") .. "\n"
|
||||
msg = msg .. " Task Reassignment: Every " .. ASSIGN_TASKS_SCHED .. "s\n"
|
||||
msg = msg .. " Warehouse Markers: " .. (ENABLE_WAREHOUSE_MARKERS and "ENABLED" or "DISABLED") .. "\n\n"
|
||||
msg = msg .. T.statsConfiguration .. "\n"
|
||||
msg = msg .. string.format(T.statsDefendersPerZone, DEFENDERS_PER_ZONE) .. "\n"
|
||||
msg = msg .. string.format(T.statsDefenderRotation, ALLOW_DEFENDER_ROTATION and T.enabled or T.disabled) .. "\n"
|
||||
msg = msg .. string.format(T.statsInfantryMovement, MOVING_INFANTRY_PATROLS and T.enabled or T.disabled) .. "\n"
|
||||
msg = msg .. string.format(T.statsTaskReassignment, ASSIGN_TASKS_SCHED) .. "\n"
|
||||
msg = msg .. string.format(T.statsWarehouseMarkers, ENABLE_WAREHOUSE_MARKERS and T.enabled or T.disabled) .. "\n\n"
|
||||
|
||||
-- Spawn Limits Section
|
||||
msg = msg .. "【SPAWN LIMITS】\n"
|
||||
msg = msg .. " Red Infantry: " .. INIT_RED_INFANTRY .. "/" .. MAX_RED_INFANTRY .. "\n"
|
||||
msg = msg .. " Red Armor: " .. INIT_RED_ARMOR .. "/" .. MAX_RED_ARMOR .. "\n"
|
||||
msg = msg .. " Blue Infantry: " .. INIT_BLUE_INFANTRY .. "/" .. MAX_BLUE_INFANTRY .. "\n"
|
||||
msg = msg .. " Blue Armor: " .. INIT_BLUE_ARMOR .. "/" .. MAX_BLUE_ARMOR .. "\n\n"
|
||||
msg = msg .. T.statsSpawnLimits .. "\n"
|
||||
msg = msg .. string.format(T.statsRedInfantry, INIT_RED_INFANTRY, MAX_RED_INFANTRY) .. "\n"
|
||||
msg = msg .. string.format(T.statsRedArmor, INIT_RED_ARMOR, MAX_RED_ARMOR) .. "\n"
|
||||
msg = msg .. string.format(T.statsBlueInfantry, INIT_BLUE_INFANTRY, MAX_BLUE_INFANTRY) .. "\n"
|
||||
msg = msg .. string.format(T.statsBlueArmor, INIT_BLUE_ARMOR, MAX_BLUE_ARMOR) .. "\n\n"
|
||||
|
||||
-- Red Coalition Section
|
||||
msg = msg .. "【RED COALITION】\n"
|
||||
msg = msg .. " Warehouses: " .. redWarehousesAlive .. "/" .. redWarehouseTotal .. " (" .. redSpawnFreqPct .. "%)\n"
|
||||
msg = msg .. " Active Units: " .. redUnits.total .. " (" .. redUnits.infantry .. " inf, " .. redUnits.armor .. " armor)\n"
|
||||
msg = msg .. " Defenders: " .. redUnits.defenders .. " | Mobile: " .. redUnits.mobile .. "\n"
|
||||
msg = msg .. " Controlled Zones: " .. redGarrison.totalZones .. "\n"
|
||||
msg = msg .. " - Garrisoned: " .. redGarrison.garrisoned .. "\n"
|
||||
msg = msg .. " - Under-Garrisoned: " .. redGarrison.underGarrisoned .. "\n"
|
||||
msg = msg .. T.statsRedCoalition .. "\n"
|
||||
msg = msg .. string.format(T.statsWarehouses, redWarehousesAlive, redWarehouseTotal, redSpawnFreqPct) .. "\n"
|
||||
msg = msg .. string.format(T.statsActiveUnits, redUnits.total, redUnits.infantry, redUnits.armor) .. "\n"
|
||||
msg = msg .. string.format(T.statsDefenders, redUnits.defenders, redUnits.mobile) .. "\n"
|
||||
msg = msg .. string.format(T.statsControlledZones, redGarrison.totalZones) .. "\n"
|
||||
msg = msg .. string.format(T.statsGarrisoned, redGarrison.garrisoned) .. "\n"
|
||||
msg = msg .. string.format(T.statsUnderGarrisoned, redGarrison.underGarrisoned) .. "\n"
|
||||
|
||||
if redInfantryInterval then
|
||||
msg = msg .. " Infantry Spawn: " .. math.floor(redInfantryInterval) .. "s\n"
|
||||
msg = msg .. string.format(T.statsInfantrySpawn, math.floor(redInfantryInterval)) .. "\n"
|
||||
else
|
||||
msg = msg .. " Infantry Spawn: PAUSED (no warehouses)\n"
|
||||
msg = msg .. T.statsInfantrySpawnPaused .. "\n"
|
||||
end
|
||||
|
||||
if redArmorInterval then
|
||||
msg = msg .. " Armor Spawn: " .. math.floor(redArmorInterval) .. "s\n\n"
|
||||
msg = msg .. string.format(T.statsArmorSpawn, math.floor(redArmorInterval)) .. "\n\n"
|
||||
else
|
||||
msg = msg .. " Armor Spawn: PAUSED (no warehouses)\n\n"
|
||||
msg = msg .. T.statsArmorSpawnPaused .. "\n\n"
|
||||
end
|
||||
|
||||
-- Blue Coalition Section
|
||||
msg = msg .. "【BLUE COALITION】\n"
|
||||
msg = msg .. " Warehouses: " .. blueWarehousesAlive .. "/" .. blueWarehouseTotal .. " (" .. blueSpawnFreqPct .. "%)\n"
|
||||
msg = msg .. " Active Units: " .. blueUnits.total .. " (" .. blueUnits.infantry .. " inf, " .. blueUnits.armor .. " armor)\n"
|
||||
msg = msg .. " Defenders: " .. blueUnits.defenders .. " | Mobile: " .. blueUnits.mobile .. "\n"
|
||||
msg = msg .. " Controlled Zones: " .. blueGarrison.totalZones .. "\n"
|
||||
msg = msg .. " - Garrisoned: " .. blueGarrison.garrisoned .. "\n"
|
||||
msg = msg .. " - Under-Garrisoned: " .. blueGarrison.underGarrisoned .. "\n"
|
||||
msg = msg .. T.statsBlueCoalition .. "\n"
|
||||
msg = msg .. string.format(T.statsWarehouses, blueWarehousesAlive, blueWarehouseTotal, blueSpawnFreqPct) .. "\n"
|
||||
msg = msg .. string.format(T.statsActiveUnits, blueUnits.total, blueUnits.infantry, blueUnits.armor) .. "\n"
|
||||
msg = msg .. string.format(T.statsDefenders, blueUnits.defenders, blueUnits.mobile) .. "\n"
|
||||
msg = msg .. string.format(T.statsControlledZones, blueGarrison.totalZones) .. "\n"
|
||||
msg = msg .. string.format(T.statsGarrisoned, blueGarrison.garrisoned) .. "\n"
|
||||
msg = msg .. string.format(T.statsUnderGarrisoned, blueGarrison.underGarrisoned) .. "\n"
|
||||
|
||||
if blueInfantryInterval then
|
||||
msg = msg .. " Infantry Spawn: " .. math.floor(blueInfantryInterval) .. "s\n"
|
||||
msg = msg .. string.format(T.statsInfantrySpawn, math.floor(blueInfantryInterval)) .. "\n"
|
||||
else
|
||||
msg = msg .. " Infantry Spawn: PAUSED (no warehouses)\n"
|
||||
msg = msg .. T.statsInfantrySpawnPaused .. "\n"
|
||||
end
|
||||
|
||||
if blueArmorInterval then
|
||||
msg = msg .. " Armor Spawn: " .. math.floor(blueArmorInterval) .. "s\n\n"
|
||||
msg = msg .. string.format(T.statsArmorSpawn, math.floor(blueArmorInterval)) .. "\n\n"
|
||||
else
|
||||
msg = msg .. " Armor Spawn: PAUSED (no warehouses)\n\n"
|
||||
msg = msg .. T.statsArmorSpawnPaused .. "\n\n"
|
||||
end
|
||||
|
||||
-- System Info
|
||||
msg = msg .. "【SYSTEM INFO】\n"
|
||||
msg = msg .. " Total Zones: " .. #zoneCaptureObjects .. "\n"
|
||||
msg = msg .. " Active Garrisons: " .. (redGarrison.garrisoned + blueGarrison.garrisoned) .. "\n"
|
||||
msg = msg .. " Total Active Units: " .. (redUnits.total + blueUnits.total) .. "\n"
|
||||
msg = msg .. T.statsSystemInfo .. "\n"
|
||||
msg = msg .. string.format(T.statsTotalZones, #zoneCaptureObjects) .. "\n"
|
||||
msg = msg .. string.format(T.statsActiveGarrisons, redGarrison.garrisoned + blueGarrison.garrisoned) .. "\n"
|
||||
msg = msg .. string.format(T.statsTotalActiveUnits, redUnits.total + blueUnits.total) .. "\n"
|
||||
|
||||
-- Memory and Performance Tracking
|
||||
local totalSpawnedGroups = 0
|
||||
@@ -995,17 +1324,17 @@ local function ShowSystemStatistics(playerCoalition)
|
||||
end
|
||||
|
||||
local luaMemoryKB = collectgarbage("count")
|
||||
msg = msg .. " Tracked Groups: " .. totalSpawnedGroups .. "\n"
|
||||
msg = msg .. " Lua Memory: " .. string.format("%.1f MB", luaMemoryKB / 1024) .. "\n"
|
||||
msg = msg .. string.format(T.statsTrackedGroups, totalSpawnedGroups) .. "\n"
|
||||
msg = msg .. string.format(T.statsLuaMemory, luaMemoryKB / 1024) .. "\n"
|
||||
|
||||
-- Warning if memory is high
|
||||
if luaMemoryKB > 512000 then -- More than 500MB
|
||||
msg = msg .. " ⚠️ WARNING: High memory usage!\n"
|
||||
msg = msg .. T.statsWarningMemory .. "\n"
|
||||
end
|
||||
|
||||
-- Warning if too many groups
|
||||
if totalSpawnedGroups > 200 then
|
||||
msg = msg .. " ⚠️ WARNING: High group count!\n"
|
||||
msg = msg .. T.statsWarningGroups .. "\n"
|
||||
end
|
||||
|
||||
msg = msg .. "\n"
|
||||
@@ -1028,8 +1357,13 @@ local blueZones = GetZonesByCoalition(coalition.side.BLUE)
|
||||
local redSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(redWarehouses)
|
||||
local blueSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(blueWarehouses)
|
||||
|
||||
MESSAGE:New("Red reinforcement capacity: " .. redSpawnFrequencyPercentage .. "%", 30):ToRed()
|
||||
MESSAGE:New("Blue reinforcement capacity: " .. blueSpawnFrequencyPercentage .. "%", 30):ToBlue()
|
||||
local redLang = DGB_GetCoalitionLanguage(coalition.side.RED)
|
||||
local redMsg = string.format(DGB_LANGUAGES[redLang].reinforcementCapacity, "Red", redSpawnFrequencyPercentage)
|
||||
MESSAGE:New(redMsg, 30):ToRed()
|
||||
|
||||
local blueLang = DGB_GetCoalitionLanguage(coalition.side.BLUE)
|
||||
local blueMsg = string.format(DGB_LANGUAGES[blueLang].reinforcementCapacity, "Blue", blueSpawnFrequencyPercentage)
|
||||
MESSAGE:New(blueMsg, 30):ToBlue()
|
||||
|
||||
-- Initialize spawners
|
||||
env.info("[DGB PLUGIN] Initializing spawn systems...")
|
||||
@@ -1277,25 +1611,28 @@ SCHEDULER:New(nil, AssignTasksToGroups, {}, 15, ASSIGN_TASKS_SCHED)
|
||||
-- Add F10 menu for manual checks (using MenuManager if available)
|
||||
if MenuManager then
|
||||
-- Create coalition-specific menus under Mission Options
|
||||
local blueMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "Ground Battle")
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Check Warehouse Status", blueMenu, MonitorWarehouses)
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Show System Statistics", blueMenu, function()
|
||||
local blueMenuText = DGB_GetTextForCoalition("menuGroundBattle", coalition.side.BLUE)
|
||||
local blueMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, blueMenuText)
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, DGB_GetTextForCoalition("menuWarehouseStatus", coalition.side.BLUE), blueMenu, MonitorWarehouses)
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, DGB_GetTextForCoalition("menuSystemStats", coalition.side.BLUE), blueMenu, function()
|
||||
ShowSystemStatistics(coalition.side.BLUE)
|
||||
end)
|
||||
|
||||
local redMenu = MenuManager.CreateCoalitionMenu(coalition.side.RED, "Ground Battle")
|
||||
MENU_COALITION_COMMAND:New(coalition.side.RED, "Check Warehouse Status", redMenu, MonitorWarehouses)
|
||||
MENU_COALITION_COMMAND:New(coalition.side.RED, "Show System Statistics", redMenu, function()
|
||||
local redMenuText = DGB_GetTextForCoalition("menuGroundBattle", coalition.side.RED)
|
||||
local redMenu = MenuManager.CreateCoalitionMenu(coalition.side.RED, redMenuText)
|
||||
MENU_COALITION_COMMAND:New(coalition.side.RED, DGB_GetTextForCoalition("menuWarehouseStatus", coalition.side.RED), redMenu, MonitorWarehouses)
|
||||
MENU_COALITION_COMMAND:New(coalition.side.RED, DGB_GetTextForCoalition("menuSystemStats", coalition.side.RED), redMenu, function()
|
||||
ShowSystemStatistics(coalition.side.RED)
|
||||
end)
|
||||
else
|
||||
-- Fallback to root-level mission menu
|
||||
local missionMenu = MENU_MISSION:New("Ground Battle")
|
||||
MENU_MISSION_COMMAND:New("Check Warehouse Status", missionMenu, MonitorWarehouses)
|
||||
MENU_MISSION_COMMAND:New("Show Blue Statistics", missionMenu, function()
|
||||
local missionMenuText = DGB_GetTextForCoalition("menuGroundBattle", coalition.side.BLUE)
|
||||
local missionMenu = MENU_MISSION:New(missionMenuText)
|
||||
MENU_MISSION_COMMAND:New(DGB_GetTextForCoalition("menuWarehouseStatus", coalition.side.BLUE), missionMenu, MonitorWarehouses)
|
||||
MENU_MISSION_COMMAND:New(DGB_GetTextForCoalition("menuSystemStats", coalition.side.BLUE) .. " (Blue)", missionMenu, function()
|
||||
ShowSystemStatistics(coalition.side.BLUE)
|
||||
end)
|
||||
MENU_MISSION_COMMAND:New("Show Red Statistics", missionMenu, function()
|
||||
MENU_MISSION_COMMAND:New(DGB_GetTextForCoalition("menuSystemStats", coalition.side.RED) .. " (Red)", missionMenu, function()
|
||||
ShowSystemStatistics(coalition.side.RED)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
--[[
|
||||
Unified F10 Menu Manager
|
||||
|
||||
Purpose: Provides a centralized menu system to organize all mission scripts
|
||||
into a consistent F10 menu structure.
|
||||
|
||||
Menu Organization:
|
||||
F10 -> F1: Mission Options (all other scripts go here)
|
||||
F10 -> F2: CTLD (reserved position)
|
||||
F10 -> F3: AFAC Control (reserved position)
|
||||
|
||||
Usage:
|
||||
1. Load this script FIRST before any other menu-creating scripts
|
||||
2. Other scripts should use MenuManager to register their menus
|
||||
|
||||
Example:
|
||||
-- In your script, instead of:
|
||||
-- local MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Script")
|
||||
|
||||
-- Use:
|
||||
-- local MyMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "My Script")
|
||||
|
||||
]]--
|
||||
|
||||
MenuManager = {}
|
||||
MenuManager.Version = "1.1"
|
||||
|
||||
-- Configuration
|
||||
MenuManager.Config = {
|
||||
EnableMissionOptionsMenu = true, -- Set to false to disable the parent menu system
|
||||
MissionOptionsMenuName = "Mission Options", -- Name of the parent menu
|
||||
Debug = false -- Set to true for debug messages
|
||||
}
|
||||
|
||||
-- Storage for menu references
|
||||
MenuManager.Menus = {
|
||||
Blue = {},
|
||||
Red = {},
|
||||
Mission = {}
|
||||
}
|
||||
|
||||
-- Parent menu references (created on first use)
|
||||
MenuManager.ParentMenus = {
|
||||
BlueCoalition = nil,
|
||||
RedCoalition = nil,
|
||||
Mission = nil
|
||||
}
|
||||
|
||||
-- Initialize the parent menus
|
||||
function MenuManager.Initialize()
|
||||
if MenuManager.Config.EnableMissionOptionsMenu then
|
||||
-- Create the parent "Mission Options" menu for each coalition
|
||||
MenuManager.ParentMenus.BlueCoalition = MENU_COALITION:New(
|
||||
coalition.side.BLUE,
|
||||
MenuManager.Config.MissionOptionsMenuName
|
||||
)
|
||||
|
||||
MenuManager.ParentMenus.RedCoalition = MENU_COALITION:New(
|
||||
coalition.side.RED,
|
||||
MenuManager.Config.MissionOptionsMenuName
|
||||
)
|
||||
|
||||
-- Note: MENU_MISSION not created to avoid duplicate empty menu
|
||||
-- Scripts that need mission-wide menus should use MENU_MISSION directly
|
||||
|
||||
if MenuManager.Config.Debug then
|
||||
env.info("MenuManager: Initialized parent coalition menus")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Create a coalition menu under "Mission Options"
|
||||
-- @param coalitionSide: coalition.side.BLUE or coalition.side.RED
|
||||
-- @param menuName: Name of the menu
|
||||
-- @param parentMenu: (Optional) If provided, creates as submenu of this parent instead of Mission Options
|
||||
-- @return: MENU_COALITION object
|
||||
function MenuManager.CreateCoalitionMenu(coalitionSide, menuName, parentMenu)
|
||||
if MenuManager.Config.EnableMissionOptionsMenu and not parentMenu then
|
||||
-- Create under Mission Options
|
||||
local parent = (coalitionSide == coalition.side.BLUE)
|
||||
and MenuManager.ParentMenus.BlueCoalition
|
||||
or MenuManager.ParentMenus.RedCoalition
|
||||
|
||||
local menu = MENU_COALITION:New(coalitionSide, menuName, parent)
|
||||
|
||||
if MenuManager.Config.Debug then
|
||||
local coalitionName = (coalitionSide == coalition.side.BLUE) and "BLUE" or "RED"
|
||||
env.info(string.format("MenuManager: Created coalition menu '%s' for %s", menuName, coalitionName))
|
||||
end
|
||||
|
||||
return menu
|
||||
else
|
||||
-- Create as root menu or under provided parent
|
||||
local menu = MENU_COALITION:New(coalitionSide, menuName, parentMenu)
|
||||
return menu
|
||||
end
|
||||
end
|
||||
|
||||
-- Create a mission menu (not nested under Mission Options, as that causes duplicates)
|
||||
-- @param menuName: Name of the menu
|
||||
-- @param parentMenu: (Optional) Parent menu
|
||||
-- @return: MENU_MISSION object
|
||||
-- Note: Mission menus are visible to all players and cannot be nested under coalition menus
|
||||
function MenuManager.CreateMissionMenu(menuName, parentMenu)
|
||||
-- Always create as root menu or under provided parent
|
||||
-- Mission menus can't be nested under coalition-specific "Mission Options"
|
||||
local menu = MENU_MISSION:New(menuName, parentMenu)
|
||||
|
||||
if MenuManager.Config.Debug then
|
||||
env.info(string.format("MenuManager: Created mission menu '%s'", menuName))
|
||||
end
|
||||
|
||||
return menu
|
||||
end
|
||||
|
||||
-- Create a group menu under "Mission Options" for the player's coalition
|
||||
-- @param group: GROUP object
|
||||
-- @param menuName: Name of the menu
|
||||
-- @param parentMenu: (Optional) If provided, creates as submenu of this parent instead of Mission Options
|
||||
-- @return: MENU_GROUP object
|
||||
function MenuManager.CreateGroupMenu(group, menuName, parentMenu)
|
||||
if MenuManager.Config.EnableMissionOptionsMenu and not parentMenu then
|
||||
-- Get group's coalition and create under appropriate Mission Options
|
||||
local groupCoalition = group:getCoalition()
|
||||
local parent = (groupCoalition == coalition.side.BLUE)
|
||||
and MenuManager.ParentMenus.BlueCoalition
|
||||
or MenuManager.ParentMenus.RedCoalition
|
||||
|
||||
local menu = MENU_GROUP:New(group, menuName, parent)
|
||||
|
||||
if MenuManager.Config.Debug then
|
||||
local coalitionName = (groupCoalition == coalition.side.BLUE) and "BLUE" or "RED"
|
||||
env.info(string.format("MenuManager: Created group menu '%s' for %s (coalition %s)",
|
||||
menuName, group:getName(), coalitionName))
|
||||
end
|
||||
|
||||
return menu
|
||||
else
|
||||
-- Create as root menu or under provided parent
|
||||
local menu = MENU_GROUP:New(group, menuName, parentMenu)
|
||||
return menu
|
||||
end
|
||||
end
|
||||
|
||||
-- Helper to disable the parent menu system at runtime
|
||||
function MenuManager.DisableParentMenus()
|
||||
MenuManager.Config.EnableMissionOptionsMenu = false
|
||||
env.info("MenuManager: Parent menu system disabled")
|
||||
end
|
||||
|
||||
-- Helper to enable the parent menu system at runtime
|
||||
function MenuManager.EnableParentMenus()
|
||||
MenuManager.Config.EnableMissionOptionsMenu = true
|
||||
if not MenuManager.ParentMenus.BlueCoalition then
|
||||
MenuManager.Initialize()
|
||||
end
|
||||
env.info("MenuManager: Parent menu system enabled")
|
||||
end
|
||||
|
||||
-- Initialize on load
|
||||
MenuManager.Initialize()
|
||||
|
||||
-- Announcement
|
||||
env.info(string.format("MenuManager v%s loaded - Mission Options menu system ready", MenuManager.Version))
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,293 +1 @@
|
||||
# MOOSE Dual Coalition Zone Capture System
|
||||
- **Author**: F99th-TracerFacer
|
||||
- **Discord:** https://discord.gg/NdZ2JuSU (The Fighting 99th Discord Server where I spend most of my time.)
|
||||
|
||||
A dynamic zone capture and control system for DCS World missions using the MOOSE framework. This script enables territory-based gameplay where RED and BLUE coalitions compete to capture and hold strategic zones across the battlefield.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## 🎯 Features
|
||||
|
||||
- **🎨 Visual Feedback**: Color-coded zone boundaries (Red/Blue/Green/Orange) that change dynamically
|
||||
- **💨 Smoke Signals**: Automatic smoke markers indicating zone status
|
||||
- **📍 Tactical Information**: Real-time force composition and MGRS coordinates for enemies
|
||||
- **🏆 Victory Conditions**: Automatic win detection when one coalition captures all zones
|
||||
- **📻 F10 Radio Menu**: Player-accessible status reports and progress tracking
|
||||
- **⚙️ Highly Configurable**: Simple zone ownership configuration via Lua tables
|
||||
- **🔄 Dual Coalition**: Full support for both RED and BLUE coalitions
|
||||
- **📊 Auto-Reporting**: Periodic status updates every 5 minutes
|
||||
- **🎮 Player-Friendly**: Clear messaging and intuitive state transitions
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. **DCS World** (version 2.9 or higher)
|
||||
2. **MOOSE Framework** ([Download here](https://github.com/FlightControl-Master/MOOSE))
|
||||
3. Basic knowledge of DCS Mission Editor
|
||||
|
||||
### Installation
|
||||
|
||||
1. **Download the files:**
|
||||
- `Moose_DualCoalitionZoneCapture.lua` - Main script
|
||||
- `Moose_DualCoalitionZoneCapture.miz` - Example mission
|
||||
- `Moose_.lua` - MOOSE framework (get latest version)
|
||||
|
||||
2. **In DCS Mission Editor:**
|
||||
- Create trigger zones for each capture point (e.g., "Capture Zone-1", "Capture Severomorsk")
|
||||
- Create two groups: `BLUEHQ` (any BLUE ground unit) and `REDHQ` (any RED ground unit)
|
||||
|
||||
3. **Configure zones** in `Moose_DualCoalitionZoneCapture.lua`:
|
||||
|
||||
```lua
|
||||
local ZONE_CONFIG = {
|
||||
RED = {
|
||||
"Capture Zone-1",
|
||||
"Capture Zone-2"
|
||||
},
|
||||
BLUE = {
|
||||
"Capture Zone-3",
|
||||
"Capture Zone-4"
|
||||
},
|
||||
NEUTRAL = {
|
||||
-- Empty zones at mission start
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
4. **Load scripts** via Mission Start trigger:
|
||||
- Action 1: DO SCRIPT FILE → `Moose_.lua`
|
||||
- Action 2: DO SCRIPT FILE → `Moose_DualCoalitionZoneCapture.lua`
|
||||
|
||||
5. **Save and test** your mission!
|
||||
|
||||
## 📖 How It Works
|
||||
|
||||
### Zone States
|
||||
|
||||
Zones transition between four distinct states:
|
||||
|
||||
| State | Color | Smoke | Description |
|
||||
|-------|-------|-------|-------------|
|
||||
| **RED Controlled** | 🔴 Red Border | Red | Zone secured by RED coalition |
|
||||
| **BLUE Controlled** | 🔵 Blue Border | Blue | Zone secured by BLUE coalition |
|
||||
| **Neutral/Empty** | 🟢 Green Border | Green | Uncontrolled, ready for capture |
|
||||
| **Contested** | 🟠 Orange Border | White | Multiple coalitions present - fighting for control |
|
||||
|
||||
### Capture Mechanics
|
||||
|
||||
- **To Capture**: Move ground units into a zone
|
||||
- **To Hold**: Eliminate all enemy forces in the zone
|
||||
- **To Win**: Capture ALL zones on the map
|
||||
|
||||
The script automatically scans zones every 30 seconds (configurable) and updates ownership based on unit presence.
|
||||
|
||||
### Tactical Information Markers
|
||||
|
||||
Each zone displays real-time tactical data:
|
||||
|
||||
```
|
||||
TACTICAL: Capture Severomorsk-1
|
||||
Forces: R:5 B:12
|
||||
TGTS: T-90@38U LV 12345 67890, BTR-80@38U LV 12346 67891
|
||||
```
|
||||
|
||||
- **Force Counts**: Number of units per coalition
|
||||
- **MGRS Coordinates**: Precise enemy locations (when ≤10 units)
|
||||
- **Coalition-Specific**: Each side sees their enemies marked
|
||||
|
||||
## ⚙️ Configuration Options
|
||||
|
||||
### Zone Settings
|
||||
|
||||
```lua
|
||||
local ZONE_SETTINGS = {
|
||||
guardDelay = 1, -- Seconds before entering Guard state after capture
|
||||
scanInterval = 30, -- How often to scan for units (seconds)
|
||||
captureScore = 200 -- Points awarded for zone capture
|
||||
}
|
||||
```
|
||||
|
||||
### Performance Tuning
|
||||
|
||||
For missions with many units:
|
||||
```lua
|
||||
scanInterval = 60 -- Scan less frequently
|
||||
```
|
||||
|
||||
For fast-paced action:
|
||||
```lua
|
||||
scanInterval = 15 -- More responsive zone changes
|
||||
```
|
||||
|
||||
### Logging Control
|
||||
|
||||
Disable detailed logging:
|
||||
```lua
|
||||
CAPTURE_ZONE_LOGGING = { enabled = false }
|
||||
```
|
||||
|
||||
## 👥 Player Features
|
||||
|
||||
### F10 Radio Menu Commands
|
||||
|
||||
Players access zone information via **F10 → Zone Control**:
|
||||
|
||||
- **Get Zone Status Report**: Current ownership of all zones
|
||||
- **Check Victory Progress**: Percentage toward victory
|
||||
- **Refresh Zone Colors**: Manually redraw zone boundaries
|
||||
|
||||
### Automatic Notifications
|
||||
|
||||
- ✅ Zone capture/loss announcements
|
||||
- ⚠️ Attack warnings when zones are contested
|
||||
- 📊 Status reports every 5 minutes
|
||||
- 🏆 Victory alerts at 80% and 100% completion
|
||||
- 🎉 Victory countdown with celebratory effects
|
||||
|
||||
## 🎮 Example Mission
|
||||
|
||||
The included `Moose_DualCoalitionZoneCapture.miz` demonstrates:
|
||||
|
||||
- Proper zone configuration
|
||||
- HQ group placement
|
||||
- Script loading order
|
||||
- AI patrol patterns for testing
|
||||
- All visual and messaging features
|
||||
|
||||
**Use this mission as a template for your own scenarios!**
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### ❌ Script Won't Load
|
||||
**Error**: "attempt to index a nil value"
|
||||
- **Cause**: MOOSE not loaded first
|
||||
- **Fix**: Ensure load order is MOOSE → Capture Script
|
||||
|
||||
#### ❌ Zone Not Found
|
||||
**Error**: "Zone 'X' not found in mission editor!"
|
||||
- **Cause**: Zone name mismatch
|
||||
- **Fix**: Verify zone names match EXACTLY (case-sensitive!)
|
||||
|
||||
#### ⚠️ Zones Not Capturing
|
||||
- Only ground units count.
|
||||
- Wait 30 seconds for scan cycle
|
||||
- Eliminate ALL enemy forces to capture
|
||||
- Check DCS.log for detailed information
|
||||
- Increase logging and capture logs before reaching out to me. Happy to help troubleshoot. Discord info below.
|
||||
|
||||
### Checking Logs
|
||||
|
||||
Open `Saved Games\DCS\Logs\DCS.log` and search for:
|
||||
- `[CAPTURE Module]` - General logging
|
||||
- `[INIT]` - Initialization messages
|
||||
- `[TACTICAL]` - Tactical marker updates
|
||||
- `[VICTORY]` - Victory condition checks
|
||||
|
||||
## 🏗️ Mission Design Tips
|
||||
|
||||
### Best Practices
|
||||
|
||||
- **Zone Size**: Large enough for tactical areas, avoid overlaps
|
||||
- **Zone Placement**: Position over airbases, FOBs, strategic terrain
|
||||
- **Starting Balance**: Consider defensive vs. offensive scenarios
|
||||
- **AI Behavior**: Use "Ground Hold" or "Ground On Road" waypoints
|
||||
- **Player Briefing**: Document F10 menu commands in mission brief
|
||||
|
||||
### Integration with Other Scripts
|
||||
|
||||
Access zone data from other scripts:
|
||||
|
||||
```lua
|
||||
-- Get current ownership status
|
||||
local status = GetZoneOwnershipStatus()
|
||||
-- Returns: { blue = X, red = Y, neutral = Z, total = N, zones = {...} }
|
||||
|
||||
-- Manual status broadcast
|
||||
BroadcastZoneStatus()
|
||||
|
||||
-- Refresh zone visuals
|
||||
RefreshAllZoneColors()
|
||||
```
|
||||
|
||||
### Victory Flags
|
||||
|
||||
The script sets user flags on victory:
|
||||
- `BLUE_VICTORY = 1` when BLUE wins
|
||||
- `RED_VICTORY = 1` when RED wins
|
||||
|
||||
Use these in triggers to end missions or transition to next phase.
|
||||
|
||||
## 📋 Requirements
|
||||
|
||||
### Essential Components
|
||||
|
||||
- ✅ DCS World 2.9 or higher
|
||||
- ✅ MOOSE Framework (latest version)
|
||||
- ✅ Trigger zones in mission editor
|
||||
- ✅ BLUEHQ and REDHQ groups
|
||||
|
||||
### Mission Prerequisites
|
||||
|
||||
- At least one trigger zone per capture point
|
||||
- Exact zone name matching between editor and Lua config
|
||||
- Both HQ groups must exist (can be hidden/inactive)
|
||||
|
||||
## 📞 Support & Resources
|
||||
|
||||
### Get Help
|
||||
|
||||
- **F99th Mission Maker Discord Community**: https://discord.gg/kTNmMScQNf
|
||||
- **Author**: F99th-TracerFacer
|
||||
- **GitHub Issues**: Report bugs or request features: https://github.com/users/iTracerFacer/projects/3
|
||||
|
||||
|
||||
### Additional Resources
|
||||
|
||||
- [MOOSE Documentation](https://flightcontrol-master.github.io/MOOSE_DOCS/)
|
||||
- [MOOSE Discord](https://discord.gg/gj68fm969S)
|
||||
- [DCS Forums](https://forum.dcs.world)
|
||||
|
||||
## 📄 License
|
||||
|
||||
This script is provided free for use in DCS World missions. Feel free to modify and distribute.
|
||||
|
||||
## 🙏 Credits
|
||||
|
||||
- **Author**: F99th-TracerFacer
|
||||
- **Discord:** https://discord.gg/NdZ2JuSU (The Fighting 99th Discord Server where I spend most of my time.)
|
||||
- **Framework**: MOOSE by FlightControl
|
||||
- **Community**: DCS World Mission Makers
|
||||
|
||||
## 🎯 Version History
|
||||
|
||||
### Version 2.0 (Current)
|
||||
- ✨ Full dual coalition support (RED & BLUE)
|
||||
- ✨ Tactical information markers with MGRS coordinates
|
||||
- ✨ Auto-victory detection and countdown
|
||||
- ✨ F10 radio menu commands
|
||||
- ✨ Periodic status reports
|
||||
- ✨ Enhanced visual feedback system
|
||||
- ✨ Configurable zone ownership via Lua tables
|
||||
|
||||
### Version 1.0
|
||||
- Initial release
|
||||
- Basic zone capture mechanics
|
||||
- Single coalition focus
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
|
||||
**🎮 Happy Mission Making! 🚁**
|
||||
|
||||
*Created with ❤️ for the DCS World Community*
|
||||
|
||||
[Discord](https://discord.gg/kTNmMScQNf) • [Documentation](Mission_Maker_Guide.html) • [Report Issue](#)
|
||||
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user