implement ignore non-buildable buildings for blueprints
This commit is contained in:
@@ -143,6 +143,28 @@ static GameConfig loadConfig()
|
|||||||
return ConfigLoader::loadFromDirectory(DOTA_FACTORY_CONFIG_DIR);
|
return ConfigLoader::loadFromDirectory(DOTA_FACTORY_CONFIG_DIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mirrors BlueprintPanel::createBlueprintFromSelection's player-placeable filter:
|
||||||
|
// building types absent from buildings.toml (HQ, stations) or with playerPlaceable=false
|
||||||
|
// are silently excluded before the bounding-box center and offsets are computed.
|
||||||
|
static Blueprint buildBlueprintFiltered(const std::vector<BuildingSpec>& specs,
|
||||||
|
const GameConfig& cfg)
|
||||||
|
{
|
||||||
|
std::vector<BuildingSpec> filtered;
|
||||||
|
for (const BuildingSpec& s : specs)
|
||||||
|
{
|
||||||
|
for (const BuildingDef& def : cfg.buildings.buildings)
|
||||||
|
{
|
||||||
|
if (def.type == s.type)
|
||||||
|
{
|
||||||
|
if (def.playerPlaceable) { filtered.push_back(s); }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the type is not in buildings (e.g. Hq, defence stations), it is skipped.
|
||||||
|
}
|
||||||
|
return buildBlueprint(filtered);
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Offset computation
|
// Offset computation
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -435,6 +457,51 @@ TEST_CASE("Blueprint: CCW rotation keeps belt adjacent to miner output port", "[
|
|||||||
REQUIRE(bp.buildings[1].offset == bp.buildings[0].offset + QPoint(1, 0));
|
REQUIRE(bp.buildings[1].offset == bp.buildings[0].offset + QPoint(1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Player-placeable filter in blueprint creation
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
TEST_CASE("Blueprint creation: non-player-placeable building alone yields empty blueprint",
|
||||||
|
"[blueprint]")
|
||||||
|
{
|
||||||
|
const GameConfig cfg = loadConfig();
|
||||||
|
|
||||||
|
// Hq has no entry in buildings.toml, so it is treated as non-player-placeable.
|
||||||
|
const BuildingSpec hq{ QPoint(-5, 0), {QPoint(-5, 0)}, BuildingType::Hq, Rotation::East };
|
||||||
|
const Blueprint bp = buildBlueprintFiltered({ hq }, cfg);
|
||||||
|
|
||||||
|
REQUIRE(bp.buildings.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Blueprint creation: mixed selection keeps only player-placeable buildings",
|
||||||
|
"[blueprint]")
|
||||||
|
{
|
||||||
|
const GameConfig cfg = loadConfig();
|
||||||
|
|
||||||
|
const BuildingSpec belt{ QPoint(-5, 0), {QPoint(-5, 0)}, BuildingType::Belt, Rotation::East };
|
||||||
|
const BuildingSpec hq { QPoint(-3, 0), {QPoint(-3, 0)}, BuildingType::Hq, Rotation::East };
|
||||||
|
const Blueprint bp = buildBlueprintFiltered({ belt, hq }, cfg);
|
||||||
|
|
||||||
|
REQUIRE(bp.buildings.size() == 1);
|
||||||
|
REQUIRE(bp.buildings[0].type == BuildingType::Belt);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Blueprint creation: bounding box ignores non-player-placeable buildings",
|
||||||
|
"[blueprint]")
|
||||||
|
{
|
||||||
|
const GameConfig cfg = loadConfig();
|
||||||
|
|
||||||
|
// Belt at (-5, 0). HQ at (-3, 0) — excluded from the blueprint.
|
||||||
|
// If HQ were included: bboxX = [-5, -3], center.x = -4, belt offset = -1.
|
||||||
|
// With HQ excluded: bboxX = [-5, -5], center.x = -5, belt offset = 0.
|
||||||
|
const BuildingSpec belt{ QPoint(-5, 0), {QPoint(-5, 0)}, BuildingType::Belt, Rotation::East };
|
||||||
|
const BuildingSpec hq { QPoint(-3, 0), {QPoint(-3, 0)}, BuildingType::Hq, Rotation::East };
|
||||||
|
const Blueprint bp = buildBlueprintFiltered({ belt, hq }, cfg);
|
||||||
|
|
||||||
|
REQUIRE(bp.buildings.size() == 1);
|
||||||
|
REQUIRE(bp.buildings[0].offset == QPoint(0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Simulation-level: blueprint placement places buildings at correct tiles
|
// Simulation-level: blueprint placement places buildings at correct tiles
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -152,7 +152,15 @@ Blueprint BlueprintPanel::createBlueprintFromSelection() const
|
|||||||
for (const EntityId id : m_selectedIds)
|
for (const EntityId id : m_selectedIds)
|
||||||
{
|
{
|
||||||
const Building* b = m_sim->buildings().findBuilding(id);
|
const Building* b = m_sim->buildings().findBuilding(id);
|
||||||
if (b) { entries.push_back({ b }); }
|
if (!b) { continue; }
|
||||||
|
const bool placeable = [&]() {
|
||||||
|
for (const BuildingDef& def : m_config->buildings.buildings)
|
||||||
|
{
|
||||||
|
if (def.type == b->type) { return def.playerPlaceable; }
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}();
|
||||||
|
if (placeable) { entries.push_back({ b }); }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entries.empty()) { return Blueprint{}; }
|
if (entries.empty()) { return Blueprint{}; }
|
||||||
@@ -235,7 +243,19 @@ void BlueprintPanel::rebuildButtons()
|
|||||||
|
|
||||||
void BlueprintPanel::refreshButtonStates()
|
void BlueprintPanel::refreshButtonStates()
|
||||||
{
|
{
|
||||||
m_createBtn->setEnabled(!m_selectedIds.empty());
|
const bool anyPlaceable = [&]() {
|
||||||
|
for (const EntityId id : m_selectedIds)
|
||||||
|
{
|
||||||
|
const Building* b = m_sim->buildings().findBuilding(id);
|
||||||
|
if (!b) { continue; }
|
||||||
|
for (const BuildingDef& def : m_config->buildings.buildings)
|
||||||
|
{
|
||||||
|
if (def.type == b->type) { return def.playerPlaceable; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}();
|
||||||
|
m_createBtn->setEnabled(anyPlaceable);
|
||||||
|
|
||||||
for (int i = 0; i < static_cast<int>(m_blueprintButtons.size()); ++i)
|
for (int i = 0; i < static_cast<int>(m_blueprintButtons.size()); ++i)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user