Summary: | save game wishlist bug | ||
---|---|---|---|
Product: | [Applications] katomic | Reporter: | Ritesh Raj Sarraf <kde-bugs> |
Component: | general | Assignee: | Stephan Kulow <coolo> |
Status: | RESOLVED FIXED | ||
Severity: | wishlist | ||
Priority: | NOR | ||
Version: | 2.0 | ||
Target Milestone: | --- | ||
Platform: | unspecified | ||
OS: | Linux | ||
Latest Commit: | Version Fixed In: | ||
Sentry Crash Report: |
Description
Ritesh Raj Sarraf
2005-03-26 21:14:26 UTC
SVN commit 603044 by dimsuz: Implement wish #102557 - saving/loading of games. BUG: 102557 M +26 -1 gamewidget.cpp M +3 -0 gamewidget.h M +107 -38 playfield.cpp M +18 -6 playfield.h M +2 -0 toplevel.cpp --- trunk/KDE/kdegames/katomic/gamewidget.cpp #603043:603044 @@ -33,6 +33,7 @@ #include <kstandarddirs.h> #include <ksimpleconfig.h> #include <kglobalsettings.h> +#include <kfiledialog.h> #define MPOSX 480 @@ -42,6 +43,7 @@ // # class GameWidget # // ########################## +// FIXME dimsuz: get rid of it int level; void GameWidget::moveUp() @@ -102,7 +104,6 @@ { high.exec(); } - updateLevel(level+1); } void GameWidget::updateMoves(int moves) @@ -212,6 +213,30 @@ { } +void GameWidget::saveGame() +{ + QString fileName = KFileDialog::getSaveFileName( KUrl(), "*.katomic", this ); + if(fileName.isEmpty()) + return; + KSimpleConfig config(fileName); + config.setGroup("Savegame"); + config.writeEntry( "Level", level ); + m_playField->saveGame( config ); +} + +void GameWidget::loadGame() +{ + QString fileName = KFileDialog::getOpenFileName( KUrl(), "*.katomic", this ); + if(fileName.isEmpty()) + return; + KSimpleConfig config(fileName); + config.setGroup("Savegame"); + int l = config.readEntry( "Level", 1 ); + level = l; + updateLevel(level); + m_playField->loadGame( config ); +} + void GameWidget::showHighscores () { KScoreDialog high(KScoreDialog::Name | KScoreDialog::Score, this); --- trunk/KDE/kdegames/katomic/gamewidget.h #603043:603044 @@ -46,6 +46,9 @@ // bringt level auf neuesten stand void updateLevel (int); + void saveGame(); + void loadGame(); + // restart current level void restartLevel(); --- trunk/KDE/kdegames/katomic/playfield.cpp #603043:603044 @@ -74,7 +74,7 @@ // =============== Play Field ======================== PlayField::PlayField( QObject* parent ) - : QGraphicsScene(parent), m_mol(0), m_numMoves(0), m_elemSize(30), m_selAtom(0), m_animSpeed(120) + : QGraphicsScene(parent), m_mol(0), m_numMoves(0), m_elemSize(30), m_selIdx(-1), m_animSpeed(120) { m_renderer = new KAtomicRenderer( KStandardDirs::locate("appdata", "pics/default_theme.svgz"), this ); m_renderer->setElementSize( m_elemSize ); @@ -137,7 +137,7 @@ } } - m_selAtom = 0; + m_selIdx = -1; updateArrows(true); // this will hide them (no atom selected) updateFieldItems(); nextAtom(); @@ -150,7 +150,7 @@ item->setPixmap( m_renderer->renderAtom( m_mol->getAtom(item->atomNum()) ) ); // this may be true if resize happens during animation - if(m_timeLine->state() == QTimeLine::Running && item == m_selAtom ) + if( isAnimating() && m_selIdx != -1 && item == m_atoms.at(m_selIdx) ) continue; // its position will be taken care of in animFrameChanged() item->setPos( toPixX( item->fieldX() ), toPixY( item->fieldY() ) ); @@ -180,7 +180,7 @@ m_renderer->setBackgroundSize( QSize(width, height) ); // if animation is running we need to rescale timeline - if( m_timeLine->state() == QTimeLine::Running ) + if( isAnimating() ) { kDebug() << "restarting animation" << endl; int curTime = m_timeLine->currentTime(); @@ -197,15 +197,15 @@ void PlayField::nextAtom() { - if(!m_selAtom) + if(m_selIdx == -1) { - m_selAtom = m_atoms.at(0); + m_selIdx = 0; updateArrows(); return; } - int xs = m_selAtom->fieldX(); - int ys = m_selAtom->fieldY()+1; + int xs = m_atoms.at(m_selIdx)->fieldX(); + int ys = m_atoms.at(m_selIdx)->fieldY()+1; int x = xs; @@ -219,7 +219,7 @@ item = qgraphicsitem_cast<FieldGraphicsItem*>( itemAt(px, py) ); if( item != 0 && item->atomNum() != -1 ) { - m_selAtom = item; + m_selIdx = m_atoms.indexOf(item); updateArrows(); return; } @@ -233,15 +233,15 @@ void PlayField::previousAtom() { - if(!m_selAtom) + if(m_selIdx == -1) { - m_selAtom = m_atoms.at(0); + m_selIdx = 0; updateArrows(); return; } - int xs = m_selAtom->fieldX(); - int ys = m_selAtom->fieldY()-1; + int xs = m_atoms.at(m_selIdx)->fieldX(); + int ys = m_atoms.at(m_selIdx)->fieldY()-1; int x = xs; @@ -255,7 +255,7 @@ item = qgraphicsitem_cast<FieldGraphicsItem*>( itemAt(px, py) ); if( item != 0 && item->atomNum() != -1 ) { - m_selAtom = item; + m_selIdx = m_atoms.indexOf(item); updateArrows(); return; } @@ -269,7 +269,7 @@ void PlayField::undo() { - if(m_timeLine->state() == QTimeLine::Running || m_undoStack.isEmpty()) + if( isAnimating() || m_undoStack.isEmpty()) return; AtomMove am = m_undoStack.pop(); @@ -284,7 +284,7 @@ m_numMoves--; emit updateMoves(m_numMoves); - m_selAtom = am.atom; + m_selIdx = am.atomIdx; switch( am.dir ) { case Up: @@ -304,7 +304,7 @@ void PlayField::redo() { - if(m_timeLine->state() == QTimeLine::Running || m_redoStack.isEmpty()) + if( isAnimating() || m_redoStack.isEmpty() ) return; AtomMove am = m_redoStack.pop(); @@ -320,22 +320,23 @@ m_numMoves++; emit updateMoves(m_numMoves); - m_selAtom = am.atom; + m_selIdx = am.atomIdx; moveSelectedAtom(am.dir, am.numCells); } void PlayField::mousePressEvent( QGraphicsSceneMouseEvent* ev ) { - if( m_timeLine->state() == QTimeLine::Running ) + if( isAnimating() ) return; FieldGraphicsItem *clickedItem = qgraphicsitem_cast<FieldGraphicsItem*>(itemAt(ev->scenePos())); if(!clickedItem) return; - if( m_atoms.indexOf( clickedItem ) != -1 ) // that is: atom selected + int idx = m_atoms.indexOf( clickedItem ); + if( idx != -1 ) // that is: atom selected { - m_selAtom = clickedItem; + m_selIdx = idx; updateArrows(); } else if( clickedItem == m_upArrow ) @@ -358,7 +359,7 @@ void PlayField::moveSelectedAtom( Direction dir, int numCells ) { - if( m_timeLine->state() == QTimeLine::Running ) + if( isAnimating() ) return; @@ -371,8 +372,8 @@ { // helpers int x = 0, y = 0; - int selX = m_selAtom->fieldX(); - int selY = m_selAtom->fieldY(); + int selX = m_atoms.at(m_selIdx)->fieldX(); + int selY = m_atoms.at(m_selIdx)->fieldY(); switch( dir ) { case Up: @@ -417,7 +418,7 @@ { if(m_undoStack.isEmpty()) emit enableUndo(true); - m_undoStack.push( AtomMove(m_selAtom, m_dir, numEmptyCells) ); + m_undoStack.push( AtomMove(m_selIdx, m_dir, numEmptyCells) ); } m_timeLine->setCurrentTime(0); // reset @@ -429,34 +430,34 @@ void PlayField::animFrameChanged(int frame) { - int posx= toPixX(m_selAtom->fieldX()); - int posy= toPixY(m_selAtom->fieldY()); + FieldGraphicsItem *selAtom = m_atoms.at(m_selIdx); + int posx= toPixX(selAtom->fieldX()); + int posy= toPixY(selAtom->fieldY()); switch( m_dir ) { case Up: - posy = toPixY(m_selAtom->fieldY()) - frame; - m_selAtom->setPos( posx, posy ); + posy = toPixY(selAtom->fieldY()) - frame; break; case Down: - posy = toPixY(m_selAtom->fieldY()) + frame; + posy = toPixY(selAtom->fieldY()) + frame; break; case Left: - posx = toPixX(m_selAtom->fieldX()) - frame; + posx = toPixX(selAtom->fieldX()) - frame; break; case Right: - posx = toPixX(m_selAtom->fieldX()) + frame; + posx = toPixX(selAtom->fieldX()) + frame; break; } - m_selAtom->setPos(posx, posy); + selAtom->setPos(posx, posy); if(frame == m_timeLine->endFrame()) // that is: move finished { // FIXME dimsuz: consider moving this to separate function // to improve code readablility - m_selAtom->setFieldX( toFieldX((int)m_selAtom->pos().x()) ); - m_selAtom->setFieldY( toFieldY((int)m_selAtom->pos().y()) ); + selAtom->setFieldX( toFieldX((int)selAtom->pos().x()) ); + selAtom->setFieldY( toFieldY((int)selAtom->pos().y()) ); updateArrows(); emit updateMoves(m_numMoves); @@ -525,11 +526,11 @@ m_leftArrow->hide(); m_rightArrow->hide(); - if(justHide || !m_selAtom) + if(justHide || m_selIdx == -1) return; - int selX = m_selAtom->fieldX(); - int selY = m_selAtom->fieldY(); + int selX = m_atoms.at(m_selIdx)->fieldX(); + int selY = m_atoms.at(m_selIdx)->fieldY(); if(cellIsEmpty(selX-1, selY)) { @@ -568,4 +569,72 @@ p->drawPixmap(toPixX(i), toPixY(j), aPix); } +bool PlayField::isAnimating() const +{ + return (m_timeLine->state() == QTimeLine::Running); +} + +void PlayField::saveGame( KSimpleConfig& config ) const +{ + // REMEMBER: while saving use atom indexes within m_atoms, not atom's atomNum()'s. + // atomNum()'s arent unique, there can be several atoms + // in molecule which represent same atomNum + + for(int idx=0; idx<m_atoms.count(); ++idx) + { + // we'll write pos through using QPoint + // I'd use QPair but it isn't supported by QVariant + QPoint pos(m_atoms.at(idx)->fieldX(), m_atoms.at(idx)->fieldY()); + config.writeEntry( QString("Atom_%1").arg(idx), pos); + } + + // save undo history + int moveCount = m_undoStack.count(); + config.writeEntry( "MoveCount", moveCount ); + AtomMove mv; + for(int i=0;i<moveCount;++i) + { + mv = m_undoStack.at(i); + // atomIdx, direction, numCells + QList<int> move; + move << mv.atomIdx << static_cast<int>(mv.dir) << mv.numCells; + config.writeEntry( QString("Move_%1").arg(i), move ); + } + config.writeEntry("SelectedAtom", m_selIdx); +} + +void PlayField::loadGame( const KSimpleConfig& config ) +{ + // it is assumed that this method is called right after loadLevel() so + // level itself is already loaded at this point + + // read atom positions + for(int idx=0; idx<m_atoms.count(); ++idx) + { + QPoint pos = config.readEntry( QString("Atom_%1").arg(idx), QPoint() ); + m_atoms.at(idx)->setFieldXY(pos.x(), pos.y()); + m_atoms.at(idx)->setPos( toPixX(pos.x()), toPixY(pos.y()) ); + } + // fill undo history + m_numMoves = config.readEntry("MoveCount", 0); + + AtomMove mv; + for(int i=0;i<m_numMoves;++i) + { + QList<int> move = config.readEntry( QString("Move_%1").arg(i), QList<int>() ); + mv.atomIdx = move.at(0); + mv.dir = static_cast<Direction>(move.at(1)); + mv.numCells = move.at(2); + m_undoStack.push(mv); + } + if(m_numMoves) + { + emit enableUndo(true); + emit updateMoves(m_numMoves); + } + + m_selIdx = config.readEntry("SelectedAtom", 0); + updateArrows(); +} + #include "playfield.moc" --- trunk/KDE/kdegames/katomic/playfield.h #603043:603044 @@ -43,7 +43,7 @@ { Q_OBJECT public: - enum Direction { Up, Down, Left, Right }; + enum Direction { Up=0, Down, Left, Right }; /** * Constructor */ @@ -85,6 +85,14 @@ * Redoes one movement */ void redo(); + /** + * Saves the current game to config object + */ + void saveGame(KSimpleConfig& config) const; + /** + * Loads game from config object + */ + void loadGame(const KSimpleConfig& config); private slots: void animFrameChanged(int frame); signals: @@ -114,6 +122,10 @@ * Returns true if Field cell (x,y) is empty, i.e. it isn't a wall and has no atom */ bool cellIsEmpty(int x, int y) const; + /** + * Returns true if atom animation is running + */ + bool isAnimating() const; inline int toPixX( int fieldX ) { return fieldX*m_elemSize; } inline int toPixY( int fieldY ) { return fieldY*m_elemSize; } @@ -150,9 +162,9 @@ */ FieldGraphicsItem *m_upArrow, *m_leftArrow, *m_downArrow, *m_rightArrow; /** - * Currently selected atom + * Index of currently selected atom */ - FieldGraphicsItem *m_selAtom; + int m_selIdx; /** * Direction in which current atom animation moves */ @@ -168,11 +180,11 @@ struct AtomMove { - FieldGraphicsItem* atom; + int atomIdx; // atom index in m_atoms Direction dir; int numCells; - AtomMove( FieldGraphicsItem* at=0, Direction d=Up, int nc=0 ) - : atom(at), dir(d), numCells(nc) { } + AtomMove( int idx=-1, Direction d=Up, int nc=0 ) + : atomIdx(idx), dir(d), numCells(nc) { } }; QStack<AtomMove> m_undoStack; QStack<AtomMove> m_redoStack; --- trunk/KDE/kdegames/katomic/toplevel.cpp #603043:603044 @@ -39,6 +39,8 @@ { KAction *act = KStdGameAction::highscores(m_gameWid, SLOT(showHighscores()), actionCollection()); act->setText(i18n("Show &Highscores")); + KStdGameAction::load( m_gameWid, SLOT(loadGame()), actionCollection() ); + KStdGameAction::save( m_gameWid, SLOT(saveGame()), actionCollection() ); KStdGameAction::quit(this, SLOT(close()), actionCollection()); KStdGameAction::restart(m_gameWid, SLOT(restartLevel()), actionCollection()); |