From b7f20055048f8ddd1fc1ac4504bc70bc6a5b80b1 Mon Sep 17 00:00:00 2001 From: mlangkabel Date: Tue, 21 Apr 2026 20:38:18 +0200 Subject: [PATCH] add restart button to game over screen --- src/lib/sim/Simulation.cpp | 39 ++++++++++++++++++++++++++++++++++++++ src/lib/sim/Simulation.h | 3 +++ src/ui/GameWorldView.cpp | 21 ++++++++++++++++++++ src/ui/GameWorldView.h | 1 + src/ui/MainWindow.cpp | 13 ++++++++++++- 5 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/lib/sim/Simulation.cpp b/src/lib/sim/Simulation.cpp index 83ddbc9..16ac4f2 100644 --- a/src/lib/sim/Simulation.cpp +++ b/src/lib/sim/Simulation.cpp @@ -49,6 +49,45 @@ Simulation::Simulation(const GameConfig& config, unsigned int seed) Simulation::~Simulation() = default; +void Simulation::reset(unsigned int seed) +{ + m_rng.seed(seed); + m_currentTick = 0; + m_nextId = 1; + m_buildingBlocksStock = m_config.world.startingBuildingBlocks; + m_gameOver = false; + m_hqId = kInvalidEntityId; + m_playerStation1Id = kInvalidEntityId; + m_playerStation2Id = kInvalidEntityId; + m_currentEnemyStationIds[0] = kInvalidEntityId; + m_currentEnemyStationIds[1] = kInvalidEntityId; + m_fireEvents.clear(); + m_blueprintDropEvents.clear(); + + m_beltSystem = BeltSystem(m_config.world.beltSpeedTilesPerSecond); + m_buildingSystem = std::make_unique( + m_config, + m_beltSystem, + [this]() { return allocateId(); }, + [this](int amount) { m_buildingBlocksStock += amount; }, + m_rng); + m_shipSystem = std::make_unique(m_config, [this]() { return allocateId(); }); + m_scrapSystem = std::make_unique([this]() { return allocateId(); }); + m_waveSystem = std::make_unique(m_config, m_rng); + m_combatSystem = std::make_unique(m_config); + + m_blueprintLevels.clear(); + for (const ShipDef& def : m_config.ships.ships) + { + BlueprintState state; + state.unlocked = def.availableFromStart; + state.level = def.availableFromStart ? def.blueprint.playerProductionLevel : 0; + m_blueprintLevels[def.id] = state; + } + + placeInitialStructures(); +} + // --------------------------------------------------------------------------- // tick // --------------------------------------------------------------------------- diff --git a/src/lib/sim/Simulation.h b/src/lib/sim/Simulation.h index c076c96..eff8e01 100644 --- a/src/lib/sim/Simulation.h +++ b/src/lib/sim/Simulation.h @@ -29,6 +29,9 @@ public: explicit Simulation(const GameConfig& config, unsigned int seed = 0); ~Simulation(); + // Reinitializes all simulation state as if constructed fresh. + void reset(unsigned int seed = 0); + // Advances the simulation by one tick. Tick order per architecture.md §Tick Order. void tick(); diff --git a/src/ui/GameWorldView.cpp b/src/ui/GameWorldView.cpp index 860c25e..2492e7c 100644 --- a/src/ui/GameWorldView.cpp +++ b/src/ui/GameWorldView.cpp @@ -1121,3 +1121,24 @@ void GameWorldView::setGameSpeed(double multiplier) m_sim->buildingBlocksStock(), m_gameSpeedMultiplier); } + +void GameWorldView::resetForNewGame() +{ + exitBuilderMode(); + m_activeBeams.clear(); + m_toasts.clear(); + m_ghostRotation = Rotation::East; + m_ghostValid = false; + m_demolishMode = false; + m_demolishHoverId = kInvalidEntityId; + m_selectedIds.clear(); + m_boxSelecting = false; + m_scrollXTiles = 0.0f; + m_scrollLeft = false; + m_scrollRight = false; + m_gameOverShown = false; + m_gameSpeedMultiplier = 1.0; + m_prevNonZeroSpeed = 1.0; + emit selectionChanged({}); + update(); +} diff --git a/src/ui/GameWorldView.h b/src/ui/GameWorldView.h index 46bb6e7..1374c74 100644 --- a/src/ui/GameWorldView.h +++ b/src/ui/GameWorldView.h @@ -51,6 +51,7 @@ public slots: void enterBuilderMode(BuildingType type); void exitBuilderMode(); void setGameSpeed(double multiplier); + void resetForNewGame(); protected: void initializeGL() override; diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp index c076be0..1a2fc63 100644 --- a/src/ui/MainWindow.cpp +++ b/src/ui/MainWindow.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -106,7 +107,17 @@ void MainWindow::onGameOver() box.setText(QString("HQ destroyed!\nSurvival time: %1:%2") .arg(minutes, 2, 10, QChar('0')) .arg(seconds, 2, 10, QChar('0'))); + QPushButton* restartBtn = box.addButton("Restart", QMessageBox::AcceptRole); box.addButton("Quit", QMessageBox::RejectRole); box.exec(); - close(); + + if (box.clickedButton() == restartBtn) + { + m_sim->reset(); + m_gameWorldView->resetForNewGame(); + } + else + { + close(); + } }