#include #include "catch.hpp" #include "ConfigLoader.h" #include "FactionComponent.h" #include "Formula.h" #include "GameConfig.h" #include "HealthComponent.h" #include "SchematicChoiceOption.h" #include "Simulation.h" #include "SimulationTestAccess.h" #include "StationBodyComponent.h" #include "TestConfig.h" static void killEnemyStations(Simulation& sim) { sim.getAdmin().forEach( [](entt::entity, StationBodyComponent&, FactionComponent& faction, HealthComponent& health) { if (faction.isEnemy) { health.hp = 0.0f; } }); sim.tick(); } // Returns the index of the Artifact option in the pending choices, or -1 if absent. static int findArtifactChoiceIndex(const Simulation& sim) { const auto& choices = sim.getPendingSchematicChoices(); for (int i = 0; i < static_cast(choices.size()); ++i) { if (choices[static_cast(i)].isArtifact) { return i; } } return -1; } // --------------------------------------------------------------------------- // Config: new artifact fields are parsed correctly (REQ-WIN-ARTIFACT-COUNT) // --------------------------------------------------------------------------- TEST_CASE("ArtifactWinCondition: artifact_chance_formula and artifact_win_count are loaded", "[artifact_win]") { const GameConfig cfg = loadTestConfig(); CHECK(cfg.world.artifacts.artifactWinCount == 3); // 0.05 * x at x=2 should be 0.1 CHECK(cfg.world.artifacts.artifactChanceFormula.evaluate(2.0) == Approx(0.1)); } // --------------------------------------------------------------------------- // Simulation initial state // --------------------------------------------------------------------------- TEST_CASE("ArtifactWinCondition: artifact count is 0 and isWon is false at game start", "[artifact_win]") { const Simulation sim(loadTestConfig()); CHECK(sim.getArtifactCount() == 0); CHECK_FALSE(sim.isWon()); } // --------------------------------------------------------------------------- // Artifact option presence in schematic choices // --------------------------------------------------------------------------- TEST_CASE("ArtifactWinCondition: artifact option appears when chance formula returns 1", "[artifact_win]") { GameConfig cfg = loadTestConfig(); cfg.world.artifacts.artifactChanceFormula = Formula::compile("1"); Simulation sim(std::move(cfg)); killEnemyStations(sim); REQUIRE(sim.hasSchematicChoicesPending()); const auto& choices = sim.getPendingSchematicChoices(); const long artifactCount = std::count_if(choices.begin(), choices.end(), [](const SchematicChoiceOption& opt) { return opt.isArtifact; }); CHECK(artifactCount == 1); // Exactly 2 schematic picks + 1 artifact (or fewer if pool was small) CHECK(choices.size() <= 3); } TEST_CASE("ArtifactWinCondition: at most 2 schematic options accompany the artifact", "[artifact_win]") { GameConfig cfg = loadTestConfig(); cfg.world.artifacts.artifactChanceFormula = Formula::compile("1"); Simulation sim(std::move(cfg)); killEnemyStations(sim); REQUIRE(sim.hasSchematicChoicesPending()); const auto& choices = sim.getPendingSchematicChoices(); const long schematicCount = std::count_if(choices.begin(), choices.end(), [](const SchematicChoiceOption& opt) { return !opt.isArtifact; }); CHECK(schematicCount <= 2); } TEST_CASE("ArtifactWinCondition: no artifact option when chance formula returns 0", "[artifact_win]") { GameConfig cfg = loadTestConfig(); cfg.world.artifacts.artifactChanceFormula = Formula::compile("0"); Simulation sim(std::move(cfg)); for (int i = 0; i < 20; ++i) { killEnemyStations(sim); if (!sim.hasSchematicChoicesPending()) { continue; } CHECK(findArtifactChoiceIndex(sim) == -1); SimulationTestAccess::applySchematicChoice(sim,0); } } // --------------------------------------------------------------------------- // Selecting the artifact option // --------------------------------------------------------------------------- TEST_CASE("ArtifactWinCondition: selecting artifact increments artifact count", "[artifact_win]") { GameConfig cfg = loadTestConfig(); cfg.world.artifacts.artifactChanceFormula = Formula::compile("1"); Simulation sim(std::move(cfg)); killEnemyStations(sim); REQUIRE(sim.hasSchematicChoicesPending()); const int index = findArtifactChoiceIndex(sim); REQUIRE(index >= 0); SimulationTestAccess::applySchematicChoice(sim,index); CHECK(sim.getArtifactCount() == 1); } TEST_CASE("ArtifactWinCondition: selecting a non-artifact option does not increment artifact count", "[artifact_win]") { GameConfig cfg = loadTestConfig(); cfg.world.artifacts.artifactChanceFormula = Formula::compile("1"); Simulation sim(std::move(cfg)); killEnemyStations(sim); REQUIRE(sim.hasSchematicChoicesPending()); // Pick the first non-artifact choice. const auto& choices = sim.getPendingSchematicChoices(); const auto it = std::find_if(choices.begin(), choices.end(), [](const SchematicChoiceOption& opt) { return !opt.isArtifact; }); REQUIRE(it != choices.end()); SimulationTestAccess::applySchematicChoice(sim,static_cast(it - choices.begin())); CHECK(sim.getArtifactCount() == 0); } // --------------------------------------------------------------------------- // Win condition (REQ-WIN-ARTIFACT-COUNT) // --------------------------------------------------------------------------- TEST_CASE("ArtifactWinCondition: isWon becomes true when artifact count reaches win count", "[artifact_win]") { GameConfig cfg = loadTestConfig(); cfg.world.artifacts.artifactChanceFormula = Formula::compile("1"); cfg.world.artifacts.artifactWinCount = 1; Simulation sim(std::move(cfg)); CHECK_FALSE(sim.isWon()); killEnemyStations(sim); REQUIRE(sim.hasSchematicChoicesPending()); const int index = findArtifactChoiceIndex(sim); REQUIRE(index >= 0); SimulationTestAccess::applySchematicChoice(sim,index); CHECK(sim.isWon()); } TEST_CASE("ArtifactWinCondition: isWon stays false when artifact count is below win count", "[artifact_win]") { GameConfig cfg = loadTestConfig(); cfg.world.artifacts.artifactChanceFormula = Formula::compile("1"); cfg.world.artifacts.artifactWinCount = 2; Simulation sim(std::move(cfg)); killEnemyStations(sim); REQUIRE(sim.hasSchematicChoicesPending()); SimulationTestAccess::applySchematicChoice(sim,findArtifactChoiceIndex(sim)); CHECK(sim.getArtifactCount() == 1); CHECK_FALSE(sim.isWon()); } TEST_CASE("ArtifactWinCondition: isWon becomes true after collecting required number of artifacts", "[artifact_win]") { GameConfig cfg = loadTestConfig(); cfg.world.artifacts.artifactChanceFormula = Formula::compile("1"); cfg.world.artifacts.artifactWinCount = 2; Simulation sim(std::move(cfg)); for (int i = 0; i < 2; ++i) { killEnemyStations(sim); REQUIRE(sim.hasSchematicChoicesPending()); const int index = findArtifactChoiceIndex(sim); REQUIRE(index >= 0); SimulationTestAccess::applySchematicChoice(sim,index); } CHECK(sim.getArtifactCount() == 2); CHECK(sim.isWon()); } // --------------------------------------------------------------------------- // reset() restores initial state (REQ-CFG-RELOAD) // --------------------------------------------------------------------------- TEST_CASE("ArtifactWinCondition: reset clears artifact count and win state", "[artifact_win]") { GameConfig cfg = loadTestConfig(); cfg.world.artifacts.artifactChanceFormula = Formula::compile("1"); cfg.world.artifacts.artifactWinCount = 1; Simulation sim(std::move(cfg)); killEnemyStations(sim); REQUIRE(sim.hasSchematicChoicesPending()); SimulationTestAccess::applySchematicChoice(sim,findArtifactChoiceIndex(sim)); REQUIRE(sim.isWon()); sim.reset(); CHECK(sim.getArtifactCount() == 0); CHECK_FALSE(sim.isWon()); }