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
@@ -250,6 +250,18 @@
{ "min": g_GameAttributes.settings.VictoryDuration }
);
+ else if (g_VictoryConditions.Name[victoryIdx] == "regicide")
+ if (g_GameAttributes.settings.RegicideGarrison)
+ titles.push({
+ "label": translate("Hero Garrison"),
+ "value": translate("Heroes can be garrisoned in structures.")
+ });
+ else
+ titles.push({
+ "label": translate("Exposed Heroes"),
+ "value": translate("Heroes cannot be garrisoned, and they are vulnerable to raids.")
+ });
+
titles.push({
"label": title,
"value": g_VictoryConditions.Description[victoryIdx]
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
@@ -340,6 +340,7 @@
"ceasefire",
],
"Checkbox": [
+ "regicideGarrison",
"exploreMap",
"revealMap",
"disableTreasures",
@@ -680,6 +681,18 @@
* Contains the logic of all boolean gamesettings.
*/
var g_Checkboxes = {
+ "regicideGarrison": {
+ "title": () => translate("Hero Garrison"),
+ "tooltip": () => translate("Toggle whether heroes can be garrisoned."),
+ "default": () => false,
+ "defined": () => g_GameAttributes.settings.RegicideGarrison !== undefined,
+ "get": () => g_GameAttributes.settings.RegicideGarrison,
+ "set": checked => {
+ g_GameAttributes.settings.RegicideGarrison = checked;
+ },
+ "hidden": () => g_GameAttributes.settings.GameType != "regicide",
+ "enabled": () => g_GameAttributes.mapType != "scenario",
+ },
"revealMap": {
"title": () =>
// Translation: Make sure to differentiate between the revealed map and explored map options!
@@ -1568,6 +1581,7 @@
{
delete g_GameAttributes.settings.VictoryDuration;
delete g_GameAttributes.settings.LastManStanding;
+ delete g_GameAttributes.settings.RegicideGarrison;
}
if (mapSettings.PlayerData)
Index: binaries/data/mods/public/gui/session/unit_actions.js
===================================================================
--- binaries/data/mods/public/gui/session/unit_actions.js
+++ binaries/data/mods/public/gui/session/unit_actions.js
@@ -647,8 +647,7 @@
},
"getActionInfo": function(entState, targetState)
{
- if (!hasClass(entState, "Unit") ||
- !targetState.garrisonHolder ||
+ if (!entState.canGarrison || !targetState.garrisonHolder ||
!playerCheck(entState, targetState, ["Player", "MutualAlly"]))
return false;
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
@@ -6,6 +6,9 @@
Trigger.prototype.InitRegicideGame = function(msg)
{
+ let cmpEndGameManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager);
+ this.regicideGarrison = cmpEndGameManager.GetGameTypeSettings().regicideGarrison;
+
let playersCivs = [];
for (let playerID = 1; playerID < TriggerHelper.GetNumberOfPlayers(); ++playerID)
playersCivs[playerID] = QueryPlayerIDInterface(playerID).GetCiv();
@@ -30,7 +33,7 @@
if (heroTemplates[identity.Civ].indexOf(templateName) == -1)
heroTemplates[identity.Civ].push({
- "templateName": templateName,
+ "templateName": this.regicideGarrison ? templateName : "ungarrisonable|" + templateName,
"classes": classes
});
}
@@ -51,6 +54,31 @@
return 0;
};
+ let cmpWaterManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_WaterManager);
+ let cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager);
+ let mapSize = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain).GetTilesPerSide() * 4;
+
+ let gaiaSpawnPreferences = (shipEnt, entity) => {
+
+ let cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
+ let cmpPosition = Engine.QueryInterface(entity, IID_Position);
+ let cmpShipPosition = Engine.QueryInterface(shipEnt, IID_Position);
+
+ if (!cmpIdentity || !cmpPosition || !cmpPosition.IsInWorld())
+ return Infinity;
+
+ let pos = cmpPosition.GetPosition();
+
+ // Do not spawn heroes underwater
+ if (pos.y <= cmpWaterManager.GetWaterLevel(pos.x, pos.z))
+ return Infinity;
+
+ if (cmpTerritoryManager.GetOwner(pos.x, pos.z) != 0)
+ return mapSize;
+
+ return Engine.QueryInterface(shipEnt, IID_Position).GetPosition2D().distanceTo(Vector2D.from3D(pos));
+ }
+
// Attempt to spawn one hero per player
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
for (let playerID = 1; playerID < TriggerHelper.GetNumberOfPlayers(); ++playerID)
@@ -58,6 +86,11 @@
let spawnPoints = cmpRangeManager.GetEntitiesByPlayer(playerID).sort((entity1, entity2) =>
getSpawnPreference(entity2) - getSpawnPreference(entity1));
+ // Spawn the hero on land as close as possible
+ if (!this.regicideGarrison && TriggerHelper.EntityHasClass(spawnPoints[0], "Ship"))
+ spawnPoints = cmpRangeManager.GetEntitiesByPlayer(0).sort((entity1, entity2) =>
+ gaiaSpawnPreferences(spawnPoints[0], entity1) - gaiaSpawnPreferences(spawnPoints[0], entity2));
+
this.regicideHeroes[playerID] = this.SpawnRegicideHero(playerID, heroTemplates[playersCivs[playerID]], spawnPoints);
}
};
@@ -109,6 +142,7 @@
{
let cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
cmpTrigger.regicideHeroes = [];
+ cmpTrigger.regicideGarrison = false;
cmpTrigger.DoAfterDelay(0, "InitRegicideGame", {});
cmpTrigger.RegisterTrigger("OnOwnershipChanged", "CheckRegicideDefeat", { "enabled": true });
}
Index: binaries/data/mods/public/simulation/ai/common-api/entity.js
===================================================================
--- binaries/data/mods/public/simulation/ai/common-api/entity.js
+++ binaries/data/mods/public/simulation/ai/common-api/entity.js
@@ -769,6 +769,8 @@
"canGuard": function() { return this.get("UnitAI/CanGuard") === "true"; },
+ "canGarrison": function() { return this.get("Garrisonable") !== "false"; },
+
move: function(x, z, queued = false) {
Engine.PostCommand(PlayerID,{"type": "walk", "entities": [this.id()], "x": x, "z": z, "queued": queued });
return this;
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
@@ -114,6 +114,20 @@
this._derivedTemplates[name] = resource;
return resource;
}
+ else if (name.indexOf("ungarrisonable|") !== -1)
+ {
+ let base = this.GetTemplate(name.substr(15));
+
+ let ent = {};
+ for (let key in base)
+ if (key !== "Garrisonable")
+ ent[key] = base[key];
+ else
+ ent[key] = "false";
+
+ this._derivedTemplates[name] = ent;
+ return ent;
+ }
error("Tried to retrieve invalid template '"+name+"'");
return null;
Index: binaries/data/mods/public/simulation/ai/petra/garrisonManager.js
===================================================================
--- binaries/data/mods/public/simulation/ai/petra/garrisonManager.js
+++ binaries/data/mods/public/simulation/ai/petra/garrisonManager.js
@@ -198,7 +198,7 @@
/** This is just a pre-garrison state, while the entity walk to the garrison holder */
m.GarrisonManager.prototype.garrison = function(gameState, ent, holder, type)
{
- if (this.numberOfGarrisonedUnits(holder) >= holder.garrisonMax())
+ if (this.numberOfGarrisonedUnits(holder) >= holder.garrisonMax() || !ent.canGarrison())
return;
this.registerHolder(gameState, holder);
Index: binaries/data/mods/public/simulation/ai/petra/navalManager.js
===================================================================
--- binaries/data/mods/public/simulation/ai/petra/navalManager.js
+++ binaries/data/mods/public/simulation/ai/petra/navalManager.js
@@ -379,6 +379,9 @@
*/
m.NavalManager.prototype.requireTransport = function(gameState, entity, startIndex, endIndex, endPos)
{
+ if (!entity.canGarrison())
+ return false;
+
if (entity.getMetadata(PlayerID, "transport") !== undefined)
{
if (this.Config.debug > 0)
Index: binaries/data/mods/public/simulation/components/GarrisonHolder.js
===================================================================
--- binaries/data/mods/public/simulation/components/GarrisonHolder.js
+++ binaries/data/mods/public/simulation/components/GarrisonHolder.js
@@ -200,7 +200,7 @@
if (!cmpIdentity)
return false;
var entityClasses = cmpIdentity.GetClassesList();
- return MatchesClassList(entityClasses, this.template.List._string);
+ return MatchesClassList(entityClasses, this.template.List._string) && Engine.QueryInterface(entity, IID_Garrisonable);
};
/**
Index: binaries/data/mods/public/simulation/components/Garrisonable.js
===================================================================
--- binaries/data/mods/public/simulation/components/Garrisonable.js
+++ binaries/data/mods/public/simulation/components/Garrisonable.js
@@ -0,0 +1,11 @@
+function Garrisonable() {}
+
+Garrisonable.prototype.Schema = "";
+
+Garrisonable.prototype.Init = function()
+{
+};
+
+Garrisonable.prototype.Serialize = null;
+
+Engine.RegisterComponentType(IID_Garrisonable, "Garrisonable", Garrisonable);
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
@@ -241,6 +241,7 @@
"alertRaiser": null,
"builder": null,
+ "canGarrison": null,
"identity": null,
"fogging": null,
"foundation": null,
@@ -375,6 +376,8 @@
"garrisonedEntitiesCount": cmpGarrisonHolder.GetGarrisonedEntitiesCount()
};
+ ret.canGarrison = !!Engine.QueryInterface(ent, IID_Garrisonable);
+
let cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
if (cmpUnitAI)
ret.unitAI = {
Index: binaries/data/mods/public/simulation/components/interfaces/Garrisonable.js
===================================================================
--- binaries/data/mods/public/simulation/components/interfaces/Garrisonable.js
+++ binaries/data/mods/public/simulation/components/interfaces/Garrisonable.js
@@ -0,0 +1 @@
+Engine.RegisterInterface("Garrisonable");
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
@@ -10,6 +10,7 @@
Engine.LoadComponentScript("interfaces/EndGameManager.js");
Engine.LoadComponentScript("interfaces/EntityLimits.js");
Engine.LoadComponentScript("interfaces/Foundation.js");
+Engine.LoadComponentScript("interfaces/Garrisonable.js");
Engine.LoadComponentScript("interfaces/GarrisonHolder.js");
Engine.LoadComponentScript("interfaces/Gate.js");
Engine.LoadComponentScript("interfaces/Guard.js");
@@ -599,6 +600,7 @@
template: "example",
alertRaiser: null,
builder: true,
+ canGarrison: false,
identity: {
rank: "foo",
classes: ["class1", "class2"],
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
@@ -49,6 +49,8 @@
gameTypeSettings.relicCount = settings.RelicCount;
if (settings.VictoryDuration)
gameTypeSettings.victoryDuration = settings.VictoryDuration * 60 * 1000;
+ if (settings.RegicideGarrison)
+ gameTypeSettings.regicideGarrison = settings.RegicideGarrison;
if (settings.GameType)
cmpEndGameManager.SetGameType(settings.GameType, gameTypeSettings);
Index: binaries/data/mods/public/simulation/templates/special_filter/ungarrisonable.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/special_filter/ungarrisonable.xml
+++ binaries/data/mods/public/simulation/templates/special_filter/ungarrisonable.xml
@@ -0,0 +1,4 @@
+
+
+
+
Index: binaries/data/mods/public/simulation/templates/template_unit.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit.xml
+++ binaries/data/mods/public/simulation/templates/template_unit.xml
@@ -27,6 +27,7 @@
2.5
+
corpse