170 lines
5.3 KiB
C++
170 lines
5.3 KiB
C++
#include "MainWindow.h"
|
|
|
|
#include <QApplication>
|
|
#include <QHBoxLayout>
|
|
#include <QMessageBox>
|
|
#include <QPushButton>
|
|
#include <QResizeEvent>
|
|
#include <QVBoxLayout>
|
|
|
|
#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<EntityId>)),
|
|
m_selectedBuildingPanel, SLOT(onSelectionChanged(std::vector<EntityId>)));
|
|
|
|
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<int>(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();
|
|
}
|
|
}
|