File indexing completed on 2023-12-03 07:52:33
0001 /* 0002 SPDX-FileCopyrightText: 2009 Mathias Kraus <k.hias@gmx.de> 0003 SPDX-FileCopyrightText: 2007-2008 Thomas Gallinari <tg8187@yahoo.fr> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "player.h" 0009 #include "bonus.h" 0010 #include "bomb.h" 0011 #include "arena.h" 0012 #include "config/playersettings.h" 0013 #include "settings.h" 0014 0015 #include <QKeyEvent> 0016 #include <QTimer> 0017 0018 #include <cmath> 0019 0020 constexpr int onIceSpeedIncrease = 2; 0021 constexpr int badBonusTimerTimeout = 100; 0022 constexpr int badBonusCountdown = 10000; 0023 0024 Player::Player(qreal p_x, qreal p_y, const QString& p_playerID, const PlayerSettings* p_playerSettings, Arena* p_arena) 0025 : Character(p_x, p_y, p_arena) 0026 , m_throwBomb(false) 0027 , m_kickBomb(false) 0028 { 0029 m_type = Granatier::Element::PLAYER; 0030 m_desktopFilePath = p_playerSettings->playerDesktopFilePath(p_playerID); 0031 m_graphicsFile = p_playerSettings->playerGraphicsFile(p_playerID); 0032 m_playerName = p_playerSettings->playerName(p_playerID); 0033 0034 m_points = 0; 0035 0036 m_direction = Granatier::Direction::EAST; 0037 0038 m_badBonusCountdownTimer = new QTimer; 0039 m_badBonusCountdownTimer->setInterval(badBonusTimerTimeout); 0040 m_badBonusMillisecondsToElapse = 0; 0041 connect(m_badBonusCountdownTimer, &QTimer::timeout, this, &Player::slot_badBonusTimerTimeout); 0042 0043 resurrect(); 0044 0045 m_key.moveLeft = p_playerSettings->keyLeft(p_playerID); 0046 m_key.moveRight = p_playerSettings->keyRight(p_playerID); 0047 m_key.moveUp = p_playerSettings->keyUp(p_playerID); 0048 m_key.moveDown = p_playerSettings->keyDown(p_playerID); 0049 m_key.dropBomb = p_playerSettings->keyPutBomb(p_playerID); 0050 } 0051 0052 Player::~Player() 0053 { 0054 delete m_badBonusCountdownTimer; 0055 } 0056 0057 void Player::setShortcuts(const Shortcuts &keys) 0058 { 0059 m_key = keys; 0060 } 0061 0062 QString Player::getGraphicsFile() const 0063 { 0064 return m_graphicsFile; 0065 } 0066 0067 QString Player::getDesktopFilePath() const 0068 { 0069 return m_desktopFilePath; 0070 } 0071 0072 QString Player::getPlayerName() const 0073 { 0074 return m_playerName; 0075 } 0076 0077 void Player::init() 0078 { 0079 updateDirection(); 0080 stopMoving(); 0081 int row = m_arena->getRowFromY(m_y); 0082 int column = m_arena->getColFromX(m_x); 0083 m_arena->setCellElement(row, column, this); 0084 } 0085 0086 void Player::pause() 0087 { 0088 m_badBonusCountdownTimer->stop(); 0089 } 0090 0091 void Player::resume() 0092 { 0093 if(m_badBonusMillisecondsToElapse > 0) 0094 { 0095 m_badBonusCountdownTimer->start(); 0096 } 0097 } 0098 0099 void Player::goUp() 0100 { 0101 m_askedXSpeed = 0; 0102 0103 qreal nSpeed = m_speed; 0104 if(m_onIce) 0105 { 0106 nSpeed = m_speed + onIceSpeedIncrease; 0107 } 0108 m_askedYSpeed = -nSpeed; 0109 0110 m_direction = Granatier::Direction::NORTH; 0111 } 0112 0113 void Player::goDown() 0114 { 0115 m_askedXSpeed = 0; 0116 0117 qreal nSpeed = m_speed; 0118 if(m_onIce) 0119 { 0120 nSpeed = m_speed + onIceSpeedIncrease; 0121 } 0122 m_askedYSpeed = nSpeed; 0123 0124 m_direction = Granatier::Direction::SOUTH; 0125 } 0126 0127 void Player::goRight() 0128 { 0129 qreal nSpeed = m_speed; 0130 if(m_onIce) 0131 { 0132 nSpeed = m_speed + onIceSpeedIncrease; 0133 } 0134 m_askedXSpeed = nSpeed; 0135 0136 m_askedYSpeed = 0; 0137 0138 m_direction = Granatier::Direction::EAST; 0139 } 0140 0141 void Player::goLeft() 0142 { 0143 qreal nSpeed = m_speed; 0144 if(m_onIce) 0145 { 0146 nSpeed = m_speed + onIceSpeedIncrease; 0147 } 0148 m_askedXSpeed = -nSpeed; 0149 0150 m_askedYSpeed = 0; 0151 0152 m_direction = Granatier::Direction::WEST; 0153 } 0154 0155 void Player::updateDirection() 0156 { 0157 if(m_death) 0158 { 0159 return; 0160 } 0161 0162 setXSpeed(m_askedXSpeed); 0163 setYSpeed(m_askedYSpeed); 0164 m_askedXSpeed = 0; 0165 m_askedYSpeed = 0; 0166 // Signal to the player item that the direction changed 0167 Q_EMIT directionChanged(); 0168 } 0169 0170 void Player::updateMove() 0171 { 0172 if(m_death) 0173 { 0174 return; 0175 } 0176 0177 //check if there is a hurdle in the way 0178 if(m_askedXSpeed != 0 || m_xSpeed != 0 || m_askedYSpeed != 0 || m_ySpeed != 0) 0179 { 0180 int xDirection = 0; //x-direction: -1: move left; 0: not moving; 1: move right 0181 int yDirection = 0; //y-direction: -1: move up; 0: not moving; 1: move down 0182 int straightDirection = 0; //straight direction: -1: backward; 1:foreward; while foreward is right for moving in x-direction and down for y-direction 0183 qreal deltaStraightMove = 0; //the move in straight direction 0184 qreal deltaPerpendicularMove = 0; //the move in perpendicular direction; e.g. the player is not in cell center and will collide with a wall in the cell above, so the player has to be moved to the cell center 0185 qreal deltaAskedMove; //how far to move; positive for right/down move and negative for left/up 0186 qreal deltaStraightCellCorner; //move in x-direction: the x-pos from the top left cell corner; move in y-direction: the y-pos from the top left cell corner 0187 qreal deltaPerpendicularCellCorner; //move in x-direction: the y-pos from the top left cell corner; move in y-direction: the x-pos from the top left cell corner 0188 qreal deltaStraightCellCenter; //distance to the cell center in moving direction; positive if left/up from cell center, negative if right/down 0189 qreal deltaPerpendicularCellCenter; //distance to the cell center perpendicular to moving direction; positive if up/left from cell center, negative if down/right 0190 bool bMoveWithinNextCellCenter = false; //move is completed without exceeding the cell center 0191 int cellCol; 0192 int cellRow; 0193 0194 // Get the current cell coordinates from the character coordinates 0195 int moveStartRow = m_arena->getRowFromY(m_y); 0196 int moveStartCol = m_arena->getColFromX(m_x); 0197 int curCellRow = moveStartRow; 0198 int curCellCol = moveStartCol; 0199 0200 //set variables for right/left move 0201 if(m_askedXSpeed != 0 || m_xSpeed != 0) 0202 { 0203 //how far to move 0204 deltaAskedMove = (m_askedXSpeed != 0 ? m_askedXSpeed : m_xSpeed); 0205 0206 //direction to move 0207 xDirection = sign(deltaAskedMove); 0208 straightDirection = xDirection; 0209 0210 deltaStraightCellCorner = m_x - curCellCol * Granatier::CellSize; 0211 deltaPerpendicularCellCorner = m_y - curCellRow * Granatier::CellSize; 0212 } 0213 else //set variables for down/up move 0214 { 0215 //how far to move 0216 deltaAskedMove = (m_askedYSpeed != 0 ? m_askedYSpeed : m_ySpeed); 0217 0218 //direction to move 0219 yDirection = sign(deltaAskedMove); 0220 straightDirection = yDirection; 0221 0222 deltaStraightCellCorner = m_y - curCellRow * Granatier::CellSize; 0223 deltaPerpendicularCellCorner = m_x - curCellCol * Granatier::CellSize; 0224 } 0225 0226 //how far to current cell center 0227 deltaStraightCellCenter = Granatier::CellSize/2 - deltaStraightCellCorner; 0228 deltaPerpendicularCellCenter = Granatier::CellSize/2 - deltaPerpendicularCellCorner; 0229 0230 //check if the move exceeds a cell center 0231 if(straightDirection*deltaStraightCellCenter >= 0) 0232 { 0233 if(fabs(deltaAskedMove) <= fabs(deltaStraightCellCenter)) 0234 { 0235 bMoveWithinNextCellCenter = true; 0236 } 0237 } 0238 else if(fabs(deltaAskedMove) + fabs(deltaStraightCellCenter) <= Granatier::CellSize) 0239 { 0240 bMoveWithinNextCellCenter = true; 0241 } 0242 0243 //the move is within two cell centers 0244 if(bMoveWithinNextCellCenter) 0245 { 0246 bool isHurdle = false; 0247 if(!(m_badBonusCountdownTimer->isActive() && m_badBonusType == Granatier::Bonus::SCATTY)) 0248 { 0249 bool kickBomb = false; 0250 QList<Element*> bombElements; 0251 //moving towards cell center; don't move if there is a bomb in the cell 0252 if(deltaStraightCellCenter * straightDirection > 0 && !m_arena->getCell(moveStartRow, moveStartCol).isWalkable(this) && !m_omitBombCurrentCell) 0253 { 0254 isHurdle = true; 0255 if(m_kickBomb) 0256 { 0257 kickBomb = true; 0258 bombElements = m_arena->getCell(moveStartRow, moveStartCol).getElements(Granatier::Element::BOMB); 0259 } 0260 } 0261 //moving away of cell center; don't move if there is a bomb in the next cell; ignore a bomb in the current cell 0262 else if(deltaStraightCellCenter * straightDirection < 0 && !m_arena->getCell(moveStartRow + yDirection, moveStartCol + xDirection).isWalkable(this)) 0263 { 0264 isHurdle = true; 0265 if(m_kickBomb) 0266 { 0267 kickBomb = true; 0268 bombElements = m_arena->getCell(moveStartRow + yDirection, moveStartCol + xDirection).getElements(Granatier::Element::BOMB); 0269 } 0270 } 0271 if(kickBomb) 0272 { 0273 for(auto& element: bombElements) 0274 { 0275 dynamic_cast <Bomb*> (element)->setKicked(m_direction); 0276 } 0277 } 0278 } 0279 if(!isHurdle) 0280 { 0281 deltaStraightMove += deltaAskedMove; 0282 //move to perpendicular center if needed 0283 if(deltaPerpendicularCellCenter != 0 && (straightDirection * deltaStraightCellCenter) < 0) //not in perpendicular center and entering a new cell 0284 { 0285 if(fabs(deltaPerpendicularCellCenter) > Granatier::CellSize/2 - fabs(deltaStraightMove - deltaStraightCellCenter)) //check if it already can collide with a hurdle 0286 { 0287 cellRow = curCellRow + yDirection - qAbs(xDirection)*signZeroPositive(deltaPerpendicularCellCenter); 0288 cellCol = curCellCol + xDirection - qAbs(yDirection)*signZeroPositive(deltaPerpendicularCellCenter); 0289 if(!m_arena->getCell(cellRow, cellCol).isWalkable(this)) 0290 { 0291 deltaPerpendicularMove = deltaPerpendicularCellCenter + signZeroPositive(deltaPerpendicularCellCenter) * (fabs(deltaStraightMove - deltaStraightCellCenter) - Granatier::CellSize/2); 0292 if(fabs(deltaPerpendicularMove) > fabs(deltaPerpendicularCellCenter)) //check if moved over perpendicular center 0293 { 0294 deltaPerpendicularMove = deltaPerpendicularCellCenter; 0295 } 0296 } 0297 } 0298 } 0299 } 0300 } 0301 else //the move exceeds a cell center 0302 { 0303 //at first move to the cell center 0304 deltaStraightMove += deltaStraightCellCenter; 0305 deltaAskedMove -= deltaStraightCellCenter; 0306 if(straightDirection * deltaStraightCellCenter < 0) //the cell center to move is in the next cell 0307 { 0308 deltaStraightMove += straightDirection * Granatier::CellSize; 0309 deltaAskedMove -= straightDirection * Granatier::CellSize; 0310 0311 //move to perpendicular center if needed 0312 if(deltaPerpendicularCellCenter != 0) 0313 { 0314 cellRow = curCellRow + yDirection - qAbs(xDirection)*signZeroPositive(deltaPerpendicularCellCenter); 0315 cellCol = curCellCol + xDirection - qAbs(yDirection)*signZeroPositive(deltaPerpendicularCellCenter); 0316 if(!m_arena->getCell(cellRow, cellCol).isWalkable(this)) 0317 { 0318 deltaPerpendicularMove = deltaPerpendicularCellCenter; 0319 } 0320 } 0321 0322 //update the current cell and row 0323 curCellCol += xDirection; 0324 curCellRow += yDirection; 0325 } 0326 while(fabs(deltaAskedMove) > 0) //complete the move 0327 { 0328 if(m_arena->getCell(curCellRow + yDirection, curCellCol + xDirection).isWalkable(this)) //check if next cell is walkable 0329 { 0330 if(fabs(deltaAskedMove) > Granatier::CellSize) //move to next cell center if the remaining move exceeds a cell center 0331 { 0332 deltaStraightMove += straightDirection * Granatier::CellSize; 0333 deltaAskedMove -= straightDirection * Granatier::CellSize; 0334 //move to perpendicular center if needed 0335 if(deltaPerpendicularCellCenter != 0) 0336 { 0337 cellRow = curCellRow + yDirection - qAbs(xDirection)*signZeroPositive(deltaPerpendicularCellCenter); 0338 cellCol = curCellCol + xDirection - qAbs(yDirection)*signZeroPositive(deltaPerpendicularCellCenter); 0339 if(!m_arena->getCell(cellRow, cellCol).isWalkable(this)) 0340 { 0341 deltaPerpendicularMove = deltaPerpendicularCellCenter; 0342 } 0343 } 0344 } 0345 else 0346 { 0347 deltaStraightMove += deltaAskedMove; 0348 //move to perpendicular center if needed 0349 if(deltaPerpendicularMove != deltaPerpendicularCellCenter && fabs(deltaPerpendicularCellCenter) > (Granatier::CellSize/2 - fabs(deltaStraightMove - deltaStraightCellCenter))) //check if it is in or already moved to perpendicular center and if it already can collide with a hurdle ***TODO: it seems to be wrong to use deltaStraightMove here, because ist could be greater than Granatier::CellSize 0350 { 0351 cellRow = curCellRow + yDirection - qAbs(xDirection)*signZeroPositive(deltaPerpendicularCellCenter); 0352 cellCol = curCellCol + xDirection - qAbs(yDirection)*signZeroPositive(deltaPerpendicularCellCenter); 0353 if(!m_arena->getCell(cellRow, cellCol).isWalkable(this)) 0354 { 0355 deltaPerpendicularMove = signZeroPositive(deltaPerpendicularCellCenter) * fabs(deltaAskedMove); 0356 if(fabs(deltaPerpendicularMove) > fabs(deltaPerpendicularCellCenter)) 0357 { 0358 deltaPerpendicularMove = deltaPerpendicularCellCenter; //check if moved over perpendicular center 0359 } 0360 } 0361 } 0362 deltaAskedMove = 0; 0363 } 0364 //update the current cell and row 0365 curCellCol += xDirection; 0366 curCellRow += yDirection; 0367 } 0368 else //there is a hurdle in the next cell, so stop moving 0369 { 0370 deltaAskedMove = 0; 0371 cellRow = curCellRow + yDirection; 0372 cellCol = curCellCol + xDirection; 0373 //check if bomb 0374 if(m_kickBomb) 0375 { 0376 QList<Element*> bombElements = m_arena->getCell(cellRow, cellCol).getElements(Granatier::Element::BOMB); 0377 for(auto& element: bombElements) 0378 { 0379 dynamic_cast <Bomb*> (element)->setKicked(m_direction); 0380 } 0381 } 0382 } 0383 } 0384 } 0385 0386 // Update the direction 0387 if(m_askedXSpeed != 0 || m_askedYSpeed != 0) 0388 { 0389 updateDirection(); 0390 } 0391 0392 // Move the player 0393 if(xDirection != 0) 0394 { 0395 move(m_x + deltaStraightMove, m_y + deltaPerpendicularMove); 0396 } 0397 else 0398 { 0399 move(m_x + deltaPerpendicularMove, m_y + deltaStraightMove); 0400 } 0401 0402 //check if the player is on ice 0403 // Get the current cell coordinates from the character coordinates 0404 int newCellRow = m_arena->getRowFromY(m_y); 0405 int newCellCol = m_arena->getColFromX(m_x); 0406 if(!m_onIce) 0407 { 0408 if(m_arena->getCell(newCellRow, newCellCol).getType() == Granatier::Cell::ICE) 0409 { 0410 if(xDirection != 0) 0411 { 0412 setXSpeed(m_xSpeed + xDirection * onIceSpeedIncrease); 0413 } 0414 else 0415 { 0416 setYSpeed(m_ySpeed + yDirection * onIceSpeedIncrease); 0417 } 0418 m_onIce = true; 0419 } 0420 } 0421 else 0422 { 0423 if(m_arena->getCell(newCellRow, newCellCol).getType() != Granatier::Cell::ICE) 0424 { 0425 if(m_arena->getCell(newCellRow, newCellCol).getType() != Granatier::Cell::HOLE) 0426 { 0427 if(xDirection != 0) 0428 { 0429 setXSpeed(m_xSpeed - xDirection * onIceSpeedIncrease); 0430 } 0431 else 0432 { 0433 setYSpeed(m_ySpeed - yDirection * onIceSpeedIncrease); 0434 } 0435 } 0436 m_onIce = false; 0437 0438 if(m_xSpeed == 0 && m_ySpeed == 0 && m_askedXSpeed == 0 && m_askedYSpeed == 0) 0439 { 0440 stopMoving(); 0441 } 0442 } 0443 } 0444 0445 //check if the player move in a hole 0446 if(m_arena->getCell(newCellRow, newCellCol).getType() == Granatier::Cell::HOLE) 0447 { 0448 m_falling = true; 0449 //check if cell center passed 0450 if(xDirection != 0) 0451 { 0452 qreal cellCenter = newCellCol * Granatier::CellSize + 0.5 * Granatier::CellSize; 0453 qreal deltaCellCenter = cellCenter - (m_x + m_xSpeed); 0454 if (cellCenter - m_x == 0) 0455 { 0456 setXSpeed(0); 0457 Q_EMIT falling(); 0458 } 0459 else if (xDirection * deltaCellCenter < 0) 0460 { 0461 setXSpeed(cellCenter - m_x); 0462 } 0463 } 0464 else if (yDirection != 0) 0465 { 0466 qreal cellCenter = newCellRow * Granatier::CellSize + 0.5 * Granatier::CellSize; 0467 qreal deltaCellCenter = cellCenter - (m_y + m_ySpeed); 0468 if (cellCenter - m_y == 0) 0469 { 0470 setYSpeed(0); 0471 Q_EMIT falling(); 0472 } 0473 else if (yDirection * deltaCellCenter < 0) 0474 { 0475 setYSpeed(cellCenter - m_y); 0476 } 0477 } 0478 } 0479 0480 if(moveStartCol != newCellCol || moveStartRow != newCellRow) 0481 { 0482 m_arena->removeCellElement(moveStartRow, moveStartCol, this); 0483 m_arena->setCellElement(newCellRow, newCellCol, this); 0484 m_omitBombCurrentCell = false; 0485 } 0486 } 0487 0488 //check if bad bonus scatty and drop bombs 0489 if(m_badBonusCountdownTimer->isActive() && m_badBonusType == Granatier::Bonus::SCATTY && m_bombArmory > 0) 0490 { 0491 //TODO: improve 0492 Q_EMIT bombDropped(this, m_x, m_y, true, 0); 0493 } 0494 } 0495 0496 void Player::move(qreal x, qreal y) 0497 { 0498 // Move the Character 0499 m_x = x; 0500 m_y = y; 0501 Q_EMIT moved(m_x, m_y); 0502 } 0503 0504 void Player::addBonus(Bonus* p_bonus) 0505 { 0506 Granatier::Bonus::Type bonusType = p_bonus->getBonusType(); 0507 0508 if(m_badBonusCountdownTimer->isActive()) 0509 { 0510 m_badBonusCountdownTimer->stop(); 0511 slot_removeBadBonus(); 0512 } 0513 0514 switch (bonusType) 0515 { 0516 case Granatier::Bonus::SPEED: 0517 m_speed += 1; 0518 if(m_speed > m_maxSpeed) 0519 { 0520 m_speed = m_maxSpeed; 0521 } 0522 setXSpeed(sign(m_xSpeed) * m_speed); 0523 setYSpeed(sign(m_ySpeed) * m_speed); 0524 break; 0525 case Granatier::Bonus::POWER: 0526 m_bombPower++; 0527 if(m_bombPower > 10) 0528 { 0529 m_bombPower = 10; 0530 } 0531 break; 0532 case Granatier::Bonus::BOMB: 0533 m_maxBombArmory++; 0534 if(m_maxBombArmory > 10) 0535 { 0536 m_maxBombArmory = 10; 0537 } 0538 m_bombArmory++; 0539 if(m_bombArmory > m_maxBombArmory) 0540 { 0541 m_bombArmory = m_maxBombArmory; 0542 } 0543 break; 0544 case Granatier::Bonus::SHIELD: 0545 if(m_listShield.isEmpty() || m_listShield.last() != 0) 0546 { 0547 m_listShield.append(0); 0548 } 0549 break; 0550 case Granatier::Bonus::THROW: 0551 m_throwBomb = true; 0552 break; 0553 case Granatier::Bonus::KICK: 0554 m_kickBomb = true; 0555 break; 0556 case Granatier::Bonus::HYPERACTIVE: 0557 { 0558 qreal askedXSpeedTemp = m_askedXSpeed; 0559 qreal askedYSpeedTemp = m_askedYSpeed; 0560 m_normalSpeed = m_speed; 0561 m_speed = m_maxSpeed * 3; 0562 m_askedXSpeed = sign(m_xSpeed) * m_speed; 0563 m_askedYSpeed = sign(m_ySpeed) * m_speed; 0564 updateDirection(); 0565 m_askedXSpeed = askedXSpeedTemp; 0566 m_askedYSpeed = askedYSpeedTemp; 0567 0568 m_badBonusType = Granatier::Bonus::HYPERACTIVE; 0569 m_badBonusMillisecondsToElapse = badBonusCountdown; 0570 m_badBonusCountdownTimer->start(); 0571 } 0572 break; 0573 case Granatier::Bonus::SLOW: 0574 { 0575 qreal askedXSpeedTemp = m_askedXSpeed; 0576 qreal askedYSpeedTemp = m_askedYSpeed; 0577 m_normalSpeed = m_speed; 0578 m_speed = 1; 0579 m_askedXSpeed = sign(m_xSpeed) * m_speed; 0580 m_askedYSpeed = sign(m_ySpeed) * m_speed; 0581 updateDirection(); 0582 m_askedXSpeed = askedXSpeedTemp; 0583 m_askedYSpeed = askedYSpeedTemp; 0584 0585 m_badBonusType = Granatier::Bonus::SLOW; 0586 m_badBonusMillisecondsToElapse = badBonusCountdown; 0587 m_badBonusCountdownTimer->start(); 0588 } 0589 break; 0590 case Granatier::Bonus::MIRROR: 0591 { 0592 qreal askedXSpeedTemp = m_askedXSpeed; 0593 qreal askedYSpeedTemp = m_askedYSpeed; 0594 m_askedXSpeed = -m_xSpeed; 0595 m_askedYSpeed = -m_ySpeed; 0596 switch(m_direction) 0597 { 0598 case Granatier::Direction::EAST: 0599 m_direction = Granatier::Direction::WEST; 0600 break; 0601 case Granatier::Direction::WEST: 0602 m_direction = Granatier::Direction::EAST; 0603 break; 0604 case Granatier::Direction::NORTH: 0605 m_direction = Granatier::Direction::SOUTH; 0606 break; 0607 case Granatier::Direction::SOUTH: 0608 m_direction = Granatier::Direction::NORTH; 0609 break; 0610 } 0611 updateDirection(); 0612 m_askedXSpeed = -askedXSpeedTemp; 0613 m_askedYSpeed = -askedYSpeedTemp; 0614 0615 QKeySequence tempKey = m_key.moveLeft; 0616 m_key.moveLeft = m_key.moveRight; 0617 m_key.moveRight = tempKey; 0618 tempKey = m_key.moveUp; 0619 m_key.moveUp = m_key.moveDown; 0620 m_key.moveDown = tempKey; 0621 0622 m_moveMirrored = true; 0623 m_badBonusType = Granatier::Bonus::MIRROR; 0624 m_badBonusMillisecondsToElapse = badBonusCountdown; 0625 m_badBonusCountdownTimer->start(); 0626 } 0627 break; 0628 case Granatier::Bonus::SCATTY: 0629 m_badBonusType = Granatier::Bonus::SCATTY; 0630 m_badBonusMillisecondsToElapse = badBonusCountdown; 0631 m_badBonusCountdownTimer->start(); 0632 break; 0633 case Granatier::Bonus::RESTRAIN: 0634 m_normalBombArmory = m_bombArmory; 0635 m_bombArmory = 0; 0636 m_badBonusType = Granatier::Bonus::RESTRAIN; 0637 m_badBonusMillisecondsToElapse = badBonusCountdown; 0638 m_badBonusCountdownTimer->start(); 0639 break; 0640 case Granatier::Bonus::RESURRECT: 0641 Q_EMIT resurrectBonusTaken(); 0642 break; 0643 default: 0644 break; 0645 } 0646 0647 Q_EMIT bonusUpdated(this, bonusType, 0); 0648 } 0649 0650 bool Player::shield(int nExplosionID) 0651 { 0652 for(int i = 0; i < m_listShield.count(); i++) 0653 { 0654 if(m_listShield[i] == nExplosionID) 0655 { 0656 return true; 0657 } 0658 else if(m_listShield[i] == 0) 0659 { 0660 m_listShield[i] = nExplosionID; 0661 if(i == m_listShield.count()-1) 0662 { 0663 Q_EMIT bonusUpdated(this, Granatier::Bonus::SHIELD, 100); 0664 } 0665 return true; 0666 } 0667 } 0668 return false; 0669 } 0670 0671 bool Player::hasShield() 0672 { 0673 if(m_listShield.count() > 0 && m_listShield.last() == 0) 0674 { 0675 return true; 0676 } 0677 return false; 0678 } 0679 0680 bool Player::hasThrowBomb() 0681 { 0682 return m_throwBomb; 0683 } 0684 0685 bool Player::hasKickBomb() 0686 { 0687 return m_kickBomb; 0688 } 0689 0690 bool Player::hasBadBonus() 0691 { 0692 if(m_badBonusCountdownTimer->isActive()) 0693 { 0694 return true; 0695 } 0696 return false; 0697 } 0698 0699 void Player::die() 0700 { 0701 if(!m_death) 0702 { 0703 m_death = true; 0704 Q_EMIT dying(); 0705 m_xSpeed = 0; 0706 m_xSpeed = 0; 0707 0708 if(m_badBonusCountdownTimer->isActive()) 0709 { 0710 m_badBonusCountdownTimer->stop(); 0711 slot_removeBadBonus(); 0712 } 0713 int row = m_arena->getRowFromY(m_y); 0714 int column = m_arena->getColFromX(m_x); 0715 m_arena->removeCellElement(row, column, this); 0716 } 0717 } 0718 0719 bool Player::isAlive() const 0720 { 0721 return !m_death; 0722 } 0723 0724 void Player::resurrect() 0725 { 0726 if(m_badBonusMillisecondsToElapse > 0) 0727 { 0728 slot_removeBadBonus(); 0729 } 0730 0731 m_onIce = false; 0732 m_falling = false; 0733 m_death = false; 0734 m_maxSpeed = 10; 0735 m_speed = Settings::self()->initialSpeed(); 0736 m_normalSpeed = m_speed; 0737 m_moveMirrored = false; 0738 m_bombPower = Settings::self()->initialBombPower(); 0739 m_maxBombArmory = Settings::self()->initialBombArmory(); 0740 m_bombArmory = m_maxBombArmory; 0741 if(m_listShield.count() != 0) 0742 { 0743 m_listShield.clear(); 0744 Q_EMIT bonusUpdated(this, Granatier::Bonus::SHIELD, 100); 0745 } 0746 if(m_throwBomb) 0747 { 0748 m_throwBomb = false; 0749 Q_EMIT bonusUpdated(this, Granatier::Bonus::THROW, 100); 0750 } 0751 if(m_kickBomb) 0752 { 0753 m_kickBomb = false; 0754 Q_EMIT bonusUpdated(this, Granatier::Bonus::KICK, 100); 0755 } 0756 m_omitBombCurrentCell = false; 0757 if(m_badBonusCountdownTimer->isActive()) 0758 { 0759 m_badBonusCountdownTimer->stop(); 0760 slot_removeBadBonus(); 0761 } 0762 0763 //check if the player is above a hole 0764 if(m_arena) 0765 { 0766 int cellRow = m_arena->getRowFromY(m_y); 0767 int cellCol = m_arena->getColFromX(m_x); 0768 0769 m_arena->removeCellElement(cellRow, cellCol, this); //just to be really sure 0770 0771 if(m_arena->getCell(cellRow, cellCol).getType() == Granatier::Cell::HOLE) 0772 { 0773 move(m_xInit, m_yInit); 0774 cellRow = m_arena->getRowFromY(m_yInit); 0775 cellCol = m_arena->getColFromX(m_xInit); 0776 } 0777 0778 m_arena->setCellElement(cellRow, cellCol, this); 0779 } 0780 0781 Q_EMIT resurrected(); 0782 } 0783 0784 int Player::points() const 0785 { 0786 return m_points; 0787 } 0788 0789 void Player::addPoint() 0790 { 0791 m_points++; 0792 } 0793 0794 void Player::emitGameUpdated() 0795 { 0796 Q_EMIT gameUpdated(); 0797 } 0798 0799 qreal Player::getAskedXSpeed() const 0800 { 0801 return m_askedXSpeed; 0802 } 0803 0804 qreal Player::getAskedYSpeed() const 0805 { 0806 return m_askedYSpeed; 0807 } 0808 0809 int Player::direction() 0810 { 0811 return m_direction; 0812 } 0813 0814 int Player::getBombPower() const 0815 { 0816 return m_bombPower; 0817 } 0818 0819 void Player::decrementBombArmory() 0820 { 0821 m_bombArmory--; 0822 if(m_bombArmory < 0) 0823 { 0824 m_bombArmory = 0; 0825 } 0826 } 0827 0828 void Player::slot_refillBombArmory() 0829 { 0830 int* bombArmory = &m_bombArmory; 0831 if(m_badBonusCountdownTimer->isActive() && m_badBonusType == Granatier::Bonus::RESTRAIN) 0832 { 0833 bombArmory = &m_normalBombArmory; 0834 } 0835 (*bombArmory)++; 0836 if((*bombArmory) > m_maxBombArmory) 0837 { 0838 (*bombArmory) = m_maxBombArmory; 0839 } 0840 } 0841 0842 void Player::slot_badBonusTimerTimeout() 0843 { 0844 m_badBonusMillisecondsToElapse -= badBonusTimerTimeout; 0845 if(m_badBonusMillisecondsToElapse <= 0) 0846 { 0847 slot_removeBadBonus(); 0848 } 0849 else 0850 { 0851 bonusUpdated(this, m_badBonusType, (badBonusCountdown - m_badBonusMillisecondsToElapse) * 100 / badBonusCountdown); 0852 } 0853 } 0854 0855 void Player::slot_removeBadBonus() 0856 { 0857 m_badBonusCountdownTimer->stop(); 0858 m_badBonusMillisecondsToElapse = 0; 0859 0860 switch (m_badBonusType) 0861 { 0862 case Granatier::Bonus::HYPERACTIVE: 0863 case Granatier::Bonus::SLOW: 0864 { 0865 qreal askedXSpeedTemp = m_askedXSpeed; 0866 qreal askedYSpeedTemp = m_askedYSpeed; 0867 m_speed = m_normalSpeed; 0868 m_askedXSpeed = sign(m_xSpeed) * m_speed; 0869 m_askedYSpeed = sign(m_ySpeed) * m_speed; 0870 updateDirection(); 0871 m_askedXSpeed = askedXSpeedTemp; 0872 m_askedYSpeed = askedYSpeedTemp; 0873 } 0874 break; 0875 case Granatier::Bonus::MIRROR: 0876 { 0877 qreal askedXSpeedTemp = m_askedXSpeed; 0878 qreal askedYSpeedTemp = m_askedYSpeed; 0879 m_askedXSpeed = -m_xSpeed; 0880 m_askedYSpeed = -m_ySpeed; 0881 switch(m_direction) 0882 { 0883 case Granatier::Direction::EAST: 0884 m_direction = Granatier::Direction::WEST; 0885 break; 0886 case Granatier::Direction::WEST: 0887 m_direction = Granatier::Direction::EAST; 0888 break; 0889 case Granatier::Direction::NORTH: 0890 m_direction = Granatier::Direction::SOUTH; 0891 break; 0892 case Granatier::Direction::SOUTH: 0893 m_direction = Granatier::Direction::NORTH; 0894 break; 0895 } 0896 updateDirection(); 0897 m_askedXSpeed = -askedXSpeedTemp; 0898 m_askedYSpeed = -askedYSpeedTemp; 0899 0900 QKeySequence tempKey = m_key.moveLeft; 0901 m_key.moveLeft = m_key.moveRight; 0902 m_key.moveRight = tempKey; 0903 tempKey = m_key.moveUp; 0904 m_key.moveUp = m_key.moveDown; 0905 m_key.moveDown = tempKey; 0906 0907 m_moveMirrored = false; 0908 } 0909 break; 0910 case Granatier::Bonus::RESTRAIN: 0911 m_bombArmory = m_normalBombArmory; 0912 break; 0913 default: 0914 break; 0915 } 0916 0917 Q_EMIT bonusUpdated(this, m_badBonusType, 100); 0918 } 0919 0920 void Player::stopMoving() 0921 { 0922 setXSpeed(0); 0923 setYSpeed(0); 0924 m_askedXSpeed = 0; 0925 m_askedYSpeed = 0; 0926 Q_EMIT stopped(); 0927 } 0928 0929 void Player::keyPressed(QKeyEvent* keyEvent) 0930 { 0931 if(m_death || m_falling) 0932 { 0933 return; 0934 } 0935 0936 QKeySequence key = QKeySequence(keyEvent->key()); 0937 0938 if(key == m_key.moveLeft || key == m_key.moveRight || key == m_key.moveUp || key == m_key.moveDown || key == m_key.dropBomb) 0939 { 0940 keyEvent->accept(); 0941 if(keyEvent->isAutoRepeat()) 0942 { 0943 return; 0944 } 0945 } 0946 else 0947 { 0948 return; 0949 } 0950 0951 if(key == m_key.moveLeft) 0952 { 0953 goLeft(); 0954 updateDirection(); 0955 } 0956 else if(key == m_key.moveRight) 0957 { 0958 goRight(); 0959 updateDirection(); 0960 } 0961 else if(key == m_key.moveUp) 0962 { 0963 goUp(); 0964 updateDirection(); 0965 } 0966 else if(key == m_key.moveDown) 0967 { 0968 goDown(); 0969 updateDirection(); 0970 } 0971 else if(key == m_key.dropBomb) 0972 { 0973 if(m_bombArmory > 0) 0974 { 0975 Q_EMIT bombDropped(this, m_x, m_y, true, 2); 0976 m_omitBombCurrentCell = true; 0977 } 0978 else 0979 { 0980 Q_EMIT bombDropped(this, m_x, m_y, false, 2); 0981 } 0982 } 0983 0984 } 0985 0986 void Player::keyReleased(QKeyEvent* keyEvent) 0987 { 0988 if(m_death || m_falling) 0989 { 0990 return; 0991 } 0992 0993 QKeySequence key = QKeySequence(keyEvent->key()); 0994 0995 if(key == m_key.moveLeft || key == m_key.moveRight || key == m_key.moveUp || key == m_key.moveDown || key == m_key.dropBomb) 0996 { 0997 keyEvent->accept(); 0998 if(keyEvent->isAutoRepeat()) 0999 { 1000 return; 1001 } 1002 } 1003 else 1004 { 1005 return; 1006 } 1007 1008 int nSpeed = 0; 1009 if(m_onIce) 1010 { 1011 nSpeed = onIceSpeedIncrease; 1012 } 1013 1014 if(key == m_key.moveLeft && m_xSpeed < 0) 1015 { 1016 setXSpeed(-nSpeed); 1017 } 1018 else if(key == m_key.moveRight && m_xSpeed > 0) 1019 { 1020 setXSpeed(nSpeed); 1021 } 1022 else if(key == m_key.moveUp && m_ySpeed < 0) 1023 { 1024 setYSpeed(-nSpeed); 1025 } 1026 else if(key == m_key.moveDown && m_ySpeed > 0) 1027 { 1028 setYSpeed(nSpeed); 1029 } 1030 else if(key == m_key.dropBomb) 1031 { 1032 //Q_EMIT bomb(this); 1033 } 1034 1035 if(m_xSpeed == 0 && m_ySpeed == 0 && m_askedXSpeed == 0 && m_askedYSpeed == 0) stopMoving(); 1036 } 1037 1038 int Player::signZeroPositive(const qreal value) 1039 { 1040 return (value >= 0 ? 1 : -1); 1041 } 1042 1043 int Player::sign(const qreal value) 1044 { 1045 if(value == 0) 1046 { 1047 return 0; 1048 } 1049 return (value > 0 ? 1 : -1); 1050 } 1051 1052 #include "moc_player.cpp"