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
@@ -31,39 +31,6 @@
"" +
"" +
"" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "tokens" +
- "" +
- "" +
- "" +
- ""+
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
"";
/**
@@ -77,22 +44,6 @@
this.entities = [];
this.timer = undefined;
this.allowGarrisoning = new Map();
- this.visibleGarrisonPoints = [];
- if (!this.template.VisibleGarrisonPoints)
- return;
-
- let points = this.template.VisibleGarrisonPoints;
- for (let point in points)
- this.visibleGarrisonPoints.push({
- "offset": {
- "x": +points[point].X,
- "y": +points[point].Y,
- "z": +points[point].Z
- },
- "allowedClasses": points[point].AllowedClasses,
- "angle": points[point].Angle ? +points[point].Angle * Math.PI / 180 : null,
- "entity": null
- });
};
/**
@@ -197,29 +148,12 @@
};
/**
- * @param {number} entity - The entity's id.
- * @param {Object|undefined} visibleGarrisonPoint - The vgp object.
- * @return {boolean} - Whether the unit is allowed be visible on that garrison point.
- */
-GarrisonHolder.prototype.AllowedToVisibleGarrisoning = function(entity, visibleGarrisonPoint)
-{
- if (!visibleGarrisonPoint)
- return false;
-
- if (!visibleGarrisonPoint.allowedClasses)
- return true;
-
- let cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
- return cmpIdentity && MatchesClassList(cmpIdentity.GetClassesList(), visibleGarrisonPoint.allowedClasses._string);
-};
-
-/**
* Garrison a unit inside. The timer for AutoHeal is started here.
* @param {number} vgpEntity - The visual garrison point that will be used.
* If vgpEntity is given, this visualGarrisonPoint will be used for the entity.
* @return {boolean} - Whether the entity was garrisoned.
*/
-GarrisonHolder.prototype.Garrison = function(entity, vgpEntity)
+GarrisonHolder.prototype.Garrison = function(entity)
{
if (!this.IsAllowedToGarrison(entity))
return false;
@@ -227,10 +161,6 @@
if (!this.HasEnoughHealth())
return false;
- let cmpPosition = Engine.QueryInterface(entity, IID_Position);
- if (!cmpPosition)
- return false;
-
if (!this.timer && this.GetHealRate() > 0)
{
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
@@ -247,52 +177,16 @@
if (cmpAura && cmpAura.HasGarrisonAura())
cmpAura.ApplyGarrisonAura(this.entity);
- let visibleGarrisonPoint;
- if (vgpEntity && this.AllowedToVisibleGarrisoning(entity, vgpEntity))
- visibleGarrisonPoint = vgpEntity;
-
- if (!visibleGarrisonPoint)
- visibleGarrisonPoint = this.visibleGarrisonPoints.find(vgp => !vgp.entity && this.AllowedToVisibleGarrisoning(entity, vgp));
-
- let isVisiblyGarrisoned = false;
- if (visibleGarrisonPoint)
- {
- visibleGarrisonPoint.entity = entity;
- // Angle of turrets:
- // Renamed entities (vgpEntity != undefined) should keep their angle.
- // Otherwise if an angle is given in the visibleGarrisonPoint, use it.
- // If no such angle given (usually walls for which outside/inside not well defined), we keep
- // the current angle as it was used for garrisoning and thus quite often was from inside to
- // outside, except when garrisoning from outWorld where we take as default PI.
- let cmpTurretPosition = Engine.QueryInterface(this.entity, IID_Position);
- if (!vgpEntity && visibleGarrisonPoint.angle != null)
- cmpPosition.SetYRotation(cmpTurretPosition.GetRotation().y + visibleGarrisonPoint.angle);
- else if (!vgpEntity && !cmpPosition.IsInWorld())
- cmpPosition.SetYRotation(cmpTurretPosition.GetRotation().y + Math.PI);
- let cmpUnitMotion = Engine.QueryInterface(entity, IID_UnitMotion);
- if (cmpUnitMotion)
- cmpUnitMotion.SetFacePointAfterMove(false);
- cmpPosition.SetTurretParent(this.entity, visibleGarrisonPoint.offset);
- let cmpUnitAI = Engine.QueryInterface(entity, IID_UnitAI);
- if (cmpUnitAI)
- cmpUnitAI.SetTurretStance();
-
- // Remove the unit's obstruction to avoid interfering with pathing.
- let cmpObstruction = Engine.QueryInterface(entity, IID_Obstruction);
- if (cmpObstruction)
- cmpObstruction.SetActive(false);
-
- isVisiblyGarrisoned = true;
- }
- else
+ let cmpPosition = Engine.QueryInterface(entity, IID_Position);
+ if (cmpPosition)
cmpPosition.MoveOutOfWorld();
- // Should only be called after the garrison has been performed else the visible Garrison Points are not updated yet.
+ let cmpTurretHolder = Engine.QueryInterface(this.entity, IID_TurretHolder);
Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {
"added": [entity],
"removed": [],
"visible": {
- [entity]: isVisiblyGarrisoned,
+ [entity]: cmpTurretHolder && cmpTurretHolder.OccupyTurret(entity),
}
});
@@ -340,25 +234,6 @@
let cmpEntPosition = Engine.QueryInterface(entity, IID_Position);
let cmpEntUnitAI = Engine.QueryInterface(entity, IID_UnitAI);
- // Needs to be set before the visible garrison points are cleared.
- let visible = {
- [entity]: this.IsVisiblyGarrisoned(entity)
- };
-
- for (let vgp of this.visibleGarrisonPoints)
- {
- if (vgp.entity != entity)
- continue;
- cmpEntPosition.SetTurretParent(INVALID_ENTITY, new Vector3D());
- let cmpEntUnitMotion = Engine.QueryInterface(entity, IID_UnitMotion);
- if (cmpEntUnitMotion)
- cmpEntUnitMotion.SetFacePointAfterMove(true);
- if (cmpEntUnitAI)
- cmpEntUnitAI.ResetTurretStance();
- vgp.entity = null;
- break;
- }
-
// Reset the obstruction flags to template defaults.
let cmpObstruction = Engine.QueryInterface(entity, IID_Obstruction);
if (cmpObstruction)
@@ -375,17 +250,23 @@
if (cmpEntAura && cmpEntAura.HasGarrisonAura())
cmpEntAura.RemoveGarrisonAura(this.entity);
- cmpEntPosition.JumpTo(pos.x, pos.z);
- cmpEntPosition.SetHeightOffset(0);
+ if (cmpEntPosition)
+ {
+ cmpEntPosition.JumpTo(pos.x, pos.z);
+ cmpEntPosition.SetHeightOffset(0);
- let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
- if (cmpPosition)
- cmpEntPosition.SetYRotation(cmpPosition.GetPosition().horizAngleTo(pos));
+ let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
+ if (cmpPosition)
+ cmpEntPosition.SetYRotation(cmpPosition.GetPosition().horizAngleTo(pos));
+ }
+ let cmpTurretHolder = Engine.QueryInterface(this.entity, IID_TurretHolder);
Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {
"added": [],
"removed": [entity],
- "visible": visible
+ "visible": {
+ [entity]: cmpTurretHolder && cmpTurretHolder.LeaveTurret(entity)
+ }
});
return true;
@@ -626,18 +507,15 @@
if (cmpHealth && cmpHealth.GetHitpoints() == 0)
{
this.entities.splice(entityIndex, 1);
+ let cmpTurretHolder = Engine.QueryInterface(this.entity, IID_TurretHolder);
Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {
"added": [],
"removed": [msg.entity],
"visible": {
- [msg.entity]: this.IsVisiblyGarrisoned(msg.entity)
+ [msg.entity]: cmpTurretHolder && cmpTurretHolder.LeaveTurret(msg.entity)
}
});
this.UpdateGarrisonFlag();
-
- for (let point of this.visibleGarrisonPoints)
- if (point.entity == msg.entity)
- point.entity = null;
}
else if (msg.to == INVALID_PLAYER || !IsOwnedByMutualAllyOfEntity(this.entity, msg.entity))
this.EjectOrKill([msg.entity]);
@@ -652,16 +530,8 @@
let entityIndex = this.entities.indexOf(msg.entity);
if (entityIndex != -1)
{
- let vgpRenamed;
- for (let vgp of this.visibleGarrisonPoints)
- {
- if (vgp.entity != msg.entity)
- continue;
- vgpRenamed = vgp;
- break;
- }
this.Eject(msg.entity, true);
- this.Garrison(msg.newentity, vgpRenamed);
+ this.Garrison(msg.newentity);
}
if (!this.initGarrison)
@@ -722,9 +592,10 @@
if (killedEntities.length)
{
+ let cmpTurretHolder = Engine.QueryInterface(this.entity, IID_TurretHolder);
let visibleEntitiesIds = {};
for (let ent of killedEntities)
- visibleEntitiesIds[ent] = this.IsVisiblyGarrisoned(ent);
+ visibleEntitiesIds[ent] = cmpTurretHolder && cmpTurretHolder.OccupiesTurret(ent);
Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {
"added": [],
"removed": killedEntities,
@@ -735,16 +606,6 @@
};
/**
- * Gives insight about the unit type of garrisoning.
- * @param {number} entity - The entity's id.
- * @return {boolean} - Whether the entity is visible on the garrison holder.
- */
-GarrisonHolder.prototype.IsVisiblyGarrisoned = function(entity)
-{
- return this.visibleGarrisonPoints.some(point => point.entity == entity);
-};
-
-/**
* Whether an entity is ejectable.
* @param {number} entity - The entity-ID to be tested.
* @return {boolean} - Whether the entity is ejectable.
Index: binaries/data/mods/public/simulation/components/TurretHolder.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/components/TurretHolder.js
@@ -0,0 +1,175 @@
+/**
+ * This class holds the functions regarding entities being visible on
+ * another entity, but tied to their location.
+ * Currently renaming and changing ownership are still manage by GarrisonHolder.js,
+ * but in the future these components could be independant.
+ */
+class TurretHolder
+{
+ Init()
+ {
+ this.turretPoints = [];
+
+ let points = this.template.TurretPoints;
+ for (let point in points)
+ this.turretPoints.push({
+ "offset": {
+ "x": +points[point].X,
+ "y": +points[point].Y,
+ "z": +points[point].Z
+ },
+ "allowedClasses": points[point].AllowedClasses,
+ "angle": points[point].Angle ? +points[point].Angle * Math.PI / 180 : null,
+ "entity": null
+ });
+ }
+
+ /**
+ * @param {number} entity - The entity to check for.
+ * @param {Object} turretPoint - The turret point to use.
+ *
+ * @return {boolean} - Whether the entity is allowed to occupy the specified turret point.
+ */
+ AllowedToOccupyTurret(entity, turretPoint)
+ {
+ if (!turretPoint || turretPoint.entity)
+ return false;
+
+ if (!IsOwnedByMutualAllyOfEntity(entity, this.entity))
+ return false;
+
+ if (!turretPoint.allowedClasses)
+ return true;
+
+ let cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
+ return cmpIdentity && MatchesClassList(cmpIdentity.GetClassesList(), turretPoint.allowedClasses._string);
+ }
+
+ /**
+ * Occupy a turret point with the given entity.
+ * @param {number} entity - The entity to use.
+ * @param {Object} turretPoint - Optionally the specific turret point to occupy.
+ *
+ * @return {boolean} - Whether the occupation was successful.
+ */
+ OccupyTurret(entity, requestedTurretPoint)
+ {
+ let cmpPositionOccupant = Engine.QueryInterface(entity, IID_Position);
+ if (!cmpPositionOccupant)
+ return false;
+
+ let cmpPositionSelf = Engine.QueryInterface(this.entity, IID_Position);
+ if (!cmpPositionSelf)
+ return false;
+
+ let turretPoint;
+ if (requestedTurretPoint && this.AllowedToOccupyTurret(entity, requestedTurretPoint))
+ turretPoint = requestedTurretPoint;
+
+ if (!turretPoint)
+ turretPoint = this.turretPoints.find(turret => !turret.entity && this.AllowedToOccupyTurret(entity, turret));
+
+ turretPoint.entity = entity;
+ // Angle of turrets:
+ // Renamed entities (turretPoint != undefined) should keep their angle.
+ // Otherwise if an angle is given in the turretPoint, use it.
+ // If no such angle given (usually walls for which outside/inside not well defined), we keep
+ // the current angle as it was used for garrisoning and thus quite often was from inside to
+ // outside, except when garrisoning from outWorld where we take as default PI.
+ if (!turretPoint && turretPoint.angle != null)
+ cmpPositionOccupant.SetYRotation(cmpPositionSelf.GetRotation().y + turretPoint.angle);
+ else if (!turretPoint && !cmpPosition.IsInWorld())
+ cmpPositionOccupant.SetYRotation(cmpPositionSelf.GetRotation().y + Math.PI);
+
+ cmpPositionOccupant.SetTurretParent(this.entity, turretPoint.offset);
+
+ let cmpUnitMotion = Engine.QueryInterface(entity, IID_UnitMotion);
+ if (cmpUnitMotion)
+ cmpUnitMotion.SetFacePointAfterMove(false);
+
+ let cmpUnitAI = Engine.QueryInterface(entity, IID_UnitAI);
+ if (cmpUnitAI)
+ cmpUnitAI.SetTurretStance();
+
+ return true;
+ }
+
+ /**
+ * Remove the entity from a turret.
+ * @param {number} entity - The specific entity to eject.
+ * @param {Object} turret - Optionally the turret to abandon.
+ *
+ * @return {boolean} - Whether the entity was occupying a/the turret before.
+ */
+ LeaveTurret(entity, turret)
+ {
+ if (!turret)
+ for (let turretPoint of this.turretPoints)
+ if (turretPoint.entity == entity)
+ {
+ turret = turretPoint;
+ break;
+ }
+
+ if (!turret)
+ return false;
+
+ let cmpPositionEntity = Engine.QueryInterface(entity, IID_Position);
+ cmpPositionEntity.SetTurretParent(INVALID_ENTITY, new Vector3D());
+
+ let cmpEntUnitMotion = Engine.QueryInterface(entity, IID_UnitMotion);
+ if (cmpEntUnitMotion)
+ cmpEntUnitMotion.SetFacePointAfterMove(true);
+
+ let cmpEntUnitAI = Engine.QueryInterface(entity, IID_UnitAI);
+ if (cmpEntUnitAI)
+ cmpEntUnitAI.ResetTurretStance();
+
+ turret.entity = null;
+ return true;
+ }
+
+ /**
+ * @param {number} entity - The entity's id.
+ * @return {boolean} - Whether the entity is positioned on a turret of this entity.
+ */
+ OccupiesTurret(entity)
+ {
+ return this.turretPoints.some(point => point.entity == entity);
+ }
+}
+
+TurretHolder.prototype.Schema =
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "tokens" +
+ "" +
+ "" +
+ "" +
+ ""+
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "";
+
+Engine.RegisterComponentType(IID_TurretHolder, "TurretHolder", TurretHolder);
Index: binaries/data/mods/public/simulation/components/interfaces/TurretHolder.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/components/interfaces/TurretHolder.js
@@ -0,0 +1,7 @@
+Engine.RegisterInterface("TurretHolder");
+
+/**
+ * Message of the form { "added": number[], "removed": number[] }
+ * sent from the TurretHolder component to the current entity whenever the turrets change.
+ */
+Engine.RegisterMessageType("TurretsChanged");
Index: binaries/data/mods/public/simulation/components/tests/test_GarrisonHolder.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_GarrisonHolder.js
+++ binaries/data/mods/public/simulation/components/tests/test_GarrisonHolder.js
@@ -2,6 +2,7 @@
Engine.LoadHelperScript("Player.js");
Engine.LoadComponentScript("interfaces/GarrisonHolder.js");
Engine.LoadComponentScript("interfaces/Garrisonable.js");
+Engine.LoadComponentScript("interfaces/TurretHolder.js");
Engine.LoadComponentScript("GarrisonHolder.js");
Engine.LoadComponentScript("interfaces/Auras.js");
Engine.LoadComponentScript("interfaces/Health.js");
@@ -73,11 +74,8 @@
"GetHeightOffset": () => 0,
"GetPosition": () => new Vector3D(4, 3, 25),
"GetRotation": () => new Vector3D(4, 0, 6),
- "GetTurretParent": () => INVALID_ENTITY,
- "IsInWorld": () => true,
"JumpTo": (posX, posZ) => {},
"MoveOutOfWorld": () => {},
- "SetTurretParent": (entity, offset) => {},
"SetHeightOffset": height => {}
});
}
@@ -94,19 +92,7 @@
"EjectClassesOnDestroy": { "_string": "Infantry" },
"BuffHeal": 1,
"LoadingRange": 2.1,
- "Pickup": false,
- "VisibleGarrisonPoints": {
- "archer1": {
- "X": 12,
- "Y": 5,
- "Z": 6
- },
- "archer2": {
- "X": 15,
- "Y": 5,
- "Z": 6
- }
- }
+ "Pickup": false
});
let testGarrisonAllowed = function()
@@ -182,23 +168,12 @@
"EjectClassesOnDestroy": { "_string": "Infantry" },
"BuffHeal": 1,
"LoadingRange": 2.1,
- "Pickup": false,
- "VisibleGarrisonPoints": {
- "archer1": {
- "X": 12,
- "Y": 5,
- "Z": 6
- },
- "archer2": {
- "X": 15,
- "Y": 5,
- "Z": 6
- }
- }
+ "Pickup": false
});
testGarrisonAllowed();
+// Test entity renaming.
let siegeEngineId = 44;
AddMock(siegeEngineId, IID_Identity, {
"GetClassesList": () => ["Siege"]
@@ -208,7 +183,6 @@
"GetClassesList": () => ["Infantry", "Ranged"]
});
-// Test visible garrisoning restrictions.
cmpGarrisonHolder = ConstructComponent(garrisonHolderId, "GarrisonHolder", {
"Max": 10,
"List": { "_string": "Infantry+Ranged Siege Cavalry" },
@@ -216,55 +190,19 @@
"EjectClassesOnDestroy": { "_string": "Infantry" },
"BuffHeal": 1,
"LoadingRange": 2.1,
- "Pickup": false,
- "VisibleGarrisonPoints": {
- "archer1": {
- "X": 12,
- "Y": 5,
- "Z": 6
- },
- "archer2": {
- "X": 15,
- "Y": 5,
- "Z": 6,
- "AllowedClasses": { "_string": "Siege Trader" }
- },
- "archer3": {
- "X": 15,
- "Y": 5,
- "Z": 6,
- "AllowedClasses": { "_string": "Siege Infantry+Ranged Infantry+Cavalry" }
- }
- }
+ "Pickup": false
});
AddMock(32, IID_Identity, {
"GetClassesList": () => ["Trader"]
});
-TS_ASSERT_EQUALS(cmpGarrisonHolder.Garrison(32), false);
-TS_ASSERT_EQUALS(cmpGarrisonHolder.AllowedToVisibleGarrisoning(siegeEngineId, cmpGarrisonHolder.visibleGarrisonPoints[0]), true);
-TS_ASSERT_EQUALS(cmpGarrisonHolder.AllowedToVisibleGarrisoning(siegeEngineId, cmpGarrisonHolder.visibleGarrisonPoints[1]), true);
-TS_ASSERT_EQUALS(cmpGarrisonHolder.AllowedToVisibleGarrisoning(siegeEngineId, cmpGarrisonHolder.visibleGarrisonPoints[2]), true);
-TS_ASSERT_EQUALS(cmpGarrisonHolder.AllowedToVisibleGarrisoning(archerId, cmpGarrisonHolder.visibleGarrisonPoints[0]), true);
-TS_ASSERT_EQUALS(cmpGarrisonHolder.AllowedToVisibleGarrisoning(archerId, cmpGarrisonHolder.visibleGarrisonPoints[1]), false);
-TS_ASSERT_EQUALS(cmpGarrisonHolder.AllowedToVisibleGarrisoning(archerId, cmpGarrisonHolder.visibleGarrisonPoints[2]), true);
-TS_ASSERT_EQUALS(cmpGarrisonHolder.AllowedToVisibleGarrisoning(33, cmpGarrisonHolder.visibleGarrisonPoints[0]), true);
-TS_ASSERT_EQUALS(cmpGarrisonHolder.AllowedToVisibleGarrisoning(33, cmpGarrisonHolder.visibleGarrisonPoints[1]), false);
-TS_ASSERT_EQUALS(cmpGarrisonHolder.AllowedToVisibleGarrisoning(33, cmpGarrisonHolder.visibleGarrisonPoints[2]), true);
-
-// If an entity gets renamed (e.g. promotion, upgrade)
-// and is no longer able to be visibly garrisoned it
-// should be garisoned instead or ejected.
AddMock(siegeEngineId, IID_Position, {
"GetHeightOffset": () => 0,
"GetPosition": () => new Vector3D(4, 3, 25),
"GetRotation": () => new Vector3D(4, 0, 6),
- "GetTurretParent": () => INVALID_ENTITY,
- "IsInWorld": () => true,
"JumpTo": (posX, posZ) => {},
"MoveOutOfWorld": () => {},
- "SetTurretParent": (entity, offset) => {},
"SetHeightOffset": height => {}
});
let currentSiegePlayer = player;
@@ -280,11 +218,8 @@
"GetHeightOffset": () => 0,
"GetPosition": () => new Vector3D(4, 3, 25),
"GetRotation": () => new Vector3D(4, 0, 6),
- "GetTurretParent": () => INVALID_ENTITY,
- "IsInWorld": () => true,
"JumpTo": (posX, posZ) => {},
"MoveOutOfWorld": () => {},
- "SetTurretParent": (entity, offset) => {},
"SetHeightOffset": height => {}
});
@@ -295,14 +230,11 @@
AddMock(cavalryId, IID_Garrisonable, {});
TS_ASSERT(cmpGarrisonHolder.Garrison(siegeEngineId));
TS_ASSERT_EQUALS(cmpGarrisonHolder.GetGarrisonedEntitiesCount(), 1);
-TS_ASSERT(cmpGarrisonHolder.IsVisiblyGarrisoned(siegeEngineId));
cmpGarrisonHolder.OnGlobalEntityRenamed({
"entity": siegeEngineId,
"newentity": cavalryId
});
TS_ASSERT_EQUALS(cmpGarrisonHolder.GetGarrisonedEntitiesCount(), 1);
-TS_ASSERT(!cmpGarrisonHolder.IsVisiblyGarrisoned(siegeEngineId));
-TS_ASSERT(!cmpGarrisonHolder.IsVisiblyGarrisoned(archerId));
// Eject enemy units.
currentCavalryPlayer = enemyPlayer;
@@ -311,14 +243,3 @@
"to": enemyPlayer
});
TS_ASSERT_EQUALS(cmpGarrisonHolder.GetGarrisonedEntitiesCount(), 0);
-
-// Visibly garrisoned units should get ejected if they change players.
-TS_ASSERT(cmpGarrisonHolder.Garrison(siegeEngineId));
-TS_ASSERT(cmpGarrisonHolder.IsVisiblyGarrisoned(siegeEngineId));
-TS_ASSERT_EQUALS(cmpGarrisonHolder.GetGarrisonedEntitiesCount(), 1);
-currentSiegePlayer = enemyPlayer;
-cmpGarrisonHolder.OnGlobalOwnershipChanged({
- "entity": siegeEngineId,
- "to": enemyPlayer
-});
-TS_ASSERT_EQUALS(cmpGarrisonHolder.GetGarrisonedEntitiesCount(), 0);
Index: binaries/data/mods/public/simulation/components/tests/test_TurretHolder.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/components/tests/test_TurretHolder.js
@@ -0,0 +1,97 @@
+Engine.LoadHelperScript("Player.js");
+Engine.LoadComponentScript("interfaces/TurretHolder.js");
+Engine.LoadComponentScript("TurretHolder.js");
+
+AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
+ "GetPlayerByID": id => id
+});
+
+const player = 1;
+const enemyPlayer = 2;
+const alliedPlayer = 3;
+const turretHolderID = 9;
+const entitiesToTest = [10, 11, 12];
+
+AddMock(turretHolderID, IID_Ownership, {
+ "GetOwner": () => player
+});
+
+for (let entity of entitiesToTest)
+{
+ AddMock(entity, IID_Position, {
+ "GetPosition": () => new Vector3D(4, 3, 25),
+ "GetRotation": () => new Vector3D(4, 0, 6),
+ "SetTurretParent": (entity, offset) => {}
+ });
+
+ AddMock(entity, IID_Ownership, {
+ "GetOwner": () => player
+ });
+}
+
+AddMock(player, IID_Player, {
+ "IsAlly": id => id != enemyPlayer,
+ "IsMutualAlly": id => id != enemyPlayer,
+ "GetPlayerID": () => player
+});
+
+AddMock(alliedPlayer, IID_Player, {
+ "IsAlly": id => true,
+ "IsMutualAlly": id => true,
+ "GetPlayerID": () => alliedPlayer
+});
+
+let cmpTurretHolder = ConstructComponent(turretHolderID, "TurretHolder", {
+ "TurretPoints": {
+ "archer1": {
+ "X": 12,
+ "Y": 5,
+ "Z": 6
+ },
+ "archer2": {
+ "X": 15,
+ "Y": 5,
+ "Z": 6,
+ "AllowedClasses": { "_string": "Siege Trader" }
+ },
+ "archer3": {
+ "X": 15,
+ "Y": 5,
+ "Z": 6,
+ "AllowedClasses": { "_string": "Siege Infantry+Ranged Infantry+Cavalry" }
+ }
+ }
+});
+
+let siegeEngineId = entitiesToTest[0];
+AddMock(siegeEngineId, IID_Identity, {
+ "GetClassesList": () => ["Siege"]
+});
+
+let archerId = entitiesToTest[1];
+AddMock(archerId, IID_Identity, {
+ "GetClassesList": () => ["Infantry", "Ranged"]
+});
+
+let cavId = entitiesToTest[2];
+AddMock(cavId, IID_Identity, {
+ "GetClassesList": () => ["Infantry", "Cavalry"]
+});
+
+// Test visible garrisoning restrictions.
+TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(siegeEngineId, cmpTurretHolder.turretPoints[0]), true);
+TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(siegeEngineId, cmpTurretHolder.turretPoints[1]), true);
+TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(siegeEngineId, cmpTurretHolder.turretPoints[2]), true);
+TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(archerId, cmpTurretHolder.turretPoints[0]), true);
+TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(archerId, cmpTurretHolder.turretPoints[1]), false);
+TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(archerId, cmpTurretHolder.turretPoints[2]), true);
+TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(cavId, cmpTurretHolder.turretPoints[0]), true);
+TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(cavId, cmpTurretHolder.turretPoints[1]), false);
+TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(cavId, cmpTurretHolder.turretPoints[2]), true);
+
+// If an entity gets renamed (e.g. promotion, upgrade)
+// and is no longer able to be visibly garrisoned it
+// should be garisoned instead or ejected.
+// This is currently tied to GarrisonHolder.js but ought to be decoupled,
+// so that it can be tested here.
+// Idem for ownership changes.
Index: binaries/data/mods/public/simulation/templates/structures/athen_wall_long.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/athen_wall_long.xml
+++ binaries/data/mods/public/simulation/templates/structures/athen_wall_long.xml
@@ -4,8 +4,8 @@
9.0
-
-
+
+
0
11.5
@@ -31,8 +31,8 @@
11.5
0
-
-
+
+
athen
Teichos
Index: binaries/data/mods/public/simulation/templates/structures/athen_wall_medium.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/athen_wall_medium.xml
+++ binaries/data/mods/public/simulation/templates/structures/athen_wall_medium.xml
@@ -4,8 +4,8 @@
12.5
-
-
+
+
0
11.5
@@ -21,8 +21,8 @@
11.5
0
-
-
+
+
athen
Teichos
Index: binaries/data/mods/public/simulation/templates/structures/brit_wall_long.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/brit_wall_long.xml
+++ binaries/data/mods/public/simulation/templates/structures/brit_wall_long.xml
@@ -4,8 +4,8 @@
10.3
-
-
+
+
0
9.3
@@ -31,8 +31,8 @@
9.3
0
-
-
+
+
brit
Rate
Index: binaries/data/mods/public/simulation/templates/structures/brit_wall_medium.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/brit_wall_medium.xml
+++ binaries/data/mods/public/simulation/templates/structures/brit_wall_medium.xml
@@ -4,8 +4,8 @@
10.3
-
-
+
+
0
9.3
@@ -21,8 +21,8 @@
9.3
0
-
-
+
+
brit
Rate
Index: binaries/data/mods/public/simulation/templates/structures/cart_wall_long.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/cart_wall_long.xml
+++ binaries/data/mods/public/simulation/templates/structures/cart_wall_long.xml
@@ -4,8 +4,8 @@
13
-
-
+
+
0
12
@@ -31,8 +31,8 @@
12
0
-
-
+
+
cart
Homah
Index: binaries/data/mods/public/simulation/templates/structures/cart_wall_medium.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/cart_wall_medium.xml
+++ binaries/data/mods/public/simulation/templates/structures/cart_wall_medium.xml
@@ -4,8 +4,8 @@
13
-
-
+
+
0
12
@@ -21,8 +21,8 @@
12
0
-
-
+
+
cart
Homah
Index: binaries/data/mods/public/simulation/templates/structures/gaul_wall_long.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/gaul_wall_long.xml
+++ binaries/data/mods/public/simulation/templates/structures/gaul_wall_long.xml
@@ -4,8 +4,8 @@
10.3
-
-
+
+
0
9.3
@@ -31,8 +31,8 @@
9.3
0
-
-
+
+
gaul
Rate
Index: binaries/data/mods/public/simulation/templates/structures/gaul_wall_medium.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/gaul_wall_medium.xml
+++ binaries/data/mods/public/simulation/templates/structures/gaul_wall_medium.xml
@@ -4,8 +4,8 @@
10.3
-
-
+
+
0
9.3
@@ -21,8 +21,8 @@
9.3
0
-
-
+
+
gaul
Rate
Index: binaries/data/mods/public/simulation/templates/structures/iber_wall_long.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/iber_wall_long.xml
+++ binaries/data/mods/public/simulation/templates/structures/iber_wall_long.xml
@@ -4,8 +4,8 @@
10
-
-
+
+
0
9
@@ -31,8 +31,8 @@
9
0
-
-
+
+
iber
Zabal Horma
Index: binaries/data/mods/public/simulation/templates/structures/iber_wall_medium.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/iber_wall_medium.xml
+++ binaries/data/mods/public/simulation/templates/structures/iber_wall_medium.xml
@@ -4,8 +4,8 @@
10
-
-
+
+
0
9
@@ -21,8 +21,8 @@
9
0
-
-
+
+
iber
Zabal Horma
Index: binaries/data/mods/public/simulation/templates/structures/kush_wall_long.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/kush_wall_long.xml
+++ binaries/data/mods/public/simulation/templates/structures/kush_wall_long.xml
@@ -4,8 +4,8 @@
12.6
-
-
+
+
0
11.6
@@ -31,8 +31,8 @@
11.6
0
-
-
+
+
kush
sbty
Index: binaries/data/mods/public/simulation/templates/structures/kush_wall_medium.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/kush_wall_medium.xml
+++ binaries/data/mods/public/simulation/templates/structures/kush_wall_medium.xml
@@ -4,8 +4,8 @@
12.6
-
-
+
+
0
11.6
@@ -21,8 +21,8 @@
11.6
0
-
-
+
+
kush
sbty
Index: binaries/data/mods/public/simulation/templates/structures/mace_wall_long.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/mace_wall_long.xml
+++ binaries/data/mods/public/simulation/templates/structures/mace_wall_long.xml
@@ -4,8 +4,8 @@
12.5
-
-
+
+
0
11.5
@@ -31,8 +31,8 @@
11.5
0
-
-
+
+
mace
Teichos
Index: binaries/data/mods/public/simulation/templates/structures/mace_wall_medium.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/mace_wall_medium.xml
+++ binaries/data/mods/public/simulation/templates/structures/mace_wall_medium.xml
@@ -4,8 +4,8 @@
12.5
-
-
+
+
0
11.5
@@ -21,8 +21,8 @@
11.5
0
-
-
+
+
mace
Teichos
Index: binaries/data/mods/public/simulation/templates/structures/maur_tower_double.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/maur_tower_double.xml
+++ binaries/data/mods/public/simulation/templates/structures/maur_tower_double.xml
@@ -23,7 +23,9 @@
Infantry+Archer
20
-
+
+
+
212.50
@@ -72,8 +74,8 @@
-2.118.0-2.1
-
-
+
+
1200
Index: binaries/data/mods/public/simulation/templates/structures/maur_wall_long.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/maur_wall_long.xml
+++ binaries/data/mods/public/simulation/templates/structures/maur_wall_long.xml
@@ -10,8 +10,8 @@
10.5
-
-
+
+
0
9.5
@@ -37,8 +37,8 @@
9.5
0
-
-
+
+
maur
Shilabanda
Index: binaries/data/mods/public/simulation/templates/structures/maur_wall_medium.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/maur_wall_medium.xml
+++ binaries/data/mods/public/simulation/templates/structures/maur_wall_medium.xml
@@ -10,8 +10,8 @@
10.5
-
-
+
+
0
9.5
@@ -27,8 +27,8 @@
9.5
0
-
-
+
+
maur
Shilabanda
Index: binaries/data/mods/public/simulation/templates/structures/pers_wall_long.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/pers_wall_long.xml
+++ binaries/data/mods/public/simulation/templates/structures/pers_wall_long.xml
@@ -4,8 +4,8 @@
11.6
-
-
+
+
0
10.6
@@ -31,8 +31,8 @@
10.6
0
-
-
+
+
pers
Para
Index: binaries/data/mods/public/simulation/templates/structures/pers_wall_medium.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/pers_wall_medium.xml
+++ binaries/data/mods/public/simulation/templates/structures/pers_wall_medium.xml
@@ -4,8 +4,8 @@
11.6
-
-
+
+
0
10.6
@@ -21,8 +21,8 @@
10.6
0
-
-
+
+
pers
Para
Index: binaries/data/mods/public/simulation/templates/structures/ptol_wall_long.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/ptol_wall_long.xml
+++ binaries/data/mods/public/simulation/templates/structures/ptol_wall_long.xml
@@ -4,8 +4,8 @@
10.8
-
-
+
+
0
9.8
@@ -31,8 +31,8 @@
9.8
0
-
-
+
+
ptol
Teichos
Index: binaries/data/mods/public/simulation/templates/structures/ptol_wall_medium.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/ptol_wall_medium.xml
+++ binaries/data/mods/public/simulation/templates/structures/ptol_wall_medium.xml
@@ -4,8 +4,8 @@
10.8
-
-
+
+
0
9.8
@@ -21,8 +21,8 @@
9.8
0
-
-
+
+
ptol
Teichos
Index: binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_long.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_long.xml
+++ binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_long.xml
@@ -23,8 +23,8 @@
6.7
-
-
+
+
0
5.7
@@ -50,8 +50,8 @@
5.7
0
-
-
+
+
0.75
Index: binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_medium.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_medium.xml
+++ binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_medium.xml
@@ -23,8 +23,8 @@
6.7
-
-
+
+
0
5.7
@@ -40,8 +40,8 @@
5.7
0
-
-
+
+
0.75
Index: binaries/data/mods/public/simulation/templates/structures/rome_wall_long.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/rome_wall_long.xml
+++ binaries/data/mods/public/simulation/templates/structures/rome_wall_long.xml
@@ -4,8 +4,8 @@
9.9
-
-
+
+
0
8.9
@@ -31,8 +31,8 @@
8.9
0
-
-
+
+
rome
Moenia
Index: binaries/data/mods/public/simulation/templates/structures/rome_wall_medium.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/rome_wall_medium.xml
+++ binaries/data/mods/public/simulation/templates/structures/rome_wall_medium.xml
@@ -4,8 +4,8 @@
9.9
-
-
+
+
0
8.9
@@ -21,8 +21,8 @@
8.9
0
-
-
+
+
rome
Moenia
Index: binaries/data/mods/public/simulation/templates/structures/sele_wall_long.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/sele_wall_long.xml
+++ binaries/data/mods/public/simulation/templates/structures/sele_wall_long.xml
@@ -4,8 +4,8 @@
11.4
-
-
+
+
0
10.4
@@ -31,8 +31,8 @@
10.4
0
-
-
+
+
sele
Teichos
Index: binaries/data/mods/public/simulation/templates/structures/sele_wall_medium.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/sele_wall_medium.xml
+++ binaries/data/mods/public/simulation/templates/structures/sele_wall_medium.xml
@@ -4,8 +4,8 @@
11.4
-
-
+
+
0
10.4
@@ -21,8 +21,8 @@
10.4
0
-
-
+
+
sele
Teichos
Index: binaries/data/mods/public/simulation/templates/structures/spart_wall_long.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/spart_wall_long.xml
+++ binaries/data/mods/public/simulation/templates/structures/spart_wall_long.xml
@@ -4,8 +4,8 @@
12.5
-
-
+
+
0
11.5
@@ -31,8 +31,8 @@
11.5
0
-
-
+
+
spart
Teichos
Index: binaries/data/mods/public/simulation/templates/structures/spart_wall_medium.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/spart_wall_medium.xml
+++ binaries/data/mods/public/simulation/templates/structures/spart_wall_medium.xml
@@ -4,8 +4,8 @@
12.5
-
-
+
+
0
11.5
@@ -21,8 +21,8 @@
11.5
0
-
-
+
+
spart
Teichos