1
2 /**
3 *
4 * @file game.cpp
5 *
6 * Part of the OpenJazz project
7 *
8 * @par History:
9 * - 23rd August 2005: Created level.c and menu.c
10 * - 3rd of February 2009: Renamed level.c to level.cpp and menu.c to menu.cpp
11 * - 9th March 2009: Created game.cpp from parts of menu.cpp and level.cpp
12 * - 3rd June 2009: Created network.cpp from parts of game.cpp
13 * - 18th July 2009: Created servergame.cpp from parts of game.cpp
14 * - 18th July 2009: Created clientgame.cpp from parts of game.cpp
15 * - 3rd October 2010: Created localgame.cpp from parts of game.cpp
16 *
17 * @par Licence:
18 * Copyright (c) 2005-2017 Alister Thomson
19 *
20 * OpenJazz is distributed under the terms of
21 * the GNU General Public License, version 2.0
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 *
27 */
28
29
30 #include "game.h"
31 #include "gamemode.h"
32
33 #include "io/gfx/video.h"
34 #include "io/sound.h"
35 #include "jj1bonuslevel/jj1bonuslevel.h"
36 #include "jj1level/jj1level.h"
37 #include "jj1planet/jj1planet.h"
38 #include "jj2level/jj2level.h"
39 #include "player/player.h"
40 #include "util.h"
41
42 #include <string.h>
43
44
45 /**
46 * Create base game
47 */
Game()48 Game::Game () {
49
50 levelFile = NULL;
51 levelType = LT_JJ1;
52
53 players = NULL;
54 baseLevel = NULL;
55
56 return;
57
58 }
59
60
61 /**
62 * Destroy game
63 */
~Game()64 Game::~Game () {
65
66 if (levelFile) delete[] levelFile;
67
68 if (players) delete[] players;
69 localPlayer = NULL;
70
71 return;
72
73 }
74
75
76 /**
77 * Check the if a file name corresponds to a type
78 *
79 * @param fileName The name of the file
80 * @param type The type identifier in lower case characters
81 * @param typeLength The length of the type identifier string
82 *
83 * @return Whether or not the file name corresponds to the type
84 */
isFileType(const char * fileName,const char * type,int typeLength)85 bool Game::isFileType (const char *fileName, const char *type, int typeLength) {
86
87 int i;
88
89 for (i = 0; i < typeLength; i++) {
90
91 if ((fileName[i] != type[i]) && (fileName[i] != type[i] - 32)) return false;
92
93 }
94
95 return true;
96 }
97
98
99 /**
100 * Create a new game mode
101 *
102 * @param modeType The mode to create
103 *
104 * @return The new game mode (NULL on failure)
105 */
createMode(GameModeType modeType)106 GameMode* Game::createMode (GameModeType modeType) {
107
108 switch (modeType) {
109
110 case M_SINGLE:
111
112 return new SingleGameMode();
113
114 case M_COOP:
115
116 return new CoopGameMode();
117
118 case M_BATTLE:
119
120 return new BattleGameMode();
121
122 case M_TEAMBATTLE:
123
124 return new TeamBattleGameMode();
125
126 case M_RACE:
127
128 return new RaceGameMode();
129
130 }
131
132 return NULL;
133
134 }
135
136
137 /**
138 * Get the game's mode
139 *
140 * @return The game's mode
141 */
getMode()142 GameMode* Game::getMode () {
143
144 return mode;
145
146 }
147
148
149 /**
150 * Get the game's difficulty
151 *
152 * @return The game's difficulty
153 */
getDifficulty()154 int Game::getDifficulty () {
155
156 return difficulty;
157
158 }
159
160
161 /**
162 * Set the game's difficulty
163 */
setDifficulty(int diff)164 void Game::setDifficulty (int diff) {
165
166 difficulty = diff;
167
168 return;
169
170 }
171
172
173 /**
174 * Play a level.
175 *
176 * @return Error code
177 */
playLevel(char * fileName,bool intro,bool checkpoint)178 int Game::playLevel (char* fileName, bool intro, bool checkpoint) {
179
180 bool multiplayer;
181 int ret;
182
183 multiplayer = (mode->getMode() != M_SINGLE);
184
185 if (isFileType(fileName, "macro", 5)) {
186
187 // Load and play the level
188
189 try {
190
191 baseLevel = level = new JJ1DemoLevel(this, fileName);
192
193 } catch (int e) {
194
195 return e;
196
197 }
198
199 ret = level->play();
200
201 delete level;
202 baseLevel = level = NULL;
203
204 } else if (levelType == LT_JJ1BONUS) {
205
206 JJ1BonusLevel *bonus;
207
208 try {
209
210 baseLevel = bonus = new JJ1BonusLevel(this, fileName, multiplayer);
211
212 } catch (int e) {
213
214 return e;
215
216 }
217
218 ret = bonus->play();
219
220 delete bonus;
221 baseLevel = NULL;
222
223 } else if (levelType == LT_JJ2) {
224
225 try {
226
227 baseLevel = jj2Level = new JJ2Level(this, fileName, checkpoint, multiplayer);
228
229 } catch (int e) {
230
231 return e;
232
233 }
234
235 ret = jj2Level->play();
236
237 delete jj2Level;
238 baseLevel = jj2Level = NULL;
239
240 } else {
241
242 try {
243
244 baseLevel = level = new JJ1Level(this, fileName, checkpoint, multiplayer);
245
246 } catch (int e) {
247
248 return e;
249
250 }
251
252 if (intro) {
253
254 JJ1Planet *planet;
255 char *planetFileName = NULL;
256
257 planetFileName = createFileName("PLANET", level->getWorld());
258
259 try {
260
261 planet = new JJ1Planet(planetFileName, planetId);
262
263 } catch (int e) {
264
265 planet = NULL;
266
267 }
268
269 delete[] planetFileName;
270
271 if (planet) {
272
273 if (planet->play() == E_QUIT) {
274
275 delete planet;
276 delete level;
277
278 return E_QUIT;
279
280 }
281
282 planetId = planet->getId();
283
284 delete planet;
285
286 }
287
288 }
289
290 ret = level->play();
291
292 delete level;
293 baseLevel = level = NULL;
294
295 }
296
297 return ret;
298
299 }
300
301
302 /**
303 * Determine the type of the specified level file.
304 *
305 * @return Level type
306 */
getLevelType(const char * fileName)307 LevelType Game::getLevelType (const char* fileName) {
308
309 int length;
310
311 length = strlen(fileName);
312
313 if ((length > 4) && isFileType(fileName + length - 4, ".j2l", 4)) return LT_JJ2;
314 if (isFileType(fileName, "bonusmap", 8)) return LT_JJ1BONUS;
315 return LT_JJ1;
316
317 }
318
319
320 /**
321 * Play a level.
322 *
323 * @return Error code
324 */
playLevel(char * fileName)325 int Game::playLevel (char* fileName) {
326
327 levelType = getLevelType(fileName);
328
329 return playLevel(fileName, false, false);
330
331 }
332
333
334 /**
335 * Play the game
336 *
337 * @return Error code
338 */
play()339 int Game::play () {
340
341 bool multiplayer;
342 bool checkpoint;
343 int ret;
344
345 multiplayer = (mode->getMode() != M_SINGLE);
346 checkpoint = false;
347 planetId = -1;
348
349 // Play the level(s)
350 while (true) {
351
352 if (!levelFile) return E_NONE;
353
354 sendTime = checkTime = 0;
355
356 // Load and play the level
357
358 ret = playLevel(levelFile, !multiplayer, checkpoint);
359
360 if (ret <= 0) return ret;
361
362 if (levelFile && isFileType(levelFile, "bonusmap", 8)) {
363
364 if (ret == WON) {
365
366 char *fileName;
367
368 // Go to next level
369 fileName = createFileName("BONUSMAP", (levelFile[10] * 10) + levelFile[11] - 527);
370 setLevel(fileName);
371 delete[] fileName;
372
373 }
374
375 } else {
376
377 if (ret == WON) {
378
379 // Won the level
380
381 // Do not use old level's checkpoint coordinates
382 checkpoint = false;
383
384 } else {
385
386 // Lost the level
387
388 if (!localPlayer->getLives()) return E_NONE;
389
390 // Use checkpoint coordinates
391 checkpoint = true;
392
393 }
394
395 }
396
397 }
398
399 return E_NONE;
400
401 }
402
403
404 /**
405 * Move the viewport towards the exit sign
406 *
407 * @param change Distance to move
408 */
view(int change)409 void Game::view (int change) {
410
411 if (TTOF(checkX) > viewX + (canvasW << 9) + change) viewX += change;
412 else if (TTOF(checkX) < viewX + (canvasW << 9) - change) viewX -= change;
413
414 if (TTOF(checkY) > viewY + (canvasH << 9) + change) viewY += change;
415 else if (TTOF(checkY) < viewY + (canvasH << 9) - change) viewY -= change;
416
417 return;
418
419 }
420
421
422 /**
423 * Make a player restart the level from the beginning/last checkpoint
424 *
425 * @param player Player to reset
426 */
resetPlayer(Player * player)427 void Game::resetPlayer (Player *player) {
428
429 player->reset(checkX, checkY);
430
431 return;
432
433 }
434
435
436 /**
437 * Create a level player
438 *
439 * @param player Player for which to create the level player
440 */
addLevelPlayer(Player * player)441 void Game::addLevelPlayer (Player *player) {
442
443 int count;
444
445 if (level) {
446
447 Anim* pAnims[JJ1PANIMS];
448
449 for (count = 0; count < JJ1PANIMS; count++) pAnims[count] = level->getPlayerAnim(count);
450
451 player->createLevelPlayer(levelType, pAnims, NULL, checkX, checkY);
452
453 } else if (jj2Level) {
454
455 Anim* pAnims[JJ2PANIMS];
456 Anim* pFlippedAnims[JJ2PANIMS];
457
458 for (count = 0; count < JJ2PANIMS; count++) {
459
460 pAnims[count] = jj2Level->getPlayerAnim(0, count, false);
461 pFlippedAnims[count] = jj2Level->getPlayerAnim(0, count, true);
462
463 }
464
465 player->createLevelPlayer(levelType, pAnims, pFlippedAnims, checkX, checkY);
466
467 }
468
469 return;
470
471 }
472
473