1 #pragma once
2 
3 /** Main game file, mainly contains various setup functions.
4 */
5 
6 namespace Gigalomania {
7 	class Screen;
8 	class Image;
9 	class PanelPage;
10 	class Sample;
11 }
12 
13 using namespace Gigalomania;
14 
15 using std::vector;
16 using std::stringstream;
17 using std::string;
18 
19 class Invention;
20 class Weapon;
21 class Element;
22 class Sector;
23 class GameState;
24 class PlayingGameState;
25 class Player;
26 class Application;
27 class TextEffect;
28 class Map;
29 class Tutorial;
30 
31 #include "common.h"
32 #include "image.h"
33 #include "TinyXML/tinyxml.h"
34 
35 enum GameStateID {
36 	GAMESTATEID_UNDEFINED = -1,
37 	GAMESTATEID_CHOOSEGAMETYPE = 0,
38 	GAMESTATEID_CHOOSEDIFFICULTY,
39 	GAMESTATEID_CHOOSEPLAYER,
40 	GAMESTATEID_CHOOSETUTORIAL,
41 	GAMESTATEID_PLACEMEN,
42 	GAMESTATEID_PLAYING,
43 	GAMESTATEID_ENDISLAND,
44 	GAMESTATEID_GAMECOMPLETE
45 };
46 
47 enum GameResult {
48 	GAMERESULT_UNDEFINED = 0,
49 	GAMERESULT_WON,
50 	GAMERESULT_QUIT,
51 	GAMERESULT_LOST
52 };
53 
54 enum DifficultyLevel {
55 	// don't change the numbers, as will break saved state and saved game compatibility!
56 	DIFFICULTY_EASY = 0,
57 	DIFFICULTY_MEDIUM = 1,
58 	DIFFICULTY_HARD = 2,
59 	DIFFICULTY_ULTRA = 3,
60 	DIFFICULTY_N_LEVELS = 4
61 };
62 
63 enum GameMode {
64 	GAMEMODE_SINGLEPLAYER = 0,
65 	GAMEMODE_MULTIPLAYER_SERVER = 1,
66 	GAMEMODE_MULTIPLAYER_CLIENT = 2
67 };
68 
69 enum GameType {
70 	// don't change the numbers, as will break saved state compatibility!
71 	GAMETYPE_SINGLEISLAND = 0,
72 	GAMETYPE_ALLISLANDS = 1,
73 	GAMETYPE_TUTORIAL = 2
74 };
75 
76 const int default_width_c = 320;
77 const int default_height_c = 240;
78 
79 const int infinity_c = 31;
80 //const int end_epoch_c = 9; // use this to have the last epoch game
81 const int end_epoch_c = -1; // use this to have the last epoch as being 2100AD
82 const int cannon_epoch_c = 5;
83 const int biplane_epoch_c = 6;
84 const int jetplane_epoch_c = 7;
85 const int nuclear_epoch_c = 8;
86 const int spaceship_epoch_c = 9;
87 const int laser_epoch_c = 9;
88 const int n_shields_c = 4;
89 const int n_playershields_c = 16;
90 const int n_flag_frames_c = 4;
91 const int max_defender_frames_c = 11;
92 const int n_attacker_directions_c = 4;
93 const int max_attacker_frames_c = 9;
94 const int n_trees_c = 4;
95 const int n_tree_frames_c = 4;
96 const int n_nuke_frames_c = 2;
97 const int n_saucer_frames_c = 4;
98 const int n_death_flashes_c = 3;
99 const int n_blue_flashes_c = 7;
100 const int n_explosions_c = 59;
101 const int n_coast_c = 8;
102 const int n_map_sq_c = 16;
103 const int max_islands_per_epoch_c = 3;
104 
105 class Game {
106 	float scale_factor_w; // how much the input graphics are scaled
107 	float scale_factor_h;
108 	float scale_width; // the scale of the logical resolution or graphics size wrt the default 320x240 coordinate system
109 	float scale_height;
110 	bool onemousebutton;
111 	bool mobile_ui;
112 	bool using_old_gfx;
113 	bool is_testing;
114 
115 	Application *application;
116 	Screen *screen;
117 	bool paused;
118 	GameState *gamestate;
119 	GameState *dispose_gamestate;
120 	unsigned int lastmousepress_time;
121 
122 	int frame_counter;
123 	int time_rate; // time factor
124 	int real_time;
125 	int real_loop_time;
126 	int game_time;
127 	int loop_time;
128 	float accumulated_time;
129 	int mouseTime;
130 
131 	bool pref_sound_on;
132 	bool pref_music_on;
133 	bool pref_disallow_nukes;
134 
135 	GameMode gameMode;
136 	GameType gameType;
137 	DifficultyLevel difficulty_level;
138 	int human_player;
139 	Tutorial *tutorial;
140 
141 	GameStateID gameStateID;
142 	bool state_changed;
143 	GameResult gameResult;
144 
145 	int start_epoch;
146 	int n_sub_epochs;
147 	int selected_island;
148 	bool completed_island[max_islands_per_epoch_c];
149 	Map *maps[n_epochs_c][max_islands_per_epoch_c];
150 	Map *map;
151 	int n_men_store;
152 	int n_player_suspended;
153 
154 	void calculateScale(const Image *image);
155 	void convertToHiColor(Image *image) const;
156 	void processImage(Image *image, bool old_smooth = true) const;
157 	bool loadAttackersWalkingImages(const string &gfx_dir, int epoch);
158 	bool loadOldImages();
159 	void getDesktopResolution(int *user_width, int *user_height) const;
160 
161 	const char *getFilename(int slot) const;
162 	bool readMapProcessLine(int *epoch, int *index, Map **l_map, char *line, const int MAX_LINE, const char *filename);
163 	bool readMap(const char *filename);
164 	bool loadGameInfo(DifficultyLevel *difficulty, int *player, int *n_men, int suspended[n_players_c], int *epoch, bool completed[max_islands_per_epoch_c], const char *filename) const;
165 	bool loadGame(const char *filename);
166 	GameState *loadStateParseXMLNode(const TiXmlNode *parent);
167 	void copyFile(const char *src, const char *dst) const;
168 
169 	bool testFindSoldiersBuildingNewTower(const Sector *sector, int *total, int *squares) const;
170 
171 	void disposeGameState();
172 
173 	int getMenPerEpoch() const;
174 	void updatedEpoch();
175 	void setEpoch(int epoch);
176 	void cleanupPlayers();
177 public:
178 	Image *background;
179 	Image *player_heads_select[n_players_c];
180 	Image *player_heads_alliance[n_players_c];
181 	Image *grave;
182 	Image *land[MAP_N_COLOURS];
183 	Image *fortress[n_epochs_c];
184 	Image *mine[n_epochs_c];
185 	Image *factory[n_epochs_c];
186 	Image *lab[n_epochs_c];
187 	Image *men[n_epochs_c];
188 	Image *unarmed_man;
189 	Image *flags[n_players_c][n_flag_frames_c];
190 	Image *panel_design;
191 	Image *panel_lab;
192 	Image *panel_factory;
193 	Image *panel_shield;
194 	Image *panel_defence;
195 	Image *panel_attack;
196 	Image *panel_bloody_attack;
197 	Image *panel_twoattack;
198 	Image *panel_build[N_BUILDINGS];
199 	Image *panel_building[N_BUILDINGS];
200 	Image *panel_knowndesigns;
201 	Image *panel_bigdesign;
202 	Image *panel_biglab;
203 	Image *panel_bigfactory;
204 	Image *panel_bigshield;
205 	Image *panel_bigdefence;
206 	Image *panel_bigattack;
207 	Image *panel_bigbuild;
208 	Image *panel_bigknowndesigns;
209 	Image *numbers_blue[10];
210 	Image *numbers_grey[10];
211 	Image *numbers_white[10];
212 	Image *numbers_orange[10];
213 	Image *numbers_yellow[10];
214 	Image *numbers_largegrey[10];
215 	Image *numbers_largeshiny[10];
216 	Image *numbers_small[n_players_c][10];
217 	Image *numbers_half;
218 	Image *letters_large[n_font_chars_c];
219 	Image *letters_small[n_font_chars_c];
220 	Image *mouse_pointers[n_players_c];
221 	Image *playershields[n_playershields_c];
222 	Image *building_health;
223 	Image *dash_grey;
224 	Image *icon_shield;
225 	Image *icon_defence;
226 	Image *icon_weapon;
227 	Image *icon_shields[n_shields_c];
228 	Image *icon_defences[n_epochs_c];
229 	Image *icon_weapons[n_epochs_c];
230 	Image *numbered_defences[n_epochs_c];
231 	Image *numbered_weapons[n_epochs_c];
232 	Image *icon_elements[N_ID];
233 	Image *icon_clocks[13];
234 	Image *icon_infinity;
235 	Image *icon_bc;
236 	Image *icon_ad;
237 	Image *icon_ad_shiny;
238 	Image *icon_towers[n_players_c];
239 	Image *icon_armies[n_players_c];
240 	Image *icon_nuke_hole;
241 	Image *mine_gatherable_small;
242 	Image *mine_gatherable_large;
243 	Image *icon_ergo;
244 	Image *icon_trash;
245 	Image *coast_icons[n_coast_c];
246 	int map_sq_offset, map_sq_coast_offset;
247 	Image *map_sq[MAP_N_COLOURS][n_map_sq_c];
248 	int n_defender_frames[n_epochs_c];
249 	Image *defenders[n_players_c][n_epochs_c][max_defender_frames_c];
250 	Image *nuke_defences[n_players_c];
251 	int n_attacker_frames[n_epochs_c+1][n_attacker_directions_c];
252 	Image *attackers_walking[n_players_c][n_epochs_c+1][n_attacker_directions_c][max_attacker_frames_c]; // epochs 6-9 are special case!
253 	Image *planes[n_players_c][n_epochs_c];
254 	Image *nukes[n_players_c][n_nuke_frames_c];
255 	Image *saucers[n_players_c][n_saucer_frames_c];
256 	Image *attackers_ammo[n_epochs_c][N_ATTACKER_AMMO_DIRS];
257 	Image *icon_openpitmine;
258 	Image *icon_trees[n_trees_c][n_tree_frames_c];
259 	vector<Image *> icon_clutter;
260 	vector<Image *> icon_clutter_nuked;
261 	Image *flashingmapsquare;
262 	Image *mapsquare;
263 	Image *arrow_left;
264 	Image *arrow_right;
265 	Image *death_flashes[n_death_flashes_c];
266 	Image *blue_flashes[n_blue_flashes_c];
267 	Image *explosions[n_explosions_c];
268 	Image *icon_mice[2];
269 	Image *icon_speeds[3];
270 	Image *smoke_image;
271 	Image *background_islands;
272 
273 	// speech
274 	Sample *s_design_is_ready;
275 	Sample *s_ergo;
276 	Sample *s_advanced_tech;
277 	Sample *s_fcompleted;
278 	Sample *s_on_hold;
279 	Sample *s_running_out_of_elements;
280 	Sample *s_tower_critical;
281 	Sample *s_sector_destroyed;
282 	Sample *s_mine_destroyed;
283 	Sample *s_factory_destroyed;
284 	Sample *s_lab_destroyed;
285 	Sample *s_itis_all_over;
286 	Sample *s_conquered;
287 	Sample *s_won;
288 	Sample *s_weve_nuked_them;
289 	Sample *s_weve_been_nuked;
290 	Sample *s_alliance_yes[n_players_c];
291 	Sample *s_alliance_no[n_players_c];
292 	Sample *s_alliance_ask[n_players_c];
293 	Sample *s_quit[n_players_c];
294 	Sample *s_cant_nuke_ally;
295 
296 	// effects
297 	Sample *s_explosion;
298 	Sample *s_scream;
299 	Sample *s_buildingdestroyed;
300 	Sample *s_guiclick;
301 	Sample *s_biplane;
302 	Sample *s_jetplane;
303 	Sample *s_spaceship;
304 
305 	Sample *music;
306 
307 	Invention *invention_shields[n_epochs_c];
308 	Invention *invention_defences[n_epochs_c];
309 	Weapon *invention_weapons[n_epochs_c];
310 	Element *elements[N_ID];
311 	Player *players[n_players_c];
312 
313 	Game();
314 	~Game();
315 
316 	bool loadImages();
317 	bool loadSamples();
318 	bool createMaps();
319 
getScaleWidth()320 	float getScaleWidth() const {
321 		return this->scale_width;
322 	}
getScaleHeight()323 	float getScaleHeight() const {
324 		return this->scale_height;
325 	}
setOneMouseButton(bool onemousebutton)326 	void setOneMouseButton(bool onemousebutton) {
327 		this->onemousebutton = onemousebutton;
328 	}
isOneMouseButton()329 	bool isOneMouseButton() const {
330 		return this->onemousebutton;
331 	}
332 	bool oneMouseButtonMode() const;
setMobileUI(bool mobile_ui)333 	void setMobileUI(bool mobile_ui) {
334 		this->mobile_ui = mobile_ui;
335 	}
isMobileUI()336 	bool isMobileUI() const {
337 		return this->mobile_ui;
338 	}
isUsingOldGfx()339 	bool isUsingOldGfx() const {
340 		return this->using_old_gfx;
341 	}
setTesting(bool is_testing)342 	void setTesting(bool is_testing) {
343 		this->is_testing = is_testing;
344 	}
isTesting()345 	bool isTesting() const {
346 		return this->is_testing;
347 	}
348 
349 	bool createApplication();
getApplication()350 	Application *getApplication() {
351 		return this->application;
352 	}
getApplication()353 	const Application *getApplication() const {
354 		return this->application;
355 	}
356 	bool openScreen(bool fullscreen);
getScreen()357 	Screen *getScreen() {
358 		return this->screen;
359 	}
getScreen()360 	const Screen *getScreen() const {
361 		return this->screen;
362 	}
363 	bool isPaused() const;
364 
cycleTimeRate()365 	void cycleTimeRate() {
366 		time_rate++;
367 		if( time_rate > 3 )
368 			time_rate = 1;
369 	}
increaseTimeRate()370 	void increaseTimeRate() {
371 		if( time_rate > 1 )
372 			time_rate--;
373 	}
decreaseTimeRate()374 	void decreaseTimeRate() {
375 		if( time_rate < 3 )
376 			time_rate++;
377 	}
378 	void setTimeRate(int time_rate);
getTimeRate()379 	int getTimeRate() const {
380 		return this->time_rate;
381 	}
382 	void setRealTime(int real_time);
383 	int getRealTime() const;
384 	int getRealLoopTime() const;
385 	void setGameTime(int game_time);
386 	int getGameTime() const;
387 	int getLoopTime() const;
getFrameCounter()388 	int getFrameCounter() const {
389 		return this->frame_counter;
390 	}
391 	void updateTime(int time);
392 	void resetMouseClick();
393 	int getNClicks();
394 
setGameMode(GameMode gameMode)395 	void setGameMode(GameMode gameMode) {
396 		this->gameMode = gameMode;
397 	}
getGameMode()398 	GameMode getGameMode() const {
399 		return this->gameMode;
400 	}
setGameType(GameType gameType)401 	void setGameType(GameType gameType) {
402 		this->gameType = gameType;
403 	}
getGameType()404 	GameType getGameType() const {
405 		return this->gameType;
406 	}
setDifficultyLevel(DifficultyLevel difficulty_level)407 	void setDifficultyLevel(DifficultyLevel difficulty_level) {
408 		this->difficulty_level = difficulty_level;
409 	}
getDifficultyLevel()410 	DifficultyLevel getDifficultyLevel() const {
411 		return this->difficulty_level;
412 	}
413 	void setGameStateID(GameStateID state, GameState *new_gamestate = NULL);
getGameStateID()414 	GameStateID getGameStateID() const {
415 		return this->gameStateID;
416 	}
setStateChanged(bool state_changed)417 	void setStateChanged(bool state_changed) {
418 		this->state_changed = state_changed;
419 	}
isStateChanged()420 	bool isStateChanged() const {
421 		return this->state_changed;
422 	}
setGameResult(GameResult gameResult)423 	void setGameResult(GameResult gameResult) {
424 		this->gameResult = gameResult;
425 	}
getGameResult()426 	GameResult getGameResult() const {
427 		return this->gameResult;
428 	}
429 	void setupTutorial(const string &id);
getTutorial()430 	const Tutorial *getTutorial() const {
431 		return this->tutorial;
432 	}
getTutorial()433 	Tutorial *getTutorial() {
434 		return this->tutorial;
435 	}
setCurrentMap()436 	void setCurrentMap() {
437 		map = maps[start_epoch][selected_island];
438 	}
439 	void setCurrentIsand(int start_epoch, int selected_island);
440 	const Map *getMap() const;
441 	Map *getMap();
getMap(int i,int j)442 	const Map *getMap(int i, int j) const {
443 		return this->maps[i][j];
444 	}
getStartEpoch()445 	int getStartEpoch() const {
446 		return this->start_epoch;
447 	}
getNSubEpochs()448 	int getNSubEpochs() const {
449 		return this->n_sub_epochs;
450 	}
setPrefSoundOn(bool pref_sound_on)451 	void setPrefSoundOn(bool pref_sound_on) {
452 		this->pref_sound_on = pref_sound_on;
453 	}
isPrefSoundOn()454 	bool isPrefSoundOn() const {
455 		return this->pref_sound_on;
456 	}
setPrefMusicOn(bool pref_music_on)457 	void setPrefMusicOn(bool pref_music_on) {
458 		this->pref_music_on = pref_music_on;
459 	}
isPrefMusicOn()460 	bool isPrefMusicOn() const {
461 		return this->pref_music_on;
462 	}
setPrefDisallowNukes(bool pref_disallow_nukes)463 	void setPrefDisallowNukes(bool pref_disallow_nukes) {
464 		this->pref_disallow_nukes = pref_disallow_nukes;
465 	}
isPrefDisallowNukes()466 	bool isPrefDisallowNukes() const {
467 		return this->pref_disallow_nukes;
468 	}
469 
getMapSqOffset()470 	int getMapSqOffset() const {
471 		return map_sq_offset;
472 	}
getMapSqCoastOffset()473 	int getMapSqCoastOffset() const {
474 		return map_sq_coast_offset;
475 	}
476 	void loadPrefs();
477 	void savePrefs() const;
478 	bool isDemo() const;
479 
480 	void deleteState() const;
481 	void saveState() const;
482 	bool loadState();
483 
484 	int getMenAvailable() const;
485 	int getNSuspended() const;
486 	void nextEpoch();
487 	void nextIsland();
488 	void startIsland();
489 	void endIsland();
490 	void returnToChooseIsland();
491 	void startNewGame();
492 	void placeTower();
493 	void newGame();
494 	void setClientPlayer(int set_client_player);
495 	bool validPlayer(int player) const;
496 	void requestQuit(bool force_quit);
497 	void keypressReturn();
498 	void togglePause();
499 	void activate();
500 	void deactivate();
501 	void mouseClick(int m_x, int m_y, bool m_left, bool m_middle, bool m_right, bool click);
502 	void updateGame();
503 	void drawGame() const;
504 	void addTextEffect(TextEffect *effect);
505 	void drawProgress(int percentage) const;
506 
507 	bool readLineFromRWOps(bool &ok, SDL_RWops *file, char *buffer, char *line, int MAX_LINE, int &buffer_offset, int &newline_index, bool &reached_end);
508 	bool loadGameInfo(DifficultyLevel *difficulty, int *player, int *n_men, int suspended[n_players_c], int *epoch, bool completed[max_islands_per_epoch_c], int slot);
509 	bool loadGame(int slot);
510 	void saveGame(int slot) const;
511 
512 	void stopMusic();
513 	void fadeMusic(int duration_ms) const;
514 	void playMusic();
515 
516 	void setupPlayers();
517 	void setupInventions();
518 	void setupElements();
519 	bool playerAlive(int player) const;
520 
521 	void runTests();
522 };
523 
524 extern Game *game_g;
525 
526 void startIsland_g();
527 void endIsland_g();
528 void returnToChooseIsland_g();
529 void startNewGame_g();
530 
531 extern const char *maps_dirname;
532 #if !defined(__ANDROID__) && defined(__DragonFly__)
533 extern const char *alt_maps_dirname;
534 #endif
535 
536 extern const int epoch_dates[];
537 extern const char *epoch_names[];
538 
539 enum PlayerMode {
540 	PLAYER_DEMO = -2,
541 	PLAYER_NONE = -1
542 };
543 
544 class Map {
545 	string name;
546 	string filename;
547 	MapColour colour;
548 	int n_opponents;
549 	Sector *sectors[map_width_c][map_height_c];
550 	bool sector_at[map_width_c][map_height_c];
551 	bool reserved[map_width_c][map_height_c]; // if true, don't use for starting players - used for testing
552 
553 public:
554 
555 	Map(MapColour colour,int n_opponents,const char *name);
556 	~Map();
557 
getColour()558 	MapColour getColour() const {
559 		return this->colour;
560 	}
getNOpponents()561 	int getNOpponents() const {
562 		return this->n_opponents;
563 	}
564 	const Sector *getSector(int x, int y) const;
565 	Sector *getSector(int x, int y);
566 	bool isSectorAt(int x, int y) const;
567 
568 	void newSquareAt(int x,int y);
569 	void createSectors(PlayingGameState *gamestate, int epoch);
570 #if 0
571 	void checkSectors() const;
572 #endif
573 	void freeSectors();
getName()574 	const char *getName() const {
575 		return name.c_str();
576 	}
getFilename()577 	const char *getFilename() const {
578 		return filename.c_str();
579 	}
setFilename(const char * filename)580 	void setFilename(const char *filename) {
581 		this->filename = filename;
582 	}
583 	int getNSquares() const;
584 	void draw(int offset_x, int offset_y) const;
585 	void findRandomSector(int *rx,int *ry) const;
isReserved(int x,int y)586 	bool isReserved(int x, int y) const {
587 		return this->reserved[x][y];
588 	}
setReserved(int x,int y,bool r)589 	void setReserved(int x, int y, bool r) {
590 		this->reserved[x][y] = r;
591 	}
592 	void canMoveTo(bool temp[map_width_c][map_height_c], int sx,int sy,int player) const;
593 	void calculateStats() const;
594 
595 	void saveStateSectors(stringstream &stream) const;
596 };
597 
598 void playGame(int n_args, char *args[]);
599 
600 #if defined(__ANDROID__)
601 
602 // JNI for Android
603 
604 void launchUrl(string url);
605 
606 #endif
607 
608 // game constants
609 
610 const int SHORT_DELAY = 4000;
611 const int nuke_delay_c = 250;
612 
613 const int gameticks_per_hour_c = 200;
614 const int hours_per_day_c = 12;
615 
616 const int mine_epoch_c = 3;
617 const int factory_epoch_c = 4;
618 const int lab_epoch_c = 5;
619 //const int air_epoch_c = 6;
620 
621 const int DESIGNTIME_M3 = 20;
622 const int DESIGNTIME_M2 = 30;
623 const int DESIGNTIME_M1 = 40;
624 const int DESIGNTIME_0 = 50;
625 const int DESIGNTIME_1 = 100;
626 const int DESIGNTIME_2 = 200;
627 const int DESIGNTIME_3 = 400;
628 
629 const int MANUFACTURETIME_0 = 15;
630 const int MANUFACTURETIME_1 = 30;
631 const int MANUFACTURETIME_2 = 45;
632 const int MANUFACTURETIME_3 = 60;
633 
634 const int BUILDTIME_TOWER = 80;
635 const int BUILDTIME_MINE = 40;
636 const int BUILDTIME_FACTORY = 40;
637 const int BUILDTIME_LAB = 40;
638 
639 const int ticks_per_frame_c = 100; // game time ticks per frame rate (used for various animated sprites)
640 const float time_ratio_c = 0.15f; // game time ticks per time ticks
641