8ec06d401ebeabde35a79c390f24d08acb118a67
[evilplumber] / src / game.h
1 /* Evil Plumber is a small puzzle game.
2    Copyright (C) 2010 Marja Hassinen
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #ifndef GAME__H
19 #define GAME__H
20
21 #include <QObject>
22 #include <QHash>
23 #include <QTimer>
24 #include <QStringList>
25
26 class QTableWidget;
27 class QTableWidgetItem;
28 class QLabel;
29 class QWidget;
30 class QPushButton;
31 class QListWidget;
32
33 enum PieceType
34 {
35     PieceNone = 0,
36     PieceStraight,
37     PieceCorner,
38     PieceCross,
39     PieceCorners,
40     PieceStart,
41     PieceEnd,
42     PieceBlock,
43     PiecesEnd
44 };
45
46 enum Direction
47 {
48     DirNone = 0,
49     DirLeft,
50     DirUp,
51     DirRight,
52     DirDown,
53     DirDone,
54     DirFailed,
55     DirPassed
56 };
57
58 typedef struct Piece
59 {
60     PieceType type;
61     int rotation;
62     bool userCanAdd;
63     int uiRow;
64     int uiColumn;
65     Direction flows[4];
66 } Piece;
67
68 static const Piece ppieces[] = {
69     {PieceNone, 0, false, 0, 0,              // 0 
70      {DirNone, DirNone, DirNone, DirNone}},
71     {PieceStraight, 0, true, 0, 0,           // 1
72      {DirUp, DirDown, DirNone, DirNone}},
73     {PieceStraight, 90, true, 0, 1,          // 2
74      {DirLeft, DirRight, DirNone, DirNone}},
75     {PieceCorner, 270, true, 1, 0,           // 3
76      {DirDown, DirRight, DirNone, DirNone}},
77     {PieceCorner, 0, true, 1, 1,             // 4
78      {DirLeft, DirDown, DirNone, DirNone}},
79     {PieceCorner, 180, true, 2, 0,           // 5
80      {DirUp, DirRight, DirNone, DirNone}},
81     {PieceCorner, 90, true, 2, 1,            // 6
82      {DirLeft, DirUp, DirNone, DirNone}},
83     {PieceCross, 0, true, 3, 0,              // 7
84      {DirLeft, DirRight, DirUp, DirDown}},
85     {PieceCorners, 0, true, 4, 0,            // 8
86      {DirLeft, DirDown, DirRight, DirUp}},
87     {PieceCorners, 90, true, 4, 1,          // 9
88      {DirRight, DirDown, DirLeft, DirUp}},
89     {PieceStart, 0, false, 0, 0,             // 10
90      {DirLeft, DirNone, DirNone, DirNone}},
91     {PieceStart, 90, false, 0, 0,            // 11
92      {DirUp, DirNone, DirNone, DirNone}},
93     {PieceStart, 180, false, 0, 0,           // 12
94      {DirRight, DirNone, DirNone, DirNone}},
95     {PieceStart, 270, false, 0, 0,           // 13
96      {DirDown, DirNone, DirNone, DirNone}},
97     {PieceEnd, 0, false, 0, 0,               // 14
98      {DirLeft, DirDone, DirNone, DirNone}},
99     {PieceEnd, 90, false, 0, 0,              // 15
100      {DirUp, DirDone, DirNone, DirNone}},
101     {PieceEnd, 180, false, 0, 0,             // 16
102      {DirRight, DirDone, DirNone, DirNone}},
103     {PieceEnd, 270, false, 0, 0,             // 17
104      {DirDown, DirDone, DirNone, DirNone}},
105     {PieceBlock, 0, false, 0, 0,             // 18
106      {DirNone, DirNone, DirNone, DirNone}},
107     {PiecesEnd, 0, false, 0, 0,              // 19
108      {DirNone, DirNone, DirNone, DirNone}}};
109
110 const int noPieces = 20;
111
112 typedef struct _PlacedPiece
113 {
114     const Piece* piece;
115     bool fixed;
116     bool flow[2]; // which directions the liquid has already flown
117 } PlacedPiece;
118
119 typedef struct _PrePlacedPiece
120 {
121     const Piece* piece;
122     int row;
123     int col;
124 } PrePlacedPiece;
125
126 typedef struct _AvailablePiece
127 {
128     const Piece* piece;
129     int count;
130 } AvailablePiece;
131
132 class GameField : public QObject
133 {
134     Q_OBJECT
135 public:
136     GameField(QTableWidget* ui);
137     void initGame(int rows_, int cols_, int count, PrePlacedPiece* prePlaced);
138
139     bool setPiece(int row, int col, const Piece* piece, bool fixed = false);
140     const Piece* pieceAt(int row, int col);
141     bool isPrePlaced(int row, int col);
142     void indicateFlow(int row, int col, Direction dir);
143
144 signals:
145     void cellClicked(int, int);
146
147 private:
148     int toIndex(int row, int col);
149
150     QTableWidget* fieldUi;
151     PlacedPiece* field;
152     int rows;
153     int cols;
154 };
155
156 class AvailablePieces : public QObject
157 {
158     Q_OBJECT
159 public:
160     AvailablePieces(QTableWidget* pieceTable);
161     void initGame(int count, AvailablePiece* pieces);
162
163 signals:
164     void validPieceSelected(const Piece* piece);
165     void invalidPieceSelected();
166
167 public slots:
168     void onPieceUsed(const Piece* piece);
169
170 private slots:
171     void onItemClicked(QTableWidgetItem* item);
172
173 private:
174     static int pieceToId(const Piece* piece);
175     static const Piece* idToPiece(int id);
176
177     QTableWidget* pieceUi;
178     QHash<const Piece*, int> pieceCounts;
179 };
180
181 class GameController : public QObject
182 {
183     Q_OBJECT
184 public:
185     GameController(AvailablePieces* pieceUi, GameField* fieldUi, 
186                    QLabel* timeLabel, QPushButton* doneButton);
187     void startLevel(QString fileName);
188
189 signals:
190     void pieceUsed(const Piece* piece);
191     void levelPassed(int score);
192     void levelFailed();
193
194 private slots:
195     void onCellClicked(int row, int column);
196     void onValidPieceSelected(const Piece* piece);
197     void onInvalidPieceSelected();
198     void onTimeout();
199     void levelEnds();
200     void computeFlow();
201
202 private:
203     AvailablePieces* pieceUi; // Not owned
204     GameField* fieldUi; // Not owned
205     QLabel* timeLabel; // Not owned
206     QPushButton* doneButton; // Not owned
207
208     // Data about the current situation in the game
209     const Piece* currentPiece;
210     int rows, cols;
211     QTimer timer;
212     QTimer flowTimer;
213     int timeLeft;
214     bool levelRunning;
215     // how many times does the liquid need to flow through the pre-placed pieces
216     int neededFlow;
217     int startRow;
218     int startCol;
219     Direction startDir;
220     int flowRow;
221     int flowCol;
222     Direction flowDir;
223     int flowPreplaced;
224     int flowScore;
225 };
226
227 class LevelSwitcher : public QObject
228 {
229     Q_OBJECT
230 public:
231     LevelSwitcher(GameController* gameController,
232                   QWidget* levelWidget, QListWidget* levelList, QPushButton* levelStartButton,
233                   QWidget* startWidget, QLabel* startTitle, QLabel* startLabel, QPushButton* startButton,
234                   QLabel* levelLabel, QLabel* scoreLabel,
235                   QStringList levels);
236
237 private slots:
238     void onLevelCollectionChosen();
239     void onStartClicked();
240     void onLevelPassed(int score);
241     void onLevelFailed();
242     void chooseLevelCollection();
243
244 private:
245     void initiateLevel();
246     void readSavedGames();
247     void writeSavedGames();
248     void readLevelCollections(QStringList collections);
249
250     GameController* gameController; // Not owned
251     QWidget* levelWidget; // Not owned
252     QListWidget* levelList; // Not owned
253     QPushButton* levelStartButton; // Not owned
254     QWidget* startWidget; // Not owned
255     QLabel* startTitle; // Not owned
256     QLabel* startLabel; // Not owned
257     QPushButton* startButton; // Not owned
258     QLabel* levelLabel; // Not owned
259     QLabel* scoreLabel; // Not owned
260
261     QString curColl;
262     QStringList levels;
263     int level;
264     int totalScore;
265     QHash<QString, int> savedGames; // level collection -> next level ix
266     QHash<QString, QStringList> levelCollections; // level collection -> level names
267 };
268
269 #endif