diff --git a/ktron.h b/ktron.h index 85a4e59..509350e 100644 --- a/ktron.h +++ b/ktron.h @@ -1,103 +1,103 @@ /********************************************************************************** This file is part of the game 'KTron' Copyright (C) 1998-2000 by Matthias Kiefer Copyright (C) 2005 Benjamin C. Meyer Copyright (C) 2008-2009 Stas Verberkt 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef KTRON_H #define KTRON_H #include #include #include #include "tron.h" #define ID_STATUS_BASE 40 #define MESSAGE_TIME 2000 class General; class QLabel; /** * @short The main window of KTron */ class KTron : public KXmlGuiWindow { Q_OBJECT public: - KTron(QWidget *parent=0); + KTron(QWidget *parent=nullptr); ~KTron(); private: void updateStatusbar(); protected: /** calls tron->updatePixmap to draw frame in the new colors */ void paletteChange(const QPalette &oldPalette); void closeEvent(QCloseEvent *) Q_DECL_OVERRIDE; /** Key hits */ void keyPressEvent(QKeyEvent *) Q_DECL_OVERRIDE; void keyReleaseEvent(QKeyEvent *) Q_DECL_OVERRIDE; public Q_SLOTS: void close(); private Q_SLOTS: void loadSettings(); /** updates players points in statusbar and checks if someone has won */ void changeStatus(); void updateScore(); void showSettings(); void showHighscores(); void optionsConfigureKeys(); void blockPause(bool block); // Triggers keys void triggerKey0Up(bool); void triggerKey0Down(bool); void triggerKey0Left(bool); void triggerKey0Right(bool); void triggerKey0Accelerate(bool); void triggerKey1Up(bool); void triggerKey1Down(bool); void triggerKey1Left(bool); void triggerKey1Right(bool); void triggerKey1Accelerate(bool); private: Tron *m_tron; QAction *m_player0Up; QAction *m_player0Down; QAction *m_player0Left; QAction *m_player0Right; QAction *m_player0Accelerate; QAction *m_player1Up; QAction *m_player1Down; QAction *m_player1Left; QAction *m_player1Right; QAction *m_player1Accelerate; QAction *m_pauseButton; General *m_generalConfigDialog; QLabel *m_statusBarLabel[3]; }; #endif // KTRON_H diff --git a/main.cpp b/main.cpp index 6cb6704..2aad245 100644 --- a/main.cpp +++ b/main.cpp @@ -1,95 +1,95 @@ /********************************************************************************** This file is part of the game 'KTron' Copyright (C) 1998-2000 by Matthias Kiefer Copyright (C) 2005 Benjamin C. Meyer Copyright (C) 2008-2009 Stas Verberkt 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include "ktron.h" #include "renderer.h" #include "settings.h" #include "version.h" static const char description[] = I18N_NOOP("A race in hyperspace"); static const char notice[] = I18N_NOOP("(c) 1998-2000, Matthias Kiefer\n" "(c) 2005, Benjamin Meyer\n" "(c) 2008-2009, Stas Verberkt\n" "\n" "Parts of the algorithms for the computer player are from\n" "xtron-1.1 by Rhett D. Jacobs "); int main(int argc, char* argv[]) { QApplication app(argc, argv); KLocalizedString::setApplicationDomain("ksnakeduel"); Kdelibs4ConfigMigrator migrate(QStringLiteral("ksnakeduel")); migrate.setConfigFiles(QStringList() << QStringLiteral("ksnakeduelrc")); migrate.setUiFiles(QStringList() << QStringLiteral("ksnakeduelui.rc")); migrate.migrate(); KAboutData aboutData( QStringLiteral("ksnakeduel"), i18n("KSnakeDuel"), - QLatin1String(KTRON_VERSION), i18n(description), KAboutLicense::GPL, i18n(notice)); + QStringLiteral(KTRON_VERSION), i18n(description), KAboutLicense::GPL, i18n(notice)); aboutData.addAuthor(i18n("Matthias Kiefer"), i18n("Original author"), QStringLiteral("matthias.kiefer@gmx.de")); aboutData.addAuthor(i18n("Benjamin Meyer"), i18n("Various improvements"), QStringLiteral("ben+ktron@meyerhome.net")); aboutData.addAuthor(i18n("Stas Verberkt"), i18n("KDE 4 Port, interface revision and KSnake mode"), QStringLiteral("legolas@legolasweb.nl")); QCommandLineParser parser; KAboutData::setApplicationData(aboutData); KCrash::initialize(); parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("snake"), i18n("Start in KSnake mode"))); aboutData.setupCommandLine(&parser); parser.process(app); aboutData.processCommandLine(&parser); KDBusService service; //KStandardDirs::locateLocal("appdata", QLatin1String( "themes/" )); if (parser.isSet(QStringLiteral("snake"))) { Settings::setGameType(Settings::EnumGameType::Snake); } else if (Settings::gameType() == Settings::EnumGameType::Snake) { Settings::setGameType(Settings::EnumGameType::PlayerVSComputer); } Renderer::self(); // Creates Renderer KTron *ktron = new KTron(); ktron->show(); app.setWindowIcon(QIcon::fromTheme(QStringLiteral("ksnakeduel"))); return app.exec(); } diff --git a/renderer.cpp b/renderer.cpp index 15b4e15..a5d2e21 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -1,298 +1,298 @@ /********************************************************************************** This file is part of the game 'KTron' Copyright (C) 1998-2000 by Matthias Kiefer Copyright (C) 2005 Benjamin C. Meyer Copyright (C) 2008-2009 Stas Verberkt 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include "renderer.h" #include "settings.h" #include "object.h" #include #include #include #include #include #include #include "ksnakeduel_debug.h" #define USE_UNSTABLE_LIBKDEGAMESPRIVATE_API #include class RendererPrivate { public: RendererPrivate(); ~RendererPrivate(); QSize m_sceneSize; QSize m_partSize; QSvgRenderer m_renderer; QPixmap *m_playField; QString m_currentTheme; }; const QString sizeSuffix(QStringLiteral( "_%1-%2" )); const QString frameSuffix(QStringLiteral( "-%1" )); RendererPrivate::RendererPrivate() : m_renderer() { QPixmapCache::setCacheLimit(40); QPixmapCache::clear(); m_playField = nullptr; } RendererPrivate::~RendererPrivate() { delete m_playField; } Renderer::Renderer() : p(new RendererPrivate) { loadTheme(Settings::theme()); } Renderer::Renderer(const Renderer &) { } Renderer::~Renderer() { delete p; } Renderer *Renderer::self() { static Renderer r; return &r; } bool Renderer::loadTheme(const QString &name) { bool discardCache = !p->m_currentTheme.isEmpty(); if (!p->m_currentTheme.isEmpty() && p->m_currentTheme == name) return true; //requested to load the theme that is already loaded KGameTheme theme; //try to load theme if (!theme.load(name)) { if (!theme.loadDefault()) return false; } p->m_currentTheme = name; //load graphics if (!p->m_renderer.load(theme.graphics())) return false; //flush cache if (discardCache) QPixmapCache::clear(); return true; } QPixmap Renderer::getPart(const QString &frameSvgName) { return getPartOfSize(frameSvgName, p->m_partSize); } QPixmap Renderer::getPartOfSize(const QString &frameSvgName, const QSize &partSize) { QString framePixName = frameSvgName + sizeSuffix.arg(partSize.width()).arg(partSize.height()); QPixmap pix; if (!QPixmapCache::find(framePixName, pix)) { pix = QPixmap(partSize); pix.fill(Qt::transparent); QPainter painter(&pix); p->m_renderer.render(&painter, frameSvgName); painter.end(); QPixmapCache::insert(framePixName, pix); } //return the static pixmap return pixmapFromCache(p, frameSvgName, partSize); } QPixmap Renderer::pixmapFromCache(RendererPrivate *p, const QString &svgName, const QSize &size) { if (size.isEmpty()) return QPixmap(); QPixmap pix; QString pixName = svgName + sizeSuffix.arg(size.width()).arg(size.height()); if (!QPixmapCache::find(pixName, pix)) { pix = QPixmap(size); pix.fill(Qt::transparent); QPainter painter(&pix); p->m_renderer.render(&painter, svgName); painter.end(); QPixmapCache::insert(pixName, pix); } return pix; } QPixmap Renderer::background() { QPixmap pix; QString pixName = QLatin1String( "bgtile" ) + sizeSuffix.arg(p->m_sceneSize.width()).arg(p->m_sceneSize.height()); if (!QPixmapCache::find(pixName, pix)) { pix = QPixmap(p->m_sceneSize); pix.fill(Qt::white); QPainter painter(&pix); QPixmap bgPix = getPart(QStringLiteral( "bgtile" )); if (!bgPix.isNull()) { pix.fill(Qt::white); int pw = bgPix.width(); int ph = bgPix.height(); for (int x = 0; x <= p->m_sceneSize.width(); x += pw) { for (int y = 0; y <= p->m_sceneSize.height(); y += ph) { painter.drawPixmap(x, y, bgPix); } } } else { pix.fill(Qt::green); } painter.end(); QPixmapCache::insert(pixName, pix); } // Tiled background return pix; } void Renderer::boardResized(int width, int height, int partWidth, int partHeight) { //new metrics p->m_sceneSize = QSize(width, height); p->m_partSize = QSize(partWidth, partHeight); } void Renderer::resetPlayField() { delete p->m_playField; p->m_playField = new QPixmap(p->m_sceneSize); //p->m_playField->fill(Qt::green); } void Renderer::updatePlayField(PlayField &playfield) { int i, j; if (!p->m_playField) { resetPlayField(); } QPainter painter; painter.begin(p->m_playField); QPixmap bgPix = background(); painter.drawPixmap(0, 0, bgPix); // Draw border for (i = 0; i < playfield.getWidth() + 2; ++i) { for (j = 0; j < playfield.getHeight() + 2; ++j) { if (i == 0 || i == playfield.getWidth() + 1 || j == 0 || j == playfield.getHeight() + 1) { QPixmap part = Renderer::self()->getPart(QStringLiteral( "border" )); painter.drawPixmap(calculateOffsetX(i), calculateOffsetY(j), part); } } } // Examine all pixels and draw for(i = 0; i < playfield.getWidth(); ++i) { for(j = 0; j < playfield.getHeight(); ++j) { if (playfield.getObjectAt(i, j)->getObjectType() != ObjectType::Object) { drawPart(painter, i, j, playfield.getObjectAt(i, j)->getSVGName()); } } } painter.end(); } int Renderer::calculateOffsetX(int x) { return (x * p->m_partSize.width()) + (p->m_sceneSize.width() - (TRON_PLAYFIELD_WIDTH + 2) * p->m_partSize.width()) / 2; } int Renderer::calculateOffsetY(int y) { return (y * p->m_partSize.height()) + (p->m_sceneSize.height() - (TRON_PLAYFIELD_HEIGHT + 2) * p->m_partSize.height()) / 2; } -void Renderer::drawPart(QPainter & painter, int x, int y, QString svgName) +void Renderer::drawPart(QPainter & painter, int x, int y, const QString &svgName) { //qCDebug(KSNAKEDUEL_LOG) << "Drawing part: " << svgName; int xOffset = calculateOffsetX(x + 1); int yOffset = calculateOffsetY(y + 1); //int type = playfield[x][y]; QPixmap snakePart = Renderer::self()->getPart(svgName); painter.drawPixmap(xOffset, yOffset, snakePart); } QPixmap *Renderer::getPlayField() { return p->m_playField; } QPixmap Renderer::messageBox(const QString &message) { int w = p->m_sceneSize.width() / 2; int h = p->m_sceneSize.height() / 3; QSize size(w, h); QPixmap pixmap = getPartOfSize(QStringLiteral( "display" ), size); QPainter painter(&pixmap); const int fontSize = KFontUtils::adaptFontSize(painter, message, w * 0.9, h, 28, 1, KFontUtils::DoNotAllowWordWrap); painter.setPen(QColor(255, 255, 255, 220)); painter.setFont(QFont(QStringLiteral( "Helvetica" ), fontSize, QFont::Bold)); painter.drawText(QRectF(0, 0, w, h), Qt::AlignCenter, message); painter.end(); return pixmap; } diff --git a/renderer.h b/renderer.h index a66845c..869ac64 100644 --- a/renderer.h +++ b/renderer.h @@ -1,66 +1,66 @@ /********************************************************************************** This file is part of the game 'KTron' Copyright (C) 1998-2000 by Matthias Kiefer Copyright (C) 2005 Benjamin C. Meyer Copyright (C) 2008-2009 Stas Verberkt 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef RENDERER_H #define RENDERER_H #include "playfield.h" #include #include #include class QPixmap; class RendererPrivate; class Renderer { private: Renderer(); Renderer(const Renderer &); ~Renderer(); public: static Renderer *self(); bool loadTheme(const QString &); void boardResized(int width, int height, int partWidth, int partHeight); int calculateOffsetX(int x); int calculateOffsetY(int y); QPixmap getPart(const QString &partName); QPixmap getPartOfSize(const QString &partName, const QSize &partSize); QPixmap background(); QPixmap messageBox(const QString &message); void resetPlayField(); - void drawPart(QPainter & painter, int x, int y, QString svgName); + void drawPart(QPainter & painter, int x, int y, const QString &svgName); void updatePlayField(PlayField &playfield); QPixmap *getPlayField(); QPixmap pixmapFromCache(RendererPrivate *p, const QString &svgName, const QSize &size); private: RendererPrivate *p; }; #endif // RENDERER_H diff --git a/tron.cpp b/tron.cpp index 234388a..f3b936f 100644 --- a/tron.cpp +++ b/tron.cpp @@ -1,708 +1,708 @@ /********************************************************************************** This file is part of the game 'KTron' Copyright (C) 1998-2000 by Matthias Kiefer Copyright (C) 2005 Benjamin C. Meyer Copyright (C) 2008-2009 Stas Verberkt 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include "tron.h" // Normal class #include #include #include #include #include #include #include #include "ksnakeduel_debug.h" #include #include #include "settings.h" #include "renderer.h" #include "object.h" #include "obstacle.h" /** * init-functions **/ Tron::Tron(QWidget *parent) : QWidget(parent) { players[0] = new Player(pf, 0); players[1] = new Player(pf, 1); connect(players[0], &Player::fetchedItem, this, &Tron::itemHit); connect(players[1], &Player::fetchedItem, this, &Tron::itemHit); intelligence.referenceTron(this); setFocusPolicy(Qt::StrongFocus); gameBlocked = false; gameEnded = true; timer = new QTimer(this); //loadSettings(); connect(timer, &QTimer::timeout, this, &Tron::doMove); } void Tron::loadSettings(){ createNewPlayfield(); reset(); // Velocity setVelocity( lineSpeed() ); // Style updatePixmap(); update(); // Player 0 is always human if (Settings::gameType() == Settings::EnumGameType::PlayerVSPlayer) { players[1]->setComputer(false); } else { players[1]->setComputer(true); } } Tron::~Tron() { delete timer; delete players[0]; delete players[1]; } void Tron::resizeRenderer() { // Block size blockWidth = width() / (pf.getWidth() + 2); blockHeight = height() / (pf.getHeight() + 2); if (blockWidth > blockHeight) { blockWidth = blockHeight; } else { blockHeight = blockWidth; } Renderer::self()->boardResized(width(), height(), blockWidth, blockHeight); Renderer::self()->resetPlayField(); } void Tron::createNewPlayfield() { resizeRenderer(); pf.initialize(); } void Tron::newGame() { players[0]->resetScore(); players[1]->resetScore(); //emit gameEnds(KTronEnum::Nobody); emit updatedScore(); reset(); } void Tron::reset() { gamePaused = false; stopGame(); players[0]->reset(); players[1]->reset(); if (Settings::gameType() == Settings::EnumGameType::Snake) { players[0]->resetScore(); players[1]->resetScore(); } setVelocity( lineSpeed() ); modMoves = 0; pf.initialize(); // set start coordinates players[0]->setStartPosition(); if (Settings::gameType() != Settings::EnumGameType::Snake) { players[1]->setStartPosition(); } updatePixmap(); update(); setFocus(); emit gameReset(); emit updatedScore(); } // // Getters / Setters // PlayField *Tron::getPlayField() { return &pf; } Player *Tron::getPlayer(int playerNr) { if (playerNr != 0 && playerNr != 1) { qCDebug(KSNAKEDUEL_LOG) << "Inexistent player requested: " << playerNr; - return 0; + return nullptr; } return players[playerNr]; } /* *************************************************************** ** ** ??? functions ** ** *************************************************************** */ void Tron::startGame() { gameEnded = false; emit pauseBlocked(false); if (Settings::gameType() == Settings::EnumGameType::Snake) { newApple(); } timer->start(velocity); } void Tron::itemHit(int playerNumber, int, int) { //qCDebug(KSNAKEDUEL_LOG) << "Got Item Hit for " << playerNumber; newApple(); players[playerNumber]->setEnlargement(3); players[playerNumber]->addScore(5); if (velocity > 15) { velocity--; timer->stop(); timer->start(velocity); } emit updatedScore(); } void Tron::newApple() { int x = rand() % pf.getWidth(); int y = rand() % pf.getHeight(); while (pf.getObjectAt(x, y)->getObjectType() != ObjectType::Object) { x = rand() % pf.getWidth(); y = rand() % pf.getHeight(); } //qCDebug(KSNAKEDUEL_LOG) << "Drawn apple at (" << x << ", " << y << ")"; apple.setType((int)(rand() % 3)); pf.setObjectAt(x, y, apple); } void Tron::newObstacle() { // KSnake only if (Settings::gameType() != Settings::EnumGameType::Snake) return; int x = rand() % pf.getWidth(); int y = rand() % pf.getHeight(); // Don't render if it's at an unwanted place if (pf.getObjectAt(x, y)->getObjectType() != ObjectType::Object) return; else if (x == players[0]->getX() || y == players[0]->getY()) return; Obstacle obst; pf.setObjectAt(x, y, obst); // Score +2 players[0]->addScore(2); emit updatedScore(); } void Tron::stopGame() { timer->stop(); gameEnded = true; } void Tron::togglePause() // pause or continue game { if (!gameEnded) { if (gamePaused) { gamePaused = false; update(); timer->start(velocity); emit updatedScore(); } else { gamePaused = true; timer->stop(); update(); emit updatedScore(); } } } void Tron::showWinner() { update(); emit gameEnds(); emit pauseBlocked(true); } /* *************************************************************** ** ** paint functions ** ** *************************************************************** */ void Tron::updatePixmap() { Renderer::self()->updatePlayField(pf); } /* *************************************************************** ** ** config functions ** ** *************************************************************** */ void Tron::setVelocity(int newVel) // set new velocity { velocity = (10 - newVel) * 15; if (!gameEnded && !gamePaused) { timer->start(velocity); } } /* *************************************************************** ** ** Events ** ** *************************************************************** */ void Tron::paintEvent(QPaintEvent *e) { QPainter p(this); p.drawPixmap(e->rect().topLeft(), *Renderer::self()->getPlayField(), e->rect()); if (gamePaused) // if game is paused, print message { QString message = i18n("Game paused"); QPixmap messageBox = Renderer::self()->messageBox(message); QPoint point(width() / 2 - messageBox.width() / 2, height() / 2 - messageBox.height() / 2); p.drawPixmap(point, messageBox, e->rect()); } else if (gameEnded) // If game ended, print "Crash!" { QString message = QString(); if (Settings::gameType() != Settings::EnumGameType::Snake) { if (hasWinner()) { int winner = getWinner(); int loser = 1 - winner; QString winnerName = players[winner]->getName(); QString loserName = players[loser]->getName(); int winnerScore = players[winner]->getScore(); int loserScore = players[loser]->getScore(); message += i18np("%1 has won versus %2 with %4 versus %3 point!", "%1 has won versus %2 with %4 versus %3 points!", winnerName, loserName, loserScore, winnerScore); message += QLatin1Char( '\n' ); } else { QString name1 = players[0]->getName(); QString name2 = players[1]->getName(); int points1 = players[0]->getScore(); int points2 = players[1]->getScore(); message += i18nc("%2 = 'x points' [player %1], %4 = 'x points' [player %3]", "%1 (%2) versus %3 (%4)", name2, i18np("%1 point", "%1 points", points2), name1, i18np("%1 point", "%1 points", points1)); message += QLatin1Char( '\n' ); } } else { int points = players[0]->getScore(); message += i18np("KSnake game ended with 1 point", "KSnake game ended with %1 points", points); message += QLatin1Char( '\n' ); } if (Settings::gameType() == Settings::EnumGameType::PlayerVSPlayer) { message += i18n("The game starts when each player has pressed one of their direction keys!"); } else { message += i18n("Press any of your direction keys to start!"); } QPixmap messageBox = Renderer::self()->messageBox(message); QPoint point(width() / 2 - messageBox.width() / 2, height() / 2 - messageBox.height() / 2); p.drawPixmap(point, messageBox, e->rect()); } } void Tron::resizeEvent(QResizeEvent *) { resizeRenderer(); updatePixmap(); update(); } void Tron::triggerKey(int player, KBAction::Action action, bool trigger) { if (action == KBAction::ACCELERATE && !trigger) { switchKeyOff(player, action); } else { switchKeyOn(player, action); } } void Tron::switchKeyOn(int player, KBAction::Action action) { // Set key pressed if (!players[player]->isComputer()) { switch (action) { case KBAction::UP: case KBAction::DOWN: case KBAction::LEFT: case KBAction::RIGHT: players[player]->setKeyPressed(true); break; case KBAction::ACCELERATE: break; default: break; } } // if both players press keys at the same time, start game... if (players[0]->hasKeyPressed() && players[1]->hasKeyPressed()) { // Start game if (gameEnded && !gameBlocked) { if (hasWinner()) { newGame(); } reset(); startGame(); } // ...or continue else if (gamePaused) { togglePause(); } } // Key handling for movement if (!players[player]->isComputer()) { switch (action) { case KBAction::UP: players[player]->setDirection(PlayerDirections::Up); break; case KBAction::DOWN: players[player]->setDirection(PlayerDirections::Down); break; case KBAction::LEFT: players[player]->setDirection(PlayerDirections::Left); break; case KBAction::RIGHT: players[player]->setDirection(PlayerDirections::Right); break; case KBAction::ACCELERATE: if (!Settings::acceleratorBlocked()) { players[player]->setAccelerated(true); } break; default: break; } } } void Tron::switchKeyOff(int player, KBAction::Action action) { if (!players[player]->isComputer()) { switch (action) { case KBAction::UP: case KBAction::DOWN: case KBAction::LEFT: case KBAction::RIGHT: players[player]->setKeyPressed(false); break; case KBAction::ACCELERATE: players[player]->setAccelerated(false); break; default: break; } } } // if playingfield loses keyboard focus, pause game void Tron::focusOutEvent(QFocusEvent *) { if(!gameEnded && !gamePaused) { togglePause(); } } /* *************************************************************** ** ** slots ** ** *************************************************************** */ void Tron::unblockGame() { gameBlocked = false; } // doMove() is called from QTimer void Tron::doMove() { if (Settings::gameType() == Settings::EnumGameType::Snake) { players[0]->movePlayer(); modMoves++; if (modMoves == 20) { modMoves = 0; newObstacle(); } updatePixmap(); update(); if (!players[0]->isAlive()) { stopGame(); showWinner(); } } else { if (players[0]->isAccelerated() || players[1]->isAccelerated()) { movementHelper(true); } if (!gameEnded) { // Player 0 is never a computer nowadays... if (players[1]->isComputer()) { intelligence.think(1); } movementHelper(false); } } if (gameEnded) { //this is for waiting 1s before starting next game gameBlocked = true; QTimer::singleShot(1000, this, &Tron::unblockGame); } } void Tron::movementHelper(bool onlyAcceleratedPlayers) { if (!onlyAcceleratedPlayers || players[0]->isAccelerated()) { players[0]->movePlayer(); } if (!onlyAcceleratedPlayers || players[1]->isAccelerated()) { players[1]->movePlayer(); } /* player collision check */ if (!players[1]->isAlive()) { checkHeadToHeadCollision(); } updatePixmap(); update(); // crashtest if (!players[0]->isAlive() || !players[1]->isAlive()) { stopGame(); if (!players[0]->isAlive() && !players[1]->isAlive()) { // Don't award points when both players die //players[0]->addScore(1); //players[1]->addScore(1); } else if (!players[0]->isAlive()) { players[1]->addScore(1); } else if (!players[1]->isAlive()) { players[0]->addScore(1); } showWinner(); } } void Tron::checkHeadToHeadCollision() { // As player 1 and player 2 move at the same time // a head to head collision is possible // but tough movement actually is done sequential // we have to check back if player 1 should die when player 2 did so // that's where this function comes in :) int xInc = 0; int yInc = 0; switch (players[1]->getDirection()) { case PlayerDirections::Left: xInc = -1; break; case PlayerDirections::Right: xInc = 1; break; case PlayerDirections::Up: yInc = -1; break; case PlayerDirections::Down: yInc = 1; break; default: break; } if ((players[1]->getX() + xInc) == players[0]->getX()) { if ((players[1]->getY() + yInc) == players[0]->getY()) { players[0]->die(); } } } /** * Skill settings */ /** retrieves the line speed */ int Tron::lineSpeed() { switch (Kg::difficultyLevel()) { case KgDifficultyLevel::VeryEasy: return 2; default: case KgDifficultyLevel::Easy: return 3; case KgDifficultyLevel::Medium: return 5; case KgDifficultyLevel::Hard: return 7; case KgDifficultyLevel::VeryHard: return 8; } } bool Tron::running() { return !gameEnded; } bool Tron::paused() { return !gameEnded && gamePaused; } bool Tron::hasWinner() { return getWinner() == 0 || getWinner() == 1; } int Tron::getWinner() { if (Settings::gameType() != Settings::EnumGameType::Snake) { if (players[0]->getScore() >= WINNING_DIFF && players[1]->getScore() < players[0]->getScore() - 1) { return 0; } else if (players[1]->getScore() >= WINNING_DIFF && players[0]->getScore() < players[1]->getScore() - 1) { return 1; } } return -1; }