mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Add tests for CanEverReachTarget and its helpers
This commit is contained in:
parent
a19b8b8b50
commit
626c91e02b
5 changed files with 178 additions and 3 deletions
|
|
@ -429,3 +429,100 @@ function testAttackPreference()
|
|||
}
|
||||
testAttackPreference();
|
||||
|
||||
function testCanEverReachTarget()
|
||||
{
|
||||
const attacker = ++entityID;
|
||||
|
||||
AddMock(attacker, IID_Position, {
|
||||
"IsInWorld": () => true,
|
||||
"GetHeightOffset": () => 0,
|
||||
"GetPosition2D": () => new Vector2D(1, 2)
|
||||
});
|
||||
|
||||
const cmpAttack = ConstructComponent(attacker, "Attack", {
|
||||
"Melee": {
|
||||
"Damage": { "Hack": 10, "Pierce": 0, "Crush": 0 },
|
||||
"MaxRange": 5
|
||||
},
|
||||
"Ranged": {
|
||||
"Damage": { "Hack": 0, "Pierce": 10, "Crush": 0 },
|
||||
"MaxRange": 30,
|
||||
"Projectile": { "Speed": 50, "Spread": 1, "Gravity": 1, "FriendlyFire": "false" }
|
||||
}
|
||||
});
|
||||
|
||||
// Melee target within 3D range
|
||||
{
|
||||
const defender = ++entityID;
|
||||
AddMock(defender, IID_Position, {
|
||||
"IsInWorld": () => true,
|
||||
"GetHeightOffset": () => 0
|
||||
});
|
||||
TS_ASSERT_EQUALS(cmpAttack.CanEverReachTarget(defender, "Melee"), true);
|
||||
}
|
||||
|
||||
// Melee target too high
|
||||
{
|
||||
const defender = ++entityID;
|
||||
AddMock(defender, IID_Position, {
|
||||
"IsInWorld": () => true,
|
||||
"GetHeightOffset": () => 10
|
||||
});
|
||||
TS_ASSERT_EQUALS(cmpAttack.CanEverReachTarget(defender, "Melee"), false);
|
||||
}
|
||||
|
||||
// Melee target at same height, within range (close distance)
|
||||
{
|
||||
const defender = ++entityID;
|
||||
AddMock(defender, IID_Position, {
|
||||
"IsInWorld": () => true,
|
||||
"GetHeightOffset": () => 4
|
||||
});
|
||||
// sqrt(0² + 4²) = 4 <= 5
|
||||
TS_ASSERT_EQUALS(cmpAttack.CanEverReachTarget(defender, "Melee"), true);
|
||||
}
|
||||
|
||||
// Ranged: target at same height — reachable from current position (check 1)
|
||||
{
|
||||
const defender = ++entityID;
|
||||
AddMock(defender, IID_Position, {
|
||||
"IsInWorld": () => true,
|
||||
"GetHeightOffset": () => 0,
|
||||
"GetPosition": () => new Vector3D(1, 0, 2)
|
||||
});
|
||||
// Need RangeManager mock for IsTargetInRange (check 1) to work
|
||||
AddMock(SYSTEM_ENTITY, IID_RangeManager, {
|
||||
"GetEffectiveParabolicRange": () => 25,
|
||||
"GetMaxReachableParabolicHeight": () => 15
|
||||
});
|
||||
AddMock(SYSTEM_ENTITY, IID_ObstructionManager, {
|
||||
"IsInTargetRange": () => true
|
||||
});
|
||||
TS_ASSERT_EQUALS(cmpAttack.CanEverReachTarget(defender, "Ranged"), true);
|
||||
}
|
||||
|
||||
// Ranged: target too high for parabolic arc even at closest approach (check 2)
|
||||
{
|
||||
const defender = ++entityID;
|
||||
AddMock(defender, IID_Position, {
|
||||
"IsInWorld": () => true,
|
||||
"GetHeightOffset": () => 20,
|
||||
"GetPosition": () => new Vector3D(1, 20, 2)
|
||||
});
|
||||
|
||||
AddMock(SYSTEM_ENTITY, IID_RangeManager, {
|
||||
"GetEffectiveParabolicRange": () => -1, // out of range
|
||||
"GetMaxReachableParabolicHeight": () => 10
|
||||
});
|
||||
|
||||
AddMock(SYSTEM_ENTITY, IID_ObstructionManager, {
|
||||
"IsInTargetRange": () => false
|
||||
});
|
||||
|
||||
// heightDiff = 20 - 0 = 20, maxReachableHeightDiff = 10 → unreachable
|
||||
TS_ASSERT_EQUALS(cmpAttack.CanEverReachTarget(defender, "Ranged"), false);
|
||||
}
|
||||
}
|
||||
testCanEverReachTarget();
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ const enemyPlayer = 2;
|
|||
const alliedPlayer = 3;
|
||||
const turretHolderID = 9;
|
||||
const entitiesToTest = [10, 11, 12, 13];
|
||||
let entityID = 100;
|
||||
|
||||
AddMock(turretHolderID, IID_Ownership, {
|
||||
"GetOwner": () => player
|
||||
|
|
@ -244,3 +245,80 @@ cmpTurretHolder.OnOwnershipChanged({
|
|||
"from": INVALID_PLAYER
|
||||
});
|
||||
TS_ASSERT(cmpTurretHolder.OccupiesTurretPoint(spawned));
|
||||
|
||||
// Test GetClosestApproachDistanceToTurretPoint
|
||||
{
|
||||
const holder = ++entityID;
|
||||
|
||||
// Mock the holder's obstruction
|
||||
AddMock(holder, IID_Obstruction, {
|
||||
"GetBlockMovementFlag": () => true,
|
||||
"GetObstructionHalfSizes": () => ({ "x": 10, "y": 15 })
|
||||
});
|
||||
|
||||
const cmpHolder = ConstructComponent(holder, "TurretHolder", {
|
||||
"TurretPoints": {
|
||||
"center": {
|
||||
"X": "0",
|
||||
"Y": "5.0",
|
||||
"Z": "0"
|
||||
},
|
||||
"edge": {
|
||||
"X": "8.0",
|
||||
"Y": "5.0",
|
||||
"Z": "0"
|
||||
},
|
||||
"corner": {
|
||||
"X": "10.0",
|
||||
"Y": "5.0",
|
||||
"Z": "15.0"
|
||||
},
|
||||
"outside": {
|
||||
"X": "15.0",
|
||||
"Y": "5.0",
|
||||
"Z": "0"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Center point (0,0) in 20x30 building → min(10, 15) = 10
|
||||
TS_ASSERT_EQUALS(cmpHolder.GetClosestApproachDistanceToTurretPoint("center"), 10);
|
||||
|
||||
// Edge point (8,0) in 20x30 building → min(10-8, 15-0) = 2
|
||||
TS_ASSERT_EQUALS(cmpHolder.GetClosestApproachDistanceToTurretPoint("edge"), 2);
|
||||
|
||||
// Corner point (10,15) in 20x30 building → min(10-10, 15-15) = 0
|
||||
TS_ASSERT_EQUALS(cmpHolder.GetClosestApproachDistanceToTurretPoint("corner"), 0);
|
||||
|
||||
// Outside point (15,0) in 20x30 building → min(10-15, 15-0) = -5 → clamped to 0
|
||||
TS_ASSERT_EQUALS(cmpHolder.GetClosestApproachDistanceToTurretPoint("outside"), 0);
|
||||
|
||||
// Nonexistent turret point
|
||||
TS_ASSERT_EQUALS(cmpHolder.GetClosestApproachDistanceToTurretPoint("nonexistent"), 0);
|
||||
|
||||
// Pass object directly
|
||||
const turretPoint = cmpHolder.TurretPointByName("center");
|
||||
TS_ASSERT_EQUALS(cmpHolder.GetClosestApproachDistanceToTurretPoint(turretPoint), 10);
|
||||
|
||||
// Passable building (no obstruction or doesn't block movement)
|
||||
const passableHolder = ++entityID;
|
||||
AddMock(passableHolder, IID_Obstruction, {
|
||||
"GetBlockMovementFlag": () => false
|
||||
});
|
||||
const cmpHolderPassable = ConstructComponent(passableHolder, "TurretHolder", {
|
||||
"TurretPoints": {
|
||||
"center": { "X": "0", "Y": "5.0", "Z": "0" }
|
||||
}
|
||||
});
|
||||
TS_ASSERT_EQUALS(cmpHolderPassable.GetClosestApproachDistanceToTurretPoint("center"), 0);
|
||||
|
||||
// No obstruction component at all
|
||||
++entityID;
|
||||
const cmpHolderNoObst = ConstructComponent(entityID, "TurretHolder", {
|
||||
"TurretPoints": {
|
||||
"center": { "X": "0", "Y": "5.0", "Z": "0" }
|
||||
}
|
||||
});
|
||||
TS_ASSERT_EQUALS(cmpHolderNoObst.GetClosestApproachDistanceToTurretPoint("center"), 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@
|
|||
<HeightOffset>18.0</HeightOffset>
|
||||
</StatusBars>
|
||||
<Vision>
|
||||
<Range>80</Range>
|
||||
<Range>10</Range>
|
||||
</Vision>
|
||||
<VisualActor>
|
||||
<FoundationActor>structures/fndn_3x3.xml</FoundationActor>
|
||||
|
|
|
|||
|
|
@ -110,6 +110,6 @@
|
|||
</SoundGroups>
|
||||
</Sound>
|
||||
<Vision>
|
||||
<Range>80</Range>
|
||||
<Range>10</Range>
|
||||
</Vision>
|
||||
</Entity>
|
||||
|
|
|
|||
|
|
@ -74,6 +74,6 @@
|
|||
<Acceleration op="mul">0.75</Acceleration>
|
||||
</UnitMotion>
|
||||
<Vision>
|
||||
<Range>100</Range>
|
||||
<Range>10</Range>
|
||||
</Vision>
|
||||
</Entity>
|
||||
|
|
|
|||
Loading…
Reference in a new issue