SVN_SILENT made messages (.desktop file)
[kdegames.git] / kapman / gamescene.cpp
blob5980344d016c3ecc2936a1e13e3190f1d8391a65
1 /*
2 * Copyright 2007-2008 Thomas Gallinari <tg8187@yahoo.fr>
3 * Copyright 2007-2008 Alexandre Galinier <alex.galinier@hotmail.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "gamescene.h"
20 #include "cell.h"
21 #include "bonus.h"
22 #include "settings.h"
24 #include <KGameTheme>
25 #include <KLocale>
27 GameScene::GameScene(Game* p_game) : m_game(p_game), m_kapmanItem(0), m_mazeItem(0) {
28 connect(p_game, SIGNAL(levelStarted(bool)), SLOT(intro(bool)));
29 connect(p_game, SIGNAL(gameStarted()), this, SLOT(start()));
30 connect(p_game, SIGNAL(pauseChanged(bool, bool)), this, SLOT(setPaused(bool, bool)));
31 connect(p_game, SIGNAL(elementEaten(qreal, qreal)), this, SLOT(hideElement(qreal, qreal)));
32 connect(p_game, SIGNAL(bonusOn()), this, SLOT(displayBonus()));
33 connect(p_game, SIGNAL(bonusOff()), this, SLOT(hideBonus()));
34 connect(p_game, SIGNAL(dataChanged(Game::InformationTypes)), this, SLOT(updateInfo(Game::InformationTypes)));
36 // Connection between Game and GameScene for the display of won points when a bonus or a ghost is eaten
37 connect(p_game, SIGNAL(pointsToDisplay(long, qreal, qreal)), this, SLOT(displayPoints(long, qreal, qreal)));
39 // Create the theme instance
40 m_theme = new KGameTheme();
42 // Set the pixmap cache limit to improve performance
43 setItemIndexMethod(NoIndex);
44 m_cache = new KPixmapCache("kapman_cache");
45 m_cache->setCacheLimit(3 * 1024);
47 // Load the SVG file
48 m_renderer = new KSvgRenderer();
49 loadTheme();
51 // Create the MazeItem
52 m_mazeItem = new MazeItem();
53 // Give the maze the shared renderer to avoid loading the whole SVG file again
54 m_mazeItem->setSharedRenderer(m_renderer);
55 // Set the element Id to the right value
56 m_mazeItem->setElementId("maze");
57 m_mazeItem->setZValue(-2);
59 // Create the KapmanItem
60 m_kapmanItem = new KapmanItem(p_game->getKapman());
61 m_kapmanItem->setSharedRenderer(m_renderer);
62 m_kapmanItem->setElementId("kapman_0");
63 // Corrects the position of the KapmanItem
64 m_kapmanItem->update(p_game->getKapman()->getX(), p_game->getKapman()->getY());
65 m_kapmanItem->setZValue(2);
66 // Stops the Kapman animation
67 m_kapmanItem->stopAnim();
69 // Create the GhostItems
70 for (int i = 0; i < p_game->getGhosts().size(); ++i) {
71 GhostItem* ghost = new GhostItem(p_game->getGhosts()[i]);
72 ghost->setSharedRenderer(m_renderer);
73 ghost->setElementId(p_game->getGhosts()[i]->getImageId());
74 ghost->update(p_game->getGhosts()[i]->getX(), p_game->getGhosts()[i]->getY());
75 // At the beginning, the ghosts are above the kapman because they eat him
76 ghost->setZValue(3);
77 m_ghostItems.append(ghost);
79 // Create the Pill and Energizer items
80 m_elementItems = new ElementItem**[m_game->getMaze()->getNbRows()];
81 for (int i = 0; i < m_game->getMaze()->getNbRows(); ++i) {
82 m_elementItems[i] = new ElementItem*[m_game->getMaze()->getNbColumns()];
83 for (int j = 0; j < m_game->getMaze()->getNbColumns(); ++j) {
84 if (m_game->getMaze()->getCell(i, j).getElement() != NULL) {
85 // Create the element and set the image
86 ElementItem* element = new ElementItem(m_game->getMaze()->getCell(i, j).getElement());
87 element->setSharedRenderer(m_renderer);
88 element->setElementId(m_game->getMaze()->getCell(i,j).getElement()->getImageId());
89 element->update(m_game->getMaze()->getCell(i, j).getElement()->getX(), m_game->getMaze()->getCell(i, j).getElement()->getY());
90 m_elementItems[i][j] = element;
91 } else {
92 m_elementItems[i][j] = NULL;
96 // Create the Bonus item
97 m_bonusItem = new ElementItem(m_game->getBonus());
98 m_bonusItem->setSharedRenderer(m_renderer);
99 m_bonusItem->setElementId("bonus1");
101 // All elements are created, update theme properties
102 updateSvgIds();
103 updateThemeProperties();
105 // Create the introduction labels
106 m_introLabel = new QGraphicsTextItem(i18n("GET READY!!!"));
107 m_introLabel->setFont(QFont("Helvetica", 25, QFont::Bold, false));
108 m_introLabel->setDefaultTextColor(QColor("#FFFF00"));
109 m_introLabel->setZValue(4);
110 m_introLabel2 = new QGraphicsTextItem(i18n("Press any arrow key to start"));
111 m_introLabel2->setFont(QFont("Helvetica", 15, QFont::Bold, false));
112 m_introLabel2->setDefaultTextColor(QColor("#FFFF00"));
113 m_introLabel2->setZValue(4);
114 // Create the new level label
115 m_newLevelLabel = new QGraphicsTextItem();
116 m_newLevelLabel->setFont(QFont("Helvetica", 35, QFont::Bold, false));
117 m_newLevelLabel->setDefaultTextColor(QColor("#FFFF00"));
118 m_newLevelLabel->setZValue(4);
119 // Create the pause label
120 m_pauseLabel = new QGraphicsTextItem(i18n("PAUSED"));
121 m_pauseLabel->setFont(QFont("Helvetica", 35, QFont::Bold, false));
122 m_pauseLabel->setDefaultTextColor(QColor("#FFFF00"));
123 m_pauseLabel->setZValue(4);
124 // Create the score label
125 m_scoreLabel = new QGraphicsTextItem();
126 m_scoreLabel->setFont(QFont("Helvetica", 15, QFont::Bold, false));
127 m_scoreLabel->setDefaultTextColor(QColor("#FFFFFF"));
128 // Create the lives label
129 m_livesLabel = new QGraphicsTextItem();
130 m_livesLabel->setFont(QFont("Helvetica", 15, QFont::Bold, false));
131 m_livesLabel->setDefaultTextColor(QColor("#FFFFFF"));
132 // Create the level label
133 m_levelLabel = new QGraphicsTextItem();
134 m_levelLabel->setFont(QFont("Helvetica", 15, QFont::Bold, false));
135 m_levelLabel->setDefaultTextColor(QColor("#FFFFFF"));
137 // Display the MazeItem
138 addItem(m_mazeItem);
139 // Display the KapmanItem
140 addItem(m_kapmanItem);
141 // Display each GhostItem
142 for (int i = 0; i < m_ghostItems.size(); ++i) {
143 addItem(m_ghostItems[i]);
145 // Initialize the information labels (score, lives and label)
146 updateInfo(Game::AllInfo);
147 // Display the score label
148 addItem(m_scoreLabel);
149 m_scoreLabel->setPos(Cell::SIZE, height() + Cell::SIZE);
150 // Display the level label
151 addItem(m_levelLabel);
152 m_levelLabel->setPos((width() - m_levelLabel->boundingRect().width()) / 2 , height() + Cell::SIZE);
153 // Display the lives label
154 addItem(m_livesLabel);
155 m_livesLabel->setPos(width() - m_livesLabel->boundingRect().width() - Cell::SIZE , height() + Cell::SIZE);
156 // Display each Pill and Energizer item and introduction labels
157 intro(true);
160 GameScene::~GameScene() {
161 delete m_mazeItem;
162 delete m_kapmanItem;
163 for (int i = 0; i < m_ghostItems.size(); ++i) {
164 delete m_ghostItems[i];
166 for (int i = 0; i < m_game->getMaze()->getNbRows();++i) {
167 for (int j = 0; j < m_game->getMaze()->getNbColumns(); ++j) {
168 if (m_elementItems[i][j] != NULL) {
169 delete m_elementItems[i][j];
172 delete[] m_elementItems[i];
174 delete[] m_elementItems;
175 delete m_bonusItem;
176 delete m_introLabel;
177 delete m_introLabel2;
178 delete m_newLevelLabel;
179 delete m_scoreLabel;
180 delete m_livesLabel;
181 delete m_levelLabel;
182 delete m_pauseLabel;
183 delete m_cache;
184 delete m_renderer;
185 delete m_theme;
188 Game* GameScene::getGame() const {
189 return m_game;
192 void GameScene::loadTheme() {
193 if (!m_theme->load(Settings::self()->theme())) {
194 return;
196 if (!m_renderer->load(m_theme->graphics())) {
197 return;
199 m_cache->discard();
201 //Update elementIDs, theme properties
202 updateSvgIds();
203 updateThemeProperties();
205 update(0, 0, width(), height());
207 // Update the theme config: if the default theme is selected, no theme entry is written -> the theme selector does not select the theme
208 Settings::self()->config()->group("General").writeEntry("Theme", Settings::self()->theme());
211 void GameScene::updateSvgIds() {
212 //Needed so new boundingRects() are read for all SVG elements after a theme change
213 // Sanity check, see if game elements already exist
214 if (!m_kapmanItem) return;
216 // Set the element Id to the right value
217 m_mazeItem->setElementId("maze");
219 // Create the KapmanItem
220 m_kapmanItem->setElementId("kapman_0");
221 // Corrects the position of the KapmanItem
222 m_kapmanItem->update(m_game->getKapman()->getX(), m_game->getKapman()->getY());
224 for (int i = 0; i < m_ghostItems.size(); ++i) {
225 GhostItem* ghost = m_ghostItems[i];
226 ghost->setElementId(m_game->getGhosts()[i]->getImageId());
227 ghost->update(m_game->getGhosts()[i]->getX(), m_game->getGhosts()[i]->getY());
229 for (int i = 0; i < m_game->getMaze()->getNbRows();++i) {
230 for (int j = 0; j < m_game->getMaze()->getNbColumns(); ++j) {
231 if (m_elementItems[i][j] != NULL) {
232 ElementItem* element = m_elementItems[i][j];
233 element->setElementId(m_game->getMaze()->getCell(i,j).getElement()->getImageId());
234 element->update(m_game->getMaze()->getCell(i, j).getElement()->getX(), m_game->getMaze()->getCell(i, j).getElement()->getY());
240 void GameScene::updateThemeProperties() {
241 // Sanity check, see if game elements already exist
242 if (!m_kapmanItem) return;
244 // Set the Rotation flag for KapmanItem
245 if (m_theme->themeProperty("RotateKapman")=="0") {
246 m_kapmanItem->setRotationFlag(false);
247 } else {
248 m_kapmanItem->setRotationFlag(true);
252 void GameScene::intro(const bool p_newLevel) {
253 // If a new level has begun
254 if (p_newLevel) {
255 // Set each Pill and Energizer item to its original coordinates
256 for (int i = 0; i < m_game->getMaze()->getNbRows(); ++i) {
257 for (int j = 0; j < m_game->getMaze()->getNbColumns(); ++j) {
258 if (m_elementItems[i][j] != NULL) {
259 if (!items().contains(m_elementItems[i][j])) {
260 addItem(m_elementItems[i][j]);
265 // Display the new level label
266 m_newLevelLabel->setPlainText(i18nc("The number of the game level", "Level %1", m_game->getLevel()));
267 if (!items().contains(m_newLevelLabel)) {
268 addItem(m_newLevelLabel);
269 m_newLevelLabel->setPos((width() - m_newLevelLabel->boundingRect().width()) / 2, (height() - m_newLevelLabel->boundingRect().height()) / 2);
271 // Display the introduction label
272 if (!items().contains(m_introLabel2)) {
273 addItem(m_introLabel2);
274 m_introLabel2->setPos((width() - m_introLabel2->boundingRect().width()) / 2,
275 (height() - m_introLabel2->boundingRect().height() + m_newLevelLabel->boundingRect().height()) / 2);
277 } else {
278 // Display the introduction labels
279 if (!items().contains(m_introLabel)) {
280 addItem(m_introLabel);
281 m_introLabel->setPos((width() - m_introLabel->boundingRect().width()) / 2, (height() - m_introLabel->boundingRect().height()) / 2);
283 if (!items().contains(m_introLabel2)) {
284 addItem(m_introLabel2);
285 m_introLabel2->setPos((width() - m_introLabel2->boundingRect().width()) / 2,
286 (height() - m_introLabel2->boundingRect().height() + m_introLabel->boundingRect().height()) / 2);
291 void GameScene::start() {
292 // If the introduction and new level labels were displayed then remove them
293 if (items().contains(m_introLabel)) {
294 removeItem(m_introLabel);
296 if (items().contains(m_introLabel2)) {
297 removeItem(m_introLabel2);
299 if (items().contains(m_newLevelLabel)) {
300 removeItem(m_newLevelLabel);
304 void GameScene::setPaused(const bool p_pause, const bool p_fromUser) {
305 // If the game has paused
306 if (p_pause) {
307 // If the pause is due to an action from the user
308 if (p_fromUser) {
309 // If the label was not displayed yet
310 if (!items().contains(m_pauseLabel)) {
311 // Display the pause label
312 addItem(m_pauseLabel);
313 m_pauseLabel->setPos((width() - m_pauseLabel->boundingRect().width()) / 2, (height() - m_pauseLabel->boundingRect().height()) / 2);
316 // Stop kapman animation
317 m_kapmanItem->pauseAnim();
318 } else { // If the game has resumed
319 // If the pause was due to an action from the user
320 if (p_fromUser) {
321 // If the label was displayed
322 if (items().contains(m_pauseLabel)) {
323 removeItem(m_pauseLabel);
326 // Resume kapman animation
327 m_kapmanItem->resumeAnim();
331 void GameScene::hideElement(const qreal p_x, const qreal p_y) {
332 if (items().contains(m_elementItems[(int)((p_y - (Cell::SIZE * 0.5)) / Cell::SIZE)][(int)((p_x - (Cell::SIZE * 0.5)) / Cell::SIZE)])) {
333 removeItem(m_elementItems[(int)((p_y - (Cell::SIZE * 0.5)) / Cell::SIZE)][(int)((p_x - (Cell::SIZE * 0.5)) / Cell::SIZE)]);
337 void GameScene::displayBonus() {
338 if (!items().contains(m_bonusItem)) {
339 switch (m_game->getLevel()) {
340 case 1:
341 m_bonusItem->setElementId("bonus1");
342 break;
343 case 2:
344 m_bonusItem->setElementId("bonus2");
345 break;
346 case 3:
347 m_bonusItem->setElementId("bonus3");
348 break;
349 case 4:
350 m_bonusItem->setElementId("bonus4");
351 break;
352 case 5:
353 m_bonusItem->setElementId("bonus5");
354 break;
355 case 6:
356 m_bonusItem->setElementId("bonus6");
357 break;
358 default:
359 m_bonusItem->setElementId("bonus7");
360 break;
362 m_bonusItem->update(m_game->getBonus()->getX(), m_game->getBonus()->getY());
363 addItem(m_bonusItem);
367 void GameScene::hideBonus() {
368 if (items().contains(m_bonusItem)) {
369 removeItem(m_bonusItem);
373 void GameScene::updateInfo(const Game::InformationTypes p_info) {
374 if (p_info & Game::LivesInfo) {
375 m_livesLabel->setPlainText(i18n("Lives: %1", m_game->getLives()));
377 if (p_info & Game::ScoreInfo) {
378 m_scoreLabel->setPlainText(i18n("Score: %1", m_game->getScore()));
380 if (p_info & Game::LevelInfo) {
381 m_levelLabel->setPlainText(i18nc("The number of the game level", "Level: %1", m_game->getLevel()));
385 void GameScene::displayPoints(long p_wonPoints, qreal p_xPos, qreal p_yPos) {
386 // Launch a singleShot timer
387 QTimer::singleShot(1000, this, SLOT(hidePoints()));
389 // Add a label in the list of won points Labels
390 m_wonPointsLabels.prepend(new QGraphicsTextItem(QString::number(p_wonPoints)));
391 addItem(m_wonPointsLabels.first());
393 // Temporary reference to the first item in the list
394 QGraphicsTextItem* tempRef = m_wonPointsLabels.first();
396 // Positioning and customization of the point label
397 tempRef->setDefaultTextColor(QColor("#FFFF00"));
398 tempRef->setFont(QFont("Helvetica", 15, QFont::Normal, false));
399 tempRef->setPos(p_xPos-(tempRef->boundingRect().width() / 2), p_yPos-(tempRef->boundingRect().height() / 2));
400 tempRef->setZValue(-1);
403 void GameScene::hidePoints() {
404 // Remove the oldest item of the list from the scene
405 removeItem(m_wonPointsLabels.last());
406 // Remove the oldest item from the list
407 delete m_wonPointsLabels.takeLast();