fix issue where repair behavior targets enemy HQ in balancing target #1
@@ -14,6 +14,7 @@
|
|||||||
#include "EntityAdmin.h"
|
#include "EntityAdmin.h"
|
||||||
#include "FactionComponent.h"
|
#include "FactionComponent.h"
|
||||||
#include "HealthComponent.h"
|
#include "HealthComponent.h"
|
||||||
|
#include "HqProxyComponent.h"
|
||||||
#include "ModuleOwnerComponent.h"
|
#include "ModuleOwnerComponent.h"
|
||||||
#include "MovementIntentSystem.h"
|
#include "MovementIntentSystem.h"
|
||||||
#include "PositionComponent.h"
|
#include "PositionComponent.h"
|
||||||
@@ -121,6 +122,8 @@ void ArenaSimulation::placeStructures()
|
|||||||
}
|
}
|
||||||
m_team1HqEntity = m_admin.spawnStation(anchor, hqParsed.footprint, absCells,
|
m_team1HqEntity = m_admin.spawnStation(anchor, hqParsed.footprint, absCells,
|
||||||
hp, hp, false);
|
hp, hp, false);
|
||||||
|
// Tag as an HQ so it is excluded from repair targeting (REQ-SHP-REPAIR).
|
||||||
|
m_admin.addComponent<HqProxyComponent>(m_team1HqEntity);
|
||||||
m_buildingSystem->registerTileOccupancy(absCells, allocateBuildingId());
|
m_buildingSystem->registerTileOccupancy(absCells, allocateBuildingId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,6 +143,8 @@ void ArenaSimulation::placeStructures()
|
|||||||
}
|
}
|
||||||
m_team2HqEntity = m_admin.spawnStation(anchor, hqParsed.footprint, absCells,
|
m_team2HqEntity = m_admin.spawnStation(anchor, hqParsed.footprint, absCells,
|
||||||
hp, hp, true);
|
hp, hp, true);
|
||||||
|
// Tag as an HQ so it is excluded from repair targeting (REQ-SHP-REPAIR).
|
||||||
|
m_admin.addComponent<HqProxyComponent>(m_team2HqEntity);
|
||||||
m_buildingSystem->registerTileOccupancy(absCells, allocateBuildingId());
|
m_buildingSystem->registerTileOccupancy(absCells, allocateBuildingId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,10 +23,14 @@ std::vector<RepairableInfo> buildRepairables(EntityAdmin& admin)
|
|||||||
});
|
});
|
||||||
|
|
||||||
admin.forEach<StationBodyComponent, PositionComponent, FactionComponent, HealthComponent>(
|
admin.forEach<StationBodyComponent, PositionComponent, FactionComponent, HealthComponent>(
|
||||||
[&repairables](entt::entity e, const StationBodyComponent& /*sb*/,
|
[&repairables, &admin](entt::entity e, const StationBodyComponent& /*sb*/,
|
||||||
const PositionComponent& pos, const FactionComponent& f,
|
const PositionComponent& pos, const FactionComponent& f,
|
||||||
const HealthComponent& h)
|
const HealthComponent& h)
|
||||||
{
|
{
|
||||||
|
// The HQ is not a repair target — only ships and defence stations are
|
||||||
|
// (REQ-SHP-REPAIR). In the balancing arena the HQ is spawned as a station,
|
||||||
|
// so it is identified by its HqProxyComponent tag.
|
||||||
|
if (admin.hasAll<HqProxyComponent>(e)) { return; }
|
||||||
repairables.push_back({e, pos.value, f.isEnemy, false, h.hp, h.maxHp});
|
repairables.push_back({e, pos.value, f.isEnemy, false, h.hp, h.maxHp});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -52,9 +56,13 @@ std::vector<CombatantInfo> buildCombatants(EntityAdmin& admin)
|
|||||||
});
|
});
|
||||||
|
|
||||||
admin.forEach<PositionComponent, FactionComponent, HqProxyComponent>(
|
admin.forEach<PositionComponent, FactionComponent, HqProxyComponent>(
|
||||||
[&combatants](entt::entity e, const PositionComponent& pos,
|
[&combatants, &admin](entt::entity e, const PositionComponent& pos,
|
||||||
const FactionComponent& f, const HqProxyComponent& /*hq*/)
|
const FactionComponent& f, const HqProxyComponent& /*hq*/)
|
||||||
{
|
{
|
||||||
|
// An arena HQ carries both StationBodyComponent and HqProxyComponent; it
|
||||||
|
// is already listed by the station pass above, so skip it here to avoid
|
||||||
|
// counting it twice.
|
||||||
|
if (admin.hasAll<StationBodyComponent>(e)) { return; }
|
||||||
combatants.push_back({e, pos.value, f.isEnemy, true});
|
combatants.push_back({e, pos.value, f.isEnemy, true});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "EntityAdmin.h"
|
#include "EntityAdmin.h"
|
||||||
#include "FactionComponent.h"
|
#include "FactionComponent.h"
|
||||||
#include "HealthComponent.h"
|
#include "HealthComponent.h"
|
||||||
|
#include "HqProxyComponent.h"
|
||||||
#include "ModuleOwnerComponent.h"
|
#include "ModuleOwnerComponent.h"
|
||||||
#include "MovementIntentComponent.h"
|
#include "MovementIntentComponent.h"
|
||||||
#include "MovementIntentSystem.h"
|
#include "MovementIntentSystem.h"
|
||||||
@@ -862,6 +863,48 @@ TEST_CASE("RepairSystem: does not crash when a tool's owner is not a repair ship
|
|||||||
REQUIRE_FALSE(f.admin.get<RepairToolComponent>(moduleEntity).currentTarget.has_value());
|
REQUIRE_FALSE(f.admin.get<RepairToolComponent>(moduleEntity).currentTarget.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("RepairSystem: repair tool does not repair an HQ", "[behavior]")
|
||||||
|
{
|
||||||
|
Fixture f;
|
||||||
|
const ShipLayoutConfig repairLayout = makeSingleModuleLayout("repair_tool");
|
||||||
|
const entt::entity repairShip = f.ships.spawn("repair_ship", 1, QVector2D(0.0f, 0.0f),
|
||||||
|
false, repairLayout);
|
||||||
|
|
||||||
|
// A damaged, same-faction HQ in repair range — spawned as a station and tagged
|
||||||
|
// as an HQ (as the balancing arena does). The HQ is not a repair target.
|
||||||
|
const std::vector<QPoint> cells = {QPoint(2, 0), QPoint(3, 0), QPoint(2, 1), QPoint(3, 1)};
|
||||||
|
const entt::entity hq = f.admin.spawnStation(QPoint(2, 0), QSize(2, 2), cells,
|
||||||
|
100.0f, 200.0f, false);
|
||||||
|
f.admin.addComponent<HqProxyComponent>(hq);
|
||||||
|
|
||||||
|
f.decide();
|
||||||
|
f.runRepairHeal();
|
||||||
|
|
||||||
|
REQUIRE(f.admin.get<HealthComponent>(hq).hp == Approx(100.0f));
|
||||||
|
const entt::entity rc = firstRepairChild(f.admin, repairShip);
|
||||||
|
REQUIRE_FALSE(f.admin.get<RepairToolComponent>(rc).currentTarget.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("RepairSystem: repair tool still repairs a damaged defence station", "[behavior]")
|
||||||
|
{
|
||||||
|
Fixture f;
|
||||||
|
const ShipLayoutConfig repairLayout = makeSingleModuleLayout("repair_tool");
|
||||||
|
const entt::entity repairShip = f.ships.spawn("repair_ship", 1, QVector2D(0.0f, 0.0f),
|
||||||
|
false, repairLayout);
|
||||||
|
|
||||||
|
// A damaged, same-faction defence station (no HQ tag) in repair range.
|
||||||
|
const std::vector<QPoint> cells = {QPoint(2, 0), QPoint(3, 0), QPoint(2, 1), QPoint(3, 1)};
|
||||||
|
const entt::entity station = f.admin.spawnStation(QPoint(2, 0), QSize(2, 2), cells,
|
||||||
|
100.0f, 200.0f, false);
|
||||||
|
|
||||||
|
f.decide();
|
||||||
|
f.runRepairHeal();
|
||||||
|
|
||||||
|
REQUIRE(f.admin.get<HealthComponent>(station).hp > 100.0f);
|
||||||
|
const entt::entity rc = firstRepairChild(f.admin, repairShip);
|
||||||
|
REQUIRE(*f.admin.get<RepairToolComponent>(rc).currentTarget == station);
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// SalvageScrapBehavior / DeliverScrapBehavior
|
// SalvageScrapBehavior / DeliverScrapBehavior
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user