/*************************************************************************** * Copyright (C) 2008 by Oliver Groß * * z.o.gross@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "constants.h" #include "cgamewindow.h" #include "ccrossfieldwidget.h" #include "cnewgamedialog.h" #include "chighscore.h" namespace qcross { using namespace libqnono; //public CGameWindow::CGameWindow(QWidget * parent) : QMainWindow(parent) { m_Highscore = NULL; m_PictureIndex = -1; m_Picture = NULL; // CNonogram * dummyPic = new CNonogram(QSize(10, 10)); // dummyPic->updateNumbers(); m_Field = new CCrossFieldWidget(NULL, this); // m_Field->setTime(42 * 60 + 23); setCentralWidget(m_Field); m_Field->showMessage(tr("Welcome to QCross!")); createActions(); // statusBar()->show(); m_Solver = new CNonogramSolver(this); connect(m_Solver, SIGNAL(markRequested(int, int, int)), m_Field, SLOT(mark(int, int, int))); connect(m_Field, SIGNAL(solved()), this, SLOT(wonGame())); connect(m_Field, SIGNAL(timeUp()), this, SLOT(lostGame())); connect(m_Field, SIGNAL(markError()), this, SLOT(handleErrorMark())); } CGameWindow::~CGameWindow() { m_Field->setPicture(NULL); delete m_Picture; } //protected void CGameWindow::createActions() { QToolBar * currentToolBar; QMenu * currentMenu; //Game currentMenu = menuBar()->addMenu(tr("&Game")); currentMenu->addAction(tr("&New..."), this, SLOT(newGame()), Qt::CTRL + Qt::Key_N); currentMenu->addSeparator(); m_SaveGameAction = currentMenu->addAction(tr("&Save..."), this, SLOT(saveGame()), Qt::CTRL + Qt::Key_N); m_SaveGameAction->setEnabled(false); currentMenu->addAction(tr("&Load..."), this, SLOT(loadGame()), Qt::CTRL + Qt::Key_N); currentMenu->addSeparator(); m_RestartGameAction = currentMenu->addAction(tr("&Restart"), this, SLOT(restartGame()), Qt::CTRL + Qt::Key_R); m_RestartGameAction->setEnabled(false); m_PauseGameAction = currentMenu->addAction(tr("&Pause")); m_PauseGameAction->setEnabled(false); m_PauseGameAction->setCheckable(true); m_PauseGameAction->setShortcut(Qt::CTRL + Qt::Key_P); connect(m_PauseGameAction, SIGNAL(toggled(bool)), this, SLOT(pauseGame(bool))); currentMenu->addSeparator(); currentMenu->addAction(tr("&Quit"), this, SLOT(close()), Qt::CTRL + Qt::Key_Q); currentMenu->addSeparator(); currentMenu->addAction(tr("debug: solve"), this, SLOT(startSolver())); currentToolBar = addToolBar(currentMenu->title()); currentToolBar->addActions(currentMenu->actions()); //Help currentMenu = menuBar()->addMenu(tr("&Help")); currentMenu->addAction(tr("&About"), this, SLOT(about())); currentMenu->addAction(tr("About &Qt"), qApp, SLOT(aboutQt())); } const char magicSaveGameHeader[] = {'C', 'R', 'S', 'V'}; bool CGameWindow::readSaveGame(QDataStream & stream) { QString stringBuffer; qint32 intBuffer; QSize sizeBuffer; // picture index stream >> intBuffer; qDebug("picture index = %i", m_PictureIndex); if (stream.atEnd()) { qCritical("invalid savegame"); return false; } m_PictureIndex = intBuffer; // package name if (m_PictureIndex > -1) { stream >> stringBuffer; qDebug("package name = %s", qPrintable(stringBuffer)); if (stream.atEnd()) { qCritical("invalid savegame"); return false; } m_PackageName = stringBuffer; stream >> stringBuffer; qDebug("highscoreFileName = %s", qPrintable(stringBuffer)); if (stream.atEnd()) { qCritical("invalid savegame"); return false; } if (m_Highscore) delete m_Highscore; m_Highscore = new CHighscore(0); m_Highscore->setFileName(QCROSS_STRING_DATAPATH + QDir::separator() + stringBuffer); m_Highscore->open(); } // picture if (m_Picture) delete m_Picture; m_Picture = new CNonogram(); if (!m_Picture->readFromStream(stream)) { qCritical("invalid savegame"); return false; } // TODO handle save game porting properly // TODO check for matching nonogram m_Field->setPicture(m_Picture); m_Field->applyState(stream); return true; } void CGameWindow::writeSaveGame(QDataStream & stream) { // picture index stream << qint32(m_PictureIndex); if (m_PictureIndex > -1) { stream << m_PackageName; stream << m_Highscore->fileName().section(QDir::separator(), -1); } m_Picture->writeToStream(stream); m_Field->dumpState(stream); } void CGameWindow::newGame() { bool notPaused = !m_Field->isPaused(); if (notPaused) m_Field->pause(); CNewGameDialog dialog; if (dialog.exec() == QDialog::Accepted) { if (m_Highscore) delete m_Highscore; m_Highscore = dialog.takeHighscore(); m_PackageName = dialog.selectedPackageName(); m_PictureIndex = m_Highscore ? dialog.nonogramIndex() : -1; CNonogram * newPicture = dialog.takeNonogram(); newPicture->updateNumbers(); m_SaveGameAction->setEnabled(true); m_PauseGameAction->setEnabled(true); m_RestartGameAction->setEnabled(true); m_Field->setPicture(newPicture); if (m_Picture) delete m_Picture; m_Picture = newPicture; m_Field->resume(); m_Field->showMessage(tr("Game started!"), 1000); } if (m_Picture && !m_PauseGameAction->isChecked()) m_Field->resume(); } void CGameWindow::saveGame() { if (!m_Picture) return; if (!m_Field->isPaused()) m_Field->pause(); QString fileName = QFileDialog::getSaveFileName(this, tr("Save current game"), QDir::homePath(), tr("QCross Saved games (*.csg)")); qDebug("saving game state file: %s", fileName.toAscii().data()); QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) return; QDataStream out(&file); out.setVersion(QDataStream::Qt_4_0); if (out.writeRawData(magicSaveGameHeader, 4) == -1) qDebug("could not write magic save game header"); else writeSaveGame(out); if(!m_PauseGameAction->isChecked()) m_Field->resume(); } void CGameWindow::loadGame() { if (!m_Field->isPaused()) m_Field->pause(); QString fileName = QFileDialog::getOpenFileName(this, tr("Open saved game"), QDir::homePath(), tr("QCross Saved games (*.csg)")); qDebug("opening game state file: %s", fileName.toAscii().data()); QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) return; QDataStream in(&file); in.setVersion(QDataStream::Qt_4_0); char magicHeader[4]; in.readRawData(magicHeader, 4); qDebug("checking magic savegame header"); for (int i = 0; i < 4; i++) { if (magicHeader[i] != magicSaveGameHeader[i]) return; } if (readSaveGame(in)) { m_PauseGameAction->setEnabled(true); m_PauseGameAction->setChecked(m_Field->isPaused()); m_SaveGameAction->setEnabled(true); } else { m_Field->setPicture(NULL); m_PictureIndex = -1; if (m_Picture) { delete m_Picture; m_Picture = NULL; } if (m_Highscore) { delete m_Highscore; m_Highscore = NULL; } } if (m_Picture && !m_PauseGameAction->isChecked()) m_Field->resume(); } void CGameWindow::restartGame() { m_Field->setTime(m_Picture->timeout()); m_PauseGameAction->setChecked(false); m_Field->start(); m_Field->showMessage(tr("Game restarted."), 1000); } void CGameWindow::pauseGame(bool value) { if (value == m_Field->isPaused()) return; if (value) { m_Field->pause(); m_Field->showMessage(tr("Game paused.")); } else { m_Field->showMessage(tr("Game resumed."), 1000); m_Field->resume(); } } void CGameWindow::wonGame() { m_PauseGameAction->setEnabled(false); m_Field->showMessage(tr("Congratulations! You've solved the puzzle.")); if (m_Highscore) { qDebug("attempting to save highscore"); (*m_Highscore)[m_PictureIndex] = m_Field->time(); m_Highscore->save(); } } void CGameWindow::lostGame() { m_PauseGameAction->setEnabled(false); m_Field->showMessage(tr("Too bad! Time's up."), 0, CCrossFieldWidget::Critical); } void CGameWindow::handleErrorMark() { int timeDiff = (m_Field->errorCount() == 1) ? 2 : ((m_Field->errorCount() == 2) ? 4 : 8); m_Field->showMessage(tr("Sorry this was not correct: -%1min").arg(timeDiff), 1000, CCrossFieldWidget::Warning); m_Field->setTime(m_Field->time() - timeDiff*60); } void CGameWindow::about() { QMessageBox::about(this, tr("About"), tr("This is a still unfancy gui for solving nonograms.")); } void CGameWindow::startSolver() { m_Solver->setNonogram(m_Picture); restartGame(); m_Solver->solve(); } }