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
@@ -206,6 +206,7 @@
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.
@@ -224,6 +225,12 @@
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.SetDisableBlockMovementPathfinding(true, true, -1);
+
}
else
cmpPosition.MoveOutOfWorld();
@@ -324,6 +331,12 @@
if (cmpEntUnitAI)
cmpEntUnitAI.ResetTurretStance();
vgp.entity = null;
+
+ // Reset the obstruction flags to template defaults.
+ let cmpObstruction = Engine.QueryInterface(entity, IID_Obstruction);
+ if (cmpObstruction)
+ cmpObstruction.SetDisableBlockMovementPathfinding(false, false, -1);
+
break;
}
Index: binaries/data/mods/public/simulation/components/Gate.js
===================================================================
--- binaries/data/mods/public/simulation/components/Gate.js
+++ binaries/data/mods/public/simulation/components/Gate.js
@@ -59,6 +59,23 @@
}
};
+Gate.prototype.OnGarrisonedUnitsChanged = function(msg)
+{
+ for (let entity of msg.removed)
+ {
+ // Ignore entities that cannot move as those won't be able to go through the gate.
+ let unitAI = Engine.QueryInterface(entity, IID_UnitAI);
+ if (!unitAI.AbleToMove())
+ continue;
+ this.allies.push(entity);
+ }
+
+ for (let entity of msg.added)
+ this.allies.splice(this.allies.indexOf(entity), 1);
+
+ this.OperateGate();
+};
+
/**
* Setup the range query to detect units coming in & out of range
*/
@@ -91,7 +108,13 @@
if (msg.added.length > 0)
for (let entity of msg.added)
+ {
+ // Ignore entities that cannot move as those won't be able to go through the gate.
+ let unitAI = Engine.QueryInterface(entity, IID_UnitAI);
+ if (!unitAI.AbleToMove())
+ continue;
this.allies.push(entity);
+ }
if (msg.removed.length > 0)
for (let entity of msg.removed)
@@ -220,7 +243,7 @@
return;
// The gate can't be closed if there are entities colliding with it.
- var collisions = cmpObstruction.GetEntitiesBlockingConstruction();
+ var collisions = cmpObstruction.GetEntitiesBlockingMovement();
if (collisions.length)
{
if (!this.timer)
Index: binaries/data/mods/public/simulation/components/UnitAI.js
===================================================================
--- binaries/data/mods/public/simulation/components/UnitAI.js
+++ binaries/data/mods/public/simulation/components/UnitAI.js
@@ -213,7 +213,7 @@
// If foundation is not ally of entity, or if entity is unpacked siege,
// ignore the order
if (!IsOwnedByAllyOfEntity(this.entity, msg.data.target) && !Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager).IsCeasefireActive() ||
- this.IsPacking() || this.CanPack() || this.IsTurret())
+ !this.AbleToMove() || this.CanPack() || this.IsTurret())
{
this.FinishOrder();
return;
@@ -1228,7 +1228,7 @@
// If foundation is not ally of entity, or if entity is unpacked siege,
// ignore the order
if (!IsOwnedByAllyOfEntity(this.entity, msg.data.target) && !Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager).IsCeasefireActive() ||
- this.IsPacking() || this.CanPack() || this.IsTurret())
+ !this.AbleToMove() || this.CanPack() || this.IsTurret())
{
this.FinishOrder();
return;
@@ -2785,6 +2785,7 @@
if (cmpGarrisonHolder.Garrison(this.entity))
{
this.isGarrisoned = true;
+ this.SetImmobile(true);
if (this.formationController)
{
@@ -2887,16 +2888,19 @@
"PACKING": {
"enter": function() {
this.StopMoving();
+ this.SetImmobile(true);
- var cmpPack = Engine.QueryInterface(this.entity, IID_Pack);
+ let cmpPack = Engine.QueryInterface(this.entity, IID_Pack);
cmpPack.Pack();
},
"PackFinished": function(msg) {
+ this.SetImmobile(false);
this.FinishOrder();
},
"leave": function() {
+ this.SetImmobile(false);
},
"Attacked": function(msg) {
@@ -2907,16 +2911,19 @@
"UNPACKING": {
"enter": function() {
this.StopMoving();
+ this.SetImmobile(true);
var cmpPack = Engine.QueryInterface(this.entity, IID_Pack);
cmpPack.Unpack();
},
"PackFinished": function(msg) {
+ this.SetImmobile(false);
this.FinishOrder();
},
"leave": function() {
+ this.SetImmobile(false);
},
"Attacked": function(msg) {
@@ -3104,6 +3111,7 @@
this.formationController = INVALID_ENTITY; // entity with IID_Formation that we belong to
this.isGarrisoned = false;
this.isIdle = false;
+ this.isImmobile = false; // True if the unit is currently unable to move (garrisoned, packing...)
this.finishedOrder = false; // used to find if all formation members finished the order
this.heldPosition = undefined;
@@ -3201,6 +3209,26 @@
return !this.orderQueue.length || this.orderQueue[0].type == "Garrison";
};
+UnitAI.prototype.SetImmobile = function(immobile)
+{
+ this.isImmobile = immobile;
+};
+
+/**
+ * @param cmpUnitMotion - optionally pass unitMotion to avoid querying it here
+ * @returns true if the entity can move, i.e. has UnitMotion
+ * and isn't immobile.
+ */
+UnitAI.prototype.AbleToMove = function(cmpUnitMotion)
+{
+ if (!cmpUnitMotion)
+ cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
+
+ if (this.isImmobile || !cmpUnitMotion)
+ return false;
+ return true;
+};
+
UnitAI.prototype.IsFleeing = function()
{
var state = this.GetCurrentState().split(".").pop();
@@ -4115,8 +4143,9 @@
UnitAI.prototype.StopMoving = function()
{
- var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
- cmpUnitMotion.StopMoving();
+ let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
+ if (cmpUnitMotion)
+ cmpUnitMotion.StopMoving();
};
/**
@@ -4144,13 +4173,17 @@
UnitAI.prototype.MoveToPoint = function(x, z)
{
- var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
+ let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
+ if (!this.AbleToMove(cmpUnitMotion))
+ return false;
return cmpUnitMotion.MoveToPointRange(x, z, 0, 0);
};
UnitAI.prototype.MoveToPointRange = function(x, z, rangeMin, rangeMax)
{
- var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
+ let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
+ if (!this.AbleToMove(cmpUnitMotion))
+ return false;
return cmpUnitMotion.MoveToPointRange(x, z, rangeMin, rangeMax);
};
@@ -4159,7 +4192,10 @@
if (!this.CheckTargetVisible(target))
return false;
- var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
+ let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
+ if (!this.AbleToMove(cmpUnitMotion))
+ return false;
+
return cmpUnitMotion.MoveToTargetRange(target, 0, 0);
};
@@ -4173,7 +4209,10 @@
return false;
var range = cmpRanged.GetRange(type);
- var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
+ let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
+ if (!this.AbleToMove(cmpUnitMotion))
+ return false;
+
return cmpUnitMotion.MoveToTargetRange(target, range.min, range.max);
};
@@ -4192,6 +4231,10 @@
return false;
}
+ let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
+ if (!this.AbleToMove(cmpUnitMotion))
+ return false;
+
let cmpFormation = Engine.QueryInterface(target, IID_Formation);
if (cmpFormation)
target = cmpFormation.GetClosestMember(this.entity);
@@ -4227,7 +4270,6 @@
// The parabole changes while walking so be cautious:
let guessedMaxRange = parabolicMaxRange > range.max ? (range.max + parabolicMaxRange) / 2 : parabolicMaxRange;
- let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
return cmpUnitMotion.MoveToTargetRange(target, range.min, guessedMaxRange);
};
@@ -4236,7 +4278,10 @@
if (!this.CheckTargetVisible(target))
return false;
- var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
+ let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
+ if (!this.AbleToMove(cmpUnitMotion))
+ return false;
+
return cmpUnitMotion.MoveToTargetRange(target, min, max);
};
@@ -4245,12 +4290,15 @@
if (!this.CheckTargetVisible(target))
return false;
- var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder);
+ let cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder);
if (!cmpGarrisonHolder)
return false;
- var range = cmpGarrisonHolder.GetLoadingRange();
+ let range = cmpGarrisonHolder.GetLoadingRange();
+
+ let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
+ if (!this.AbleToMove(cmpUnitMotion))
+ return false;
- var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
return cmpUnitMotion.MoveToTargetRange(target, range.min, range.max);
};
@@ -4904,7 +4952,7 @@
// ignore this new request so we don't end up being too indecisive
// to ever actually move anywhere
// Ignore also the request if we are packing
- if (this.order && (this.order.type == "LeaveFoundation" || (this.order.type == "Flee" && this.order.data.target == target) || this.IsPacking()))
+ if (this.order && (this.order.type == "LeaveFoundation" || (this.order.type == "Flee" && this.order.data.target == target) || !this.AbleToMove()))
return;
this.PushOrderFront("LeaveFoundation", { "target": target, "force": true });
@@ -4958,7 +5006,10 @@
UnitAI.prototype.Ungarrison = function()
{
if (this.IsGarrisoned())
+ {
+ this.SetImmobile(false);
this.AddOrder("Ungarrison", null, false);
+ }
};
/**
Index: binaries/data/mods/public/simulation/templates/structures/iber_wall_gate.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/structures/iber_wall_gate.xml
+++ binaries/data/mods/public/simulation/templates/structures/iber_wall_gate.xml
@@ -4,6 +4,25 @@
9.0
+
+ 3
+ Ranged+Infantry
+ 0.1
+ Unit
+ 0
+ 2
+
+
+ 011.50
+
+
+ 411.50
+
+
+ -411.50
+
+
+
iber
Biko Sarbide
@@ -15,6 +34,7 @@
+
structures/iberians/wall_gate.xml
Index: source/simulation2/components/CCmpObstruction.cpp
===================================================================
--- source/simulation2/components/CCmpObstruction.cpp
+++ source/simulation2/components/CCmpObstruction.cpp
@@ -645,6 +645,11 @@
return ret;
}
+ virtual std::vector GetEntitiesBlockingMovement() const
+ {
+ return GetEntitiesByFlags(ICmpObstructionManager::FLAG_BLOCK_MOVEMENT);
+ }
+
virtual std::vector GetEntitiesBlockingConstruction() const
{
return GetEntitiesByFlags(ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION);
Index: source/simulation2/components/ICmpObstruction.h
===================================================================
--- source/simulation2/components/ICmpObstruction.h
+++ source/simulation2/components/ICmpObstruction.h
@@ -94,6 +94,12 @@
*/
virtual std::vector GetEntitiesByFlags(ICmpObstructionManager::flags_t flags) const = 0;
+ /**
+ * Returns a list of entities that are blocking movement.
+ * @return vector of blocking entities
+ */
+ virtual std::vector GetEntitiesBlockingMovement() const = 0;
+
/**
* Returns a list of entities that are blocking construction of a foundation.
* @return vector of blocking entities
Index: source/simulation2/components/ICmpObstruction.cpp
===================================================================
--- source/simulation2/components/ICmpObstruction.cpp
+++ source/simulation2/components/ICmpObstruction.cpp
@@ -50,6 +50,7 @@
DEFINE_INTERFACE_METHOD_CONST_0("CheckShorePlacement", bool, ICmpObstruction, CheckShorePlacement)
DEFINE_INTERFACE_METHOD_CONST_2("CheckFoundation", std::string, ICmpObstruction, CheckFoundation_wrapper, std::string, bool)
DEFINE_INTERFACE_METHOD_CONST_0("CheckDuplicateFoundation", bool, ICmpObstruction, CheckDuplicateFoundation)
+DEFINE_INTERFACE_METHOD_CONST_0("GetEntitiesBlockingMovement", std::vector, ICmpObstruction, GetEntitiesBlockingMovement)
DEFINE_INTERFACE_METHOD_CONST_0("GetEntitiesBlockingConstruction", std::vector, ICmpObstruction, GetEntitiesBlockingConstruction)
DEFINE_INTERFACE_METHOD_CONST_0("GetEntitiesDeletedUponConstruction", std::vector, ICmpObstruction, GetEntitiesDeletedUponConstruction)
DEFINE_INTERFACE_METHOD_1("SetActive", void, ICmpObstruction, SetActive, bool)