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
34KBlocksWin::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
61KBlocksWin::~KBlocksWin()
62{
63 delete mpGameView;
64 delete mpGameScene;
65 delete mpAIPlayer;
66 delete mpKBPlayer;
67}
68
69void KBlocksWin::setGamesPerLine(int count)
70{
71 mpGameScene->setGamesPerLine(count);
72}
73
74void KBlocksWin::setGameAnimEnabled(bool flag)
75{
76 mpGameScene->setGameAnimEnabled(flag);
77 mGameAnim = flag;
78}
79
80void KBlocksWin::setWaitForAllUpdate(bool flag)
81{
82 mpGameScene->setWaitForAllUpdate(flag);
83 mWaitForAll = flag;
84}
85
86void KBlocksWin::setUpdateInterval(int interval)
87{
88 mpGameScene->setUpdateInterval(interval);
89}
90
91void KBlocksWin::addScore(int gameIndex, int lineCount)
92{
93 mpGameScene->addScore(gameIndex, lineCount);
94}
95
96void 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
136void 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
149void 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
158void KBlocksWin::singleGame()
159{
160 mpPlayManager->stopGame();
161 mpPlayManager->clearGamePlayer();
162 mpPlayManager->addGamePlayer(mpKBPlayer, -1, -1);
163 mGameCount = 1;
164
165 startGame();
166}
167
168void 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
182void 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
196void KBlocksWin::closeEvent(QCloseEvent *event)
197{
198 Settings::self()->writeConfig();
199 KXmlGuiWindow::closeEvent(event);
200}
201
202void KBlocksWin::showHighscore()
203{
204 KScoreDialog ksdialog(KScoreDialog::Name | KScoreDialog::Level | KScoreDialog::Score, this);
205 ksdialog.initFromDifficulty(Kg::difficulty());
206 ksdialog.exec();
207}
208
209void 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
223void 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
231void 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
247void KBlocksWin::levelChanged()
248{
249 //Scene reads the difficulty level for us
250 startGame();
251 mpGameView->setFocus(Qt::MouseFocusReason);
252}
253
254void KBlocksWin::setSoundsEnabled(bool enabled)
255{
256 mpGameScene->setSoundsEnabled(enabled);
257 Settings::setSounds(enabled);
258}
259
260void 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