/* This file is part of KsirK. Copyright (C) 2001-2007 Gael de Chalendar KsirK is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* begin : Wed Jul 18 2001 */ #include "animsprite.h" #include "skinSpritesData.h" #include "backgnd.h" #include "kgamewin.h" #include "ksirksettings.h" #include "GameLogic/nationality.h" #include "GameLogic/country.h" #include "GameLogic/gameautomaton.h" #include "GameLogic/onu.h" #include #include #include #include #include #include #include "ksirk_debug.h" namespace Ksirk { using namespace GameLogic; AnimSprite::AnimSprite(const QString &svgid, unsigned int width, unsigned int height, unsigned int nbFrames, unsigned int nbDirs, double zoom, BackGnd* aBackGnd, unsigned int visibility) : QGraphicsPixmapItem(0), m_animated(false), m_zoom(zoom), m_svgid(svgid), look(right), nbVersions(nbDirs), backGnd(aBackGnd), destination(0), destinationPoint(), frames(nbFrames), actFrame(0), myState(NONE), m_height(zoom*height), m_width(zoom*width), approachDestByLeft(false), approachDestByRight(false), approachDestByTop(false), approachDestByBottom(false), m_frames(), m_renderer(const_cast(aBackGnd->onu())->renderer()), m_numberOfShots(0), m_timer(this), m_skin(backGnd->onu()->skin()) { aBackGnd-> scene()->addItem(this); // qCDebug(KSIRK_LOG) << svgid << nbFrames; setNone(); sequenceConstruction(); setZValue(visibility); show(); /// @note uncomment here if you want to try sprites animation by connection to a timer // connect(GameAutomaton::changeable().game()->frame()->timer(),SIGNAL(timeout()),this,SLOT(animate())); connect(&m_timer,&QTimer::timeout,this,&AnimSprite::animate); // m_timer.setSingleShot(true); if (frames > 1) { m_timer.start(200); } } AnimSprite::~AnimSprite() { // qCDebug(KSIRK_LOG) << (void*)this ; m_timer.stop(); disconnect(&m_timer,&QTimer::timeout,this,&AnimSprite::animate); setStatic(); } void AnimSprite::repaint() { update(); } void AnimSprite::setLook(TDir newLook) { // qCDebug(KSIRK_LOG); if (newLook != look) { // qCDebug(KSIRK_LOG)<<"setLook : " << newLook << ")"; look=newLook; setFrame(0); update(); } } /** * updates the sequence of images used by the underlying QGraphicsPixmapItem * with the ones taken from the image found at imgPath. It is function of the * direction of the look and the geometry of the sprite */ void AnimSprite::sequenceConstruction() { QList list; QPixmap allpm; QString allpmCacheId = m_skin+m_svgid+QString::number(m_width*frames)+"x"+QString::number(m_height*nbVersions); if (!QPixmapCache::find(allpmCacheId, &allpm)) { // Pixmap isn't in the cache, create it and insert to cache QSize size((int)(m_width*frames), (int)(m_height*nbVersions)); QImage image(size, QImage::Format_ARGB32_Premultiplied); image.fill(0); QPainter p(&image); m_renderer->render(&p, m_svgid); allpm = QPixmap::fromImage(image); QPixmapCache::insert(allpmCacheId, allpm); } for (unsigned int l = 0; l (frames-1)) { actFrame=0; // come back to start if (m_numberOfShots == 1) { setStatic(); m_numberOfShots = std::numeric_limits::max(); qCDebug(KSIRK_LOG) << "Emiting animationFinished"; emit animationFinished(this); } else if (m_numberOfShots != std::numeric_limits::max()) { m_numberOfShots--; qCDebug(KSIRK_LOG) << "numberOfShots is now " << m_numberOfShots ; } } setFrame(actFrame); } void AnimSprite::setFrame(unsigned int numFrame) { // qCDebug(KSIRK_LOG) << " " << numFrame << " look=" << look <<" ; frames=" // < delta) setPos(pos()+QPointF(0,delta)); else if (destinationPoint.y() - y() <= delta) setPos(x(),destinationPoint.y()); else /*if (destinationPoint.y() - y() <= delta)*/ setPos(pos()+QPointF(0,1)); } if (y() > destinationPoint.y()) { if (getMaxY() - y() > delta) setPos(pos()+QPointF(0,delta)); if (getMaxY() - y() <= delta) setPos(x(),destinationPoint.y()<0?destinationPoint.y():0); } } else if (getApproachDestByBottom()) { if (y() < destinationPoint.y()) { if (destinationPoint.y() - y() > delta) setPos(pos()+QPointF(0,-delta)); if (destinationPoint.y() - y() <= delta) setPos(x(), getMaxY() ); } if (y() > destinationPoint.y()) { if ( y() - destinationPoint.y() > delta) setPos(pos()+QPointF(0,-delta)); else if ( y() - destinationPoint.y() <= 1) setPos(x(),destinationPoint.y()); else /*if ( y() - destinationPoint.y() <= delta)*/ setPos(pos()+QPointF(0,-1)); } } else { if (y() < destinationPoint.y()) { if (destinationPoint.y() - y() > delta) setPos(pos()+QPointF(0,delta)); else if (destinationPoint.y() - y() <= 1) setPos(x(),destinationPoint.y()); else /*if (destinationPoint.y() - y() <= delta)*/ setPos(pos()+QPointF(0,1)); } if (y() > destinationPoint.y()) { if (y() - destinationPoint.y() > delta) setPos(pos()+QPointF(0,-delta)); else if (y() - destinationPoint.y() <= 1) setPos(x(), destinationPoint.y()); else /*if (y() - destinationPoint.y() <= delta)*/ setPos(pos()+QPointF(0,-1)); } } // qCDebug(KSIRK_LOG) << "New position of " << (void*)this << " is: " << pos(); nextFrame(); if (pos() == destinationPoint) { setStatic(); destinationPoint = QPointF(); emit atDestination(this); } } bool AnimSprite::isLastFrame() const { // qCDebug(KSIRK_LOG)<<"AnimSprite::isLastFrame actFrame = "< pixmap().height(); else { KMessageBox::error(0, i18n("Cannot find Max Y for sprite: no background!"), i18n("Error!")); exit(2); } } void AnimSprite::setupTravel(Country* src, Country* dest, const QPointF* dpi) { qCDebug(KSIRK_LOG) << src->name() << dest->name() << *dpi << (dpi==0?QPointF():*dpi); if (dpi ==0) AnimSprite::setupTravel(src, dest, src->centralPoint(), dest-> centralPoint()); else AnimSprite::setupTravel(src, dest, src->centralPoint(), *dpi); } /** * This function chooses the approach mode of a sprite towards its destination: * if the distance between the origin and the destination is higher than half * the size of the map and if the origin and destination countries comunicate, * then the sprite should choose an approach by left or right, through the * edge of the map. * This protected method will be called by three public functions specialized * using as source point, respectivly, the infantryman point, the cavalryman * point and the cannon point. */ void AnimSprite::setupTravel( Country* src, Country* dest, const QPointF& srcPoint, const QPointF& destPoint) { qCDebug(KSIRK_LOG) << src->name() << srcPoint << ", " << dest->name() << destPoint ; setDestination(dest); setDestinationPoint(destPoint); setPos(srcPoint); if (!src-> communicateWith(dest)) { qCCritical(KSIRK_LOG) << "Error in AnimSprite::setupTravel: " << src-> name() << " and " << dest-> name() << " do not communicate!\n"; exit(2); } if ( (qAbs(srcPoint.x() - destPoint.x())) > ((backGnd-> boundingRect().width())/2) && !backGnd->bgIsArena()) { // src is at the right of dest, approch dest by left if (srcPoint.x() > destPoint.x()) setApproachDestByLeft(true); // src is at the left of dest, approch dest by right if (srcPoint.x() < destPoint.x()) setApproachDestByRight(true); } else { // src is at the right of dest, approch dest by left if (srcPoint.x() > destPoint.x()) setApproachDestByRight(true); // src is at the left of dest, approch dest by right if (srcPoint.x() < destPoint.x()) setApproachDestByLeft(true); } if ( ((qAbs(srcPoint.y() - destPoint.y())) > ((backGnd-> boundingRect().height())/2)) && !backGnd->bgIsArena()) { // src is under the dest, approch dest by top if (srcPoint.y() > destPoint.y()) setApproachDestByTop(true); // src is up to the dest, approch dest by botto if (srcPoint. y() < destPoint.y()) setApproachDestByBottom(true); } else { // src is under the dest, approch dest by bottom if (srcPoint.y() > destPoint.y()) setApproachDestByBottom(true); // src is up to the dest, approch dest by top if (srcPoint. y() < destPoint.y()) setApproachDestByTop(true); } if (src->pointFlag().x() < dest-> pointFlag().x()) { setLookRight(); } else { setLookLeft(); } setAnimated(); qCDebug(KSIRK_LOG) << "Done"; } void AnimSprite::arrival() { qCDebug(KSIRK_LOG)<< "at " << destinationPoint ; if (!backGnd->bgIsArena()) { qCDebug(KSIRK_LOG)<< "x=" << x() << "pf=" << getDestination()->pointFlag().x(); if (x() < getDestination()-> pointFlag().x()) setLookRight(); else setLookLeft(); } repaint(); } /** Return true if the state of the sprite is the argument; false otherwise */ bool AnimSprite::isMyState(State state) const { return myState == state; } /** * returns the current state of the sprite */ AnimSprite::State AnimSprite::getState() const { // qCDebug(KSIRK_LOG) << "I'm a sprite; my state is : " << myState ; return myState; } /** sets the new state of the game */ void AnimSprite::setState(AnimSprite::State newState) { // qCDebug(KSIRK_LOG) << "Setting sprite's state to : " << newState << " (was : " << myState << ")"; myState = newState; } void AnimSprite::saveXml(QTextStream& /*xmlStream*/) { } QPixmap AnimSprite::image(unsigned int numFrame) const { // qCDebug(KSIRK_LOG) << "image(" << numFrame << ") / " << m_frames.size(); if (numFrame >= (unsigned int)m_frames.size()) { return QPixmap(); } else { return m_frames[(look-1)*frames+numFrame]; } } void AnimSprite::animate() { // qCDebug(KSIRK_LOG) << (void*)this ; if (!destinationPoint.isNull() && pos() != destinationPoint) { moveIt(); } else if (m_animated && frames > 1) { nextFrame(); } // qCDebug(KSIRK_LOG) <<"finished for " << (void*)this ; } void AnimSprite::setAnimated(unsigned int numberOfShots) { m_numberOfShots = numberOfShots; m_animated = true; if (!m_timer.isActive()) { m_timer.start(200); } // AnimSpritePool::changeable().addSprite(this); } void AnimSprite::setStatic() { m_animated = false; m_timer.stop(); // AnimSpritePool::changeable().removeSprite(this); } void AnimSprite::applyZoomFactor(qreal zoomFactor) { qCDebug(KSIRK_LOG) << "old zoom=" << m_zoom ; m_zoom *= zoomFactor; m_width *= m_zoom; m_height *= m_zoom; sequenceConstruction(); update(); } void AnimSprite::addDecoration(const QString& svgid, const QRectF& geometry) { QSize size(geometry.size().toSize()); QImage image(size, QImage::Format_ARGB32_Premultiplied); image.fill(0); QPainter p(&image); m_renderer->render(&p, svgid); QPixmap pm = QPixmap::fromImage(image); QGraphicsPixmapItem* item = new QGraphicsPixmapItem(pm,this); item->setPos(geometry.topLeft()); item->show(); } } // closing namespace Ksirk