Implement config-driven unlock groups so that multiple things can be unlocked at once (including buildings)
This commit is contained in:
117
src/test/UnlockGroupTest.cpp
Normal file
117
src/test/UnlockGroupTest.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
// Unlock groups as the unit of loot (REQ-LOCK-EXPLICIT, REQ-LOCK-BUILDING,
|
||||
// REQ-DEF-SCHEMATIC-DROP): buildings can be locked, and one drop can grant a
|
||||
// building and a module together.
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "BuildingType.h"
|
||||
#include "ConfigLoader.h"
|
||||
#include "FactionComponent.h"
|
||||
#include "GameConfig.h"
|
||||
#include "HealthComponent.h"
|
||||
#include "SchematicChoiceOption.h"
|
||||
#include "Simulation.h"
|
||||
#include "SimulationTestAccess.h"
|
||||
#include "StationBodyComponent.h"
|
||||
#include "UnlocksConfig.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
GameConfig loadConfig()
|
||||
{
|
||||
return ConfigLoader::loadFromDirectory(CONFIG_DIR);
|
||||
}
|
||||
|
||||
void killEnemyStations(Simulation& sim)
|
||||
{
|
||||
sim.getAdmin().forEach<StationBodyComponent, FactionComponent, HealthComponent>(
|
||||
[](entt::entity, StationBodyComponent&, FactionComponent& faction, HealthComponent& health)
|
||||
{
|
||||
if (faction.isEnemy) { health.hp = 0.0f; }
|
||||
});
|
||||
sim.tick();
|
||||
}
|
||||
|
||||
// A config whose only unlock group grants the salvager module and the salvage
|
||||
// bay together, gated to the given station level.
|
||||
GameConfig configWithSalvageGroup(int stationLevel)
|
||||
{
|
||||
GameConfig cfg = loadConfig();
|
||||
cfg.unlocks.groups.clear();
|
||||
cfg.unlocks.groups.push_back(
|
||||
UnlockGroupDef{"salvage_operations", stationLevel, {}, {}, {"salvager"}, {"salvage_bay"}, {}});
|
||||
return cfg;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("UnlockGroup: a building granted by a group is locked at game start", "[unlock_group]")
|
||||
{
|
||||
const Simulation sim(configWithSalvageGroup(0));
|
||||
CHECK_FALSE(sim.isBuildingUnlocked(BuildingType::SalvageBay));
|
||||
CHECK_FALSE(sim.isModuleSchematicUnlocked("salvager"));
|
||||
// A building in no unlock group is available from the start.
|
||||
CHECK(sim.isBuildingUnlocked(BuildingType::Miner));
|
||||
}
|
||||
|
||||
TEST_CASE("UnlockGroup: the drop option lists every granted item", "[unlock_group]")
|
||||
{
|
||||
Simulation sim(configWithSalvageGroup(0));
|
||||
killEnemyStations(sim); // level 0
|
||||
REQUIRE(sim.hasSchematicChoicesPending());
|
||||
|
||||
const std::vector<SchematicChoiceOption>& options = sim.getPendingSchematicChoices();
|
||||
const auto it = std::find_if(options.begin(), options.end(),
|
||||
[](const SchematicChoiceOption& o) { return o.unlockGroupId == "salvage_operations"; });
|
||||
REQUIRE(it != options.end());
|
||||
|
||||
const bool grantsModule = std::any_of(it->grantedItems.begin(), it->grantedItems.end(),
|
||||
[](const GrantedSchematic& g) { return g.type == SchematicType::Module && g.id == "salvager"; });
|
||||
const bool grantsBuilding = std::any_of(it->grantedItems.begin(), it->grantedItems.end(),
|
||||
[](const GrantedSchematic& g) { return g.type == SchematicType::Building && g.id == "salvage_bay"; });
|
||||
CHECK(grantsModule);
|
||||
CHECK(grantsBuilding);
|
||||
}
|
||||
|
||||
TEST_CASE("UnlockGroup: awarding a group unlocks the building and module at once", "[unlock_group]")
|
||||
{
|
||||
Simulation sim(configWithSalvageGroup(0));
|
||||
killEnemyStations(sim); // level 0
|
||||
REQUIRE(sim.hasSchematicChoicesPending());
|
||||
|
||||
// The only eligible group is salvage_operations, so option 0 grants it.
|
||||
REQUIRE(sim.getPendingSchematicChoices()[0].unlockGroupId == "salvage_operations");
|
||||
SimulationTestAccess::applySchematicChoice(sim, 0);
|
||||
|
||||
CHECK(sim.isBuildingUnlocked(BuildingType::SalvageBay));
|
||||
CHECK(sim.isModuleSchematicUnlocked("salvager"));
|
||||
}
|
||||
|
||||
TEST_CASE("UnlockGroup: a group above the destroyed station level is not offered", "[unlock_group]")
|
||||
{
|
||||
Simulation sim(configWithSalvageGroup(5)); // eligible only at level >= 5
|
||||
killEnemyStations(sim); // level 0 push
|
||||
// Pool is empty at level 0, so no choice dialog opens at all.
|
||||
CHECK_FALSE(sim.hasSchematicChoicesPending());
|
||||
CHECK_FALSE(sim.isBuildingUnlocked(BuildingType::SalvageBay));
|
||||
}
|
||||
|
||||
TEST_CASE("UnlockGroup: reset re-locks a previously awarded building", "[unlock_group]")
|
||||
{
|
||||
Simulation sim(configWithSalvageGroup(0));
|
||||
killEnemyStations(sim);
|
||||
REQUIRE(sim.getPendingSchematicChoices()[0].unlockGroupId == "salvage_operations");
|
||||
SimulationTestAccess::applySchematicChoice(sim, 0);
|
||||
REQUIRE(sim.isBuildingUnlocked(BuildingType::SalvageBay));
|
||||
|
||||
sim.reset();
|
||||
|
||||
CHECK_FALSE(sim.isBuildingUnlocked(BuildingType::SalvageBay));
|
||||
CHECK_FALSE(sim.isModuleSchematicUnlocked("salvager"));
|
||||
}
|
||||
Reference in New Issue
Block a user