1/*******************************************************************
2 *
3 * Copyright 2006-2007 Dmitry Suzdalev <dimsuz@gmail.com>
4 * Copyright 2010 Brian Croom <brian.s.croom@gmail.com>
5 *
6 * This file is part of the KDE project "KAtomic"
7 *
8 * KAtomic is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * KAtomic is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with KAtomic; see the file COPYING. If not, write to
20 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 ********************************************************************/
24#ifndef PLAYFIELD_H
25#define PLAYFIELD_H
26#include <QGraphicsScene>
27#include <KGameRenderer>
28#include <QList>
29#include <QStack>
30
31#include "commondefs.h"
32
33#define MIN_ELEM_SIZE 30
34
35class KConfigGroup;
36class AtomFieldItem;
37class ArrowFieldItem;
38class MoleculePreviewItem;
39class QTimeLine;
40class KGamePopupItem;
41class LevelData;
42
43/**
44 * KAtomic level playfield
45 */
46class PlayField : public QGraphicsScene
47{
48 Q_OBJECT
49public:
50 enum Direction { Up=0, Down, Left, Right };
51 /**
52 * Constructor
53 */
54 explicit PlayField( QObject *parent );
55 /**
56 * Destructor
57 */
58 virtual ~PlayField();
59 /**
60 * Resizes playfield to width,height
61 */
62 void resize( int width, int height );
63 /**
64 * Loads level
65 */
66 void setLevelData(const LevelData* level);
67 /**
68 * Sets animation speed (0-slow, 1-normal, 2-fast)
69 */
70 void setAnimationSpeed(int speed);
71 /**
72 * Animates currently selected atom movement in direction dir
73 * @param numCells used on undos/redos
74 */
75 void moveSelectedAtom( Direction dir, int numCells=0 );
76 /**
77 * Saves the current game to config object
78 */
79 void saveGame(KConfigGroup& config) const;
80 /**
81 * Loads game from config object
82 */
83 void loadGame(const KConfigGroup& config);
84 /**
85 * Returns whether level is finished already
86 */
87 bool isLevelFinished() const { return m_levelFinished; }
88 /**
89 * Displays a passive popup message at the bottom of the scene
90 */
91 void showMessage( const QString& message );
92 /**
93 * Name of the current molecule
94 */
95 QString moleculeName() const;
96 /**
97 * The caching SVG pixmap renderer
98 */
99 KGameRenderer* renderer() { return &m_renderer; }
100
101public slots:
102 /**
103 * Selects next atom
104 */
105 void nextAtom();
106 /**
107 * Selects previous atom
108 */
109 void previousAtom();
110 /**
111 * Undoes one movement
112 */
113 void undo();
114 /**
115 * Redoes one movement
116 */
117 void redo();
118 /**
119 * Undoes all movements
120 */
121 void undoAll();
122 /**
123 * Redoes all movements
124 */
125 void redoAll();
126signals:
127 void gameOver(int numMoves);
128 void updateMoves(int);
129 void enableUndo(bool);
130 void enableRedo(bool);
131private slots:
132 void atomAnimFrameChanged(int frame);
133private:
134 virtual void drawForeground( QPainter*, const QRectF& );
135 virtual void mousePressEvent( QGraphicsSceneMouseEvent* ev );
136
137 /**
138 * Checks if molecule is finished
139 */
140 bool checkDone() const;
141 /**
142 * Re-renders atoms&arrows Pixmaps, updates their positions
143 */
144 void updateFieldItems();
145 /**
146 * Updates arrows around selected atom
147 */
148 void updateArrows(bool justHide=false);
149 /**
150 * Set the background brush to a properly sized pixmap
151 */
152 void updateBackground();
153 /**
154 * Returns true if Field cell (x,y) is empty, i.e. it isn't a wall and has no atom
155 */
156 bool cellIsEmpty(int x, int y) const;
157 /**
158 * Returns true if atom animation is running
159 */
160 bool isAnimating() const;
161
162 inline int toPixX( int fieldX ) const { return fieldX*m_elemSize; }
163 inline int toPixY( int fieldY ) const { return fieldY*m_elemSize; }
164 inline int toFieldX( int pixX ) const { return pixX/m_elemSize; }
165 inline int toFieldY( int pixY ) const { return pixY/m_elemSize; }
166 inline int fieldCenterX() const { return toPixX(0) + m_elemSize*FIELD_SIZE/2; }
167 inline int fieldCenterY() const { return toPixY(0) + m_elemSize*FIELD_SIZE/2; }
168
169 /**
170 * Renderer object
171 */
172 KGameRenderer m_renderer;
173 /**
174 * Number of moves made for current level
175 */
176 int m_numMoves;
177 /**
178 * Level Data
179 */
180 const LevelData* m_levelData;
181 /**
182 * Element (i.e. atom, wall, arrow) size
183 */
184 int m_elemSize;
185 /**
186 * List of atom QGraphicsItems
187 */
188 QList<AtomFieldItem*> m_atoms;
189 /**
190 * Arrow items
191 */
192 ArrowFieldItem *m_upArrow, *m_leftArrow, *m_downArrow, *m_rightArrow;
193 /**
194 * Item used to show messages to user
195 */
196 KGamePopupItem *m_messageItem;
197 /**
198 * Index of currently selected atom
199 */
200 int m_selIdx;
201 /**
202 * Direction in which current atom animation moves
203 */
204 Direction m_dir;
205 /**
206 * Animation speed. Atom will move at 1cell in m_animSpeed msec speed
207 */
208 int m_animSpeed;
209 /**
210 * Timeline object to control atom movement animation
211 */
212 QTimeLine *m_atomTimeLine;
213 /**
214 * True if current level is finished and thus all player input should be disabled
215 */
216 bool m_levelFinished;
217
218 struct AtomMove
219 {
220 int atomIdx; // atom index in m_atoms
221 Direction dir;
222 int numCells;
223 AtomMove( int idx=-1, Direction d=Up, int nc=0 )
224 : atomIdx(idx), dir(d), numCells(nc) { }
225 };
226 QStack<AtomMove> m_undoStack;
227 QStack<AtomMove> m_redoStack;
228
229 MoleculePreviewItem *m_previewItem;
230};
231
232#endif
233