]> Shamusworld >> Repos - warehouse-man-deluxe/blob - src/gameboard.cpp
Added level editor.
[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
19
20 GameBoard::GameBoard(int boardNumber)
21 {
22         // Sanity check
23         if (boardNumber > NUMBER_OF_BOARDS)
24                 boardNumber = NUMBER_OF_BOARDS;
25
26         // boardNumber is 1-based
27         Board * boardToUse = (Board *)boards[boardNumber - 1];
28
29         width = boardToUse->width;
30         height = boardToUse->height;
31         boardLength = width * height;
32         board = new char[boardLength];
33         initialBoard = new char[boardLength];
34         name = (const char *)&(boardToUse->state[boardLength]);
35
36         for(int i=0; i<boardLength; i++)
37         {
38                 char c = boardToUse->state[i];
39
40                 if (c == '@')
41                         initialBoard[i] = GTWall;
42                 else if (c == ' ')
43                         initialBoard[i] = GTSpace;
44                 else if (c == 'X')
45                         initialBoard[i] = GTBox;
46                 else if (c == '.')
47                         initialBoard[i] = GTBoxSpot;
48                 else if (c == '+')
49                         initialBoard[i] = GTBox | GTBoxSpot;
50                 else if (c == 'o' || c == '*')
51                 {
52                         initialBoard[i] = (c == '*' ? GTBoxSpot : GTSpace);
53                         initialX = i % width, initialY = i / width;
54                 }
55                 else
56                         initialBoard[i] = GTNull;
57         }
58
59         ResetGame();
60 }
61
62
63 GameBoard::~GameBoard()
64 {
65         if (board)
66                 delete[] board;
67
68         if (initialBoard)
69                 delete[] initialBoard;
70 }
71
72
73 bool GameBoard::GameHasBeenWon(void)
74 {
75         // Check to see if all boxes are on their spots
76         for(int i=0; i<boardLength; i++)
77         {
78                 char cell = board[i] & ~GTBoxSpot;
79
80                 if ((cell == GTBox) && !(board[i] & GTBoxSpot))
81                         return false;
82         }
83
84         return true;
85 }
86
87
88 void GameBoard::ResetGame(void)
89 {
90         memcpy(board, initialBoard, boardLength);
91         playerX = initialX, playerY = initialY;
92         numMoves = 0;
93 }
94
95
96 int GameBoard::MovePlayerN(void)
97 {
98         // Sanity check (player trying to move into wall)
99         if (playerY == 1)
100                 return PMInvalid;
101
102         char cell1 = board[playerX + ((playerY - 1) * width)] & ~GTBoxSpot;
103         char cell2 = board[playerX + ((playerY - 2) * width)] & ~GTBoxSpot;
104
105         return Move(0, -1, cell1, cell2);
106 }
107
108
109 int GameBoard::MovePlayerS(void)
110 {
111         // Sanity check (player trying to move into wall)
112         if (playerY == (height - 2))
113                 return PMInvalid;
114
115         char cell1 = board[playerX + ((playerY + 1) * width)] & ~GTBoxSpot;
116         char cell2 = board[playerX + ((playerY + 2) * width)] & ~GTBoxSpot;
117
118         return Move(0, +1, cell1, cell2);
119 }
120
121
122 int GameBoard::MovePlayerE(void)
123 {
124         // Sanity check (player trying to move into wall)
125         if (playerX == (width - 2))
126                 return PMInvalid;
127
128         char cell1 = board[(playerX + 1) + (playerY * width)] & ~GTBoxSpot;
129         char cell2 = board[(playerX + 2) + (playerY * width)] & ~GTBoxSpot;
130
131         return Move(+1, 0, cell1, cell2);
132 }
133
134
135 int GameBoard::MovePlayerW(void)
136 {
137         // Sanity check (player trying to move into wall)
138         if (playerX == 1)
139                 return PMInvalid;
140
141         char cell1 = board[(playerX - 1) + (playerY * width)] & ~GTBoxSpot;
142         char cell2 = board[(playerX - 2) + (playerY * width)] & ~GTBoxSpot;
143
144         return Move(-1, 0, cell1, cell2);
145 }
146
147
148 int GameBoard::Move(int dx, int dy, char cell1, char cell2)
149 {
150         // Player is moving into an unoccupied space...
151         if (cell1 == GTSpace)
152         {
153                 playerX += dx, playerY += dy;
154                 undo[numMoves].dx = dx, undo[numMoves].dy = dy, undo[numMoves].type = PMWalk;
155                 numMoves++;
156                 return PMWalk;
157         }
158         // Player is pushing a box into an unoccupied space...
159         else if ((cell1 == GTBox) && (cell2 == GTSpace))
160         {
161                 playerX += dx, playerY += dy;
162                 board[playerX + (playerY * width)] &= GTBoxSpot;
163                 playerX += dx, playerY += dy;
164                 board[playerX + (playerY * width)] |= GTBox;
165                 playerX -= dx, playerY -= dy;
166                 undo[numMoves].dx = dx, undo[numMoves].dy = dy, undo[numMoves].type = PMPush;
167                 numMoves++;
168                 return PMPush;
169         }
170
171         // All other combinations are no good
172         return PMInvalid;
173 }
174
175
176 bool GameBoard::IsBoxNOfPlayer(void)
177 {
178         if ((board[playerX + ((playerY - 1) * width)] & ~GTBoxSpot) == GTBox)
179                 return true;
180
181         return false;
182 }
183
184
185 bool GameBoard::IsBoxSOfPlayer(void)
186 {
187         if ((board[playerX + ((playerY + 1) * width)] & ~GTBoxSpot) == GTBox)
188                 return true;
189
190         return false;
191 }
192
193
194 bool GameBoard::IsBoxEOfPlayer(void)
195 {
196         if ((board[(playerX + 1) + (playerY * width)] & ~GTBoxSpot) == GTBox)
197                 return true;
198
199         return false;
200 }
201
202
203 bool GameBoard::IsBoxWOfPlayer(void)
204 {
205         if ((board[(playerX - 1) + (playerY * width)] & ~GTBoxSpot) == GTBox)
206                 return true;
207
208         return false;
209 }
210
211
212 bool GameBoard::UndoLastMove(int & dx, int & dy, int & type)
213 {
214         if (numMoves == 0)
215                 return false;
216
217         numMoves--;
218         dx = undo[numMoves].dx;
219         dy = undo[numMoves].dy;
220         type = undo[numMoves].type;
221
222         // Undo the box's move (if any)
223         if (type == PMPush)
224         {
225                 int boxPosition = (playerX + dx) + ((playerY + dy) * width);
226                 int newBoxPosition = playerX + (playerY * width);
227
228                 board[boxPosition] &= GTBoxSpot;
229 //              board[newBoxPosition] &= GTBoxSpot;     // This is extraneous
230                 board[newBoxPosition] |= GTBox;
231         }
232
233         // Undo the player's move
234         playerX += -dx;
235         playerY += -dy;
236
237         return true;
238 }
239