Index: binaries/data/mods/public/globalscripts/utility.js
===================================================================
--- binaries/data/mods/public/globalscripts/utility.js (revision 18527)
+++ binaries/data/mods/public/globalscripts/utility.js (working copy)
@@ -14,5 +14,23 @@ function clone(o)
return o;
for (let key in o)
r[key] = clone(o[key]);
return r;
}
+
+/**
+ * "Inside-out" implementation of Fisher-Yates shuffle
+ */
+function shuffleArray(source)
+{
+ if (!source.length)
+ return [];
+
+ let result = [source[0]];
+ for (let i = 1; i < source.length; ++i)
+ {
+ let j = Math.floor(Math.random() * i);
+ result[i] = result[j];
+ result[j] = source[i];
+ }
+ return result;
+}
Index: binaries/data/mods/public/maps/random/rmgen/library.js
===================================================================
--- binaries/data/mods/public/maps/random/rmgen/library.js (revision 18527)
+++ binaries/data/mods/public/maps/random/rmgen/library.js (working copy)
@@ -9,11 +9,11 @@ const MAX_MAP_SIZE = 512;
const MAP_BORDER_WIDTH = 3;
const FALLBACK_CIV = "athen";
/**
* Constants needed for heightmap_manipulation.js
*/
-const MAX_HEIGHT_RANGE = 0xFFFF / HEIGHT_UNITS_PER_METRE // Engine limit, Roughly 700 meters
+const MAX_HEIGHT_RANGE = 0xFFFF / HEIGHT_UNITS_PER_METRE; // Engine limit, Roughly 700 meters
const MIN_HEIGHT = - SEA_LEVEL;
const MAX_HEIGHT = MAX_HEIGHT_RANGE - SEA_LEVEL;
// Default angle for buildings
const BUILDING_ORIENTATION = - PI / 4;
@@ -90,28 +90,10 @@ function min(a, b)
{
return a < b ? a : b;
}
/**
- * "Inside-out" implementation of Fisher-Yates shuffle
- */
-function shuffleArray(source)
-{
- if (!source.length)
- return [];
-
- let result = [source[0]];
- for (let i = 1; i < source.length; ++i)
- {
- let j = randInt(0, i);
- result[i] = result[j];
- result[j] = source[i];
- }
- return result;
-}
-
-/**
* Retries the given function with those arguments as often as specified.
*/
function retryPlacing(placeFunc, placeArgs, retryFactor, amount, getResult)
{
let maxFail = amount * retryFactor;
Index: binaries/data/mods/public/maps/scripts/Regicide.js
===================================================================
--- binaries/data/mods/public/maps/scripts/Regicide.js (revision 0)
+++ binaries/data/mods/public/maps/scripts/Regicide.js (working copy)
@@ -0,0 +1,120 @@
+Trigger.prototype.CheckRegicideDefeat = function(data)
+{
+ if (data.entity == this.heroes[data.from])
+ TriggerHelper.DefeatPlayer(data.from);
+};
+
+Trigger.prototype.InitRegicideGame = function(msg)
+{
+ let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
+
+ // Get unique list of chosen civs
+ let civs = [];
+ let playersCivs = [];
+ for (let playerID = 1; playerID < TriggerHelper.GetNumberOfPlayers(); ++playerID)
+ {
+ let civ = QueryPlayerIDInterface(playerID).GetCiv();
+ playersCivs[playerID] = civ;
+
+ if (civs.indexOf(civ) == -1)
+ civs.push(civ);
+ }
+
+ // Get all hero templates of these civs
+ let heroTemplates = {};
+ for (let templateName of cmpTemplateManager.FindAllTemplates(false))
+ {
+ if (templateName.substring(0,6) != "units/")
+ continue;
+
+ let identity = cmpTemplateManager.GetTemplate(templateName).Identity;
+ let classes = GetIdentityClasses(identity);
+
+ if (classes.indexOf("Hero") == -1)
+ continue;
+
+ if (!heroTemplates[identity.Civ])
+ heroTemplates[identity.Civ] = [];
+
+ if (heroTemplates[identity.Civ].indexOf(templateName) == -1)
+ heroTemplates[identity.Civ].push({
+ "templateName": templateName,
+ "classes": classes
+ });
+ }
+
+ // Sort spawn points by preference
+ let getPreference = entity => {
+ let cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
+ let classes = cmpIdentity.GetClassesList();
+
+ if (classes.indexOf("CivilCentre") != -1)
+ return 3;
+
+ if (classes.indexOf("Structure") != -1)
+ return 2;
+
+ if (classes.indexOf("Ship") != -1)
+ return 1;
+
+ return 0;
+ };
+
+ let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+ for (let playerID = 1; playerID < TriggerHelper.GetNumberOfPlayers(); ++playerID)
+ {
+ let spawnPoints = cmpRangeManager.GetEntitiesByPlayer(playerID).sort((entity1, entity2) =>
+ getPreference(entity2) - getPreference(entity1));
+
+ this.heroes[playerID] = this.SpawnHero(playerID, heroTemplates[playersCivs[playerID]], spawnPoints);
+ }
+};
+
+/**
+ * Spawn a random hero at one of the given locations (which are checked in order).
+ * Garrison it if the location is a ship.
+ *
+ * @param spawnPoints - entity IDs at which to spawn
+ */
+Trigger.prototype.SpawnHero = function(playerID, heroTemplates, spawnPoints)
+{
+ for (let heroTemplate of shuffleArray(heroTemplates))
+ for (let spawnPoint of spawnPoints)
+ {
+ let cmpPosition = Engine.QueryInterface(spawnPoint, IID_Position);
+ if (!cmpPosition || !cmpPosition.IsInWorld())
+ continue;
+
+ let isShip = TriggerHelper.EntityHasClass(spawnPoint, "Ship");
+ if (isShip)
+ {
+ let cmpGarrisonHolder = Engine.QueryInterface(spawnPoint, IID_GarrisonHolder);
+ if (cmpGarrisonHolder.IsFull() ||
+ !MatchesClassList(heroTemplate.classes, cmpGarrisonHolder.GetAllowedClasses()))
+ continue;
+ }
+
+ let hero = TriggerHelper.SpawnUnits(spawnPoint, heroTemplate.templateName, 1, playerID);
+ if (!hero.length)
+ continue;
+
+ hero = hero[0];
+
+ if (isShip)
+ {
+ let cmpUnitAI = Engine.QueryInterface(hero, IID_UnitAI);
+ cmpUnitAI.Garrison(spawnPoint);
+ }
+
+ return hero;
+ }
+
+ error("Couldn't spawn hero for player " + playerID);
+ return undefined;
+};
+
+let cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
+cmpTrigger.heroes = []; // TODO: what if gaia gets a hero?
+cmpTrigger.DoAfterDelay(0, "InitRegicideGame", {});
+
+cmpTrigger.RegisterTrigger("OnOwnershipChanged", "CheckRegicideDefeat", { "enabled": true });
Index: binaries/data/mods/public/maps/scripts/TriggerHelper.js
===================================================================
--- binaries/data/mods/public/maps/scripts/TriggerHelper.js (revision 18527)
+++ binaries/data/mods/public/maps/scripts/TriggerHelper.js (working copy)
@@ -20,12 +20,12 @@ TriggerHelper.GetOwner = function(ent)
return -1;
};
/**
- * Can be used to "force" a building to spawn a group of entities.
- * Only works for buildings that can already train units.
+ * Can be used to "force" a building/unit to spawn a group of entities.
+ * A default position is returned if no valid position is found.
* @param source Entity id of the point where they will be spawned from
* @param template Name of the template
* @param count Number of units to spawn
* @param owner Player id of the owner of the new units. By default, the owner
* of the source entity.
Index: binaries/data/mods/public/simulation/data/settings/victory_conditions/regicide.json
===================================================================
--- binaries/data/mods/public/simulation/data/settings/victory_conditions/regicide.json (revision 0)
+++ binaries/data/mods/public/simulation/data/settings/victory_conditions/regicide.json (working copy)
@@ -0,0 +1,15 @@
+{
+ "TranslatedKeys": ["Title", "Description"],
+ "Data":
+ {
+ "Title": "Regicide",
+ "Description": "Keep your Hero alive to win",
+ "Scripts":
+ [
+ "scripts/TriggerHelper.js",
+ "scripts/ConquestCommon.js",
+ "scripts/Conquest.js",
+ "scripts/Regicide.js"
+ ]
+ }
+}
Index: binaries/data/mods/public/simulation/templates/units/maur_ship_trireme.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/units/maur_ship_trireme.xml (revision 18527)
+++ binaries/data/mods/public/simulation/templates/units/maur_ship_trireme.xml (working copy)
@@ -6,11 +6,11 @@
8.0
- 40
+ 15
200
Index: source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp
===================================================================
--- source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp (revision 18527)
+++ source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp (working copy)
@@ -1,6 +1,6 @@
-/* Copyright (C) 2015 Wildfire Games.
+/* Copyright (C) 2016 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
@@ -146,10 +146,11 @@ void MapSettingsControl::CreateWidgets()
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"));
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));