Allow creating blueprints from construction sites
This commit is contained in:
@@ -1,10 +1,55 @@
|
||||
#include "BuildingConfig.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
|
||||
#include "BeltSystem.h"
|
||||
#include "Building.h"
|
||||
#include "BuildingSystem.h"
|
||||
#include "Simulation.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
// The blueprint-relevant geometry shared by operational buildings and construction
|
||||
// sites. Resolved from whichever of the two a selected id refers to.
|
||||
struct SelectedBuilding
|
||||
{
|
||||
BuildingId id;
|
||||
BuildingType type;
|
||||
Rotation rotation;
|
||||
QPoint anchor;
|
||||
const std::vector<QPoint>* bodyCells;
|
||||
};
|
||||
|
||||
// Resolves a selected id to a player-placeable building or construction site, if it
|
||||
// is one. Returns std::nullopt for an unknown id or a non-player-placeable building
|
||||
// (the HQ and defence stations, per REQ-UI-BLUEPRINT-CREATE).
|
||||
std::optional<SelectedBuilding> resolvePlaceable(const Simulation& sim, BuildingId id)
|
||||
{
|
||||
const Building* building = sim.buildings().findBuilding(id);
|
||||
const ConstructionSite* site = building ? nullptr : sim.buildings().findSite(id);
|
||||
if (!building && !site)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const BuildingType type = building ? building->type : site->type;
|
||||
const BuildingDef* def = sim.config().buildings.findBuildingDef(type);
|
||||
if (!def || !def->playerPlaceable)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
SelectedBuilding resolved;
|
||||
resolved.id = id;
|
||||
resolved.type = type;
|
||||
resolved.rotation = building ? building->rotation : site->rotation;
|
||||
resolved.anchor = building ? building->anchor : site->anchor;
|
||||
resolved.bodyCells = building ? &building->bodyCells : &site->bodyCells;
|
||||
return resolved;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::optional<BuildingConfig> readBuildingConfig(const Simulation& sim, BuildingId id)
|
||||
{
|
||||
const Building* building = sim.buildings().findBuilding(id);
|
||||
@@ -49,3 +94,74 @@ std::optional<BuildingConfig> readBuildingConfig(const Simulation& sim, Building
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
Blueprint captureBlueprintFromSelection(const Simulation& sim,
|
||||
const std::vector<BuildingId>& selectedIds)
|
||||
{
|
||||
std::vector<SelectedBuilding> entries;
|
||||
entries.reserve(selectedIds.size());
|
||||
for (const BuildingId id : selectedIds)
|
||||
{
|
||||
const std::optional<SelectedBuilding> resolved = resolvePlaceable(sim, id);
|
||||
if (resolved.has_value())
|
||||
{
|
||||
entries.push_back(*resolved);
|
||||
}
|
||||
}
|
||||
|
||||
if (entries.empty())
|
||||
{
|
||||
return Blueprint{};
|
||||
}
|
||||
|
||||
int minX = INT_MAX, maxX = INT_MIN;
|
||||
int minY = INT_MAX, maxY = INT_MIN;
|
||||
for (const SelectedBuilding& e : entries)
|
||||
{
|
||||
for (const QPoint& cell : *e.bodyCells)
|
||||
{
|
||||
minX = std::min(minX, cell.x());
|
||||
maxX = std::max(maxX, cell.x());
|
||||
minY = std::min(minY, cell.y());
|
||||
maxY = std::max(maxY, cell.y());
|
||||
}
|
||||
}
|
||||
|
||||
const QPoint center((minX + maxX) / 2, (minY + maxY) / 2);
|
||||
|
||||
Blueprint blueprint;
|
||||
blueprint.buildings.reserve(entries.size());
|
||||
for (const SelectedBuilding& e : entries)
|
||||
{
|
||||
BlueprintBuilding building;
|
||||
building.type = e.type;
|
||||
building.rotation = e.rotation;
|
||||
building.offset = e.anchor - center;
|
||||
// Recipe / schematic / layout / splitter-filter capture is shared with the
|
||||
// copy-settings gesture (REQ-BLD-COPY-CONFIG) via readBuildingConfig, which
|
||||
// handles operational buildings and construction sites alike.
|
||||
const std::optional<BuildingConfig> config = readBuildingConfig(sim, e.id);
|
||||
if (config.has_value())
|
||||
{
|
||||
building.recipeId = config->recipeId.value_or(std::string());
|
||||
building.shipLayout = config->shipLayout;
|
||||
building.splitterFilterA = config->splitterFilterA;
|
||||
building.splitterFilterB = config->splitterFilterB;
|
||||
}
|
||||
blueprint.buildings.push_back(building);
|
||||
}
|
||||
return blueprint;
|
||||
}
|
||||
|
||||
bool selectionHasPlaceableBuilding(const Simulation& sim,
|
||||
const std::vector<BuildingId>& selectedIds)
|
||||
{
|
||||
for (const BuildingId id : selectedIds)
|
||||
{
|
||||
if (resolvePlaceable(sim, id).has_value())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user