change repair_tool application and add beams for salvager and repair_tool
This commit is contained in:
@@ -70,6 +70,7 @@ struct Fixture
|
||||
DynamicBodySystem dynamicBody;
|
||||
ScrapSystem scraps;
|
||||
Tick tick;
|
||||
std::vector<BeamFiredEvent> beamEvents;
|
||||
|
||||
explicit Fixture()
|
||||
: cfg(loadConfig())
|
||||
@@ -102,8 +103,9 @@ struct Fixture
|
||||
// World mutation: collection/delivery and healing.
|
||||
void runModules()
|
||||
{
|
||||
salvager.tick(scraps, buildings);
|
||||
repair.tick();
|
||||
beamEvents.clear();
|
||||
salvager.tick(tick, scraps, buildings, beamEvents);
|
||||
repair.tick(tick, beamEvents);
|
||||
}
|
||||
|
||||
// Run one full behavior+movement tick (steps 7 and 10).
|
||||
@@ -115,6 +117,35 @@ struct Fixture
|
||||
dynamicBody.tick(admin);
|
||||
++tick;
|
||||
}
|
||||
|
||||
// One repair-system tick at the current sim time (advances the tick counter).
|
||||
// Starts cycles and applies any due (mid-beam-delayed) heals.
|
||||
void repairTick()
|
||||
{
|
||||
beamEvents.clear();
|
||||
repair.tick(tick, beamEvents);
|
||||
++tick;
|
||||
}
|
||||
|
||||
// Drive the repair system long enough for a started cycle's delayed heal to land.
|
||||
void runRepairHeal()
|
||||
{
|
||||
for (int i = 0; i <= kBeamImpactDelayTicks; ++i) { repairTick(); }
|
||||
}
|
||||
|
||||
// One salvage-system tick at the current sim time (advances the tick counter).
|
||||
void salvageTick()
|
||||
{
|
||||
beamEvents.clear();
|
||||
salvager.tick(tick, scraps, buildings, beamEvents);
|
||||
++tick;
|
||||
}
|
||||
|
||||
// Drive the salvage system long enough for a started cycle's delayed collection.
|
||||
void runSalvageCollect()
|
||||
{
|
||||
for (int i = 0; i <= kBeamImpactDelayTicks; ++i) { salvageTick(); }
|
||||
}
|
||||
};
|
||||
|
||||
static ShipLayoutConfig makeSingleModuleLayout(const std::string& moduleId)
|
||||
@@ -602,7 +633,7 @@ TEST_CASE("BehaviorSystem: repair ship heals damaged ally within repair range",
|
||||
f.admin.get<HealthComponent>(friendly).hp = initialHp;
|
||||
|
||||
f.decide();
|
||||
f.runModules();
|
||||
f.runRepairHeal();
|
||||
|
||||
REQUIRE(health(f.admin, friendly).hp > initialHp);
|
||||
}
|
||||
@@ -616,11 +647,8 @@ TEST_CASE("BehaviorSystem: repair ship does not heal above maxHp", "[behavior]")
|
||||
|
||||
f.admin.get<HealthComponent>(friendly).hp = f.admin.get<HealthComponent>(friendly).maxHp - 0.001f;
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
f.decide();
|
||||
f.runModules();
|
||||
}
|
||||
f.decide();
|
||||
f.runRepairHeal();
|
||||
|
||||
const HealthComponent& h = health(f.admin, friendly);
|
||||
REQUIRE(h.hp <= h.maxHp);
|
||||
@@ -644,7 +672,7 @@ TEST_CASE("RepairSystem: tool heals the in-range damaged target chosen by the ex
|
||||
f.admin.get<HealthComponent>(friendly).hp = initHp;
|
||||
|
||||
f.decide();
|
||||
f.runModules();
|
||||
f.runRepairHeal();
|
||||
|
||||
const entt::entity rc = firstRepairChild(f.admin, repairShip);
|
||||
REQUIRE(f.admin.isValid(rc));
|
||||
@@ -674,7 +702,7 @@ TEST_CASE("RepairSystem: tool falls back to in-range target when its target is o
|
||||
const entt::entity rc = firstRepairChild(f.admin, repairShip);
|
||||
f.admin.get<RepairToolComponent>(rc).currentTarget = outOfRange;
|
||||
|
||||
f.repair.tick();
|
||||
f.runRepairHeal();
|
||||
|
||||
REQUIRE(f.admin.get<RepairToolComponent>(rc).currentTarget.has_value());
|
||||
REQUIRE(*f.admin.get<RepairToolComponent>(rc).currentTarget == fallback);
|
||||
@@ -699,7 +727,7 @@ TEST_CASE("RepairSystem: tool falls back when its target is fully healed",
|
||||
const entt::entity rc = firstRepairChild(f.admin, repairShip);
|
||||
f.admin.get<RepairToolComponent>(rc).currentTarget = healed;
|
||||
|
||||
f.repair.tick();
|
||||
f.runRepairHeal();
|
||||
|
||||
REQUIRE(*f.admin.get<RepairToolComponent>(rc).currentTarget == fallback);
|
||||
REQUIRE(health(f.admin, fallback).hp > fallbackInitHp);
|
||||
@@ -722,7 +750,7 @@ TEST_CASE("RepairSystem: tool falls back when its target is destroyed",
|
||||
f.admin.get<RepairToolComponent>(rc).currentTarget = gone;
|
||||
f.ships.despawn(gone);
|
||||
|
||||
f.repair.tick();
|
||||
f.runRepairHeal();
|
||||
|
||||
REQUIRE(*f.admin.get<RepairToolComponent>(rc).currentTarget == fallback);
|
||||
REQUIRE(health(f.admin, fallback).hp > fallbackInitHp);
|
||||
@@ -744,7 +772,7 @@ TEST_CASE("RepairSystem: tool target is cleared when no repairable target is in
|
||||
const entt::entity rc = firstRepairChild(f.admin, repairShip);
|
||||
f.admin.get<RepairToolComponent>(rc).currentTarget = outOfRange;
|
||||
|
||||
f.repair.tick();
|
||||
f.runRepairHeal();
|
||||
|
||||
REQUIRE_FALSE(f.admin.get<RepairToolComponent>(rc).currentTarget.has_value());
|
||||
REQUIRE(health(f.admin, outOfRange).hp == Approx(initHp));
|
||||
@@ -763,11 +791,12 @@ TEST_CASE("RepairSystem: two repair modules both heal the chosen target additive
|
||||
f.admin.get<HealthComponent>(targetA).hp = initHp;
|
||||
|
||||
f.decide();
|
||||
f.runModules();
|
||||
f.runRepairHeal();
|
||||
|
||||
// Both modules should have healed targetA — total increase is 2 * ratePerTick.
|
||||
const float ratePerTick = (5.0f + 1.0f) / static_cast<float>(kTickRateHz);
|
||||
REQUIRE(health(f.admin, targetA).hp == Approx(initHp + 2.0f * ratePerTick));
|
||||
// Both modules run one cycle and heal targetA — total increase is 2 * repairAmountHp.
|
||||
// repair_amount_hp_formula = "5 + x" at x=1 → 6 HP per cycle.
|
||||
const float repairAmountHp = 5.0f + 1.0f;
|
||||
REQUIRE(health(f.admin, targetA).hp == Approx(initHp + 2.0f * repairAmountHp));
|
||||
|
||||
const std::vector<entt::entity> children = allRepairChildren(f.admin, repairShip);
|
||||
REQUIRE(children.size() == 2);
|
||||
@@ -797,10 +826,10 @@ TEST_CASE("RepairSystem: two modules both fall back and heal the same target",
|
||||
f.admin.get<RepairToolComponent>(child).currentTarget = healed;
|
||||
}
|
||||
|
||||
f.repair.tick();
|
||||
f.runRepairHeal();
|
||||
|
||||
const float ratePerTick = (5.0f + 1.0f) / static_cast<float>(kTickRateHz);
|
||||
REQUIRE(health(f.admin, targetB).hp == Approx(initHp + 2.0f * ratePerTick));
|
||||
const float repairAmountHp = 5.0f + 1.0f;
|
||||
REQUIRE(health(f.admin, targetB).hp == Approx(initHp + 2.0f * repairAmountHp));
|
||||
|
||||
const std::vector<entt::entity> children = allRepairChildren(f.admin, repairShip);
|
||||
REQUIRE(children.size() == 2);
|
||||
@@ -819,14 +848,16 @@ TEST_CASE("RepairSystem: does not crash when a tool's owner is not a repair ship
|
||||
const entt::entity ownerShip = f.ships.spawn("interceptor", 1, QVector2D(0.0f, 0.0f));
|
||||
const entt::entity moduleEntity = f.admin.createModuleEntity();
|
||||
RepairToolComponent rt;
|
||||
rt.ratePerTick = 1.0f;
|
||||
rt.range_tiles = 10.0f;
|
||||
rt.currentTarget = std::nullopt;
|
||||
rt.repairAmountHp = 1.0f;
|
||||
rt.repairIntervalTicks = kTickRateHz;
|
||||
rt.cooldownTicksRemaining = 0;
|
||||
rt.range_tiles = 10.0f;
|
||||
rt.currentTarget = std::nullopt;
|
||||
f.admin.addComponent<RepairToolComponent>(moduleEntity, rt);
|
||||
f.admin.addComponent<ModuleOwnerComponent>(moduleEntity, ModuleOwnerComponent{ownerShip});
|
||||
|
||||
// Must not crash; no damaged friendly in range, so no target is set.
|
||||
f.repair.tick();
|
||||
f.runRepairHeal();
|
||||
|
||||
REQUIRE_FALSE(f.admin.get<RepairToolComponent>(moduleEntity).currentTarget.has_value());
|
||||
}
|
||||
@@ -866,7 +897,7 @@ TEST_CASE("BehaviorSystem: salvage ship collects scrap on arrival", "[behavior]"
|
||||
false, salvageLayout);
|
||||
const entt::entity scrapEntity = f.scraps.spawn(QVector2D(0.0f, 0.0f), 1, 100000);
|
||||
|
||||
f.salvager.tick(f.scraps, f.buildings);
|
||||
f.runSalvageCollect();
|
||||
|
||||
const entt::entity sc = firstSalvageChild(f.admin, ship);
|
||||
REQUIRE(f.admin.isValid(sc));
|
||||
@@ -935,7 +966,7 @@ TEST_CASE("SalvagerSystem: module does not collect scrap beyond its collection r
|
||||
false, salvageLayout);
|
||||
f.scraps.spawn(QVector2D(55.0f, 0.0f), 1, 100000);
|
||||
|
||||
f.salvager.tick(f.scraps, f.buildings);
|
||||
f.runSalvageCollect();
|
||||
|
||||
REQUIRE(f.admin.get<SalvageCargoComponent>(firstSalvageChild(f.admin, ship)).current == 0);
|
||||
}
|
||||
@@ -950,7 +981,7 @@ TEST_CASE("SalvagerSystem: module collects scrap within its collection range",
|
||||
false, salvageLayout);
|
||||
f.scraps.spawn(QVector2D(45.0f, 0.0f), 1, 100000);
|
||||
|
||||
f.salvager.tick(f.scraps, f.buildings);
|
||||
f.runSalvageCollect();
|
||||
|
||||
REQUIRE(f.admin.get<SalvageCargoComponent>(firstSalvageChild(f.admin, ship)).current == 1);
|
||||
}
|
||||
@@ -967,11 +998,13 @@ TEST_CASE("SalvagerSystem: collection sets cooldown on module", "[behavior]")
|
||||
false, salvageLayout);
|
||||
f.scraps.spawn(QVector2D(0.0f, 0.0f), 1, 100000);
|
||||
|
||||
f.salvager.tick(f.scraps, f.buildings);
|
||||
// Starting a collection cycle sets the cooldown immediately; the scrap is not
|
||||
// collected until mid-beam (REQ-SHP-SALVAGE), so cargo is still empty now.
|
||||
f.salvageTick();
|
||||
|
||||
const SalvageCargoComponent& cargo =
|
||||
f.admin.get<SalvageCargoComponent>(firstSalvageChild(f.admin, ship));
|
||||
REQUIRE(cargo.current == 1);
|
||||
REQUIRE(cargo.current == 0);
|
||||
REQUIRE(cargo.cooldownTicksRemaining == cargo.collectionIntervalTicks);
|
||||
}
|
||||
|
||||
@@ -985,7 +1018,7 @@ TEST_CASE("SalvagerSystem: module on cooldown does not collect scrap", "[behavio
|
||||
|
||||
f.admin.get<SalvageCargoComponent>(firstSalvageChild(f.admin, ship)).cooldownTicksRemaining = 10;
|
||||
|
||||
f.salvager.tick(f.scraps, f.buildings);
|
||||
f.runSalvageCollect();
|
||||
|
||||
REQUIRE(f.admin.get<SalvageCargoComponent>(firstSalvageChild(f.admin, ship)).current == 0);
|
||||
}
|
||||
@@ -999,15 +1032,16 @@ TEST_CASE("SalvagerSystem: module collects again after cooldown expires", "[beha
|
||||
const entt::entity sc = firstSalvageChild(f.admin, ship);
|
||||
|
||||
f.scraps.spawn(QVector2D(0.0f, 0.0f), 1, 100000);
|
||||
f.salvager.tick(f.scraps, f.buildings);
|
||||
f.runSalvageCollect();
|
||||
REQUIRE(f.admin.get<SalvageCargoComponent>(sc).current == 1);
|
||||
|
||||
// Shorten cooldown to 1 tick and place a second scrap.
|
||||
f.admin.get<SalvageCargoComponent>(sc).cooldownTicksRemaining = 1;
|
||||
f.scraps.spawn(QVector2D(0.0f, 0.0f), 1, 100000);
|
||||
|
||||
// Next tick: cooldown decrements to 0, module collects the second scrap.
|
||||
f.salvager.tick(f.scraps, f.buildings);
|
||||
// Once the cooldown expires the module starts another cycle and collects the
|
||||
// second scrap after the mid-beam delay.
|
||||
f.runSalvageCollect();
|
||||
|
||||
REQUIRE(f.admin.get<SalvageCargoComponent>(sc).current == 2);
|
||||
}
|
||||
@@ -1026,7 +1060,7 @@ TEST_CASE("SalvagerSystem: two salvage modules collect independently in same tic
|
||||
f.scraps.spawn(QVector2D(0.0f, 0.0f), 1, 100000);
|
||||
f.scraps.spawn(QVector2D(0.0f, 0.0f), 1, 100000);
|
||||
|
||||
f.salvager.tick(f.scraps, f.buildings);
|
||||
f.runSalvageCollect();
|
||||
|
||||
REQUIRE(totalSalvageCurrent(f.admin, ship) == 2);
|
||||
}
|
||||
@@ -1055,7 +1089,7 @@ TEST_CASE("SalvagerSystem: second salvage module does not collect when first is
|
||||
f.scraps.spawn(QVector2D(0.0f, 0.0f), 1, 100000);
|
||||
f.scraps.spawn(QVector2D(0.0f, 0.0f), 1, 100000);
|
||||
|
||||
f.salvager.tick(f.scraps, f.buildings);
|
||||
f.runSalvageCollect();
|
||||
|
||||
// Only one module was ready, so only one scrap is collected.
|
||||
REQUIRE(totalSalvageCurrent(f.admin, ship) == 1);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "ConfigLoader.h"
|
||||
#include "EntityAdmin.h"
|
||||
#include "FactionComponent.h"
|
||||
#include "WeaponFiredEvent.h"
|
||||
#include "BeamFiredEvent.h"
|
||||
#include "HealthComponent.h"
|
||||
#include "HqProxyComponent.h"
|
||||
#include "ModuleOwnerComponent.h"
|
||||
@@ -112,7 +112,7 @@ TEST_CASE("CombatSystem: ship fires when cooldown=0 and target in range", "[comb
|
||||
|
||||
const float hpBefore = f.admin.get<HealthComponent>(player).hp;
|
||||
|
||||
std::vector<WeaponFiredEvent> events;
|
||||
std::vector<BeamFiredEvent> events;
|
||||
f.combat.tick(0, f.admin, f.buildings, events);
|
||||
f.combat.applyPendingDamage(5, f.admin);
|
||||
|
||||
@@ -136,16 +136,16 @@ TEST_CASE("CombatSystem: cooldown prevents firing before it expires", "[combat]"
|
||||
f.admin.get<WeaponComponent>(wc).cooldownTicks = 3.0f; // override to 3
|
||||
}
|
||||
|
||||
auto enemyFiredIn = [&enemy](const std::vector<WeaponFiredEvent>& evts)
|
||||
auto enemyFiredIn = [&enemy](const std::vector<BeamFiredEvent>& evts)
|
||||
{
|
||||
for (const WeaponFiredEvent& evt : evts)
|
||||
for (const BeamFiredEvent& evt : evts)
|
||||
{
|
||||
if (evt.shooter == enemy) { return true; }
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
std::vector<WeaponFiredEvent> events;
|
||||
std::vector<BeamFiredEvent> events;
|
||||
f.combat.tick(0, f.admin, f.buildings, events);
|
||||
REQUIRE_FALSE(enemyFiredIn(events));
|
||||
|
||||
@@ -166,7 +166,7 @@ TEST_CASE("CombatSystem: no fire when target is out of range", "[combat]")
|
||||
const entt::entity player = f.ships.spawn(combatDef->id, 1, QVector2D(500.0f, 0.0f), false);
|
||||
f.wireEnemyTarget(enemy, player);
|
||||
|
||||
std::vector<WeaponFiredEvent> events;
|
||||
std::vector<BeamFiredEvent> events;
|
||||
f.combat.tick(0, f.admin, f.buildings, events);
|
||||
REQUIRE(events.empty());
|
||||
}
|
||||
@@ -205,9 +205,9 @@ TEST_CASE("CombatSystem: player station fires at enemy ship in range", "[combat]
|
||||
|
||||
sim.tick();
|
||||
|
||||
const std::vector<WeaponFiredEvent> events = sim.drainWeaponFiredEvents();
|
||||
const std::vector<BeamFiredEvent> events = sim.drainBeamFiredEvents();
|
||||
bool stationFired = false;
|
||||
for (const WeaponFiredEvent& evt : events)
|
||||
for (const BeamFiredEvent& evt : events)
|
||||
{
|
||||
if (evt.shooter == stationEntity) { stationFired = true; }
|
||||
}
|
||||
@@ -243,9 +243,9 @@ TEST_CASE("CombatSystem: enemy station fires at player ship in range", "[combat]
|
||||
|
||||
sim.tick();
|
||||
|
||||
const std::vector<WeaponFiredEvent> events = sim.drainWeaponFiredEvents();
|
||||
const std::vector<BeamFiredEvent> events = sim.drainBeamFiredEvents();
|
||||
bool stationFired = false;
|
||||
for (const WeaponFiredEvent& evt : events)
|
||||
for (const BeamFiredEvent& evt : events)
|
||||
{
|
||||
if (evt.shooter == stationEntity) { stationFired = true; }
|
||||
}
|
||||
@@ -281,9 +281,9 @@ TEST_CASE("CombatSystem: player ship fires at enemy station in range", "[combat]
|
||||
|
||||
sim.tick();
|
||||
|
||||
const std::vector<WeaponFiredEvent> events = sim.drainWeaponFiredEvents();
|
||||
const std::vector<BeamFiredEvent> events = sim.drainBeamFiredEvents();
|
||||
bool playerFiredAtStation = false;
|
||||
for (const WeaponFiredEvent& evt : events)
|
||||
for (const BeamFiredEvent& evt : events)
|
||||
{
|
||||
if (evt.shooter == playerShip && evt.target == stationEntity)
|
||||
{
|
||||
@@ -309,7 +309,7 @@ TEST_CASE("CombatSystem: damage not applied before impact tick", "[combat]")
|
||||
|
||||
const float hpBefore = f.admin.get<HealthComponent>(player).hp;
|
||||
|
||||
std::vector<WeaponFiredEvent> events;
|
||||
std::vector<BeamFiredEvent> events;
|
||||
f.combat.tick(0, f.admin, f.buildings, events);
|
||||
|
||||
for (Tick t = 1; t < 5; ++t)
|
||||
@@ -331,7 +331,7 @@ TEST_CASE("CombatSystem: damage applied exactly at impact tick", "[combat]")
|
||||
|
||||
const float hpBefore = f.admin.get<HealthComponent>(player).hp;
|
||||
|
||||
std::vector<WeaponFiredEvent> events;
|
||||
std::vector<BeamFiredEvent> events;
|
||||
f.combat.tick(0, f.admin, f.buildings, events);
|
||||
f.combat.applyPendingDamage(5, f.admin);
|
||||
|
||||
@@ -348,7 +348,7 @@ TEST_CASE("CombatSystem: damage silently dropped if target already dead", "[comb
|
||||
const entt::entity player = f.ships.spawn(combatDef->id, 1, QVector2D(4.0f, 5.0f), false);
|
||||
f.wireEnemyTarget(enemy, player);
|
||||
|
||||
std::vector<WeaponFiredEvent> events;
|
||||
std::vector<BeamFiredEvent> events;
|
||||
f.combat.tick(0, f.admin, f.buildings, events);
|
||||
|
||||
f.ships.despawn(player);
|
||||
@@ -371,7 +371,7 @@ TEST_CASE("CombatSystem: damage still applied if shooter already dead", "[combat
|
||||
|
||||
const float hpBefore = f.admin.get<HealthComponent>(player).hp;
|
||||
|
||||
std::vector<WeaponFiredEvent> events;
|
||||
std::vector<BeamFiredEvent> events;
|
||||
f.combat.tick(0, f.admin, f.buildings, events);
|
||||
|
||||
f.ships.despawn(enemy);
|
||||
|
||||
@@ -93,6 +93,38 @@ TEST_CASE("ScrapSystem: consume returns nullopt for invalid entity", "[scrap]")
|
||||
REQUIRE_FALSE(amount.has_value());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// collectOne
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("ScrapSystem: collectOne depletes one scrap and keeps the pile until empty", "[scrap]")
|
||||
{
|
||||
EntityAdmin admin;
|
||||
ScrapSystem ss(admin);
|
||||
|
||||
const entt::entity e = ss.spawn(QVector2D(0.0f, 0.0f), 3, 100);
|
||||
|
||||
REQUIRE(ss.collectOne(e));
|
||||
REQUIRE(admin.isValid(e));
|
||||
REQUIRE(admin.get<ScrapDataComponent>(e).amount == 2);
|
||||
|
||||
REQUIRE(ss.collectOne(e));
|
||||
REQUIRE(admin.isValid(e));
|
||||
REQUIRE(admin.get<ScrapDataComponent>(e).amount == 1);
|
||||
|
||||
// Final unit collected: the pile is removed once depleted.
|
||||
REQUIRE(ss.collectOne(e));
|
||||
REQUIRE_FALSE(admin.isValid(e));
|
||||
}
|
||||
|
||||
TEST_CASE("ScrapSystem: collectOne returns false for an invalid entity", "[scrap]")
|
||||
{
|
||||
EntityAdmin admin;
|
||||
ScrapSystem ss(admin);
|
||||
|
||||
REQUIRE_FALSE(ss.collectOne(entt::null));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// allScrapInfo
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -256,11 +256,13 @@ TEST_CASE("ShipSystem: repair_ship level 1 repair stats match config formulas",
|
||||
const ShipLayoutConfig layout = makeSingleModuleLayout("repair_tool");
|
||||
const entt::entity e = ss.spawn("repair_ship", 1, QVector2D(0.0f, 0.0f), false, layout);
|
||||
|
||||
// repair_tool: repair_rate_hz_formula = "5 + x" at x=1 → 6 / kTickRateHz
|
||||
const float expectedRate = 6.0f / static_cast<float>(kTickRateHz);
|
||||
const entt::entity rc = firstRepairChild(admin, e);
|
||||
REQUIRE(admin.isValid(rc));
|
||||
REQUIRE(admin.get<RepairToolComponent>(rc).ratePerTick == Approx(expectedRate));
|
||||
// repair_rate_hz_formula = "1" cycle/s → interval = kTickRateHz ticks
|
||||
REQUIRE(admin.get<RepairToolComponent>(rc).repairIntervalTicks == kTickRateHz);
|
||||
// repair_amount_hp_formula = "5 + x" at x=1 → 6 HP per cycle
|
||||
REQUIRE(admin.get<RepairToolComponent>(rc).repairAmountHp == Approx(6.0f));
|
||||
REQUIRE(admin.get<RepairToolComponent>(rc).cooldownTicksRemaining == 0);
|
||||
// repair_range_m_formula = "800" m → 800/10 = 80 tiles
|
||||
REQUIRE(admin.get<RepairToolComponent>(rc).range_tiles == Approx(80.0f));
|
||||
REQUIRE(admin.get<RepairBehavior>(e).maxRepairRange_tiles == Approx(80.0f));
|
||||
|
||||
@@ -43,22 +43,22 @@ TEST_CASE("Simulation::tick 10 times yields currentTick == 10", "[simulation]")
|
||||
REQUIRE(sim.currentTick() == 10);
|
||||
}
|
||||
|
||||
TEST_CASE("Simulation::drainWeaponFiredEvents returns empty initially", "[simulation]")
|
||||
TEST_CASE("Simulation::drainBeamFiredEvents returns empty initially", "[simulation]")
|
||||
{
|
||||
Simulation sim(loadConfig());
|
||||
|
||||
REQUIRE(sim.drainWeaponFiredEvents().empty());
|
||||
REQUIRE(sim.drainBeamFiredEvents().empty());
|
||||
}
|
||||
|
||||
TEST_CASE("Simulation::drainWeaponFiredEvents clears queue on drain", "[simulation]")
|
||||
TEST_CASE("Simulation::drainBeamFiredEvents clears queue on drain", "[simulation]")
|
||||
{
|
||||
Simulation sim(loadConfig());
|
||||
|
||||
// First drain: empty.
|
||||
sim.drainWeaponFiredEvents();
|
||||
sim.drainBeamFiredEvents();
|
||||
|
||||
// Second drain must also be empty (not a double-return).
|
||||
REQUIRE(sim.drainWeaponFiredEvents().empty());
|
||||
REQUIRE(sim.drainBeamFiredEvents().empty());
|
||||
}
|
||||
|
||||
TEST_CASE("Simulation::hasSchematicChoicesPending returns false initially", "[simulation]")
|
||||
|
||||
Reference in New Issue
Block a user