From d92feab275cf4b2d44cc650ae186fb64cc5f0cd3 Mon Sep 17 00:00:00 2001 From: wraitii Date: Fri, 22 Jan 2021 18:16:13 +0000 Subject: [PATCH] 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. --- .../data/mods/public/simulation/components/Attack.js | 4 +++- .../public/simulation/components/tests/test_Damage.js | 1 + source/simulation2/components/CCmpPosition.cpp | 11 ++++++++--- source/simulation2/components/ICmpPosition.cpp | 2 +- source/simulation2/components/ICmpPosition.h | 8 +++++++- .../simulation2/components/tests/test_RangeManager.h | 1 + 6 files changed, 21 insertions(+), 6 deletions(-) diff --git a/binaries/data/mods/public/simulation/components/Attack.js b/binaries/data/mods/public/simulation/components/Attack.js index 3102a8d84d..9e25dc498f 100644 --- a/binaries/data/mods/public/simulation/components/Attack.js +++ b/binaries/data/mods/public/simulation/components/Attack.js @@ -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); diff --git a/binaries/data/mods/public/simulation/components/tests/test_Damage.js b/binaries/data/mods/public/simulation/components/tests/test_Damage.js index 3dbfb30e78..cc2a6c0653 100644 --- a/binaries/data/mods/public/simulation/components/tests/test_Damage.js +++ b/binaries/data/mods/public/simulation/components/tests/test_Damage.js @@ -95,6 +95,7 @@ function Test_Generic() "GetPosition": () => targetPos, "GetPreviousPosition": () => targetPos, "GetPosition2D": () => Vector2D.From(targetPos), + "GetHeightAt": () => 0, "IsInWorld": () => true, }); diff --git a/source/simulation2/components/CCmpPosition.cpp b/source/simulation2/components/CCmpPosition.cpp index c4cad8912d..56e71bc9e0 100644 --- a/source/simulation2/components/CCmpPosition.cpp +++ b/source/simulation2/components/CCmpPosition.cpp @@ -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 cmpTerrain(GetSystemEntity()); if (cmpTerrain) - baseY = cmpTerrain->GetGroundLevel(m_X, m_Z); + baseY = cmpTerrain->GetGroundLevel(x, z); if (m_Floating) { CmpPtr 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 diff --git a/source/simulation2/components/ICmpPosition.cpp b/source/simulation2/components/ICmpPosition.cpp index 86ed2989f9..7523b606d7 100644 --- a/source/simulation2/components/ICmpPosition.cpp +++ b/source/simulation2/components/ICmpPosition.cpp @@ -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) diff --git a/source/simulation2/components/ICmpPosition.h b/source/simulation2/components/ICmpPosition.h index 0cc5505c87..3ed1337a2b 100644 --- a/source/simulation2/components/ICmpPosition.h +++ b/source/simulation2/components/ICmpPosition.h @@ -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) */ diff --git a/source/simulation2/components/tests/test_RangeManager.h b/source/simulation2/components/tests/test_RangeManager.h index e636afcdcf..5bd3fc9a7a 100644 --- a/source/simulation2/components/tests/test_RangeManager.h +++ b/source/simulation2/components/tests/test_RangeManager.h @@ -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; }