mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-08-15 14:43:32 -07:00
Fix terrain elevation not affecting attack range
The parabolic range formula in GetEffectiveParabolicRange was only computating height differences from manual HeightOffset values, completely ignoring actual terrain elevation. This meant units on hills received no tactical advantage despite the UI stat tooltip correctly showing extended ranges. Fixes #8889
This commit is contained in:
parent
0123a28018
commit
438f874292
2 changed files with 17 additions and 9 deletions
|
|
@ -1408,7 +1408,12 @@ public:
|
||||||
if (!cmpTargetPosition || !cmpTargetPosition->IsInWorld())
|
if (!cmpTargetPosition || !cmpTargetPosition->IsInWorld())
|
||||||
return NEVER_IN_RANGE;
|
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)
|
if (heightDifference < -range / 2)
|
||||||
return NEVER_IN_RANGE;
|
return NEVER_IN_RANGE;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,13 +63,13 @@ public:
|
||||||
entity_id_t GetTurretParent() const override {return INVALID_ENTITY;}
|
entity_id_t GetTurretParent() const override {return INVALID_ENTITY;}
|
||||||
void UpdateTurretPosition() override {}
|
void UpdateTurretPosition() override {}
|
||||||
std::set<entity_id_t>* GetTurrets() override { return nullptr; }
|
std::set<entity_id_t>* GetTurrets() override { return nullptr; }
|
||||||
bool IsInWorld() const override { return true; }
|
bool IsInWorld() const override { return m_InWorld; }
|
||||||
void MoveOutOfWorld() override { }
|
void MoveOutOfWorld() override { m_InWorld = false; }
|
||||||
void MoveTo(entity_pos_t /*x*/, entity_pos_t /*z*/) override { }
|
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 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 JumpTo(entity_pos_t /*x*/, entity_pos_t /*z*/) override { }
|
||||||
void SetHeightOffset(entity_pos_t /*dy*/) override { }
|
void SetHeightOffset(entity_pos_t dy) override { m_HeightOffset = dy; }
|
||||||
entity_pos_t GetHeightOffset() const override { return entity_pos_t::Zero(); }
|
entity_pos_t GetHeightOffset() const override { return m_HeightOffset; }
|
||||||
void SetHeightFixed(entity_pos_t /*y*/) override { }
|
void SetHeightFixed(entity_pos_t /*y*/) override { }
|
||||||
entity_pos_t GetHeightFixed() const override { return entity_pos_t::Zero(); }
|
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(); }
|
entity_pos_t GetHeightAtFixed(entity_pos_t, entity_pos_t) const override { return entity_pos_t::Zero(); }
|
||||||
|
|
@ -94,6 +94,8 @@ public:
|
||||||
CMatrix3D GetInterpolatedTransform(float /*frameOffset*/) const override { return CMatrix3D(); }
|
CMatrix3D GetInterpolatedTransform(float /*frameOffset*/) const override { return CMatrix3D(); }
|
||||||
|
|
||||||
CFixedVector3D m_Pos;
|
CFixedVector3D m_Pos;
|
||||||
|
entity_pos_t m_HeightOffset = entity_pos_t::Zero();
|
||||||
|
bool m_InWorld = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MockObstructionRgm : public ICmpObstruction
|
class MockObstructionRgm : public ICmpObstruction
|
||||||
|
|
@ -291,14 +293,15 @@ public:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_IsInTargetParabolicRange()
|
void test_ParabolicRangeBasic()
|
||||||
{
|
{
|
||||||
ComponentTestHelper test(*g_ScriptContext);
|
ComponentTestHelper test(*g_ScriptContext);
|
||||||
ICmpRangeManager* cmp = test.Add<ICmpRangeManager>(CID_RangeManager, "", SYSTEM_ENTITY);
|
ICmpRangeManager* cmp = test.Add<ICmpRangeManager>(CID_RangeManager, "", SYSTEM_ENTITY);
|
||||||
|
|
||||||
const entity_id_t source = 200;
|
const entity_id_t source = 200;
|
||||||
const entity_id_t target = 201;
|
const entity_id_t target = 201;
|
||||||
entity_pos_t range = fixed::FromInt(-3);
|
entity_pos_t range{fixed::FromInt(-3)};
|
||||||
entity_pos_t yOrigin = fixed::FromInt(-20);
|
entity_pos_t yOrigin{fixed::FromInt(-20)};
|
||||||
|
|
||||||
// Invalid range.
|
// Invalid range.
|
||||||
TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, range, yOrigin), range);
|
TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, range, yOrigin), range);
|
||||||
|
|
@ -323,7 +326,7 @@ public:
|
||||||
TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, range, yOrigin), range);
|
TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, range, yOrigin), range);
|
||||||
TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, fixed::Zero(), yOrigin), fixed::Zero());
|
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);
|
yOrigin = fixed::FromInt(5);
|
||||||
range = fixed::FromInt(10);
|
range = fixed::FromInt(10);
|
||||||
TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, range, yOrigin), fixed::FromFloat(14.142136f));
|
TS_ASSERT_EQUALS(cmp->GetEffectiveParabolicRange(source, target, range, yOrigin), fixed::FromFloat(14.142136f));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue