| 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 First Reported In: | 2.0 | ||
| Target Milestone: | --- | ||
| Platform: | unspecified | ||
| OS: | Linux | ||
| Latest Commit: | Version Fixed/Implemented 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());
|