cf83eb2ffd3870da04668aa9a58bcbbfbc5c4fb8
[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 QFrame;
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 };
56
57 typedef struct Piece
58 {
59     PieceType type;
60     int rotation;
61     bool userCanAdd;
62     int uiRow;
63     int uiColumn;
64     Direction flows[4];
65 } Piece;
66
67 static const Piece ppieces[] = {
68     {PieceNone, 0, false, 0, 0,              // 0 
69      {DirNone, DirNone, DirNone, DirNone}},
70     {PieceStraight, 0, true, 0, 0,           // 1
71      {DirUp, DirDown, DirNone, DirNone}},
72     {PieceStraight, 90, true, 0, 1,          // 2
73      {DirLeft, DirRight, DirNone, DirNone}},
74     {PieceCorner, 270, true, 1, 0,           // 3
75      {DirDown, DirRight, DirNone, DirNone}},
76     {PieceCorner, 0, true, 1, 1,             // 4
77      {DirLeft, DirDown, DirNone, DirNone}},
78     {PieceCorner, 180, true, 2, 0,           // 5
79      {DirUp, DirRight, DirNone, DirNone}},
80     {PieceCorner, 90, true, 2, 1,            // 6
81      {DirLeft, DirUp, DirNone, DirNone}},
82     {PieceCross, 0, true, 3, 0,              // 7
83      {DirLeft, DirRight, DirUp, DirDown}},
84     {PieceCorners, 0, true, 4, 0,            // 8
85      {DirLeft, DirUp, DirRight, DirDown}},
86     {PieceCorners, 90, true, 4, 1,          // 9
87      {DirUp, DirRight, DirLeft, DirDown}},
88     {PieceStart, 0, false, 0, 0,             // 10
89      {DirLeft, DirNone, DirNone, DirNone}},
90     {PieceStart, 90, false, 0, 0,            // 11
91      {DirUp, DirNone, DirNone, DirNone}},
92     {PieceStart, 180, false, 0, 0,           // 12
93      {DirRight, DirNone, DirNone, DirNone}},
94     {PieceStart, 270, false, 0, 0,           // 13
95      {DirDown, DirNone, DirNone, DirNone}},
96     {PieceEnd, 0, false, 0, 0,               // 14
97      {DirLeft, DirDone, DirNone, DirNone}},
98     {PieceEnd, 90, false, 0, 0,              // 15
99      {DirUp, DirDone, DirNone, DirNone}},
100     {PieceEnd, 180, false, 0, 0,             // 16
101      {DirRight, DirDone, DirNone, DirNone}},
102     {PieceEnd, 270, false, 0, 0,             // 17
103      {DirDown, DirDone, DirNone, DirNone}},
104     {PieceBlock, 0, false, 0, 0,             // 18
105      {DirNone, DirNone, DirNone, DirNone}},
106     {PiecesEnd, 0, false, 0, 0,              // 19
107      {DirNone, DirNone, DirNone, DirNone}}};
108
109 const int noPieces = 20;
110
111 typedef struct _PlacedPiece
112 {
113     const Piece* piece;
114     bool fixed;
115     bool flow[2]; // which directions the liquid has already flown
116 } PlacedPiece;
117
118 typedef struct _PrePlacedPiece
119 {
120     const Piece* piece;
121     int row;
122     int col;
123 } PrePlacedPiece;
124
125 typedef struct _AvailablePiece
126 {
127     const Piece* piece;
128     int count;
129 } AvailablePiece;
130
131 class GameField : public QObject
132 {
133     Q_OBJECT
134 public:
135     GameField(QTableWidget* ui);
136     void initGame(int rows_, int cols_, int count, PrePlacedPiece* prePlaced);
137
138     bool setPiece(int row, int col, const Piece* piece, bool fixed = false);
139     const Piece* pieceAt(int row, int col);
140     bool isPrePlaced(int row, int col);
141     void indicateFlow(int row, int col, Direction dir);
142
143 signals:
144     void cellClicked(int, int);
145
146 private:
147     int toIndex(int row, int col);
148
149     QTableWidget* fieldUi;
150     PlacedPiece* field;
151     int rows;
152     int cols;
153 };
154
155 class AvailablePieces : public QObject
156 {
157     Q_OBJECT
158 public:
159     AvailablePieces(QTableWidget* pieceTable);
160     void initGame(int count, AvailablePiece* pieces);
161
162 signals:
163     void validPieceSelected(const Piece* piece);
164     void invalidPieceSelected();
165
166 public slots:
167     void onPieceUsed(const Piece* piece);
168
169 private slots:
170     void onItemClicked(QTableWidgetItem* item);
171
172 private:
173     void initPieceCache();
174     static int pieceToId(const Piece* piece);
175     static const Piece* idToPiece(int id);
176
177     static QHash<QPair<PieceType, int>, const Piece*> pieceCache;
178     QTableWidget* pieceUi;
179     QHash<const Piece*, int> pieceCounts;
180 };
181
182 class GameController : public QObject
183 {
184     Q_OBJECT
185 public:
186     GameController(AvailablePieces* pieceUi, GameField* fieldUi, 
187                    QLabel* timeLabel, QPushButton* doneButton);
188     void startLevel(QString fileName);
189
190 signals:
191     void pieceUsed(const Piece* piece);
192     void levelPassed(int score);
193     void levelFailed();
194
195 private slots:
196     void onCellClicked(int row, int column);
197     void onValidPieceSelected(const Piece* piece);
198     void onInvalidPieceSelected();
199     void onTimeout();
200     void levelEnds();
201     void computeFlow();
202
203 private:
204     AvailablePieces* pieceUi; // Not owned
205     GameField* fieldUi; // Not owned
206     QLabel* timeLabel; // Not owned
207     QPushButton* doneButton; // Not owned
208
209     // Data about the current situation in the game
210     const Piece* currentPiece;
211     int rows, cols;
212     QTimer timer;
213     QTimer flowTimer;
214     int timeLeft;
215     bool levelRunning;
216     // how many times does the liquid need to flow through the pre-placed pieces
217     int neededFlow;
218     int startRow;
219     int startCol;
220     Direction startDir;
221     int flowRow;
222     int flowCol;
223     Direction flowDir;
224     int flowPreplaced;
225     int flowScore;
226 };
227
228 class LevelSwitcher : public QObject
229 {
230     Q_OBJECT
231 public:
232     LevelSwitcher(GameController* gameController, QLabel* levelLabel, 
233                   QFrame* startFrame, QLabel* startTitle, QLabel* startLabel, QPushButton* startButton,
234                   QLabel* scoreLabel,
235                   QStringList levels);
236     void initiateLevel();
237
238 private slots:
239     void onStartClicked();
240     void onLevelPassed(int score);
241     void onLevelFailed();
242
243 private:
244     GameController* gameController; // Not owned
245     QLabel* levelLabel; // Not owned
246     QFrame* startFrame; // Not owned
247     QLabel* startTitle; // Not owned
248     QLabel* startLabel; // Not owned
249     QPushButton* startButton; // Not owned
250     QLabel* scoreLabel; // Not owned
251
252     QStringList levels;
253     int level;
254     int totalScore;
255 };
256
257 #endif