File indexing completed on 2024-12-01 03:46:16

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 "bombitem.h"
0009 #include "bomb.h"
0010 #include "settings.h"
0011 
0012 #include <QTimer>
0013 #include <QGraphicsView>
0014 
0015 #include <KGameRenderer>
0016 
0017 const int nBombPulseTime = 100;
0018 
0019 BombItem::BombItem(Bomb* p_model, KGameRenderer* renderer) : ElementItem (p_model, renderer)
0020 {
0021     setSpriteKey(QStringLiteral("bomb"));
0022     setZValue(210);
0023     connect(p_model, &Bomb::bombDetonated, this, &BombItem::startDetonation);
0024     connect(p_model, &Bomb::falling, this, &BombItem::fallingAnimation);
0025     connect(this, &BombItem::bombItemFinished, p_model, &Bomb::slot_detonationCompleted);
0026 
0027     int width = static_cast<int>(Granatier::CellSize * 0.9);
0028     int height = static_cast<int>(Granatier::CellSize * 0.9);
0029     if((static_cast<int>(Granatier::CellSize) - width) % 2 != 0)
0030     {
0031         width--;
0032     }
0033     if((static_cast<int>(Granatier::CellSize) - height) % 2 != 0)
0034     {
0035         height--;
0036     }
0037     m_itemSizeSet = QSize(width, height);
0038     m_itemSizeReal = m_itemSizeSet;
0039 
0040     m_animationCounter = 0;
0041     // Define the timer which sets the puls frequency
0042     m_pulseTimer = new QTimer(this);
0043     m_pulseTimer->setInterval(nBombPulseTime);
0044     m_pulseTimer->start();
0045     connect(m_pulseTimer, &QTimer::timeout, this, &BombItem::pulse);
0046 
0047     m_explosionTimer = nullptr;
0048     m_listExplosionTiming = {
0049         Settings::self()->blastTime1(),
0050         Settings::self()->blastTime2(),
0051         Settings::self()->blastTime3(),
0052         Settings::self()->blastTime4(),
0053         Settings::self()->blastTime5(),
0054     };
0055 
0056     m_fallingAnimationCounter = 0;
0057     m_dudBomb = false;
0058 }
0059 
0060 BombItem::~BombItem()
0061 {
0062     delete m_pulseTimer;
0063     delete m_explosionTimer;
0064 }
0065 
0066 QPainterPath BombItem::shape() const
0067 {
0068     QPainterPath path;
0069     // Temporary variable to keep the boundingRect available
0070     QRectF rect = boundingRect();
0071 
0072     // Calculation of the shape
0073     QRectF shapeRect = QRectF( rect.x()+rect.width()/8, rect.y()+rect.height()/8, rect.width()*3.0/4.0, rect.height()*3.0/4.0 );
0074     path.addEllipse(shapeRect);
0075     return path;
0076 }
0077 
0078 void BombItem::pauseAnim()
0079 {
0080     dynamic_cast <Bomb*> (m_model)->pause();
0081     if(m_pulseTimer)
0082     {
0083         m_pulseTimer->stop();
0084     }
0085     if(m_explosionTimer)
0086     {
0087         m_explosionTimer->stop();
0088     }
0089 }
0090 
0091 void BombItem::resumeAnim()
0092 {
0093     if(m_pulseTimer && !m_dudBomb)
0094     {
0095         m_pulseTimer->start();
0096     }
0097     if(m_explosionTimer)
0098     {
0099         m_explosionTimer->start();
0100     }
0101     dynamic_cast <Bomb*> (m_model)->resume();
0102 }
0103 
0104 void BombItem::update(qreal p_x, qreal p_y)
0105 {
0106     // Compute the top-right coordinates of the item
0107     qreal x = p_x - m_itemSizeSet.width() / 2;
0108     qreal y = p_y - m_itemSizeSet.height() / 2;
0109     // Updates the view coordinates
0110     setPos(x, y);
0111     m_x = static_cast<int>(p_x);
0112     m_y = static_cast<int>(p_y);
0113 }
0114 
0115 void BombItem::startDetonation()
0116 {
0117     if(m_pulseTimer)
0118     {
0119         m_pulseTimer->stop();
0120         delete m_pulseTimer;
0121         m_pulseTimer = nullptr;
0122     }
0123     m_animationCounter = 0;
0124     QTransform transform;
0125     transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.height() / 2.0);
0126     setRenderSize(m_renderSize);
0127     transform.translate(-m_itemSizeReal.width() / 2.0, -m_itemSizeReal.height() / 2.0);
0128     setTransform(transform);
0129     dynamic_cast <Bomb*> (m_model)->setXSpeed(0);
0130     dynamic_cast <Bomb*> (m_model)->setYSpeed(0);
0131 
0132     // Define the timer which sets the explosion frequency
0133     m_explosionTimer = new QTimer(this);
0134     m_explosionTimer->setInterval(m_listExplosionTiming.at(0));
0135     m_explosionTimer->setSingleShot(true);
0136     m_explosionTimer->start();
0137     connect(m_explosionTimer, &QTimer::timeout, this, &BombItem::updateAnimation);
0138 
0139     int width = static_cast<int>(Granatier::CellSize * 1.1);
0140     int height = static_cast<int>(Granatier::CellSize * 1.1);
0141     if((static_cast<int>(Granatier::CellSize) - width) % 2 != 0)
0142     {
0143         width--;
0144     }
0145     if((static_cast<int>(Granatier::CellSize) - height) % 2 != 0)
0146     {
0147         height--;
0148     }
0149     m_itemSizeSet = QSize(width, height);
0150     m_itemSizeReal = m_itemSizeSet;
0151     setSpriteKey(QStringLiteral("bomb_blast_core_0"));
0152     setZValue(300+15); //300+maxBombPower+5
0153     updateGraphics(scale());
0154     update(m_x, m_y);
0155 }
0156 
0157 void BombItem::pulse()
0158 {
0159     if(m_fallingAnimationCounter == 0)
0160     {
0161         m_animationCounter++;
0162         if (m_animationCounter % 2 == 0)
0163         {
0164             m_animationCounter = 0;
0165             int viewWidth = static_cast<int>(m_renderSize.width() * 0.98);
0166             int viewHeight = static_cast<int>(m_renderSize.height() * 0.98);
0167             if((m_renderSize.width() - viewWidth) % 2 != 0)
0168             {
0169                 viewWidth--;
0170             }
0171             if((m_renderSize.height() - viewHeight) % 2 != 0)
0172             {
0173                 viewHeight--;
0174             }
0175 
0176             //calculate the real item size after change of the render size
0177             QPointF sceneTopLeft = scene()->views().first()->mapToScene(QPoint(0, 0));
0178             QPointF sceneBottomRight = scene()->views().first()->mapToScene(QPoint(viewWidth, viewHeight));
0179 
0180             qreal sceneWidth = sceneBottomRight.x() - sceneTopLeft.x();
0181             qreal sceneHeight = sceneBottomRight.y() - sceneTopLeft.y();
0182 
0183             // shrink the item
0184             QTransform transform;
0185             transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.height() / 2.0);
0186             setRenderSize(QSize(viewWidth, viewHeight));
0187             transform.translate(-sceneWidth / 2.0, -sceneHeight / 2.0);
0188             setTransform(transform);
0189         }
0190         else
0191         {
0192             QTransform transform;
0193             transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.height() / 2.0);
0194             setRenderSize(m_renderSize);
0195             transform.translate(-m_itemSizeReal.width() / 2.0, -m_itemSizeReal.height() / 2.0);
0196             setTransform(transform);
0197         }
0198     }
0199     else
0200     {
0201         // shrink the item
0202         QTransform transform;
0203         transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.height() / 2.0);
0204         setRenderSize(m_renderSize * (1-m_fallingAnimationCounter*0.02));
0205         transform.translate(-m_itemSizeReal.width() * (1-m_fallingAnimationCounter*0.02) / 2.0, -m_itemSizeReal.height() * (1-m_fallingAnimationCounter*0.02) / 2.0);
0206         setTransform(transform);
0207         m_fallingAnimationCounter++;
0208 
0209         if(m_fallingAnimationCounter > 50)
0210         {
0211             m_pulseTimer->stop();
0212             m_dudBomb = true;
0213             Q_EMIT bombItemFinished(this);
0214         }
0215     }
0216 }
0217 
0218 void BombItem::updateAnimation()
0219 {
0220     m_animationCounter++;
0221     if (m_animationCounter > 4)
0222     {
0223         Q_EMIT bombItemFinished(this);
0224         m_animationCounter = 0;
0225         return;
0226     }
0227     QString strElemetId = QStringLiteral("bomb_blast_core_%1").arg(m_animationCounter);
0228     setSpriteKey(strElemetId);
0229     updateGraphics(scale());
0230     update(m_x, m_y);
0231 
0232     Q_EMIT animationFrameChanged(this, m_animationCounter);
0233     m_explosionTimer->setInterval(m_listExplosionTiming.at(m_animationCounter));
0234     m_explosionTimer->start();
0235 }
0236 
0237 void BombItem::updateMortar(int nMortarState, int nMortarRampEnd, int nMortarPeak, int nMortarGround)
0238 {
0239     if(m_pulseTimer)
0240     {
0241         m_pulseTimer->stop();
0242         delete m_pulseTimer;
0243         m_pulseTimer = nullptr;
0244     }
0245 
0246     if(nMortarState <= 0)
0247     {
0248         setVisible(false);
0249         setZValue(-1);
0250     }
0251     else if(nMortarState <= nMortarGround)
0252     {
0253         updateMortarAnimation(nMortarState, nMortarRampEnd, nMortarPeak);
0254     }
0255     else
0256     {
0257         if(!m_pulseTimer)
0258         {
0259             m_pulseTimer = new QTimer(this);
0260             m_pulseTimer->setInterval(nBombPulseTime);
0261             m_animationCounter = 1; // set to one, to start pulsing with a small bomb
0262             m_pulseTimer->start();
0263             connect(m_pulseTimer, &QTimer::timeout, this, &BombItem::pulse);
0264         }
0265         QTransform transform;
0266         transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.height() / 2.0);
0267         setRenderSize(m_renderSize);
0268         transform.translate(-m_itemSizeReal.width() / 2.0, -m_itemSizeReal.height() / 2.0);
0269         setTransform(transform);
0270         setVisible(true);
0271         setZValue(210);
0272     }
0273 }
0274 
0275 void BombItem::updateMortarAnimation(int animationCounter, int nMortarRampEnd, int nMortarPeak)
0276 {
0277     qreal mortarScale = 1;
0278     int mortarZValue = 210;
0279     QTransform transform;
0280 
0281     if(animationCounter < nMortarRampEnd)
0282     {
0283         mortarZValue = 210;
0284     }
0285     else
0286     {
0287         mortarZValue = 800;
0288     }
0289 
0290     int frame = animationCounter - nMortarRampEnd;
0291     int peak = nMortarPeak - nMortarRampEnd;
0292 
0293     mortarScale = 1.5 - (frame-peak) * (frame-peak) / static_cast<qreal>(peak*peak) * 0.5;
0294 
0295     transform.translate(m_itemSizeSet.width() / 2.0, m_itemSizeSet.height() / 2.0);
0296     setRenderSize(m_renderSize * mortarScale);
0297     transform.translate(-m_itemSizeReal.width() * mortarScale / 2.0, -m_itemSizeReal.height() * mortarScale / 2.0);
0298     setTransform(transform);
0299 
0300     setVisible(true);
0301     setZValue(mortarZValue);
0302 }
0303 
0304 void BombItem::fallingAnimation()
0305 {
0306     m_fallingAnimationCounter = 1;
0307     // set z-value below the ground
0308     setZValue(-2);
0309     m_pulseTimer->setInterval(1000 / Granatier::FPS);
0310 }
0311 
0312 #include "moc_bombitem.cpp"