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