File indexing completed on 2022-10-04 14:27:22

0001 /*
0002     SPDX-FileCopyrightText: 2008-2009 Stefan Majewsky <majewsky@gmx.net>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "game-state.h"
0008 #include "settings.h"
0009 
0010 #include <QElapsedTimer>
0011 #include <KLocalizedString>
0012 #include <KNotification>
0013 
0014 namespace KDiamond
0015 {
0016 
0017 class GameStatePrivate
0018 {
0019 public:
0020     GameStatePrivate();
0021     ~GameStatePrivate();
0022 
0023     QElapsedTimer m_gameTime, m_pauseTime;
0024 
0025     Mode m_mode;
0026     State m_state;
0027     int m_earnedMilliseconds, m_leftMilliseconds, m_pausedMilliseconds;
0028     int m_points, m_cascade;
0029 };
0030 
0031 }
0032 
0033 KDiamond::GameStatePrivate::GameStatePrivate()
0034 //these should be the same values as in KDiamond::GameState::startNewGame
0035     : m_mode(Settings::untimed() ? KDiamond::UntimedGame : KDiamond::NormalGame)
0036     , m_state(KDiamond::Playing)
0037     , m_earnedMilliseconds(0)
0038     , m_leftMilliseconds(0)
0039     , m_pausedMilliseconds(0)
0040     , m_points(0)
0041     , m_cascade(0)
0042 {
0043     m_gameTime.start();
0044     m_pauseTime.start(); //now we can always call restart() when we need it
0045 }
0046 
0047 KDiamond::GameStatePrivate::~GameStatePrivate()
0048 {
0049 }
0050 
0051 KDiamond::GameState::GameState()
0052     : p(new KDiamond::GameStatePrivate)
0053 {
0054     startTimer(500);
0055 }
0056 
0057 KDiamond::GameState::~GameState()
0058 {
0059     delete p;
0060 }
0061 
0062 KDiamond::Mode KDiamond::GameState::mode() const
0063 {
0064     return p->m_mode;
0065 }
0066 
0067 KDiamond::State KDiamond::GameState::state() const
0068 {
0069     return p->m_state;
0070 }
0071 
0072 int KDiamond::GameState::leftTime() const
0073 {
0074     return p->m_leftMilliseconds;
0075 }
0076 
0077 int KDiamond::GameState::points() const
0078 {
0079     return p->m_points;
0080 }
0081 
0082 void KDiamond::GameState::setMode(KDiamond::Mode mode)
0083 {
0084     p->m_mode = mode;
0085     Settings::setUntimed(p->m_mode == KDiamond::UntimedGame);
0086     update(true); //recalculate time
0087 }
0088 
0089 void KDiamond::GameState::setState(KDiamond::State state)
0090 {
0091     if (p->m_state == KDiamond::Finished) { //cannot be changed (except with startNewGame slot)
0092         return;
0093     }
0094     //check for important transitions
0095     if (p->m_state == KDiamond::Paused && state == KDiamond::Playing) {
0096         //resuming from paused state
0097         p->m_pausedMilliseconds += p->m_pauseTime.elapsed();
0098         update(true); //recalculate time
0099         Q_EMIT message(QString()); //flush message
0100     } else if (p->m_state == KDiamond::Playing && state == KDiamond::Paused) {
0101         //going to paused state
0102         p->m_pauseTime.restart();
0103         Q_EMIT message(i18n("Click the pause button again to resume the game."));
0104     }
0105     //set new state
0106     p->m_state = state;
0107     Q_EMIT stateChanged(state);
0108     if (state == KDiamond::Finished) {
0109         KNotification::event(QStringLiteral("gamefinished"));
0110         Q_EMIT message(i18nc("Not meant like 'You have lost', more like 'Time is up'.", "Game over."));
0111     }
0112 }
0113 
0114 void KDiamond::GameState::timerEvent(QTimerEvent *event)
0115 {
0116     Q_UNUSED(event)
0117     update();
0118 }
0119 
0120 void KDiamond::GameState::addPoints(int removedDiamonds)
0121 {
0122     p->m_points += ++p->m_cascade;
0123     p->m_earnedMilliseconds += 500;
0124     if (removedDiamonds > 3)
0125         //add half an extra second for each extra diamond
0126     {
0127         p->m_earnedMilliseconds += 500 * (removedDiamonds - 3);
0128     }
0129     Q_EMIT pointsChanged(p->m_points);
0130     update(true); //recalculate time
0131 }
0132 
0133 void KDiamond::GameState::removePoints(int points)
0134 {
0135     p->m_points = qMax(0, p->m_points - points);
0136     Q_EMIT pointsChanged(p->m_points);
0137 }
0138 
0139 void KDiamond::GameState::resetCascadeCounter()
0140 {
0141     p->m_cascade = 0;
0142 }
0143 
0144 void KDiamond::GameState::startNewGame()
0145 {
0146     p->m_gameTime.restart();
0147     //p->m_mode does not need to be reset as it is kept in sync with Settings::untimed()
0148     //these should be the same values as in KDiamond::GameStatePrivate constructor
0149     p->m_state = KDiamond::Playing;
0150     p->m_earnedMilliseconds = 0;
0151     p->m_leftMilliseconds = 0;
0152     p->m_pausedMilliseconds = 0;
0153     p->m_points = 0;
0154     p->m_cascade = 0;
0155     update(true); //recalculate time
0156     Q_EMIT message(QString()); //flush message
0157     Q_EMIT stateChanged(p->m_state);
0158     Q_EMIT pointsChanged(p->m_points);
0159 }
0160 
0161 void KDiamond::GameState::update(bool forceRecalculation)
0162 {
0163     //will not recalculate time when not playing a normal game (unless forced)
0164     if (p->m_mode == KDiamond::UntimedGame || (p->m_state != KDiamond::Playing && !forceRecalculation)) {
0165         return;
0166     }
0167     //calculate new time
0168     const int leftMilliseconds = 1000 * KDiamond::GameDuration + p->m_earnedMilliseconds + p->m_pausedMilliseconds - p->m_gameTime.elapsed();
0169     const int leftSeconds = leftMilliseconds / 1000;
0170     if (leftSeconds <= 0) {
0171         setState(KDiamond::Finished);
0172     }
0173     if (p->m_leftMilliseconds / 1000 != leftSeconds) {
0174         Q_EMIT leftTimeChanged(qMax(0, leftSeconds));
0175     }
0176     p->m_leftMilliseconds = leftMilliseconds;
0177 }
0178