Index: binaries/data/mods/public/gui/common/gamedescription.js =================================================================== --- binaries/data/mods/public/gui/common/gamedescription.js +++ binaries/data/mods/public/gui/common/gamedescription.js @@ -216,12 +216,20 @@ function getGameDescription(extended = false) { let titles = []; + if (!g_GameAttributes.settings.VictoryConditions.length) + titles.push({ + "label": translateWithContext("victory condition", "Endless"), + "value": translate("No Victory Condition specfied.") + }); - let victoryIdx = g_VictoryConditions.Name.indexOf(g_GameAttributes.settings.GameType || g_VictoryConditions.Default); - if (victoryIdx != -1) + for (let vc of clone(g_GameAttributes.settings.VictoryConditions).sort((a, b) => a > b ? 1 : a < b ? -1 : 0)) { - let title = g_VictoryConditions.Title[victoryIdx]; - if (g_VictoryConditions.Name[victoryIdx] == "wonder") + let victoryCondition = g_VictoryConditions.find(data => data.Name == "endless"); + if (!victoryCondition) + continue; + + let title = victoryCondition.Title; + if (vc == "wonder") title = sprintf( translatePluralWithContext( "victory condition", @@ -232,7 +240,7 @@ { "min": g_GameAttributes.settings.WonderDuration } ); - let isCaptureTheRelic = g_VictoryConditions.Name[victoryIdx] == "capture_the_relic"; + let isCaptureTheRelic = vc == "capture_the_relic"; if (isCaptureTheRelic) title = sprintf( translatePluralWithContext( @@ -246,7 +254,7 @@ titles.push({ "label": title, - "value": g_VictoryConditions.Description[victoryIdx] + "value": victoryCondition.Description }); if (isCaptureTheRelic) @@ -255,7 +263,7 @@ "value": g_GameAttributes.settings.RelicCount }); - if (g_VictoryConditions.Name[victoryIdx] == "regicide") + if (vc == "regicide") if (g_GameAttributes.settings.RegicideGarrison) titles.push({ "label": translate("Hero Garrison"), @@ -264,7 +272,7 @@ else titles.push({ "label": translate("Exposed Heroes"), - "value": translate("Heroes cannot be garrisoned, and they are vulnerable to raids.") + "value": translate("Heroes cannot be garrisoned and they are vulnerable to raids.") }); } Index: binaries/data/mods/public/gui/common/settings.js =================================================================== --- binaries/data/mods/public/gui/common/settings.js +++ binaries/data/mods/public/gui/common/settings.js @@ -247,7 +247,7 @@ } /** - * Loads available gametypes. + * Loads available victoryCondtions from json files. * * @returns {Array|undefined} */ @@ -265,15 +265,6 @@ if (victoryConditions.some(vc => vc == undefined)) return undefined; - // TODO: We might support enabling victory conditions separately sometime. - // Until then, we supplement the endless gametype here. - victoryConditions.push({ - "Name": "endless", - "Title": translateWithContext("victory condition", "None"), - "Description": translate("Endless game."), - "Scripts": [] - }); - return victoryConditions; } @@ -428,11 +419,11 @@ /** * Returns title or placeholder. * - * @param {string} gameType - for example "conquest" + * @param {string} victoryCondition - for example "conquest" * @returns {string} */ -function translateVictoryCondition(gameType) +function translateVictoryCondition(victoryCondition) { - let victoryCondition = g_Settings.VictoryConditions.find(vc => vc.Name == gameType); - return victoryCondition ? victoryCondition.Title : translateWithContext("victory condition", "Unknown"); + let victoryConditionData = g_Settings.VictoryConditions.find(vc => vc.Name == victoryCondition); + return victoryConditionData ? victoryConditionData.Title : translateWithContext("victory condition", "Unknown"); } Index: binaries/data/mods/public/gui/gamesetup/gamesetup.js =================================================================== --- binaries/data/mods/public/gui/gamesetup/gamesetup.js +++ binaries/data/mods/public/gui/gamesetup/gamesetup.js @@ -7,8 +7,9 @@ const g_TriggerDifficulties = prepareForDropdown(g_Settings && g_Settings.TriggerDifficulties); const g_PopulationCapacities = prepareForDropdown(g_Settings && g_Settings.PopulationCapacities); const g_StartingResources = prepareForDropdown(g_Settings && g_Settings.StartingResources); -const g_VictoryConditions = prepareForDropdown(g_Settings && g_Settings.VictoryConditions); const g_VictoryDurations = prepareForDropdown(g_Settings && g_Settings.VictoryDurations); + +const g_VictoryConditions = g_Settings && g_Settings.VictoryConditions; var g_GameSpeeds = getGameSpeedChoices(false); /** @@ -294,6 +295,8 @@ var g_DefaultPlayerData = []; +var g_DefaultVictoryConditions = []; + var g_GameAttributes = { "settings": {} }; /** @@ -433,7 +436,7 @@ { "label": translateWithContext("Match settings tab name", "Game Type"), "settings": [ - "victoryCondition", + ...g_VictoryConditions.map(vc => vc.Name), "relicCount", "relicDuration", "wonderDuration", @@ -640,22 +643,6 @@ "enabled": () => g_GameAttributes.mapType != "scenario", "initOrder": 1000 }, - "victoryCondition": { - "title": () => translate("Victory Condition"), - "tooltip": (hoverIdx) => g_VictoryConditions.Description[hoverIdx] || translate("Select victory condition."), - "labels": () => g_VictoryConditions.Title, - "ids": () => g_VictoryConditions.Name, - "default": () => g_VictoryConditions.Default, - "defined": () => g_GameAttributes.settings.GameType !== undefined, - "get": () => g_GameAttributes.settings.GameType, - "select": (itemIdx) => { - g_GameAttributes.settings.GameType = g_VictoryConditions.Name[itemIdx]; - g_GameAttributes.settings.VictoryScripts = g_VictoryConditions.Scripts[itemIdx]; - }, - "enabled": () => g_GameAttributes.mapType != "scenario", - "autocomplete": 0, - "initOrder": 1000 - }, "relicCount": { "title": () => translate("Relic Count"), "tooltip": (hoverIdx) => translate("Total number of relics spawned on the map. Relic victory is most realistic with only one or two relics. With greater numbers, the relics are important to capture to receive aura bonuses."), @@ -667,7 +654,7 @@ "select": (itemIdx) => { g_GameAttributes.settings.RelicCount = g_RelicCountList[itemIdx]; }, - "hidden": () => g_GameAttributes.settings.GameType != "capture_the_relic", + "hidden": () => g_GameAttributes.settings.VictoryConditions.indexOf("capture_the_relic") == -1, "enabled": () => g_GameAttributes.mapType != "scenario", "initOrder": 1000 }, @@ -682,7 +669,7 @@ "select": (itemIdx) => { g_GameAttributes.settings.RelicDuration = g_VictoryDurations.Duration[itemIdx]; }, - "hidden": () => g_GameAttributes.settings.GameType != "capture_the_relic", + "hidden": () => g_GameAttributes.settings.VictoryConditions.indexOf("capture_the_relic") == -1, "enabled": () => g_GameAttributes.mapType != "scenario", "initOrder": 1000 }, @@ -697,7 +684,7 @@ "select": (itemIdx) => { g_GameAttributes.settings.WonderDuration = g_VictoryDurations.Duration[itemIdx]; }, - "hidden": () => g_GameAttributes.settings.GameType != "wonder", + "hidden": () => g_GameAttributes.settings.VictoryConditions.indexOf("wonder") == -1, "enabled": () => g_GameAttributes.mapType != "scenario", "initOrder": 1000 }, @@ -822,7 +809,33 @@ /** * Contains the logic of all boolean gamesettings. */ -var g_Checkboxes = { +var g_Checkboxes = Object.assign( + {}, + g_VictoryConditions.reduce((obj, victoryCondition) => { + obj[victoryCondition.Name] = { + "title": () => victoryCondition.Title, + "tooltip": () => victoryCondition.Description, + "default": () => victoryCondition.Default, + "defined": () => true, + "get": () => g_GameAttributes.settings.VictoryConditions.indexOf(victoryCondition.Name) != -1, + "set": checked => { + if (checked) + { + g_GameAttributes.settings.VictoryConditions.push(victoryCondition.Name); + if (victoryCondition.Set) + for (let setting in victoryCondition.ChangeWhenChecked) + g_Checkboxes[setting].set(victoryCondition.ChangeOnChecked[setting]); + } + else + g_GameAttributes.settings.VictoryConditions = g_GameAttributes.settings.VictoryConditions.filter(vc => vc != victoryCondition.Name) + }, + "enabled": () => + g_GameAttributes.mapType != "scenario" && + (!victoryCondition.DisabledWhenChecked || + victoryCondition.DisabledWhenChecked.every(vc => g_GameAttributes.settings.VictoryConditions.indexOf(vc) == -1)) + }; + return obj; + }, {}), "regicideGarrison": { "title": () => translate("Hero Garrison"), "tooltip": () => translate("Toggle whether heroes can be garrisoned."), @@ -968,7 +981,8 @@ }, "initOrder": 1000 }, -}; + } +); /** * For setting up arbitrary GUI objects. @@ -1142,6 +1156,9 @@ } deepfreeze(g_DefaultPlayerData); + + g_DefaultVictoryConditions = g_VictoryConditions.filter(vc => !!vc.Default).map(vc => vc.Name); + deepfreeze(g_DefaultVictoryConditions); } /** @@ -1149,6 +1166,7 @@ */ function supplementDefaults() { + g_GameAttributes.settings.VictoryConditions = g_GameAttributes.settings.VictoryConditions || clone(g_DefaultVictoryConditions); for (let dropdown in g_Dropdowns) if (!g_Dropdowns[dropdown].defined()) g_Dropdowns[dropdown].select(g_Dropdowns[dropdown].default()); @@ -1987,14 +2005,8 @@ let mapSettings = mapData && mapData.settings ? clone(mapData.settings) : {}; if (g_GameAttributes.mapType != "random") - { delete g_GameAttributes.settings.Nomad; - let victoryIdx = g_VictoryConditions.Name.indexOf(mapSettings.GameType || "") != -1 ? g_VictoryConditions.Name.indexOf(mapSettings.GameType) : g_VictoryConditions.Default; - g_GameAttributes.settings.GameType = g_VictoryConditions.Name[victoryIdx]; - g_GameAttributes.settings.VictoryScripts = g_VictoryConditions.Scripts[victoryIdx]; - } - if (g_GameAttributes.mapType == "scenario") { delete g_GameAttributes.settings.RelicDuration; @@ -2134,13 +2146,7 @@ // Select random map if (g_GameAttributes.map == "random") - { - let victoryScriptsSelected = g_GameAttributes.settings.VictoryScripts; - let gameTypeSelected = g_GameAttributes.settings.GameType; selectMap(pickRandom(g_Dropdowns.mapSelection.ids().slice(1))); - g_GameAttributes.settings.VictoryScripts = victoryScriptsSelected; - g_GameAttributes.settings.GameType = gameTypeSelected; - } if (g_GameAttributes.settings.Biome == "random") g_GameAttributes.settings.Biome = pickRandom( @@ -2148,6 +2154,11 @@ g_BiomeList.Id.slice(1).filter(biomeID => biomeID.startsWith(g_GameAttributes.settings.SupportedBiomes)) : g_GameAttributes.settings.SupportedBiomes); + let victoryScripts = []; + for (let vc of g_GameAttributes.settings.VictoryConditions) + victoryScripts = victoryScripts.concat(g_VictoryConditions[g_VictoryConditions.map(data => data.Name).indexOf(vc)].Scripts); + + g_GameAttributes.settings.VictoryScripts = victoryScripts.filter((vc, i) => victoryScripts.indexOf(vc) == i) g_GameAttributes.settings.TriggerScripts = g_GameAttributes.settings.VictoryScripts.concat(g_GameAttributes.settings.TriggerScripts || []); // Prevent reseting the readystate @@ -2278,7 +2289,6 @@ for (let name in g_MiscControls) updateGUIMiscControl(name); - updateGameDescription(); distributeSettings(); rightAlignCancelButton(); @@ -2640,7 +2650,7 @@ "niceMapName": getMapDisplayName(g_GameAttributes.map), "mapSize": g_GameAttributes.mapType == "random" ? g_GameAttributes.settings.Size : "Default", "mapType": g_GameAttributes.mapType, - "victoryCondition": g_GameAttributes.settings.GameType, + "victoryConditions": g_GameAttributes.settings.VictoryConditions.map(vc => translateVictoryCondition(vc)).join(", "), "nbp": clients.connectedPlayers, "maxnbp": g_GameAttributes.settings.PlayerData.length, "players": clients.list, Index: binaries/data/mods/public/gui/loadgame/load.js =================================================================== --- binaries/data/mods/public/gui/loadgame/load.js +++ binaries/data/mods/public/gui/loadgame/load.js @@ -113,7 +113,7 @@ Engine.GetGUIObjectByName("savedPlayedTime").caption = timeToString(metadata.gui.timeElapsed ? metadata.gui.timeElapsed : 0); Engine.GetGUIObjectByName("savedMapType").caption = translateMapType(metadata.initAttributes.mapType); Engine.GetGUIObjectByName("savedMapSize").caption = translateMapSize(metadata.initAttributes.settings.Size); - Engine.GetGUIObjectByName("savedVictory").caption = translateVictoryCondition(metadata.initAttributes.settings.GameType); + Engine.GetGUIObjectByName("savedVictory").caption = metadata.initAttributes.settings.VictoryConditions.map(vc => translateVictoryCondition(vc)).join(", "); let caption = sprintf(translate("Mods: %(mods)s"), { "mods": modsToString(metadata.mods) }); if (!hasSameMods(metadata.mods, Engine.GetEngineInfo().mods)) Index: binaries/data/mods/public/gui/replaymenu/replay_filters.js =================================================================== --- binaries/data/mods/public/gui/replaymenu/replay_filters.js +++ binaries/data/mods/public/gui/replaymenu/replay_filters.js @@ -243,7 +243,8 @@ // Filter by victory condition let victoryConditionFilter = Engine.GetGUIObjectByName("victoryConditionFilter"); - if (victoryConditionFilter.selected > 0 && replay.attribs.settings.GameType != victoryConditionFilter.list_data[victoryConditionFilter.selected]) + if (victoryConditionFilter.selected > 0 && + replay.attribs.settings.VictoryConditions.indexOf(victoryConditionFilter.list_data[victoryConditionFilter.selected]) == -1) return false; // Filter by rating Index: binaries/data/mods/public/gui/replaymenu/replay_menu.js =================================================================== --- binaries/data/mods/public/gui/replaymenu/replay_menu.js +++ binaries/data/mods/public/gui/replaymenu/replay_menu.js @@ -109,8 +109,9 @@ g_MapNames.push(replay.attribs.settings.Name); // Extract victory conditions - if (replay.attribs.settings.GameType && g_VictoryConditions.indexOf(replay.attribs.settings.GameType) == -1) - g_VictoryConditions.push(replay.attribs.settings.GameType); + for (let vc of replay.attribs.settings.VictoryConditions) + if (g_VictoryConditions.indexOf(vc) == -1) + g_VictoryConditions.push(vc); // Extract playernames for (let playerData of replay.attribs.settings.PlayerData) @@ -182,9 +183,6 @@ if (!attribs.settings.mapType) attribs.settings.mapType = "skirmish"; - if (!attribs.settings.GameType) - attribs.settings.GameType = "conquest"; - // Remove gaia if (attribs.settings.PlayerData.length && attribs.settings.PlayerData[0] == null) attribs.settings.PlayerData.shift(); @@ -276,7 +274,8 @@ Engine.GetGUIObjectByName("sgMapName").caption = translate(replay.attribs.settings.Name); Engine.GetGUIObjectByName("sgMapSize").caption = translateMapSize(replay.attribs.settings.Size); Engine.GetGUIObjectByName("sgMapType").caption = translateMapType(replay.attribs.settings.mapType); - Engine.GetGUIObjectByName("sgVictory").caption = translateVictoryCondition(replay.attribs.settings.GameType); + Engine.GetGUIObjectByName("sgVictory").caption = replay.attribs.settings.VictoryConditions.map(vc => + translateVictoryCondition(vc)).join(", "); Engine.GetGUIObjectByName("sgNbPlayers").caption = sprintf(translate("Players: %(numberOfPlayers)s"), { "numberOfPlayers": replay.attribs.settings.PlayerData.length }); Engine.GetGUIObjectByName("replayFilename").caption = Engine.GetReplayDirectoryName(replay.directory); Index: binaries/data/mods/public/gui/replaymenu/replay_menu.xml =================================================================== --- binaries/data/mods/public/gui/replaymenu/replay_menu.xml +++ binaries/data/mods/public/gui/replaymenu/replay_menu.xml @@ -183,7 +183,7 @@ - + Index: binaries/data/mods/public/gui/session/session.js =================================================================== --- binaries/data/mods/public/gui/session/session.js +++ binaries/data/mods/public/gui/session/session.js @@ -7,8 +7,9 @@ const g_MapTypes = prepareForDropdown(g_Settings && g_Settings.MapTypes); const g_PopulationCapacities = prepareForDropdown(g_Settings && g_Settings.PopulationCapacities); const g_StartingResources = prepareForDropdown(g_Settings && g_Settings.StartingResources); -const g_VictoryConditions = prepareForDropdown(g_Settings && g_Settings.VictoryConditions); const g_VictoryDurations = prepareForDropdown(g_Settings && g_Settings.VictoryDurations); + +const g_VictoryConditions = g_Settings && g_Settings.VictoryConditions; var g_GameSpeeds; /** Index: binaries/data/mods/public/maps/random/wall_demo.json =================================================================== --- binaries/data/mods/public/maps/random/wall_demo.json +++ binaries/data/mods/public/maps/random/wall_demo.json @@ -1,13 +1,13 @@ { "settings" : { "Name" : "Wall Demo", - "GameType" : "endless", "Script" : "wall_demo.js", "Description" : "A demonstration of wall placement methods/code in random maps. Giant map size is recommended!", "Keywords": ["demo"], "CircularMap" : false, "TriggerScripts" : [ "random/wall_demo_triggers.js" - ] + ], + "VictoryConditions": [] } } Index: binaries/data/mods/public/maps/scripts/CaptureTheRelic.js =================================================================== --- binaries/data/mods/public/maps/scripts/CaptureTheRelic.js +++ binaries/data/mods/public/maps/scripts/CaptureTheRelic.js @@ -12,7 +12,7 @@ } let cmpEndGameManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager); - let numSpawnedRelics = cmpEndGameManager.GetGameTypeSettings().relicCount; + let numSpawnedRelics = cmpEndGameManager.GetGameSettings().relicCount; this.playerRelicsCount = new Array(TriggerHelper.GetNumberOfPlayers()).fill(0, 1); this.playerRelicsCount[0] = numSpawnedRelics; @@ -122,7 +122,7 @@ let cmpPlayer = QueryOwnerInterface(this.relics[0], IID_Player); let cmpEndGameManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager); - let captureTheRelicDuration = cmpEndGameManager.GetGameTypeSettings().relicDuration; + let captureTheRelicDuration = cmpEndGameManager.GetGameSettings().relicDuration; let isTeam = playerAndAllies.length > 1; this.ownRelicsVictoryMessage = cmpGuiInterface.AddTimeNotification({ Index: binaries/data/mods/public/maps/scripts/Conquest.js =================================================================== --- binaries/data/mods/public/maps/scripts/Conquest.js +++ binaries/data/mods/public/maps/scripts/Conquest.js @@ -1,5 +1,7 @@ { let cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); - cmpTrigger.conquestClassFilter = "ConquestCritical"; - cmpTrigger.conquestDefeatReason = markForTranslation("%(player)s has been defeated (lost all critical units and structures)."); + cmpTrigger.ConquestAddVictoryCondition({ + "classFilter": "ConquestCritical", + "defeatReason": markForTranslation("%(player)s has been defeated (lost all critical units and structures).") + }); } Index: binaries/data/mods/public/maps/scripts/ConquestCommon.js =================================================================== --- binaries/data/mods/public/maps/scripts/ConquestCommon.js +++ binaries/data/mods/public/maps/scripts/ConquestCommon.js @@ -1,17 +1,20 @@ Trigger.prototype.ConquestOwnershipChanged = function(msg) { - if (!this.conquestDataInit || !this.conquestClassFilter) + if (!this.conquestDataInit) return; - if (!TriggerHelper.EntityMatchesClassList(msg.entity, this.conquestClassFilter)) - return; + for (let i = 0; i < this.conquestQueries.length; ++i) + { + if (!TriggerHelper.EntityMatchesClassList(msg.entity, this.conquestQueries[i].classFilter)) + continue; - if (msg.to > 0) - this.conquestEntitiesByPlayer[msg.to].push(msg.entity); + if (msg.to > 0) + this.conquestQueries[i].entitiesByPlayer[msg.to].push(msg.entity); - if (msg.from > 0) - { - let entities = this.conquestEntitiesByPlayer[msg.from]; + if (msg.from <= 0) + continue; + + let entities = this.conquestQueries[i].entitiesByPlayer[msg.from]; let index = entities.indexOf(msg.entity); if (index != -1) entities.splice(index, 1); @@ -20,35 +23,41 @@ { let cmpPlayer = QueryPlayerIDInterface(msg.from); if (cmpPlayer) - cmpPlayer.SetState("defeated", this.conquestDefeatReason); + cmpPlayer.SetState("defeated", this.conquestQueries[i].defeatReason); } } }; Trigger.prototype.ConquestStartGameCount = function() { - if (!this.conquestClassFilter) + if (!this.conquestQueries.length) { - warn("ConquestStartGameCount: conquestClassFilter undefined"); + warn("ConquestStartGameCount: no conquestQueries set"); return; } let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); - - let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers(); - for (let i = 1; i < numPlayers; ++i) - this.conquestEntitiesByPlayer[i] = - cmpRangeManager.GetEntitiesByPlayer(i).filter(ent => - TriggerHelper.EntityMatchesClassList(ent, this.conquestClassFilter)); + let entitiesByPlayer = []; + for (let playerID of Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetAllPlayers()) + entitiesByPlayer[playerID] = cmpRangeManager.GetEntitiesByPlayer(playerID); + + for (let i = 0; i < this.conquestQueries.length; ++i) + this.conquestQueries[i].entitiesByPlayer = entitiesByPlayer.map( + ents => ents.filter( + ent => TriggerHelper.EntityMatchesClassList(ent, this.conquestQueries[i].classFilter))); this.conquestDataInit = true; }; +Trigger.prototype.ConquestAddVictoryCondition = function(data) +{ + this.conquestQueries.push(data); +}; + { let cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); - cmpTrigger.conquestEntitiesByPlayer = {}; cmpTrigger.conquestDataInit = false; - cmpTrigger.conquestClassFilter = ""; + cmpTrigger.conquestQueries = []; cmpTrigger.RegisterTrigger("OnOwnershipChanged", "ConquestOwnershipChanged", { "enabled": true }); cmpTrigger.DoAfterDelay(0, "ConquestStartGameCount", null); } Index: binaries/data/mods/public/maps/scripts/ConquestStructures.js =================================================================== --- binaries/data/mods/public/maps/scripts/ConquestStructures.js +++ binaries/data/mods/public/maps/scripts/ConquestStructures.js @@ -1,5 +1,7 @@ { let cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); - cmpTrigger.conquestClassFilter = "Structure"; - cmpTrigger.conquestDefeatReason = markForTranslation("%(player)s has been defeated (lost all structures)."); + cmpTrigger.ConquestAddVictoryCondition({ + "classFilter": "Structure", + "defeatReason": markForTranslation("%(player)s has been defeated (lost all structures).") + }); } Index: binaries/data/mods/public/maps/scripts/ConquestUnits.js =================================================================== --- binaries/data/mods/public/maps/scripts/ConquestUnits.js +++ binaries/data/mods/public/maps/scripts/ConquestUnits.js @@ -1,5 +1,7 @@ { let cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); - cmpTrigger.conquestClassFilter = "Unit+!Animal"; - cmpTrigger.conquestDefeatReason = markForTranslation("%(player)s has been defeated (lost all units)."); + cmpTrigger.ConquestAddVictoryCondition({ + "classFilter": "Unit+!Animal", + "defeatReason": markForTranslation("%(player)s has been defeated (lost all units).") + }); } Index: binaries/data/mods/public/maps/scripts/Regicide.js =================================================================== --- binaries/data/mods/public/maps/scripts/Regicide.js +++ binaries/data/mods/public/maps/scripts/Regicide.js @@ -9,7 +9,7 @@ Trigger.prototype.InitRegicideGame = function(msg) { let cmpEndGameManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager); - let regicideGarrison = cmpEndGameManager.GetGameTypeSettings().regicideGarrison; + let regicideGarrison = cmpEndGameManager.GetGameSettings().regicideGarrison; let playersCivs = []; for (let playerID = 1; playerID < TriggerHelper.GetNumberOfPlayers(); ++playerID) Index: binaries/data/mods/public/maps/scripts/WonderVictory.js =================================================================== --- binaries/data/mods/public/maps/scripts/WonderVictory.js +++ binaries/data/mods/public/maps/scripts/WonderVictory.js @@ -54,7 +54,7 @@ let cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); - let wonderDuration = cmpEndGameManager.GetGameTypeSettings().wonderDuration; + let wonderDuration = cmpEndGameManager.GetGameSettings().wonderDuration; this.wonderVictoryMessages[ent] = { "playerID": player, "allies": new Set(allies), Index: binaries/data/mods/public/maps/tutorials/Introductory_Tutorial.xml =================================================================== --- binaries/data/mods/public/maps/tutorials/Introductory_Tutorial.xml +++ binaries/data/mods/public/maps/tutorials/Introductory_Tutorial.xml @@ -40,7 +40,6 @@ { "CircularMap": true, "Description": "This is a basic tutorial to get you started playing 0 A.D.", - "GameType": "endless", "Keywords": ["demo"], "LockTeams": false, "Name": "Introductory Tutorial", @@ -86,7 +85,8 @@ "scripts/TriggerHelper.js", "scripts/Tutorial.js", "tutorials/Introductory_Tutorial.js" - ] + ], + "VictoryConditions": [] } ]]> Index: binaries/data/mods/public/maps/tutorials/starting_economy_walkthrough.xml =================================================================== --- binaries/data/mods/public/maps/tutorials/starting_economy_walkthrough.xml +++ binaries/data/mods/public/maps/tutorials/starting_economy_walkthrough.xml @@ -48,7 +48,6 @@ ], "CircularMap": true, "Description": "This map will give a rough guide for starting the game effectively. Early in the game the most important thing is to gather resources as fast as possible so you are able to build enough troops later.", - "GameType": "endless", "Keywords": ["trigger"], "LockTeams": false, "Name": "Starting Economy Walkthrough", @@ -71,7 +70,8 @@ "scripts/Tutorial.js", "tutorials/starting_economy_walkthrough.js" ], - "Size": 256 + "Size": 256, + "VictoryConditions": [] } ]]> Index: binaries/data/mods/public/simulation/ai/common-api/shared.js =================================================================== --- binaries/data/mods/public/simulation/ai/common-api/shared.js +++ binaries/data/mods/public/simulation/ai/common-api/shared.js @@ -74,7 +74,7 @@ this.timeElapsed = state.timeElapsed; this.circularMap = state.circularMap; this.mapSize = state.mapSize; - this.victoryConditions = new Set([state.gameType]); + this.victoryConditions = new Set(state.victoryConditions); this.alliedVictory = state.alliedVictory; this.ceasefireActive = state.ceasefireActive; this.ceasefireTimeRemaining = state.ceasefireTimeRemaining / 1000; Index: binaries/data/mods/public/simulation/components/EndGameManager.js =================================================================== --- binaries/data/mods/public/simulation/components/EndGameManager.js +++ binaries/data/mods/public/simulation/components/EndGameManager.js @@ -9,11 +9,9 @@ EndGameManager.prototype.Init = function() { - this.gameType = "conquest"; - // Contains settings specific to the victory condition, // for example wonder victory duration. - this.gameTypeSettings = {}; + this.gameSettings = {}; // Allied victory means allied players can win if victory conditions are met for each of them // False for a "last man standing" game @@ -28,24 +26,23 @@ this.endlessGame = false; }; -EndGameManager.prototype.GetGameType = function() +EndGameManager.prototype.GetGameSettings = function() { - return this.gameType; + return this.gameSettings; }; -EndGameManager.prototype.GetGameTypeSettings = function() +EndGameManager.prototype.GetVictoryConditions = function() { - return this.gameTypeSettings; + return this.gameSettings.victoryConditions; }; -EndGameManager.prototype.SetGameType = function(newGameType, newSettings = {}) +EndGameManager.prototype.SetGameSettings = function(newSettings = {}) { - this.gameType = newGameType; - this.gameTypeSettings = newSettings; + this.gameSettings = newSettings; this.skipAlliedVictoryCheck = false; - this.endlessGame = newGameType == "endless"; + this.endlessGame = !this.gameSettings.victoryConditions.length; - Engine.BroadcastMessage(MT_GameTypeChanged, {}); + Engine.BroadcastMessage(MT_VictoryConditionsChanged, {}); }; /** Index: binaries/data/mods/public/simulation/components/GuiInterface.js =================================================================== --- binaries/data/mods/public/simulation/components/GuiInterface.js +++ binaries/data/mods/public/simulation/components/GuiInterface.js @@ -154,7 +154,7 @@ // Add the game type and allied victory let cmpEndGameManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager); - ret.gameType = cmpEndGameManager.GetGameType(); + ret.victoryConditions = cmpEndGameManager.GetVictoryConditions(); ret.alliedVictory = cmpEndGameManager.GetAlliedVictory(); // Add basic statistics to each player Index: binaries/data/mods/public/simulation/components/interfaces/EndGameManager.js =================================================================== --- binaries/data/mods/public/simulation/components/interfaces/EndGameManager.js +++ binaries/data/mods/public/simulation/components/interfaces/EndGameManager.js @@ -4,4 +4,4 @@ * Message of the form {} * sent from EndGameManager component. */ -Engine.RegisterMessageType("GameTypeChanged"); +Engine.RegisterMessageType("VictoryConditionsChanged"); Index: binaries/data/mods/public/simulation/components/tests/test_EndGameManager.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_EndGameManager.js +++ binaries/data/mods/public/simulation/components/tests/test_EndGameManager.js @@ -23,7 +23,10 @@ TS_ASSERT_EQUALS(cmpEndGameManager.skipAlliedVictoryCheck, true); cmpEndGameManager.SetAlliedVictory(true); TS_ASSERT_EQUALS(cmpEndGameManager.GetAlliedVictory(), true); -cmpEndGameManager.SetGameType("wonder", { "wonderDuration": wonderDuration }); +cmpEndGameManager.SetGameSettings({ + "victoryConditions": ["wonder"], + "wonderDuration": wonderDuration +}); TS_ASSERT_EQUALS(cmpEndGameManager.skipAlliedVictoryCheck, false); -TS_ASSERT(cmpEndGameManager.GetGameType() == "wonder"); -TS_ASSERT_EQUALS(cmpEndGameManager.GetGameTypeSettings().wonderDuration, wonderDuration); +TS_ASSERT_UNEVAL_EQUALS(cmpEndGameManager.GetVictoryConditions(), ["wonder"]); +TS_ASSERT_EQUALS(cmpEndGameManager.GetGameSettings().wonderDuration, wonderDuration); Index: binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js +++ binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js @@ -65,7 +65,7 @@ }); AddMock(SYSTEM_ENTITY, IID_EndGameManager, { - GetGameType: function() { return "conquest"; }, + GetVictoryConditions: () => ["conquest", "wonder"], GetAlliedVictory: function() { return false; } }); @@ -365,7 +365,7 @@ ], circularMap: false, timeElapsed: 0, - gameType: "conquest", + "victoryConditions": ["conquest", "wonder"], alliedVictory: false }); @@ -518,7 +518,7 @@ ], "circularMap": false, "timeElapsed": 0, - "gameType": "conquest", + "victoryConditions": ["conquest", "wonder"], "alliedVictory": false }); Index: binaries/data/mods/public/simulation/data/settings/victory_conditions/capture_the_relic.json =================================================================== --- binaries/data/mods/public/simulation/data/settings/victory_conditions/capture_the_relic.json +++ binaries/data/mods/public/simulation/data/settings/victory_conditions/capture_the_relic.json @@ -7,8 +7,6 @@ "Scripts": [ "scripts/TriggerHelper.js", - "scripts/ConquestCommon.js", - "scripts/Conquest.js", "scripts/CaptureTheRelic.js" ] } Index: binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest.json =================================================================== --- binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest.json +++ binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest.json @@ -3,13 +3,17 @@ "Data": { "Title": "Conquest", - "Description": "Defeat all opponents to win.", + "Description": "Defeat opponents by killing all their units and destroying all their structures.", "Scripts": [ "scripts/TriggerHelper.js", "scripts/ConquestCommon.js", "scripts/Conquest.js" ], - "Default": true + "Default": true, + "ChangeOnChecked": { + "conquest_units": false, + "conquest_structures": false + } } } Index: binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest_structures.json =================================================================== --- binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest_structures.json +++ binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest_structures.json @@ -3,12 +3,13 @@ "Data": { "Title": "Conquest Structures", - "Description": "Destroy all enemy structures to win.", + "Description": "Defeat opponents by destroying all their structures.", "Scripts": [ "scripts/TriggerHelper.js", "scripts/ConquestCommon.js", "scripts/ConquestStructures.js" - ] + ], + "DisabledWhenChecked": ["conquest"] } } Index: binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest_units.json =================================================================== --- binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest_units.json +++ binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest_units.json @@ -3,12 +3,13 @@ "Data": { "Title": "Conquest Units", - "Description": "Kill all enemy units to win.", + "Description": "Defeat opponents by killing all their units.", "Scripts": [ "scripts/TriggerHelper.js", "scripts/ConquestCommon.js", "scripts/ConquestUnits.js" - ] + ], + "DisabledWhenChecked": ["conquest"] } } Index: binaries/data/mods/public/simulation/data/settings/victory_conditions/regicide.json =================================================================== --- binaries/data/mods/public/simulation/data/settings/victory_conditions/regicide.json +++ binaries/data/mods/public/simulation/data/settings/victory_conditions/regicide.json @@ -7,8 +7,6 @@ "Scripts": [ "scripts/TriggerHelper.js", - "scripts/ConquestCommon.js", - "scripts/Conquest.js", "scripts/Regicide.js" ] } Index: binaries/data/mods/public/simulation/data/settings/victory_conditions/wonder.json =================================================================== --- binaries/data/mods/public/simulation/data/settings/victory_conditions/wonder.json +++ binaries/data/mods/public/simulation/data/settings/victory_conditions/wonder.json @@ -7,8 +7,6 @@ "Scripts": [ "scripts/TriggerHelper.js", - "scripts/ConquestCommon.js", - "scripts/Conquest.js", "scripts/WonderVictory.js" ] } Index: binaries/data/mods/public/simulation/helpers/Setup.js =================================================================== --- binaries/data/mods/public/simulation/helpers/Setup.js +++ binaries/data/mods/public/simulation/helpers/Setup.js @@ -53,17 +53,17 @@ } let cmpEndGameManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager); - let gameTypeSettings = {}; - if (settings.GameType && settings.GameType == "capture_the_relic") - gameTypeSettings.relicCount = settings.RelicCount; - if (settings.GameType && settings.GameType == "capture_the_relic") - gameTypeSettings.relicDuration = settings.RelicDuration * 60 * 1000; - if (settings.GameType && settings.GameType == "wonder") - gameTypeSettings.wonderDuration = settings.WonderDuration * 60 * 1000; - if (settings.GameType && settings.GameType == "regicide") - gameTypeSettings.regicideGarrison = settings.RegicideGarrison; - if (settings.GameType) - cmpEndGameManager.SetGameType(settings.GameType, gameTypeSettings); + let gameSettings = { "victoryConditions": settings.VictoryConditions }; + if (gameSettings.victoryConditions.indexOf("capture_the_relic") != -1) + { + gameSettings.relicCount = settings.RelicCount; + gameSettings.relicDuration = settings.RelicDuration * 60 * 1000; + } + if (gameSettings.victoryConditions.indexOf("wonder") != -1) + gameSettings.wonderDuration = settings.WonderDuration * 60 * 1000; + if (gameSettings.victoryConditions.indexOf("regicide") != -1) + gameSettings.regicideGarrison = settings.RegicideGarrison; + cmpEndGameManager.SetGameSettings(gameSettings); cmpEndGameManager.SetAlliedVictory(settings.LockTeams || !settings.LastManStanding); if (settings.LockTeams && settings.LastManStanding) Index: source/ps/GameSetup/GameSetup.cpp =================================================================== --- source/ps/GameSetup/GameSetup.cpp +++ source/ps/GameSetup/GameSetup.cpp @@ -1155,7 +1155,7 @@ * -autostart-nonvisual disable any graphics and sounds * -autostart-victory=SCRIPTNAME sets the victory conditions with SCRIPTNAME * located in simulation/data/settings/victory_conditions/ - * (default conquest) + * (default none) * -autostart-wonderduration=NUM sets the victory duration NUM for wonder victory conditions * (default 10 minutes) * -autostart-relicduration=NUM sets the victory duration NUM for relic victory conditions @@ -1464,24 +1464,29 @@ triggerScriptsVector.push_back(nonVisualScript.FromUTF8()); } - CStr victory = "conquest"; + std::vector victoryConditions; if (args.Has("autostart-victory")) - victory = args.Get("autostart-victory"); + victoryConditions = args.GetMultiple("autostart-victory"); - scriptInterface.SetProperty(settings, "GameType", std::string(victory)); + scriptInterface.SetProperty(settings, "VictoryConditions", victoryConditions); - CStrW scriptPath = L"simulation/data/settings/victory_conditions/" + victory.FromUTF8() + L".json"; - JS::RootedValue scriptData(cx); - JS::RootedValue data(cx); - JS::RootedValue victoryScripts(cx); - scriptInterface.ReadJSONFile(scriptPath, &scriptData); - if (!scriptData.isUndefined() && scriptInterface.GetProperty(scriptData, "Data", &data) && !data.isUndefined() - && scriptInterface.GetProperty(data, "Scripts", &victoryScripts) && !victoryScripts.isUndefined()) - { - std::vector victoryScriptsVector; - FromJSVal_vector(cx, victoryScripts, victoryScriptsVector); - triggerScriptsVector.insert(triggerScriptsVector.end(), victoryScriptsVector.begin(), victoryScriptsVector.end()); + for (CStr victory : victoryConditions) + { + JS::RootedValue scriptData(cx); + JS::RootedValue data(cx); + JS::RootedValue victoryScripts(cx); + + CStrW scriptPath = L"simulation/data/settings/victory_conditions/" + victory.FromUTF8() + L".json"; + scriptInterface.ReadJSONFile(scriptPath, &scriptData); + if (!scriptData.isUndefined() && scriptInterface.GetProperty(scriptData, "Data", &data) && !data.isUndefined() + && scriptInterface.GetProperty(data, "Scripts", &victoryScripts) && !victoryScripts.isUndefined()) + { + std::vector victoryScriptsVector; + FromJSVal_vector(cx, victoryScripts, victoryScriptsVector); + triggerScriptsVector.insert(triggerScriptsVector.end(), victoryScriptsVector.begin(), victoryScriptsVector.end()); + } } + ToJSVal_vector(cx, &triggerScripts, triggerScriptsVector); scriptInterface.SetProperty(settings, "TriggerScripts", triggerScripts); Index: source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp =================================================================== --- source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp +++ source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp @@ -41,6 +41,12 @@ ID_MapTeams, ID_MapKW_Demo, ID_MapKW_Naval, + ID_VC_Conquest, + ID_VC_ConquestUnits, + ID_VC_ConquestStructures, + ID_VC_CaptureTheRelic, + ID_VC_Wonder, + ID_VC_Regicide, ID_RandomScript, ID_RandomSize, ID_RandomNomad, @@ -97,13 +103,17 @@ AtObj UpdateSettingsObject(); private: void SendToEngine(); + void OnConquestChanged(); - void OnEdit(wxCommandEvent& WXUNUSED(evt)) + void OnEdit(wxCommandEvent& evt) { SendToEngine(); + if (evt.GetId() == ID_VC_Conquest) + OnConquestChanged(); } std::set m_MapSettingsKeywords; + std::set m_MapSettingsVictoryConditions; std::vector m_PlayerCivChoices; Observable& m_MapSettings; @@ -146,31 +156,34 @@ sizer->AddSpacer(5); - // TODO: replace by filenames in binaries/data/mods/public/simulation/data/settings/victory_conditions/ - wxArrayString gameTypes; - gameTypes.Add(_T("conquest")); - gameTypes.Add(_T("conquest_structures")); - gameTypes.Add(_T("conquest_units")); - gameTypes.Add(_T("wonder")); - gameTypes.Add(_T("endless")); - gameTypes.Add(_T("regicide")); - gameTypes.Add(_T("capture_the_relic")); - wxFlexGridSizer* gridSizer = new wxFlexGridSizer(2, 5, 5); gridSizer->AddGrowableCol(1); + // TODO: have preview selector tool? gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Preview")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT)); gridSizer->Add(Tooltipped(new wxTextCtrl(this, ID_MapPreview, wxEmptyString), _("Texture used for map preview")), wxSizerFlags().Expand()); CREATE_CHECKBOX(this, gridSizer, "Reveal map", "If checked, players won't need to explore", ID_MapReveal); - gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Game type")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT)); - gridSizer->Add(Tooltipped(new wxChoice(this, ID_MapType, wxDefaultPosition, wxDefaultSize, gameTypes), - _("Select the game type (or victory condition)")), wxSizerFlags().Expand()); CREATE_CHECKBOX(this, gridSizer, "Lock teams", "If checked, teams will be locked", ID_MapTeams); sizer->Add(gridSizer, wxSizerFlags().Expand()); sizer->AddSpacer(5); + // TODO: replace by names in binaries/data/mods/public/simulation/data/settings/victory_conditions/ + wxStaticBoxSizer* victoryConditionSizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Victory Conditions")); + wxFlexGridSizer* vcGridSizer = new wxFlexGridSizer(2, 5, 5); + vcGridSizer->AddGrowableCol(1); + CREATE_CHECKBOX(this, vcGridSizer, "Conquest", "Select Conquest victory condition", ID_VC_Conquest); + CREATE_CHECKBOX(this, vcGridSizer, "Conquest Units", "Select Conquest Units victory condition", ID_VC_ConquestUnits); + CREATE_CHECKBOX(this, vcGridSizer, "Conquest Structures", "Select Conquest Structures victory condition", ID_VC_ConquestStructures); + CREATE_CHECKBOX(this, vcGridSizer, "Capture the Relic", "Select Capture the Relic victory condition", ID_VC_CaptureTheRelic); + CREATE_CHECKBOX(this, vcGridSizer, "Wonder", "Select Wonder victory condition", ID_VC_Wonder); + CREATE_CHECKBOX(this, vcGridSizer, "Regicide", "Select Regicide victory condition", ID_VC_Regicide); + victoryConditionSizer->Add(vcGridSizer); + sizer->Add(victoryConditionSizer, wxSizerFlags().Expand()); + + sizer->AddSpacer(5); + wxStaticBoxSizer* keywordsSizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Keywords")); wxFlexGridSizer* kwGridSizer = new wxFlexGridSizer(4, 5, 5); CREATE_CHECKBOX(this, kwGridSizer, "Demo", "If checked, map will only be visible using filters in game setup", ID_MapKW_Demo); @@ -201,11 +214,24 @@ // reveal map wxDynamicCast(FindWindow(ID_MapReveal), wxCheckBox)->SetValue(wxString(m_MapSettings["RevealMap"]) == L"true"); - // game type / victory conditions - if (m_MapSettings["GameType"].defined()) - wxDynamicCast(FindWindow(ID_MapType), wxChoice)->SetStringSelection(wxString(m_MapSettings["GameType"])); - else - wxDynamicCast(FindWindow(ID_MapType), wxChoice)->SetSelection(0); + // victory conditions + m_MapSettingsVictoryConditions.clear(); + for (AtIter victoryCondition = m_MapSettings["VictoryConditions"]["item"]; victoryCondition.defined(); ++victoryCondition) + m_MapSettingsVictoryConditions.insert(std::wstring(victoryCondition)); + + wxWindow* window; +#define INIT_CHECKBOX(ID, mapSettings, value) \ + window = FindWindow(ID_VC_Conquest); \ + if (window != nullptr) \ + wxDynamicCast(window, wxCheckBox)->SetValue(mapSettings.count(value) != 0); + + INIT_CHECKBOX(ID_VC_Conquest, m_MapSettingsVictoryConditions, L"conquest"); + INIT_CHECKBOX(ID_VC_ConquestUnits, m_MapSettingsVictoryConditions, L"conquest_units"); + INIT_CHECKBOX(ID_VC_ConquestStructures, m_MapSettingsVictoryConditions, L"conquest_structures"); + INIT_CHECKBOX(ID_VC_CaptureTheRelic, m_MapSettingsVictoryConditions, L"capture_the_relic"); + INIT_CHECKBOX(ID_VC_Wonder, m_MapSettingsVictoryConditions, L"wonder"); + INIT_CHECKBOX(ID_VC_Regicide, m_MapSettingsVictoryConditions, L"regicide"); + OnConquestChanged(); // lock teams wxDynamicCast(FindWindow(ID_MapTeams), wxCheckBox)->SetValue(wxString(m_MapSettings["LockTeams"]) == L"true"); @@ -216,8 +242,8 @@ for (AtIter keyword = m_MapSettings["Keywords"]["item"]; keyword.defined(); ++keyword) m_MapSettingsKeywords.insert(std::wstring(keyword)); - wxDynamicCast(FindWindow(ID_MapKW_Demo), wxCheckBox)->SetValue(m_MapSettingsKeywords.count(L"demo") != 0); - wxDynamicCast(FindWindow(ID_MapKW_Naval), wxCheckBox)->SetValue(m_MapSettingsKeywords.count(L"naval") != 0); + INIT_CHECKBOX(ID_MapKW_Demo, m_MapSettingsKeywords, L"demo"); + INIT_CHECKBOX(ID_MapKW_Naval, m_MapSettingsKeywords, L"naval"); } } @@ -229,6 +255,21 @@ SendToEngine(); } +void MapSettingsControl::OnConquestChanged() +{ + bool conqestEnabled = wxDynamicCast(FindWindow(ID_VC_Conquest), wxCheckBox)->GetValue(); + + wxCheckBox* conquestUnitsCheckbox = wxDynamicCast(FindWindow(ID_VC_ConquestUnits), wxCheckBox); + conquestUnitsCheckbox->Enable(!conqestEnabled); + wxCheckBox* conquestStructuresCheckbox = wxDynamicCast(FindWindow(ID_VC_ConquestStructures), wxCheckBox); + conquestStructuresCheckbox->Enable(!conqestEnabled); + if (conqestEnabled) + { + conquestUnitsCheckbox->SetValue(false); + conquestStructuresCheckbox->SetValue(false); + } +} + AtObj MapSettingsControl::UpdateSettingsObject() { // map name @@ -243,8 +284,25 @@ // reveal map m_MapSettings.setBool("RevealMap", wxDynamicCast(FindWindow(ID_MapReveal), wxCheckBox)->GetValue()); - // game type / victory conditions - m_MapSettings.set("GameType", wxDynamicCast(FindWindow(ID_MapType), wxChoice)->GetStringSelection()); + // victory conditions +#define INSERT_VICTORY_CONDITION_CHECKBOX(name, ID) \ + if (wxDynamicCast(FindWindow(ID), wxCheckBox)->GetValue()) \ + m_MapSettingsVictoryConditions.insert(name); \ + else \ + m_MapSettingsVictoryConditions.erase(name); + + INSERT_VICTORY_CONDITION_CHECKBOX(L"conquest", ID_VC_Conquest); + INSERT_VICTORY_CONDITION_CHECKBOX(L"conquest_units", ID_VC_ConquestUnits); + INSERT_VICTORY_CONDITION_CHECKBOX(L"conquest_structures", ID_VC_ConquestStructures); + INSERT_VICTORY_CONDITION_CHECKBOX(L"capture_the_relic", ID_VC_CaptureTheRelic); + INSERT_VICTORY_CONDITION_CHECKBOX(L"wonder", ID_VC_Wonder); + INSERT_VICTORY_CONDITION_CHECKBOX(L"regicide", ID_VC_Regicide); + + AtObj victoryConditions; + victoryConditions.set("@array", L""); + for (std::set::iterator it = m_MapSettingsVictoryConditions.begin(); it != m_MapSettingsVictoryConditions.end(); ++it) + victoryConditions.add("item", it->c_str()); + m_MapSettings.set("VictoryConditions", victoryConditions); // keywords {