Fix target height computation when launching projectiles.

The Y coordinate at which to fire a projectile is currently assumed to
be the target's current Y, which is incorrect if the target is moving on
a slope.
This fixes that.

Note that this was purely visual, since projectiles still hit the target
regardless, as the height component is totally ignored, even if the
projectile is underground (in fact, the projectile's position is not
known in DelayedDamage::MissileHit, which just assumes it lands where it
said it would when fired).

As noted by bb in f737831167

Fixes #5939

Differential Revision: https://code.wildfiregames.com/D3425
This was SVN commit r24766.
This commit is contained in:
wraitii
2021-01-22 18:16:13 +00:00
parent 6b05cc9d3c
commit d92feab275
6 changed files with 21 additions and 6 deletions
@@ -560,6 +560,8 @@ Attack.prototype.PerformAttack = function(type, target)
predictedPosition = Vector3D.mult(targetVelocity, timeToTarget).add(targetPosition);
}
let predictedHeight = cmpTargetPosition.GetHeightAt(predictedPosition.x, predictedPosition.z);
// Add inaccuracy based on spread.
let distanceModifiedSpread = ApplyValueModificationsToEntity("Attack/Ranged/Spread", +this.template[type].Projectile.Spread, this.entity) *
predictedPosition.horizDistanceTo(selfPosition) / 100;
@@ -568,7 +570,7 @@ Attack.prototype.PerformAttack = function(type, target)
let offsetX = randNorm[0] * distanceModifiedSpread;
let offsetZ = randNorm[1] * distanceModifiedSpread;
let realTargetPosition = new Vector3D(predictedPosition.x + offsetX, targetPosition.y, predictedPosition.z + offsetZ);
let realTargetPosition = new Vector3D(predictedPosition.x + offsetX, predictedHeight, predictedPosition.z + offsetZ);
// Recalculate when the missile will hit the target position.
let realHorizDistance = realTargetPosition.horizDistanceTo(selfPosition);
@@ -95,6 +95,7 @@ function Test_Generic()
"GetPosition": () => targetPos,
"GetPreviousPosition": () => targetPos,
"GetPosition2D": () => Vector2D.From(targetPos),
"GetHeightAt": () => 0,
"IsInWorld": () => true,
});
@@ -439,6 +439,11 @@ public:
}
virtual entity_pos_t GetHeightFixed() const
{
return GetHeightAtFixed(m_X, m_Z);
}
virtual entity_pos_t GetHeightAtFixed(entity_pos_t x, entity_pos_t z) const
{
if (!m_RelativeToGround)
return m_Y;
@@ -447,13 +452,13 @@ public:
entity_pos_t baseY;
CmpPtr<ICmpTerrain> cmpTerrain(GetSystemEntity());
if (cmpTerrain)
baseY = cmpTerrain->GetGroundLevel(m_X, m_Z);
baseY = cmpTerrain->GetGroundLevel(x, z);
if (m_Floating)
{
CmpPtr<ICmpWaterManager> cmpWaterManager(GetSystemEntity());
if (cmpWaterManager)
baseY = std::max(baseY, cmpWaterManager->GetWaterLevel(m_X, m_Z) - m_FloatDepth);
baseY = std::max(baseY, cmpWaterManager->GetWaterLevel(x, z) - m_FloatDepth);
}
return m_Y + baseY;
}
@@ -525,7 +530,7 @@ public:
return CFixedVector3D();
}
return CFixedVector3D(m_PrevX, GetHeightFixed(), m_PrevZ);
return CFixedVector3D(m_PrevX, GetHeightAtFixed(m_PrevX, m_PrevZ), m_PrevZ);
}
virtual CFixedVector2D GetPreviousPosition2D() const
@@ -32,7 +32,7 @@ DEFINE_INTERFACE_METHOD_2("JumpTo", void, ICmpPosition, JumpTo, entity_pos_t, en
DEFINE_INTERFACE_METHOD_1("SetHeightOffset", void, ICmpPosition, SetHeightOffset, entity_pos_t)
DEFINE_INTERFACE_METHOD_CONST_0("GetHeightOffset", entity_pos_t, ICmpPosition, GetHeightOffset)
DEFINE_INTERFACE_METHOD_1("SetHeightFixed", void, ICmpPosition, SetHeightFixed, entity_pos_t)
DEFINE_INTERFACE_METHOD_CONST_0("GetHeightFixed", entity_pos_t, ICmpPosition, GetHeightFixed)
DEFINE_INTERFACE_METHOD_CONST_2("GetHeightAt", entity_pos_t, ICmpPosition, GetHeightAtFixed, entity_pos_t, entity_pos_t)
DEFINE_INTERFACE_METHOD_CONST_0("IsHeightRelative", bool, ICmpPosition, IsHeightRelative)
DEFINE_INTERFACE_METHOD_1("SetHeightRelative", void, ICmpPosition, SetHeightRelative, bool)
DEFINE_INTERFACE_METHOD_CONST_0("CanFloat", bool, ICmpPosition, CanFloat)
+7 -1
View File
@@ -121,10 +121,16 @@ public:
virtual void SetHeightFixed(entity_pos_t y) = 0;
/**
* Returns the vertical offset above the map zero point
* Returns the current vertical offset above above the map zero point.
*/
virtual entity_pos_t GetHeightFixed() const = 0;
/**
* Returns the vertical offset above above the map zero point
* the unit would have at the given position.
*/
virtual entity_pos_t GetHeightAtFixed(entity_pos_t x, entity_pos_t z) const = 0;
/**
* Returns true iff the entity will follow the terrain height (possibly with an offset)
*/
@@ -52,6 +52,7 @@ public:
virtual entity_pos_t GetHeightOffset() const { return entity_pos_t::Zero(); }
virtual void SetHeightFixed(entity_pos_t UNUSED(y)) { }
virtual entity_pos_t GetHeightFixed() const { return entity_pos_t::Zero(); }
virtual entity_pos_t GetHeightAtFixed(entity_pos_t, entity_pos_t) const { return entity_pos_t::Zero(); }
virtual bool IsHeightRelative() const { return true; }
virtual void SetHeightRelative(bool UNUSED(relative)) { }
virtual bool CanFloat() const { return false; }