Index: ps/trunk/binaries/data/mods/public/simulation/components/Attack.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/Attack.js +++ ps/trunk/binaries/data/mods/public/simulation/components/Attack.js @@ -560,6 +560,8 @@ 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 @@ 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); Index: ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js +++ ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js @@ -95,6 +95,7 @@ "GetPosition": () => targetPos, "GetPreviousPosition": () => targetPos, "GetPosition2D": () => Vector2D.From(targetPos), + "GetHeightAt": () => 0, "IsInWorld": () => true, }); Index: ps/trunk/source/simulation2/components/CCmpPosition.cpp =================================================================== --- ps/trunk/source/simulation2/components/CCmpPosition.cpp +++ ps/trunk/source/simulation2/components/CCmpPosition.cpp @@ -440,6 +440,11 @@ 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; // relative to the ground, so the fixed height = ground height + m_Y @@ -447,13 +452,13 @@ 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 @@ return CFixedVector3D(); } - return CFixedVector3D(m_PrevX, GetHeightFixed(), m_PrevZ); + return CFixedVector3D(m_PrevX, GetHeightAtFixed(m_PrevX, m_PrevZ), m_PrevZ); } virtual CFixedVector2D GetPreviousPosition2D() const Index: ps/trunk/source/simulation2/components/ICmpPosition.h =================================================================== --- ps/trunk/source/simulation2/components/ICmpPosition.h +++ ps/trunk/source/simulation2/components/ICmpPosition.h @@ -121,11 +121,17 @@ 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) */ virtual bool IsHeightRelative() const = 0; Index: ps/trunk/source/simulation2/components/ICmpPosition.cpp =================================================================== --- ps/trunk/source/simulation2/components/ICmpPosition.cpp +++ ps/trunk/source/simulation2/components/ICmpPosition.cpp @@ -32,7 +32,7 @@ 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) Index: ps/trunk/source/simulation2/components/tests/test_RangeManager.h =================================================================== --- ps/trunk/source/simulation2/components/tests/test_RangeManager.h +++ ps/trunk/source/simulation2/components/tests/test_RangeManager.h @@ -52,6 +52,7 @@ 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; }