]> Shamusworld >> Repos - warehouse-man-deluxe/blob - src/gameboard.cpp
Added/fixed editor, added play level functionality.
[warehouse-man-deluxe] / src / gameboard.cpp
1 //
2 // gameboard.cpp: Game board class implementation
3 //
4 // by James Hammons
5 // © 2014 Underground Software
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 //
9 // Who  When        What
10 // ---  ----------  ------------------------------------------------------------
11 // JLH  03/01/2014  Created this file
12 //
13
14 #include "gameboard.h"
15 #include <string.h>
16 //#include <stdio.h>    // for printf()
17 #include "boards.h"
18 #include "editorwidget.h"       // for Level
19
20
21 GameBoard::GameBoard(int boardNumber)
22 {
23         // Sanity check
24         if (boardNumber > NUMBER_OF_BOARDS)
25                 boardNumber = NUMBER_OF_BOARDS;
26
27         // boardNumber is 1-based
28         Board * boardToUse = (Board *)boards[boardNumber - 1];
29
30         width = boardToUse->width;
31         height = boardToUse->height;
32         boardLength = width * height;
33         board = new char[boardLength];
34         initialBoard = new char[boardLength];
35         name = (const char *)&(boardToUse->state[boardLength]);
36
37         for(int i=0; i<boardLength; i++)
38         {
39                 char c = boardToUse->state[i];
40
41                 if (c == '@')
42                         initialBoard[i] = GTWall;
43                 else if (c == ' ')
44                         initialBoard[i] = GTSpace;
45                 else if (c == 'X')
46                         initialBoard[i] = GTBox;
47                 else if (c == '.')
48                         initialBoard[i] = GTBoxSpot;
49                 else if (c == '+')
50                         initialBoard[i] = GTBox | GTBoxSpot;
51                 else if (c == 'o' || c == '*')
52                 {
53                         initialBoard[i] = (c == '*' ? GTBoxSpot : GTSpace);
54                         initialX = i % width, initialY = i / width;
55                 }
56                 else
57                         initialBoard[i] = GTNull;
58         }
59
60         ResetGame();
61 }
62
63
64 GameBoard::GameBoard(Level * level)
65 {
66         Point size, corner;
67
68         EditorWidget::GetSizeAndCorner(level, size, corner);
69
70         width = size.x;
71         height = size.y;
72         boardLength = width * height;
73         board = new char[boardLength];
74         initialBoard = new char[boardLength];
75         name = level->name;
76
77         int current = 0;
78
79         for(int y=0; y<size.y; y++)
80         {
81                 for(int x=0; x<size.x; x++)
82                 {
83                         uint8_t tile = level->board[corner.x + x][corner.y + y];
84
85                         if (tile & GTMan)
86                         {
87                                 initialX = x;
88                                 initialY = y;
89                                 tile &= ~GTMan;
90                         }
91
92                         initialBoard[current++] = tile;
93                 }
94         }
95
96         ResetGame();
97 }
98
99
100 GameBoard::~GameBoard()
101 {
102         if (board)
103                 delete[] board;
104
105         if (initialBoard)
106                 delete[] initialBoard;
107 }
108
109
110 bool GameBoard::GameHasBeenWon(void)
111 {
112         // Check to see if all boxes are on their spots
113         for(int i=0; i<boardLength; i++)
114         {
115                 char cell = board[i] & ~GTBoxSpot;
116
117                 if ((cell == GTBox) && !(board[i] & GTBoxSpot))
118                         return false;
119         }
120
121         return true;
122 }
123
124
125 void GameBoard::ResetGame(void)
126 {
127         memcpy(board, initialBoard, boardLength);
128         playerX = initialX, playerY = initialY;
129         numMoves = 0;
130 }
131
132
133 int GameBoard::MovePlayerN(void)
134 {
135         // Sanity check (player trying to move into wall)
136         if (playerY == 1)
137                 return PMInvalid;
138
139         char cell1 = board[playerX + ((playerY - 1) * width)] & ~GTBoxSpot;
140         char cell2 = board[playerX + ((playerY - 2) * width)] & ~GTBoxSpot;
141
142         return Move(0, -1, cell1, cell2);
143 }
144
145
146 int GameBoard::MovePlayerS(void)
147 {
148         // Sanity check (player trying to move into wall)
149         if (playerY == (height - 2))
150                 return PMInvalid;
151
152         char cell1 = board[playerX + ((playerY + 1) * width)] & ~GTBoxSpot;
153         char cell2 = board[playerX + ((playerY + 2) * width)] & ~GTBoxSpot;
154
155         return Move(0, +1, cell1, cell2);
156 }
157
158
159 int GameBoard::MovePlayerE(void)
160 {
161         // Sanity check (player trying to move into wall)
162         if (playerX == (width - 2))
163                 return PMInvalid;
164
165         char cell1 = board[(playerX + 1) + (playerY * width)] & ~GTBoxSpot;
166         char cell2 = board[(playerX + 2) + (playerY * width)] & ~GTBoxSpot;
167
168         return Move(+1, 0, cell1, cell2);
169 }
170
171
172 int GameBoard::MovePlayerW(void)
173 {
174         // Sanity check (player trying to move into wall)
175         if (playerX == 1)
176                 return PMInvalid;
177
178         char cell1 = board[(playerX - 1) + (playerY * width)] & ~GTBoxSpot;
179         char cell2 = board[(playerX - 2) + (playerY * width)] & ~GTBoxSpot;
180
181         return Move(-1, 0, cell1, cell2);
182 }
183
184
185 int GameBoard::Move(int dx, int dy, char cell1, char cell2)
186 {
187         // Player is moving into an unoccupied space...
188         if (cell1 == GTSpace)
189         {
190                 playerX += dx, playerY += dy;
191                 undo[numMoves].dx = dx, undo[numMoves].dy = dy, undo[numMoves].type = PMWalk;
192                 numMoves++;
193                 return PMWalk;
194         }
195         // Player is pushing a box into an unoccupied space...
196         else if ((cell1 == GTBox) && (cell2 == GTSpace))
197         {
198                 playerX += dx, playerY += dy;
199                 board[playerX + (playerY * width)] &= GTBoxSpot;
200                 playerX += dx, playerY += dy;
201                 board[playerX + (playerY * width)] |= GTBox;
202                 playerX -= dx, playerY -= dy;
203                 undo[numMoves].dx = dx, undo[numMoves].dy = dy, undo[numMoves].type = PMPush;
204                 numMoves++;
205                 return PMPush;
206         }
207
208         // All other combinations are no good
209         return PMInvalid;
210 }
211
212
213 bool GameBoard::IsBoxNOfPlayer(void)
214 {
215         if ((board[playerX + ((playerY - 1) * width)] & ~GTBoxSpot) == GTBox)
216                 return true;
217
218         return false;
219 }
220
221
222 bool GameBoard::IsBoxSOfPlayer(void)
223 {
224         if ((board[playerX + ((playerY + 1) * width)] & ~GTBoxSpot) == GTBox)
225                 return true;
226
227         return false;
228 }
229
230
231 bool GameBoard::IsBoxEOfPlayer(void)
232 {
233         if ((board[(playerX + 1) + (playerY * width)] & ~GTBoxSpot) == GTBox)
234                 return true;
235
236         return false;
237 }
238
239
240 bool GameBoard::IsBoxWOfPlayer(void)
241 {
242         if ((board[(playerX - 1) + (playerY * width)] & ~GTBoxSpot) == GTBox)
243                 return true;
244
245         return false;
246 }
247
248
249 bool GameBoard::UndoLastMove(int & dx, int & dy, int & type)
250 {
251         if (numMoves == 0)
252                 return false;
253
254         numMoves--;
255         dx = undo[numMoves].dx;
256         dy = undo[numMoves].dy;
257         type = undo[numMoves].type;
258
259         // Undo the box's move (if any)
260         if (type == PMPush)
261         {
262                 int boxPosition = (playerX + dx) + ((playerY + dy) * width);
263                 int newBoxPosition = playerX + (playerY * width);
264
265                 board[boxPosition] &= GTBoxSpot;
266 //              board[newBoxPosition] &= GTBoxSpot;     // This is extraneous
267                 board[newBoxPosition] |= GTBox;
268         }
269
270         // Undo the player's move
271         playerX += -dx;
272         playerY += -dy;
273
274         return true;
275 }
276