Add building status light
This commit is contained in:
@@ -1308,3 +1308,116 @@ TEST_CASE("BuildingSystem: splitter filters configured on a construction site ca
|
||||
REQUIRE(builtInfo->filterA == filterA);
|
||||
REQUIRE(builtInfo->filterB.empty());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Production status classifier (REQ-UI-STATUS-LIGHT)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("BuildingSystem: getProductionStatus classifies production state", "[building]")
|
||||
{
|
||||
PlacementFixture f;
|
||||
|
||||
// Pick representative config ids so the test survives content edits.
|
||||
std::string minerRecipeId;
|
||||
for (const RecipeDef& r : f.cfg.recipes.recipes)
|
||||
{
|
||||
if (r.building == BuildingType::Miner) { minerRecipeId = r.id; break; }
|
||||
}
|
||||
REQUIRE_FALSE(minerRecipeId.empty());
|
||||
|
||||
const RecipeDef* assemblerRecipe = nullptr;
|
||||
for (const RecipeDef& r : f.cfg.recipes.recipes)
|
||||
{
|
||||
if (r.building == BuildingType::Assembler && !r.inputs.empty())
|
||||
{
|
||||
assemblerRecipe = &r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
REQUIRE(assemblerRecipe != nullptr);
|
||||
|
||||
std::string shipId;
|
||||
for (const ShipDef& s : f.cfg.ships.ships)
|
||||
{
|
||||
if (!s.schematic.materials.empty()) { shipId = s.id; break; }
|
||||
}
|
||||
REQUIRE_FALSE(shipId.empty());
|
||||
|
||||
const auto statusOf = [&f](const Building& b) { return f.bs.getProductionStatus(b); };
|
||||
|
||||
SECTION("non-production buildings show no status light")
|
||||
{
|
||||
Building belt; belt.type = BuildingType::Belt;
|
||||
Building hq; hq.type = BuildingType::Hq;
|
||||
REQUIRE_FALSE(statusOf(belt).has_value());
|
||||
REQUIRE_FALSE(statusOf(hq).has_value());
|
||||
}
|
||||
|
||||
SECTION("Miner: unconfigured, producing, output-blocked")
|
||||
{
|
||||
Building miner; miner.type = BuildingType::Miner;
|
||||
REQUIRE(statusOf(miner) == ProductionStatus::Unconfigured); // no recipe -> grey
|
||||
|
||||
miner.recipeId = minerRecipeId;
|
||||
miner.production = Production{};
|
||||
REQUIRE(statusOf(miner) == ProductionStatus::Producing); // active cycle -> green
|
||||
|
||||
// A miner has no inputs, so its only idle reason is a full output buffer.
|
||||
miner.production = std::nullopt;
|
||||
miner.outputBuffer.capacity = 2;
|
||||
miner.outputBuffer.items = { makeItem("iron_ore"), makeItem("iron_ore") };
|
||||
REQUIRE(statusOf(miner) == ProductionStatus::Blocked); // -> yellow
|
||||
}
|
||||
|
||||
SECTION("Assembler: starved vs blocked, input-missing takes precedence")
|
||||
{
|
||||
Building assembler; assembler.type = BuildingType::Assembler;
|
||||
assembler.recipeId = assemblerRecipe->id;
|
||||
|
||||
// Idle with inputs missing -> red.
|
||||
REQUIRE(statusOf(assembler) == ProductionStatus::Starved);
|
||||
|
||||
// Inputs present but idle -> the only remaining reason is a full output
|
||||
// buffer -> yellow.
|
||||
for (const RecipeIngredient& ing : assemblerRecipe->inputs)
|
||||
{
|
||||
assembler.inputBuffer.counts[ItemType{ing.item}] = ing.amount;
|
||||
}
|
||||
REQUIRE(statusOf(assembler) == ProductionStatus::Blocked);
|
||||
|
||||
// Inputs missing AND output full -> red wins over yellow.
|
||||
assembler.inputBuffer.counts.clear();
|
||||
assembler.outputBuffer.capacity = 2;
|
||||
assembler.outputBuffer.items = { makeItem("x"), makeItem("x") };
|
||||
REQUIRE(statusOf(assembler) == ProductionStatus::Starved);
|
||||
}
|
||||
|
||||
SECTION("Smelter (auto-recipe) is never grey")
|
||||
{
|
||||
Building smelter; smelter.type = BuildingType::Smelter;
|
||||
// No player-selectable recipe and empty inputs -> red, not grey.
|
||||
REQUIRE(statusOf(smelter) == ProductionStatus::Starved);
|
||||
}
|
||||
|
||||
SECTION("Shipyard: unconfigured, then starved without materials, then producing")
|
||||
{
|
||||
Building yard; yard.type = BuildingType::Shipyard;
|
||||
REQUIRE(statusOf(yard) == ProductionStatus::Unconfigured); // no schematic -> grey
|
||||
|
||||
yard.recipeId = shipId;
|
||||
REQUIRE(statusOf(yard) == ProductionStatus::Starved); // no materials -> red
|
||||
|
||||
yard.production = Production{};
|
||||
REQUIRE(statusOf(yard) == ProductionStatus::Producing); // active cycle -> green
|
||||
}
|
||||
|
||||
SECTION("Salvage Bay: red when empty, green when holding scrap")
|
||||
{
|
||||
Building bay; bay.type = BuildingType::SalvageBay;
|
||||
bay.outputBuffer.capacity = 20;
|
||||
REQUIRE(statusOf(bay) == ProductionStatus::Starved); // empty -> red
|
||||
|
||||
bay.outputBuffer.items = { makeItem("scrap") };
|
||||
REQUIRE(statusOf(bay) == ProductionStatus::Producing); // holding scrap -> green
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user