diff --git a/source/simulation2/components/CCmpRangeManager.cpp b/source/simulation2/components/CCmpRangeManager.cpp index 6cbcb9d9ad..3d0ddf5dd1 100644 --- a/source/simulation2/components/CCmpRangeManager.cpp +++ b/source/simulation2/components/CCmpRangeManager.cpp @@ -1379,7 +1379,12 @@ public: if (!cmpTargetPosition || !cmpTargetPosition->IsInWorld()) return NEVER_IN_RANGE; - entity_pos_t heightDifference = cmpSourcePosition->GetHeightOffset() - cmpTargetPosition->GetHeightOffset() + yOrigin; + // GetPosition() returns the world height (terrain + water + offset) + CFixedVector3D sourcePos = cmpSourcePosition->GetPosition(); + CFixedVector3D targetPos = cmpTargetPosition->GetPosition(); + + entity_pos_t heightDifference = sourcePos.Y - targetPos.Y + yOrigin; + if (heightDifference < -range / 2) return NEVER_IN_RANGE; diff --git a/source/simulation2/components/tests/test_RangeManager.h b/source/simulation2/components/tests/test_RangeManager.h index 30fc69720d..b4f06d0535 100644 --- a/source/simulation2/components/tests/test_RangeManager.h +++ b/source/simulation2/components/tests/test_RangeManager.h @@ -62,13 +62,13 @@ public: entity_id_t GetTurretParent() const override {return INVALID_ENTITY;} void UpdateTurretPosition() override {} std::set* GetTurrets() override { return nullptr; } - bool IsInWorld() const override { return true; } - void MoveOutOfWorld() override { } + bool IsInWorld() const override { return m_InWorld; } + void MoveOutOfWorld() override { m_InWorld = false; } void MoveTo(entity_pos_t /*x*/, entity_pos_t /*z*/) override { } void MoveAndTurnTo(entity_pos_t /*x*/, entity_pos_t /*z*/, entity_angle_t /*a*/) override { } void JumpTo(entity_pos_t /*x*/, entity_pos_t /*z*/) override { } - void SetHeightOffset(entity_pos_t /*dy*/) override { } - entity_pos_t GetHeightOffset() const override { return entity_pos_t::Zero(); } + void SetHeightOffset(entity_pos_t dy) override { m_HeightOffset = dy; } + entity_pos_t GetHeightOffset() const override { return m_HeightOffset; } void SetHeightFixed(entity_pos_t /*y*/) override { } entity_pos_t GetHeightFixed() const override { return entity_pos_t::Zero(); } entity_pos_t GetHeightAtFixed(entity_pos_t, entity_pos_t) const override { return entity_pos_t::Zero(); } @@ -93,6 +93,8 @@ public: CMatrix3D GetInterpolatedTransform(float /*frameOffset*/) const override { return CMatrix3D(); } CFixedVector3D m_Pos; + entity_pos_t m_HeightOffset = entity_pos_t::Zero(); + bool m_InWorld = true; }; class MockObstructionRgm : public ICmpObstruction @@ -290,14 +292,15 @@ public: } - void test_IsInTargetParabolicRange() + void test_ParabolicRangeBasic() { ComponentTestHelper test(*g_ScriptContext); ICmpRangeManager* cmp = test.Add(CID_RangeManager, "", SYSTEM_ENTITY); + const entity_id_t source = 200; const entity_id_t target = 201; - entity_pos_t range = fixed::FromInt(-3); - entity_pos_t yOrigin = fixed::FromInt(-20); + entity_pos_t range{fixed::FromInt(-3)}; + entity_pos_t yOrigin{fixed::FromInt(-20)}; // Invalid range. TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, range, yOrigin), range); @@ -322,7 +325,7 @@ public: TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, range, yOrigin), range); TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, fixed::Zero(), yOrigin), fixed::Zero()); - // Normal case. + // Normal case with yOrigin only (no terrain difference) yOrigin = fixed::FromInt(5); range = fixed::FromInt(10); TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, range, yOrigin), fixed::FromFloat(14.142136f));