File indexing completed on 2024-04-14 03:59:29
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 0179 #include "moc_game-state.cpp"