Ensure units do get in attacking range since that range can change over time because of elevation differences.
This is a partial revert of4fda917f46
, which skipped the "MoveToTargetAttackingRange" in APPROACHING. I (incorrectly) assumed that the original order was still perfectly fine, but in fact the attacker's max range may have changed as that depends on the relative elevation between attack and target - and so the original order might never get us in range! This was introduced originally in8c74df2acd
. Add a comment to clarify this. Further, this makes sure UnitMotion still is aware that it has a target even if it is in range from the beginning, as that could lead to stuckiness (and did when chasing sometimes). This was done in D1984 anyways. Fixes #5478. Differential Revision: https://code.wildfiregames.com/D2035 This was SVN commit r22429.
This commit is contained in:
parent
8a38cfb7cf
commit
f990cd2381
@ -1797,7 +1797,13 @@ UnitAI.prototype.UnitFsmSpec = {
|
||||
}
|
||||
|
||||
if (!this.CheckTargetAttackRange(this.order.data.target, this.order.data.attackType))
|
||||
{
|
||||
// Try moving again,
|
||||
// attack range uses a height-related formula and our actual max range might have changed.
|
||||
if (!this.MoveToTargetAttackRange(this.order.data.target, this.order.data.attackType))
|
||||
this.FinishOrder();
|
||||
return;
|
||||
}
|
||||
|
||||
// If the unit needs to unpack, do so
|
||||
if (this.CanUnpack())
|
||||
@ -4200,12 +4206,12 @@ UnitAI.prototype.MoveToTargetAttackRange = function(target, type)
|
||||
// for formation members, the formation will take care of the range check
|
||||
if (this.IsFormationMember())
|
||||
{
|
||||
var cmpFormationUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI);
|
||||
let cmpFormationUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI);
|
||||
if (cmpFormationUnitAI && cmpFormationUnitAI.IsAttackingAsFormation())
|
||||
return false;
|
||||
}
|
||||
|
||||
var cmpFormation = Engine.QueryInterface(target, IID_Formation);
|
||||
let cmpFormation = Engine.QueryInterface(target, IID_Formation);
|
||||
if (cmpFormation)
|
||||
target = cmpFormation.GetClosestMember(this.entity);
|
||||
|
||||
@ -4215,39 +4221,33 @@ UnitAI.prototype.MoveToTargetAttackRange = function(target, type)
|
||||
if (!this.CheckTargetVisible(target))
|
||||
return false;
|
||||
|
||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||
var range = cmpAttack.GetRange(type);
|
||||
let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||
let range = cmpAttack.GetRange(type);
|
||||
|
||||
var thisCmpPosition = Engine.QueryInterface(this.entity, IID_Position);
|
||||
let thisCmpPosition = Engine.QueryInterface(this.entity, IID_Position);
|
||||
if (!thisCmpPosition.IsInWorld())
|
||||
return false;
|
||||
var s = thisCmpPosition.GetPosition();
|
||||
let s = thisCmpPosition.GetPosition();
|
||||
|
||||
var targetCmpPosition = Engine.QueryInterface(target, IID_Position);
|
||||
let targetCmpPosition = Engine.QueryInterface(target, IID_Position);
|
||||
if (!targetCmpPosition.IsInWorld())
|
||||
return false;
|
||||
|
||||
var t = targetCmpPosition.GetPosition();
|
||||
let t = targetCmpPosition.GetPosition();
|
||||
// h is positive when I'm higher than the target
|
||||
var h = s.y-t.y+range.elevationBonus;
|
||||
let h = s.y - t.y + range.elevationBonus;
|
||||
|
||||
let parabolicMaxRange = Math.sqrt(Math.square(range.max) + 2 * range.max * h);
|
||||
// No negative roots please
|
||||
if (h>-range.max/2)
|
||||
var parabolicMaxRange = Math.sqrt(Math.square(range.max) + 2 * range.max * h);
|
||||
else
|
||||
if (h <= -range.max / 2)
|
||||
// return false? Or hope you come close enough?
|
||||
var parabolicMaxRange = 0;
|
||||
//return false;
|
||||
parabolicMaxRange = 0;
|
||||
|
||||
// the parabole changes while walking, take something in the middle
|
||||
var guessedMaxRange = (range.max + parabolicMaxRange)/2;
|
||||
// The parabole changes while walking so be cautious:
|
||||
let guessedMaxRange = parabolicMaxRange > range.max ? (range.max + parabolicMaxRange) / 2 : parabolicMaxRange;
|
||||
|
||||
var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
||||
if (cmpUnitMotion.MoveToTargetRange(target, range.min, guessedMaxRange))
|
||||
return true;
|
||||
|
||||
// if that failed, try closer
|
||||
return cmpUnitMotion.MoveToTargetRange(target, range.min, Math.min(range.max, parabolicMaxRange));
|
||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
||||
return cmpUnitMotion.MoveToTargetRange(target, range.min, guessedMaxRange);
|
||||
};
|
||||
|
||||
UnitAI.prototype.MoveToTargetRangeExplicit = function(target, min, max)
|
||||
@ -4323,42 +4323,42 @@ UnitAI.prototype.CheckTargetAttackRange = function(target, type)
|
||||
// for formation members, the formation will take care of the range check
|
||||
if (this.IsFormationMember())
|
||||
{
|
||||
var cmpFormationUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI);
|
||||
if (cmpFormationUnitAI && cmpFormationUnitAI.IsAttackingAsFormation()
|
||||
&& cmpFormationUnitAI.order.data.target == target)
|
||||
let cmpFormationUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI);
|
||||
if (cmpFormationUnitAI && cmpFormationUnitAI.IsAttackingAsFormation() &&
|
||||
cmpFormationUnitAI.order.data.target == target)
|
||||
return true;
|
||||
}
|
||||
|
||||
var cmpFormation = Engine.QueryInterface(target, IID_Formation);
|
||||
let cmpFormation = Engine.QueryInterface(target, IID_Formation);
|
||||
if (cmpFormation)
|
||||
target = cmpFormation.GetClosestMember(this.entity);
|
||||
|
||||
if (type != "Ranged")
|
||||
return this.CheckTargetRange(target, IID_Attack, type);
|
||||
|
||||
var targetCmpPosition = Engine.QueryInterface(target, IID_Position);
|
||||
let targetCmpPosition = Engine.QueryInterface(target, IID_Position);
|
||||
if (!targetCmpPosition || !targetCmpPosition.IsInWorld())
|
||||
return false;
|
||||
|
||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||
var range = cmpAttack.GetRange(type);
|
||||
let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||
let range = cmpAttack.GetRange(type);
|
||||
|
||||
var thisCmpPosition = Engine.QueryInterface(this.entity, IID_Position);
|
||||
let thisCmpPosition = Engine.QueryInterface(this.entity, IID_Position);
|
||||
if (!thisCmpPosition.IsInWorld())
|
||||
return false;
|
||||
|
||||
var s = thisCmpPosition.GetPosition();
|
||||
let s = thisCmpPosition.GetPosition();
|
||||
|
||||
var t = targetCmpPosition.GetPosition();
|
||||
let t = targetCmpPosition.GetPosition();
|
||||
|
||||
var h = s.y-t.y+range.elevationBonus;
|
||||
var maxRangeSq = 2*range.max*(h + range.max/2);
|
||||
let h = s.y - t.y + range.elevationBonus;
|
||||
let maxRange = Math.sqrt(Math.square(range.max) + 2 * range.max * h);
|
||||
|
||||
if (maxRangeSq < 0)
|
||||
if (maxRange < 0)
|
||||
return false;
|
||||
|
||||
let cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager);
|
||||
return cmpObstructionManager.IsInTargetRange(this.entity, target, range.min, Math.sqrt(maxRangeSq), false);
|
||||
return cmpObstructionManager.IsInTargetRange(this.entity, target, range.min, maxRange, false);
|
||||
};
|
||||
|
||||
UnitAI.prototype.CheckTargetRangeExplicit = function(target, min, max)
|
||||
|
@ -1401,13 +1401,6 @@ bool CCmpUnitMotion::MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos
|
||||
if (goal.hw <= entity_pos_t::Zero())
|
||||
goal.type = PathGoal::POINT;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're already in range - no need to move anywhere
|
||||
if (m_FacePointAfterMove)
|
||||
FaceTowardsPointFromPos(pos, x, z);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
m_State = STATE_INDIVIDUAL_PATH;
|
||||
@ -1527,12 +1520,6 @@ bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange
|
||||
goal.hh = obstruction.hh + goalDistance;
|
||||
}
|
||||
}
|
||||
else if (maxRange < entity_pos_t::Zero() || distance < maxRange || previousDistance < maxRange)
|
||||
{
|
||||
// We're already in range - no need to move anywhere
|
||||
FaceTowardsPointFromPos(pos, goal.x, goal.z);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We might need to move closer:
|
||||
@ -1550,14 +1537,6 @@ bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange
|
||||
entity_pos_t circleDistance = (pos - CFixedVector2D(obstruction.x, obstruction.z)).Length() - circleRadius;
|
||||
entity_pos_t previousCircleDistance = (pos - CFixedVector2D(previousObstruction.x, previousObstruction.z)).Length() - circleRadius;
|
||||
|
||||
if (circleDistance < maxRange || previousCircleDistance < maxRange)
|
||||
{
|
||||
// We're already in range - no need to move anywhere
|
||||
if (m_FacePointAfterMove)
|
||||
FaceTowardsPointFromPos(pos, goal.x, goal.z);
|
||||
return true;
|
||||
}
|
||||
|
||||
entity_pos_t goalDistance = maxRange;
|
||||
|
||||
goal.type = PathGoal::CIRCLE;
|
||||
|
Loading…
Reference in New Issue
Block a user