SVN commit 919345 by majewsky: Move Kolf::NormalGame to the new base class Kolf::Game. Please report any regressions, I haven't noticed any up to now. M +1 -0 CMakeLists.txt M +30 -182 engine/game-normal.cpp M +9 -34 engine/game-normal.h A engine/game.cpp [License: GPL (v2+)] A engine/game.h [License: GPL (v2+)] --- trunk/playground/games/kolf-ng/CMakeLists.txt #919344:919345 @@ -32,6 +32,7 @@ elements/overlay-wall.cpp elements/putter.cpp engine/course.cpp + engine/game.cpp engine/game-normal.cpp engine/player.cpp engine/player-dummy.cpp --- trunk/playground/games/kolf-ng/engine/game-normal.cpp #919344:919345 @@ -18,67 +18,47 @@ #include "game-normal.h" #include "course.h" -#include "player-dummy.h" #include "player-local.h" #include "../elements/ball.h" #include "../elements/putter.h" #include "../interface/view.h" -#include #include -#include #include Kolf::NormalGame::NormalGame(Kolf::Course* course, Kolf::View* view) - : m_currentHole(-1) + : Kolf::Game(course, view) , m_currentPlayer(-1) - , m_view(view) - , m_course(course) - , m_parPlayer(new Kolf::DummyPlayer(i18n("Par"), m_course->holeCount())) { - //retrieve par scores - for (int i = 0; i < m_course->holeCount(); ++i) - m_parPlayer->setScore(i, m_course->parForHole(i)); } Kolf::NormalGame::~NormalGame() { - qDeleteAll(m_players); - delete m_parPlayer; } -//BEGIN game management - Kolf::Player* Kolf::NormalGame::addPlayer() { - beginInsertColumns(QModelIndex(), m_players.count() + 1, m_players.count() + 1); //the "+1" is because the first column is for the parPlayer - Kolf::Player* newPlayer = new Kolf::LocalPlayer(i18n("Player %1", m_players.count() + 1), m_course->holeCount()); + const QString name = i18n("Player %1", playerCount() + 1); + Kolf::Player* newPlayer = new Kolf::LocalPlayer(name, course()->holeCount()); connect(newPlayer->ball(), SIGNAL(moveFinished()), this, SLOT(finishMove())); - connect(newPlayer, SIGNAL(scoreChanged(Kolf::Player*, int)), this, SLOT(scoreChanged(Kolf::Player*, int))); - m_players << newPlayer; - endInsertColumns(); + Kolf::Game::addPlayer(newPlayer); return newPlayer; } -const QList Kolf::NormalGame::players() const -{ - return m_players; -} - bool Kolf::NormalGame::startGame() { - if (m_players.isEmpty() || m_course->holeCount() <= 0) + if (playerCount() == 0 || course()->holeCount() <= 0) return false; //start with first hole and first player - advanceHole(); + setCurrentHole(0); return true; } void Kolf::NormalGame::finishMove() { //turn control to next player if all balls are standing still - foreach (Kolf::Player* player, m_players) - if (!player->ball()->velocity().isNull()) + for (int i = 0; i < playerCount(); ++i) + if (!player(i)->ball()->velocity().isNull()) return; emit playerMoveEnded(m_currentPlayer); QTimer::singleShot(500, this, SLOT(advancePlayer())); @@ -86,25 +66,7 @@ void Kolf::NormalGame::advanceHole() { - //delete all objects of the current hole, but save players' items (balls) from being deleted - foreach (Kolf::Player* player, m_players) - player->depopulate(m_view); - m_view->clear(); - foreach (Kolf::Player* player, m_players) - player->populate(m_view); - //go to next hole - setCurrentHole_modelAware(m_currentHole + 1); - if (m_currentHole < m_course->holeCount()) - { - m_course->loadHole(m_currentHole, m_view); - foreach (Kolf::Player* player, m_players) - m_course->loadHole(m_currentHole, player->ball()); - //start with first player - m_currentPlayer = -1; - QTimer::singleShot(500, this, SLOT(advancePlayer())); - } - else - emit gameEnded(); + setCurrentHole(currentHole() + 1); } //TODO: base play order on success at last hole (like in Kolf 1) @@ -115,158 +77,44 @@ int newPlayer = m_currentPlayer; do { - newPlayer = (newPlayer + 1) % m_players.count(); - if (newPlayer == oldPlayer && m_players[newPlayer]->ball()->isInHole()) + newPlayer = (newPlayer + 1) % playerCount(); + if (newPlayer == oldPlayer && player(newPlayer)->ball()->isInHole()) { //looped through all players -> no player can play -> all players are in the hole -> proceed to the next hole QTimer::singleShot(500, this, SLOT(advanceHole())); return; } } - while (m_players[newPlayer]->ball()->isInHole()); + while (player(newPlayer)->ball()->isInHole()); //turn control to this player m_currentPlayer = newPlayer; emit playerMoveStarted(newPlayer); - m_players[newPlayer]->giveControl(); + player(newPlayer)->giveControl(); } -//END game management - -//BEGIN model functions - -int Kolf::NormalGame::rowCount(const QModelIndex& parent) const +void Kolf::NormalGame::currentHoleAboutToBeChanged() { - if (parent.isValid()) - return 0; - return m_course->holeCount() + 1; //"+1" because the last row contains the total score + //delete all objects of the current hole, but save players' items (balls) from being deleted + for (int i = 0; i < playerCount(); ++i) + player(i)->depopulate(view()); + view()->clear(); + for (int i = 0; i < playerCount(); ++i) + player(i)->populate(view()); } -int Kolf::NormalGame::columnCount(const QModelIndex& parent) const +void Kolf::NormalGame::currentHoleChanged() { - if (parent.isValid()) - return 0; - return m_players.count() + 1; //"+1" because of the parPlayer -} - -Qt::ItemFlags Kolf::NormalGame::flags(const QModelIndex& index) const -{ - Q_UNUSED(index) - return Qt::ItemIsEnabled; -} - -QVariant Kolf::NormalGame::data(const QModelIndex& index, int role) const -{ - if (index.parent().isValid()) - return QVariant(); - const int holeIndex = index.row(); - const int playerIndex = index.column() - 1; - //column selects player - const Kolf::Player* const player = (playerIndex == -1) ? m_parPlayer : m_players[playerIndex]; - //variable declarations (cannot be done in switch statement, at least in gcc) - KColorScheme::BackgroundRole bgRole = KColorScheme::NormalBackground; - //retrieve data - switch (role) + if (currentHole() < course()->holeCount()) { - case Qt::DisplayRole: - //show score - if (holeIndex == m_course->holeCount()) - return player->totalScore(); - else - { - if (player == m_parPlayer || holeIndex >= m_currentHole) - return player->score(holeIndex); - else - { - //player has finished this hole -> show difference to par together with score - return i18nc("used as \"score (difference)\" on the score card", "%1 (%2)", - player->score(holeIndex), - player->score(holeIndex) - m_parPlayer->score(holeIndex) - ); - } - } - case Qt::BackgroundRole: - //mark current hole - if (holeIndex == m_currentHole) - bgRole = KColorScheme::NeutralBackground; - //create brush - return KStatefulBrush(KColorScheme::View, bgRole).brush(QPalette::Active); - default: - return QVariant(); + course()->loadHole(currentHole(), view()); + for (int i = 0; i < playerCount(); ++i) + course()->loadHole(currentHole(), player(i)->ball()); + //start with first player + m_currentPlayer = -1; + QTimer::singleShot(500, this, SLOT(advancePlayer())); } + else + emit gameEnded(); } -QVariant Kolf::NormalGame::headerData(int section, Qt::Orientation orientation, int role) const -{ - switch (role) - { - case Qt::DisplayRole: - if (orientation == Qt::Vertical) - { - if (section == m_course->holeCount()) - return i18nc("as in: total score", "Total"); - else - return i18n("Hole %1", section + 1); //"+1" because user-visible hole numbers start at 1 - } - else //orientation == Qt::Horizontal - { - if (section == 0) - return m_parPlayer->name(); - else - return m_players[section - 1]->name(); - } - case Qt::DecorationRole: - //mark current hole - if (orientation == Qt::Vertical && section == m_currentHole) - return KIcon(QApplication::isLeftToRight() ? "arrow-right" : "arrow-left"); - else - return QVariant(); - case Qt::BackgroundRole: - //show player color - if (orientation == Qt::Horizontal && section != 0) //section == 0 is the par player - { - return m_players[section - 1]->color(); - } - default: - return QVariant(); - } -} - -void Kolf::NormalGame::setCurrentHole_modelAware(int newHole) -{ - int oldHole = m_currentHole; - m_currentHole = newHole; - //report change to players - foreach (Kolf::Player* player, m_players) - player->setCurrentHole(newHole); - //report header data changes - if (oldHole >= 0 && oldHole < m_course->holeCount()) - emit headerDataChanged(Qt::Vertical, oldHole, oldHole); - if (newHole >= 0 && newHole < m_course->holeCount()) - emit headerDataChanged(Qt::Vertical, newHole, newHole); - //report data change for the data row of the old hole (background brush has changed) - QModelIndex startIndex = index(oldHole, 0); - QModelIndex endIndex = index(oldHole, m_players.count() + 1); - emit dataChanged(startIndex, endIndex); - //report data change for the data row of the new hole (background brush has changed) - startIndex = index(newHole, 0); - endIndex = index(newHole, m_players.count() + 1); - emit dataChanged(startIndex, endIndex); -} - -void Kolf::NormalGame::scoreChanged(Kolf::Player* player, int hole) -{ - //find player - int playerIndex = m_players.indexOf(player); - if (playerIndex < 0) - return; - //report data change for the single score - QModelIndex dataIndex = index(hole, playerIndex + 1); - emit dataChanged(dataIndex, dataIndex); - //report data change for the total score - dataIndex = index(m_course->holeCount() + 1, playerIndex + 1); - emit dataChanged(dataIndex, dataIndex); -} - -//END model functions - #include "game-normal.moc" --- trunk/playground/games/kolf-ng/engine/game-normal.h #919344:919345 @@ -19,65 +19,40 @@ #ifndef KOLF_GAME_NORMAL_H #define KOLF_GAME_NORMAL_H -#include -#include -#include -#include +#include "game.h" namespace Kolf { - class Ball; - class Course; - class Player; - class View; /** * \class NormalGame * \since 2.0 * - * The central game management class which reacts on the movements of the ball and turns control to the players. This class is also a data model (in the sense of Qt's Model/View framework) which shows the scores and highlights the current hole and the best scores. + * The standard game implementation which lets a handful players play locally. */ - class NormalGame : public QAbstractTableModel + class NormalGame : public Kolf::Game { Q_OBJECT public: ///Constructs a new Kolf::NormalGame instance. Note that the game does not take ownership of the \a course and the \a view. NormalGame(Kolf::Course* course, Kolf::View* view); - ~NormalGame(); -//BEGIN game management + virtual ~NormalGame(); + Kolf::Player* addPlayer(); ///< \warning Do not use after the game has started. - const QList players() const; bool startGame(); ///< Fails if no players have been added to the game or if the course does not contain any holes. Q_SIGNALS: void playerMoveStarted(int player); void playerMoveEnded(int player); void gameEnded(); + protected: + virtual void currentHoleAboutToBeChanged(); + virtual void currentHoleChanged(); private Q_SLOTS: void finishMove(); ///< Called by a ball when it stops. void advanceHole(); ///< Advance to next hole (or end game if current hole is last one). void advancePlayer(); ///< Turn control to next player (or advance to next hole if all players have finished). -//END game management -//BEGIN model functions - public: - virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; - virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; - virtual Qt::ItemFlags flags(const QModelIndex& index) const; - virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; - virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - private Q_SLOTS: - void scoreChanged(Kolf::Player* player, int hole); private: - ///Sets the current hole and reports header data changes appropriately. - void setCurrentHole_modelAware(int newHole); - ///Sets a score and reports data changes appropriately. - void setScore_modelAware(int player, int hole, int score); -//END model functions - private: - int m_currentHole, m_currentPlayer; //counting starts at zero - Kolf::View* m_view; - QList m_players; - Kolf::Course* m_course; - Kolf::Player* m_parPlayer; //an imaginary dummy player which holds the par scores + int m_currentPlayer; //counting starts at zero }; }