1 | /* |
2 | * Copyright 2009 Mathias Kraus <k.hias@gmx.de> |
3 | * Copyright 2007-2008 Thomas Gallinari <tg8187@yahoo.fr> |
4 | * Copyright 2007-2008 Pierre-Benoit Besse <besse@gmail.com> |
5 | * Copyright 2007-2008 Alexandre Galinier <alex.galinier@hotmail.com> |
6 | * |
7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License as |
9 | * published by the Free Software Foundation; either version 2 of |
10 | * the License, or (at your option) any later version. |
11 | * |
12 | * This program is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * GNU General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU General Public License |
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | */ |
20 | |
21 | #include "game.h" |
22 | #include "mapparser.h" |
23 | #include "settings.h" |
24 | #include "gamescene.h" |
25 | #include "arena.h" |
26 | #include "player.h" |
27 | #include "bonus.h" |
28 | #include "bomb.h" |
29 | #include "block.h" |
30 | #include "config/playersettings.h" |
31 | |
32 | #include <QPointF> |
33 | #include <QTimer> |
34 | #include <QKeyEvent> |
35 | |
36 | #include <KStandardDirs> |
37 | #include <KConfig> |
38 | #include <KComponentData> |
39 | #include <kgsound.h> |
40 | |
41 | Game::Game(PlayerSettings* playerSettings) |
42 | { |
43 | m_playerSettings = playerSettings; |
44 | |
45 | // Initialize the sound state |
46 | setSoundsEnabled(Settings::sounds()); |
47 | m_wilhelmScream = Settings::useWilhelmScream(); |
48 | |
49 | m_soundPutBomb = new KgSound(KStandardDirs::locate("appdata" , "sounds/putbomb.wav" )); |
50 | m_soundExplode = new KgSound(KStandardDirs::locate("appdata" , "sounds/explode.wav" )); |
51 | m_soundBonus = new KgSound(KStandardDirs::locate("appdata" , "sounds/wow.wav" )); |
52 | m_soundFalling = new KgSound(KStandardDirs::locate("appdata" , "sounds/deepfall.wav" )); |
53 | m_soundDie = new KgSound(KStandardDirs::locate("appdata" , "sounds/die.wav" )); |
54 | |
55 | m_arena = 0; |
56 | m_randomArenaModeArenaList.clear(); |
57 | m_gameScene = 0; |
58 | m_winPoints = Settings::self()->pointsToWin(); |
59 | |
60 | QStringList strPlayerIDs = m_playerSettings->playerIDs(); |
61 | for(int i = 0; i < strPlayerIDs.count(); i++) |
62 | { |
63 | if(m_playerSettings->enabled(strPlayerIDs[i])) |
64 | { |
65 | Player* player = new Player(qreal(Granatier::CellSize * (-0.5)),qreal(Granatier::CellSize * 0.5), strPlayerIDs[i], playerSettings, m_arena); |
66 | m_players.append(player); |
67 | connect(player, SIGNAL(dying()), this, SLOT(playerDeath())); |
68 | connect(player, SIGNAL(falling()), this, SLOT(playerFalling())); |
69 | connect(player, SIGNAL(resurrectBonusTaken()), this, SLOT(resurrectBonusTaken())); |
70 | } |
71 | } |
72 | |
73 | init(); |
74 | |
75 | for (int i = 0; i < m_players.size(); i++) |
76 | { |
77 | connect(m_players[i], SIGNAL(bombDropped(Player*,qreal,qreal,bool,int)), this, SLOT(createBomb(Player*,qreal,qreal,bool,int))); |
78 | } |
79 | |
80 | m_gameOver = false; |
81 | } |
82 | |
83 | void Game::init() |
84 | { |
85 | // Create the Arena instance |
86 | m_arena = new Arena(); |
87 | |
88 | m_remainingTime = Settings::roundTime(); |
89 | m_bombCount = 0; |
90 | |
91 | // Create the parser that will parse the XML file in order to initialize the Arena instance |
92 | // This also creates all the characters |
93 | MapParser mapParser(m_arena); |
94 | // Set the XML file as input source for the parser |
95 | QString filePath; |
96 | if(Settings::self()->randomArenaMode()) |
97 | { |
98 | if(m_randomArenaModeArenaList.isEmpty()) |
99 | { |
100 | QStringList arenasAvailable; |
101 | m_randomArenaModeArenaList = Settings::self()->randomArenaModeArenaList(); |
102 | |
103 | KGlobal::dirs()->addResourceType("arenaselector" , "data" , KGlobal::mainComponent().componentName() + "/arenas/" ); |
104 | KGlobal::dirs()->findAllResources("arenaselector" , "*.desktop" , KStandardDirs::Recursive, arenasAvailable); |
105 | |
106 | QStringList::Iterator i = m_randomArenaModeArenaList.begin(); |
107 | while(i != m_randomArenaModeArenaList.end()) |
108 | { |
109 | if(arenasAvailable.contains(*i)) |
110 | { |
111 | i++; |
112 | } |
113 | else |
114 | { |
115 | i = m_randomArenaModeArenaList.erase(i); |
116 | } |
117 | } |
118 | |
119 | if(m_randomArenaModeArenaList.isEmpty()) |
120 | { |
121 | m_randomArenaModeArenaList = arenasAvailable; |
122 | } |
123 | } |
124 | |
125 | int nIndex = ((double) qrand() / RAND_MAX) * m_randomArenaModeArenaList.count(); |
126 | if(nIndex < 0) |
127 | { |
128 | nIndex = 0; |
129 | } |
130 | else if(nIndex >= m_randomArenaModeArenaList.count()) |
131 | { |
132 | nIndex = m_randomArenaModeArenaList.count() - 1; |
133 | } |
134 | filePath = KStandardDirs::locate("appdata" , "arenas/" + m_randomArenaModeArenaList.at(nIndex)); |
135 | m_randomArenaModeArenaList.removeAt(nIndex); |
136 | } |
137 | else |
138 | { |
139 | filePath = KStandardDirs::locate("appdata" , Settings::self()->arena()); |
140 | } |
141 | |
142 | if(!QFile::exists(filePath)) |
143 | { |
144 | Settings::self()->useDefaults(true); |
145 | filePath = KStandardDirs::locate("appdata" , Settings::self()->arena()); |
146 | Settings::self()->useDefaults(false); |
147 | } |
148 | |
149 | KConfig arenaConfig(filePath, KConfig::SimpleConfig); |
150 | KConfigGroup group = arenaConfig.group("Arena" ); |
151 | QString arenaFileName = group.readEntry("FileName" ); |
152 | |
153 | QFile arenaXmlFile(KStandardDirs::locate("appdata" , QString("arenas/%1" ).arg(arenaFileName))); |
154 | //QFile arenaXmlFile(KStandardDirs::locate("appdata", "arenas/granatier.xml")); |
155 | QXmlInputSource source(&arenaXmlFile); |
156 | // Create the XML file reader |
157 | QXmlSimpleReader reader; |
158 | reader.setContentHandler(&mapParser); |
159 | // Parse the XML file |
160 | reader.parse(source); |
161 | |
162 | QString arenaName = group.readEntry("Name" ); |
163 | m_arena->setName(arenaName); |
164 | |
165 | //create the block items |
166 | for (int i = 0; i < m_arena->getNbRows(); ++i) |
167 | { |
168 | for (int j = 0; j < m_arena->getNbColumns(); ++j) |
169 | { |
170 | if(m_arena->getCell(i,j).getType() == Granatier::Cell::BLOCK) |
171 | { |
172 | Block* block = new Block((j + 0.5) * Granatier::CellSize, (i + 0.5) * Granatier::CellSize, m_arena, "arena_block" ); |
173 | m_blocks.append(block); |
174 | m_arena->setCellElement(i, j, block); |
175 | } |
176 | } |
177 | } |
178 | |
179 | // Start the Game timer |
180 | m_timer = new QTimer(this); |
181 | m_timer->setInterval(int(1000 / Granatier::FPS)); |
182 | connect(m_timer, SIGNAL(timeout()), this, SLOT(update())); |
183 | m_timer->start(); |
184 | m_state = RUNNING; |
185 | |
186 | m_roundTimer = new QTimer(this); |
187 | m_roundTimer->setInterval(1000); |
188 | connect(m_roundTimer, SIGNAL(timeout()), this, SLOT(decrementRemainingRoundTime())); |
189 | m_roundTimer->start(); |
190 | |
191 | m_setRoundFinishedTimer = new QTimer(this); |
192 | m_setRoundFinishedTimer->setSingleShot(true); |
193 | connect(m_setRoundFinishedTimer, SIGNAL(timeout()), this, SLOT(setRoundFinished())); |
194 | |
195 | // Init the characters coordinates on the Arena |
196 | for (int i = 0; i < m_players.size(); i++) |
197 | { |
198 | m_players[i]->setArena(m_arena); |
199 | QPointF playerPosition = m_arena->getPlayerPosition(i); |
200 | m_players[i]->setInitialCoordinates(qreal(Granatier::CellSize * playerPosition.x()), qreal(Granatier::CellSize * playerPosition.y())); |
201 | } |
202 | initCharactersPosition(); |
203 | |
204 | // Create the hidden Bonuses |
205 | createBonus(); |
206 | } |
207 | |
208 | Game::~Game() |
209 | { |
210 | //pause is needed to stop all animations and therefore the access of the *items to their model |
211 | pause(true); |
212 | |
213 | qDeleteAll(m_players); |
214 | m_players.clear(); |
215 | |
216 | cleanUp(); |
217 | |
218 | delete m_soundPutBomb; |
219 | delete m_soundExplode; |
220 | delete m_soundBonus; |
221 | delete m_soundFalling; |
222 | delete m_soundDie; |
223 | } |
224 | |
225 | void Game::cleanUp() |
226 | { |
227 | qDeleteAll(m_blocks); |
228 | m_blocks.clear(); |
229 | qDeleteAll(m_bonus); |
230 | m_bonus.clear(); |
231 | qDeleteAll(m_bombs); |
232 | m_bombs.clear(); |
233 | delete m_arena; |
234 | m_arena = 0; |
235 | delete m_timer; |
236 | m_timer = 0; |
237 | delete m_roundTimer; |
238 | m_roundTimer = 0; |
239 | delete m_setRoundFinishedTimer; |
240 | m_setRoundFinishedTimer = 0; |
241 | } |
242 | |
243 | void Game::setGameScene(GameScene* p_gameScene) |
244 | { |
245 | m_gameScene = p_gameScene; |
246 | } |
247 | |
248 | void Game::start() |
249 | { |
250 | // Restart the Game timer |
251 | m_timer->start(); |
252 | m_state = RUNNING; |
253 | m_roundTimer->start(); |
254 | emit(pauseChanged(false, false)); |
255 | } |
256 | |
257 | void Game::pause(bool p_locked) |
258 | { |
259 | // Stop the Game timer |
260 | m_timer->stop(); |
261 | m_roundTimer->stop(); |
262 | if (p_locked) |
263 | { |
264 | m_state = PAUSED_LOCKED; |
265 | } |
266 | else |
267 | { |
268 | m_state = PAUSED_UNLOCKED; |
269 | } |
270 | emit(pauseChanged(true, false)); |
271 | } |
272 | |
273 | void Game::switchPause() |
274 | { |
275 | // If the Game is not already paused |
276 | if (m_state == RUNNING) |
277 | { |
278 | // Pause the Game |
279 | pause(); |
280 | emit(pauseChanged(true, true)); |
281 | } |
282 | // If the Game is already paused |
283 | else |
284 | { |
285 | // Resume the Game |
286 | start(); |
287 | emit(pauseChanged(false, true)); |
288 | } |
289 | } |
290 | |
291 | QList<Player*> Game::getPlayers() const |
292 | { |
293 | return m_players; |
294 | } |
295 | |
296 | QTimer* Game::getTimer() const |
297 | { |
298 | return m_timer; |
299 | } |
300 | |
301 | int Game::getRemainingTime() const |
302 | { |
303 | return m_remainingTime; |
304 | } |
305 | |
306 | Arena* Game::getArena() const |
307 | { |
308 | return m_arena; |
309 | } |
310 | |
311 | bool Game::isPaused() const |
312 | { |
313 | return (m_state != RUNNING); |
314 | } |
315 | |
316 | bool Game::getGameOver() const |
317 | { |
318 | return m_gameOver; |
319 | } |
320 | |
321 | QString Game::getWinner() const |
322 | { |
323 | return m_strWinner; |
324 | } |
325 | |
326 | int Game::getWinPoints() const |
327 | { |
328 | return m_winPoints; |
329 | } |
330 | |
331 | QList<Bonus*> Game::getBonus() const |
332 | { |
333 | return m_bonus; |
334 | } |
335 | |
336 | void Game::createBonus() |
337 | { |
338 | Bonus* bonus; |
339 | int nBonusCount = 0.3 * m_blocks.size(); |
340 | int nBadBonusCount = 0.1 * m_blocks.size(); |
341 | int nNeutralBonusCount = static_cast <int> ((qrand()/1.0)/RAND_MAX * 2); |
342 | QList<Granatier::Bonus::Type> bonusTypeList; |
343 | Granatier::Bonus::Type bonusType; |
344 | for (int i = 0; i < m_blocks.size(); i++) |
345 | { |
346 | bonusType = Granatier::Bonus::NONE; |
347 | if(i < nBonusCount) |
348 | { |
349 | int nNumberOfBonuses = 6; |
350 | switch (static_cast <int> ((qrand()/1.0)/RAND_MAX * nNumberOfBonuses)) |
351 | { |
352 | case 0: bonusType = Granatier::Bonus::SPEED; |
353 | break; |
354 | case 1: bonusType = Granatier::Bonus::BOMB; |
355 | break; |
356 | case 2: bonusType = Granatier::Bonus::POWER; |
357 | break; |
358 | case 3: bonusType = Granatier::Bonus::SHIELD; |
359 | break; |
360 | case 4: bonusType = Granatier::Bonus::THROW; |
361 | break; |
362 | case 5: bonusType = Granatier::Bonus::KICK; |
363 | break; |
364 | default: bonusType = Granatier::Bonus::SPEED; |
365 | } |
366 | } |
367 | else if (i-nBonusCount < nBadBonusCount) |
368 | { |
369 | switch (static_cast <int> ((qrand()/1.0)/RAND_MAX * 5)) |
370 | { |
371 | case 0: bonusType = Granatier::Bonus::HYPERACTIVE; |
372 | break; |
373 | case 1: bonusType = Granatier::Bonus::SLOW; |
374 | break; |
375 | case 2: bonusType = Granatier::Bonus::MIRROR; |
376 | break; |
377 | case 3: bonusType = Granatier::Bonus::SCATTY; |
378 | break; |
379 | case 4: bonusType = Granatier::Bonus::RESTRAIN; |
380 | break; |
381 | default: bonusType = Granatier::Bonus::HYPERACTIVE; |
382 | } |
383 | } |
384 | else if(i-nBonusCount-nBadBonusCount < nNeutralBonusCount) |
385 | { |
386 | bonusType = Granatier::Bonus::RESURRECT; |
387 | } |
388 | bonusTypeList.append(bonusType); |
389 | } |
390 | |
391 | int nShuffle; |
392 | for (int i = 0; i < m_blocks.size(); i++) |
393 | { |
394 | nShuffle = m_blocks.size() * (qrand()/1.0)/RAND_MAX; |
395 | if(nShuffle >= m_blocks.size()) |
396 | { |
397 | nShuffle = m_blocks.size() - 1; |
398 | } |
399 | else if(nShuffle < 0) |
400 | { |
401 | nShuffle = 0; |
402 | } |
403 | bonusTypeList.swap(i, nShuffle); |
404 | } |
405 | |
406 | for (int i = 0; i < m_blocks.size(); ++i) |
407 | { |
408 | if(bonusTypeList[i] != Granatier::Bonus::NONE) |
409 | { |
410 | bonus = new Bonus(m_blocks[i]->getX(), m_blocks[i]->getY(), m_arena, bonusTypeList[i]); |
411 | m_bonus.append(bonus); |
412 | m_blocks[i]->setBonus(bonus); |
413 | } |
414 | } |
415 | } |
416 | |
417 | void Game::removeBonus(Bonus* bonus) |
418 | { |
419 | m_bonus.removeAt(m_bonus.indexOf(bonus)); |
420 | //do not delete the Bonus, because the ElementItem will delete it |
421 | if(m_soundEnabled && !bonus->isDestroyed()) |
422 | { |
423 | m_soundBonus->start(); |
424 | } |
425 | } |
426 | |
427 | void Game::setSoundsEnabled(bool p_enabled) |
428 | { |
429 | m_soundEnabled = p_enabled; |
430 | Settings::setSounds(p_enabled); |
431 | Settings::self()->writeConfig(); |
432 | } |
433 | |
434 | void Game::initCharactersPosition() |
435 | { |
436 | // If the timer is stopped, it means that collisions are already being handled |
437 | if (m_timer->isActive()) |
438 | { |
439 | // At the beginning, the timer is stopped but the Game isn't paused (to allow keyPressedEvent detection) |
440 | m_timer->stop(); |
441 | m_roundTimer->stop(); |
442 | m_state = RUNNING; |
443 | // Initialize the Player coordinates |
444 | for(int i = 0; i < m_players.size(); i++) |
445 | { |
446 | m_players[i]->initCoordinate(); |
447 | m_players[i]->init(); |
448 | } |
449 | } |
450 | } |
451 | |
452 | void Game::keyPressEvent(QKeyEvent* p_event) |
453 | { |
454 | if(p_event->isAutoRepeat()) |
455 | { |
456 | return; |
457 | } |
458 | |
459 | // At the beginning or when paused, we start the timer when a key is pressed |
460 | if (!m_timer->isActive()) |
461 | { |
462 | if(p_event->key() == Qt::Key_Space) |
463 | { |
464 | // If paused |
465 | if (m_state == PAUSED_UNLOCKED) |
466 | { |
467 | switchPause(); |
468 | } |
469 | else if (m_state == RUNNING) // At the game beginning |
470 | { |
471 | // Start the game |
472 | m_timer->start(); |
473 | m_roundTimer->start(); |
474 | emit(gameStarted()); |
475 | } |
476 | else if (m_state == PAUSED_LOCKED) |
477 | { |
478 | // if the game is over, start a new game |
479 | if (m_gameOver) |
480 | { |
481 | emit(gameOver()); |
482 | return; |
483 | } |
484 | else |
485 | { |
486 | m_gameScene->cleanUp(); |
487 | cleanUp(); |
488 | init(); |
489 | m_gameScene->init(); |
490 | for(int i = 0; i < m_players.length(); i++) |
491 | { |
492 | m_players[i]->resurrect(); |
493 | } |
494 | } |
495 | } |
496 | } |
497 | return; |
498 | } |
499 | // Behaviour when the game has begun |
500 | switch (p_event->key()) |
501 | { |
502 | case Qt::Key_P: |
503 | case Qt::Key_Escape: |
504 | switchPause(); |
505 | return; |
506 | default: |
507 | break; |
508 | } |
509 | |
510 | //TODO: make signal |
511 | for(int i = 0; i < m_players.size(); i++) |
512 | { |
513 | m_players[i]->keyPressed(p_event); |
514 | } |
515 | } |
516 | |
517 | void Game::keyReleaseEvent(QKeyEvent* p_event) |
518 | { |
519 | if(p_event->isAutoRepeat()) |
520 | { |
521 | return; |
522 | } |
523 | //TODO: make signal |
524 | for(int i = 0; i < m_players.size(); i++) |
525 | { |
526 | m_players[i]->keyReleased(p_event); |
527 | } |
528 | } |
529 | |
530 | void Game::update() |
531 | { |
532 | //update Bombs |
533 | for (int i = 0; i < m_bombs.size(); ++i) |
534 | { |
535 | m_bombs[i]->updateMove(); |
536 | } |
537 | |
538 | //update Player |
539 | for(int i = 0; i < m_players.size(); i++) |
540 | { |
541 | m_players[i]->updateMove(); |
542 | m_players[i]->emitGameUpdated(); |
543 | } |
544 | } |
545 | |
546 | void Game::decrementRemainingRoundTime() |
547 | { |
548 | m_remainingTime--; |
549 | if(m_remainingTime >= 0) |
550 | { |
551 | emit(infoChanged(Granatier::Info::TimeInfo)); |
552 | } |
553 | else |
554 | { |
555 | if(m_remainingTime % 2 == 0) |
556 | { |
557 | //create bombs at randoms places |
558 | int nRow; |
559 | int nCol; |
560 | Granatier::Cell::Type cellType; |
561 | bool bFound = false; |
562 | do |
563 | { |
564 | nRow = m_arena->getNbRows() * (qrand()/1.0)/RAND_MAX; |
565 | nCol = m_arena->getNbColumns() * (qrand()/1.0)/RAND_MAX; |
566 | cellType = m_arena->getCell(nRow, nCol).getType(); |
567 | if(cellType != Granatier::Cell::WALL && cellType != Granatier::Cell::HOLE && m_arena->getCell(nRow, nCol).isWalkable(0)) |
568 | { |
569 | bFound = true; |
570 | } |
571 | } |
572 | while (!bFound); |
573 | |
574 | m_bombCount++; |
575 | Bomb* bomb = new Bomb((nCol + 0.5) * Granatier::CellSize, (nRow + 0.5) * Granatier::CellSize, m_arena, m_bombCount, 1000); // time in ms |
576 | bomb->setBombPower((qrand()/1.0)/RAND_MAX * 2 + 1); |
577 | emit bombCreated(bomb); |
578 | connect(bomb, SIGNAL(bombDetonated(Bomb*)), this, SLOT(bombDetonated())); |
579 | m_bombs.append(bomb); |
580 | if(m_remainingTime > -100 && m_roundTimer->interval() > 150) |
581 | { |
582 | m_roundTimer->setInterval(m_roundTimer->interval() + m_remainingTime); |
583 | } |
584 | else if (m_roundTimer->interval() > 30) |
585 | { |
586 | m_roundTimer->setInterval(m_roundTimer->interval() - 1); |
587 | } |
588 | } |
589 | } |
590 | } |
591 | |
592 | void Game::playerFalling() |
593 | { |
594 | if(m_soundEnabled) |
595 | { |
596 | m_soundFalling->start(); |
597 | } |
598 | } |
599 | |
600 | void Game::playerDeath() |
601 | { |
602 | if(m_soundEnabled) |
603 | { |
604 | m_soundDie->start(); |
605 | } |
606 | |
607 | //check if at most one player is alive if not already finished |
608 | if(!m_setRoundFinishedTimer->isActive()) |
609 | { |
610 | int nPlayerAlive = 0; |
611 | for(int i = 0; i < m_players.length(); i++) |
612 | { |
613 | if(m_players[i]->isAlive()) |
614 | { |
615 | nPlayerAlive++; |
616 | } |
617 | } |
618 | if(nPlayerAlive <= 1) |
619 | { |
620 | //wait some time until the game stops |
621 | m_setRoundFinishedTimer->start(1500); |
622 | } |
623 | } |
624 | } |
625 | |
626 | void Game::resurrectBonusTaken() |
627 | { |
628 | for(int i = 0; i < m_players.length(); i++) |
629 | { |
630 | if(!(m_players[i]->isAlive())) |
631 | { |
632 | m_players[i]->resurrect(); |
633 | } |
634 | } |
635 | } |
636 | |
637 | void Game::setRoundFinished() |
638 | { |
639 | int nPlayerAlive = 0; |
640 | int nIndex = 0;; |
641 | if(m_gameOver) |
642 | { |
643 | return; |
644 | } |
645 | for(int i = 0; i < m_players.length(); i++) |
646 | { |
647 | if(m_players[i]->isAlive()) |
648 | { |
649 | nPlayerAlive++; |
650 | nIndex = i; |
651 | } |
652 | } |
653 | //this check is needed, if in the meantime the resurrect bonus was taken |
654 | if (nPlayerAlive > 1) |
655 | { |
656 | return; |
657 | } |
658 | |
659 | if (nPlayerAlive == 1) |
660 | { |
661 | m_players[nIndex]->addPoint(); |
662 | } |
663 | |
664 | pause(true); |
665 | |
666 | for(int i = 0; i < m_players.length(); i++) |
667 | { |
668 | // check if a player reaches the win points |
669 | if (m_players[i]->points() >= m_winPoints) |
670 | { |
671 | m_gameOver = true; |
672 | m_strWinner = m_players[i]->getPlayerName(); |
673 | break; |
674 | } |
675 | } |
676 | m_gameScene->showScore(); |
677 | } |
678 | |
679 | void Game::createBomb(Player* player, qreal x, qreal y, bool newBomb, int throwDistance) |
680 | { |
681 | int col = m_arena->getColFromX(x); |
682 | int row = m_arena->getRowFromY(y); |
683 | if(col >= 0 && col < m_arena->getNbColumns() && row >= 0 && row < m_arena->getNbRows()) |
684 | { |
685 | QList<Element*> bombElements = m_arena->getCell(row, col).getElements(Granatier::Element::BOMB); |
686 | if (!bombElements.isEmpty()) |
687 | { |
688 | if(player->hasThrowBomb() && throwDistance > 0) |
689 | { |
690 | foreach(Element* element, bombElements) |
691 | { |
692 | dynamic_cast <Bomb*> (element)->setThrown(player->direction()); |
693 | } |
694 | } |
695 | return; |
696 | } |
697 | } |
698 | |
699 | if(!newBomb) |
700 | { |
701 | return; |
702 | } |
703 | |
704 | m_bombCount++; |
705 | Bomb* bomb = new Bomb((col + 0.5) * Granatier::CellSize, (row + 0.5) * Granatier::CellSize, m_arena, m_bombCount, 2500); // time in ms |
706 | bomb->setBombPower(player->getBombPower()); |
707 | emit bombCreated(bomb); |
708 | connect(bomb, SIGNAL(bombDetonated(Bomb*)), this, SLOT(bombDetonated())); |
709 | connect(bomb, SIGNAL(releaseBombArmory()), player, SLOT(slot_refillBombArmory())); |
710 | m_bombs.append(bomb); |
711 | player->decrementBombArmory(); |
712 | |
713 | if(m_soundEnabled) |
714 | { |
715 | m_soundPutBomb->start(); |
716 | } |
717 | } |
718 | |
719 | void Game::removeBomb(Bomb* bomb) |
720 | { |
721 | // Find the Bomb |
722 | int index = m_bombs.indexOf(bomb); |
723 | //remove the bomb |
724 | if(index != -1) |
725 | { |
726 | //do not delete the bomb because it will be deleted through the destructor of elementitem |
727 | m_bombs.removeAt(index); |
728 | } |
729 | } |
730 | |
731 | void Game::bombDetonated() |
732 | { |
733 | if(m_soundEnabled) |
734 | { |
735 | m_soundExplode->start(); |
736 | } |
737 | } |
738 | |
739 | void Game::blockDestroyed(const int row, const int col, Block* block) |
740 | { |
741 | // find the Block |
742 | int index = m_blocks.indexOf(block); |
743 | // remove the Block |
744 | if(index != -1) |
745 | { |
746 | //do not delete the block because it will be deleted through the destructor of elementitem |
747 | m_arena->removeCellElement(row, col, block); |
748 | } |
749 | } |
750 | |