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; }