#include "ShipyardContent.h" #include #include #include "BuildingTarget.h" #include "EventManager.h" #include "GameConfig.h" #include "LayoutDialogRequestedEvent.h" #include "ProductionRules.h" #include "RecipeSelectionControl.h" #include "SectionBox.h" #include "ShipLayoutPreview.h" ShipyardContent::ShipyardContent(const SelectionContext& context, const SelectionRequest& request, QWidget* parent) : BufferedBuildingContent(context, request.buildings.front(), parent) { m_schematicControl = new RecipeSelectionControl(context, getBuildingId(), BuildingType::Shipyard, this); m_layoutSection = new SectionBox(tr("Layout"), this); m_layoutPreview = new ShipLayoutPreview(m_layoutSection); m_configureButton = new QPushButton(tr("Configure Layout"), m_layoutSection); m_layoutSection->getContentLayout()->addWidget(m_layoutPreview); m_layoutSection->getContentLayout()->addWidget(m_configureButton); // Ahead of the recipe summary the base adds, so the card reads schematic, layout, // then what one ship costs. getConfigurationLayout()->insertWidget(0, m_schematicControl); getConfigurationLayout()->insertWidget(1, m_layoutSection); const BuildingId id = getBuildingId(); connect(m_configureButton, &QPushButton::clicked, this, [id]() { EventManager::getInstance()->sendEventImmediately( std::make_shared(id)); }); } void ShipyardContent::refreshControls(const BuildingTarget& target) { m_schematicControl->setRecipeId(target.recipeId); // The preview and Configure button are always shown for a shipyard and are only // enabled once a schematic is selected (REQ-MOD-UI-PREVIEW). The schematic arrives // by queued command, so this refresh is what picks it up rather than the click that // chose it. const ShipDef* shipDef = target.recipeId.empty() ? nullptr : getContext().config->ships.findShipDef(target.recipeId); const bool hasSchematic = shipDef && !shipDef->layout.empty(); if (hasSchematic) { m_layoutPreview->setShipAndLayout( shipDef->layout, target.shipLayout.has_value() ? *target.shipLayout : ShipLayoutConfig(), &getContext().config->modules); } else { m_layoutPreview->showPlaceholder(); } m_layoutPreview->setEnabled(hasSchematic); m_configureButton->setEnabled(hasSchematic); } BufferedBuildingContent::CycleInfo ShipyardContent::getCycleInfo( const BuildingTarget& target) const { CycleInfo info; const ShipDef* shipDef = target.recipeId.empty() ? nullptr : getContext().config->ships.findShipDef(target.recipeId); if (!shipDef) { return info; } // The schematic's materials plus every placed module's, which is also what sized the // input buffers (REQ-BLD-SHIPYARD). The simulation owns that sum, so the panel asks // it rather than adding the modules up a second time. info.perCycleInputs = computeShipyardRequiredMaterials( *getContext().config, target.recipeId, target.shipLayout); // A shipyard's output is the ship itself, which never lands in an item buffer -- so // the summary shows one ship rather than an item id. info.durationSeconds = shipDef->schematic.productionTimeSeconds; if (target.shipLayout.has_value()) { for (const PlacedModule& placed : target.shipLayout->placedModules) { const ModuleDef* moduleDef = getContext().config->modules.findModuleDef(placed.moduleId); if (moduleDef) { info.durationSeconds += moduleDef->productionTimeSeconds; } } } info.runsProduction = true; return info; }