/*************************************************************************** Description : KPuzzle - A KDE Jigsaw Puzzle Game Version : 0.2 Copyright : (C) 2000-2001 by Michael Wand EMail : mwand@gmx.de ***************************************************************************/ /*************************************************************************** * * * This program 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. * * * ***************************************************************************/ #include "main.h" #include "piece.h" #include "kpuzzlegame.h" #include #include #include QCache* maskCache; /* Constructor. Reads piece data from a stream. Used when a game is * loaded from a file. */ CPiece::CPiece(KPuzzleGame* owner,QDataStream* f) { _owner = owner; _timerNr = -1; load(f); } /* Constructor. Makes a piece at a certain position. Used when * a new game is created. */ CPiece::CPiece(KPuzzleGame* owner,QPoint pos) { _owner = owner; _pos = pos; _turn = -1; /* because mingling is done by _owner */ _time = 0; _faults = 0; _hasBeenSet = false; _isCurrent = false; _timerNr = -1; } /* Destructor */ CPiece::~CPiece() { hidePiece(); } /* The piece time in seconds, as shown in the time widget. * Only valid if gameType \in PIECE_TIME_GAME, UNBEARABLE_GAME. */ int CPiece::time() const { return _owner->scoreData()->_maxPieceTime - _time; } /* The basic size of a piece (which does *not* take * into account the additional space needed for the * jigsaw puzzle-like shape of a piece). */ QSize CPiece::pieceSize() const { return _owner->pieceSize(); } /* The number of pieces (horizontally / vertically). */ QSize CPiece::piecesCount() const { return _owner->piecesCount(); } /* The number which has to be added to the piece size *in * every direction* to get the real size of a piece pixmap. * This is positive if and only if we are playing with * _useMask == true. */ int CPiece::displace() const { return _owner->displace(); } /* Return true if this piece should be shown to the player, i.e. * _hasBeenSet is false *and* there is time left for this piece * *and* the faults count for this piece is not too high (according * to the game type). */ bool CPiece::mayKeepPiece() const { return !_hasBeenSet && (_owner->gameType() == PIECE_TIME_GAME ? _time <= _owner->scoreData()->_maxPieceTime : true) && (_owner->gameType() == PIECE_FAULTS_GAME ? _faults <= _owner->scoreData()->_maxFaults : true); } /* Called when this piece is to be shown. Returns true if * this piece should be shown; in this case, makes the piece ready * to be shown (i.e. starts the timer). */ bool CPiece::showPiece() { if (_hasBeenSet) return false; /* This piece is already placed correctly. */ if ((_owner->gameData()->_gameType == PIECE_TIME_GAME && _time > _owner->scoreData()->_maxPieceTime) || (_owner->gameData()->_gameType == PIECE_FAULTS_GAME && _faults > _owner->scoreData()->_maxFaults)) return false; /* This piece may not be shown */ if (_owner->gameData()->_gameType == PIECE_TIME_GAME || _owner->gameData()->_gameType == UNBEARABLE_GAME) { startTimer(); } _isCurrent = true; return true; } /* Hide this piece, destroy connections. */ void CPiece::hidePiece() { stopTimer(); _isCurrent = false; } /* Try to place this piece at position p. If p != _pos (with a certain * tolerance), return false, if p == _pos, set _hasBeenSet to true. */ bool CPiece::setPiece(QPoint p) { if (p != pos() || turn()) { /* Wrong place, or wrong _turn */ if (_owner->gameType() == PIECE_FAULTS_GAME) _faults++; return false; } _hasBeenSet = true; return true; } /* Copy the pixmap showing this piece (in its jigsaw-puzzle-like shape) * into p. */ void CPiece::getPixmap(QPixmap* p) const { p->fill(Qt::black); QPoint realPos; if (_owner->maskedPieces()) { /* If we aren't at the left/top border, we copy displace() pixels more at the left/top side */ realPos = QPoint(pos().x() * pieceSize().width() - (pos().x() != 0 ? displace() : 0), pos().y() * pieceSize().height() - (pos().y() != 0 ? displace() : 0)); /* If we aren't at a border at all, we need 2 * _displace */ QSize copySize(pieceSize().width() + displace() + ((pos().x() && pos().x() < piecesCount().width() - 1) ? displace() : 0), pieceSize().height() + displace() + ((pos().y() && pos().y() < piecesCount().height() - 1) ? displace() : 0)); /* If we copy less, the destination position must be adjusted */ QPoint copyTo(pos().x() ? 0 : displace(),pos().y() ? 0 : displace()); bitBlt(p,copyTo,_owner->mainPixmap(),QRect(realPos,copySize),CopyROP,false); p->setMask(*getPieceMask()); } else { realPos = QPoint(pos().x() * pieceSize().width(),pos().y() * pieceSize().height()); bitBlt(p,QPoint(0,0),_owner->mainPixmap(),QRect(realPos,pieceSize()),CopyROP,false); } } /* Retrieve the mask of this piece, which is responsible for the jigsaw-like * shape of this piece. */ QBitmap* CPiece::getPieceMask() const { QBitmap* ret; QString resName; /* Calculate variant (1,2) and type of the piece */ int variant = ((pos().x() + pos().y()) % 2 ? 2 : 1); resName.sprintf("piece%i",variant); if (!pos().x()) resName += "-l"; if (pos().x() == piecesCount().width() - 1) resName += "-r"; if (!pos().y()) resName += "-t"; if (pos().y() == piecesCount().height() - 1) resName += "-b"; if ((ret = maskCache->find(resName))) return ret; QPixmap pxm(PICFILE(resName + ".bmp")); ret = new QBitmap; *ret = pxm; if (ret->width() != _owner->pieceSizeDisp().width() || ret->height() != _owner->pieceSizeDisp().height()) { QBitmap* temp = new QBitmap; QWMatrix mx; mx.scale((float) _owner->pieceSizeDisp().width() / ret->width(), (float) _owner->pieceSizeDisp().height() / ret->height()); *temp = ret->xForm(mx); delete ret; ret = temp; } maskCache->insert(resName,ret); return ret; } /* Copy the pixmap showing this piece (in its jigsaw-puzzle-like shape) * into p. Take into account the _turn of this piece. */ void CPiece::getTurnedPixmap(QPixmap* p) const { QWMatrix t((turn() & TURN_LR ? -1 : 1),0,0,(turn() & TURN_UD ? -1 : 1),0,0); *p = _owner->currentPiecePixmap()->xForm(t); } /* Save the data of this piece to f. */ void CPiece::save(QDataStream* f) const { *f << _pos; *f << _turn; *f << _time; *f << _faults; *f << (Q_INT8) _hasBeenSet; *f << (Q_INT8) _isCurrent; } /* Load the data of this piece. Only called by the constructor. */ void CPiece::load(QDataStream* f) { *f >> _pos; *f >> _turn; *f >> _time; *f >> _faults; *f >> (Q_INT8&) _hasBeenSet; *f >> (Q_INT8&) _isCurrent; } /* Called on each timer tick. */ void CPiece::timerEvent(QTimerEvent*) { ASSERT(_owner->gameData()->_gameType == PIECE_TIME_GAME || _owner->gameData()->_gameType == UNBEARABLE_GAME); _time++; emit sigTimerTick(_owner->scoreData()->_maxPieceTime - _time); if (_time > _owner->scoreData()->_maxPieceTime) { if (_owner->gameData()->_gameType == UNBEARABLE_GAME) _time = 0; _owner->hidePiece(); } } /* Start the timer of this piece. */ void CPiece::startTimer() { if (_owner->gameData()->_gameType == PIECE_TIME_GAME || _owner->gameData()->_gameType == UNBEARABLE_GAME) _timerNr = QObject::startTimer(1000); } /* Stop the timer of this piece. */ void CPiece::stopTimer() { if (_timerNr != -1) killTimer(_timerNr); }