File indexing completed on 2023-12-03 07:52:31
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 <KgSound> 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 KgSound(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("sounds/putbomb.wav"))); 0040 m_soundExplode = new KgSound(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("sounds/explode.wav"))); 0041 m_soundBonus = new KgSound(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("sounds/wow.wav"))); 0042 m_soundFalling = new KgSound(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("sounds/deepfall.wav"))); 0043 m_soundDie = new KgSound(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(QStringList() << 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("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 mapParser.parse(&arenaXmlFile); 0141 0142 QString arenaName = group.readEntry("Name"); 0143 m_arena->setName(arenaName); 0144 0145 //create the block items 0146 for (int i = 0; i < m_arena->getNbRows(); ++i) 0147 { 0148 for (int j = 0; j < m_arena->getNbColumns(); ++j) 0149 { 0150 if(m_arena->getCell(i,j).getType() == Granatier::Cell::BLOCK) 0151 { 0152 auto* block = new Block((j + 0.5) * Granatier::CellSize, (i + 0.5) * Granatier::CellSize, m_arena, QStringLiteral("arena_block")); 0153 m_blocks.append(block); 0154 m_arena->setCellElement(i, j, block); 0155 } 0156 } 0157 } 0158 0159 // Start the Game timer 0160 m_timer = new QTimer(this); 0161 m_timer->setInterval(int(1000 / Granatier::FPS)); 0162 connect(m_timer, &QTimer::timeout, this, &Game::update); 0163 m_timer->start(); 0164 m_state = RUNNING; 0165 0166 m_roundTimer = new QTimer(this); 0167 m_roundTimer->setInterval(1000); 0168 connect(m_roundTimer, &QTimer::timeout, this, &Game::decrementRemainingRoundTime); 0169 m_roundTimer->start(); 0170 0171 m_setRoundFinishedTimer = new QTimer(this); 0172 m_setRoundFinishedTimer->setSingleShot(true); 0173 connect(m_setRoundFinishedTimer, &QTimer::timeout, this, &Game::setRoundFinished); 0174 0175 // Init the characters coordinates on the Arena 0176 for (int i = 0; i < m_players.size(); i++) 0177 { 0178 m_players[i]->setArena(m_arena); 0179 QPointF playerPosition = m_arena->getPlayerPosition(i); 0180 m_players[i]->setInitialCoordinates(qreal(Granatier::CellSize * playerPosition.x()), qreal(Granatier::CellSize * playerPosition.y())); 0181 } 0182 initCharactersPosition(); 0183 0184 // Create the hidden Bonuses 0185 createBonus(); 0186 } 0187 0188 Game::~Game() 0189 { 0190 //pause is needed to stop all animations and therefore the access of the *items to their model 0191 pause(true); 0192 0193 qDeleteAll(m_players); 0194 m_players.clear(); 0195 0196 cleanUp(); 0197 0198 delete m_soundPutBomb; 0199 delete m_soundExplode; 0200 delete m_soundBonus; 0201 delete m_soundFalling; 0202 delete m_soundDie; 0203 } 0204 0205 void Game::cleanUp() 0206 { 0207 qDeleteAll(m_blocks); 0208 m_blocks.clear(); 0209 qDeleteAll(m_bonus); 0210 m_bonus.clear(); 0211 qDeleteAll(m_bombs); 0212 m_bombs.clear(); 0213 delete m_arena; 0214 m_arena = nullptr; 0215 delete m_timer; 0216 m_timer = nullptr; 0217 delete m_roundTimer; 0218 m_roundTimer = nullptr; 0219 delete m_setRoundFinishedTimer; 0220 m_setRoundFinishedTimer = nullptr; 0221 } 0222 0223 void Game::setGameScene(GameScene* p_gameScene) 0224 { 0225 m_gameScene = p_gameScene; 0226 } 0227 0228 void Game::start() 0229 { 0230 // Restart the Game timer 0231 m_timer->start(); 0232 m_state = RUNNING; 0233 m_roundTimer->start(); 0234 Q_EMIT pauseChanged(false, false); 0235 } 0236 0237 void Game::pause(bool p_locked) 0238 { 0239 // Stop the Game timer 0240 m_timer->stop(); 0241 m_roundTimer->stop(); 0242 if (p_locked) 0243 { 0244 m_state = PAUSED_LOCKED; 0245 } 0246 else 0247 { 0248 m_state = PAUSED_UNLOCKED; 0249 } 0250 Q_EMIT pauseChanged(true, false); 0251 } 0252 0253 void Game::switchPause() 0254 { 0255 // If the Game is not already paused 0256 if (m_state == RUNNING) 0257 { 0258 // Pause the Game 0259 pause(); 0260 Q_EMIT pauseChanged(true, true); 0261 } 0262 // If the Game is already paused 0263 else 0264 { 0265 // Resume the Game 0266 start(); 0267 Q_EMIT pauseChanged(false, true); 0268 } 0269 } 0270 0271 QList<Player*> Game::getPlayers() const 0272 { 0273 return m_players; 0274 } 0275 0276 QTimer* Game::getTimer() const 0277 { 0278 return m_timer; 0279 } 0280 0281 int Game::getRemainingTime() const 0282 { 0283 return m_remainingTime; 0284 } 0285 0286 Arena* Game::getArena() const 0287 { 0288 return m_arena; 0289 } 0290 0291 bool Game::isPaused() const 0292 { 0293 return (m_state != RUNNING); 0294 } 0295 0296 bool Game::getGameOver() const 0297 { 0298 return m_gameOver; 0299 } 0300 0301 QString Game::getWinner() const 0302 { 0303 return m_strWinner; 0304 } 0305 0306 int Game::getWinPoints() const 0307 { 0308 return m_winPoints; 0309 } 0310 0311 QList<Bonus*> Game::getBonus() const 0312 { 0313 return m_bonus; 0314 } 0315 0316 void Game::createBonus() 0317 { 0318 int nRemainingNeutralBonuses = 1; 0319 for(int nQuarter = 0; nQuarter < 4; nQuarter++) 0320 { 0321 Bonus* bonus; 0322 int nBonusCount = static_cast<int>(0.3 * m_blocks.size() / 4); 0323 int nBadBonusCount = static_cast<int>(0.1 * m_blocks.size() / 4); 0324 int nNeutralBonusCount = granatier::RNG::fromRange(0, nRemainingNeutralBonuses); 0325 QList<Granatier::Bonus::Type> bonusTypeList; 0326 Granatier::Bonus::Type bonusType; 0327 int nFullSize = m_blocks.size(); 0328 int nQuarterSize = (nQuarter < 3 ? nFullSize / 4 : nFullSize - 3 * (nFullSize / 4)); 0329 0330 for (int i = 0; i < nQuarterSize; ++i) 0331 { 0332 if(i < nBonusCount) 0333 { 0334 constexpr int NumberOfBonuses = 6; 0335 switch (granatier::RNG::fromRange(0, NumberOfBonuses-1)) 0336 { 0337 case 0: bonusType = Granatier::Bonus::SPEED; 0338 break; 0339 case 1: bonusType = Granatier::Bonus::BOMB; 0340 break; 0341 case 2: bonusType = Granatier::Bonus::POWER; 0342 break; 0343 case 3: bonusType = Granatier::Bonus::SHIELD; 0344 break; 0345 case 4: bonusType = Granatier::Bonus::THROW; 0346 break; 0347 case 5: bonusType = Granatier::Bonus::KICK; 0348 break; 0349 default: bonusType = Granatier::Bonus::SPEED; 0350 } 0351 } 0352 else if (i-nBonusCount < nBadBonusCount) 0353 { 0354 constexpr int NumberOfBadBonuses = 5; 0355 switch (granatier::RNG::fromRange(0, NumberOfBadBonuses-1)) 0356 { 0357 case 0: bonusType = Granatier::Bonus::HYPERACTIVE; 0358 break; 0359 case 1: bonusType = Granatier::Bonus::SLOW; 0360 break; 0361 case 2: bonusType = Granatier::Bonus::MIRROR; 0362 break; 0363 case 3: bonusType = Granatier::Bonus::SCATTY; 0364 break; 0365 case 4: bonusType = Granatier::Bonus::RESTRAIN; 0366 break; 0367 default: bonusType = Granatier::Bonus::HYPERACTIVE; 0368 } 0369 } 0370 else if(i-nBonusCount-nBadBonusCount < nNeutralBonusCount) 0371 { 0372 bonusType = Granatier::Bonus::RESURRECT; 0373 nRemainingNeutralBonuses--; 0374 } 0375 else { 0376 bonusType = Granatier::Bonus::NONE; 0377 } 0378 0379 bonusTypeList.append(bonusType); 0380 } 0381 0382 int nShuffle; 0383 for (int i = 0; i < nQuarterSize; ++i) 0384 { 0385 nShuffle = granatier::RNG::fromRange(0, nQuarterSize-1); 0386 0387 bonusTypeList.swapItemsAt(i, nShuffle); 0388 } 0389 0390 for (int i = 0; i < nQuarterSize; ++i) 0391 { 0392 if(bonusTypeList[i] != Granatier::Bonus::NONE) 0393 { 0394 int nIndex = nQuarter * (nFullSize/4) + i; 0395 bonus = new Bonus(m_blocks[nIndex]->getX(), m_blocks[nIndex]->getY(), m_arena, bonusTypeList[i]); 0396 m_bonus.append(bonus); 0397 m_blocks[nIndex]->setBonus(bonus); 0398 } 0399 } 0400 } 0401 } 0402 0403 void Game::removeBonus(Bonus* bonus) 0404 { 0405 m_bonus.removeAt(m_bonus.indexOf(bonus)); 0406 //do not delete the Bonus, because the ElementItem will delete it 0407 if(m_soundEnabled && !bonus->isDestroyed()) 0408 { 0409 m_soundBonus->start(); 0410 } 0411 } 0412 0413 void Game::setSoundsEnabled(bool p_enabled) 0414 { 0415 m_soundEnabled = p_enabled; 0416 Settings::setSounds(p_enabled); 0417 Settings::self()->save(); 0418 } 0419 0420 void Game::initCharactersPosition() 0421 { 0422 // If the timer is stopped, it means that collisions are already being handled 0423 if (m_timer->isActive()) 0424 { 0425 // At the beginning, the timer is stopped but the Game isn't paused (to allow keyPressedEvent detection) 0426 m_timer->stop(); 0427 m_roundTimer->stop(); 0428 m_state = RUNNING; 0429 // Initialize the Player coordinates 0430 for(auto & player : m_players) 0431 { 0432 player->initCoordinate(); 0433 player->init(); 0434 } 0435 } 0436 } 0437 0438 void Game::keyPressEvent(QKeyEvent* p_event) 0439 { 0440 if(p_event->isAutoRepeat()) 0441 { 0442 return; 0443 } 0444 0445 // At the beginning or when paused, we start the timer when a key is pressed 0446 if (!m_timer->isActive()) 0447 { 0448 if(p_event->key() == Qt::Key_Space) 0449 { 0450 // If paused 0451 if (m_state == PAUSED_UNLOCKED) 0452 { 0453 switchPause(); 0454 } 0455 else if (m_state == RUNNING) // At the game beginning 0456 { 0457 // Start the game 0458 m_timer->start(); 0459 m_roundTimer->start(); 0460 Q_EMIT gameStarted(); 0461 } 0462 else if (m_state == PAUSED_LOCKED) 0463 { 0464 // if the game is over, start a new game 0465 if (m_gameOver) 0466 { 0467 Q_EMIT gameOver(); 0468 return; 0469 } 0470 else 0471 { 0472 m_gameScene->cleanUp(); 0473 cleanUp(); 0474 init(); 0475 m_gameScene->init(); 0476 for(auto & player : m_players) 0477 { 0478 player->resurrect(); 0479 } 0480 } 0481 } 0482 } 0483 return; 0484 } 0485 // Behaviour when the game has begun 0486 switch (p_event->key()) 0487 { 0488 case Qt::Key_P: 0489 case Qt::Key_Escape: 0490 switchPause(); 0491 return; 0492 default: 0493 break; 0494 } 0495 0496 //TODO: make signal 0497 for(auto & player : m_players) 0498 { 0499 player->keyPressed(p_event); 0500 } 0501 } 0502 0503 void Game::keyReleaseEvent(QKeyEvent* p_event) 0504 { 0505 if(p_event->isAutoRepeat()) 0506 { 0507 return; 0508 } 0509 //TODO: make signal 0510 for(auto & player : m_players) 0511 { 0512 player->keyReleased(p_event); 0513 } 0514 } 0515 0516 void Game::update() 0517 { 0518 //update Bombs 0519 for (auto & bomb : m_bombs) 0520 { 0521 bomb->updateMove(); 0522 } 0523 0524 //update Player 0525 for(auto & player : m_players) 0526 { 0527 player->updateMove(); 0528 player->emitGameUpdated(); 0529 } 0530 } 0531 0532 void Game::decrementRemainingRoundTime() 0533 { 0534 m_remainingTime--; 0535 if(m_remainingTime >= 0) 0536 { 0537 Q_EMIT infoChanged(Granatier::Info::TimeInfo); 0538 } 0539 else 0540 { 0541 if(m_remainingTime % 2 == 0) 0542 { 0543 //create bombs at randoms places 0544 int nRow; 0545 int nCol; 0546 Granatier::Cell::Type cellType; 0547 bool bFound = false; 0548 do 0549 { 0550 nRow = granatier::RNG::fromRange(0, m_arena->getNbRows()-1); 0551 nCol = granatier::RNG::fromRange(0, m_arena->getNbColumns()-1); 0552 cellType = m_arena->getCell(nRow, nCol).getType(); 0553 if(cellType != Granatier::Cell::WALL && cellType != Granatier::Cell::HOLE && m_arena->getCell(nRow, nCol).isWalkable(nullptr)) 0554 { 0555 bFound = true; 0556 } 0557 } 0558 while (!bFound); 0559 0560 m_bombCount++; 0561 Bomb* bomb = new Bomb((nCol + 0.5) * Granatier::CellSize, (nRow + 0.5) * Granatier::CellSize, m_arena, m_bombCount, 1000); // time in ms 0562 bomb->setBombPower(static_cast<int>(granatier::RNG::fromRange(1.0, 2.5))); 0563 Q_EMIT bombCreated(bomb); 0564 connect(bomb, &Bomb::bombDetonated, this, &Game::bombDetonated); 0565 m_bombs.append(bomb); 0566 if(m_remainingTime > -100 && m_roundTimer->interval() > 150) 0567 { 0568 m_roundTimer->setInterval(m_roundTimer->interval() + m_remainingTime); 0569 } 0570 else if (m_roundTimer->interval() > 30) 0571 { 0572 m_roundTimer->setInterval(m_roundTimer->interval() - 1); 0573 } 0574 } 0575 } 0576 } 0577 0578 void Game::playerFalling() 0579 { 0580 if(m_soundEnabled) 0581 { 0582 m_soundFalling->start(); 0583 } 0584 } 0585 0586 void Game::playerDeath() 0587 { 0588 if(m_soundEnabled) 0589 { 0590 m_soundDie->start(); 0591 } 0592 0593 //check if at most one player is alive if not already finished 0594 if(!m_setRoundFinishedTimer->isActive()) 0595 { 0596 int nPlayerAlive = 0; 0597 for(auto & player : m_players) 0598 { 0599 if(player->isAlive()) 0600 { 0601 nPlayerAlive++; 0602 } 0603 } 0604 if(nPlayerAlive <= 1) 0605 { 0606 //wait some time until the game stops 0607 m_setRoundFinishedTimer->start(1500); 0608 } 0609 } 0610 } 0611 0612 void Game::resurrectBonusTaken() 0613 { 0614 for(auto & player : m_players) 0615 { 0616 if(!(player->isAlive())) 0617 { 0618 player->resurrect(); 0619 } 0620 } 0621 } 0622 0623 void Game::setRoundFinished() 0624 { 0625 int nPlayerAlive = 0; 0626 int nIndex = 0;; 0627 if(m_gameOver) 0628 { 0629 return; 0630 } 0631 for(int i = 0; i < m_players.length(); ++i) 0632 { 0633 if(m_players[i]->isAlive()) 0634 { 0635 nPlayerAlive++; 0636 nIndex = i; 0637 } 0638 } 0639 //this check is needed, if in the meantime the resurrect bonus was taken 0640 if (nPlayerAlive > 1) 0641 { 0642 return; 0643 } 0644 0645 if (nPlayerAlive == 1) 0646 { 0647 m_players[nIndex]->addPoint(); 0648 } 0649 0650 pause(true); 0651 0652 for(auto & player : m_players) 0653 { 0654 // check if a player reaches the win points 0655 if (player->points() >= m_winPoints) 0656 { 0657 m_gameOver = true; 0658 m_strWinner = player->getPlayerName(); 0659 break; 0660 } 0661 } 0662 m_gameScene->showScore(); 0663 } 0664 0665 void Game::createBomb(Player* player, qreal x, qreal y, bool newBomb, int throwDistance) 0666 { 0667 int col = m_arena->getColFromX(x); 0668 int row = m_arena->getRowFromY(y); 0669 if(col >= 0 && col < m_arena->getNbColumns() && row >= 0 && row < m_arena->getNbRows()) 0670 { 0671 QList<Element*> bombElements = m_arena->getCell(row, col).getElements(Granatier::Element::BOMB); 0672 if (!bombElements.isEmpty()) 0673 { 0674 if(player->hasThrowBomb() && throwDistance > 0) 0675 { 0676 for(auto& element: bombElements) 0677 { 0678 dynamic_cast <Bomb*> (element)->setThrown(player->direction()); 0679 } 0680 } 0681 return; 0682 } 0683 } 0684 0685 if(!newBomb) 0686 { 0687 return; 0688 } 0689 0690 m_bombCount++; 0691 Bomb* bomb = new Bomb((col + 0.5) * Granatier::CellSize, (row + 0.5) * Granatier::CellSize, m_arena, m_bombCount, 2500); // time in ms 0692 bomb->setBombPower(player->getBombPower()); 0693 Q_EMIT bombCreated(bomb); 0694 connect(bomb, &Bomb::bombDetonated, this, &Game::bombDetonated); 0695 connect(bomb, &Bomb::releaseBombArmory, player, &Player::slot_refillBombArmory); 0696 m_bombs.append(bomb); 0697 player->decrementBombArmory(); 0698 0699 if(m_soundEnabled) 0700 { 0701 m_soundPutBomb->start(); 0702 } 0703 } 0704 0705 void Game::removeBomb(Bomb* bomb) 0706 { 0707 // Find the Bomb 0708 int index = m_bombs.indexOf(bomb); 0709 //remove the bomb 0710 if(index != -1) 0711 { 0712 //do not delete the bomb because it will be deleted through the destructor of elementitem 0713 m_bombs.removeAt(index); 0714 } 0715 } 0716 0717 void Game::bombDetonated() 0718 { 0719 if(m_soundEnabled) 0720 { 0721 m_soundExplode->start(); 0722 } 0723 } 0724 0725 void Game::blockDestroyed(const int row, const int col, Block* block) 0726 { 0727 // find the Block 0728 int index = m_blocks.indexOf(block); 0729 // remove the Block 0730 if(index != -1) 0731 { 0732 //do not delete the block because it will be deleted through the destructor of elementitem 0733 m_arena->removeCellElement(row, col, block); 0734 } 0735 } 0736 0737 #include "moc_game.cpp"