File indexing completed on 2025-04-13 03:47:08
0001 /* 0002 SPDX-FileCopyrightText: 2009 Mathias Kraus <k.hias@gmx.de> 0003 SPDX-FileCopyrightText: 2007-2008 Thomas Gallinari <tg8187@yahoo.fr> 0004 SPDX-FileCopyrightText: 2007-2008 Pierre-Benoit Besse <besse@gmail.com> 0005 SPDX-FileCopyrightText: 2007-2008 Alexandre Galinier <alex.galinier@hotmail.com> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "game.h" 0011 #include "mapparser.h" 0012 #include "settings.h" 0013 #include "gamescene.h" 0014 #include "arena.h" 0015 #include "player.h" 0016 #include "bonus.h" 0017 #include "bomb.h" 0018 #include "block.h" 0019 #include "config/playersettings.h" 0020 #include "granatier_random.h" 0021 0022 #include <QPointF> 0023 #include <QTimer> 0024 #include <QKeyEvent> 0025 #include <QDir> 0026 #include <KConfig> 0027 #include <KGameSound> 0028 #include <QStandardPaths> 0029 0030 0031 Game::Game(PlayerSettings* playerSettings) 0032 { 0033 m_playerSettings = playerSettings; 0034 0035 // Initialize the sound state 0036 setSoundsEnabled(Settings::sounds()); 0037 m_wilhelmScream = Settings::useWilhelmScream(); 0038 0039 m_soundPutBomb = new KGameSound(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("sounds/putbomb.wav"))); 0040 m_soundExplode = new KGameSound(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("sounds/explode.wav"))); 0041 m_soundBonus = new KGameSound(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("sounds/wow.wav"))); 0042 m_soundFalling = new KGameSound(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("sounds/deepfall.wav"))); 0043 m_soundDie = new KGameSound(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("sounds/die.wav"))); 0044 0045 m_arena = nullptr; 0046 m_randomArenaModeArenaList.clear(); 0047 m_gameScene = nullptr; 0048 m_winPoints = Settings::self()->pointsToWin(); 0049 0050 QStringList strPlayerIDs = m_playerSettings->playerIDs(); 0051 for(int i = 0; i < strPlayerIDs.count(); i++) 0052 { 0053 if(m_playerSettings->enabled(strPlayerIDs[i])) 0054 { 0055 auto* player = new Player(qreal(Granatier::CellSize * (-0.5)),qreal(Granatier::CellSize * 0.5), strPlayerIDs[i], playerSettings, m_arena); 0056 m_players.append(player); 0057 connect(player, &Player::dying, this, &Game::playerDeath); 0058 connect(player, &Player::falling, this, &Game::playerFalling); 0059 connect(player, &Player::resurrectBonusTaken, this, &Game::resurrectBonusTaken); 0060 } 0061 } 0062 0063 init(); 0064 0065 for (auto & player : m_players) 0066 { 0067 connect(player, &Player::bombDropped, this, &Game::createBomb); 0068 } 0069 0070 m_gameOver = false; 0071 } 0072 0073 void Game::init() 0074 { 0075 // Create the Arena instance 0076 m_arena = new Arena(); 0077 0078 m_remainingTime = Settings::roundTime(); 0079 m_bombCount = 0; 0080 0081 // Create the parser that will parse the XML file in order to initialize the Arena instance 0082 // This also creates all the characters 0083 MapParser mapParser(m_arena); 0084 // Set the XML file as input source for the parser 0085 QString filePath; 0086 if(Settings::self()->randomArenaMode()) 0087 { 0088 if(m_randomArenaModeArenaList.isEmpty()) 0089 { 0090 auto randomArenaModeArenaList = Settings::self()->randomArenaModeArenaList(); 0091 0092 QStringList arenasAvailable; 0093 const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::AppDataLocation, QStringLiteral("arenas"), QStandardPaths::LocateDirectory); 0094 for(const auto& dir: dirs) { 0095 const QStringList fileNames = QDir(dir).entryList({QStringLiteral("*.desktop")}); 0096 for(const auto& file: fileNames) { 0097 arenasAvailable.append(dir + QLatin1Char('/') + file); 0098 } 0099 } 0100 0101 // store the random arenas if they are available 0102 for(const auto& randomArena: randomArenaModeArenaList) { 0103 for(const auto& arena: arenasAvailable) { 0104 if(arena.endsWith(randomArena)) { 0105 m_randomArenaModeArenaList.append(arena); 0106 break; 0107 } 0108 } 0109 } 0110 0111 if(m_randomArenaModeArenaList.isEmpty()){ 0112 m_randomArenaModeArenaList = arenasAvailable; 0113 } 0114 } 0115 0116 int nIndex = granatier::RNG::fromRange<int>(0, m_randomArenaModeArenaList.count() - 1); 0117 filePath = m_randomArenaModeArenaList.at(nIndex); 0118 m_randomArenaModeArenaList.removeAt(nIndex); 0119 } 0120 else 0121 { 0122 filePath = QStandardPaths::locate(QStandardPaths::AppDataLocation, Settings::self()->arena()); 0123 } 0124 0125 if(!QFile::exists(filePath)) 0126 { 0127 Settings::self()->useDefaults(true); 0128 filePath = QStandardPaths::locate(QStandardPaths::AppDataLocation, Settings::self()->arena()); 0129 Settings::self()->useDefaults(false); 0130 } 0131 0132 KConfig arenaConfig(filePath, KConfig::SimpleConfig); 0133 KConfigGroup group = arenaConfig.group(QStringLiteral("Arena")); 0134 QString arenaFileName = group.readEntry("FileName"); 0135 0136 QFile arenaXmlFile(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("arenas/%1").arg(arenaFileName))); 0137 if (!arenaXmlFile.open(QIODevice::ReadOnly)) { 0138 qWarning() << " impossible to open file " << arenaFileName; 0139 } 0140 if (!mapParser.parse(&arenaXmlFile)) { 0141 qWarning() << " failed to parse file " << arenaFileName; 0142 } 0143 0144 QString arenaName = group.readEntry("Name"); 0145 m_arena->setName(arenaName); 0146 0147 //create the block items 0148 for (int i = 0; i < m_arena->getNbRows(); ++i) 0149 { 0150 for (int j = 0; j < m_arena->getNbColumns(); ++j) 0151 { 0152 if(m_arena->getCell(i,j).getType() == Granatier::Cell::BLOCK) 0153 { 0154 auto* block = new Block((j + 0.5) * Granatier::CellSize, (i + 0.5) * Granatier::CellSize, m_arena, QStringLiteral("arena_block")); 0155 m_blocks.append(block); 0156 m_arena->setCellElement(i, j, block); 0157 } 0158 } 0159 } 0160 0161 // Start the Game timer 0162 m_timer = new QTimer(this); 0163 m_timer->setInterval(int(1000 / Granatier::FPS)); 0164 connect(m_timer, &QTimer::timeout, this, &Game::update); 0165 m_timer->start(); 0166 m_state = RUNNING; 0167 0168 m_roundTimer = new QTimer(this); 0169 m_roundTimer->setInterval(1000); 0170 connect(m_roundTimer, &QTimer::timeout, this, &Game::decrementRemainingRoundTime); 0171 m_roundTimer->start(); 0172 0173 m_setRoundFinishedTimer = new QTimer(this); 0174 m_setRoundFinishedTimer->setSingleShot(true); 0175 connect(m_setRoundFinishedTimer, &QTimer::timeout, this, &Game::setRoundFinished); 0176 0177 // Init the characters coordinates on the Arena 0178 for (int i = 0; i < m_players.size(); i++) 0179 { 0180 m_players[i]->setArena(m_arena); 0181 QPointF playerPosition = m_arena->getPlayerPosition(i); 0182 m_players[i]->setInitialCoordinates(qreal(Granatier::CellSize * playerPosition.x()), qreal(Granatier::CellSize * playerPosition.y())); 0183 } 0184 initCharactersPosition(); 0185 0186 // Create the hidden Bonuses 0187 createBonus(); 0188 } 0189 0190 Game::~Game() 0191 { 0192 //pause is needed to stop all animations and therefore the access of the *items to their model 0193 pause(true); 0194 0195 qDeleteAll(m_players); 0196 m_players.clear(); 0197 0198 cleanUp(); 0199 0200 delete m_soundPutBomb; 0201 delete m_soundExplode; 0202 delete m_soundBonus; 0203 delete m_soundFalling; 0204 delete m_soundDie; 0205 } 0206 0207 void Game::cleanUp() 0208 { 0209 qDeleteAll(m_blocks); 0210 m_blocks.clear(); 0211 qDeleteAll(m_bonus); 0212 m_bonus.clear(); 0213 qDeleteAll(m_bombs); 0214 m_bombs.clear(); 0215 delete m_arena; 0216 m_arena = nullptr; 0217 delete m_timer; 0218 m_timer = nullptr; 0219 delete m_roundTimer; 0220 m_roundTimer = nullptr; 0221 delete m_setRoundFinishedTimer; 0222 m_setRoundFinishedTimer = nullptr; 0223 } 0224 0225 void Game::setGameScene(GameScene* p_gameScene) 0226 { 0227 m_gameScene = p_gameScene; 0228 } 0229 0230 void Game::start() 0231 { 0232 // Restart the Game timer 0233 m_timer->start(); 0234 m_state = RUNNING; 0235 m_roundTimer->start(); 0236 Q_EMIT pauseChanged(false, false); 0237 } 0238 0239 void Game::pause(bool p_locked) 0240 { 0241 // Stop the Game timer 0242 m_timer->stop(); 0243 m_roundTimer->stop(); 0244 if (p_locked) 0245 { 0246 m_state = PAUSED_LOCKED; 0247 } 0248 else 0249 { 0250 m_state = PAUSED_UNLOCKED; 0251 } 0252 Q_EMIT pauseChanged(true, false); 0253 } 0254 0255 void Game::switchPause() 0256 { 0257 // If the Game is not already paused 0258 if (m_state == RUNNING) 0259 { 0260 // Pause the Game 0261 pause(); 0262 Q_EMIT pauseChanged(true, true); 0263 } 0264 // If the Game is already paused 0265 else 0266 { 0267 // Resume the Game 0268 start(); 0269 Q_EMIT pauseChanged(false, true); 0270 } 0271 } 0272 0273 QList<Player*> Game::getPlayers() const 0274 { 0275 return m_players; 0276 } 0277 0278 QTimer* Game::getTimer() const 0279 { 0280 return m_timer; 0281 } 0282 0283 int Game::getRemainingTime() const 0284 { 0285 return m_remainingTime; 0286 } 0287 0288 Arena* Game::getArena() const 0289 { 0290 return m_arena; 0291 } 0292 0293 bool Game::isPaused() const 0294 { 0295 return (m_state != RUNNING); 0296 } 0297 0298 bool Game::getGameOver() const 0299 { 0300 return m_gameOver; 0301 } 0302 0303 QString Game::getWinner() const 0304 { 0305 return m_strWinner; 0306 } 0307 0308 int Game::getWinPoints() const 0309 { 0310 return m_winPoints; 0311 } 0312 0313 QList<Bonus*> Game::getBonus() const 0314 { 0315 return m_bonus; 0316 } 0317 0318 void Game::createBonus() 0319 { 0320 int nRemainingNeutralBonuses = 1; 0321 for(int nQuarter = 0; nQuarter < 4; nQuarter++) 0322 { 0323 Bonus* bonus; 0324 int nBonusCount = static_cast<int>(0.3 * m_blocks.size() / 4); 0325 int nBadBonusCount = static_cast<int>(0.1 * m_blocks.size() / 4); 0326 int nNeutralBonusCount = granatier::RNG::fromRange(0, nRemainingNeutralBonuses); 0327 QList<Granatier::Bonus::Type> bonusTypeList; 0328 Granatier::Bonus::Type bonusType; 0329 int nFullSize = m_blocks.size(); 0330 int nQuarterSize = (nQuarter < 3 ? nFullSize / 4 : nFullSize - 3 * (nFullSize / 4)); 0331 0332 for (int i = 0; i < nQuarterSize; ++i) 0333 { 0334 if(i < nBonusCount) 0335 { 0336 constexpr int NumberOfBonuses = 6; 0337 switch (granatier::RNG::fromRange(0, NumberOfBonuses-1)) 0338 { 0339 case 0: bonusType = Granatier::Bonus::SPEED; 0340 break; 0341 case 1: bonusType = Granatier::Bonus::BOMB; 0342 break; 0343 case 2: bonusType = Granatier::Bonus::POWER; 0344 break; 0345 case 3: bonusType = Granatier::Bonus::SHIELD; 0346 break; 0347 case 4: bonusType = Granatier::Bonus::THROW; 0348 break; 0349 case 5: bonusType = Granatier::Bonus::KICK; 0350 break; 0351 default: bonusType = Granatier::Bonus::SPEED; 0352 } 0353 } 0354 else if (i-nBonusCount < nBadBonusCount) 0355 { 0356 constexpr int NumberOfBadBonuses = 5; 0357 switch (granatier::RNG::fromRange(0, NumberOfBadBonuses-1)) 0358 { 0359 case 0: bonusType = Granatier::Bonus::HYPERACTIVE; 0360 break; 0361 case 1: bonusType = Granatier::Bonus::SLOW; 0362 break; 0363 case 2: bonusType = Granatier::Bonus::MIRROR; 0364 break; 0365 case 3: bonusType = Granatier::Bonus::SCATTY; 0366 break; 0367 case 4: bonusType = Granatier::Bonus::RESTRAIN; 0368 break; 0369 default: bonusType = Granatier::Bonus::HYPERACTIVE; 0370 } 0371 } 0372 else if(i-nBonusCount-nBadBonusCount < nNeutralBonusCount) 0373 { 0374 bonusType = Granatier::Bonus::RESURRECT; 0375 nRemainingNeutralBonuses--; 0376 } 0377 else { 0378 bonusType = Granatier::Bonus::NONE; 0379 } 0380 0381 bonusTypeList.append(bonusType); 0382 } 0383 0384 int nShuffle; 0385 for (int i = 0; i < nQuarterSize; ++i) 0386 { 0387 nShuffle = granatier::RNG::fromRange(0, nQuarterSize-1); 0388 0389 bonusTypeList.swapItemsAt(i, nShuffle); 0390 } 0391 0392 for (int i = 0; i < nQuarterSize; ++i) 0393 { 0394 if(bonusTypeList[i] != Granatier::Bonus::NONE) 0395 { 0396 int nIndex = nQuarter * (nFullSize/4) + i; 0397 bonus = new Bonus(m_blocks[nIndex]->getX(), m_blocks[nIndex]->getY(), m_arena, bonusTypeList[i]); 0398 m_bonus.append(bonus); 0399 m_blocks[nIndex]->setBonus(bonus); 0400 } 0401 } 0402 } 0403 } 0404 0405 void Game::removeBonus(Bonus* bonus) 0406 { 0407 m_bonus.removeAt(m_bonus.indexOf(bonus)); 0408 //do not delete the Bonus, because the ElementItem will delete it 0409 if(m_soundEnabled && !bonus->isDestroyed()) 0410 { 0411 m_soundBonus->start(); 0412 } 0413 } 0414 0415 void Game::setSoundsEnabled(bool p_enabled) 0416 { 0417 m_soundEnabled = p_enabled; 0418 Settings::setSounds(p_enabled); 0419 Settings::self()->save(); 0420 } 0421 0422 void Game::initCharactersPosition() 0423 { 0424 // If the timer is stopped, it means that collisions are already being handled 0425 if (m_timer->isActive()) 0426 { 0427 // At the beginning, the timer is stopped but the Game isn't paused (to allow keyPressedEvent detection) 0428 m_timer->stop(); 0429 m_roundTimer->stop(); 0430 m_state = RUNNING; 0431 // Initialize the Player coordinates 0432 for(auto & player : m_players) 0433 { 0434 player->initCoordinate(); 0435 player->init(); 0436 } 0437 } 0438 } 0439 0440 void Game::keyPressEvent(QKeyEvent* p_event) 0441 { 0442 if(p_event->isAutoRepeat()) 0443 { 0444 return; 0445 } 0446 0447 // At the beginning or when paused, we start the timer when a key is pressed 0448 if (!m_timer->isActive()) 0449 { 0450 if(p_event->key() == Qt::Key_Space) 0451 { 0452 // If paused 0453 if (m_state == PAUSED_UNLOCKED) 0454 { 0455 switchPause(); 0456 } 0457 else if (m_state == RUNNING) // At the game beginning 0458 { 0459 // Start the game 0460 m_timer->start(); 0461 m_roundTimer->start(); 0462 Q_EMIT gameStarted(); 0463 } 0464 else if (m_state == PAUSED_LOCKED) 0465 { 0466 // if the game is over, start a new game 0467 if (m_gameOver) 0468 { 0469 Q_EMIT gameOver(); 0470 return; 0471 } 0472 else 0473 { 0474 m_gameScene->cleanUp(); 0475 cleanUp(); 0476 init(); 0477 m_gameScene->init(); 0478 for(auto & player : m_players) 0479 { 0480 player->resurrect(); 0481 } 0482 } 0483 } 0484 } 0485 return; 0486 } 0487 // Behaviour when the game has begun 0488 switch (p_event->key()) 0489 { 0490 case Qt::Key_P: 0491 case Qt::Key_Escape: 0492 switchPause(); 0493 return; 0494 default: 0495 break; 0496 } 0497 0498 //TODO: make signal 0499 for(auto & player : m_players) 0500 { 0501 player->keyPressed(p_event); 0502 } 0503 } 0504 0505 void Game::keyReleaseEvent(QKeyEvent* p_event) 0506 { 0507 if(p_event->isAutoRepeat()) 0508 { 0509 return; 0510 } 0511 //TODO: make signal 0512 for(auto & player : m_players) 0513 { 0514 player->keyReleased(p_event); 0515 } 0516 } 0517 0518 void Game::update() 0519 { 0520 //update Bombs 0521 for (auto & bomb : m_bombs) 0522 { 0523 bomb->updateMove(); 0524 } 0525 0526 //update Player 0527 for(auto & player : m_players) 0528 { 0529 player->updateMove(); 0530 player->emitGameUpdated(); 0531 } 0532 } 0533 0534 void Game::decrementRemainingRoundTime() 0535 { 0536 m_remainingTime--; 0537 if(m_remainingTime >= 0) 0538 { 0539 Q_EMIT infoChanged(Granatier::Info::TimeInfo); 0540 } 0541 else 0542 { 0543 if(m_remainingTime % 2 == 0) 0544 { 0545 //create bombs at randoms places 0546 int nRow; 0547 int nCol; 0548 Granatier::Cell::Type cellType; 0549 bool bFound = false; 0550 do 0551 { 0552 nRow = granatier::RNG::fromRange(0, m_arena->getNbRows()-1); 0553 nCol = granatier::RNG::fromRange(0, m_arena->getNbColumns()-1); 0554 cellType = m_arena->getCell(nRow, nCol).getType(); 0555 if(cellType != Granatier::Cell::WALL && cellType != Granatier::Cell::HOLE && m_arena->getCell(nRow, nCol).isWalkable(nullptr)) 0556 { 0557 bFound = true; 0558 } 0559 } 0560 while (!bFound); 0561 0562 m_bombCount++; 0563 Bomb* bomb = new Bomb((nCol + 0.5) * Granatier::CellSize, (nRow + 0.5) * Granatier::CellSize, m_arena, m_bombCount, 1000); // time in ms 0564 bomb->setBombPower(static_cast<int>(granatier::RNG::fromRange(1.0, 2.5))); 0565 Q_EMIT bombCreated(bomb); 0566 connect(bomb, &Bomb::bombDetonated, this, &Game::bombDetonated); 0567 m_bombs.append(bomb); 0568 if(m_remainingTime > -100 && m_roundTimer->interval() > 150) 0569 { 0570 m_roundTimer->setInterval(m_roundTimer->interval() + m_remainingTime); 0571 } 0572 else if (m_roundTimer->interval() > 30) 0573 { 0574 m_roundTimer->setInterval(m_roundTimer->interval() - 1); 0575 } 0576 } 0577 } 0578 } 0579 0580 void Game::playerFalling() 0581 { 0582 if(m_soundEnabled) 0583 { 0584 m_soundFalling->start(); 0585 } 0586 } 0587 0588 void Game::playerDeath() 0589 { 0590 if(m_soundEnabled) 0591 { 0592 m_soundDie->start(); 0593 } 0594 0595 //check if at most one player is alive if not already finished 0596 if(!m_setRoundFinishedTimer->isActive()) 0597 { 0598 int nPlayerAlive = 0; 0599 for(auto & player : m_players) 0600 { 0601 if(player->isAlive()) 0602 { 0603 nPlayerAlive++; 0604 } 0605 } 0606 if(nPlayerAlive <= 1) 0607 { 0608 //wait some time until the game stops 0609 m_setRoundFinishedTimer->start(1500); 0610 } 0611 } 0612 } 0613 0614 void Game::resurrectBonusTaken() 0615 { 0616 for(auto & player : m_players) 0617 { 0618 if(!(player->isAlive())) 0619 { 0620 player->resurrect(); 0621 } 0622 } 0623 } 0624 0625 void Game::setRoundFinished() 0626 { 0627 int nPlayerAlive = 0; 0628 int nIndex = 0;; 0629 if(m_gameOver) 0630 { 0631 return; 0632 } 0633 for(int i = 0; i < m_players.length(); ++i) 0634 { 0635 if(m_players[i]->isAlive()) 0636 { 0637 nPlayerAlive++; 0638 nIndex = i; 0639 } 0640 } 0641 //this check is needed, if in the meantime the resurrect bonus was taken 0642 if (nPlayerAlive > 1) 0643 { 0644 return; 0645 } 0646 0647 if (nPlayerAlive == 1) 0648 { 0649 m_players[nIndex]->addPoint(); 0650 } 0651 0652 pause(true); 0653 0654 for(auto & player : m_players) 0655 { 0656 // check if a player reaches the win points 0657 if (player->points() >= m_winPoints) 0658 { 0659 m_gameOver = true; 0660 m_strWinner = player->getPlayerName(); 0661 break; 0662 } 0663 } 0664 m_gameScene->showScore(); 0665 } 0666 0667 void Game::createBomb(Player* player, qreal x, qreal y, bool newBomb, int throwDistance) 0668 { 0669 int col = m_arena->getColFromX(x); 0670 int row = m_arena->getRowFromY(y); 0671 if(col >= 0 && col < m_arena->getNbColumns() && row >= 0 && row < m_arena->getNbRows()) 0672 { 0673 QList<Element*> bombElements = m_arena->getCell(row, col).getElements(Granatier::Element::BOMB); 0674 if (!bombElements.isEmpty()) 0675 { 0676 if(player->hasThrowBomb() && throwDistance > 0) 0677 { 0678 for(auto& element: bombElements) 0679 { 0680 dynamic_cast <Bomb*> (element)->setThrown(player->direction()); 0681 } 0682 } 0683 return; 0684 } 0685 } 0686 0687 if(!newBomb) 0688 { 0689 return; 0690 } 0691 0692 m_bombCount++; 0693 Bomb* bomb = new Bomb((col + 0.5) * Granatier::CellSize, (row + 0.5) * Granatier::CellSize, m_arena, m_bombCount, 2500); // time in ms 0694 bomb->setBombPower(player->getBombPower()); 0695 Q_EMIT bombCreated(bomb); 0696 connect(bomb, &Bomb::bombDetonated, this, &Game::bombDetonated); 0697 connect(bomb, &Bomb::releaseBombArmory, player, &Player::slot_refillBombArmory); 0698 m_bombs.append(bomb); 0699 player->decrementBombArmory(); 0700 0701 if(m_soundEnabled) 0702 { 0703 m_soundPutBomb->start(); 0704 } 0705 } 0706 0707 void Game::removeBomb(Bomb* bomb) 0708 { 0709 // Find the Bomb 0710 int index = m_bombs.indexOf(bomb); 0711 //remove the bomb 0712 if(index != -1) 0713 { 0714 //do not delete the bomb because it will be deleted through the destructor of elementitem 0715 m_bombs.removeAt(index); 0716 } 0717 } 0718 0719 void Game::bombDetonated() 0720 { 0721 if(m_soundEnabled) 0722 { 0723 m_soundExplode->start(); 0724 } 0725 } 0726 0727 void Game::blockDestroyed(const int row, const int col, Block* block) 0728 { 0729 // find the Block 0730 int index = m_blocks.indexOf(block); 0731 // remove the Block 0732 if(index != -1) 0733 { 0734 //do not delete the block because it will be deleted through the destructor of elementitem 0735 m_arena->removeCellElement(row, col, block); 0736 } 0737 } 0738 0739 #include "moc_game.cpp"