File indexing completed on 2023-12-03 07:52:30

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