1 | /*************************************************************************** |
2 | * KBlocks, a falling blocks game for KDE * |
3 | * Copyright (C) 2009 Mauricio Piacentini <mauricio@tabuleiro.com> * |
4 | * Zhongjie Cai <squall.leonhart.cai@gmail.com> * |
5 | * * |
6 | * This program is free software; you can redistribute it and/or modify * |
7 | * it under the terms of the GNU General Public License as published by * |
8 | * the Free Software Foundation; either version 2 of the License, or * |
9 | * (at your option) any later version. * |
10 | ***************************************************************************/ |
11 | #include "KBlocksWin.h" |
12 | |
13 | #include <limits.h> |
14 | #include <stdlib.h> |
15 | |
16 | #include <KConfigDialog> |
17 | #include <kstandardgameaction.h> |
18 | #include <KStandardAction> |
19 | #include <KIcon> |
20 | #include <kscoredialog.h> |
21 | #include <KLocale> |
22 | #include <KToggleAction> |
23 | #include <KActionCollection> |
24 | #include <KStatusBar> |
25 | #include <KgDifficulty> |
26 | |
27 | #include <QPixmapCache> |
28 | |
29 | #define USE_UNSTABLE_LIBKDEGAMESPRIVATE_API |
30 | #include <libkdegamesprivate/kgamethemeselector.h> |
31 | |
32 | #include "settings.h" |
33 | |
34 | KBlocksWin::KBlocksWin(KBlocksGameLogic * p, KBlocksPlayManager * pM, int capacity, int gamecount) : KXmlGuiWindow() |
35 | { |
36 | //Use up to 3MB for global application pixmap cache |
37 | QPixmapCache::setCacheLimit(3*1024); |
38 | |
39 | mFirstInit = true; |
40 | |
41 | mpKBPlayer = new KBlocksKeyboardPlayer(this); |
42 | mpAIPlayer = new KBlocksAIPlayer(); |
43 | |
44 | mMaxGameCapacity = capacity; |
45 | mGameCount = gamecount; |
46 | mpGameLogic = p; |
47 | mpPlayManager = pM; |
48 | |
49 | mpGameScene = new KBlocksScene(mpGameLogic, capacity); |
50 | |
51 | mpGameView = new KBlocksView(mpGameScene, this); |
52 | mpGameView->show(); |
53 | setCentralWidget(mpGameView); |
54 | connect(mpGameView, SIGNAL(focusEvent(bool)), this, SLOT(focusEvent(bool))); |
55 | |
56 | setAutoSaveSettings(); |
57 | |
58 | setupGUILayout(); |
59 | } |
60 | |
61 | KBlocksWin::~KBlocksWin() |
62 | { |
63 | delete mpGameView; |
64 | delete mpGameScene; |
65 | delete mpAIPlayer; |
66 | delete mpKBPlayer; |
67 | } |
68 | |
69 | void KBlocksWin::setGamesPerLine(int count) |
70 | { |
71 | mpGameScene->setGamesPerLine(count); |
72 | } |
73 | |
74 | void KBlocksWin::setGameAnimEnabled(bool flag) |
75 | { |
76 | mpGameScene->setGameAnimEnabled(flag); |
77 | mGameAnim = flag; |
78 | } |
79 | |
80 | void KBlocksWin::setWaitForAllUpdate(bool flag) |
81 | { |
82 | mpGameScene->setWaitForAllUpdate(flag); |
83 | mWaitForAll = flag; |
84 | } |
85 | |
86 | void KBlocksWin::setUpdateInterval(int interval) |
87 | { |
88 | mpGameScene->setUpdateInterval(interval); |
89 | } |
90 | |
91 | void KBlocksWin::addScore(int gameIndex, int lineCount) |
92 | { |
93 | mpGameScene->addScore(gameIndex, lineCount); |
94 | } |
95 | |
96 | void KBlocksWin::startGame() |
97 | { |
98 | if (mFirstInit) |
99 | { |
100 | mFirstInit = false; |
101 | return; |
102 | } |
103 | |
104 | srand(time(0)); |
105 | mpGameLogic->setGameSeed(rand()); |
106 | if (mpGameLogic->startGame(mGameCount)) |
107 | { |
108 | mpPlayManager->startGame(); |
109 | |
110 | mpGameScene->createGameItemGroups(mGameCount, false); |
111 | mpGameScene->startGame(); |
112 | |
113 | int levelUpTime = 0; |
114 | switch ((int) Kg::difficultyLevel()) |
115 | { |
116 | case KgDifficultyLevel::Medium: |
117 | levelUpTime = 5; |
118 | break; |
119 | case KgDifficultyLevel::Hard: |
120 | levelUpTime = 10; |
121 | break; |
122 | } |
123 | mpGameLogic->levelUpGame(levelUpTime); |
124 | |
125 | Kg::difficulty()->setGameRunning(true); |
126 | } |
127 | else |
128 | { |
129 | stopGame(); |
130 | startGame(); |
131 | } |
132 | |
133 | statusBar()->changeItem( i18n("Points: %1 - Lines: %2 - Level: %3" , 0, 0, 0), 0 ); |
134 | } |
135 | |
136 | void KBlocksWin::stopGame() |
137 | { |
138 | if (mpGameLogic->stopGame()) |
139 | { |
140 | mpPlayManager->stopGame(); |
141 | |
142 | mpGameScene->stopGame(); |
143 | mpGameScene->deleteGameItemGroups(); |
144 | |
145 | Kg::difficulty()->setGameRunning(false); |
146 | } |
147 | } |
148 | |
149 | void KBlocksWin::pauseGame() |
150 | { |
151 | mpGameLogic->pauseGame(m_pauseAction->isChecked()); |
152 | mpPlayManager->pauseGame(m_pauseAction->isChecked()); |
153 | mpGameScene->pauseGame(m_pauseAction->isChecked()); |
154 | |
155 | Kg::difficulty()->setGameRunning(!m_pauseAction->isChecked()); |
156 | } |
157 | |
158 | void KBlocksWin::singleGame() |
159 | { |
160 | mpPlayManager->stopGame(); |
161 | mpPlayManager->clearGamePlayer(); |
162 | mpPlayManager->addGamePlayer(mpKBPlayer, -1, -1); |
163 | mGameCount = 1; |
164 | |
165 | startGame(); |
166 | } |
167 | |
168 | void KBlocksWin::pveStepGame() |
169 | { |
170 | mpPlayManager->stopGame(); |
171 | mpPlayManager->clearGamePlayer(); |
172 | mpPlayManager->addGamePlayer(mpKBPlayer, -1, -1); |
173 | mpPlayManager->addGamePlayer(mpAIPlayer, 200, 50); |
174 | mGameCount = 2; |
175 | |
176 | mpGameLogic->setGameStandbyMode(true); |
177 | setWaitForAllUpdate(true); |
178 | |
179 | startGame(); |
180 | } |
181 | |
182 | void KBlocksWin::focusEvent(bool flag) |
183 | { |
184 | if (!flag) |
185 | { |
186 | if (m_pauseAction->isChecked()) |
187 | { |
188 | return; |
189 | } |
190 | } |
191 | mpGameLogic->pauseGame(flag); |
192 | mpPlayManager->pauseGame(flag); |
193 | mpGameScene->pauseGame(flag, true); |
194 | } |
195 | |
196 | void KBlocksWin::closeEvent(QCloseEvent *event) |
197 | { |
198 | Settings::self()->writeConfig(); |
199 | KXmlGuiWindow::closeEvent(event); |
200 | } |
201 | |
202 | void KBlocksWin::showHighscore() |
203 | { |
204 | KScoreDialog ksdialog(KScoreDialog::Name | KScoreDialog::Level | KScoreDialog::Score, this); |
205 | ksdialog.initFromDifficulty(Kg::difficulty()); |
206 | ksdialog.exec(); |
207 | } |
208 | |
209 | void KBlocksWin::configureSettings() |
210 | { |
211 | if ( KConfigDialog::showDialog("settings" ) ) |
212 | { |
213 | return; |
214 | } |
215 | KConfigDialog *dialog = new KConfigDialog(this, "settings" , Settings::self()); |
216 | dialog->addPage(new KGameThemeSelector(dialog, Settings::self()), i18n("Theme" ), "games-config-theme" ); |
217 | dialog->setFaceType(KConfigDialog::Plain); //only one page -> no page selection necessary |
218 | connect(dialog, SIGNAL(settingsChanged(QString)), mpGameView, SLOT(settingsChanged())); |
219 | //connect(dialog, SIGNAL(hidden()), view, SLOT(resumeFromConfigure())); |
220 | dialog->show(); |
221 | } |
222 | |
223 | void KBlocksWin::onScoreChanged(int index, int points, int lines, int level) |
224 | { |
225 | if (index == 0) // TODO : game id?? multi game display?? |
226 | { |
227 | statusBar()->changeItem( i18n("Points: %1 - Lines: %2 - Level: %3" , points, lines, level), 0 ); |
228 | } |
229 | } |
230 | |
231 | void KBlocksWin::onIsHighscore(int index, int points, int level) |
232 | { |
233 | if (index == 0) // TODO : game id?? multi game display?? |
234 | { |
235 | KScoreDialog ksdialog( KScoreDialog::Name | KScoreDialog::Level | KScoreDialog::Score, this ); |
236 | ksdialog.initFromDifficulty(Kg::difficulty()); |
237 | KScoreDialog::FieldInfo info; |
238 | info[KScoreDialog::Score].setNum( points ); |
239 | info[KScoreDialog::Level].setNum( level ); |
240 | if ( ksdialog.addScore( info ) ) |
241 | { |
242 | ksdialog.exec(); |
243 | } |
244 | } |
245 | } |
246 | |
247 | void KBlocksWin::levelChanged() |
248 | { |
249 | //Scene reads the difficulty level for us |
250 | startGame(); |
251 | mpGameView->setFocus(Qt::MouseFocusReason); |
252 | } |
253 | |
254 | void KBlocksWin::setSoundsEnabled(bool enabled) |
255 | { |
256 | mpGameScene->setSoundsEnabled(enabled); |
257 | Settings::setSounds(enabled); |
258 | } |
259 | |
260 | void KBlocksWin::setupGUILayout() |
261 | { |
262 | QAction *action; |
263 | |
264 | action = KStandardGameAction::gameNew(this, SLOT(singleGame()), actionCollection()); |
265 | action->setText(i18n("Single Game" )); |
266 | actionCollection()->addAction( QLatin1String( "newGame" ), action); |
267 | |
268 | action = new KAction(this); |
269 | action->setText(i18n("Human vs AI" )); |
270 | actionCollection()->addAction( QLatin1String( "pve_step" ), action); |
271 | connect(action, SIGNAL(triggered(bool)), this, SLOT(pveStepGame())); |
272 | |
273 | m_pauseAction = KStandardGameAction::pause(this, SLOT(pauseGame()), actionCollection()); |
274 | actionCollection()->addAction( QLatin1String( "pauseGame" ), m_pauseAction); |
275 | |
276 | action = KStandardGameAction::highscores(this, SLOT(showHighscore()), actionCollection()); |
277 | actionCollection()->addAction( QLatin1String( "showHighscores" ), action); |
278 | |
279 | action = KStandardGameAction::quit(this, SLOT(close()), actionCollection()); |
280 | actionCollection()->addAction( QLatin1String( "quit" ), action); |
281 | |
282 | KStandardAction::preferences(this, SLOT(configureSettings()), actionCollection()); |
283 | |
284 | KAction* soundAction = new KToggleAction(i18n("&Play sounds" ), this); |
285 | soundAction->setChecked(Settings::sounds()); |
286 | actionCollection()->addAction( QLatin1String( "sounds" ), soundAction); |
287 | connect(soundAction, SIGNAL(triggered(bool)), this, SLOT(setSoundsEnabled(bool))); |
288 | |
289 | // TODO |
290 | statusBar()->insertItem( i18n("Points: 0 - Lines: 0 - Level: 0" ), 0 ); |
291 | connect(mpGameScene, SIGNAL(scoreChanged(int,int,int,int)), this, SLOT(onScoreChanged(int,int,int,int))); |
292 | connect(mpGameScene, SIGNAL(isHighscore(int,int,int)), this, SLOT(onIsHighscore(int,int,int))); |
293 | |
294 | Kg::difficulty()->addStandardLevelRange( |
295 | KgDifficultyLevel::Easy, KgDifficultyLevel::Hard |
296 | ); |
297 | KgDifficultyGUI::init(this); |
298 | connect(Kg::difficulty(), SIGNAL(currentLevelChanged(const KgDifficultyLevel*)), SLOT(levelChanged())); |
299 | |
300 | setupGUI(); |
301 | } |
302 | |
303 | |