Commit ab110bac authored by Dmitry Suzdalev's avatar Dmitry Suzdalev
Browse files

Implement one level undo.

Note that due to bug in QTimeLine, after this commit the game becomes unplayable
unless you exchange lines 113 and 114 in qtimeline.cpp which is in
qt-copy/src/corelib/tools/.

I thought about making patch for qt-copy, but this is not a critical one, so
I think it doesn't worth it :-)

Well, in fact I can place a temporary workaround so patching qt-copy won't be needed.
If someone needs this, ping me somewhere :-).

Bug has been reported to TT. Not accepted yet :).

svn path=/trunk/KDE/kdegames/klines/; revision=619586
parent b23cac6b
......@@ -79,7 +79,8 @@ KLinesAnimator::KLinesAnimator( KLinesScene* scene )
bool KLinesAnimator::isAnimating() const
{
return (m_moveTimeLine.state() == QTimeLine::Running
return (m_bornTimeLine.state() == QTimeLine::Running
|| m_moveTimeLine.state() == QTimeLine::Running
|| m_removeTimeLine.state() == QTimeLine::Running);
}
......
......@@ -59,7 +59,7 @@ public:
*/
void animateBorn( const QList<BallItem*>& list );
/**
* @returns whether some animation is in progress
* @return whether some animation is in progress
*/
bool isAnimating() const;
signals:
......
......@@ -40,9 +40,11 @@ BallItem::BallItem( QGraphicsScene* parent )
connect(&m_timeLine, SIGNAL(frameChanged(int)), SLOT(animFrameChanged(int)) );
}
void BallItem::setColor( BallColor c )
void BallItem::setColor( BallColor c, bool setPix )
{
m_color = c;
if(setPix)
setPixmap( KLinesRenderer::self()->ballPixmap( m_color ) );
}
void BallItem::startSelectedAnimation()
......
......@@ -38,8 +38,11 @@ public:
BallItem( QGraphicsScene* parent );
/**
* Sets ball's color
* @param setPix specifies whether to set corresponding ball pixmap to this
* item. In rare cases this may not be needed.
* (for example when the ball is created and born animation is played immediately)
*/
void setColor( BallColor c );
void setColor( BallColor c, bool setPix = true );
/**
* @return color of the ball
*/
......
......@@ -102,14 +102,17 @@ void KLines::initKAction()
act_demo->setText(i18n("Start &Tutorial"));
KStandardGameAction::highscores(this, SLOT(viewHighScore()), actionCollection());
KStandardGameAction::quit(this, SLOT(close()), actionCollection());
endTurnAction = KStandardGameAction::endTurn(this, SLOT(makeTurn()), actionCollection());
endTurnAction = KStandardGameAction::endTurn(mwidget->scene(), SLOT(endTurn()), actionCollection());
showNextAction = new KToggleAction(i18n("&Show Next"), actionCollection(), "options_show_next");
connect(showNextAction, SIGNAL(triggered(bool) ), SLOT(switchPrompt()));
showNextAction->setShortcut(KShortcut(Qt::CTRL+Qt::Key_P));
showNextAction->setCheckedState(KGuiItem(i18n("Hide Next")));
showNumberedAction = new KToggleAction(i18n("&Use Numbered Balls"), actionCollection(), "options_show_numbered");
connect(showNumberedAction, SIGNAL(triggered(bool) ), SLOT(switchNumbered()));
undoAction = KStandardGameAction::undo(this, SLOT(undo()), actionCollection());
undoAction = KStandardGameAction::undo(mwidget->scene(), SLOT(undo()), actionCollection());
undoAction->setEnabled(false);
connect( mwidget->scene(), SIGNAL(enableUndo(bool)), undoAction, SLOT(setEnabled(bool)) );
levelAction = KStandardGameAction::chooseGameType(0, 0, actionCollection());
QStringList items;
......
......@@ -107,8 +107,17 @@ void KLinesScene::resizeScene(int width,int height)
setSceneRect( 0, 0, width, height );
}
void KLinesScene::endTurn()
{
saveUndoInfo();
nextThreeBalls();
}
void KLinesScene::nextThreeBalls()
{
if( m_animator->isAnimating() )
return;
QList<BallItem*> newItems;
BallItem* newBall;
for(int i=0; i<3; i++)
......@@ -151,7 +160,7 @@ BallItem* KLinesScene::randomlyPlaceBall(BallColor c)
} while( m_field[posx][posy] != 0 );
BallItem* newBall = new BallItem( this );
newBall->setColor(c);
newBall->setColor(c, false); // pixmap will be set by born animation
newBall->setPos( fieldToPix( FieldPos(posx,posy) ) );
m_field[posx][posy] = newBall;
return newBall;
......@@ -179,6 +188,7 @@ void KLinesScene::selectOrMove( const FieldPos& fpos )
{
if( m_selPos.isValid() && m_field[fpos.x][fpos.y] == 0 )
{
saveUndoInfo();
// start move animation
// slot moveAnimFinished() will be called when it finishes
m_animator->animateMove(m_selPos, fpos);
......@@ -220,13 +230,19 @@ void KLinesScene::removeAnimFinished()
{
// slot bornAnimFinished() will be called
// when born animation finishes
// NOTE: removeAnimFinished() will be called again
// after new balls will born (because searchAndErase() will be called)
// but other if branch will be taken
nextThreeBalls();
}
else
{
// expression taked from previous code in klines.cpp
// this is kind of 'things to do after one turn is finished'
// place in code :)
int numBallsErased = m_itemsToDelete.count();
if(numBallsErased)
// expression taked from previous code in klines.cpp
m_score += 2*numBallsErased*numBallsErased - 20*numBallsErased + 60 ;
foreach( BallItem* item, m_itemsToDelete )
......@@ -236,13 +252,8 @@ void KLinesScene::removeAnimFinished()
}
m_itemsToDelete.clear();
// it is needed after qDeleteAll()
// as an optimisation we may update only rects
// in which items from m_itemsToDelete were before
// deletion
update();
emit scoreChanged(m_score);
if(numBallsErased)
emit scoreChanged(m_score);
}
}
......@@ -469,6 +480,65 @@ void KLinesScene::cellSelected()
selectOrMove( pixToField( m_focusItem->pos() + QPointF(16,16) ) );
}
void KLinesScene::saveUndoInfo()
{
// save field state to undoInfo
for(int x=0;x<FIELD_SIZE;++x)
for(int y=0; y<FIELD_SIZE;++y)
// NumColors represents no color
m_undoInfo.fcolors[x][y] = ( m_field[x][y] ? m_field[x][y]->color() : NumColors );
m_undoInfo.numFreeCells = m_numFreeCells;
m_undoInfo.score = m_score;
m_undoInfo.nextColors = m_nextColors;
emit enableUndo(true);
}
// Brings m_field and some other vars to the state it was before last turn
void KLinesScene::undo()
{
BallColor col;
for(int x=0;x<FIELD_SIZE;++x)
for(int y=0; y<FIELD_SIZE;++y)
{
col = m_undoInfo.fcolors[x][y];
if(col == NumColors) // no ball
{
if( m_field[x][y] )
{
removeItem( m_field[x][y] );
delete m_field[x][y];
m_field[x][y] = 0;
}
continue;
}
if( m_field[x][y] )
{
if( m_field[x][y]->color() != col )
m_field[x][y]->setColor(col);
//else live it as it is
}
else
{
BallItem *item = new BallItem(this);
item->setColor(col);
item->setPos( fieldToPix( FieldPos(x,y) ) );
item->show();
m_field[x][y] = item;
}
}
m_numFreeCells = m_undoInfo.numFreeCells;
m_score = m_undoInfo.score;
m_nextColors = m_undoInfo.nextColors;
m_selPos = FieldPos();
emit scoreChanged(m_score);
emit nextColorsChanged();
emit enableUndo(false);
}
void KLinesScene::drawBackground(QPainter *p, const QRectF&)
{
kDebug() << k_funcinfo << endl;
......
......@@ -44,19 +44,18 @@ class KLinesScene : public QGraphicsScene
public:
explicit KLinesScene( QObject *parent );
~KLinesScene();
/**
* Resizes scene
*/
void resizeScene( int width, int height );
/**
* Returns colors of the 3 balls in the next turn
*/
QList<BallColor> nextColors() const { return m_nextColors; }
/**
* Brings in next three balls to scene
*/
void nextThreeBalls();
/**
* Returns colors of the 3 balls in the next turn
*/
QList<BallColor> nextColors() const { return m_nextColors; }
/**
* Returns ballitem in field position pos or 0 if there
* is no item there
......@@ -82,6 +81,14 @@ public slots:
* Starts new game
*/
void startNewGame();
/**
* Ends current and starts next turn explicitly
*/
void endTurn();
/**
* Undoes one move
*/
void undo();
/**
* Moves keyboard-playing focus rect to the left
*/
......@@ -104,6 +111,7 @@ public slots:
void cellSelected();
signals:
void scoreChanged(int);
void enableUndo(bool);
void nextColorsChanged();
void gameOver(int);
private slots:
......@@ -129,6 +137,10 @@ private:
* (if the move is possible, of course)
*/
void selectOrMove( const FieldPos& fpos );
/**
* Saves game state information to be used during undo
*/
void saveUndoInfo();
virtual void drawBackground( QPainter*, const QRectF& );
virtual void mousePressEvent( QGraphicsSceneMouseEvent* );
......@@ -177,6 +189,22 @@ private:
* Keyboard-playing focus indication
*/
QGraphicsRectItem *m_focusItem;
/**
* Struct for holding game state - used on undos
*/
struct UndoInfo
{
int numFreeCells;
int score;
QList<BallColor> nextColors;
BallColor fcolors[FIELD_SIZE][FIELD_SIZE];
};
/**
* Holds game state for undo.
* It is saved before every new turn
*/
UndoInfo m_undoInfo;
};
class KLinesView : public QGraphicsView
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment