Enable garrisoning on gates / fix movement of units with visible garrison points
This addresses two related issues: - Units visibly garrisoned on gates keep the gate open. - Units visibly garrisoned on entities keep their pathfinding blocker flags. Remove the block-movement flag from visibly garrisoned entities. Keep a list of entities that cannot move and thus should not count towards gate-opening logic. Packing logic is kept separate: it is more related to entities having 'alternate forms' with different capabilities than being currently incapable of moving. Based on work by temple Comments by: Freagarach Tested by: Nescio Fixes #2679 Fixes #5151 Differential Revision: https://code.wildfiregames.com/D1418 This was SVN commit r23710.
This commit is contained in:
parent
ed2ae1d283
commit
2abd9cead2
@ -249,6 +249,11 @@ GarrisonHolder.prototype.Garrison = function(entity, vgpEntity)
|
|||||||
if (cmpUnitAI)
|
if (cmpUnitAI)
|
||||||
cmpUnitAI.SetTurretStance();
|
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);
|
||||||
|
|
||||||
isVisiblyGarrisoned = true;
|
isVisiblyGarrisoned = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -366,6 +371,11 @@ GarrisonHolder.prototype.Eject = function(entity, forced)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset the obstruction flags to template defaults.
|
||||||
|
let cmpObstruction = Engine.QueryInterface(entity, IID_Obstruction);
|
||||||
|
if (cmpObstruction)
|
||||||
|
cmpObstruction.SetDisableBlockMovementPathfinding(false, false, -1);
|
||||||
|
|
||||||
if (cmpEntUnitAI)
|
if (cmpEntUnitAI)
|
||||||
cmpEntUnitAI.Ungarrison();
|
cmpEntUnitAI.Ungarrison();
|
||||||
|
|
||||||
|
@ -15,10 +15,25 @@ Gate.prototype.Schema =
|
|||||||
Gate.prototype.Init = function()
|
Gate.prototype.Init = function()
|
||||||
{
|
{
|
||||||
this.allies = [];
|
this.allies = [];
|
||||||
|
this.ignoreList = [];
|
||||||
this.opened = false;
|
this.opened = false;
|
||||||
this.locked = false;
|
this.locked = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the renaming case (from long-wall to gate)
|
||||||
|
* because that does not trigger ownershipchange or diplomacy change
|
||||||
|
* and units don't get added to the ignorelist.
|
||||||
|
*/
|
||||||
|
Gate.prototype.OnEntityRenamed = function(msg)
|
||||||
|
{
|
||||||
|
let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||||
|
if (!cmpOwnership || cmpOwnership.GetOwner() == INVALID_PLAYER)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.SetupRangeQuery();
|
||||||
|
};
|
||||||
|
|
||||||
Gate.prototype.OnOwnershipChanged = function(msg)
|
Gate.prototype.OnOwnershipChanged = function(msg)
|
||||||
{
|
{
|
||||||
if (msg.to != INVALID_PLAYER)
|
if (msg.to != INVALID_PLAYER)
|
||||||
@ -32,10 +47,11 @@ Gate.prototype.OnOwnershipChanged = function(msg)
|
|||||||
|
|
||||||
Gate.prototype.OnDiplomacyChanged = function(msg)
|
Gate.prototype.OnDiplomacyChanged = function(msg)
|
||||||
{
|
{
|
||||||
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||||
if (cmpOwnership && cmpOwnership.GetOwner() == msg.player)
|
if (cmpOwnership && cmpOwnership.GetOwner() == msg.player)
|
||||||
{
|
{
|
||||||
this.allies = [];
|
this.allies = [];
|
||||||
|
this.ignoreList = [];
|
||||||
this.SetupRangeQuery(msg.player);
|
this.SetupRangeQuery(msg.player);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -91,11 +107,36 @@ Gate.prototype.OnRangeUpdate = function(msg)
|
|||||||
|
|
||||||
if (msg.added.length > 0)
|
if (msg.added.length > 0)
|
||||||
for (let entity of msg.added)
|
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())
|
||||||
|
this.ignoreList.push(entity);
|
||||||
this.allies.push(entity);
|
this.allies.push(entity);
|
||||||
|
}
|
||||||
|
|
||||||
if (msg.removed.length > 0)
|
if (msg.removed.length > 0)
|
||||||
for (let entity of msg.removed)
|
for (let entity of msg.removed)
|
||||||
|
{
|
||||||
|
let index = this.ignoreList.indexOf(entity);
|
||||||
|
if (index !== -1)
|
||||||
|
this.ignoreList.splice(index, 1);
|
||||||
this.allies.splice(this.allies.indexOf(entity), 1);
|
this.allies.splice(this.allies.indexOf(entity), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.OperateGate();
|
||||||
|
};
|
||||||
|
|
||||||
|
Gate.prototype.OnGlobalUnitAbleToMoveChanged = function(msg)
|
||||||
|
{
|
||||||
|
if (this.allies.indexOf(msg.entity) === -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let index = this.ignoreList.indexOf(msg.entity);
|
||||||
|
if (msg.ableToMove && index !== -1)
|
||||||
|
this.ignoreList.splice(index, 1);
|
||||||
|
else if (!msg.ableToMove && index === -1)
|
||||||
|
this.ignoreList.push(msg.entity);
|
||||||
|
|
||||||
this.OperateGate();
|
this.OperateGate();
|
||||||
};
|
};
|
||||||
@ -108,6 +149,11 @@ Gate.prototype.GetPassRange = function()
|
|||||||
return +this.template.PassRange;
|
return +this.template.PassRange;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Gate.prototype.ShouldOpen = function()
|
||||||
|
{
|
||||||
|
return this.allies.some(ent => this.ignoreList.indexOf(ent) === -1);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to open or close the gate.
|
* Attempt to open or close the gate.
|
||||||
* An ally must be in range to open the gate, but an unlocked gate will only close
|
* An ally must be in range to open the gate, but an unlocked gate will only close
|
||||||
@ -122,10 +168,9 @@ Gate.prototype.OperateGate = function()
|
|||||||
cmpTimer.CancelTimer(this.timer);
|
cmpTimer.CancelTimer(this.timer);
|
||||||
this.timer = undefined;
|
this.timer = undefined;
|
||||||
}
|
}
|
||||||
|
if (this.opened && (this.locked || !this.ShouldOpen()))
|
||||||
if (this.opened && (this.allies.length == 0 || this.locked))
|
|
||||||
this.CloseGate();
|
this.CloseGate();
|
||||||
else if (!this.opened && this.allies.length)
|
else if (!this.opened && this.ShouldOpen())
|
||||||
this.OpenGate();
|
this.OpenGate();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -215,19 +260,19 @@ Gate.prototype.OpenGate = function()
|
|||||||
*/
|
*/
|
||||||
Gate.prototype.CloseGate = function()
|
Gate.prototype.CloseGate = function()
|
||||||
{
|
{
|
||||||
var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
|
let cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
|
||||||
if (!cmpObstruction)
|
if (!cmpObstruction)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// The gate can't be closed if there are entities colliding with it.
|
// The gate can't be closed if there are entities colliding with it.
|
||||||
var collisions = cmpObstruction.GetEntitiesBlockingConstruction();
|
let collisions = cmpObstruction.GetEntitiesBlockingMovement();
|
||||||
if (collisions.length)
|
if (collisions.length)
|
||||||
{
|
{
|
||||||
if (!this.timer)
|
if (!this.timer)
|
||||||
{
|
{
|
||||||
// Set an "instant" timer which will run on the next simulation turn.
|
// Set an "instant" timer which will run on the next simulation turn.
|
||||||
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
||||||
this.timer = cmpTimer.SetTimeout(this.entity, IID_Gate, "OperateGate", 0, {});
|
this.timer = cmpTimer.SetTimeout(this.entity, IID_Gate, "OperateGate", 0);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -241,7 +286,7 @@ Gate.prototype.CloseGate = function()
|
|||||||
this.opened = false;
|
this.opened = false;
|
||||||
|
|
||||||
PlaySound("gate_closing", this.entity);
|
PlaySound("gate_closing", this.entity);
|
||||||
var cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
|
let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
|
||||||
if (cmpVisual)
|
if (cmpVisual)
|
||||||
cmpVisual.SelectAnimation("gate_closing", true, 1.0);
|
cmpVisual.SelectAnimation("gate_closing", true, 1.0);
|
||||||
};
|
};
|
||||||
|
@ -209,7 +209,7 @@ UnitAI.prototype.UnitFsmSpec = {
|
|||||||
// Called when being told to walk as part of a formation
|
// Called when being told to walk as part of a formation
|
||||||
"Order.FormationWalk": function(msg) {
|
"Order.FormationWalk": function(msg) {
|
||||||
// Let players move captured domestic animals around
|
// Let players move captured domestic animals around
|
||||||
if (this.IsAnimal() && !this.IsDomestic() || this.IsTurret())
|
if (this.IsAnimal() && !this.IsDomestic() || !this.AbleToMove())
|
||||||
{
|
{
|
||||||
this.FinishOrder();
|
this.FinishOrder();
|
||||||
return;
|
return;
|
||||||
@ -269,7 +269,7 @@ UnitAI.prototype.UnitFsmSpec = {
|
|||||||
|
|
||||||
"Order.Walk": function(msg) {
|
"Order.Walk": function(msg) {
|
||||||
// Let players move captured domestic animals around
|
// Let players move captured domestic animals around
|
||||||
if (this.IsAnimal() && !this.IsDomestic() || this.IsTurret())
|
if (this.IsAnimal() && !this.IsDomestic() || !this.AbleToMove())
|
||||||
{
|
{
|
||||||
this.FinishOrder();
|
this.FinishOrder();
|
||||||
return;
|
return;
|
||||||
@ -295,7 +295,7 @@ UnitAI.prototype.UnitFsmSpec = {
|
|||||||
|
|
||||||
"Order.WalkAndFight": function(msg) {
|
"Order.WalkAndFight": function(msg) {
|
||||||
// Let players move captured domestic animals around
|
// Let players move captured domestic animals around
|
||||||
if (this.IsAnimal() && !this.IsDomestic() || this.IsTurret())
|
if (this.IsAnimal() && !this.IsDomestic() || !this.AbleToMove())
|
||||||
{
|
{
|
||||||
this.FinishOrder();
|
this.FinishOrder();
|
||||||
return;
|
return;
|
||||||
@ -322,7 +322,7 @@ UnitAI.prototype.UnitFsmSpec = {
|
|||||||
|
|
||||||
"Order.WalkToTarget": function(msg) {
|
"Order.WalkToTarget": function(msg) {
|
||||||
// Let players move captured domestic animals around
|
// Let players move captured domestic animals around
|
||||||
if (this.IsAnimal() && !this.IsDomestic() || this.IsTurret())
|
if (this.IsAnimal() && !this.IsDomestic() || !this.AbleToMove())
|
||||||
{
|
{
|
||||||
this.FinishOrder();
|
this.FinishOrder();
|
||||||
return;
|
return;
|
||||||
@ -451,7 +451,7 @@ UnitAI.prototype.UnitFsmSpec = {
|
|||||||
|
|
||||||
// If we can't reach the target, but are standing ground, then abandon this attack order.
|
// If we can't reach the target, but are standing ground, then abandon this attack order.
|
||||||
// Unless we're hunting, that's a special case where we should continue attacking our target.
|
// Unless we're hunting, that's a special case where we should continue attacking our target.
|
||||||
if (this.GetStance().respondStandGround && !this.order.data.force && !this.order.data.hunting || this.IsTurret())
|
if (this.GetStance().respondStandGround && !this.order.data.force && !this.order.data.hunting || !this.AbleToMove())
|
||||||
{
|
{
|
||||||
this.FinishOrder();
|
this.FinishOrder();
|
||||||
return;
|
return;
|
||||||
@ -477,7 +477,7 @@ UnitAI.prototype.UnitFsmSpec = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
"Order.Patrol": function(msg) {
|
"Order.Patrol": function(msg) {
|
||||||
if (this.IsAnimal() || this.IsTurret())
|
if (this.IsAnimal() || !this.AbleToMove())
|
||||||
{
|
{
|
||||||
this.FinishOrder();
|
this.FinishOrder();
|
||||||
return;
|
return;
|
||||||
@ -630,7 +630,7 @@ UnitAI.prototype.UnitFsmSpec = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
"Order.Garrison": function(msg) {
|
"Order.Garrison": function(msg) {
|
||||||
if (this.IsTurret())
|
if (!this.AbleToMove())
|
||||||
{
|
{
|
||||||
this.SetNextState("IDLE");
|
this.SetNextState("IDLE");
|
||||||
return;
|
return;
|
||||||
@ -3055,6 +3055,7 @@ UnitAI.prototype.UnitFsmSpec = {
|
|||||||
if (cmpGarrisonHolder.Garrison(this.entity))
|
if (cmpGarrisonHolder.Garrison(this.entity))
|
||||||
{
|
{
|
||||||
this.isGarrisoned = true;
|
this.isGarrisoned = true;
|
||||||
|
this.SetImmobile(true);
|
||||||
|
|
||||||
if (this.formationController)
|
if (this.formationController)
|
||||||
{
|
{
|
||||||
@ -3386,6 +3387,7 @@ UnitAI.prototype.Init = function()
|
|||||||
this.formationController = INVALID_ENTITY; // entity with IID_Formation that we belong to
|
this.formationController = INVALID_ENTITY; // entity with IID_Formation that we belong to
|
||||||
this.isGarrisoned = false;
|
this.isGarrisoned = false;
|
||||||
this.isIdle = false;
|
this.isIdle = false;
|
||||||
|
this.isImmobile = false; // True if the unit is currently unable to move (garrisoned,...)
|
||||||
this.finishedOrder = false; // used to find if all formation members finished the order
|
this.finishedOrder = false; // used to find if all formation members finished the order
|
||||||
|
|
||||||
this.heldPosition = undefined;
|
this.heldPosition = undefined;
|
||||||
@ -3485,6 +3487,30 @@ UnitAI.prototype.ShouldRespondToEndOfAlert = function()
|
|||||||
return !this.orderQueue.length || this.orderQueue[0].type == "Garrison";
|
return !this.orderQueue.length || this.orderQueue[0].type == "Garrison";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
UnitAI.prototype.SetImmobile = function(immobile)
|
||||||
|
{
|
||||||
|
this.isImmobile = immobile;
|
||||||
|
Engine.PostMessage(this.entity, MT_UnitAbleToMoveChanged, {
|
||||||
|
"entity": this.entity,
|
||||||
|
"ableToMove": this.AbleToMove()
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 (this.isImmobile || this.IsTurret())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!cmpUnitMotion)
|
||||||
|
cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
||||||
|
|
||||||
|
return !!cmpUnitMotion;
|
||||||
|
};
|
||||||
|
|
||||||
UnitAI.prototype.IsFleeing = function()
|
UnitAI.prototype.IsFleeing = function()
|
||||||
{
|
{
|
||||||
var state = this.GetCurrentState().split(".").pop();
|
var state = this.GetCurrentState().split(".").pop();
|
||||||
@ -3921,9 +3947,8 @@ UnitAI.prototype.WillMoveFromFoundation = function(target, checkPacking = true)
|
|||||||
// If foundation is not ally of entity, or if entity is unpacked siege,
|
// If foundation is not ally of entity, or if entity is unpacked siege,
|
||||||
// ignore the order.
|
// ignore the order.
|
||||||
if (!IsOwnedByAllyOfEntity(this.entity, target) &&
|
if (!IsOwnedByAllyOfEntity(this.entity, target) &&
|
||||||
!Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager).IsCeasefireActive() ||
|
!Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager).IsCeasefireActive() ||
|
||||||
checkPacking && this.IsPacking() ||
|
checkPacking && this.IsPacking() || this.CanPack() || !this.AbleToMove())
|
||||||
this.CanPack() || this.IsTurret())
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Move a tile outside the building.
|
// Move a tile outside the building.
|
||||||
@ -4513,13 +4538,13 @@ UnitAI.prototype.MoveTo = function(data, iid, type)
|
|||||||
UnitAI.prototype.MoveToPoint = function(x, z)
|
UnitAI.prototype.MoveToPoint = function(x, z)
|
||||||
{
|
{
|
||||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
||||||
return cmpUnitMotion && cmpUnitMotion.MoveToPointRange(x, z, 0, 0); // For point goals, allow a max range of 0.
|
return this.AbleToMove(cmpUnitMotion) && cmpUnitMotion.MoveToPointRange(x, z, 0, 0); // For point goals, allow a max range of 0.
|
||||||
};
|
};
|
||||||
|
|
||||||
UnitAI.prototype.MoveToPointRange = function(x, z, rangeMin, rangeMax)
|
UnitAI.prototype.MoveToPointRange = function(x, z, rangeMin, rangeMax)
|
||||||
{
|
{
|
||||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
||||||
return cmpUnitMotion && cmpUnitMotion.MoveToPointRange(x, z, rangeMin, rangeMax);
|
return this.AbleToMove(cmpUnitMotion) && cmpUnitMotion.MoveToPointRange(x, z, rangeMin, rangeMax);
|
||||||
};
|
};
|
||||||
|
|
||||||
UnitAI.prototype.MoveToTarget = function(target)
|
UnitAI.prototype.MoveToTarget = function(target)
|
||||||
@ -4528,12 +4553,12 @@ UnitAI.prototype.MoveToTarget = function(target)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
||||||
return cmpUnitMotion && cmpUnitMotion.MoveToTargetRange(target, 0, 1);
|
return this.AbleToMove(cmpUnitMotion) && cmpUnitMotion.MoveToTargetRange(target, 0, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
UnitAI.prototype.MoveToTargetRange = function(target, iid, type)
|
UnitAI.prototype.MoveToTargetRange = function(target, iid, type)
|
||||||
{
|
{
|
||||||
if (!this.CheckTargetVisible(target) || this.IsTurret())
|
if (!this.CheckTargetVisible(target))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
let range = this.GetRange(iid, type);
|
let range = this.GetRange(iid, type);
|
||||||
@ -4541,7 +4566,7 @@ UnitAI.prototype.MoveToTargetRange = function(target, iid, type)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
||||||
return cmpUnitMotion && cmpUnitMotion.MoveToTargetRange(target, range.min, range.max);
|
return this.AbleToMove(cmpUnitMotion) && cmpUnitMotion.MoveToTargetRange(target, range.min, range.max);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -4559,6 +4584,10 @@ UnitAI.prototype.MoveToTargetAttackRange = function(target, type)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
||||||
|
if (!this.AbleToMove(cmpUnitMotion))
|
||||||
|
return false;
|
||||||
|
|
||||||
let cmpFormation = Engine.QueryInterface(target, IID_Formation);
|
let cmpFormation = Engine.QueryInterface(target, IID_Formation);
|
||||||
if (cmpFormation)
|
if (cmpFormation)
|
||||||
target = cmpFormation.GetClosestMember(this.entity);
|
target = cmpFormation.GetClosestMember(this.entity);
|
||||||
@ -4595,7 +4624,6 @@ UnitAI.prototype.MoveToTargetAttackRange = function(target, type)
|
|||||||
// The parabole changes while walking so be cautious:
|
// The parabole changes while walking so be cautious:
|
||||||
let guessedMaxRange = parabolicMaxRange > range.max ? (range.max + parabolicMaxRange) / 2 : parabolicMaxRange;
|
let guessedMaxRange = parabolicMaxRange > range.max ? (range.max + parabolicMaxRange) / 2 : parabolicMaxRange;
|
||||||
|
|
||||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
|
||||||
return cmpUnitMotion && cmpUnitMotion.MoveToTargetRange(target, range.min, guessedMaxRange);
|
return cmpUnitMotion && cmpUnitMotion.MoveToTargetRange(target, range.min, guessedMaxRange);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -4605,7 +4633,7 @@ UnitAI.prototype.MoveToTargetRangeExplicit = function(target, min, max)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
||||||
return cmpUnitMotion && cmpUnitMotion.MoveToTargetRange(target, min, max);
|
return this.AbleToMove(cmpUnitMotion) && cmpUnitMotion.MoveToTargetRange(target, min, max);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -4620,7 +4648,7 @@ UnitAI.prototype.MoveFormationToTargetAttackRange = function(target)
|
|||||||
if (cmpTargetFormation)
|
if (cmpTargetFormation)
|
||||||
target = cmpTargetFormation.GetClosestMember(this.entity);
|
target = cmpTargetFormation.GetClosestMember(this.entity);
|
||||||
|
|
||||||
if (!this.CheckTargetVisible(target) || this.IsTurret())
|
if (!this.CheckTargetVisible(target))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
let cmpFormationAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
let cmpFormationAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||||
@ -4629,7 +4657,7 @@ UnitAI.prototype.MoveFormationToTargetAttackRange = function(target)
|
|||||||
let range = cmpFormationAttack.GetRange(target);
|
let range = cmpFormationAttack.GetRange(target);
|
||||||
|
|
||||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
||||||
return cmpUnitMotion && cmpUnitMotion.MoveToTargetRange(target, range.min, range.max);
|
return this.AbleToMove(cmpUnitMotion) && cmpUnitMotion.MoveToTargetRange(target, range.min, range.max);
|
||||||
};
|
};
|
||||||
|
|
||||||
UnitAI.prototype.MoveToGarrisonRange = function(target)
|
UnitAI.prototype.MoveToGarrisonRange = function(target)
|
||||||
@ -4643,7 +4671,7 @@ UnitAI.prototype.MoveToGarrisonRange = function(target)
|
|||||||
var range = cmpGarrisonHolder.GetLoadingRange();
|
var range = cmpGarrisonHolder.GetLoadingRange();
|
||||||
|
|
||||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
||||||
return cmpUnitMotion && cmpUnitMotion.MoveToTargetRange(target, range.min, range.max);
|
return this.AbleToMove(cmpUnitMotion) && cmpUnitMotion.MoveToTargetRange(target, range.min, range.max);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -5028,7 +5056,7 @@ UnitAI.prototype.ShouldAbandonChase = function(target, force, iid, type)
|
|||||||
*/
|
*/
|
||||||
UnitAI.prototype.ShouldChaseTargetedEntity = function(target, force)
|
UnitAI.prototype.ShouldChaseTargetedEntity = function(target, force)
|
||||||
{
|
{
|
||||||
if (this.IsTurret())
|
if (!this.AbleToMove())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (this.GetStance().respondChase)
|
if (this.GetStance().respondChase)
|
||||||
@ -5354,11 +5382,11 @@ UnitAI.prototype.LeaveFoundation = function(target)
|
|||||||
{
|
{
|
||||||
// If we're already being told to leave a foundation, then
|
// If we're already being told to leave a foundation, then
|
||||||
// ignore this new request so we don't end up being too indecisive
|
// ignore this new request so we don't end up being too indecisive
|
||||||
// to ever actually move anywhere
|
// 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)))
|
if (this.order && (this.order.type == "LeaveFoundation" || (this.order.type == "Flee" && this.order.data.target == target)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Ignore also the request if we are packing.
|
||||||
if (this.orderQueue.length && this.orderQueue[0].type == "Unpack" && this.WillMoveFromFoundation(target, false))
|
if (this.orderQueue.length && this.orderQueue[0].type == "Unpack" && this.WillMoveFromFoundation(target, false))
|
||||||
{
|
{
|
||||||
let cmpPack = Engine.QueryInterface(this.entity, IID_Pack);
|
let cmpPack = Engine.QueryInterface(this.entity, IID_Pack);
|
||||||
@ -5420,7 +5448,10 @@ UnitAI.prototype.Garrison = function(target, queued)
|
|||||||
UnitAI.prototype.Ungarrison = function()
|
UnitAI.prototype.Ungarrison = function()
|
||||||
{
|
{
|
||||||
if (this.IsGarrisoned())
|
if (this.IsGarrisoned())
|
||||||
|
{
|
||||||
|
this.SetImmobile(false);
|
||||||
this.AddOrder("Ungarrison", null, false);
|
this.AddOrder("Ungarrison", null, false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,6 +6,13 @@ Engine.RegisterInterface("UnitAI");
|
|||||||
*/
|
*/
|
||||||
Engine.RegisterMessageType("UnitIdleChanged");
|
Engine.RegisterMessageType("UnitIdleChanged");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message of the form { "ableToMove": boolean }
|
||||||
|
* sent from UnitAI whenever the unit's ability to move changes.
|
||||||
|
*/
|
||||||
|
Engine.RegisterMessageType("UnitAbleToMoveChanged");
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Message of the form { "to": string }
|
* Message of the form { "to": string }
|
||||||
* where "to" value is a UnitAI stance,
|
* where "to" value is a UnitAI stance,
|
||||||
|
@ -61,6 +61,7 @@ TestTargetEntityRenaming(
|
|||||||
(unitAI, player_ent, target_ent) => {
|
(unitAI, player_ent, target_ent) => {
|
||||||
unitAI.CanGarrison = (target) => target == target_ent;
|
unitAI.CanGarrison = (target) => target == target_ent;
|
||||||
unitAI.MoveToGarrisonRange = (target) => target == target_ent;
|
unitAI.MoveToGarrisonRange = (target) => target == target_ent;
|
||||||
|
unitAI.AbleToMove = () => true;
|
||||||
|
|
||||||
AddMock(target_ent, IID_GarrisonHolder, {
|
AddMock(target_ent, IID_GarrisonHolder, {
|
||||||
"CanPickup": () => false
|
"CanPickup": () => false
|
||||||
|
@ -651,6 +651,11 @@ public:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual std::vector<entity_id_t> GetEntitiesBlockingMovement() const
|
||||||
|
{
|
||||||
|
return GetEntitiesByFlags(ICmpObstructionManager::FLAG_BLOCK_MOVEMENT);
|
||||||
|
}
|
||||||
|
|
||||||
virtual std::vector<entity_id_t> GetEntitiesBlockingConstruction() const
|
virtual std::vector<entity_id_t> GetEntitiesBlockingConstruction() const
|
||||||
{
|
{
|
||||||
return GetEntitiesByFlags(ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION);
|
return GetEntitiesByFlags(ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION);
|
||||||
|
@ -50,6 +50,7 @@ DEFINE_INTERFACE_METHOD_CONST_0("GetUnitRadius", entity_pos_t, ICmpObstruction,
|
|||||||
DEFINE_INTERFACE_METHOD_CONST_0("CheckShorePlacement", bool, ICmpObstruction, CheckShorePlacement)
|
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_2("CheckFoundation", std::string, ICmpObstruction, CheckFoundation_wrapper, std::string, bool)
|
||||||
DEFINE_INTERFACE_METHOD_CONST_0("CheckDuplicateFoundation", bool, ICmpObstruction, CheckDuplicateFoundation)
|
DEFINE_INTERFACE_METHOD_CONST_0("CheckDuplicateFoundation", bool, ICmpObstruction, CheckDuplicateFoundation)
|
||||||
|
DEFINE_INTERFACE_METHOD_CONST_0("GetEntitiesBlockingMovement", std::vector<entity_id_t>, ICmpObstruction, GetEntitiesBlockingMovement)
|
||||||
DEFINE_INTERFACE_METHOD_CONST_0("GetEntitiesBlockingConstruction", std::vector<entity_id_t>, ICmpObstruction, GetEntitiesBlockingConstruction)
|
DEFINE_INTERFACE_METHOD_CONST_0("GetEntitiesBlockingConstruction", std::vector<entity_id_t>, ICmpObstruction, GetEntitiesBlockingConstruction)
|
||||||
DEFINE_INTERFACE_METHOD_CONST_0("GetEntitiesDeletedUponConstruction", std::vector<entity_id_t>, ICmpObstruction, GetEntitiesDeletedUponConstruction)
|
DEFINE_INTERFACE_METHOD_CONST_0("GetEntitiesDeletedUponConstruction", std::vector<entity_id_t>, ICmpObstruction, GetEntitiesDeletedUponConstruction)
|
||||||
DEFINE_INTERFACE_METHOD_1("SetActive", void, ICmpObstruction, SetActive, bool)
|
DEFINE_INTERFACE_METHOD_1("SetActive", void, ICmpObstruction, SetActive, bool)
|
||||||
|
@ -104,6 +104,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual std::vector<entity_id_t> GetEntitiesByFlags(ICmpObstructionManager::flags_t flags) const = 0;
|
virtual std::vector<entity_id_t> GetEntitiesByFlags(ICmpObstructionManager::flags_t flags) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of entities that are blocking movement.
|
||||||
|
* @return vector of blocking entities
|
||||||
|
*/
|
||||||
|
virtual std::vector<entity_id_t> GetEntitiesBlockingMovement() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of entities that are blocking construction of a foundation.
|
* Returns a list of entities that are blocking construction of a foundation.
|
||||||
* @return vector of blocking entities
|
* @return vector of blocking entities
|
||||||
|
@ -41,6 +41,7 @@ public:
|
|||||||
virtual std::string CheckFoundation_wrapper(const std::string& UNUSED(className), bool UNUSED(onlyCenterPoint)) const { return std::string(); }
|
virtual std::string CheckFoundation_wrapper(const std::string& UNUSED(className), bool UNUSED(onlyCenterPoint)) const { return std::string(); }
|
||||||
virtual bool CheckDuplicateFoundation() const { return true; }
|
virtual bool CheckDuplicateFoundation() const { return true; }
|
||||||
virtual std::vector<entity_id_t> GetEntitiesByFlags(ICmpObstructionManager::flags_t UNUSED(flags)) const { return std::vector<entity_id_t>(); }
|
virtual std::vector<entity_id_t> GetEntitiesByFlags(ICmpObstructionManager::flags_t UNUSED(flags)) const { return std::vector<entity_id_t>(); }
|
||||||
|
virtual std::vector<entity_id_t> GetEntitiesBlockingMovement() const { return std::vector<entity_id_t>(); }
|
||||||
virtual std::vector<entity_id_t> GetEntitiesBlockingConstruction() const { return std::vector<entity_id_t>(); }
|
virtual std::vector<entity_id_t> GetEntitiesBlockingConstruction() const { return std::vector<entity_id_t>(); }
|
||||||
virtual std::vector<entity_id_t> GetEntitiesDeletedUponConstruction() const { return std::vector<entity_id_t>(); }
|
virtual std::vector<entity_id_t> GetEntitiesDeletedUponConstruction() const { return std::vector<entity_id_t>(); }
|
||||||
virtual void ResolveFoundationCollisions() const { }
|
virtual void ResolveFoundationCollisions() const { }
|
||||||
|
Loading…
Reference in New Issue
Block a user