allow to set the recipe already for construction sites
This commit is contained in:
@@ -193,18 +193,26 @@ void MainWindow::handleEvent(std::shared_ptr<const LayoutDialogRequestedEvent> e
|
||||
const double prevSpeed = m_gameWorldView->gameSpeed();
|
||||
m_gameWorldView->setGameSpeed(0.0);
|
||||
|
||||
// A construction site has no Building yet; fall back to its site record so
|
||||
// the shipyard layout can be configured before it is built (REQ-BLD-SITE-CONFIG).
|
||||
const Building* b = m_sim->buildings().findBuilding(event->shipyardId);
|
||||
if (!b)
|
||||
const ConstructionSite* s =
|
||||
b ? nullptr : m_sim->buildings().findSite(event->shipyardId);
|
||||
if (!b && !s)
|
||||
{
|
||||
m_gameWorldView->setGameSpeed(prevSpeed);
|
||||
m_gameWorldView->resetFrameTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string& schematicId = b ? b->recipeId : s->recipeId;
|
||||
const std::optional<ShipLayoutConfig>& layoutOpt =
|
||||
b ? b->shipLayout : s->shipLayout;
|
||||
|
||||
ShipLayoutConfig currentLayout;
|
||||
if (b->shipLayout.has_value())
|
||||
if (layoutOpt.has_value())
|
||||
{
|
||||
currentLayout = *b->shipLayout;
|
||||
currentLayout = *layoutOpt;
|
||||
}
|
||||
|
||||
std::set<std::string> unlockedModuleIds;
|
||||
@@ -218,7 +226,7 @@ void MainWindow::handleEvent(std::shared_ptr<const LayoutDialogRequestedEvent> e
|
||||
moduleLevels[def.id] = m_sim->moduleSchematicLevel(def.id);
|
||||
}
|
||||
|
||||
ShipLayoutDialog dialog(&m_sim->config(), b->recipeId, currentLayout,
|
||||
ShipLayoutDialog dialog(&m_sim->config(), schematicId, currentLayout,
|
||||
m_layoutBlueprints,
|
||||
std::move(unlockedModuleIds),
|
||||
std::move(moduleLevels),
|
||||
@@ -238,17 +246,22 @@ void MainWindow::handleEvent(std::shared_ptr<const RecipeSelectionRequestedEvent
|
||||
const double prevSpeed = m_gameWorldView->gameSpeed();
|
||||
m_gameWorldView->setGameSpeed(0.0);
|
||||
|
||||
// A construction site has no Building yet; fall back to its site record so
|
||||
// the recipe/schematic can be chosen before it is built (REQ-BLD-SITE-CONFIG).
|
||||
const Building* b = m_sim->buildings().findBuilding(event->buildingId);
|
||||
if (!b)
|
||||
const ConstructionSite* s =
|
||||
b ? nullptr : m_sim->buildings().findSite(event->buildingId);
|
||||
if (!b && !s)
|
||||
{
|
||||
m_gameWorldView->setGameSpeed(prevSpeed);
|
||||
m_gameWorldView->resetFrameTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
const BuildingType type = b ? b->type : s->type;
|
||||
const std::vector<RecipeSelectionOption> options =
|
||||
buildRecipeSelectionOptions(*b, *m_sim, m_sim->config());
|
||||
const QString title = (b->type == BuildingType::Shipyard)
|
||||
buildRecipeSelectionOptions(type, *m_sim, m_sim->config());
|
||||
const QString title = (type == BuildingType::Shipyard)
|
||||
? tr("Select Schematic")
|
||||
: tr("Select Recipe");
|
||||
|
||||
|
||||
@@ -88,12 +88,12 @@ QString shipTooltip(const ShipDef& def)
|
||||
} // namespace
|
||||
|
||||
std::vector<RecipeSelectionOption> buildRecipeSelectionOptions(
|
||||
const Building& building, Simulation& sim, const GameConfig& config)
|
||||
BuildingType type, Simulation& sim, const GameConfig& config)
|
||||
{
|
||||
std::vector<RecipeSelectionOption> options;
|
||||
options.push_back({std::string(), QObject::tr("(None)"), QString()});
|
||||
|
||||
if (building.type == BuildingType::Shipyard)
|
||||
if (type == BuildingType::Shipyard)
|
||||
{
|
||||
for (const ShipDef& def : config.ships.ships)
|
||||
{
|
||||
@@ -107,9 +107,9 @@ std::vector<RecipeSelectionOption> buildRecipeSelectionOptions(
|
||||
{
|
||||
for (const RecipeDef& recipe : config.recipes.recipes)
|
||||
{
|
||||
if (recipe.building != building.type) { continue; }
|
||||
if ((building.type == BuildingType::Miner
|
||||
|| building.type == BuildingType::Assembler)
|
||||
if (recipe.building != type) { continue; }
|
||||
if ((type == BuildingType::Miner
|
||||
|| type == BuildingType::Assembler)
|
||||
&& !sim.isRecipeUnlocked(recipe.id))
|
||||
{
|
||||
continue;
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
#include <QDialog>
|
||||
#include <QString>
|
||||
|
||||
struct Building;
|
||||
#include "BuildingType.h"
|
||||
|
||||
struct GameConfig;
|
||||
class Simulation;
|
||||
class QPushButton;
|
||||
@@ -21,13 +22,14 @@ struct RecipeSelectionOption
|
||||
QString tooltip;
|
||||
};
|
||||
|
||||
// Builds the lock-aware list of selectable options for a production building,
|
||||
// with display captions and info tooltips (REQ-UI-SELECT-BUTTON,
|
||||
// REQ-UI-SELECT-TOOLTIP). The first entry is always a "(None)" option with an
|
||||
// empty id. Shared by the selection dialog and the panel selection button so
|
||||
// both render identical captions and tooltips.
|
||||
// Builds the lock-aware list of selectable options for a production building
|
||||
// of the given type, with display captions and info tooltips
|
||||
// (REQ-UI-SELECT-BUTTON, REQ-UI-SELECT-TOOLTIP). The first entry is always a
|
||||
// "(None)" option with an empty id. Shared by the selection dialog and the
|
||||
// panel selection button so both render identical captions and tooltips, and
|
||||
// usable for construction sites which have no Building yet (REQ-BLD-SITE-CONFIG).
|
||||
std::vector<RecipeSelectionOption> buildRecipeSelectionOptions(
|
||||
const Building& building, Simulation& sim, const GameConfig& config);
|
||||
BuildingType type, Simulation& sim, const GameConfig& config);
|
||||
|
||||
// Modal dialog showing a grid of option buttons (REQ-UI-SELECT-BUTTON). The
|
||||
// game is paused by the caller while it is open. Clicking an option selects it
|
||||
|
||||
@@ -237,62 +237,40 @@ void SelectedBuildingPanel::buildSingle(BuildingId id)
|
||||
m_singleBuildingId = id;
|
||||
hideAllWidgets();
|
||||
|
||||
const Building* b = m_sim->buildings().findBuilding(id);
|
||||
if (!b)
|
||||
const Building* b = m_sim->buildings().findBuilding(id);
|
||||
const ConstructionSite* s = b ? nullptr : m_sim->buildings().findSite(id);
|
||||
if (!b && !s)
|
||||
{
|
||||
const ConstructionSite* s = m_sim->buildings().findSite(id);
|
||||
if (!s)
|
||||
{
|
||||
buildEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
QString progress;
|
||||
if (s->completesAt == 0)
|
||||
{
|
||||
progress = tr("Queued");
|
||||
}
|
||||
else
|
||||
{
|
||||
const BuildingDef* def = nullptr;
|
||||
for (const BuildingDef& d : m_config->buildings.buildings)
|
||||
{
|
||||
if (d.type == s->type) { def = &d; break; }
|
||||
}
|
||||
if (def && def->constructionTimeSeconds > 0)
|
||||
{
|
||||
const Tick duration = secondsToTicks(def->constructionTimeSeconds);
|
||||
const Tick elapsed = m_sim->currentTick() - (s->completesAt - duration);
|
||||
const int pct = static_cast<int>(
|
||||
std::max(Tick(0), std::min(duration, elapsed)) * 100 / duration);
|
||||
progress = tr("%1% complete").arg(pct);
|
||||
}
|
||||
else
|
||||
{
|
||||
progress = tr("Building...");
|
||||
}
|
||||
}
|
||||
|
||||
m_titleLabel->setText(tr("(Building) %1").arg(buildingTypeName(s->type)));
|
||||
m_titleLabel->show();
|
||||
m_buffersLabel->setText(progress);
|
||||
m_buffersLabel->show();
|
||||
buildEmpty();
|
||||
return;
|
||||
}
|
||||
m_singleIsSite = (s != nullptr);
|
||||
|
||||
m_titleLabel->setText(buildingTypeName(b->type));
|
||||
// A construction site exposes the same configuration as the operational
|
||||
// building it will become (REQ-BLD-SITE-CONFIG). The only difference is
|
||||
// that its buffer/production rows are replaced by a construction-progress
|
||||
// line, since a site has no buffers and runs no production cycle.
|
||||
const BuildingType type = b ? b->type : s->type;
|
||||
const std::string& recipeId = b ? b->recipeId : s->recipeId;
|
||||
const std::optional<ShipLayoutConfig>& shipLayout =
|
||||
b ? b->shipLayout : s->shipLayout;
|
||||
const QPoint anchor = b ? b->anchor : s->anchor;
|
||||
|
||||
m_titleLabel->setText(m_singleIsSite
|
||||
? tr("(Building) %1").arg(buildingTypeName(type))
|
||||
: buildingTypeName(type));
|
||||
m_titleLabel->show();
|
||||
m_buffersLabel->show();
|
||||
|
||||
if (isProductionBuilding(b->type))
|
||||
if (isProductionBuilding(type))
|
||||
{
|
||||
const std::vector<RecipeSelectionOption> options =
|
||||
buildRecipeSelectionOptions(*b, *m_sim, *m_config);
|
||||
buildRecipeSelectionOptions(type, *m_sim, *m_config);
|
||||
|
||||
const RecipeSelectionOption* current = nullptr;
|
||||
for (const RecipeSelectionOption& option : options)
|
||||
{
|
||||
if (option.id == b->recipeId)
|
||||
if (option.id == recipeId)
|
||||
{
|
||||
current = &option;
|
||||
break;
|
||||
@@ -306,7 +284,7 @@ void SelectedBuildingPanel::buildSingle(BuildingId id)
|
||||
}
|
||||
else
|
||||
{
|
||||
const QString placeholder = (b->type == BuildingType::Shipyard)
|
||||
const QString placeholder = (type == BuildingType::Shipyard)
|
||||
? tr("Select schematic")
|
||||
: tr("Select recipe");
|
||||
m_recipeSelectButton->setText(placeholder);
|
||||
@@ -314,15 +292,15 @@ void SelectedBuildingPanel::buildSingle(BuildingId id)
|
||||
}
|
||||
m_recipeSelectButton->show();
|
||||
|
||||
if (b->type == BuildingType::Shipyard && !b->recipeId.empty())
|
||||
if (type == BuildingType::Shipyard && !recipeId.empty())
|
||||
{
|
||||
const ShipDef* sDef = findShipDef(b->recipeId);
|
||||
const ShipDef* sDef = findShipDef(recipeId);
|
||||
if (sDef && !sDef->layout.empty())
|
||||
{
|
||||
ShipLayoutConfig layout;
|
||||
if (b->shipLayout.has_value())
|
||||
if (shipLayout.has_value())
|
||||
{
|
||||
layout = *b->shipLayout;
|
||||
layout = *shipLayout;
|
||||
}
|
||||
m_layoutPreview->setShipAndLayout(
|
||||
sDef->layout, layout, &m_config->modules.modules);
|
||||
@@ -348,7 +326,9 @@ void SelectedBuildingPanel::buildSingle(BuildingId id)
|
||||
m_configureLayoutBtn->hide();
|
||||
}
|
||||
|
||||
if (isBeltLike(b->type))
|
||||
// Belt "Clear" removes items from a live belt tile; a construction site has
|
||||
// none and is not registered with BeltSystem yet, so hide it for sites.
|
||||
if (isBeltLike(type) && !m_singleIsSite)
|
||||
{
|
||||
m_clearBeltBtn->show();
|
||||
}
|
||||
@@ -357,10 +337,19 @@ void SelectedBuildingPanel::buildSingle(BuildingId id)
|
||||
m_clearBeltBtn->hide();
|
||||
}
|
||||
|
||||
if (b->type == BuildingType::Splitter)
|
||||
if (type == BuildingType::Splitter)
|
||||
{
|
||||
m_splitterTile = b->anchor;
|
||||
buildSplitterFilters(m_splitterTile);
|
||||
std::optional<BeltSystem::SplitterInfo> info;
|
||||
if (m_singleIsSite)
|
||||
{
|
||||
info = m_sim->buildings().getSiteSplitterInfo(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_splitterTile = anchor;
|
||||
info = m_sim->belts().getSplitterInfo(m_splitterTile);
|
||||
}
|
||||
buildSplitterFilters(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -370,7 +359,39 @@ void SelectedBuildingPanel::buildSingle(BuildingId id)
|
||||
m_filterBList->hide();
|
||||
}
|
||||
|
||||
refreshBuffers(b);
|
||||
if (m_singleIsSite)
|
||||
{
|
||||
QString progress;
|
||||
if (s->completesAt == 0)
|
||||
{
|
||||
progress = tr("Queued");
|
||||
}
|
||||
else
|
||||
{
|
||||
const BuildingDef* def = nullptr;
|
||||
for (const BuildingDef& d : m_config->buildings.buildings)
|
||||
{
|
||||
if (d.type == s->type) { def = &d; break; }
|
||||
}
|
||||
if (def && def->constructionTimeSeconds > 0)
|
||||
{
|
||||
const Tick duration = secondsToTicks(def->constructionTimeSeconds);
|
||||
const Tick elapsed = m_sim->currentTick() - (s->completesAt - duration);
|
||||
const int pct = static_cast<int>(
|
||||
std::max(Tick(0), std::min(duration, elapsed)) * 100 / duration);
|
||||
progress = tr("%1% complete").arg(pct);
|
||||
}
|
||||
else
|
||||
{
|
||||
progress = tr("Building...");
|
||||
}
|
||||
}
|
||||
m_buffersLabel->setText(progress);
|
||||
}
|
||||
else
|
||||
{
|
||||
refreshBuffers(b);
|
||||
}
|
||||
}
|
||||
|
||||
void SelectedBuildingPanel::refreshBuffers(const Building* b)
|
||||
@@ -632,10 +653,9 @@ void SelectedBuildingPanel::onSelectRecipeClicked()
|
||||
rebuild();
|
||||
}
|
||||
|
||||
void SelectedBuildingPanel::buildSplitterFilters(QPoint splitterTile)
|
||||
void SelectedBuildingPanel::buildSplitterFilters(
|
||||
const std::optional<BeltSystem::SplitterInfo>& info)
|
||||
{
|
||||
const std::optional<BeltSystem::SplitterInfo> info =
|
||||
m_sim->belts().getSplitterInfo(splitterTile);
|
||||
if (!info.has_value())
|
||||
{
|
||||
m_filterALabel->hide();
|
||||
@@ -698,10 +718,20 @@ void SelectedBuildingPanel::onSplitterFilterChanged()
|
||||
return filter;
|
||||
};
|
||||
|
||||
m_sim->belts().setSplitterFilters(
|
||||
m_splitterTile,
|
||||
collectFilter(m_filterAList),
|
||||
collectFilter(m_filterBList));
|
||||
if (m_singleIsSite)
|
||||
{
|
||||
m_sim->buildings().setSiteSplitterFilters(
|
||||
m_singleBuildingId,
|
||||
collectFilter(m_filterAList),
|
||||
collectFilter(m_filterBList));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sim->belts().setSplitterFilters(
|
||||
m_splitterTile,
|
||||
collectFilter(m_filterAList),
|
||||
collectFilter(m_filterBList));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> SelectedBuildingPanel::allItemIds() const
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "entt/entity/entity.hpp"
|
||||
|
||||
#include "BeltSystem.h"
|
||||
#include "Building.h"
|
||||
#include "BuildingId.h"
|
||||
#include "DebugDrawToggledEvent.h"
|
||||
@@ -63,7 +64,7 @@ private:
|
||||
void buildSingle(BuildingId id);
|
||||
void buildMulti(const std::vector<BuildingId>& ids);
|
||||
void refreshBuffers(const Building* b);
|
||||
void buildSplitterFilters(QPoint splitterTile);
|
||||
void buildSplitterFilters(const std::optional<BeltSystem::SplitterInfo>& info);
|
||||
const RecipeDef* findRecipe(const Building* b) const;
|
||||
const ShipDef* findShipDef(const std::string& id) const;
|
||||
std::vector<std::string> allItemIds() const;
|
||||
@@ -86,6 +87,7 @@ private:
|
||||
QPushButton* m_configureLayoutBtn;
|
||||
|
||||
BuildingId m_singleBuildingId;
|
||||
bool m_singleIsSite = false; // selected single entity is a construction site
|
||||
QPoint m_splitterTile;
|
||||
std::string m_currentRecipeId;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user