diff --git a/binaries/data/mods/public/gui/common/gamedescription.js b/binaries/data/mods/public/gui/common/gamedescription.js
index af4de5ff4c..af601adfd2 100644
--- a/binaries/data/mods/public/gui/common/gamedescription.js
+++ b/binaries/data/mods/public/gui/common/gamedescription.js
@@ -216,12 +216,23 @@ function formatPlayerInfo(playerDataArray, playerStates)
function getGameDescription(extended = false)
{
let titles = [];
+ if (!g_GameAttributes.settings.VictoryConditions.length)
+ titles.push({
+ "label": translateWithContext("victory condition", "Endless Game"),
+ "value": translate("No winner will be determined, even if everyone is defeated.")
+ });
- let victoryIdx = g_VictoryConditions.Name.indexOf(g_GameAttributes.settings.GameType || g_VictoryConditions.Default);
- if (victoryIdx != -1)
+ let victoryConditions = g_GameAttributes.settings.VictoryConditions.map(victoryConditionName =>
+ g_VictoryConditions.find(victoryCondition => victoryCondition.Name == victoryConditionName) || {
+ "Name": victoryConditionName,
+ "Description": ""
+ });
+
+ for (let victoryCondition of victoryConditions.sort((a, b) =>
+ a.GUIOrder - b.GUIOrder || (a.Title > b.Title ? 1 : a.Title > b.Title ? -1 : 0)))
{
- let title = g_VictoryConditions.Title[victoryIdx];
- if (g_VictoryConditions.Name[victoryIdx] == "wonder")
+ let title = translateVictoryCondition(victoryCondition.Name);
+ if (victoryCondition.Name == "wonder")
title = sprintf(
translatePluralWithContext(
"victory condition",
@@ -232,7 +243,7 @@ function getGameDescription(extended = false)
{ "min": g_GameAttributes.settings.WonderDuration }
);
- let isCaptureTheRelic = g_VictoryConditions.Name[victoryIdx] == "capture_the_relic";
+ let isCaptureTheRelic = victoryCondition.Name == "capture_the_relic";
if (isCaptureTheRelic)
title = sprintf(
translatePluralWithContext(
@@ -246,7 +257,7 @@ function getGameDescription(extended = false)
titles.push({
"label": title,
- "value": g_VictoryConditions.Description[victoryIdx]
+ "value": victoryCondition.Description
});
if (isCaptureTheRelic)
@@ -255,7 +266,7 @@ function getGameDescription(extended = false)
"value": g_GameAttributes.settings.RelicCount
});
- if (g_VictoryConditions.Name[victoryIdx] == "regicide")
+ if (victoryCondition.Name == "regicide")
if (g_GameAttributes.settings.RegicideGarrison)
titles.push({
"label": translate("Hero Garrison"),
@@ -264,7 +275,7 @@ function getGameDescription(extended = false)
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.")
});
}
diff --git a/binaries/data/mods/public/gui/common/settings.js b/binaries/data/mods/public/gui/common/settings.js
index ce83d0f4aa..4630cec33e 100644
--- a/binaries/data/mods/public/gui/common/settings.js
+++ b/binaries/data/mods/public/gui/common/settings.js
@@ -247,7 +247,7 @@ function loadBiomes()
}
/**
- * Loads available gametypes.
+ * Loads available victoryCondtions from json files.
*
* @returns {Array|undefined}
*/
@@ -256,24 +256,15 @@ function loadVictoryConditions()
let subdir = "victory_conditions/";
let victoryConditions = listFiles(g_SettingsDirectory + subdir, ".json", false).map(victoryScriptName => {
- let vc = loadSettingValuesFile(subdir + victoryScriptName + ".json");
- if (vc)
- vc.Name = victoryScriptName;
- return vc;
+ let victoryCondition = loadSettingValuesFile(subdir + victoryScriptName + ".json");
+ if (victoryCondition)
+ victoryCondition.Name = victoryScriptName;
+ return victoryCondition;
});
- if (victoryConditions.some(vc => vc == undefined))
+ if (victoryConditions.some(victoryCondition => victoryCondition == 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 @@ function translatePopulationCapacity(population)
/**
* Returns title or placeholder.
*
- * @param {string} gameType - for example "conquest"
+ * @param {string} victoryConditionName - For example "conquest".
* @returns {string}
*/
-function translateVictoryCondition(gameType)
+function translateVictoryCondition(victoryConditionName)
{
- let victoryCondition = g_Settings.VictoryConditions.find(vc => vc.Name == gameType);
- return victoryCondition ? victoryCondition.Title : translateWithContext("victory condition", "Unknown");
+ let victoryCondition = g_Settings.VictoryConditions.find(victoryCondition => victoryCondition.Name == victoryConditionName);
+ return victoryCondition ? victoryCondition.Title : translate("Unknown Victory Condition");
}
diff --git a/binaries/data/mods/public/gui/gamesetup/gamesetup.js b/binaries/data/mods/public/gui/gamesetup/gamesetup.js
index ef7e37d9ad..124168397f 100644
--- a/binaries/data/mods/public/gui/gamesetup/gamesetup.js
+++ b/binaries/data/mods/public/gui/gamesetup/gamesetup.js
@@ -7,8 +7,9 @@ const g_MapTypes = prepareForDropdown(g_Settings && g_Settings.MapTypes);
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);
/**
@@ -433,7 +434,7 @@ var g_SettingsTabsGUI = [
{
"label": translateWithContext("Match settings tab name", "Game Type"),
"settings": [
- "victoryCondition",
+ ...g_VictoryConditions.map(victoryCondition => victoryCondition.Name),
"relicCount",
"relicDuration",
"wonderDuration",
@@ -640,22 +641,6 @@ var g_Dropdowns = {
"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 +652,7 @@ var g_Dropdowns = {
"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 +667,7 @@ var g_Dropdowns = {
"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 +682,7 @@ var g_Dropdowns = {
"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 +807,34 @@ var g_PlayerDropdowns = {
/**
* 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,
+ // Defaults are set in supplementDefault directly from g_VictoryConditions since we use an array
+ "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(victoryConditionName => victoryConditionName != victoryCondition.Name);
+ },
+ "enabled": () =>
+ g_GameAttributes.mapType != "scenario" &&
+ (!victoryCondition.DisabledWhenChecked ||
+ victoryCondition.DisabledWhenChecked.every(victoryConditionName => g_GameAttributes.settings.VictoryConditions.indexOf(victoryConditionName) == -1))
+ };
+ return obj;
+ }, {}),
+ {
"regicideGarrison": {
"title": () => translate("Hero Garrison"),
"tooltip": () => translate("Toggle whether heroes can be garrisoned."),
@@ -832,7 +844,7 @@ var g_Checkboxes = {
"set": checked => {
g_GameAttributes.settings.RegicideGarrison = checked;
},
- "hidden": () => g_GameAttributes.settings.GameType != "regicide",
+ "hidden": () => g_GameAttributes.settings.VictoryConditions.indexOf("regicide") == -1,
"enabled": () => g_GameAttributes.mapType != "scenario",
"initOrder": 1000
},
@@ -968,7 +980,8 @@ var g_Checkboxes = {
},
"initOrder": 1000
},
-};
+ }
+);
/**
* For setting up arbitrary GUI objects.
@@ -1149,6 +1162,9 @@ function initDefaults()
*/
function supplementDefaults()
{
+ g_GameAttributes.settings.VictoryConditions = g_GameAttributes.settings.VictoryConditions ||
+ g_VictoryConditions.filter(victoryCondition => !!victoryCondition.Default).map(victoryCondition => victoryCondition.Name);
+
for (let dropdown in g_Dropdowns)
if (!g_Dropdowns[dropdown].defined())
g_Dropdowns[dropdown].select(g_Dropdowns[dropdown].default());
@@ -1987,14 +2003,8 @@ function selectMap(name)
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 +2144,7 @@ function launchGame()
// 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 +2152,11 @@ function launchGame()
g_BiomeList.Id.slice(1).filter(biomeID => biomeID.startsWith(g_GameAttributes.settings.SupportedBiomes)) :
g_GameAttributes.settings.SupportedBiomes);
+ g_GameAttributes.settings.VictoryScripts = g_GameAttributes.settings.VictoryConditions.reduce(
+ (scripts, victoryConditionName) => scripts.concat(g_VictoryConditions[g_VictoryConditions.map(data =>
+ data.Name).indexOf(victoryConditionName)].Scripts.filter(script => scripts.indexOf(script) == -1)),
+ []);
+
g_GameAttributes.settings.TriggerScripts = g_GameAttributes.settings.VictoryScripts.concat(g_GameAttributes.settings.TriggerScripts || []);
// Prevent reseting the readystate
@@ -2640,7 +2649,7 @@ function sendRegisterGameStanzaImmediate()
"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.join(","),
"nbp": clients.connectedPlayers,
"maxnbp": g_GameAttributes.settings.PlayerData.length,
"players": clients.list,
diff --git a/binaries/data/mods/public/gui/loadgame/load.js b/binaries/data/mods/public/gui/loadgame/load.js
index beb6fed6c7..8783d40af3 100644
--- a/binaries/data/mods/public/gui/loadgame/load.js
+++ b/binaries/data/mods/public/gui/loadgame/load.js
@@ -113,7 +113,7 @@ function selectionChanged()
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(victoryConditionName => translateVictoryCondition(victoryConditionName)).join(translate(", "));
let caption = sprintf(translate("Mods: %(mods)s"), { "mods": modsToString(metadata.mods) });
if (!hasSameMods(metadata.mods, Engine.GetEngineInfo().mods))
diff --git a/binaries/data/mods/public/gui/loadgame/load.xml b/binaries/data/mods/public/gui/loadgame/load.xml
index 4e5811d2ae..33c6472c90 100644
--- a/binaries/data/mods/public/gui/loadgame/load.xml
+++ b/binaries/data/mods/public/gui/loadgame/load.xml
@@ -97,17 +97,17 @@
Map Size:
-
diff --git a/binaries/data/mods/public/gui/replaymenu/replay_filters.js b/binaries/data/mods/public/gui/replaymenu/replay_filters.js
index f05ce717a9..a8f0cc9e38 100644
--- a/binaries/data/mods/public/gui/replaymenu/replay_filters.js
+++ b/binaries/data/mods/public/gui/replaymenu/replay_filters.js
@@ -152,8 +152,8 @@ function initSingleplayerFilter(filters)
function initVictoryConditionFilter(filters)
{
let victoryConditionFilter = Engine.GetGUIObjectByName("victoryConditionFilter");
- victoryConditionFilter.list = [translateWithContext("victory condition", "Any gametype")].concat(g_VictoryConditions.map(vc => translateVictoryCondition(vc)));
- victoryConditionFilter.list_data = [""].concat(g_VictoryConditions);
+ victoryConditionFilter.list = [translate("Any Victory Condition")].concat(g_VictoryConditions.map(victoryCondition => translateVictoryCondition(victoryCondition.Name)));
+ victoryConditionFilter.list_data = [""].concat(g_VictoryConditions.map(victoryCondition => victoryCondition.Name));
if (filters && filters.victoryCondition)
victoryConditionFilter.selected = victoryConditionFilter.list_data.indexOf(filters.victoryCondition);
@@ -243,7 +243,8 @@ function filterReplay(replay)
// 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
diff --git a/binaries/data/mods/public/gui/replaymenu/replay_menu.js b/binaries/data/mods/public/gui/replaymenu/replay_menu.js
index 5c3b5caf5a..2994f617aa 100644
--- a/binaries/data/mods/public/gui/replaymenu/replay_menu.js
+++ b/binaries/data/mods/public/gui/replaymenu/replay_menu.js
@@ -36,7 +36,7 @@ var g_MapNames = [];
/**
* Sorted list of the victory conditions occuring in the replays
*/
-var g_VictoryConditions = [];
+var g_VictoryConditions = g_Settings && g_Settings.VictoryConditions;
/**
* Directory name of the currently selected replay. Used to restore the selection after changing filters.
@@ -108,10 +108,6 @@ function loadReplays(replaySelectionData, compareFiles)
if (g_MapNames.indexOf(replay.attribs.settings.Name) == -1 && replay.attribs.settings.Name != "")
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);
-
// Extract playernames
for (let playerData of replay.attribs.settings.PlayerData)
{
@@ -138,7 +134,6 @@ function loadReplays(replaySelectionData, compareFiles)
}
g_MapNames.sort();
- g_VictoryConditions.sort();
// Reload filters (since they depend on g_Replays and its derivatives)
initFilters(replaySelectionData && replaySelectionData.filters);
@@ -182,9 +177,6 @@ function sanitizeGameAttributes(attribs)
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 +268,8 @@ function displayReplayDetails()
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(victoryConditionName =>
+ translateVictoryCondition(victoryConditionName)).join(translate(", "));
Engine.GetGUIObjectByName("sgNbPlayers").caption = sprintf(translate("Players: %(numberOfPlayers)s"),
{ "numberOfPlayers": replay.attribs.settings.PlayerData.length });
Engine.GetGUIObjectByName("replayFilename").caption = Engine.GetReplayDirectoryName(replay.directory);
diff --git a/binaries/data/mods/public/gui/replaymenu/replay_menu.xml b/binaries/data/mods/public/gui/replaymenu/replay_menu.xml
index 90917ba079..c425abbab5 100644
--- a/binaries/data/mods/public/gui/replaymenu/replay_menu.xml
+++ b/binaries/data/mods/public/gui/replaymenu/replay_menu.xml
@@ -175,22 +175,22 @@
-
+
Victory:
-
-
+
+
-
+
-
+
diff --git a/binaries/data/mods/public/gui/session/session.js b/binaries/data/mods/public/gui/session/session.js
index 72348db11e..9374f6618d 100644
--- a/binaries/data/mods/public/gui/session/session.js
+++ b/binaries/data/mods/public/gui/session/session.js
@@ -7,8 +7,9 @@ const g_MapSizes = prepareForDropdown(g_Settings && g_Settings.MapSizes);
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;
/**
diff --git a/binaries/data/mods/public/maps/random/wall_demo.json b/binaries/data/mods/public/maps/random/wall_demo.json
index 1fad1572e3..f70bbc90a1 100644
--- a/binaries/data/mods/public/maps/random/wall_demo.json
+++ b/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": []
}
}
diff --git a/binaries/data/mods/public/maps/scripts/CaptureTheRelic.js b/binaries/data/mods/public/maps/scripts/CaptureTheRelic.js
index 19b379a521..54fc6ca4fc 100644
--- a/binaries/data/mods/public/maps/scripts/CaptureTheRelic.js
+++ b/binaries/data/mods/public/maps/scripts/CaptureTheRelic.js
@@ -12,7 +12,7 @@ Trigger.prototype.InitCaptureTheRelic = function()
}
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;
@@ -132,7 +132,7 @@ Trigger.prototype.StartCaptureTheRelicCountdown = function(winningPlayers)
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 = winningPlayers.length > 1;
this.ownRelicsVictoryMessage = cmpGuiInterface.AddTimeNotification({
diff --git a/binaries/data/mods/public/maps/scripts/Conquest.js b/binaries/data/mods/public/maps/scripts/Conquest.js
index 9e3b6b15fe..11b74db1c8 100644
--- a/binaries/data/mods/public/maps/scripts/Conquest.js
+++ b/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).")
+ });
}
diff --git a/binaries/data/mods/public/maps/scripts/ConquestCommon.js b/binaries/data/mods/public/maps/scripts/ConquestCommon.js
index 52520b7d4e..259bf5f1d5 100644
--- a/binaries/data/mods/public/maps/scripts/ConquestCommon.js
+++ b/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;
-
- if (msg.to > 0)
- this.conquestEntitiesByPlayer[msg.to].push(msg.entity);
-
- if (msg.from > 0)
+ for (let query of this.conquestQueries)
{
- let entities = this.conquestEntitiesByPlayer[msg.from];
+ if (!TriggerHelper.EntityMatchesClassList(msg.entity, query.classFilter))
+ continue;
+
+ if (msg.to > 0)
+ query.entitiesByPlayer[msg.to].push(msg.entity);
+
+ if (msg.from <= 0)
+ continue;
+
+ let entities = query.entitiesByPlayer[msg.from];
let index = entities.indexOf(msg.entity);
if (index != -1)
entities.splice(index, 1);
@@ -20,35 +23,40 @@ Trigger.prototype.ConquestOwnershipChanged = function(msg)
{
let cmpPlayer = QueryPlayerIDInterface(msg.from);
if (cmpPlayer)
- cmpPlayer.SetState("defeated", this.conquestDefeatReason);
+ cmpPlayer.SetState("defeated", query.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 entitiesByPlayer = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetAllPlayers().map(playerID =>
+ cmpRangeManager.GetEntitiesByPlayer(playerID));
- 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));
+ for (let query of this.conquestQueries)
+ query.entitiesByPlayer = entitiesByPlayer.map(
+ ents => ents.filter(
+ ent => TriggerHelper.EntityMatchesClassList(ent, query.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);
}
diff --git a/binaries/data/mods/public/maps/scripts/ConquestStructures.js b/binaries/data/mods/public/maps/scripts/ConquestStructures.js
index db0e8a98b2..bfae0761a9 100644
--- a/binaries/data/mods/public/maps/scripts/ConquestStructures.js
+++ b/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).")
+ });
}
diff --git a/binaries/data/mods/public/maps/scripts/ConquestUnits.js b/binaries/data/mods/public/maps/scripts/ConquestUnits.js
index c9c00c3c6d..29a765db68 100644
--- a/binaries/data/mods/public/maps/scripts/ConquestUnits.js
+++ b/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).")
+ });
}
diff --git a/binaries/data/mods/public/maps/scripts/Regicide.js b/binaries/data/mods/public/maps/scripts/Regicide.js
index 56d9884ddc..3cae698ae2 100644
--- a/binaries/data/mods/public/maps/scripts/Regicide.js
+++ b/binaries/data/mods/public/maps/scripts/Regicide.js
@@ -9,7 +9,7 @@ Trigger.prototype.CheckRegicideDefeat = function(data)
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)
diff --git a/binaries/data/mods/public/maps/scripts/WonderVictory.js b/binaries/data/mods/public/maps/scripts/WonderVictory.js
index 91aab1a012..ce8a820dc3 100644
--- a/binaries/data/mods/public/maps/scripts/WonderVictory.js
+++ b/binaries/data/mods/public/maps/scripts/WonderVictory.js
@@ -54,7 +54,7 @@ Trigger.prototype.WonderVictoryStartTimer = function(ent, player)
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),
diff --git a/binaries/data/mods/public/maps/tutorials/Introductory_Tutorial.xml b/binaries/data/mods/public/maps/tutorials/Introductory_Tutorial.xml
index 325936f3e8..1845b21e6d 100644
--- a/binaries/data/mods/public/maps/tutorials/Introductory_Tutorial.xml
+++ b/binaries/data/mods/public/maps/tutorials/Introductory_Tutorial.xml
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0666a4489bbd3c375f8f6effbc14cf77018af1f575e55bb3bf7c4a41b0672ca9
-size 152290
+oid sha256:bb0aea292fcb0671300272615dc8f61b3a55908a819ac712a5d49ce41af8f8a8
+size 152292
diff --git a/binaries/data/mods/public/maps/tutorials/starting_economy_walkthrough.xml b/binaries/data/mods/public/maps/tutorials/starting_economy_walkthrough.xml
index e17ea790ba..39197ccb4e 100644
--- a/binaries/data/mods/public/maps/tutorials/starting_economy_walkthrough.xml
+++ b/binaries/data/mods/public/maps/tutorials/starting_economy_walkthrough.xml
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4edbb0d89389ce3dbecd2815cb23c333a16c66cd75c15ccaa54927944d432b9e
-size 251502
+oid sha256:5f36041a3caebc1e2a7122956e31539759a2a9f455a50d880d52258e4ba28257
+size 251504
diff --git a/binaries/data/mods/public/simulation/ai/common-api/shared.js b/binaries/data/mods/public/simulation/ai/common-api/shared.js
index ecde2b946b..d12452ad6d 100644
--- a/binaries/data/mods/public/simulation/ai/common-api/shared.js
+++ b/binaries/data/mods/public/simulation/ai/common-api/shared.js
@@ -74,7 +74,7 @@ m.SharedScript.prototype.init = function(state, deserialization)
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;
diff --git a/binaries/data/mods/public/simulation/components/EndGameManager.js b/binaries/data/mods/public/simulation/components/EndGameManager.js
index bac54fe769..5af5e2f23e 100644
--- a/binaries/data/mods/public/simulation/components/EndGameManager.js
+++ b/binaries/data/mods/public/simulation/components/EndGameManager.js
@@ -1,5 +1,5 @@
/**
- * System component to store the gametype, gametype settings and
+ * System component to store the victory conditions and their settings and
* check for allied victory / last-man-standing.
*/
function EndGameManager() {}
@@ -9,11 +9,9 @@ EndGameManager.prototype.Schema =
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 @@ EndGameManager.prototype.Init = function()
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, {});
};
/**
diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js
index b0d8007492..975fe6353e 100644
--- a/binaries/data/mods/public/simulation/components/GuiInterface.js
+++ b/binaries/data/mods/public/simulation/components/GuiInterface.js
@@ -154,7 +154,7 @@ GuiInterface.prototype.GetSimulationState = function()
// 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
diff --git a/binaries/data/mods/public/simulation/components/interfaces/EndGameManager.js b/binaries/data/mods/public/simulation/components/interfaces/EndGameManager.js
index 7fe9b233b6..aadb703e37 100644
--- a/binaries/data/mods/public/simulation/components/interfaces/EndGameManager.js
+++ b/binaries/data/mods/public/simulation/components/interfaces/EndGameManager.js
@@ -4,4 +4,4 @@ Engine.RegisterInterface("EndGameManager");
* Message of the form {}
* sent from EndGameManager component.
*/
-Engine.RegisterMessageType("GameTypeChanged");
+Engine.RegisterMessageType("VictoryConditionsChanged");
diff --git a/binaries/data/mods/public/simulation/components/tests/test_EndGameManager.js b/binaries/data/mods/public/simulation/components/tests/test_EndGameManager.js
index dca3e2bb6a..d8c9d7f4ef 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_EndGameManager.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_EndGameManager.js
@@ -23,7 +23,10 @@ AddMock(playerEnt1, IID_Player, {
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);
diff --git a/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js b/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
index 62a0c897d3..ef662c0f1d 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
@@ -65,7 +65,7 @@ AddMock(SYSTEM_ENTITY, IID_Barter, {
});
AddMock(SYSTEM_ENTITY, IID_EndGameManager, {
- GetGameType: function() { return "conquest"; },
+ GetVictoryConditions: () => ["conquest", "wonder"],
GetAlliedVictory: function() { return false; }
});
@@ -365,7 +365,7 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), {
],
circularMap: false,
timeElapsed: 0,
- gameType: "conquest",
+ "victoryConditions": ["conquest", "wonder"],
alliedVictory: false
});
@@ -518,7 +518,7 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
],
"circularMap": false,
"timeElapsed": 0,
- "gameType": "conquest",
+ "victoryConditions": ["conquest", "wonder"],
"alliedVictory": false
});
diff --git a/binaries/data/mods/public/simulation/data/settings/victory_conditions/capture_the_relic.json b/binaries/data/mods/public/simulation/data/settings/victory_conditions/capture_the_relic.json
index 2cd40322c7..9eef593f4f 100644
--- a/binaries/data/mods/public/simulation/data/settings/victory_conditions/capture_the_relic.json
+++ b/binaries/data/mods/public/simulation/data/settings/victory_conditions/capture_the_relic.json
@@ -7,9 +7,8 @@
"Scripts":
[
"scripts/TriggerHelper.js",
- "scripts/ConquestCommon.js",
- "scripts/Conquest.js",
"scripts/CaptureTheRelic.js"
- ]
+ ],
+ "GUIOrder": 10
}
}
diff --git a/binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest.json b/binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest.json
index ac101a4e37..28f0a66d51 100644
--- a/binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest.json
+++ b/binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest.json
@@ -3,13 +3,18 @@
"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
+ },
+ "GUIOrder": 0
}
}
diff --git a/binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest_structures.json b/binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest_structures.json
index c8f920f9b9..6fb4a8f759 100644
--- a/binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest_structures.json
+++ b/binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest_structures.json
@@ -3,12 +3,14 @@
"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"],
+ "GUIOrder": 1
}
}
diff --git a/binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest_units.json b/binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest_units.json
index 06a1c855be..58256fef4f 100644
--- a/binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest_units.json
+++ b/binaries/data/mods/public/simulation/data/settings/victory_conditions/conquest_units.json
@@ -3,12 +3,14 @@
"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"],
+ "GUIOrder": 1
}
}
diff --git a/binaries/data/mods/public/simulation/data/settings/victory_conditions/regicide.json b/binaries/data/mods/public/simulation/data/settings/victory_conditions/regicide.json
index 02022f3f56..a02249932d 100644
--- a/binaries/data/mods/public/simulation/data/settings/victory_conditions/regicide.json
+++ b/binaries/data/mods/public/simulation/data/settings/victory_conditions/regicide.json
@@ -7,9 +7,8 @@
"Scripts":
[
"scripts/TriggerHelper.js",
- "scripts/ConquestCommon.js",
- "scripts/Conquest.js",
"scripts/Regicide.js"
- ]
+ ],
+ "GUIOrder": 10
}
}
diff --git a/binaries/data/mods/public/simulation/data/settings/victory_conditions/wonder.json b/binaries/data/mods/public/simulation/data/settings/victory_conditions/wonder.json
index 065670b735..e125eaf7b7 100644
--- a/binaries/data/mods/public/simulation/data/settings/victory_conditions/wonder.json
+++ b/binaries/data/mods/public/simulation/data/settings/victory_conditions/wonder.json
@@ -7,9 +7,8 @@
"Scripts":
[
"scripts/TriggerHelper.js",
- "scripts/ConquestCommon.js",
- "scripts/Conquest.js",
"scripts/WonderVictory.js"
- ]
+ ],
+ "GUIOrder": 10
}
}
diff --git a/binaries/data/mods/public/simulation/helpers/Setup.js b/binaries/data/mods/public/simulation/helpers/Setup.js
index b9f72e38ef..8c48dfd862 100644
--- a/binaries/data/mods/public/simulation/helpers/Setup.js
+++ b/binaries/data/mods/public/simulation/helpers/Setup.js
@@ -53,17 +53,17 @@ function LoadMapSettings(settings)
}
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)
diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp
index 5738f94579..55120e9bcb 100644
--- a/source/ps/GameSetup/GameSetup.cpp
+++ b/source/ps/GameSetup/GameSetup.cpp
@@ -1464,24 +1464,37 @@ bool Autostart(const CmdLineArgs& args)
triggerScriptsVector.push_back(nonVisualScript.FromUTF8());
}
- CStr victory = "conquest";
+ std::vector victoryConditions(1, "conquest");
if (args.Has("autostart-victory"))
- victory = args.Get("autostart-victory");
+ victoryConditions = args.GetMultiple("autostart-victory");
- scriptInterface.SetProperty(settings, "GameType", std::string(victory));
+ if (victoryConditions.size() == 1 && victoryConditions[0] == "endless")
+ victoryConditions.clear();
- 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())
+ scriptInterface.SetProperty(settings, "VictoryConditions", victoryConditions);
+
+ for (const CStr& victory : victoryConditions)
{
- std::vector victoryScriptsVector;
- FromJSVal_vector(cx, victoryScripts, victoryScriptsVector);
- triggerScriptsVector.insert(triggerScriptsVector.end(), victoryScriptsVector.begin(), victoryScriptsVector.end());
+ 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());
+ }
+ else
+ {
+ LOGERROR("Autostart: Error reading victory script '%s'", utf8_from_wstring(scriptPath));
+ throw PSERROR_Game_World_MapLoadFailed("Error reading victory script.\nCheck application log for details.");
+ }
}
+
ToJSVal_vector(cx, &triggerScripts, triggerScriptsVector);
scriptInterface.SetProperty(settings, "TriggerScripts", triggerScripts);
diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp
index fb92202e05..471b15de52 100644
--- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp
+++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp
@@ -41,6 +41,12 @@ enum
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 @@ public:
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 @@ void MapSettingsControl::CreateWidgets()
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, 0, 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 @@ void MapSettingsControl::ReadFromEngine()
// 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); \
+ 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,9 +242,11 @@ void MapSettingsControl::ReadFromEngine()
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");
}
+
+#undef INIT_CHECKBOX
}
void MapSettingsControl::SetMapSettings(const AtObj& obj)
@@ -229,6 +257,22 @@ void MapSettingsControl::SetMapSettings(const AtObj& obj)
SendToEngine();
}
+// TODO Use the json data for this
+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 +287,27 @@ AtObj MapSettingsControl::UpdateSettingsObject()
// 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);
+
+#undef INSERT_VICTORY_CONDITION_CHECKBOX
+
+ 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
{