#include "MainWindow.h" #include #include #include #include #include #include #include "BuildButtonGrid.h" #include "GameWorldView.h" #include "HeaderBar.h" #include "SelectedBuildingPanel.h" #include "Simulation.h" #include "Tick.h" MainWindow::MainWindow(Simulation* sim, const GameConfig* config, const VisualsConfig* visuals, QWidget* parent) : QWidget(parent) , m_sim(sim) { setWindowTitle("Dota Factory"); resize(1280, 768); m_headerBar = new HeaderBar(this); m_gameWorldView = new GameWorldView(sim, config, visuals, this); m_bottomPanel = new QWidget(this); QHBoxLayout* bottomLayout = new QHBoxLayout(m_bottomPanel); bottomLayout->setContentsMargins(0, 0, 0, 0); bottomLayout->setSpacing(0); m_selectedBuildingPanel = new SelectedBuildingPanel(sim, config, m_bottomPanel); m_buildButtonGrid = new BuildButtonGrid(config, m_bottomPanel); bottomLayout->addWidget(m_selectedBuildingPanel, 1); bottomLayout->addWidget(m_buildButtonGrid, 1); // Signals: game world → other panels connect(m_gameWorldView, SIGNAL(selectionChanged(std::vector)), m_selectedBuildingPanel, SLOT(onSelectionChanged(std::vector))); connect(m_gameWorldView, SIGNAL(stateUpdated(Tick, int, double)), m_headerBar, SLOT(onStateUpdated(Tick, int, double))); connect(m_gameWorldView, SIGNAL(stateUpdated(Tick, int, double)), this, SLOT(onStateUpdated(Tick, int, double))); // for affordability connect(m_gameWorldView, SIGNAL(stateUpdated(Tick, int, double)), m_selectedBuildingPanel, SLOT(onStateUpdated(Tick, int, double))); connect(m_gameWorldView, SIGNAL(gameOver()), this, SLOT(onGameOver())); connect(m_gameWorldView, SIGNAL(escapeMenuRequested()), this, SLOT(onEscapeMenuRequested())); // Signals: build grid → game world connect(m_buildButtonGrid, SIGNAL(buildingTypeSelected(BuildingType)), m_gameWorldView, SLOT(enterBuilderMode(BuildingType))); connect(m_buildButtonGrid, SIGNAL(builderModeExited()), m_gameWorldView, SLOT(exitBuilderMode())); connect(m_gameWorldView, SIGNAL(builderModeExited()), m_buildButtonGrid, SLOT(clearActiveButton())); connect(m_buildButtonGrid, SIGNAL(demolishModeToggleRequested()), m_gameWorldView, SLOT(toggleDemolishMode())); connect(m_gameWorldView, SIGNAL(demolishModeChanged(bool)), m_buildButtonGrid, SLOT(setDemolishModeActive(bool))); // Signals: header bar → game world connect(m_headerBar, SIGNAL(speedChanged(double)), m_gameWorldView, SLOT(setGameSpeed(double))); m_gameWorldView->setFocus(); connect(qApp, &QApplication::focusChanged, this, [this](QWidget*, QWidget* newWidget) { if (newWidget && newWidget != m_gameWorldView && !QApplication::activeModalWidget()) { m_gameWorldView->setFocus(); } }); } void MainWindow::resizeEvent(QResizeEvent* event) { QWidget::resizeEvent(event); layoutPanels(); } void MainWindow::layoutPanels() { const int totalW = width(); const int totalH = height(); const int headerH = m_headerBar->sizeHint().height(); if (headerH <= 0) { return; } const int remaining = totalH - headerH; const int gameH = remaining * 70 / 100; const int panelH = remaining - gameH; m_headerBar->setGeometry(0, 0, totalW, headerH); m_gameWorldView->setGeometry(0, headerH, totalW, gameH); m_bottomPanel->setGeometry(0, headerH + gameH, totalW, panelH); } void MainWindow::onStateUpdated(Tick /*tick*/, int blocks, double /*speed*/) { m_buildButtonGrid->updateAffordability(blocks); } void MainWindow::onEscapeMenuRequested() { const double prevSpeed = m_gameWorldView->gameSpeed(); m_gameWorldView->setGameSpeed(0.0); QMessageBox box(this); box.setWindowTitle("Paused"); QPushButton* continueBtn = box.addButton("Continue", QMessageBox::AcceptRole); QPushButton* restartBtn = box.addButton("Restart", QMessageBox::ResetRole); QPushButton* quitBtn = box.addButton("Quit", QMessageBox::DestructiveRole); box.setEscapeButton(continueBtn); box.exec(); QAbstractButton* clicked = box.clickedButton(); if (clicked == restartBtn) { m_sim->reset(); m_gameWorldView->resetForNewGame(); } else if (clicked == quitBtn) { close(); } else { m_gameWorldView->setGameSpeed(prevSpeed); } } void MainWindow::onGameOver() { const Tick tick = m_sim->currentTick(); const int totalSeconds = static_cast(ticksToSeconds(tick)); const int minutes = totalSeconds / 60; const int seconds = totalSeconds % 60; QMessageBox box(this); box.setWindowTitle("Game Over"); 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(); if (box.clickedButton() == restartBtn) { m_sim->reset(); m_gameWorldView->resetForNewGame(); } else { close(); } }