1 //---------------------------------------------------------------------------
2 #include "stdafx.h"
3 
4 #include <cassert>
5 #include <cerrno> // n.b., needed on Linux at least
6 
7 #include <stdexcept> // needed for Android at least
8 
9 #include <sstream>
10 
11 #include "gamestate.h"
12 #include "game.h"
13 #include "utils.h"
14 #include "sector.h"
15 #include "gui.h"
16 #include "player.h"
17 #include "tutorial.h"
18 
19 #include "screen.h"
20 #include "image.h"
21 #include "sound.h"
22 
23 //---------------------------------------------------------------------------
24 
25 const int defenders_ticks_per_update_c = (int)(60.0 * ticks_per_frame_c * time_ratio_c); // consider a turn every this number of ticks
26 const int soldier_move_rate_c = (int)(1.8 * ticks_per_frame_c * time_ratio_c); // ticks per pixel - needs to be in sync with the animation!
27 const int cannon_move_rate_c = (int)(0.6 * ticks_per_frame_c * time_ratio_c); // ticks per pixel - needs to be in sync with the animation!
28 const int air_move_rate_c = (int)(0.2 * ticks_per_frame_c * time_ratio_c); // ticks per pixel
29 const int soldier_turn_rate_c = (int)(50.0 * ticks_per_frame_c * time_ratio_c); // mean ticks per turn
30 
31 const int shield_step_y_c = 20;
32 
33 class Soldier {
34 	static int sort_soldier_pair(const void *v1,const void *v2);
35 public:
36 	int player;
37 	int epoch;
38 	int xpos, ypos;
39 	AmmoDirection dir;
Soldier(int player,int epoch,int xpos,int ypos)40 	Soldier(int player,int epoch,int xpos,int ypos) {
41 		ASSERT_S_EPOCH(epoch);
42 		this->player = player;
43 		this->epoch = epoch;
44 		this->xpos = xpos;
45 		this->ypos = ypos;
46 		this->dir = (AmmoDirection)(rand() % 4);
47 	}
sortSoldiers(Soldier ** soldiers,int n_soldiers)48 	static void sortSoldiers(Soldier **soldiers,int n_soldiers) {
49 		qsort(soldiers, n_soldiers, sizeof( Soldier *), sort_soldier_pair);
50 	}
51 };
52 
sort_soldier_pair(const void * v1,const void * v2)53 int Soldier::sort_soldier_pair(const void *v1,const void *v2) {
54 	Soldier *s1 = *(Soldier **)v1;
55 	Soldier *s2 = *(Soldier **)v2;
56 	/*if( s1->epoch >= 6 )
57 	return 1;
58 	else if( s2->epoch >= 6 )
59 	return -1;
60 	else*/
61 	return (s1->ypos - s2->ypos);
62 }
63 
draw() const64 void Feature::draw() const {
65 	const int ticks_per_frame_c = 110; // tree animation looks better if offset from main animation, and if slightly slower
66 	int counter = ( game_g->getRealTime() * game_g->getTimeRate() ) / ticks_per_frame_c;
67 	image[counter % n_frames]->draw(xpos, ypos);
68 }
69 
TimedEffect()70 TimedEffect::TimedEffect() {
71 	this->timeset = game_g->getRealTime();
72 	this->func_finish = NULL;
73 }
74 
TimedEffect(int delay,void (* func_finish)())75 TimedEffect::TimedEffect(int delay, void (*func_finish)()) {
76 	this->timeset = game_g->getRealTime() + delay;
77 	this->func_finish = func_finish;
78 }
79 
80 const int ammo_time_c = 1000;
81 const float ammo_speed_c = 1.5f; // higher is faster
82 
AmmoEffect(PlayingGameState * gamestate,int epoch,AmmoDirection dir,int xpos,int ypos)83 AmmoEffect::AmmoEffect(PlayingGameState *gamestate,int epoch, AmmoDirection dir, int xpos, int ypos) : TimedEffect(), gamestate(gamestate) {
84 	ASSERT_EPOCH(epoch);
85 	this->gametimeset = game_g->getGameTime();
86 	this->epoch = epoch;
87 	this->dir = dir;
88 	this->xpos = xpos;
89 	this->ypos = ypos;
90 }
91 
render() const92 bool AmmoEffect::render() const {
93 	int time = game_g->getRealTime() - this->timeset;
94 	if( time < 0 )
95 		return false;
96 	int gametime = game_g->getGameTime() - this->gametimeset;
97 	int x = xpos;
98 	int y = ypos;
99 	int dist = (int)(gametime * ammo_speed_c);
100 	if( dir == ATTACKER_AMMO_BOMB )
101 		dist /= 2;
102 	if( dir == ATTACKER_AMMO_DOWN )
103 		y += dist;
104 	else if( dir == ATTACKER_AMMO_UP )
105 		y -= dist;
106 	else if( dir == ATTACKER_AMMO_LEFT )
107 		x -= dist;
108 	else if( dir == ATTACKER_AMMO_RIGHT )
109 		x += dist;
110 	else if( dir == ATTACKER_AMMO_BOMB )
111 		y += dist;
112 	else {
113 		ASSERT(0);
114 	}
115 	Image *image = game_g->attackers_ammo[epoch][dir];
116 	if( dir == ATTACKER_AMMO_BOMB && dist > 24 ) {
117 		if( game_g->explosions[0] != NULL ) {
118 			int w = image->getScaledWidth();
119 			int w2 = game_g->explosions[0]->getScaledWidth();
120 			gamestate->explosionEffect(offset_land_x_c + x + (w-w2)/2, offset_land_y_c + y);
121 		}
122 		return true;
123 	}
124 	if( x < 0 || y < 0 )
125 		return true;
126 	x += offset_land_x_c;
127 	y += offset_land_y_c;
128 	if( x + image->getScaledWidth() >= game_g->getScreen()->getWidth() || y + image->getScaledHeight() >= game_g->getScreen()->getHeight() )
129 		return true;
130 	image->draw(x, y);
131 	if( time > ammo_time_c )
132 		return true;
133 	return false;
134 }
135 
136 const int fade_time_c = 1000;
137 const int whitefade_time_c = 1000;
138 
FadeEffect(bool white,bool out,int delay,void (* func_finish)())139 FadeEffect::FadeEffect(bool white,bool out,int delay, void (*func_finish)()) : TimedEffect(delay, func_finish) {
140 	this->white = white;
141 	this->out = out;
142 #if SDL_MAJOR_VERSION == 1
143 	this->image = Image::createBlankImage(game_g->getScreen()->getWidth(), game_g->getScreen()->getHeight(), 24);
144 	int r = 0, g = 0, b = 0;
145 	if( white ) {
146 		r = g = b = 255;
147 	}
148 	else {
149 		r = g = b = 0;
150 	}
151 	image->fillRect(0, 0, game_g->getScreen()->getWidth(), game_g->getScreen()->getHeight(), r, g, b);
152 	this->image->convertToDisplayFormat();
153 #else
154 	image = NULL;
155 #endif
156 }
157 
~FadeEffect()158 FadeEffect::~FadeEffect() {
159 #if SDL_MAJOR_VERSION == 1
160 	delete image;
161 #endif
162 }
163 
render() const164 bool FadeEffect::render() const {
165 	int time = game_g->getRealTime() - this->timeset;
166 	int length = white ? whitefade_time_c : fade_time_c;
167 	if( time < 0 )
168 		return false;
169 	double alpha = 0.0;
170 	if( white ) {
171 		alpha = ((double)time) / (0.5 * (double)length);
172 		if( alpha > 2.0 )
173 			alpha = 2.0;
174 		if( time > length/2.0 ) {
175 			alpha = 2.0 - alpha;
176 		}
177 	}
178 	else {
179 		alpha = ((double)time) / (double)length;
180 		if( alpha > 1.0 )
181 			alpha = 1.0;
182 		if( !out )
183 			alpha = 1.0 - alpha;
184 	}
185 #if SDL_MAJOR_VERSION == 1
186 	image->drawWithAlpha(0, 0, (unsigned char)(alpha * 255));
187 #else
188 	unsigned char value = white ? 255 : 0;
189 	game_g->getScreen()->fillRectWithAlpha(0, 0, game_g->getScreen()->getWidth(), game_g->getScreen()->getHeight(), value, value, value, (unsigned char)(alpha * 255));
190 #endif
191 	if( time > length ) // we still need to draw the fade, on the last time
192 		return true;
193 	return false;
194 }
195 
196 const int flashingsquare_flash_time_c = 250;
197 const int flashing_square_n_flashes_c = 8;
198 
render() const199 bool FlashingSquare::render() const {
200 	int time = game_g->getRealTime() - this->timeset;
201 	if( time < 0 )
202 		return false;
203 	if( time > flashingsquare_flash_time_c * flashing_square_n_flashes_c ) {
204 		return true;
205 	}
206 
207 	bool flash = ( time / flashingsquare_flash_time_c ) % 2 == 0;
208 	if( flash ) {
209 		int map_x = offset_map_x_c + 16 * this->xpos;
210 		int map_y = offset_map_y_c + 16 * this->ypos;
211 		game_g->flashingmapsquare->draw(map_x, map_y);
212 	}
213 	return false;
214 }
215 
render() const216 bool AnimationEffect::render() const {
217 	int time = game_g->getRealTime() - this->timeset;
218 	if( time < 0 )
219 		return false;
220 	int frame = time / time_per_frame;
221 	if( frame >= n_images )
222 		return true;
223 	//this->finished = true;
224 	else {
225 		if( !dir )
226 			frame = n_images - 1 - frame;
227 		images[frame]->draw(xpos, ypos);
228 	}
229 	return false;
230 }
231 
render() const232 bool TextEffect::render() const {
233 	int time = game_g->getRealTime() - this->timeset;
234 	if( time < 0 )
235 		return false;
236 	else if( time > duration )
237 		return true;
238 	Image::write(xpos, ypos, game_g->letters_small, text.c_str(), Image::JUSTIFY_CENTRE);
239 	return false;
240 }
241 
GameState(int client_player)242 GameState::GameState(int client_player) : client_player(client_player) {
243 	this->fade = NULL;
244 	this->whitefade = NULL;
245 	this->screen_page = new PanelPage(0, 0);
246 	this->screen_page->setTolerance(0);
247 	this->mobile_ui_display_mouse = false;
248 	this->mouse_image = NULL;
249 	this->mouse_off_x = 0;
250 	this->mouse_off_y = 0;
251 	this->confirm_type = CONFIRMTYPE_UNKNOWN;
252     this->confirm_window = NULL;
253     this->confirm_button_1 = NULL;
254     this->confirm_button_2 = NULL;
255     this->confirm_button_3 = NULL;
256 }
257 
~GameState()258 GameState::~GameState() {
259 	LOG("~GameState()\n");
260 	if( fade != NULL )
261 		delete fade;
262 	if( whitefade != NULL )
263 		delete whitefade;
264 
265 	if( this->screen_page )
266 		delete screen_page;
267 
268 	LOG("~GameState() done\n");
269 }
270 
reset()271 void GameState::reset() {
272     //LOG("GameState::reset()\n");
273 	this->screen_page->free(true);
274 }
275 
setDefaultMouseImage()276 void GameState::setDefaultMouseImage() {
277 	if( game_g->isDemo() )
278 		mouse_image = game_g->mouse_pointers[0];
279 	else
280 		mouse_image = game_g->mouse_pointers[client_player];
281 	mobile_ui_display_mouse = false;
282 }
283 
draw()284 void GameState::draw() {
285 	if( mouse_image != NULL ) {
286 		bool touch_mode = game_g->isMobileUI() || game_g->getApplication()->isBlankMouse();
287 		if( touch_mode && mobile_ui_display_mouse ) {
288 			mouse_image->draw(default_width_c - mouse_image->getScaledWidth(), 0);
289 		}
290 		else if( !touch_mode ) {
291 			int m_x = 0, m_y = 0;
292 			game_g->getScreen()->getMouseCoords(&m_x, &m_y);
293 			m_x = (int)(m_x / game_g->getScaleWidth());
294 			m_y = (int)(m_y / game_g->getScaleHeight());
295 			m_x += mouse_off_x;
296 			m_y += mouse_off_y;
297 			mouse_image->draw(m_x, m_y);
298 		}
299 	}
300 
301 	if( fade ) {
302 		if( fade->render() ) {
303 			FadeEffect *copy = fade;
304 			delete fade;
305 			if( copy == fade )
306 				fade = NULL;
307 		}
308 	}
309 	if( whitefade ) {
310 		if( whitefade->render() ) {
311 			FadeEffect *copy = whitefade;
312 			delete whitefade;
313 			if( copy == whitefade )
314 				whitefade = NULL;
315 		}
316 	}
317 
318 	if( game_g->isPaused() ) {
319 		string str = game_g->isMobileUI() ? "touch screen\nto unpause game" : "press p or click\nmouse to unpause game";
320 		// n.b., don't use 120 for y pos, need to avoid collision with quit game message
321 		// and offset x pos slightly, to avoid overlapping with GUI
322 		Image::write(120, 100, game_g->letters_large, str.c_str(), Image::JUSTIFY_LEFT);
323 	}
324 
325 	if( game_g->getApplication()->hasFPS() ) {
326 		float fps = game_g->getApplication()->getFPS();
327 		if( fps > 0.0f ) {
328 			stringstream str;
329 			str << fps;
330 			Image::writeMixedCase(4, default_height_c - 16, game_g->letters_large, game_g->letters_small, game_g->numbers_white, str.str().c_str(), Image::JUSTIFY_LEFT);
331 		}
332 	}
333 
334 	game_g->getScreen()->refresh();
335 }
336 
mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click)337 void GameState::mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click) {
338 	this->screen_page->input(m_x, m_y, m_left, m_middle, m_right, click);
339 }
340 
requestQuit(bool force_quit)341 void GameState::requestQuit(bool force_quit) {
342 	game_g->getApplication()->setQuit();
343 }
344 
createQuitWindow()345 void GameState::createQuitWindow() {
346     if( confirm_window == NULL && !game_g->isStateChanged() ) {
347 		confirm_type = CONFIRMTYPE_QUITGAME;
348 		confirm_window = new PanelPage(0, 0, default_width_c, default_height_c);
349 		confirm_window->setBackground(0, 0, 0, 200);
350 		const int offset_x_c = 120, offset_y_c = 120;
351 		Button *text_button = new Button(offset_x_c, offset_y_c, "REALLY QUIT?", game_g->letters_large);
352 		confirm_window->add(text_button);
353 		confirm_button_1 = new Button(offset_x_c, offset_y_c+16, "YES", game_g->letters_large);
354 		confirm_window->add(confirm_button_1);
355 		confirm_button_2 = new Button(offset_x_c+32, offset_y_c+16, "NO", game_g->letters_large);
356 		confirm_window->add(confirm_button_2);
357 		screen_page->add(confirm_window);
358 	}
359 	else if( confirm_window != NULL && !game_g->isStateChanged() ) {
360 		closeConfirmWindow();
361 	}
362 }
363 
closeConfirmWindow()364 void GameState::closeConfirmWindow() {
365     //LOG("GameState::closeConfirmWindow()\n");
366     if( confirm_window != NULL ) {
367         delete confirm_window;
368         confirm_window = NULL;
369         confirm_button_1 = NULL;
370         confirm_button_2 = NULL;
371         confirm_button_3 = NULL;
372     }
373     //LOG("GameState::closeConfirmWindow() done\n");
374 }
375 
ChooseGameTypeGameState(int client_player)376 ChooseGameTypeGameState::ChooseGameTypeGameState(int client_player) : GameState(client_player) {
377 	this->choosegametypePanel = NULL;
378 	T_ASSERT(game_g->getTutorial() == NULL);
379 }
380 
~ChooseGameTypeGameState()381 ChooseGameTypeGameState::~ChooseGameTypeGameState() {
382 	LOG("~ChooseGameTypeGameState()\n");
383 	if( this->choosegametypePanel )
384 		delete choosegametypePanel;
385 	LOG("~ChooseGameTypeGameState() done\n");
386 }
387 
getChooseGameTypePanel()388 ChooseGameTypePanel *ChooseGameTypeGameState::getChooseGameTypePanel() {
389 	return this->choosegametypePanel;
390 }
391 
reset()392 void ChooseGameTypeGameState::reset() {
393     //LOG("ChooseGameTypeGameState::reset()\n");
394 	this->screen_page->free(true);
395 
396 	if( this->choosegametypePanel != NULL ) {
397 		delete this->choosegametypePanel;
398 		this->choosegametypePanel = NULL;
399 	}
400 	this->choosegametypePanel = new ChooseGameTypePanel();
401 }
402 
draw()403 void ChooseGameTypeGameState::draw() {
404 #if defined(__ANDROID__)
405 	game_g->getScreen()->clear(); // SDL on Android requires screen be cleared (otherwise we get corrupt regions outside of the main area)
406 #endif
407 	game_g->background->draw(0, 0);
408 
409 	this->choosegametypePanel->draw();
410 
411 	this->screen_page->draw();
412 	//this->screen_page->drawPopups();
413 
414 	GameState::setDefaultMouseImage();
415 	GameState::draw();
416 }
417 
mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click)418 void ChooseGameTypeGameState::mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click) {
419 	GameState::mouseClick(m_x, m_y, m_left, m_middle, m_right, click);
420 
421 	this->choosegametypePanel->input(m_x, m_y, m_left, m_middle, m_right, click);
422 }
423 
ChooseDifficultyGameState(int client_player)424 ChooseDifficultyGameState::ChooseDifficultyGameState(int client_player) : GameState(client_player) {
425 	this->choosedifficultyPanel = NULL;
426 }
427 
~ChooseDifficultyGameState()428 ChooseDifficultyGameState::~ChooseDifficultyGameState() {
429 	LOG("~ChooseDifficultyGameState()\n");
430 	if( this->choosedifficultyPanel )
431 		delete choosedifficultyPanel;
432 	LOG("~ChooseDifficultyGameState() done\n");
433 }
434 
getChooseDifficultyPanel()435 ChooseDifficultyPanel *ChooseDifficultyGameState::getChooseDifficultyPanel() {
436 	return this->choosedifficultyPanel;
437 }
438 
reset()439 void ChooseDifficultyGameState::reset() {
440     //LOG("ChooseDifficultyGameState::reset()\n");
441 	this->screen_page->free(true);
442 
443 	if( this->choosedifficultyPanel != NULL ) {
444 		delete this->choosedifficultyPanel;
445 		this->choosedifficultyPanel = NULL;
446 	}
447 	this->choosedifficultyPanel = new ChooseDifficultyPanel();
448 }
449 
draw()450 void ChooseDifficultyGameState::draw() {
451 #if defined(__ANDROID__)
452 	game_g->getScreen()->clear(); // SDL on Android requires screen be cleared (otherwise we get corrupt regions outside of the main area)
453 #endif
454 	game_g->background->draw(0, 0);
455 
456 	this->choosedifficultyPanel->draw();
457 
458 	this->screen_page->draw();
459 
460 	GameState::setDefaultMouseImage();
461 	GameState::draw();
462 }
463 
mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click)464 void ChooseDifficultyGameState::mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click) {
465 	GameState::mouseClick(m_x, m_y, m_left, m_middle, m_right, click);
466 
467 	this->choosedifficultyPanel->input(m_x, m_y, m_left, m_middle, m_right, click);
468 }
469 
ChoosePlayerGameState(int client_player)470 ChoosePlayerGameState::ChoosePlayerGameState(int client_player) : GameState(client_player), button_red(NULL), button_yellow(NULL), button_green(NULL), button_blue(NULL) {
471 }
472 
~ChoosePlayerGameState()473 ChoosePlayerGameState::~ChoosePlayerGameState() {
474 	LOG("~ChoosePlayerGameState()\n");
475 	LOG("~ChoosePlayerGameState() done\n");
476 }
477 
reset()478 void ChoosePlayerGameState::reset() {
479 	this->screen_page->free(true);
480 
481 	const int xpos = 64;
482 	int ypos = 48;
483 	const int ydiff = 48;
484 	const int xindent = 8;
485 	const int ylargediff = game_g->letters_large[0]->getScaledHeight() + 2;
486 	const int ysmalldiff = game_g->letters_small[0]->getScaledHeight() + 2;
487 	const int draw_offset_x = 32;
488 
489 	button_red = new Button(xpos-draw_offset_x, ypos, draw_offset_x, ylargediff + 2*ysmalldiff, "CONTROLLER OF THE RED PEOPLE", game_g->letters_large);
490 	screen_page->add(new Button(xpos+xindent, ypos+ylargediff, "SPECIAL SKILL STRENGTH", game_g->letters_small));
491 	screen_page->add(new Button(xpos+xindent, ypos+ylargediff+ysmalldiff, "UNARMED MEN ARE STRONGER IN COMBAT", game_g->letters_small));
492 	ypos += ydiff;
493 	screen_page->add(button_red);
494 
495 	button_green = new Button(xpos-draw_offset_x, ypos, draw_offset_x, ylargediff + 2*ysmalldiff, "CONTROLLER OF THE GREEN PEOPLE", game_g->letters_large);
496 	screen_page->add(new Button(xpos+xindent, ypos+ylargediff, "SPECIAL SKILL CONSTRUCTION", game_g->letters_small));
497 	screen_page->add(new Button(xpos+xindent, ypos+ylargediff+ysmalldiff, "FASTER AT BUILDING NEW TOWERS", game_g->letters_small));
498 	ypos += ydiff;
499 	screen_page->add(button_green);
500 
501 	button_yellow = new Button(xpos-draw_offset_x, ypos, draw_offset_x, ylargediff + 2*ysmalldiff, "CONTROLLER OF THE YELLOW PEOPLE", game_g->letters_large);
502 	screen_page->add(new Button(xpos+xindent, ypos+ylargediff, "SPECIAL SKILL DIPLOMACY", game_g->letters_small));
503 	screen_page->add(new Button(xpos+xindent, ypos+ylargediff+ysmalldiff, "EASIER TO FORM ALLIANCES", game_g->letters_small));
504 	ypos += ydiff;
505 	screen_page->add(button_yellow);
506 
507 	button_blue = new Button(xpos-draw_offset_x, ypos, draw_offset_x, ylargediff + 2*ysmalldiff, "CONTROLLER OF THE BLUE PEOPLE", game_g->letters_large);
508 	screen_page->add(new Button(xpos+xindent, ypos+ylargediff, "SPECIAL SKILL DEFENCE", game_g->letters_small));
509 	screen_page->add(new Button(xpos+xindent, ypos+ylargediff+ysmalldiff, "BUILDINGS STRONGER AGAINST ATTACK", game_g->letters_small));
510 	ypos += ydiff;
511 	screen_page->add(button_blue);
512 }
513 
draw()514 void ChoosePlayerGameState::draw() {
515 #if defined(__ANDROID__)
516 	game_g->getScreen()->clear(); // SDL on Android requires screen be cleared (otherwise we get corrupt regions outside of the main area)
517 #endif
518 	//player_select->draw(0, 0, false);
519 	game_g->background->draw(0, 0);
520     Image::writeMixedCase(160, 16, game_g->letters_large, game_g->letters_small, NULL, "Select a Player", Image::JUSTIFY_CENTRE);
521 
522 	const int y_offset = 2; // must be even, otherwise we have graphical problems when running at 1280x1024 mode
523 	if( game_g->player_heads_select[0] != NULL )
524 		game_g->player_heads_select[0]->draw(button_red->getLeft(), button_red->getTop()+y_offset);
525 	if( game_g->player_heads_select[1] != NULL )
526 		game_g->player_heads_select[1]->draw(button_green->getLeft(), button_green->getTop()+y_offset);
527 	if( game_g->player_heads_select[2] != NULL )
528 		game_g->player_heads_select[2]->draw(button_yellow->getLeft(), button_yellow->getTop()+y_offset);
529 	if( game_g->player_heads_select[3] != NULL )
530 		game_g->player_heads_select[3]->draw(button_blue->getLeft(), button_blue->getTop()+y_offset);
531 
532 	this->screen_page->draw();
533 
534 	GameState::setDefaultMouseImage();
535 	GameState::draw();
536 }
537 
mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click)538 void ChoosePlayerGameState::mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click) {
539 	GameState::mouseClick(m_x, m_y, m_left, m_middle, m_right, click);
540 
541 	int player = -1;
542     if( m_left && click && button_red->mouseOver(m_x, m_y) ) {
543 		player = 0;
544 	}
545     else if( m_left && click && button_yellow->mouseOver(m_x, m_y) ) {
546 		player = 2;
547 	}
548     else if( m_left && click && button_green->mouseOver(m_x, m_y) ) {
549 		player = 1;
550 	}
551     else if( m_left && click && button_blue->mouseOver(m_x, m_y) ) {
552 		player = 3;
553 	}
554 
555 	if( player != -1 ) {
556 		game_g->setClientPlayer(player);
557 		if( game_g->getGameType() == GAMETYPE_TUTORIAL ) {
558 			game_g->setGameStateID(GAMESTATEID_CHOOSETUTORIAL);
559 		}
560 		else {
561 			game_g->setGameStateID(GAMESTATEID_PLACEMEN);
562 			game_g->newGame();
563 		}
564 	}
565 }
566 
ChooseTutorialGameState(int client_player)567 ChooseTutorialGameState::ChooseTutorialGameState(int client_player) : GameState(client_player) {
568 }
569 
reset()570 void ChooseTutorialGameState::reset() {
571 	this->screen_page->free(true);
572 
573 	const int xpos = 96;
574 	int ypos = 48;
575 	const int ydiff = 16;
576 
577 	vector<TutorialInfo> infos = TutorialManager::getTutorialInfo();
578 	for(vector<TutorialInfo>::const_iterator iter = infos.begin(); iter != infos.end(); ++iter) {
579 		TutorialInfo info = *iter;
580 		Button *button = new Button(xpos, ypos, info.text.c_str(), game_g->letters_large);
581 		button->setId(info.id);
582 		ypos += ydiff;
583 		screen_page->add(button);
584 		buttons.push_back(button);
585 	}
586 }
587 
draw()588 void ChooseTutorialGameState::draw() {
589 #if defined(__ANDROID__)
590 	game_g->getScreen()->clear(); // SDL on Android requires screen be cleared (otherwise we get corrupt regions outside of the main area)
591 #endif
592 	game_g->background->draw(0, 0);
593     Image::writeMixedCase(160, 16, game_g->letters_large, game_g->letters_small, NULL, "Select a Tutorial", Image::JUSTIFY_CENTRE);
594 
595 	this->screen_page->draw();
596 
597 	GameState::setDefaultMouseImage();
598 	GameState::draw();
599 }
600 
mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click)601 void ChooseTutorialGameState::mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click) {
602 	GameState::mouseClick(m_x, m_y, m_left, m_middle, m_right, click);
603 
604 	for(vector<Button *>::const_iterator iter = buttons.begin(); iter != buttons.end(); ++iter) {
605 		const Button *button = *iter;
606 	    if( m_left && click && button->mouseOver(m_x, m_y) ) {
607 			game_g->setupTutorial(button->getId());
608 			game_g->setCurrentIsand(game_g->getTutorial()->getStartEpoch(), game_g->getTutorial()->getIsland());
609 			game_g->setupPlayers();
610 			game_g->setGameStateID(GAMESTATEID_PLAYING);
611 			break;
612 		}
613 	}
614 }
615 
PlaceMenGameState(int client_player)616 PlaceMenGameState::PlaceMenGameState(int client_player) : GameState(client_player), start_map_x(-1), start_map_y(-1) {
617 	this->off_x = 220;
618 	this->off_y = 32;
619 	this->choosemenPanel = NULL;
620 	for(int y=0;y<map_height_c;y++) {
621 		for(int x=0;x<map_width_c;x++) {
622 			map_panels[x][y] = NULL;
623 		}
624 	}
625 }
626 
~PlaceMenGameState()627 PlaceMenGameState::~PlaceMenGameState() {
628 	LOG("~PlaceMenGameState()\n");
629 	if( this->choosemenPanel )
630 		delete choosemenPanel;
631 	LOG("~PlaceMenGameState() done\n");
632 }
633 
getChooseMenPanel()634 ChooseMenPanel *PlaceMenGameState::getChooseMenPanel() {
635 	return this->choosemenPanel;
636 }
637 
getMapPanel(int x,int y) const638 const PanelPage *PlaceMenGameState::getMapPanel(int x, int y) const {
639 	ASSERT( x >= 0 && x < map_width_c );
640 	ASSERT( y >= 0 && y < map_height_c );
641 	return this->map_panels[x][y];
642 }
643 
getMapPanel(int x,int y)644 PanelPage *PlaceMenGameState::getMapPanel(int x, int y) {
645 	ASSERT( x >= 0 && x < map_width_c );
646 	ASSERT( y >= 0 && y < map_height_c );
647 	return this->map_panels[x][y];
648 }
649 
reset()650 void PlaceMenGameState::reset() {
651     //LOG("PlaceMenGameState::reset()\n");
652 	/*if( !_CrtCheckMemory() ) {
653 		throw "_CrtCheckMemory FAILED";
654 	}*/
655 	this->screen_page->free(true);
656 
657 	if( this->choosemenPanel != NULL ) {
658 		delete this->choosemenPanel;
659 		this->choosemenPanel = NULL;
660 	}
661 
662 	this->choosemenPanel = new ChooseMenPanel(this);
663 
664 	// setup screen_page buttons
665 	for(int y=0;y<map_height_c;y++) {
666 		for(int x=0;x<map_width_c;x++) {
667 			map_panels[x][y] = NULL;
668 			if( game_g->getMap()->isSectorAt(x, y) ) {
669 				//int map_x = offset_map_x_c + 16 * x;
670 				int map_x = this->off_x - 8 * map_width_c + 16 * x;
671 				int map_y = this->off_y + 16 * y;
672 				PanelPage *panel = new PanelPage(map_x, map_y, 16, 16);
673 				panel->setInfoLMB("place starting tower\nin this sector");
674 				panel->setVisible(false);
675 				screen_page->add(panel);
676 				map_panels[x][y] = panel;
677 			}
678 		}
679 	}
680 	/*if( !_CrtCheckMemory() ) {
681 		throw "_CrtCheckMemory FAILED";
682 	}*/
683 }
684 
draw()685 void PlaceMenGameState::draw() {
686 	char buffer[256] = "";
687 
688 #if defined(__ANDROID__)
689 	game_g->getScreen()->clear(); // SDL on Android requires screen be cleared (otherwise we get corrupt regions outside of the main area)
690 #endif
691 	game_g->background_islands->draw(0, 0);
692 
693 	if( !game_g->isUsingOldGfx() ) {
694 		sprintf(buffer, "Gigalomania v%d.%d", majorVersion, minorVersion);
695 	    Image::writeMixedCase(160, 228, game_g->letters_large, game_g->letters_small, game_g->numbers_white, buffer, Image::JUSTIFY_CENTRE);
696 	}
697 
698     /*this->choosemenPanel->draw();
699     this->screen_page->draw();
700     GameState::draw();
701     return;*/
702 
703     int l_h = game_g->letters_large[0]->getScaledHeight();
704 	int s_h = game_g->letters_small[0]->getScaledHeight();
705 	const int cx = this->off_x;
706     int cy = this->off_y + 104;
707 	Image::writeMixedCase(cx, cy, game_g->letters_large, game_g->letters_small, NULL, game_g->getMap()->getName(), Image::JUSTIFY_CENTRE);
708 	cy += s_h + 2;
709 	Image::writeMixedCase(cx, cy, game_g->letters_large, game_g->letters_small, NULL, "of the", Image::JUSTIFY_CENTRE);
710 	cy += l_h + 2;
711 	sprintf(buffer, "%s AGE", epoch_names[game_g->getStartEpoch()]);
712 	Image::writeMixedCase(cx, cy, game_g->letters_large, game_g->letters_small, NULL, buffer, Image::JUSTIFY_CENTRE);
713     cy += l_h + 2;
714 
715 	int year = epoch_dates[game_g->getStartEpoch()];
716 	bool shiny = game_g->getStartEpoch() == n_epochs_c-1;
717 	Image::writeNumbers(cx+8, cy, shiny ? game_g->numbers_largeshiny : game_g->numbers_largegrey, abs(year),Image::JUSTIFY_RIGHT);
718 	Image *era = ( year < 0 ) ? game_g->icon_bc :
719 		shiny ? game_g->icon_ad_shiny : game_g->icon_ad;
720 	if( era != NULL )
721 		era->draw(cx+8, cy);
722 	else {
723 		Image::write(cx+8, cy, game_g->letters_small, ( year < 0 ) ? "BC" : "AD", Image::JUSTIFY_LEFT);
724 	}
725     cy += l_h + 2;
726 
727 	if( !game_g->isDemo() && game_g->getGameType() == GAMETYPE_ALLISLANDS ) {
728 		int n_suspended = game_g->getNSuspended();
729         if( n_suspended > 0 )
730 		{
731 			sprintf(buffer, "Saved Men %d", n_suspended);
732             Image::writeMixedCase(cx, cy, game_g->letters_large, game_g->letters_small, game_g->numbers_white, buffer, Image::JUSTIFY_CENTRE);
733 		}
734 	}
735 
736     /*cy += l_h + 2;
737 	cy += l_h + 2;
738 	if( choosemenPanel->getPage() == ChooseMenPanel::STATE_LOADGAME ) {
739 		Image::write(cx, cy, game_g->letters_large, "LOAD", Image::JUSTIFY_CENTRE, true);
740 	}
741 	else if( choosemenPanel->getPage() == ChooseMenPanel::STATE_SAVEGAME ) {
742 		Image::write(cx, cy, game_g->letters_large, "SAVE", Image::JUSTIFY_CENTRE, true);
743 	}
744     cy += s_h + 2;*/
745 
746 	if( choosemenPanel->getPage() == ChooseMenPanel::STATE_CHOOSEMEN ) {
747 		cy = 100;
748 		const int xpos = 80;
749 		Image::writeMixedCase(xpos, cy, game_g->letters_large, game_g->letters_small, NULL, "Click on the icon below", Image::JUSTIFY_CENTRE);
750 		cy += l_h + 2;
751 		Image::writeMixedCase(xpos, cy, game_g->letters_large, game_g->letters_small, NULL, "to choose how many men", Image::JUSTIFY_CENTRE);
752 		cy += l_h + 2;
753 		Image::writeMixedCase(xpos, cy, game_g->letters_large, game_g->letters_small, NULL, "to play with", Image::JUSTIFY_CENTRE);
754 		cy += l_h + 2;
755 		Image::writeMixedCase(xpos, cy, game_g->letters_large, game_g->letters_small, NULL, "then click on the map", Image::JUSTIFY_CENTRE);
756 		cy += l_h + 2;
757 		Image::writeMixedCase(xpos, cy, game_g->letters_large, game_g->letters_small, NULL, "to the right", Image::JUSTIFY_CENTRE);
758 		cy += l_h + 2;
759 	}
760 
761 	game_g->getMap()->draw(cx - 8*map_width_c, off_y);
762 
763 	this->choosemenPanel->draw();
764 	//this->choosemenPanel->drawPopups();
765 
766     this->screen_page->draw();
767 	//this->screen_page->drawPopups();
768 
769 	GameState::setDefaultMouseImage();
770 	GameState::draw();
771 }
772 
mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click)773 void PlaceMenGameState::mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click) {
774 	GameState::mouseClick(m_x, m_y, m_left, m_middle, m_right, click);
775 
776     bool done = false;
777     if( !done && m_left && click && confirm_button_1 != NULL && confirm_button_1->mouseOver(m_x, m_y) ) {
778         LOG("confirm yes clicked\n");
779         done = true;
780         registerClick();
781         ASSERT( confirm_window != NULL );
782 		this->requestConfirm();
783     }
784     else if( !done && m_left && click && confirm_button_2 != NULL && confirm_button_2->mouseOver(m_x, m_y) ) {
785         LOG("confirm no clicked\n");
786         done = true;
787         registerClick();
788         ASSERT( confirm_window != NULL );
789         this->closeConfirmWindow();
790     }
791 
792     if( !done && m_left && click && this->choosemenPanel->getPage() == ChooseMenPanel::STATE_CHOOSEMEN && this->choosemenPanel->getNMen() > 0 ) {
793 		bool found = false;
794 		int map_x = -1;
795 		int map_y = -1;
796 		for(int y=0;y<map_height_c && !found;y++) {
797 			for(int x=0;x<map_width_c && !found;x++) {
798 				if( game_g->getMap()->isSectorAt(x, y) ) {
799 					ASSERT( this->map_panels[x][y] != NULL );
800 					if( this->map_panels[x][y]->mouseOver(m_x, m_y) ) {
801 						found = true;
802 						map_x = x;
803 						map_y = y;
804 					}
805 				}
806 			}
807 		}
808 		if( found ) {
809 			LOG("starting epoch %d island %s at %d, %d\n", game_g->getStartEpoch(), game_g->getMap()->getName(), map_x, map_y);
810 			this->setStartMapPos(map_x, map_y);
811 			return;
812 		}
813 	}
814 
815     if( !done )
816         this->choosemenPanel->input(m_x, m_y, m_left, m_middle, m_right, click);
817 }
818 
requestQuit(bool force_quit)819 void PlaceMenGameState::requestQuit(bool force_quit) {
820 	if( force_quit ) {
821 		game_g->saveState();
822 	    game_g->getApplication()->setQuit();
823 	}
824 	else if( choosemenPanel->getPage() == ChooseMenPanel::STATE_CHOOSEMEN && !game_g->isStateChanged() ) {
825 		choosemenPanel->setPage(ChooseMenPanel::STATE_CHOOSEISLAND);
826 	}
827 	else {
828 		this->createQuitWindow();
829 	}
830 }
831 
requestConfirm()832 void PlaceMenGameState::requestConfirm() {
833 	if( confirm_window != NULL ) {
834         this->closeConfirmWindow();
835 		if( confirm_type == CONFIRMTYPE_NEWGAME ) {
836 			game_g->setGameStateID(GAMESTATEID_CHOOSEGAMETYPE);
837 		}
838 		else if( confirm_type == CONFIRMTYPE_QUITGAME ) {
839 	        game_g->getApplication()->setQuit();
840 		}
841 		else {
842 			T_ASSERT(false);
843 		}
844 	}
845 }
846 
setStartMapPos(int start_map_x,int start_map_y)847 void PlaceMenGameState::setStartMapPos(int start_map_x, int start_map_y ) {
848 	this->start_map_x = start_map_x;
849 	this->start_map_y = start_map_y;
850 	if( !game_g->isDemo() ) {
851 		game_g->players[client_player]->setNMenForThisIsland( this->choosemenPanel->getNMen() );
852 		ASSERT( game_g->players[client_player]->getNMenForThisIsland() <= game_g->getMenAvailable() );
853 		LOG("human is player %d, starting with %d men\n", client_player, game_g->players[client_player]->getNMenForThisIsland());
854 	}
855 	else {
856 		LOG("DEMO mode\n");
857 		//placeTower(map_x, map_y, 0);
858 	}
859 	game_g->placeTower();
860 }
861 
requestNewGame()862 void PlaceMenGameState::requestNewGame() {
863 	if( confirm_window != NULL ) {
864 		this->closeConfirmWindow();
865 	}
866 	confirm_window = new PanelPage(0, 0, default_width_c, default_height_c);
867 	confirm_type = CONFIRMTYPE_NEWGAME;
868 	confirm_window->setBackground(0, 0, 0, 200);
869 	const int offset_x_c = 120, offset_y_c = 120;
870 	Button *text_button = new Button(offset_x_c, offset_y_c, "NEW GAME?", game_g->letters_large);
871 	confirm_window->add(text_button);
872 	confirm_button_1 = new Button(offset_x_c, offset_y_c+16, "YES", game_g->letters_large);
873 	confirm_window->add(confirm_button_1);
874 	confirm_button_2 = new Button(offset_x_c+32, offset_y_c+16, "NO", game_g->letters_large);
875 	confirm_window->add(confirm_button_2);
876 	this->screen_page->add(confirm_window);
877 }
878 
879 
PlayingGameState(int client_player)880 PlayingGameState::PlayingGameState(int client_player) : GameState(client_player) {
881 	this->current_sector = NULL;
882 	this->flag_frame_step = 0;
883 	this->defenders_last_time_update = 0;
884 	this->soldier_last_time_moved_x = -1;
885 	this->soldier_last_time_moved_y = -1;
886 	this->cannon_last_time_moved_x = -1;
887 	this->cannon_last_time_moved_y = -1;
888 	this->air_last_time_moved = -1;
889 	this->soldiers_last_time_turned = 0;
890 
891 	this->text_effect = NULL;
892 	this->speed_button = NULL;
893 	for(int i=0;i<n_players_c;i++) {
894 		this->shield_buttons[i] = NULL;
895 		this->shield_number_panels[i] = NULL;
896 	}
897 	this->shield_blank_button = NULL;
898 	this->land_panel = NULL;
899 	this->pause_button = NULL;
900 	this->quit_button = NULL;
901 	this->tutorial_next_button = NULL;
902 	this->gamePanel = NULL;
903 	this->selected_army = NULL;
904 	this->map_display = MAPDISPLAY_MAP;
905 	//this->map_display = MAPDISPLAY_UNITS;
906 	this->player_asking_alliance = -1;
907 	/*for(i=0;i<n_players_c;i++)
908 	this->n_soldiers[i] = 0;*/
909 	for(int i=0;i<n_players_c;i++)
910 		for(int j=0;j<=n_epochs_c;j++)
911 			this->n_deaths[i][j] = 0;
912 	//this->refreshSoldiers(false);
913 	for(int y=0;y<map_height_c;y++) {
914 		for(int x=0;x<map_width_c;x++) {
915 			map_panels[x][y] = NULL;
916 		}
917 	}
918 	alliance_yes = NULL;
919 	alliance_no = NULL;
920 
921 	game_g->setTimeRate(client_player == PLAYER_DEMO ? 5 : 1);
922 }
923 
~PlayingGameState()924 PlayingGameState::~PlayingGameState() {
925 	LOG("~PlayingGameState()\n");
926 	if( game_g->getMap() != NULL ) { // check needed if the current map failed to load, and we're resuming from saved state with that island
927 		game_g->getMap()->freeSectors(); // needed to avoid crash for tests, and exiting to desktop
928 	}
929 	game_g->s_biplane->fadeOut(500);
930 	game_g->s_jetplane->fadeOut(500);
931 	game_g->s_spaceship->fadeOut(500);
932 	for(size_t i=0;i<effects.size();i++) {
933 		TimedEffect *effect = effects.at(i);
934 		delete effect;
935 	}
936 	for(size_t i=0;i<ammo_effects.size();i++) {
937 		TimedEffect *effect = ammo_effects.at(i);
938 		delete effect;
939 	}
940 	if( text_effect != NULL ) {
941 		delete text_effect;
942 	}
943 	if( this->gamePanel )
944 		delete gamePanel;
945 	LOG("~PlayingGameState() done\n");
946 }
947 
createQuitWindow()948 void PlayingGameState::createQuitWindow() {
949     if( confirm_window == NULL && !game_g->isStateChanged() ) {
950 		confirm_type = CONFIRMTYPE_QUITGAME;
951 		confirm_window = new PanelPage(0, 0, default_width_c, default_height_c);
952 		confirm_window->setBackground(0, 0, 0, 200);
953 		const int offset_x_c = 80, offset_y_c = 100;
954 #if defined(__ANDROID__)
955 		confirm_button_1 = NULL; // if user wants to exit to homescreen, they can just press the Home button
956 #else
957 		confirm_button_1 = new Button(offset_x_c, offset_y_c, "SAVE GAME AND QUIT TO DESKTOP", game_g->letters_large);
958 		confirm_window->add(confirm_button_1);
959 #endif
960 		confirm_button_2 = new Button(offset_x_c, offset_y_c+16, "EXIT BATTLE", game_g->letters_large);
961 		confirm_window->add(confirm_button_2);
962 		confirm_button_3 = new Button(offset_x_c, offset_y_c+32, "CANCEL", game_g->letters_large);
963 		confirm_window->add(confirm_button_3);
964 		screen_page->add(confirm_window);
965 	}
966 	else if( confirm_window != NULL && !game_g->isStateChanged() ) {
967 		closeConfirmWindow();
968 	}
969 }
970 
readSectorsProcessLine(Map * map,char * line,bool * done_header,int * sec_x,int * sec_y)971 bool PlayingGameState::readSectorsProcessLine(Map *map, char *line, bool *done_header, int *sec_x, int *sec_y) {
972 	bool ok = true;
973 	line[ strlen(line) - 1 ] = '\0'; // trim new line
974 	line[ strlen(line) - 1 ] = '\0'; // trim carriage return
975 	if( !(*done_header) ) {
976 		if( line[0] != '#' ) {
977 			LOG("expected first character to be '#'\n");
978 			ok = false;
979 			return ok;
980 		}
981 		// ignore rest of header
982 		*done_header = true;
983 	}
984 	else {
985 		char *line_ptr = line;
986 		while( *line_ptr == ' ' || *line_ptr == '\t' ) // avoid initial whitespace
987 			line_ptr++;
988 		char *comment = strchr(line_ptr, '#');
989 		if( comment != NULL ) { // trim comments
990 			*comment = '\0';
991 		}
992 		char *ptr = strtok(line_ptr, " ");
993 		if( ptr == NULL ) {
994 			// this line may be a comment
995 		}
996 		else if( strcmp(ptr, "SECTOR") == 0 ) {
997 			ptr = strtok(NULL, " ");
998 			if( ptr == NULL ) {
999 				LOG("can't find sec_x\n");
1000 				ok = false;
1001 				return ok;
1002 			}
1003 			*sec_x = atoi(ptr);
1004 			if( *sec_x < 0 || *sec_x >= map_width_c ) {
1005 				LOG("invalid map x %d\n", *sec_x);
1006 				ok = false;
1007 				return ok;
1008 			}
1009 
1010 			ptr = strtok(NULL, " ");
1011 			if( ptr == NULL ) {
1012 				LOG("can't find sec_y\n");
1013 				ok = false;
1014 				return ok;
1015 			}
1016 			*sec_y = atoi(ptr);
1017 			if( *sec_y < 0 || *sec_y >= map_height_c ) {
1018 				LOG("invalid map y %d\n", *sec_y);
1019 				ok = false;
1020 				return ok;
1021 			}
1022 		}
1023 		else if( strcmp(ptr, "ELEMENT") == 0 ) {
1024 			if( *sec_x == -1 || *sec_y == -1 ) {
1025 				LOG("sector not defined\n");
1026 				ok = false;
1027 				return ok;
1028 			}
1029 			ptr = strtok(NULL, " ");
1030 			if( ptr == NULL ) {
1031 				LOG("can't find element name\n");
1032 				ok = false;
1033 				return ok;
1034 			}
1035 			/*char elementname[MAX_LINE+1] = "";
1036 			strcpy(elementname, ptr);*/
1037 			string elementname = ptr;
1038 
1039 			ptr = strtok(NULL, " ");
1040 			if( ptr == NULL ) {
1041 				LOG("can't find n_elements\n");
1042 				ok = false;
1043 				return ok;
1044 			}
1045 			int n_elements = atoi(ptr);
1046 
1047 			Id element = UNDEFINED;
1048 			for(int i=0;i<N_ID;i++) {
1049 				if( strcmp( game_g->elements[i]->getName(), elementname.c_str() ) == 0 ) {
1050 					element = (Id)i;
1051 				}
1052 			}
1053 			if( element == UNDEFINED ) {
1054 				LOG("unknown element: %s\n", elementname.c_str());
1055 				ok = false;
1056 				return ok;
1057 			}
1058 
1059 			game_g->getMap()->getSector(*sec_x, *sec_y)->setElements(element, n_elements);
1060 		}
1061 		else {
1062 			LOG("unknown word: %s\n", ptr);
1063 			ok = false;
1064 			return ok;
1065 		}
1066 	}
1067 	return ok;
1068 }
1069 
readSectors(Map * map)1070 bool PlayingGameState::readSectors(Map *map) {
1071 	bool ok = true;
1072 	const int MAX_LINE = 4096;
1073 	char line[MAX_LINE+1] = "";
1074 	int sec_x = -1, sec_y = -1;
1075 	bool done_header = false;
1076 
1077     char fullname[4096] = "";
1078 	sprintf(fullname, "%s/%s", maps_dirname, game_g->getMap()->getFilename());
1079 	// open in binary mode, so that we parse files in an OS-independent manner
1080 	// (otherwise, Windows will parse "\r\n" as being "\n", but Linux will still read it as "\n")
1081 	//FILE *file = fopen(fullname, "rb");
1082 	SDL_RWops *file = SDL_RWFromFile(fullname, "rb");
1083 #if !defined(__ANDROID__) && defined(__DragonFly__)
1084 	if( file == NULL ) {
1085 		LOG("searching in /usr/local/share/gigalomania/ for islands folder\n");
1086 		sprintf(fullname, "%s/%s", alt_maps_dirname, game_g->getMap()->getFilename());
1087 		file = SDL_RWFromFile(fullname, "rb");
1088 	}
1089 #endif
1090 	if( file == NULL ) {
1091 		LOG("failed to open file: %s\n", fullname);
1092 		//perror("perror returns: ");
1093 		return false;
1094 	}
1095 	char buffer[MAX_LINE+1] = "";
1096 	int buffer_offset = 0;
1097 	bool reached_end = false;
1098 	int newline_index = 0;
1099 	while( ok ) {
1100 		bool done = game_g->readLineFromRWOps(ok, file, buffer, line, MAX_LINE, buffer_offset, newline_index, reached_end);
1101 		if( !ok )  {
1102 			LOG("failed to read line\n");
1103 		}
1104 		else if( done ) {
1105 			break;
1106 		}
1107 		else {
1108 			ok = readSectorsProcessLine(map, line, &done_header, &sec_x, &sec_y);
1109 		}
1110 	}
1111 	file->close(file);
1112 
1113 	return ok;
1114 }
1115 
createSectors(int x,int y,int n_men)1116 void PlayingGameState::createSectors(int x, int y, int n_men) {
1117 	LOG("PlayingGameState::createSectors(%d, %d, %d)\n", x, y, n_men);
1118 
1119 	game_g->getMap()->createSectors(this, game_g->getStartEpoch());
1120 	Sector *sector = game_g->getMap()->getSector(x, y);
1121 	current_sector = sector;
1122 	if( !game_g->isDemo() ) {
1123 		sector->createTower(client_player, n_men);
1124 	}
1125 	//current_sector->createTower(human_player, 10);
1126 
1127 	//current_sector->getArmy(enemy_player)->soldiers[10] = 0;
1128 	//game_g->getMap()->sectors[2][2]->getArmy(enemy_player)->soldiers[0] = 10;
1129 
1130 	//Sector *enemy_sector = game_g->getMap()->sectors[1][2];
1131 
1132 	for(int i=0;i<n_players_c;i++) {
1133 		if( i == client_player || game_g->players[i] == NULL )
1134 			continue;
1135 		int ex = 0, ey = 0;
1136 		while( true ) {
1137 			game_g->getMap()->findRandomSector(&ex, &ey);
1138 			ASSERT( game_g->getMap()->isSectorAt(ex, ey) );
1139 			if( game_g->getMap()->getSector(ex, ey)->getPlayer() == -1 && !game_g->getMap()->isReserved(ex, ey) )
1140 				break;
1141 		}
1142 		//Sector *enemy_sector = game_g->getMap()->sectors[ex][ey];
1143 		Sector *enemy_sector = game_g->getMap()->getSector(ex, ey);
1144 		//enemy_sector->getArmy(enemy_player)->soldiers[10] = 30;
1145 		//enemy_sector->createTower(enemy_player, 12);
1146 		if( game_g->getStartEpoch() == end_epoch_c ) {
1147 			//game_g->players[i]->n_men_for_this_island = n_suspended[i];
1148 			game_g->players[i]->setNMenForThisIsland(100);
1149 		}
1150 		else {
1151 			game_g->players[i]->setNMenForThisIsland(20 + 5*game_g->getStartEpoch());
1152 			// total: 360*3 + 65 = 1145 men
1153 		}
1154 		LOG("Enemy %d created at %d , %d\n", i, ex, ey);
1155 		enemy_sector->createTower(i, game_g->players[i]->getNMenForThisIsland());
1156 		//enemy_sector->createTower(enemy_player, 20);
1157 		//enemy_sector->createTower(enemy_player, 200);
1158 	}
1159 
1160 	if( !readSectors(game_g->getMap()) ) {
1161 		LOG("failed to read map sector info!\n");
1162 		ASSERT(false);
1163 	}
1164 }
1165 
getGamePanel()1166 GamePanel *PlayingGameState::getGamePanel() {
1167 	return this->gamePanel;
1168 }
1169 
1170 /*Sector *PlayingGameState::getCurrentSector() {
1171 	return current_sector;
1172 }*/
1173 
getCurrentSector() const1174 const Sector *PlayingGameState::getCurrentSector() const {
1175 	return current_sector;
1176 }
1177 
viewingActiveClientSector() const1178 bool PlayingGameState::viewingActiveClientSector() const {
1179 	return this->getCurrentSector()->getActivePlayer() == client_player;
1180 }
1181 
viewingAnyClientSector() const1182 bool PlayingGameState::viewingAnyClientSector() const {
1183 	// includes shutdown sectors
1184 	return this->getCurrentSector()->getPlayer() == client_player;
1185 }
1186 
openPitMine()1187 bool PlayingGameState::openPitMine() {
1188 	if( current_sector->getActivePlayer() != -1 && current_sector->getBuilding(BUILDING_MINE) == NULL && current_sector->getEpoch() >= 1 ) {
1189 		for(int i=0;i<N_ID;i++) {
1190 			if( current_sector->anyElements((Id)i) ) {
1191 				Element *element = game_g->elements[i];
1192 				if( element->getType() == Element::OPENPITMINE )
1193 					return true;
1194 			}
1195 		}
1196 	}
1197 	return false;
1198 }
1199 
setupMapGUI()1200 void PlayingGameState::setupMapGUI() {
1201 	if( alliance_yes != NULL ) {
1202 		delete alliance_yes;
1203 		alliance_yes = NULL;
1204 	}
1205 	if( alliance_no != NULL ) {
1206 		delete alliance_no;
1207 		alliance_no = NULL;
1208 	}
1209 	for(int y=0;y<map_height_c;y++) {
1210 		for(int x=0;x<map_width_c;x++) {
1211 			if( map_panels[x][y] != NULL ) {
1212 				delete map_panels[x][y];
1213 				map_panels[x][y] = NULL;
1214 			}
1215 		}
1216 	}
1217 	if( this->player_asking_alliance != -1 ) {
1218 		alliance_yes = new Button(24, 82, "YES", game_g->letters_large);
1219 		alliance_yes->setInfoLMB("join the alliance");
1220 		screen_page->add(alliance_yes);
1221 		alliance_no = new Button(56, 82, "NO", game_g->letters_large);
1222 		alliance_no->setInfoLMB("refuse the alliance");
1223 		screen_page->add(alliance_no);
1224 	}
1225 	else if( this->map_display == MAPDISPLAY_MAP ) {
1226 		for(int y=0;y<map_height_c;y++) {
1227 			for(int x=0;x<map_width_c;x++) {
1228 				if( game_g->getMap()->isSectorAt(x, y) ) {
1229 					int map_x = offset_map_x_c + 16 * x;
1230 					int map_y = offset_map_y_c + 16 * y;
1231 					PanelPage *panel = new PanelPage(map_x, map_y, 16, 16);
1232 					panel->setTolerance(0); // since map sectors are aligned, better for touchscreens not to use the "tolerance"
1233 					panel->setInfoLMB("view this sector");
1234 					screen_page->add(panel);
1235 					//game_g->getMap()->panels[x][y] = panel;
1236 					map_panels[x][y] = panel;
1237 					char buffer[256] = "";
1238 					sprintf(buffer, "map_%d_%d", x, y);
1239 					map_panels[x][y]->setId(buffer);
1240 				}
1241 			}
1242 		}
1243 	}
1244 }
1245 
reset()1246 void PlayingGameState::reset() {
1247     //LOG("PlayingGameState::reset()\n");
1248 	if( current_sector == NULL )
1249 		return;
1250 
1251 	this->screen_page->free(true);
1252 	alliance_yes = NULL;
1253 	alliance_no = NULL;
1254 	tutorial_next_button = NULL;
1255 	for(int y=0;y<map_height_c;y++) {
1256 		for(int x=0;x<map_width_c;x++) {
1257 			map_panels[x][y] = NULL;
1258 		}
1259 	}
1260 	confirm_type = CONFIRMTYPE_UNKNOWN;
1261 	confirm_window = NULL;
1262 	confirm_button_1 = NULL;
1263 	confirm_button_2 = NULL;
1264 	confirm_button_3 = NULL;
1265 
1266 	if( this->gamePanel != NULL ) {
1267 		delete this->gamePanel;
1268 		this->gamePanel = NULL;
1269 	}
1270 
1271 	this->land_panel = new PanelPage(offset_land_x_c, offset_land_y_c, default_width_c - offset_land_x_c, default_height_c - offset_land_y_c - quit_button_offset_c);
1272 	screen_page->add(this->land_panel);
1273 
1274 	// setup screen_page buttons
1275 	this->setupMapGUI();
1276 
1277 	if( !game_g->isDemo() ) {
1278 		speed_button = new ImageButton(offset_map_x_c + 16 * map_width_c + 4, 4, game_g->icon_speeds[game_g->getTimeRate()-1]);
1279 		speed_button->setId("speed_button");
1280 		if( game_g->isOneMouseButton() ) {
1281 			speed_button->setInfoLMB("cycle through different time rates");
1282 		}
1283 		else {
1284 			speed_button->setInfoLMB("decrease the rate of time");
1285 			speed_button->setInfoRMB("increase the rate of time");
1286 		}
1287 		screen_page->add(speed_button);
1288 
1289 		//if( mobile_ui )
1290 		{
1291 			pause_button = new Button(default_width_c - 80, default_height_c - quit_button_offset_c, "PAUSE", game_g->letters_large);
1292 			pause_button->setId("pause_button");
1293 			screen_page->add(pause_button);
1294 			quit_button = new Button(default_width_c - 32, default_height_c - quit_button_offset_c, "QUIT", game_g->letters_large);
1295 			quit_button->setId("quit_button");
1296 			screen_page->add(quit_button);
1297 		}
1298 	}
1299 
1300 	for(int i=0;i<n_players_c;i++) {
1301 		shield_buttons[i] = NULL;
1302 		shield_number_panels[i] = NULL;
1303 	}
1304 	this->shield_blank_button = NULL;
1305 
1306 	resetShieldButtons();
1307 
1308 	for(int i=0;i<N_BUILDINGS;i++) {
1309 		Building *building = current_sector->getBuilding((Type)i);
1310 		if( building != NULL ) {
1311 			addBuilding(building);
1312 		}
1313 	}
1314 
1315 	// must be done after creating shield_number_panels
1316 	this->refreshSoldiers(false);
1317 
1318 	/*if( smokeParticleSystem != NULL ) {
1319 		delete smokeParticleSystem;
1320 	}
1321 	Building *building_factory = current_sector->getBuilding(BUILDING_FACTORY);
1322 	//Building *building_factory = current_sector->getBuilding(BUILDING_TOWER);
1323 	if( building_factory != NULL ) {
1324 		//smokeParticleSystem = new SmokeParticleSystem(smoke_image, offset_land_x_c + building_factory->getX(), offset_land_y_c + building_factory->getY());
1325 		smokeParticleSystem = new SmokeParticleSystem(smoke_image, offset_land_x_c + building_factory->getX() + 20, offset_land_y_c + building_factory->getY());
1326 	}*/
1327 	/*if( smokeParticleSystem == NULL ) {
1328 		smokeParticleSystem = new SmokeParticleSystem(smoke_image);
1329 	}*/
1330 
1331 	this->gamePanel = new GamePanel(this, this->client_player);
1332 	// must call setup last, in case it recalls member functions of PlayingGameState, that requires the buttons to have been initialised
1333 	this->gamePanel->setup();
1334 
1335 	if( game_g->getTutorial() != NULL ) {
1336 		const TutorialCard *card = game_g->getTutorial()->getCard();
1337 		if( card != NULL ) {
1338 			card->setGUI(this);
1339 		}
1340 		else {
1341 			GUIHandler::resetGUI(this);
1342 		}
1343 	}
1344 	if( LOGGING ) {
1345 		current_sector->printDebugInfo();
1346 	}
1347 }
1348 
resetShieldButtons()1349 void PlayingGameState::resetShieldButtons() {
1350 	bool done_shield[n_players_c];
1351 	for(int i=0;i<n_players_c;i++)
1352 		done_shield[i] = false;
1353 	for(int i=0;i<n_players_c;i++) {
1354 		if( shield_buttons[i] != NULL ) {
1355 			screen_page->remove(shield_buttons[i]);
1356 			delete shield_buttons[i];
1357 			shield_buttons[i] = NULL;
1358 		}
1359 		if( shield_number_panels[i] != NULL ) {
1360 			screen_page->remove(shield_number_panels[i]);
1361 			delete shield_number_panels[i];
1362 			shield_number_panels[i] = NULL;
1363 		}
1364 	}
1365 	if( shield_blank_button != NULL ) {
1366 		screen_page->remove(shield_blank_button);
1367 		delete shield_blank_button;
1368 		shield_blank_button = NULL;
1369 	}
1370 	int n_sides = 0;
1371 	for(int i=0;i<n_players_c;i++) {
1372 		if( !done_shield[i] && game_g->players[i] != NULL && !game_g->players[i]->isDead() ) {
1373 			bool allied[n_players_c];
1374 			for(int j=0;j<n_players_c;j++)
1375 				allied[j] = false;
1376 			allied[i] = true;
1377 			done_shield[i] = true;
1378 			for(int j=i+1;j<n_players_c;j++) {
1379 				if( Player::isAlliance(i, j) ) {
1380 					ASSERT( game_g->players[j] != NULL );
1381 					ASSERT( !game_g->players[j]->isDead() );
1382 					allied[j] = true;
1383 					done_shield[j] = true;
1384 				}
1385 			}
1386 			n_sides++;
1387 			shield_buttons[i] = new ImageButton(offset_map_x_c + 16 * map_width_c + 4, offset_map_y_c + shield_step_y_c * i + 8, game_g->playershields[ Player::getShieldIndex(allied) ]);
1388 			screen_page->add(shield_buttons[i]);
1389 			//shield_number_panels[i] = new PanelPage(offset_map_x_c + 16 * map_width_c + 4 + 16, offset_map_y_c + shield_step_y_c * i + 8, 20, 10);
1390 			shield_number_panels[i] = new PanelPage(offset_map_x_c + 16 * map_width_c + 4 + 16, offset_map_y_c + shield_step_y_c * i + 8, 20, shield_step_y_c);
1391 			screen_page->add(shield_number_panels[i]);
1392 		}
1393 	}
1394 	if( !game_g->isDemo() && n_sides > 2 ) {
1395 		for(int i=0;i<n_players_c;i++) {
1396 			if( shield_buttons[i] != NULL && i != client_player && !Player::isAlliance(i, client_player) ) {
1397 				shield_buttons[i]->setInfoLMB("make an alliance");
1398 			}
1399 		}
1400 	}
1401 	bool any_alliances = false;
1402 	for(int i=0;i<n_players_c && !any_alliances && !game_g->isDemo();i++) {
1403 		if( i != client_player && Player::isAlliance(i, client_player) ) {
1404 			any_alliances = true;
1405 			ASSERT( game_g->players[i] != NULL );
1406 			ASSERT( !game_g->players[i]->isDead() );
1407 		}
1408 	}
1409 	if( any_alliances ) {
1410 		shield_blank_button = new ImageButton(offset_map_x_c + 16 * map_width_c + 4, offset_map_y_c + 4*shield_step_y_c + 8, game_g->playershields[0]);
1411 		shield_blank_button->setInfoLMB("break current alliance");
1412 		screen_page->add(shield_blank_button);
1413 	}
1414 
1415 	refreshShieldNumberPanels();
1416 }
1417 
addBuilding(Building * building)1418 void PlayingGameState::addBuilding(Building *building) {
1419 	for(int j=0;j<building->getNTurrets();j++) {
1420 		screen_page->add(building->getTurretButton(j));
1421 	}
1422 	if( building->getBuildingButton() != NULL )
1423 		screen_page->add(building->getBuildingButton());
1424 }
1425 
setFlashingSquare(int xpos,int ypos)1426 void PlayingGameState::setFlashingSquare(int xpos,int ypos) {
1427 	if( this->player_asking_alliance == -1 && map_display == MAPDISPLAY_MAP ) {
1428 		FlashingSquare *square = new FlashingSquare(xpos, ypos);
1429 		this->effects.push_back(square);
1430 	}
1431 };
1432 
fadeScreen(bool out,int delay,void (* func_finish)())1433 void GameState::fadeScreen(bool out, int delay, void (*func_finish)()) {
1434     if( fade != NULL )
1435         delete fade;
1436 	if( game_g->isTesting() ) {
1437 		if( func_finish != NULL ) {
1438 			func_finish();
1439 		}
1440 	}
1441 	else {
1442 	    fade = new FadeEffect(false, out, delay, func_finish);
1443 	}
1444 }
1445 
whiteFlash()1446 void GameState::whiteFlash() {
1447 	//ASSERT( whitefade == NULL );
1448     if( whitefade != NULL )
1449         delete whitefade;
1450 	if( !game_g->isTesting() ) {
1451 	    whitefade = new FadeEffect(true, false, 0, NULL);
1452 	}
1453 }
1454 
getFlagOffset(int * offset_x,int * offset_y,int epoch) const1455 void PlayingGameState::getFlagOffset(int *offset_x, int *offset_y, int epoch) const {
1456 	if( game_g->isUsingOldGfx() ) {
1457 		*offset_x = 22;
1458 		*offset_y = 6;
1459 	}
1460 	else if( epoch == 6  || epoch ==7 ) {
1461 		// building towers have flat roof
1462 		*offset_x = 22;
1463 		*offset_y = 6;
1464 	}
1465 	else {
1466 		*offset_x = 21;
1467 		*offset_y = 2;
1468 	}
1469 }
1470 
draw()1471 void PlayingGameState::draw() {
1472 #if defined(__ANDROID__)
1473 	game_g->getScreen()->clear(); // SDL on Android requires screen be cleared (otherwise we get corrupt regions outside of the main area)
1474 #endif
1475 
1476 	game_g->background->draw(0, 0);
1477 	//background->draw(0, 0, true);
1478 
1479 	bool no_armies = true;
1480 	for(int i=0;i<n_players_c && no_armies;i++) {
1481 		const Army *army = current_sector->getArmy(i);
1482 		if( army->getTotal() > 0 )  {
1483 			no_armies = false;
1484 		}
1485 	}
1486 	if( no_armies && this->map_display == MAPDISPLAY_UNITS ) {
1487 		this->map_display = MAPDISPLAY_MAP;
1488 		this->reset();
1489 	}
1490 
1491 	if( this->player_asking_alliance != -1 ) {
1492 		// ask alliance
1493 		if( game_g->player_heads_alliance[player_asking_alliance] != NULL ) {
1494 			game_g->player_heads_alliance[player_asking_alliance]->draw(offset_map_x_c + 24, offset_map_y_c + 24);
1495 		}
1496 		stringstream str;
1497 		str << PlayerType::getName((PlayerType::PlayerTypeID)player_asking_alliance);
1498 		Image::write(offset_map_x_c + 8, offset_map_y_c + 0, game_g->letters_small, str.str().c_str(), Image::JUSTIFY_LEFT);
1499 		str.str("asks for an");
1500 		Image::write(offset_map_x_c + 8, offset_map_y_c + 8, game_g->letters_small, str.str().c_str(), Image::JUSTIFY_LEFT);
1501 		str.str("alliance");
1502 		Image::write(offset_map_x_c + 8, offset_map_y_c + 16, game_g->letters_small, str.str().c_str(), Image::JUSTIFY_LEFT);
1503 	}
1504 	else if( this->map_display == MAPDISPLAY_MAP ) {
1505 		// map
1506 
1507 		game_g->getMap()->draw(offset_map_x_c, offset_map_y_c);
1508 		for(int y=0;y<map_height_c;y++) {
1509 			for(int x=0;x<map_width_c;x++) {
1510 				if( game_g->getMap()->getSector(x, y) != NULL ) {
1511 					int map_x = offset_map_x_c + 16 * x;
1512 					int map_y = offset_map_y_c + 16 * y;
1513 					//map_sq[15]->draw(map_x, map_y, true);
1514 					if( game_g->getMap()->getSector(x, y)->getPlayer() != -1 ) {
1515 						game_g->icon_towers[ game_g->getMap()->getSector(x, y)->getPlayer() ]->draw(map_x + 5, map_y + 5);
1516 					}
1517 					else if( game_g->getMap()->getSector(x, y)->isNuked() ) {
1518 						game_g->icon_nuke_hole->draw(map_x + 4, map_y + 4);
1519 					}
1520 					for(int i=0;i<n_players_c;i++) {
1521 						Army *army = game_g->getMap()->getSector(x, y)->getArmy(i);
1522 						int n_army = army->getTotal();
1523 						if( n_army > 0 ) {
1524 							int off_step = 5;
1525 							int off_step_x = ( i == 0 || i == 2 ) ? -off_step : off_step;
1526 							int off_step_y = ( i == 0 || i == 1 ) ? -off_step : off_step;
1527 							game_g->icon_armies[i]->draw(map_x + 6 + off_step_x, map_y + 6 + off_step_y);
1528 						}
1529 					}
1530 				}
1531 			}
1532 		}
1533 		int map_x = offset_map_x_c + 16 * current_sector->getXPos();
1534 		int map_y = offset_map_y_c + 16 * current_sector->getYPos();
1535 		game_g->mapsquare->draw(map_x, map_y);
1536 	}
1537 	else if( this->map_display == MAPDISPLAY_UNITS ) {
1538 		// unit stats
1539 		const int gap = 18;
1540 		const int extra = 0;
1541 		for(int i=0;i<=game_g->getNSubEpochs();i++) {
1542 			Image *image = (i==0) ? game_g->unarmed_man : game_g->numbered_weapons[game_g->getStartEpoch() + i - 1];
1543 			//Image *image = (i==0) ? men[game_g->getStartEpoch()] : numbered_weapons[game_g->getStartEpoch() + i - 1];
1544 			image->draw(offset_map_x_c + gap * i + extra, offset_map_y_c + 2 - 16 + 8);
1545 		}
1546 		for(int i=0;i<n_players_c;i++) {
1547 			if( shield_buttons[i] == NULL ) {
1548 				continue;
1549 			}
1550 			int off = 0;
1551 			for(int j=i;j<n_players_c;j++) {
1552 				if( j == i || Player::isAlliance(i, j) ) {
1553 					const Army *army = current_sector->getArmy(j);
1554 					if( army->getTotal() > 0 ) {
1555 						for(int k=0;k<=game_g->getNSubEpochs();k++) {
1556 							int idx = (k==0) ? 10 : game_g->getStartEpoch() + k - 1;
1557 							int n_men = army->getSoldiers(idx);
1558 							if( n_men > 0 ) {
1559 								//Image::writeNumbers(offset_map_x_c + 16 * k + 4, offset_map_y_c + 2 + 16 * i + 8 * off + 8, game_g->numbers_small[j], n_men, Image::JUSTIFY_LEFT, true);
1560 								Image::writeNumbers(offset_map_x_c + gap * k + extra, offset_map_y_c + 2 + 16 * i + 8 * off + 8, game_g->numbers_small[j], n_men, Image::JUSTIFY_LEFT);
1561 							}
1562 						}
1563 						off++;
1564 					}
1565 				}
1566 			}
1567 		}
1568 	}
1569 
1570 	// land area
1571 	game_g->land[game_g->getMap()->getColour()]->draw(offset_land_x_c, offset_land_y_c);
1572 
1573 	// trees etc (not at front)
1574 	for(int i=0;i<current_sector->getNFeatures();i++) {
1575 		const Feature *feature = current_sector->getFeature(i);
1576 		if( !feature->isAtFront() ) {
1577 			feature->draw();
1578 		}
1579 	}
1580 
1581 	if( current_sector->getActivePlayer() != -1 )
1582 	{
1583 		if( openPitMine() )
1584 			game_g->icon_openpitmine->draw(offset_land_x_c + offset_openpitmine_x_c, offset_land_y_c + offset_openpitmine_y_c);
1585 
1586 		bool rotate_defenders = false;
1587 		if( game_g->getGameTime() - defenders_last_time_update > defenders_ticks_per_update_c ) {
1588 			rotate_defenders = true;
1589 			defenders_last_time_update = game_g->getGameTime();
1590 		}
1591 
1592 		for(int i=0;i<N_BUILDINGS;i++) {
1593 			Building *building = current_sector->getBuilding((Type)i);
1594 			if( building == NULL )
1595 				continue;
1596 
1597 			// draw building
1598 			Image **images = building->getImages();
1599 			images[ current_sector->getBuildingEpoch() ]->draw(offset_land_x_c + building->getX(), offset_land_y_c + building->getY());
1600 
1601 			if( rotate_defenders )
1602 				building->rotateDefenders();
1603 
1604 			// draw defenders
1605 			for(int j=0;j<building->getNTurrets();j++) {
1606 				// uncomment to draw turrent button regions:
1607 				/*{
1608 					PanelPage *button = building->getTurretButton(j);
1609 					game_g->getScreen()->fillRectWithAlpha(game_g->getScaleWidth()*button->getLeft(), game_g->getScaleHeight()*button->getTop(), game_g->getScaleWidth()*button->getWidth(), game_g->getScaleHeight()*button->getHeight(), 255, 0, 0, 127);
1610 				}*/
1611 
1612 				if( building->getTurretMan(j) != -1 ) {
1613 					Image *image = NULL;
1614 					int defender_epoch = building->getTurretMan(j);
1615 					if( defender_epoch == nuclear_epoch_c ) {
1616 						image = game_g->nuke_defences[current_sector->getPlayer()];
1617 					}
1618 					else {
1619 						image = game_g->defenders[current_sector->getPlayer()][defender_epoch][ building->getTurretManFrame(j) % game_g->n_defender_frames[defender_epoch] ];
1620 					}
1621 					image->draw(building->getTurretButton(j)->getLeft(), building->getTurretButton(j)->getTop() - 4);
1622 				}
1623 			}
1624 
1625 			if( i == BUILDING_TOWER ) {
1626 				int offset_x = 0, offset_y = 0;
1627 				getFlagOffset(&offset_x, &offset_y, current_sector->getBuildingEpoch());
1628 				game_g->flags[ current_sector->getPlayer() ][game_g->getFrameCounter() % n_flag_frames_c]->draw(offset_land_x_c + building->getX() + offset_x, offset_land_y_c + building->getY() + offset_y);
1629 			}
1630 
1631 			int width = game_g->building_health->getScaledWidth();
1632 			int health = building->getHealth();
1633 			int max_health = building->getMaxHealth();
1634 			int offx = offset_land_x_c + building->getX() + 4;
1635 			int offy = offset_land_y_c + building->getY() + images[ current_sector->getBuildingEpoch() ]->getScaledHeight() + 2;
1636 			game_g->building_health->draw(offx, offy, (int)((width*health)/(float)max_health), game_g->building_health->getScaledHeight());
1637 		}
1638 	}
1639 	else if( current_sector->getPlayer() != -1 ) {
1640 		ASSERT( current_sector->isShutdown() );
1641 		Building *building = current_sector->getBuilding(BUILDING_TOWER);
1642 		ASSERT( building != NULL );
1643 		Image **images = building->getImages();
1644 		images[ current_sector->getBuildingEpoch() ]->draw(offset_land_x_c + building->getX(), offset_land_y_c + building->getY());
1645 		int offset_x = 0, offset_y = 0;
1646 		getFlagOffset(&offset_x, &offset_y, current_sector->getBuildingEpoch());
1647 		game_g->flags[ current_sector->getPlayer() ][game_g->getFrameCounter() % n_flag_frames_c]->draw(offset_land_x_c + building->getX() + offset_x, offset_land_y_c + building->getY() + offset_y);
1648 	}
1649 
1650 	//Vector soldier_list(n_players_c * 250);
1651 	int n_total_soldiers = 0;
1652 	for(int i=0;i<n_players_c;i++) {
1653 		n_total_soldiers += soldiers[i].size();
1654 	}
1655 	Soldier **soldier_list = new Soldier *[n_total_soldiers];
1656 	for(int i=0,c=0;i<n_players_c;i++) {
1657 		//for(int j=0;j<n_soldiers[i];j++) {
1658 		for(size_t j=0;j<soldiers[i].size();j++) {
1659 			//Soldier *soldier = soldiers[i][j];
1660 			//Soldier *soldier = (Soldier *)soldiers[i]->get(j);
1661 			Soldier *soldier = soldiers[i].at(j);
1662 			//soldier_list.add(soldier);
1663 			soldier_list[c++] = soldier;
1664 		}
1665 	}
1666 	//Soldier::sortSoldiers((Soldier **)soldier_list.getData(), soldier_list.size());
1667 	Soldier::sortSoldiers(soldier_list, n_total_soldiers);
1668 	// draw land units
1669 	/*for(int i=0;i<soldier_list.size();i++) {
1670 	Soldier *soldier = (Soldier *)soldier_list.elementAt(i);*/
1671 	for(int i=0;i<n_total_soldiers;i++) {
1672 		Soldier *soldier = soldier_list[i];
1673 		ASSERT(soldier->epoch != nuclear_epoch_c);
1674 		if( !isAirUnit(soldier->epoch) ) {
1675 			//int frame = soldier->dir * 4 + ( game_g->getFrameCounter() % 3 );
1676 			//Image *image = attackers_walking[soldier->player][soldier->epoch][frame];
1677 			int n_frames = game_g->n_attacker_frames[soldier->epoch][soldier->dir];
1678 			Image *image = game_g->attackers_walking[soldier->player][soldier->epoch][soldier->dir][game_g->getFrameCounter() % n_frames];
1679 			image->draw(offset_land_x_c + soldier->xpos, offset_land_y_c + soldier->ypos);
1680 		}
1681 	}
1682 
1683 	// trees etc (at front)
1684 	for(int i=0;i<current_sector->getNFeatures();i++) {
1685 		const Feature *feature = current_sector->getFeature(i);
1686 		if( feature->isAtFront() ) {
1687 			feature->draw();
1688 		}
1689 	}
1690 
1691 	for(int i=effects.size()-1;i>=0;i--) {
1692 		TimedEffect *effect = effects.at(i);
1693 		if( effect->render() ) {
1694 			effects.erase(effects.begin() + i);
1695 			delete effect;
1696 		}
1697 	}
1698 	for(int i=ammo_effects.size()-1;i>=0;i--) {
1699 		TimedEffect *effect = ammo_effects.at(i);
1700 		if( effect->render() ) {
1701 			ammo_effects.erase(ammo_effects.begin() + i);
1702 			delete effect;
1703 		}
1704 	}
1705 
1706 	// draw air units
1707 	/*for(int i=0;i<soldier_list.size();i++) {
1708 	Soldier *soldier = (Soldier *)soldier_list.elementAt(i);*/
1709 	for(int i=0;i<n_total_soldiers;i++) {
1710 		Soldier *soldier = soldier_list[i];
1711 		ASSERT(soldier->epoch != nuclear_epoch_c);
1712 		if( isAirUnit(soldier->epoch) ) {
1713 			Image *image = NULL;
1714 			if( soldier->epoch == 6 || soldier->epoch == 7 ) {
1715 				image = game_g->planes[soldier->player][soldier->epoch];
1716 			}
1717 			else if( soldier->epoch == 9 ) {
1718 				int frame = game_g->getFrameCounter() % 3;
1719 				image = game_g->saucers[soldier->player][frame];
1720 			}
1721 			ASSERT(image != NULL);
1722 			image->draw(offset_land_x_c + soldier->xpos, offset_land_y_c + soldier->ypos);
1723 			if( soldier->epoch == 7 ) {
1724 				if( current_sector->getJetParticleSystem() != NULL ) {
1725 					current_sector->getJetParticleSystem()->draw(offset_land_x_c + soldier->xpos + 17, offset_land_y_c + soldier->ypos + 17);
1726 				}
1727 			}
1728 		}
1729 	}
1730 	delete [] soldier_list;
1731 
1732 	// nuke
1733 	int nuke_time = -1;
1734 	int nuke_by_player = current_sector->beingNuked(&nuke_time);
1735 	if( nuke_by_player != -1 ) {
1736 		int xpos = -1, ypos = -1;
1737 		current_sector->getNukePos(&xpos, &ypos);
1738 		game_g->nukes[nuke_by_player][1]->draw(xpos, ypos);
1739 		if( current_sector->getNukeParticleSystem() != NULL ) {
1740 			current_sector->getNukeParticleSystem()->draw(xpos + 23 - 4, ypos + 2 - 4);
1741 		}
1742 	}
1743 	// nuke defence
1744 	int nuke_defence_time = -1;
1745 	int nuke_defence_x = 0;
1746 	int nuke_defence_y = 0;
1747 	if( current_sector->hasNuclearDefenceAnimation(&nuke_defence_time, &nuke_defence_x, &nuke_defence_y) ) {
1748 		ASSERT( nuke_defence_time != -1 );
1749 		float alpha = ((float)( game_g->getGameTime() - nuke_defence_time )) / (float)nuke_delay_c;
1750 		ASSERT( alpha >= 0.0 );
1751 		if( alpha > 1.0 )
1752 			alpha = 1.0;
1753 		int ey = nuke_defence_y - 200;
1754 		int ypos = (int)(alpha * ey + (1.0 - alpha) * nuke_defence_y);
1755 		game_g->nukes[current_sector->getPlayer()][0]->draw(nuke_defence_x, ypos);
1756 		if( current_sector->getNukeDefenceParticleSystem() != NULL ) {
1757 			current_sector->getNukeDefenceParticleSystem()->draw(nuke_defence_x + 4 - 4, ypos + 31 - 4);
1758 		}
1759 	}
1760 
1761 	// playershields etc
1762 	for(int i=0;i<n_players_c;i++) {
1763 		if( game_g->players[i] != NULL && !game_g->players[i]->isDead() ) {
1764 			//ASSERT( shield_buttons[i] != NULL );
1765 			if( shield_buttons[i] == NULL ) {
1766 				continue;
1767 			}
1768 			shield_number_panels[i]->setVisible(false);
1769 			/*int n_allied = 1;
1770 			for(j=i+1;j<n_players_c;j++) {
1771 			if( Player::isAlliance(i, j) ) {
1772 			n_allied++;
1773 			}
1774 			}*/
1775 			//playershields[ game_g->players[i]->getShieldIndex()  ]->draw(offset_map_x_c + 16 * map_width_c + 4, offset_map_y_c + shield_step_y_c * i + 8, true);
1776 			int off = 0;
1777 			for(int j=i;j<n_players_c;j++) {
1778 				if( j == i || Player::isAlliance(i, j) ) {
1779 					const Army *army = current_sector->getArmy(j);
1780 					int n_army = army->getTotal();
1781 					if( n_army > 0 ) {
1782 						shield_number_panels[i]->setVisible(true);
1783 						//Image::writeNumbers(offset_map_x_c + 16 * map_width_c + 20, offset_map_y_c + 2 + shield_step_y_c * i + 8, game_g->numbers_small[i], n_army, Image::JUSTIFY_LEFT, true);
1784 						Image::writeNumbers(offset_map_x_c + 16 * map_width_c + 20, offset_map_y_c + 2 + shield_step_y_c * i + 8 * off + 8, game_g->numbers_small[j], n_army, Image::JUSTIFY_LEFT);
1785 						off++;
1786 					}
1787 				}
1788 			}
1789 		}
1790 	}
1791 
1792 	// panel
1793 	if( game_g->getTutorial() != NULL ) {
1794 		const TutorialCard *card = game_g->getTutorial()->getCard();
1795 		if( card != NULL ) {
1796 			const unsigned char tutorial_alpha_c = 127;
1797 			int n_lines = 0, max_wid = 0;
1798 			int s_w = game_g->letters_small[0]->getScaledWidth();
1799 			int l_w = game_g->letters_large[0]->getScaledWidth();
1800 			int l_h = game_g->letters_large[0]->getScaledHeight();
1801 			textLines(&n_lines, &max_wid, card->getText().c_str(), s_w, l_w);
1802 
1803 			Rect2D rect;
1804 			rect.x = 100;
1805 			rect.y = 130;
1806 			rect.w = max_wid;
1807 			rect.h = n_lines * (l_h + 2);
1808 			const Image *player_image = game_g->player_heads_alliance[client_player];
1809 			if( player_image != NULL ) {
1810 				player_image->draw(rect.x, rect.y - player_image->getScaledHeight());
1811 			}
1812 #if SDL_MAJOR_VERSION == 1
1813 			Image *fill_rect = Image::createBlankImage(game_g->getScaleWidth()*rect.w, game_g->getScaleHeight()*rect.h, 24);
1814 			fill_rect->fillRect(0, 0, game_g->getScaleWidth()*rect.w, game_g->getScaleHeight()*rect.h, 0, 0, 0);
1815 			fill_rect->convertToDisplayFormat();
1816 			fill_rect->drawWithAlpha(game_g->getScaleWidth()*rect.x, game_g->getScaleHeight()*rect.y, tutorial_alpha_c);
1817 			delete fill_rect;
1818 #else
1819 			game_g->getScreen()->fillRectWithAlpha((short)(game_g->getScaleWidth()*rect.x), (short)(game_g->getScaleHeight()*rect.y), (short)(game_g->getScaleWidth()*rect.w), (short)(game_g->getScaleHeight()*rect.h), 0, 0, 0, tutorial_alpha_c);
1820 #endif
1821 			Image::writeMixedCase(rect.x, rect.y, game_g->letters_large, game_g->letters_small, game_g->numbers_white, card->getText().c_str(), Image::JUSTIFY_LEFT);
1822 			if( card->hasArrow(this) ) {
1823 				int arrow_x = card->getArrowX();
1824 				int arrow_y = card->getArrowY();
1825 				int src_x = rect.x - 4;
1826 				int src_y = (int)(rect.y + 0.5*rect.h);
1827 				if( arrow_x >= rect.x + rect.w ) {
1828 					src_x = rect.x + rect.w + 4;
1829 				}
1830 				else if( arrow_x >= rect.x && arrow_x < rect.x + rect.w ) {
1831 					src_x = (int)(rect.x + 0.5*rect.w);
1832 					if( arrow_y < src_y ) {
1833 						src_y = rect.y - 4;
1834 					}
1835 					else {
1836 						src_y = rect.y + rect.h + 4;
1837 					}
1838 				}
1839 				game_g->getScreen()->drawLine((short)(game_g->getScaleWidth()*src_x), (short)(game_g->getScaleHeight()*src_y), (short)(game_g->getScaleWidth()*arrow_x), (short)(game_g->getScaleHeight()*arrow_y), 255, 255, 255);
1840 			}
1841 
1842 			if( !card->autoProceed() && card->canProceed(this) ) {
1843 				if( tutorial_next_button == NULL ) {
1844 					textLines(&n_lines, &max_wid, card->getNextText().c_str(), l_w, l_w);
1845 					tutorial_next_button = new Button(rect.x + rect.w - max_wid, rect.y + rect.h + 4, card->getNextText().c_str(), game_g->letters_large);
1846 					tutorial_next_button->setBackground(0, 0, 0, tutorial_alpha_c);
1847 					screen_page->add(tutorial_next_button);
1848 				}
1849 			}
1850 			else {
1851 				if( tutorial_next_button != NULL ) {
1852 					delete tutorial_next_button;
1853 					tutorial_next_button = NULL;
1854 				}
1855 			}
1856 			if( card->autoProceed() && card->canProceed(this) ) {
1857 				game_g->getTutorial()->proceed();
1858 				const TutorialCard *new_card = game_g->getTutorial()->getCard();
1859 				if( new_card != NULL ) {
1860 					new_card->setGUI(this);
1861 				}
1862 				else {
1863 					GUIHandler::resetGUI(this);
1864 				}
1865 			}
1866 		}
1867 	}
1868 
1869 	this->gamePanel->draw();
1870 	//this->gamePanel->drawPopups();
1871 
1872 	this->screen_page->draw();
1873 	//this->screen_page->drawPopups();
1874 
1875 	/*if( smokeParticleSystem != NULL ) {
1876 		const Building *building_factory = current_sector->getBuilding(BUILDING_FACTORY);
1877 		//const Building *building_factory = current_sector->getBuilding(BUILDING_TOWER);
1878 		if( building_factory != NULL ) {
1879 			const SmokeParticleSystem *ps = ( current_sector->getWorkers() > 0 ) ? smokeParticleSystem_busy : smokeParticleSystem;
1880 			ps->draw(offset_land_x_c + building_factory->getX() + 17, offset_land_y_c + building_factory->getY() + 2);
1881 		}
1882 	}*/
1883 	if( current_sector->getSmokeParticleSystem() != NULL ) {
1884 		const Building *building_factory = current_sector->getBuilding(BUILDING_FACTORY);
1885 		//const Building *building_factory = current_sector->getBuilding(BUILDING_TOWER);
1886 		if( building_factory != NULL ) {
1887 			current_sector->getSmokeParticleSystem()->draw(offset_land_x_c + building_factory->getX() + 17, offset_land_y_c + building_factory->getY() + 2);
1888 		}
1889 	}
1890 
1891 	if( text_effect != NULL && text_effect->render() ) {
1892 		delete text_effect;
1893 		text_effect = NULL;
1894 	}
1895 
1896 	// mouse pointer
1897 	GameState::setDefaultMouseImage();
1898 	mouse_off_x = 0;
1899 	mouse_off_y = 0;
1900 	if( game_g->getGameStateID() == GAMESTATEID_PLAYING ) {
1901 		GamePanel::MouseState mousestate = gamePanel->getMouseState();
1902 		if( mousestate == GamePanel::MOUSESTATE_DEPLOY_WEAPON || selected_army != NULL ) {
1903 			ASSERT( mousestate != GamePanel::MOUSESTATE_DEPLOY_WEAPON || selected_army == NULL );
1904 			bool bloody = false;
1905 			const Sector *this_sector = ( selected_army == NULL ) ? current_sector : selected_army->getSector();
1906 			if( this_sector->getPlayer() != client_player ) {
1907 				if( this_sector->getPlayer() != PLAYER_NONE && !Player::isAlliance(this_sector->getPlayer(), client_player) )
1908 					bloody = true;
1909 				for(int i=0;i<n_players_c && !bloody;i++) {
1910 					if( i != client_player && !Player::isAlliance(i, client_player) ) {
1911 						if( this_sector->getArmy(i)->any(true) )
1912 							bloody = true;
1913 					}
1914 				}
1915 			}
1916 			if( bloody )
1917 				mouse_image = game_g->panel_bloody_attack;
1918 			else
1919 				mouse_image = game_g->panel_attack;
1920 			mobile_ui_display_mouse = true;
1921 		}
1922 		else if( mousestate == GamePanel::MOUSESTATE_DEPLOY_DEFENCE ) {
1923 			mouse_image = game_g->panel_defence;
1924 			//m_x -= mouse_image->getScaledWidth() / 2;
1925 			//m_y -= mouse_image->getScaledHeight() / 2;
1926 			mouse_off_x = - mouse_image->getScaledWidth() / 2;
1927 			mouse_off_y = - mouse_image->getScaledHeight() / 2;
1928 			mobile_ui_display_mouse = true;
1929 		}
1930 		else if( mousestate == GamePanel::MOUSESTATE_DEPLOY_SHIELD ) {
1931 			mouse_image = game_g->panel_shield;
1932 			mobile_ui_display_mouse = true;
1933 			//m_x -= mouse_image->getScaledWidth() / 2;
1934 			//m_y -= mouse_image->getScaledHeight() / 2;
1935 			mouse_off_x = - mouse_image->getScaledWidth() / 2;
1936 			mouse_off_y = - mouse_image->getScaledHeight() / 2;
1937 		}
1938 		else if( mousestate == GamePanel::MOUSESTATE_SHUTDOWN ) {
1939 			mouse_image = game_g->men[n_epochs_c-1];
1940 			mouse_off_x = - mouse_image->getScaledWidth() / 2;
1941 			mouse_off_y = - mouse_image->getScaledHeight() / 2;
1942 			mobile_ui_display_mouse = true;
1943 		}
1944 	}
1945 
1946 	GameState::draw();
1947 }
1948 
update()1949 void PlayingGameState::update() {
1950 	/*if( this->smokeParticleSystem != NULL ) {
1951 		if( current_sector->getWorkers() > 0 ) {
1952 			this->smokeParticleSystem->setBirthRate(0.008f);
1953 		}
1954 		else {
1955 			this->smokeParticleSystem->setBirthRate(0.004f);
1956 		}
1957 	}*/
1958 	int move_soldier_step_x = 0;
1959 	int move_soldier_step_y = 0;
1960 	int move_cannon_step_x = 0;
1961 	int move_cannon_step_y = 0;
1962 	int move_air_step = 0;
1963 	if( soldier_last_time_moved_x == -1 )
1964 		soldier_last_time_moved_x = game_g->getGameTime();
1965 	if( soldier_last_time_moved_y == -1 )
1966 		soldier_last_time_moved_y = game_g->getGameTime();
1967 	if( cannon_last_time_moved_x == -1 )
1968 		cannon_last_time_moved_x = game_g->getGameTime();
1969 	if( cannon_last_time_moved_y == -1 )
1970 		cannon_last_time_moved_y = game_g->getGameTime();
1971 	if( air_last_time_moved == -1 )
1972 		air_last_time_moved = game_g->getGameTime();
1973 	// move twice as fast in x direction, to simulate 3D look
1974 	while( game_g->getGameTime() - soldier_last_time_moved_x > soldier_move_rate_c ) {
1975 		move_soldier_step_x++;
1976 		soldier_last_time_moved_x += soldier_move_rate_c;
1977 	}
1978 	while( game_g->getGameTime() - soldier_last_time_moved_y > 2*soldier_move_rate_c ) {
1979 		move_soldier_step_y++;
1980 		soldier_last_time_moved_y += 2*soldier_move_rate_c;
1981 	}
1982 	while( game_g->getGameTime() - cannon_last_time_moved_x > cannon_move_rate_c ) {
1983 		move_cannon_step_x++;
1984 		cannon_last_time_moved_x += cannon_move_rate_c;
1985 	}
1986 	while( game_g->getGameTime() - cannon_last_time_moved_y > 2*cannon_move_rate_c ) {
1987 		move_cannon_step_y++;
1988 		cannon_last_time_moved_y += 2*cannon_move_rate_c;
1989 	}
1990 	while( game_g->getGameTime() - air_last_time_moved > air_move_rate_c ) {
1991 		move_air_step++;
1992 		air_last_time_moved += air_move_rate_c;
1993 	}
1994 	/*bool move_soldiers = ( game_g->getGameTime() - soldiers_last_time_moved > soldier_move_rate_c );
1995 	bool move_air = ( game_g->getGameTime() - air_last_time_moved > air_move_rate_c );
1996 	if( move_soldiers )
1997 	soldiers_last_time_moved = game_g->getGameTime();
1998 	if( move_air )
1999 	air_last_time_moved = game_g->getGameTime();*/
2000 	int time_interval = game_g->getLoopTime();
2001 
2002 	int n_armies = 0;
2003 	for(int i=0;i<n_players_c;i++) {
2004 		const Army *army = current_sector->getArmy(i);
2005 		if( army->getTotal() > 0 )
2006 			n_armies++;
2007 	}
2008 	bool combat = false;
2009 	if( n_armies >= 2 || ( current_sector->getPlayer() != -1 && current_sector->enemiesPresent() ) ) {
2010 		combat = true;
2011 	}
2012 
2013 	int fire_prob = poisson(soldier_turn_rate_c, time_interval);
2014 	for(int i=0;i<n_players_c;i++) {
2015 		//for(int j=0;j<n_soldiers[i];j++) {
2016 		for(size_t j=0;j<soldiers[i].size();j++) {
2017 			//Soldier *soldier = soldiers[i][j];
2018 			//Soldier *soldier = (Soldier *)soldiers[i]->get(j);
2019 			Soldier *soldier = soldiers[i].at(j);
2020 			//if( soldier->epoch == 6 || soldier->epoch == 7 || soldier->epoch == 9 ) {
2021 			if( isAirUnit(soldier->epoch) ) {
2022 				// air unit
2023 				if( move_air_step > 0 ) {
2024 					soldier->xpos -= move_air_step;
2025 					soldier->ypos -= move_air_step;
2026 					while( soldier->xpos < - offset_land_x_c - 32 )
2027 						soldier->xpos += default_width_c + 64;
2028 					while( soldier->ypos < - offset_land_y_c - 32 )
2029 						soldier->ypos += default_height_c + 64;
2030 				}
2031 				if( combat ) {
2032 					int fire_random = rand() % RAND_MAX;
2033 					if( fire_random <= fire_prob ) {
2034 						// fire!
2035 						AmmoEffect *ammoeffect = new AmmoEffect( this, soldier->epoch, ATTACKER_AMMO_BOMB, soldier->xpos + 4, soldier->ypos + 8 );
2036 						this->ammo_effects.push_back(ammoeffect);
2037 					}
2038 				}
2039 			}
2040 			else {
2041 				if( !validSoldierLocation(soldier->epoch,soldier->xpos, soldier->ypos) ) {
2042 					/* Soldier is already invalid location. This usually happens if the scenery suddenly
2043 					* changes (eg, new building appearing). If this happens, find a new valid locaation.
2044 					*/
2045 					bool found_loc = false;
2046 					while(!found_loc) {
2047 						soldier->xpos = rand() % land_width_c;
2048 						soldier->ypos = rand() % land_height_c;
2049 						found_loc = validSoldierLocation(soldier->epoch, soldier->xpos, soldier->ypos);
2050 					}
2051 				}
2052 				/* Turns are modelled as a Poisson distribution - so soldier_turn_rate_c is the mean number of
2053 				* ticks that elapse per turn. Therefore we are interested in the probability that at least one
2054 				* turn occured within this time interval.
2055 				*/
2056 				/*double prob = 1.0 - exp( - ((double)time_interval) / soldier_turn_rate_c );
2057 				double random = ((double)( rand() % RAND_MAX )) / (double)RAND_MAX;*/
2058 				//double prob = RAND_MAX * ( 1.0 - exp( - ((double)time_interval) / soldier_turn_rate_c ) );
2059 				int prob = poisson(soldier_turn_rate_c, time_interval);
2060 				int random = rand() % RAND_MAX;
2061 				if( random <= prob ) {
2062 					// turn!
2063 					soldier->dir = (AmmoDirection)(rand() % 4);
2064 				}
2065 				int move_step = 0;
2066 				if( soldier->epoch == cannon_epoch_c )
2067 					move_step = (soldier->dir == 0 || soldier->dir == 1) ? move_cannon_step_y : move_cannon_step_x;
2068 				else
2069 					move_step = (soldier->dir == 0 || soldier->dir == 1) ? move_soldier_step_y : move_soldier_step_x;
2070 				if( move_step > 0  ) {
2071 					int step_x = 0;
2072 					int step_y = 0;
2073 					if( soldier->dir == 0 )
2074 						step_y = move_step;
2075 					else if( soldier->dir == 1 )
2076 						step_y = - move_step;
2077 					else if( soldier->dir == 2 )
2078 						step_x = move_step;
2079 					else if( soldier->dir == 3 )
2080 						step_x = - move_step;
2081 
2082 					int new_xpos = soldier->xpos + step_x;
2083 					int new_ypos = soldier->ypos + step_y;
2084 					if( !validSoldierLocation(soldier->epoch,new_xpos, new_ypos) ) {
2085 						// path blocked, so turn around
2086 						new_xpos = soldier->xpos;
2087 						new_ypos = soldier->ypos;
2088 						if( soldier->dir == 0 )
2089 							soldier->dir = (AmmoDirection)1;
2090 						else if( soldier->dir == 1 )
2091 							soldier->dir = (AmmoDirection)0;
2092 						else if( soldier->dir == 2 )
2093 							soldier->dir = (AmmoDirection)3;
2094 						else if( soldier->dir == 3 )
2095 							soldier->dir = (AmmoDirection)2;
2096 					}
2097 					soldier->xpos = new_xpos;
2098 					soldier->ypos = new_ypos;
2099 				}
2100 
2101 				if( combat && soldier->epoch != n_epochs_c ) {
2102 					int fire_random = rand() % RAND_MAX;
2103 					if( fire_random <= fire_prob ) {
2104 						// fire!
2105 						Image *image = game_g->attackers_walking[soldier->player][soldier->epoch][soldier->dir][0];
2106 						int xpos = 0, ypos = 0;
2107 						if( soldier->epoch == cannon_epoch_c ) {
2108 							xpos = soldier->xpos;
2109 							ypos = soldier->ypos;
2110 							if( soldier->dir == ATTACKER_AMMO_LEFT ) {
2111 								xpos = soldier->xpos;
2112 								ypos = soldier->ypos;
2113 							}
2114 							else if( soldier->dir == ATTACKER_AMMO_RIGHT ) {
2115 								xpos = soldier->xpos + image->getScaledWidth();
2116 								ypos = soldier->ypos;
2117 							}
2118 							else if( soldier->dir == ATTACKER_AMMO_UP ) {
2119 								xpos = soldier->xpos + image->getScaledWidth()/4;
2120 								ypos = soldier->ypos;
2121 							}
2122 							else if( soldier->dir == ATTACKER_AMMO_DOWN ) {
2123 								xpos = soldier->xpos + image->getScaledWidth()/4;
2124 								ypos = soldier->ypos + image->getScaledHeight();
2125 							}
2126 						}
2127 						else {
2128 							xpos = soldier->xpos + image->getScaledWidth()/2;
2129 							ypos = soldier->ypos;
2130 						}
2131 						AmmoEffect *ammoeffect = new AmmoEffect( this, soldier->epoch, soldier->dir, xpos, ypos );
2132 						this->ammo_effects.push_back(ammoeffect);
2133 					}
2134 				}
2135 			}
2136 		}
2137 	}
2138 }
2139 
buildingMouseClick(int s_m_x,int s_m_y,bool m_left,bool m_right,Building * building)2140 bool PlayingGameState::buildingMouseClick(int s_m_x,int s_m_y,bool m_left,bool m_right,Building *building) {
2141 	bool done = false;
2142 	if( building == NULL )
2143 		return done;
2144 	if( !m_left && !m_right )
2145 		return done;
2146 
2147 	//Image *base_image = building->getImages()[0];
2148 	Image *base_image = building->getImages()[current_sector->getBuildingEpoch()];
2149 	ASSERT( base_image != NULL );
2150 	if( s_m_x < offset_land_x_c + building->getX() || s_m_x >= offset_land_x_c + building->getX() + base_image->getScaledWidth() ||
2151 		s_m_y < offset_land_y_c + building->getY() || s_m_y >= offset_land_y_c + building->getY() + base_image->getScaledHeight() ) {
2152 			return done;
2153 	}
2154 
2155 	if( !done && this->getGamePanel()->getMouseState() == GamePanel::MOUSESTATE_SHUTDOWN && building->getType() == BUILDING_TOWER ) {
2156 		//current_sector->shutdown();
2157 		this->shutdown(current_sector->getXPos(), current_sector->getYPos());
2158 		done = true;
2159 	}
2160 
2161 	for(int i=0;i<building->getNTurrets() && !done;i++) {
2162 		if( m_left
2163 			/*&& s_m_x >= offset_land_x_c + building->pos_x + building->turret_pos[i].x
2164 			&& s_m_x < offset_land_x_c + building->pos_x + building->turret_pos[i].getRight()
2165 			&& s_m_y >= offset_land_y_c + building->pos_y + building->turret_pos[i].y
2166 			&& s_m_y < offset_land_y_c + building->pos_y + building->turret_pos[i].getBottom()*/
2167 			&& s_m_x >= building->getTurretButton(i)->getLeft()
2168 			&& s_m_x < building->getTurretButton(i)->getRight()
2169 			&& s_m_y >= building->getTurretButton(i)->getTop()
2170 			&& s_m_y < building->getTurretButton(i)->getBottom()
2171 			) {
2172 				done = true;
2173 				//int n_population = current_sector->getPopulation();
2174 				//int n_spare = current_sector->getSparePopulation();
2175 				if( this->getGamePanel()->getMouseState() == GamePanel::MOUSESTATE_DEPLOY_DEFENCE ) {
2176 					// set new defender
2177 					int deploy_defence = this->getGamePanel()->getDeployDefence();
2178 					ASSERT(deploy_defence != -1);
2179 					//current_sector->deployDefender(building, i, deploy_defence);
2180 					this->deployDefender(current_sector->getXPos(), current_sector->getYPos(), building->getType(), i, deploy_defence);
2181 				}
2182 				else if( building->getTurretMan(i) != -1 ) {
2183 					// remove existing defender
2184 					// return current defender to stocks
2185 					//current_sector->returnDefender(building, i);
2186 					this->returnDefender(current_sector->getXPos(), current_sector->getYPos(), building->getType(), i);
2187 				}
2188 		}
2189 	}
2190 
2191 	if( !done && this->getGamePanel()->getMouseState() == GamePanel::MOUSESTATE_DEPLOY_SHIELD ) {
2192 		if( building->getHealth() < building->getMaxHealth() ) {
2193 			int deploy_shield = this->getGamePanel()->getDeployShield();
2194 			ASSERT(deploy_shield != -1);
2195 			this->useShield(current_sector->getXPos(), current_sector->getYPos(), building->getType(), deploy_shield);
2196 		}
2197 	}
2198 
2199 	return done;
2200 }
2201 
moveTo(int map_x,int map_y)2202 void PlayingGameState::moveTo(int map_x,int map_y) {
2203 	current_sector = game_g->getMap()->getSector(map_x, map_y);
2204 	if( this->getGamePanel() != NULL )
2205 		this->getGamePanel()->setPage( GamePanel::STATE_SECTORCONTROL );
2206 	this->reset();
2207 	for(size_t i=0;i<effects.size();i++) {
2208 		TimedEffect *effect = effects.at(i);
2209 		delete effect;
2210 	}
2211 	effects.clear();
2212 	for(size_t i=0;i<ammo_effects.size();i++) {
2213 		TimedEffect *effect = ammo_effects.at(i);
2214 		delete effect;
2215 	}
2216 	ammo_effects.clear();
2217 }
2218 
canRequestAlliance(int player,int i) const2219 bool PlayingGameState::canRequestAlliance(int player,int i) const {
2220 	ASSERT(player != i);
2221 	ASSERT(game_g->players[player] != NULL);
2222 	ASSERT(!game_g->players[player]->isDead());
2223 	bool ok = true;
2224 	// check not already allied
2225 	for(int j=0;j<n_players_c && ok;j++) {
2226 		if( j == player || game_g->players[j] == NULL || game_g->players[j]->isDead() ) {
2227 		}
2228 		else if( j == i || Player::isAlliance(i, j) ) {
2229 			if( Player::isAlliance(player, j) )
2230 				ok = false;
2231 		}
2232 	}
2233 
2234 	// check still two sides
2235 	bool allied_all_others = ok;
2236 	for(int j=0;j<n_players_c && allied_all_others;j++) {
2237 		if( j == player || game_g->players[j] == NULL || game_g->players[j]->isDead() ) {
2238 		}
2239 		else if( j == i || Player::isAlliance(i, j) ) {
2240 			// player on the side that we are requesting an alliance with
2241 		}
2242 		else if( !Player::isAlliance(player, j) ) {
2243 			allied_all_others = false;
2244 		}
2245 	}
2246 	if( allied_all_others )
2247 		ok = false;
2248 	return ok;
2249 }
2250 
requestAlliance(int player,int i,bool human)2251 void PlayingGameState::requestAlliance(int player,int i,bool human) {
2252 	// 'player' requests alliance with 'i'
2253 	/*if( !human ) {
2254 		// AIs only supported in non-player mode
2255 		ASSERT(gameMode == GAMEMODE_SINGLEPLAYER);
2256 	}*/
2257 	ASSERT(game_g->getGameMode() == GAMEMODE_SINGLEPLAYER); // blocked for now
2258 	ASSERT(player != i);
2259 	ASSERT(game_g->players[player] != NULL);
2260 	ASSERT(!game_g->players[player]->isDead());
2261 	//ASSERT(i != human_player); // todo: for requesting with human player
2262 	bool ok = true;
2263 	bool ask_human_player = false;
2264 	int playing_asking_human = -1; // which player do we need to ask the human?
2265 	int human_player = -1;
2266 	// okay to request?
2267 	// check i, and those who are allied with i
2268 	for(int j=0;j<n_players_c && ok;j++) {
2269 		if( j == player || game_g->players[j] == NULL || game_g->players[j]->isDead() ) {
2270 		}
2271 		else if( j == i || Player::isAlliance(i, j) ) {
2272 			//if( j == human_player ) {
2273 			if( game_g->players[j]->isHuman() ) {
2274 				// request if human is part of alliance
2275 				ask_human_player = true;
2276 				playing_asking_human = player;
2277 				human_player = j;
2278 			}
2279 			else if( !game_g->players[j]->requestAlliance(player) ) {
2280 				ok = false;
2281 				if( human )
2282 					playSample(game_g->s_alliance_no[j]);
2283 			}
2284 		}
2285 	}
2286 	// check those who are allied with player
2287 	for(int j=0;j<n_players_c && ok;j++) {
2288 		if( j == player || game_g->players[j] == NULL || game_g->players[j]->isDead() ) {
2289 		}
2290 		else if( Player::isAlliance(player, j) ) {
2291 			//if( j == human_player ) {
2292 			if( game_g->players[j]->isHuman() ) {
2293 				// request if human is part of alliance
2294 				//ok = false;
2295 				ask_human_player = true;
2296 				playing_asking_human = i;
2297 				human_player = j;
2298 			}
2299 			else if( !game_g->players[j]->requestAlliance(i) ) {
2300 				ok = false;
2301 				if( human )
2302 					playSample(game_g->s_alliance_no[j]);
2303 			}
2304 		}
2305 	}
2306 
2307 	if( ok && ask_human_player ) {
2308 		if( this->player_asking_alliance != -1 ) {
2309 			// someone else asking, so don't ask
2310 		}
2311 		else {
2312 			// askHuman() is called to avoid the cpu player repeatedly asking
2313 			if( game_g->players[playing_asking_human]->askHuman() && game_g->players[playing_asking_human]->requestAlliance(human_player) ) {
2314 				playSample(game_g->s_alliance_ask[playing_asking_human]);
2315 				this->player_asking_alliance = playing_asking_human;
2316 				//this->reset();
2317 				this->setupMapGUI(); // needed to change the map GUI to ask player; call this rather than reset(), to avoid resetting the entire GUI (which causes the GUI to return to main sector control)
2318 			}
2319 		}
2320 	}
2321 	else if( ok ) {
2322 		if( human )
2323 			playSample(game_g->s_alliance_yes[i]);
2324 		makeAlliance(player, i);
2325 	}
2326 }
2327 
makeAlliance(int player,int i)2328 void PlayingGameState::makeAlliance(int player,int i) {
2329 	for(int j=0;j<n_players_c;j++) {
2330 		if( j == player || game_g->players[j] == NULL || game_g->players[j]->isDead() ) {
2331 		}
2332 		else if( j == i || Player::isAlliance(i, j) ) {
2333 			// bring player j into the alliance
2334 			for(int k=0;k<n_players_c;k++) {
2335 				if( k != j && ( k == player || Player::isAlliance(k, player) ) ) {
2336 					Player::setAlliance(k, j, true);
2337 				}
2338 			}
2339 		}
2340 	}
2341 	//gamestate->reset(); // reset shield buttons
2342 	//((PlayingGameState *)gamestate)->resetShieldButtons(); // needed to update player shield buttons
2343 	this->resetShieldButtons(); // needed to update player shield buttons
2344 	this->cancelPlayerAskingAlliance(); // need to do this even if AIs make an alliance between themselves, as it may mean the player-alliance is no longer possible!
2345 }
2346 
cancelPlayerAskingAlliance()2347 void PlayingGameState::cancelPlayerAskingAlliance() {
2348 	if( this->player_asking_alliance != -1 ) {
2349 		this->player_asking_alliance = -1;
2350 		//this->reset();
2351 		this->setupMapGUI(); // call this rather than reset(), to avoid the GUI going back to main sector control!
2352 	}
2353 }
2354 
refreshTimeRate()2355 void PlayingGameState::refreshTimeRate() {
2356 	speed_button->setImage( game_g->icon_speeds[ game_g->getTimeRate()-1 ] );
2357 }
2358 
mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click)2359 void PlayingGameState::mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click) {
2360 	if( !game_g->isDemo() && game_g->players[client_player]->isDead() ) {
2361 		return;
2362 	}
2363 	GameState::mouseClick(m_x, m_y, m_left, m_middle, m_right, click);
2364 
2365 	//bool m_left = mouse_left(m_b);
2366 	//bool m_right = mouse_right(m_b);
2367 	int s_m_x = (int)(m_x / game_g->getScaleWidth());
2368 	int s_m_y = (int)(m_y / game_g->getScaleHeight());
2369 
2370 	bool done = false;
2371 	bool clear_selected_army = true;
2372 
2373 	//int s_m_x = m_x / 1;
2374 	//int s_m_y = m_y / 1;
2375 	int map_x = ( s_m_x - offset_map_x_c ) / 16;
2376 	int map_y = ( s_m_y - offset_map_y_c ) / 16;
2377 	/*if( m_x >= offset_map_x_c && m_x < offset_map_x_c + map_width_c * map_sq->getScaledWidth() &&
2378 	m_y >= offset_map_y_c && m_y < offset_map_y_c + map_height_c * map_sq->getScaledHeight() ) {*/
2379 	if( !done && m_left && click && this->player_asking_alliance != -1 ) {
2380 		ASSERT( this->alliance_yes != NULL );
2381 		ASSERT( this->alliance_no != NULL );
2382 		if( this->alliance_yes->mouseOver(m_x, m_y) ) {
2383 			ASSERT( game_g->players[player_asking_alliance] != NULL );
2384 			ASSERT( !game_g->players[player_asking_alliance]->isDead() );
2385 			this->makeAlliance(player_asking_alliance, client_player);
2386 			// makeAlliance also cancels
2387 			done = true;
2388 		}
2389 		else if( this->alliance_no->mouseOver(m_x, m_y ) ) {
2390 			this->cancelPlayerAskingAlliance();
2391 			done = true;
2392 		}
2393 		if( done ) {
2394 			registerClick();
2395 		}
2396 	}
2397 	if( !done && click && map_x >= 0 && map_x < map_width_c && map_y >= 0 && map_y < map_height_c ) {
2398 		if( this->player_asking_alliance == -1 && map_display == MAPDISPLAY_MAP && game_g->getMap()->isSectorAt(map_x, map_y) && this->map_panels[map_x][map_y]->mouseOver(m_x, m_y) ) {
2399 			// although the mouse should always be over the map square, we call mouseOver so that the enabled flag is checked
2400 			done = true;
2401 			if( m_left && selected_army != NULL ) {
2402 				if( selected_army->getSector() != game_g->getMap()->getSector(map_x, map_y) ) {
2403 					int n_nukes = selected_army->getSoldiers(nuclear_epoch_c);
2404 					ASSERT( n_nukes == 0 );
2405 					// move selected army
2406 					/*if( game_g->getMap()->getSector(map_x, map_y)->moveArmy(selected_army) ) {
2407 						this->moveTo(map_x,map_y);
2408 					}*/
2409 					if( this->moveArmyTo(selected_army->getSector()->getXPos(), selected_army->getSector()->getYPos(), map_x, map_y) ) {
2410 						this->moveTo(map_x, map_y);
2411 					}
2412 					else {
2413 						// (some of) army too far - don't lose selection
2414 						clear_selected_army = false;
2415 					}
2416 				}
2417 			}
2418 			else if( m_left && this->getGamePanel()->getMouseState() == GamePanel::MOUSESTATE_DEPLOY_WEAPON ) {
2419 				// deploy assembled army
2420 				ASSERT( current_sector->getAssembledArmy() != NULL );
2421 				Sector *target_sector = game_g->getMap()->getSector(map_x, map_y);
2422 				if( target_sector->isNuked() ) {
2423 					//clear_selected_army = false;
2424 				}
2425 				else {
2426 					int n_nukes = current_sector->getAssembledArmy()->getSoldiers(nuclear_epoch_c);
2427 					if( n_nukes > 0 ) {
2428 						// nuke!
2429 						LOG("nuke sector %d, %d (%d)\n", map_x, map_y, n_nukes);
2430 						ASSERT( n_nukes == 1 );
2431 						if( target_sector->getActivePlayer() != -1 && target_sector->getPlayer() == current_sector->getPlayer() ) {
2432 							// don't nuke own sector
2433 							LOG("don't nuke own sector: %d\n", target_sector->getActivePlayer());
2434 						}
2435 						else if( target_sector->getActivePlayer() != -1 && Player::isAlliance(current_sector->getPlayer(), target_sector->getPlayer()) ) {
2436 							// don't nuke allied sectors
2437 							LOG("don't nuke allied sector\n");
2438 							playSample(game_g->s_cant_nuke_ally);
2439 						}
2440 						else {
2441 							if( this->nukeSector(current_sector->getXPos(), current_sector->getYPos(), map_x, map_y) ) {
2442 								this->moveTo(map_x,map_y);
2443 							}
2444 						}
2445 					}
2446 					//else if( game_g->getMap()->getSector(map_x, map_y)->moveArmy(current_sector->getAssembledArmy() ) ) {
2447 					else if( this->moveAssembledArmyTo(current_sector->getXPos(), current_sector->getYPos(), map_x, map_y) ) {
2448 						this->getGamePanel()->setMouseState(GamePanel::MOUSESTATE_NORMAL);
2449 						this->moveTo(map_x,map_y);
2450 					}
2451 				}
2452 			}
2453 			else if( m_left ) {
2454 				//if( game_g->getMap()->sectors[map_x][map_y] != current_sector )
2455 				{
2456 					// move to viewing a different sector
2457 					if( current_sector->getPlayer() == client_player ) {
2458 						//current_sector->returnAssembledArmy();
2459 						this->returnAssembledArmy(current_sector->getXPos(), current_sector->getYPos());
2460 					}
2461 					this->getGamePanel()->setMouseState(GamePanel::MOUSESTATE_NORMAL);
2462 					this->moveTo(map_x,map_y);
2463 				}
2464 			}
2465 			else if( m_right && !game_g->isDemo() ) {
2466 				// select an army
2467 				Army *army = game_g->getMap()->getSector(map_x, map_y)->getArmy(client_player);
2468 				if( army->getTotal() > 0 ) {
2469 					done = true;
2470 					selected_army = army;
2471 					clear_selected_army = false;
2472 				}
2473 			}
2474 		}
2475 	}
2476 
2477 	if( !done && ( m_left || m_right ) && click && speed_button != NULL && speed_button->mouseOver(m_x, m_y) ) {
2478         done = true;
2479         registerClick();
2480         if( game_g->oneMouseButtonMode() ) {
2481 			// cycle through the speeds
2482 			game_g->cycleTimeRate();
2483 		}
2484 		else {
2485 			if( m_left ) {
2486 				game_g->increaseTimeRate();
2487 			}
2488 			else if( m_right ) {
2489 				game_g->decreaseTimeRate();
2490 			}
2491 		}
2492 		LOG("set time_rate to %d\n", game_g->getTimeRate());
2493 		refreshTimeRate();
2494 		//processClick(buttonSpeedClick, this->screen_page, this, 0, speed_button, m_left, m_middle, m_right);
2495 	}
2496 	else if( !done && m_left && click && quit_button != NULL && quit_button->mouseOver(m_x, m_y) ) {
2497         done = true;
2498         registerClick();
2499         requestQuit(false);
2500 	}
2501 	else if( !done && m_left && click && confirm_button_1 != NULL && confirm_button_1->mouseOver(m_x, m_y) ) {
2502 		// save game and quit to desktop
2503         done = true;
2504         registerClick();
2505         ASSERT( confirm_window != NULL );
2506 		game_g->saveState();
2507 	    game_g->getApplication()->setQuit();
2508 	}
2509 	else if( !done && m_left && click && confirm_button_2 != NULL && confirm_button_2->mouseOver(m_x, m_y) ) {
2510 		// exit battle
2511         done = true;
2512         registerClick();
2513         ASSERT( confirm_window != NULL );
2514 		this->requestConfirm();
2515 	}
2516 	else if( !done && m_left && click && confirm_button_3 != NULL && confirm_button_3->mouseOver(m_x, m_y) ) {
2517 		// cancel
2518         done = true;
2519         registerClick();
2520         ASSERT( confirm_window != NULL );
2521         this->closeConfirmWindow();
2522     }
2523 	else if( !done && m_left && click && pause_button != NULL && pause_button->mouseOver(m_x, m_y) ) {
2524 		// should always be non-paused if we are here!
2525 		if( !game_g->isPaused() ) {
2526             done = true;
2527             registerClick();
2528 			game_g->togglePause();
2529 		}
2530 	}
2531 	else if( !done && m_left && click && tutorial_next_button != NULL && tutorial_next_button->mouseOver(m_x, m_y) ) {
2532 		game_g->getTutorial()->proceed();
2533 		const TutorialCard *new_card = game_g->getTutorial()->getCard();
2534 		if( new_card != NULL ) {
2535 			new_card->setGUI(this);
2536 		}
2537 		else {
2538 			GUIHandler::resetGUI(this);
2539 		}
2540 		delete tutorial_next_button;
2541 		tutorial_next_button = NULL;
2542 		done = true;
2543         registerClick();
2544 		// don't lose selection, important for tutorial:
2545 		clear_selected_army = false;
2546 	}
2547 
2548 	// switch map display
2549 	for(int i=0;i<n_players_c && !done && m_left && click;i++) {
2550 		if( shield_buttons[i] == NULL ) {
2551 			continue;
2552 		}
2553 		ASSERT( shield_number_panels[i] != NULL );
2554 		/*int bx = offset_map_x_c + 16 * map_width_c + 20;
2555 		int by = offset_map_y_c + 2 + 16 * i + 8;
2556 		if( s_m_x >= bx && s_m_x < bx + 16 && s_m_y >= by && s_m_y < by + 16 ) {*/
2557 		if( shield_number_panels[i]->mouseOver(m_x, m_y) ) {
2558 			bool ok = false;
2559 			for(int j=i;j<n_players_c && !ok;j++) {
2560 				if( j == i || Player::isAlliance(i, j) ) {
2561 					const Army *army = current_sector->getArmy(j);
2562 					if( army->getTotal() > 0 )
2563 						ok = true;
2564 				}
2565 			}
2566 
2567 			if( ok ) {
2568                 done = true;
2569                 registerClick();
2570                 if( this->map_display == MAPDISPLAY_MAP )
2571 					this->map_display = MAPDISPLAY_UNITS;
2572 				else if( this->map_display == MAPDISPLAY_UNITS )
2573 					this->map_display = MAPDISPLAY_MAP;
2574 				this->reset();
2575 			}
2576 		}
2577 	}
2578 
2579 	// alliances
2580 	for(int i=0;i<n_players_c && !done && m_left && click && !game_g->isDemo();i++) {
2581 		if( i != client_player && game_g->players[i] != NULL && !game_g->players[i]->isDead() ) {
2582 			if( shield_buttons[i] != NULL && shield_buttons[i]->mouseOver(m_x, m_y) ) {
2583 				if( this->player_asking_alliance != -1 && this->player_asking_alliance == i ) {
2584 					// automatically accept
2585 					this->makeAlliance(client_player, i);
2586 				}
2587 				else {
2588 					// request alliance
2589 					if( canRequestAlliance(client_player, i) ) {
2590 						requestAlliance(client_player, i, true);
2591 					}
2592 				}
2593 				// automatically cancel any alliance being asked for
2594 				if( this->player_asking_alliance != -1 ) {
2595 					this->cancelPlayerAskingAlliance();
2596 				}
2597 				done = true;
2598 			}
2599 		}
2600 	}
2601 	if( !done && m_left && click && shield_blank_button != NULL && shield_blank_button->mouseOver(m_x, m_y) ) {
2602 		// break alliance
2603 		bool any = false;
2604 		for(int i=0;i<n_players_c;i++) {
2605 			if( i != client_player && Player::isAlliance(i, client_player) ) {
2606 				Player::setAlliance(i, client_player, false);
2607 				any = true;
2608 			}
2609 		}
2610 		ASSERT( any );
2611 		//gamestate->reset(); // reset shield buttons
2612 		//((PlayingGameState *)gamestate)->resetShieldButtons(); // needed to update player shield buttons
2613 		this->resetShieldButtons(); // needed to update player shield buttons
2614 		done = true;
2615 	}
2616 
2617 	//if( !done && s_m_x >= offset_land_x_c + 16 && s_m_y >= offset_land_y_c ) {
2618 	if( !done && click && !game_g->isDemo() && this->land_panel->mouseOver(m_x, m_y) ) {
2619 		const Army *army_in_sector = current_sector->getArmy(client_player);
2620 		Building *building = current_sector->getBuilding(BUILDING_TOWER);
2621 		bool clicked_fortress = building != NULL && s_m_x >= offset_land_x_c + building->getX() && s_m_x < offset_land_x_c + building->getX() + game_g->fortress[ current_sector->getBuildingEpoch() ]->getScaledWidth() &&
2622 			s_m_y >= offset_land_y_c + building->getY() && s_m_y < offset_land_y_c + building->getY() + game_g->fortress[ current_sector->getBuildingEpoch() ]->getScaledHeight();
2623 		if( m_left ) {
2624             if( this->getGamePanel()->getMouseState() == GamePanel::MOUSESTATE_DEPLOY_WEAPON ) {
2625                 ASSERT( current_sector->getAssembledArmy() != NULL );
2626 				int n_nukes = current_sector->getAssembledArmy()->getSoldiers(nuclear_epoch_c);
2627 				if( n_nukes == 0 ) {
2628 					// deploy assembled army
2629                     done = true;
2630                     registerClick();
2631                     //army_in_sector->add( current_sector->getAssembledArmy() );
2632 					this->moveAssembledArmyTo(current_sector->getXPos(), current_sector->getYPos(), current_sector->getXPos(), current_sector->getYPos());
2633 					this->getGamePanel()->setMouseState(GamePanel::MOUSESTATE_NORMAL);
2634                 }
2635 				else {
2636 					// can't nuke own sector!
2637 					int n_selected = current_sector->getAssembledArmy()->getTotal();
2638 					ASSERT( n_nukes == 1 );
2639 					ASSERT( n_selected == n_nukes );
2640 				}
2641 			}
2642 			else if( selected_army != NULL ) {
2643 				done = true;
2644                 registerClick();
2645                 // move selected army
2646 				if( clicked_fortress && current_sector->getPlayer() == selected_army->getPlayer() ) {
2647 					this->returnArmy(current_sector->getXPos(), current_sector->getYPos(), selected_army->getSector()->getXPos(), selected_army->getSector()->getYPos());
2648 				}
2649 				else {
2650 					if( selected_army->getSector() != current_sector ) {
2651 						// move selected army
2652 						this->moveArmyTo(selected_army->getSector()->getXPos(), selected_army->getSector()->getYPos(), current_sector->getXPos(), current_sector->getYPos());
2653 					}
2654 				}
2655 			}
2656 		}
2657 		if( !done && ( game_g->oneMouseButtonMode() ? m_left : m_right ) && !clicked_fortress && army_in_sector->getTotal() > 0 ) {
2658 			done = true;
2659             registerClick();
2660             //selected_army = army_in_sector;
2661 			selected_army = game_g->getMap()->getSector(current_sector->getXPos(), current_sector->getYPos())->getArmy(client_player);
2662 			clear_selected_army = false;
2663 			if( current_sector->getPlayer() == client_player ) {
2664 				//current_sector->returnAssembledArmy();
2665 				this->returnAssembledArmy(current_sector->getXPos(), current_sector->getYPos());
2666 			}
2667 			this->getGamePanel()->setMouseState(GamePanel::MOUSESTATE_NORMAL);
2668 		}
2669 	}
2670 
2671 	if( current_sector->getPlayer() == client_player && click ) {
2672 		for(int i=0;i<N_BUILDINGS && !done;i++) {
2673 			done = buildingMouseClick(s_m_x, s_m_y, m_left, m_right, current_sector->getBuilding((Type)i));
2674 		}
2675 	}
2676 
2677 	if( !done )
2678 		this->getGamePanel()->input(m_x, m_y, m_left, m_middle, m_right, click);
2679 
2680 	if( clear_selected_army && ( m_left || m_right ) && click ) {
2681 		selected_army = NULL;
2682 		refreshButtons();
2683 	}
2684 	else if( selected_army != NULL ) {
2685 		refreshButtons();
2686 	}
2687 
2688 }
2689 
requestQuit(bool force_quit)2690 void PlayingGameState::requestQuit(bool force_quit) {
2691 	if( force_quit ) {
2692 		game_g->saveState();
2693 	    game_g->getApplication()->setQuit();
2694 	}
2695 	else {
2696 		this->createQuitWindow();
2697 	}
2698 }
2699 
requestConfirm()2700 void PlayingGameState::requestConfirm() {
2701 	if( confirm_window != NULL ) {
2702         this->closeConfirmWindow();
2703         if( !game_g->isStateChanged() ) {
2704 			game_g->setGameResult(GAMERESULT_QUIT);
2705 			game_g->fadeMusic(1000);
2706 			game_g->setStateChanged(true);
2707 			this->fadeScreen(true, 0, endIsland_g);
2708 		}
2709 	}
2710 }
2711 
validSoldierLocation(int epoch,int xpos,int ypos)2712 bool PlayingGameState::validSoldierLocation(int epoch,int xpos,int ypos) {
2713 	ASSERT_S_EPOCH(epoch);
2714 	bool okay = true;
2715 	if( epoch == 6 || epoch == 7 || epoch == 9 )
2716 		return true;
2717 
2718 	//int size_x = attackers_walking[0][ epoch ][0]->getScaledWidth();
2719 	//int size_y = attackers_walking[0][ epoch ][0]->getScaledHeight();
2720 	int size_x = game_g->attackers_walking[0][ epoch ][0][0]->getScaledWidth();
2721 	int size_y = game_g->attackers_walking[0][ epoch ][0][0]->getScaledHeight();
2722 	if( xpos < 0 || xpos + size_x >= land_width_c || ypos < 0 || ypos + size_y >= land_height_c )
2723 		okay = false;
2724 	else if( current_sector->getPlayer() != -1 ) {
2725 		for(int i=0;i<N_BUILDINGS && okay;i++) {
2726 			Building *building = current_sector->getBuilding((Type)i);
2727 			if( building == NULL )
2728 				continue;
2729 			Image *image = building->getImages()[current_sector->getBuildingEpoch()];
2730 			if( xpos + size_x >= building->getX() && xpos < building->getX() + image->getScaledWidth() &&
2731 				ypos + size_y >= building->getY() && ypos < building->getY() + image->getScaledHeight() )
2732 				okay = false;
2733 		}
2734 		if( okay && openPitMine() && xpos + size_x >= offset_openpitmine_x_c && xpos < offset_openpitmine_x_c + game_g->icon_openpitmine->getScaledWidth() &&
2735 			ypos + size_y >= offset_openpitmine_y_c && ypos < offset_openpitmine_y_c + game_g->icon_openpitmine->getScaledHeight() )
2736 			okay = false;
2737 		/*Building *building = current_sector->getBuilding(BUILDING_TOWER);
2738 		Building *building_mine = current_sector->getBuilding(BUILDING_MINE);
2739 		if( xpos + size_x >= building->pos_x && xpos < building->pos_x + fortress[ current_sector->getBuildingEpoch() ]->getScaledWidth() &&
2740 		ypos + size_y >= building->pos_y && ypos < building->pos_y + fortress[ current_sector->getBuildingEpoch() ]->getScaledHeight() )
2741 		okay = false;
2742 		else if( building_mine != NULL && xpos + size_x >= building_mine->pos_x && xpos < building_mine->pos_x + mine[ current_sector->getBuildingEpoch() ]->getScaledWidth() &&
2743 		ypos + size_y >= building_mine->pos_y && ypos < building_mine->pos_y + mine[ current_sector->getBuildingEpoch() ]->getScaledHeight() )
2744 		okay = false;
2745 		else if( openPitMine() && xpos + size_x >= offset_openpitmine_x_c && xpos < offset_openpitmine_x_c + icon_openpitmine->getScaledWidth() &&
2746 		ypos + size_y >= offset_openpitmine_y_c && ypos < offset_openpitmine_y_c + icon_openpitmine->getScaledHeight() )
2747 		okay = false;*/
2748 	}
2749 	return okay;
2750 }
2751 
refreshSoldiers(bool flash)2752 void PlayingGameState::refreshSoldiers(bool flash) {
2753 	for(int i=0;i<n_players_c;i++) {
2754 		int n_soldiers_type[n_epochs_c+1];
2755 		for(int j=0;j<=n_epochs_c;j++)
2756 			n_soldiers_type[j] = 0;
2757 		for(size_t j=0;j<soldiers[i].size();j++) {
2758 			Soldier *soldier = soldiers[i].at(j);
2759 			n_soldiers_type[ soldier->epoch ]++;
2760 		}
2761 		const Army *army = current_sector->getArmy(i);
2762 		for(int j=0;j<=n_epochs_c;j++) {
2763 			int diff = army->getSoldiers(j) - n_soldiers_type[j];
2764 			if( diff > 0 ) {
2765 				// create some more
2766 				for(int k=0;k<diff;k++) {
2767 					int xpos = 0, ypos = 0;
2768 					bool found_loc = false;
2769 					while(!found_loc) {
2770 						xpos = rand() % land_width_c;
2771 						ypos = rand() % land_height_c;
2772 						found_loc = validSoldierLocation(j, xpos, ypos);
2773 					}
2774 					Soldier *soldier = new Soldier(i, j, xpos, ypos);
2775 					soldiers[i].push_back( soldier );
2776 					if( flash && !isAirUnit( soldier->epoch ) ) {
2777 						blueEffect(offset_land_x_c + soldier->xpos, offset_land_y_c + soldier->ypos, true);
2778 					}
2779 				}
2780 				if( j == biplane_epoch_c ) {
2781 					playSample(game_g->s_biplane, SOUND_CHANNEL_BIPLANE, -1); // n.b., doesn't matter if this restarts the currently playing sample
2782 				}
2783 				else if( j == jetplane_epoch_c ) {
2784 					playSample(game_g->s_jetplane, SOUND_CHANNEL_BOMBER, -1); // n.b., doesn't matter if this restarts the currently playing sample
2785 				}
2786 				else if( j == spaceship_epoch_c ) {
2787 					playSample(game_g->s_spaceship, SOUND_CHANNEL_SPACESHIP, -1); // n.b., doesn't matter if this restarts the currently playing sample
2788 				}
2789 			}
2790 			else if( diff < 0 ) {
2791 				// remove some
2792 				for(size_t k=0;k<soldiers[i].size();) {
2793 					Soldier *soldier = soldiers[i].at(k);
2794 					if( soldier->epoch == j ) {
2795 						if( n_deaths[i][j] > 0 ) {
2796 							if( flash && !isAirUnit( soldier->epoch ) ) {
2797 								deathEffect(offset_land_x_c + soldier->xpos, offset_land_y_c + soldier->ypos);
2798 								if( !isPlaying(SOUND_CHANNEL_FX) ) {
2799 									// only play if sound fx channel is free, to avoid too many death samples sounding
2800 									playSample(game_g->s_scream, SOUND_CHANNEL_FX);
2801 								}
2802 							}
2803 							n_deaths[i][j]--;
2804 						}
2805 						else if( flash && !isAirUnit( soldier->epoch ) ) {
2806 							blueEffect(offset_land_x_c + soldier->xpos, offset_land_y_c + soldier->ypos, false);
2807 						}
2808 						soldiers[i].erase(soldiers[i].begin() + k);
2809 						delete soldier;
2810 						diff++;
2811 						if( diff == 0 )
2812 							break;
2813 					}
2814 					else
2815 						k++;
2816 				}
2817 				if( army->getSoldiers(j) == 0 ) {
2818 					if( j == biplane_epoch_c ) {
2819 						game_g->s_biplane->fadeOut(500);
2820 					}
2821 					else if( j == jetplane_epoch_c ) {
2822 						game_g->s_jetplane->fadeOut(500);
2823 					}
2824 					else if( j == spaceship_epoch_c ) {
2825 						game_g->s_spaceship->fadeOut(500);
2826 					}
2827 				}
2828 			}
2829 		}
2830 	}
2831 
2832 	//this->refreshShieldNumberPanels();
2833 }
2834 
2835 /*void GameState::clearSoldiers() {
2836 for(int i=0;i<n_players_c;i++) {
2837 n_soldiers[i] = 0;
2838 }
2839 }*/
2840 
deathEffect(int xpos,int ypos)2841 void PlayingGameState::deathEffect(int xpos,int ypos) {
2842 	AnimationEffect *animationeffect = new AnimationEffect(xpos, ypos, game_g->death_flashes, n_death_flashes_c, 100, true);
2843 	this->effects.push_back(animationeffect);
2844 }
2845 
blueEffect(int xpos,int ypos,bool dir)2846 void PlayingGameState::blueEffect(int xpos,int ypos,bool dir) {
2847 	AnimationEffect *animationeffect = new AnimationEffect(xpos, ypos, game_g->blue_flashes, n_blue_flashes_c, 50, dir);
2848 	this->effects.push_back(animationeffect);
2849 }
2850 
explosionEffect(int xpos,int ypos)2851 void PlayingGameState::explosionEffect(int xpos,int ypos) {
2852 	if( game_g->explosions[0] != NULL ) { // not available with "old" graphics
2853 		AnimationEffect *animationeffect = new AnimationEffect(xpos, ypos, game_g->explosions, n_explosions_c, 50, true);
2854 		this->effects.push_back(animationeffect);
2855 	}
2856 }
2857 
refreshButtons()2858 void PlayingGameState::refreshButtons() {
2859 	for(int i=0;i<N_BUILDINGS;i++) {
2860 		Building *building = current_sector->getBuilding((Type)i);
2861 		if( building != NULL ) {
2862 			for(int j=0;j<building->getNTurrets();j++) {
2863 				PanelPage *panel = building->getTurretButton(j);
2864 				panel->setInfoLMB("");
2865 			}
2866 			if( building->getBuildingButton() != NULL ) {
2867 				building->getBuildingButton()->setInfoLMB("");
2868 			}
2869 
2870 			if( current_sector->getPlayer() != client_player ) {
2871 				// no text
2872 			}
2873 			else if( this->getGamePanel()->getMouseState() == GamePanel::MOUSESTATE_SHUTDOWN ) {
2874 				if( building->getBuildingButton() != NULL ) {
2875 					building->getBuildingButton()->setInfoLMB("shutdown the sector");
2876 				}
2877 			}
2878 			else {
2879 				for(int j=0;j<building->getNTurrets();j++) {
2880 					PanelPage *panel = building->getTurretButton(j);
2881 					if( this->getGamePanel()->getMouseState() == GamePanel::MOUSESTATE_DEPLOY_DEFENCE ) {
2882 						panel->setInfoLMB("place a defender here");
2883 					}
2884 					else if( building->getTurretMan(j) != -1 ) {
2885 						panel->setInfoLMB("return defender to tower"); // todo: check text
2886 					}
2887 				}
2888 			}
2889 		}
2890 	}
2891 
2892 	if( selected_army != NULL || this->gamePanel->getMouseState() == GamePanel::MOUSESTATE_DEPLOY_WEAPON ) {
2893 		bool is_nukes = current_sector->getAssembledArmy() != NULL && current_sector->getAssembledArmy()->getSoldiers(nuclear_epoch_c) > 0;
2894 		this->land_panel->setInfoLMB(is_nukes ? "" : "move army here");
2895 		if( this->player_asking_alliance == -1 && this->map_display == MAPDISPLAY_MAP ) {
2896 			for(int y=0;y<map_height_c;y++) {
2897 				for(int x=0;x<map_width_c;x++) {
2898 					if( game_g->getMap()->isSectorAt(x, y) ) {
2899 						if( is_nukes ) {
2900 							if( game_g->getMap()->getSector(x, y)->getPlayer() == current_sector->getPlayer() || game_g->getMap()->getSector(x, y)->isBeingNuked() || game_g->getMap()->getSector(x, y)->isNuked() ) {
2901 								map_panels[x][y]->setInfoLMB("");
2902 							}
2903 							else {
2904 								map_panels[x][y]->setInfoLMB("nuke sector");
2905 							}
2906 						}
2907 						else {
2908 							map_panels[x][y]->setInfoLMB("move army to this sector");
2909 						}
2910 						//map_panels[x][y]->setInfoLMB(!is_nukes ? "move army to this sector" : game_g->getMap()->getSector(x, y) == current_sector ? "" : "nuke sector");
2911 					}
2912 				}
2913 			}
2914 		}
2915 	}
2916 	else {
2917 		this->land_panel->setInfoLMB("");
2918 		if( this->player_asking_alliance == -1 && this->map_display == MAPDISPLAY_MAP ) {
2919 			for(int y=0;y<map_height_c;y++) {
2920 				for(int x=0;x<map_width_c;x++) {
2921 					if( game_g->getMap()->isSectorAt(x, y) ) {
2922 						map_panels[x][y]->setInfoLMB("view this sector");
2923 					}
2924 				}
2925 			}
2926 		}
2927 	}
2928 }
2929 
refreshShieldNumberPanels()2930 void PlayingGameState::refreshShieldNumberPanels() {
2931 	if( this->map_display == MAPDISPLAY_MAP ) {
2932 		for(int i=0;i<n_players_c;i++) {
2933 			if( shield_number_panels[i] != NULL ) {
2934 				//shield_number_panels[i]->setVisible(false);
2935 				shield_number_panels[i]->setInfoLMB("display numbers in each army");
2936 			}
2937 		}
2938 	}
2939 	else {
2940 		for(int i=0;i<n_players_c;i++) {
2941 			if( shield_number_panels[i] != NULL ) {
2942 				shield_number_panels[i]->setInfoLMB("display map");
2943 			}
2944 		}
2945 	}
2946 }
2947 
setNDesigners(int sector_x,int sector_y,int n_designers)2948 void PlayingGameState::setNDesigners(int sector_x, int sector_y, int n_designers) {
2949 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
2950 	ASSERT(sector != NULL);
2951 	if( sector->getActivePlayer() == client_player ) {
2952 		if( sector->getCurrentDesign() != NULL ) {
2953 			sector->setDesigners(n_designers);
2954 		}
2955 	}
2956 }
2957 
setNWorkers(int sector_x,int sector_y,int n_workers)2958 void PlayingGameState::setNWorkers(int sector_x, int sector_y, int n_workers) {
2959 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
2960 	ASSERT(sector != NULL);
2961 	if( sector->getActivePlayer() == client_player ) {
2962 		if( sector->getCurrentManufacture() != NULL ) {
2963 			sector->setWorkers(n_workers);
2964 		}
2965 	}
2966 }
2967 
setFAmount(int sector_x,int sector_y,int n_famount)2968 void PlayingGameState::setFAmount(int sector_x, int sector_y, int n_famount) {
2969 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
2970 	ASSERT(sector != NULL);
2971 	if( sector->getActivePlayer() == client_player ) {
2972 		if( sector->getCurrentManufacture() != NULL ) {
2973 			sector->setFAmount(n_famount);
2974 		}
2975 	}
2976 }
2977 
setNMiners(int sector_x,int sector_y,Id element,int n_miners)2978 void PlayingGameState::setNMiners(int sector_x, int sector_y, Id element, int n_miners) {
2979 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
2980 	ASSERT(sector != NULL);
2981 	if( sector->getActivePlayer() == client_player ) {
2982 		if( sector->canMine(element) ) {
2983 			sector->setMiners(element, n_miners);
2984 		}
2985 	}
2986 }
2987 
setNBuilders(int sector_x,int sector_y,Type type,int n_builders)2988 void PlayingGameState::setNBuilders(int sector_x, int sector_y, Type type, int n_builders) {
2989 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
2990 	ASSERT(sector != NULL);
2991 	if( sector->getActivePlayer() == client_player ) {
2992 		if( sector->canBuild(type) ) {
2993 			sector->setBuilders(type, n_builders);
2994 		}
2995 	}
2996 }
2997 
setCurrentDesign(int sector_x,int sector_y,Design * design)2998 void PlayingGameState::setCurrentDesign(int sector_x, int sector_y, Design *design) {
2999 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
3000 	ASSERT(sector != NULL);
3001 	if( sector->getActivePlayer() == client_player ) {
3002 		sector->setCurrentDesign(design);
3003 	}
3004 }
3005 
setCurrentManufacture(int sector_x,int sector_y,Design * design)3006 void PlayingGameState::setCurrentManufacture(int sector_x, int sector_y, Design *design) {
3007 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
3008 	ASSERT(sector != NULL);
3009 	if( sector->getActivePlayer() == client_player ) {
3010 		sector->setCurrentManufacture(design);
3011 	}
3012 }
3013 
assembledArmyEmpty(int sector_x,int sector_y)3014 void PlayingGameState::assembledArmyEmpty(int sector_x, int sector_y) {
3015 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
3016 	ASSERT(sector != NULL);
3017 	if( sector->getActivePlayer() == client_player ) {
3018 		sector->getAssembledArmy()->empty();
3019 	}
3020 }
3021 
assembleArmyUnarmed(int sector_x,int sector_y,int n)3022 bool PlayingGameState::assembleArmyUnarmed(int sector_x, int sector_y, int n) {
3023 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
3024 	ASSERT(sector != NULL);
3025 	if( sector->getActivePlayer() == client_player ) {
3026 		int n_spare = sector->getAvailablePopulation();
3027 		if( n_spare >= n ) {
3028 			int n_population = sector->getPopulation();
3029 			sector->getAssembledArmy()->add(n_epochs_c, n);
3030 			sector->setPopulation(n_population - n);
3031 			return true;
3032 		}
3033 	}
3034 	return false;
3035 }
3036 
assembleArmy(int sector_x,int sector_y,int epoch,int n)3037 bool PlayingGameState::assembleArmy(int sector_x, int sector_y, int epoch, int n) {
3038 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
3039 	ASSERT(sector != NULL);
3040 	if( sector->getActivePlayer() == client_player ) {
3041 		if( sector->assembleArmy(epoch, n) ) {
3042 			return true;
3043 		}
3044 	}
3045 	return false;
3046 }
3047 
assembleAll(int sector_x,int sector_y,bool include_unarmed)3048 bool PlayingGameState::assembleAll(int sector_x, int sector_y, bool include_unarmed) {
3049 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
3050 	ASSERT(sector != NULL);
3051 	if( sector->getActivePlayer() == client_player ) {
3052 		sector->assembleAll(include_unarmed);
3053 	}
3054 	return false;
3055 }
3056 
returnAssembledArmy(int sector_x,int sector_y)3057 void PlayingGameState::returnAssembledArmy(int sector_x, int sector_y) {
3058 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
3059 	ASSERT(sector != NULL);
3060 	if( sector->getActivePlayer() == client_player ) {
3061 		sector->returnAssembledArmy();
3062 	}
3063 }
3064 
returnArmy(int sector_x,int sector_y,int src_x,int src_y)3065 bool PlayingGameState::returnArmy(int sector_x, int sector_y, int src_x, int src_y) {
3066 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
3067 	ASSERT(sector != NULL);
3068 	if( sector->getActivePlayer() == client_player ) {
3069 		Sector *src = game_g->getMap()->getSector(src_x, src_y);
3070 		Army *army = src->getArmy(client_player);
3071 		return sector->returnArmy(army);
3072 	}
3073 	return false;
3074 }
3075 
moveArmyTo(int src_x,int src_y,int target_x,int target_y)3076 bool PlayingGameState::moveArmyTo(int src_x, int src_y, int target_x, int target_y) {
3077 	Sector *src = game_g->getMap()->getSector(src_x, src_y);
3078 	Sector *target = game_g->getMap()->getSector(target_x, target_y);
3079 	ASSERT(src != NULL);
3080 	ASSERT(target != NULL);
3081 	Army *army = src->getArmy(client_player);
3082 	return target->moveArmy(army);
3083 }
3084 
moveAssembledArmyTo(int src_x,int src_y,int target_x,int target_y)3085 bool PlayingGameState::moveAssembledArmyTo(int src_x, int src_y, int target_x, int target_y) {
3086 	Sector *src = game_g->getMap()->getSector(src_x, src_y);
3087 	ASSERT(src != NULL);
3088 	if( src->getActivePlayer() == client_player ) {
3089 		Army *army = src->getAssembledArmy();
3090 		Sector *target = game_g->getMap()->getSector(target_x, target_y);
3091 		ASSERT(target != NULL);
3092 		return target->moveArmy(army);
3093 	}
3094 	return false;
3095 }
3096 
nukeSector(int src_x,int src_y,int target_x,int target_y)3097 bool PlayingGameState::nukeSector(int src_x, int src_y, int target_x, int target_y) {
3098 	Sector *src = game_g->getMap()->getSector(src_x, src_y);
3099 	Sector *target = game_g->getMap()->getSector(target_x, target_y);
3100 	ASSERT(src != NULL);
3101 	ASSERT(target != NULL);
3102 	if( src->getActivePlayer() == client_player ) {
3103 		if( target->nukeSector(src) ) {
3104 			this->assembledArmyEmpty(src_x, src_y);
3105 			return true;
3106 		}
3107 	}
3108 	return false;
3109 }
3110 
deployDefender(int sector_x,int sector_y,Type type,int turret,int epoch)3111 void PlayingGameState::deployDefender(int sector_x, int sector_y, Type type, int turret, int epoch) {
3112 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
3113 	ASSERT(sector != NULL);
3114 	if( sector->getActivePlayer() == client_player ) {
3115 		Building *building = sector->getBuilding(type);
3116 		if( building != NULL ) {
3117 			sector->deployDefender(building, turret, epoch);
3118 		}
3119 	}
3120 }
3121 
returnDefender(int sector_x,int sector_y,Type type,int turret)3122 void PlayingGameState::returnDefender(int sector_x, int sector_y, Type type, int turret) {
3123 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
3124 	ASSERT(sector != NULL);
3125 	if( sector->getActivePlayer() == client_player ) {
3126 		Building *building = sector->getBuilding(type);
3127 		if( building != NULL ) {
3128 			sector->returnDefender(building, turret);
3129 		}
3130 	}
3131 }
3132 
useShield(int sector_x,int sector_y,Type type,int shield)3133 void PlayingGameState::useShield(int sector_x, int sector_y, Type type, int shield) {
3134 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
3135 	ASSERT(sector != NULL);
3136 	if( sector->getActivePlayer() == client_player ) {
3137 		Building *building = sector->getBuilding(type);
3138 		if( building != NULL ) {
3139 			sector->useShield(building, shield);
3140 		}
3141 	}
3142 }
3143 
trashDesign(int sector_x,int sector_y,Invention * invention)3144 void PlayingGameState::trashDesign(int sector_x, int sector_y, Invention *invention) {
3145 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
3146 	ASSERT(sector != NULL);
3147 	if( sector->getActivePlayer() == client_player ) {
3148 		sector->trashDesign(invention);
3149 	}
3150 }
3151 
shutdown(int sector_x,int sector_y)3152 void PlayingGameState::shutdown(int sector_x, int sector_y) {
3153 	Sector *sector = game_g->getMap()->getSector(sector_x, sector_y);
3154 	ASSERT(sector != NULL);
3155 	if( sector->getActivePlayer() == client_player ) {
3156 		sector->shutdown(client_player);
3157 	}
3158 }
3159 
saveState(stringstream & stream) const3160 void PlayingGameState::saveState(stringstream &stream) const {
3161 	stream << "<playing_gamestate>\n";
3162 	if( game_g->getGameType() == GAMETYPE_TUTORIAL ) {
3163 		stream << "<tutorial ";
3164 		stream << "name=\"" << game_g->getTutorial()->getId().c_str() << "\" ";
3165 		if( game_g->getTutorial()->getCard() != NULL ) {
3166 			stream << "current_card_name=\"" << game_g->getTutorial()->getCard()->getId().c_str() << "\" ";
3167 		}
3168 		stream << "/>\n";
3169 	}
3170 	stream << "<current_sector x=\"" << current_sector->getXPos() << "\" y=\"" << current_sector->getYPos() << "\" />\n";
3171 	stream << "<game_panel page=\"" << this->gamePanel->getPage() << "\" />\n";
3172 	stream << "<player_asking_alliance player_id=\"" << player_asking_alliance << "\" />\n";
3173 
3174 	for(int i=0;i<n_players_c;i++) {
3175 		if( game_g->players[i] != NULL ) {
3176 			game_g->players[i]->saveState(stream);
3177 		}
3178 	}
3179 	Player::saveStateAlliances(stream);
3180 	for(int i=0;i<n_players_c;i++) {
3181 		for(int j=0;j<n_epochs_c+1;j++) {
3182 			stream << "<n_deaths player_id=\"" << i << "\" epoch=\"" << j << "\" n=\"" << n_deaths[i][j] << "\" />\n";
3183 		}
3184 	}
3185 	game_g->getMap()->saveStateSectors(stream);
3186 	stream << "</playing_gamestate>\n";
3187 }
3188 
loadStateParseXMLMapXY(int * map_x,int * map_y,const TiXmlAttribute * attribute)3189 void PlayingGameState::loadStateParseXMLMapXY(int *map_x, int *map_y, const TiXmlAttribute *attribute) {
3190 	*map_x = -1;
3191 	*map_y = -1;
3192 	while( attribute != NULL ) {
3193 		const char *attribute_name = attribute->Name();
3194 		if( strcmp(attribute_name, "x") == 0 ) {
3195 			*map_x = atoi(attribute->Value());
3196 		}
3197 		else if( strcmp(attribute_name, "y") == 0 ) {
3198 			*map_y = atoi(attribute->Value());
3199 		}
3200 		else {
3201 			// skip the other sector attributes, only interested in x/y in this subfunction
3202 		}
3203 		attribute = attribute->Next();
3204 	}
3205 	if( *map_x < 0 || *map_x >= map_width_c || *map_y < 0 || *map_y >= map_height_c ) {
3206 		throw std::runtime_error("current_sector invalid map reference");
3207 	}
3208 	else if( !game_g->getMap()->isSectorAt(*map_x, *map_y) ) {
3209 		throw std::runtime_error("current_sector map reference doesn't exist");
3210 	}
3211 }
3212 
loadStateParseXMLNode(const TiXmlNode * parent)3213 void PlayingGameState::loadStateParseXMLNode(const TiXmlNode *parent) {
3214 	if( parent == NULL ) {
3215 		return;
3216 	}
3217 	bool read_children = true;
3218 	//throw std::runtime_error("blah"); // test failing to load state
3219 
3220 	switch( parent->Type() ) {
3221 		case TiXmlNode::TINYXML_DOCUMENT:
3222 			break;
3223 		case TiXmlNode::TINYXML_ELEMENT:
3224 			{
3225 				const char *element_name = parent->Value();
3226 				const TiXmlElement *element = parent->ToElement();
3227 				const TiXmlAttribute *attribute = element->FirstAttribute();
3228 				if( strcmp(element_name, "playing_gamestate") == 0 ) {
3229 					// handled entirely by caller
3230 				}
3231 				else if( strcmp(element_name, "tutorial") == 0 ) {
3232 					if( game_g->getGameType() != GAMETYPE_TUTORIAL ) {
3233 						throw std::runtime_error("wrong game type for tutorial");
3234 					}
3235 					bool has_card_name = false;
3236 					string card_name;
3237 					while( attribute != NULL ) {
3238 						const char *attribute_name = attribute->Name();
3239 						if( strcmp(attribute_name, "name") == 0 ) {
3240 							string name = attribute->Value();
3241 							game_g->setupTutorial(name);
3242 						}
3243 						else if( strcmp(attribute_name, "current_card_name") == 0 ) {
3244 							has_card_name = true;
3245 							card_name = attribute->Value();
3246 						}
3247 						else {
3248 							// don't throw an error here, to help backwards compatibility, but should throw an error in debug mode in case this is a sign of not loading something that we've saved
3249 							LOG("unknown playinggamestate/tutorial attribute: %s\n", attribute_name);
3250 							ASSERT(false);
3251 						}
3252 						attribute = attribute->Next();
3253 					}
3254 					if( game_g->getTutorial() == NULL ) {
3255 						throw std::runtime_error("unknown tutorial name");
3256 					}
3257 					game_g->getTutorial()->initCards();
3258 					if( has_card_name ) {
3259 						if( !game_g->getTutorial()->jumpTo(card_name) ) {
3260 							throw std::runtime_error("unknown tutorial card name");
3261 						}
3262 					}
3263 					else
3264 						game_g->getTutorial()->jumpToEnd();
3265 				}
3266 				else if( strcmp(element_name, "player_asking_alliance") == 0 ) {
3267 					while( attribute != NULL ) {
3268 						const char *attribute_name = attribute->Name();
3269 						if( strcmp(attribute_name, "player_id") == 0 ) {
3270 							player_asking_alliance = atoi(attribute->Value());
3271 						}
3272 						else {
3273 							// don't throw an error here, to help backwards compatibility, but should throw an error in debug mode in case this is a sign of not loading something that we've saved
3274 							LOG("unknown playinggamestate/player_asking_alliance attribute: %s\n", attribute_name);
3275 							ASSERT(false);
3276 						}
3277 						attribute = attribute->Next();
3278 					}
3279 				}
3280 				else if( strcmp(element_name, "n_deaths") == 0 ) {
3281 					int player_id = -1;
3282 					int epoch = -1;
3283 					int n = -1;
3284 					while( attribute != NULL ) {
3285 						const char *attribute_name = attribute->Name();
3286 						if( strcmp(attribute_name, "player_id") == 0 ) {
3287 							player_id = atoi(attribute->Value());
3288 						}
3289 						else if( strcmp(attribute_name, "epoch") == 0 ) {
3290 							epoch = atoi(attribute->Value());
3291 						}
3292 						else if( strcmp(attribute_name, "n") == 0 ) {
3293 							n = atoi(attribute->Value());
3294 						}
3295 						else {
3296 							// don't throw an error here, to help backwards compatibility, but should throw an error in debug mode in case this is a sign of not loading something that we've saved
3297 							LOG("unknown playinggamestate/n_deaths attribute: %s\n", attribute_name);
3298 							ASSERT(false);
3299 						}
3300 						attribute = attribute->Next();
3301 					}
3302 					if( player_id == -1 || epoch == -1 || n == -1 ) {
3303 						throw std::runtime_error("n_deaths missing attributes");
3304 					}
3305 					else if( player_id < 0 || player_id >= n_players_c ) {
3306 						throw std::runtime_error("n_deaths invalid player_id");
3307 					}
3308 					else if( epoch < 0 || epoch >= n_epochs_c+1 ) {
3309 						throw std::runtime_error("n_deaths invalid epoch");
3310 					}
3311 					n_deaths[player_id][epoch] = n;
3312 				}
3313 				else if( strcmp(element_name, "current_sector") == 0 ) {
3314 					int map_x = -1, map_y = -1;
3315 					loadStateParseXMLMapXY(&map_x, &map_y, attribute);
3316 					this->moveTo(map_x, map_y);
3317 				}
3318 				else if( strcmp(element_name, "game_panel") == 0 ) {
3319 					while( attribute != NULL ) {
3320 						const char *attribute_name = attribute->Name();
3321 						if( strcmp(attribute_name, "page") == 0 ) {
3322 							int page = atoi(attribute->Value());
3323 							if( page < 0 || page > GamePanel::N_STATES ) {
3324 								throw std::runtime_error("game_panel invalid page");
3325 							}
3326 							this->gamePanel->setPage(page);
3327 						}
3328 						else {
3329 							// don't throw an error here, to help backwards compatibility, but should throw an error in debug mode in case this is a sign of not loading something that we've saved
3330 							LOG("unknown playinggamestate/game_panel attribute: %s\n", attribute_name);
3331 							ASSERT(false);
3332 						}
3333 						attribute = attribute->Next();
3334 					}
3335 				}
3336 				else if( strcmp(element_name, "sector") == 0 ) {
3337 					int map_x = -1, map_y = -1;
3338 					loadStateParseXMLMapXY(&map_x, &map_y, attribute);
3339 					game_g->getMap()->getSector(map_x, map_y)->loadStateParseXMLNode(parent);
3340 					read_children = false;
3341 				}
3342 				else if( strcmp(element_name, "player") == 0 ) {
3343 					int player_id = -1;
3344 					while( attribute != NULL ) {
3345 						const char *attribute_name = attribute->Name();
3346 						if( strcmp(attribute_name, "player_id") == 0 ) {
3347 							player_id = atoi(attribute->Value());
3348 						}
3349 						else {
3350 							// everything else parsed by Player::loadStateParseXMLNode()
3351 						}
3352 						attribute = attribute->Next();
3353 					}
3354 					if( player_id < 0 || player_id >= n_players_c ) {
3355 						throw std::runtime_error("player invalid player_id");
3356 					}
3357 					game_g->players[player_id] = new Player(player_id == this->client_player, player_id);
3358 					game_g->players[player_id]->loadStateParseXMLNode(parent);
3359 					read_children = false;
3360 				}
3361 				else if( strcmp(element_name, "player_alliances") == 0 ) {
3362 					Player::loadStateParseXMLNodeAlliances(parent);
3363 					read_children = false;
3364 				}
3365 				else {
3366 					// don't throw an error here, to help backwards compatibility, but should throw an error in debug mode in case this is a sign of not loading something that we've saved
3367 					LOG("unknown playinggamestate tag at line %d col %d: %s\n", parent->Row(), parent->Column(), element_name);
3368 					ASSERT(false);
3369 				}
3370 			}
3371 			break;
3372 		case TiXmlNode::TINYXML_COMMENT:
3373 			break;
3374 		case TiXmlNode::TINYXML_UNKNOWN:
3375 			break;
3376 		case TiXmlNode::TINYXML_TEXT:
3377 			{
3378 				/*
3379 				// add to the existing node, not a child
3380 				vi_tree->setData( parent->Value() );
3381 				*/
3382 				/*VI_XMLTreeNode *vi_child = new VI_XMLTreeNode();
3383 				vi_child->setData( parent->Value() );
3384 				// add to the tree
3385 				vi_tree->addChild(vi_child);
3386 				vi_tree = vi_child;*/
3387 			}
3388 			break;
3389 		case TiXmlNode::TINYXML_DECLARATION:
3390 			break;
3391 	}
3392 
3393 	for(const TiXmlNode *child=parent->FirstChild();child!=NULL && read_children;child=child->NextSibling())  {
3394 		loadStateParseXMLNode(child);
3395 	}
3396 }
3397 
reset()3398 void EndIslandGameState::reset() {
3399     //LOG("EndIslandGameState::reset()\n");
3400 	this->screen_page->free(true);
3401 }
3402 
draw()3403 void EndIslandGameState::draw() {
3404 #if defined(__ANDROID__)
3405 	game_g->getScreen()->clear(); // SDL on Android requires screen be cleared (otherwise we get corrupt regions outside of the main area)
3406 #endif
3407 	game_g->background->draw(0, 0);
3408 	game_g->getScreen()->fillRectWithAlpha((short)(game_g->getScaleWidth()*40), (short)(game_g->getScaleHeight()*120), (short)(game_g->getScaleWidth()*240), (short)(game_g->getScaleHeight()*70), 0, 0, 0, 127);
3409 	char text[4096] = "";
3410 	if( game_g->getGameResult() == GAMERESULT_QUIT )
3411 		strcpy(text, "QUITTER!");
3412 	else if( game_g->getGameResult() == GAMERESULT_LOST )
3413 		strcpy(text, "LOSER!");
3414 	else if( game_g->getGameResult() == GAMERESULT_WON )
3415 		strcpy(text, "CONGRATULATIONS!");
3416 	else {
3417 		ASSERT(false);
3418 	}
3419 	Image::write(160, 122, game_g->letters_large, text, Image::JUSTIFY_CENTRE);
3420 
3421 	bool suspend = false;
3422 	if( game_g->getStartEpoch() >= 6 && game_g->getGameResult() == GAMERESULT_WON )
3423 		suspend = true;
3424 
3425 	if( !game_g->isDemo() ) {
3426 		if( game_g->player_heads_select[client_player] != NULL ) {
3427 			game_g->player_heads_select[client_player]->draw(40, 96);
3428 			if( game_g->getGameResult() == GAMERESULT_LOST ) {
3429 				game_g->grave->draw(42, 64);
3430 			}
3431 		}
3432 	}
3433 	const int xstep = 40;
3434 	for(int i=0,xpos=96;i<n_players_c;i++) {
3435 		if( i == client_player || game_g->players[i] == NULL )
3436 			continue;
3437 		if( game_g->player_heads_select[i] != NULL ) {
3438 			game_g->player_heads_select[i]->draw(xpos, 96);
3439 			if( game_g->getGameResult() == GAMERESULT_WON || game_g->players[i]->getFinalMen() == 0 ) {
3440 				game_g->grave->draw(xpos+2, 64);
3441 			}
3442 		}
3443 		xpos += xstep;
3444 	}
3445 
3446 	Image::write(40, 140, game_g->letters_small, "PLAYER", Image::JUSTIFY_LEFT);
3447 	Image::write(100, 140, game_g->letters_small, "START", Image::JUSTIFY_LEFT);
3448 	Image::write(140, 140, game_g->letters_small, "BIRTHS", Image::JUSTIFY_LEFT);
3449 	Image::write(180, 140, game_g->letters_small, "DEATHS", Image::JUSTIFY_LEFT);
3450 	Image::write(220, 140, game_g->letters_small, "END", Image::JUSTIFY_LEFT);
3451 	if( suspend )
3452 		Image::write(260, 140, game_g->letters_small, "SAVED", Image::JUSTIFY_LEFT);
3453 
3454 	int ypos = 150;
3455 	int rect_y_offset = 2;
3456 	//int r = 0, g = 0, b = 0, col = 0;
3457 	int r = 0, g = 0, b = 0;
3458 	int rect_x = (int)(20 * game_g->getScaleWidth());
3459 	int rect_y = (int)((ypos-rect_y_offset) * game_g->getScaleHeight());
3460 	int rect_w = (int)(16 * game_g->getScaleWidth());
3461 	int rect_h = (int)(8 * game_g->getScaleHeight());
3462 
3463 	if( !game_g->isDemo() ) {
3464 		PlayerType::getColour(&r, &g, &b, (PlayerType::PlayerTypeID)client_player);
3465 		/*col = SDL_MapRGB(game_g->getScreen()->getSurface()->format, r, g, b);
3466 		SDL_FillRect(game_g->getScreen()->getSurface(), &rect, col);*/
3467 		game_g->getScreen()->fillRect(rect_x, rect_y, rect_w, rect_h, r, g, b);
3468 
3469 		//Image::write(40, ypos, game_g->letters_small, "HUMAN", Image::JUSTIFY_LEFT, true);
3470 		Image::write(40, ypos, game_g->letters_small, PlayerType::getName((PlayerType::PlayerTypeID)client_player), Image::JUSTIFY_LEFT);
3471 
3472 		Image::writeNumbers(110, ypos, game_g->numbers_yellow, game_g->players[client_player]->getNMenForThisIsland(), Image::JUSTIFY_LEFT);
3473 		Image::writeNumbers(150, ypos, game_g->numbers_yellow, game_g->players[client_player]->getNBirths(), Image::JUSTIFY_LEFT);
3474 		Image::writeNumbers(190, ypos, game_g->numbers_yellow, game_g->players[client_player]->getNDeaths(), Image::JUSTIFY_LEFT);
3475 		Image::writeNumbers(230, ypos, game_g->numbers_yellow, game_g->players[client_player]->getFinalMen(), Image::JUSTIFY_LEFT);
3476 		if( suspend )
3477 			Image::writeNumbers(270, ypos, game_g->numbers_yellow, game_g->players[client_player]->getNSuspended(), Image::JUSTIFY_LEFT);
3478 		ypos += 10;
3479 	}
3480 
3481 	for(int i=0;i<n_players_c;i++) {
3482 		if( i == client_player || game_g->players[i] == NULL )
3483 			continue;
3484 		PlayerType::getColour(&r, &g, &b, (PlayerType::PlayerTypeID)i);
3485 		/*col = SDL_MapRGB(game_g->getScreen()->getSurface()->format, r, g, b);
3486 		rect.y = (Sint16)(ypos * game_g->getScaleHeight());
3487 		SDL_FillRect(game_g->getScreen()->getSurface(), &rect, col);*/
3488 		rect_y = (int)((ypos-rect_y_offset) * game_g->getScaleHeight());
3489 		game_g->getScreen()->fillRect(rect_x, rect_y, rect_w, rect_h, r, g, b);
3490 
3491 		//Image::write(40, ypos, game_g->letters_small, "COMPUTER", Image::JUSTIFY_LEFT, true);
3492 		Image::write(40, ypos, game_g->letters_small, PlayerType::getName((PlayerType::PlayerTypeID)i), Image::JUSTIFY_LEFT);
3493 		Image::writeNumbers(110, ypos, game_g->numbers_yellow, game_g->players[i]->getNMenForThisIsland(), Image::JUSTIFY_LEFT);
3494 		Image::writeNumbers(150, ypos, game_g->numbers_yellow, game_g->players[i]->getNBirths(), Image::JUSTIFY_LEFT);
3495 		Image::writeNumbers(190, ypos, game_g->numbers_yellow, game_g->players[i]->getNDeaths(), Image::JUSTIFY_LEFT);
3496 		Image::writeNumbers(230, ypos, game_g->numbers_yellow, game_g->players[i]->getFinalMen(), Image::JUSTIFY_LEFT);
3497 		if( suspend )
3498 			Image::writeNumbers(270, ypos, game_g->numbers_yellow, game_g->players[i]->getNSuspended(), Image::JUSTIFY_LEFT);
3499 		ypos += 10;
3500 	}
3501 
3502 	this->screen_page->draw();
3503 	//this->screen_page->drawPopups();
3504 
3505 	GameState::setDefaultMouseImage();
3506 	GameState::draw();
3507 }
3508 
mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click)3509 void EndIslandGameState::mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click) {
3510 	GameState::mouseClick(m_x, m_y, m_left, m_middle, m_right, click);
3511 
3512 	//bool m_left = mouse_left(m_b);
3513 	//bool m_right = mouse_right(m_b);
3514 
3515 	if( ( m_left || m_right ) && click && !game_g->isStateChanged() ) {
3516 		this->requestQuit(false);
3517 	}
3518 }
3519 
requestQuit(bool force_quit)3520 void EndIslandGameState::requestQuit(bool force_quit) {
3521 	if( force_quit ) {
3522 		game_g->saveState();
3523 	    game_g->getApplication()->setQuit();
3524 	}
3525 	else {
3526 		game_g->setStateChanged(true);
3527 		this->fadeScreen(true, 0, returnToChooseIsland_g);
3528 	}
3529 }
3530 
reset()3531 void GameCompleteGameState::reset() {
3532     //LOG("GameCompleteGameState::reset()\n");
3533 	this->screen_page->free(true);
3534 }
3535 
draw()3536 void GameCompleteGameState::draw() {
3537 #if defined(__ANDROID__)
3538 	game_g->getScreen()->clear(); // SDL on Android requires screen be cleared (otherwise we get corrupt regions outside of the main area)
3539 #endif
3540 	game_g->background->draw(0, 0);
3541 
3542 	this->screen_page->draw();
3543 	//this->screen_page->drawPopups();
3544 
3545 	if( !game_g->isDemo() ) {
3546 		stringstream str;
3547 		int l_h = game_g->letters_large[0]->getScaledHeight();
3548 		int y = 80;
3549 
3550 		Image::writeMixedCase(160, y, game_g->letters_large, game_g->letters_small, game_g->numbers_white, "GAME COMPLETE", Image::JUSTIFY_CENTRE);
3551 		y += l_h + 2;
3552 
3553 		if( game_g->getDifficultyLevel() == DIFFICULTY_EASY )
3554 			str.str("Easy");
3555 		else if( game_g->getDifficultyLevel() == DIFFICULTY_MEDIUM )
3556 			str.str("Medium");
3557 		else if( game_g->getDifficultyLevel() == DIFFICULTY_HARD )
3558 			str.str("Hard");
3559 		else if( game_g->getDifficultyLevel() == DIFFICULTY_ULTRA )
3560 			str.str("Ultra");
3561 		else {
3562 			ASSERT(false);
3563 		}
3564 		Image::writeMixedCase(160, y, game_g->letters_large, game_g->letters_small, game_g->numbers_white, str.str().c_str(), Image::JUSTIFY_CENTRE);
3565 		y += l_h + 2;
3566 
3567 		y += l_h + 2;
3568 
3569 		str << "Men Remaining " << game_g->getMenAvailable();
3570 		Image::writeMixedCase(160, y, game_g->letters_large, game_g->letters_small, game_g->numbers_white, str.str().c_str(), Image::JUSTIFY_CENTRE);
3571 		y += l_h + 2;
3572 
3573 		str.str("");
3574 		str << "Men Saved " << game_g->getNSuspended();
3575 		Image::writeMixedCase(160, y, game_g->letters_large, game_g->letters_small, game_g->numbers_white, str.str().c_str(), Image::JUSTIFY_CENTRE);
3576 		y += l_h + 2;
3577 
3578 		int score = game_g->getMenAvailable() + game_g->getNSuspended();
3579 		str.str("");
3580 		str << "Total Score " << score;
3581 		Image::writeMixedCase(160, y, game_g->letters_large, game_g->letters_small, game_g->numbers_white, str.str().c_str(), Image::JUSTIFY_CENTRE);
3582 		y += l_h + 2;
3583 	}
3584 
3585 	GameState::setDefaultMouseImage();
3586 	GameState::draw();
3587 }
3588 
mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click)3589 void GameCompleteGameState::mouseClick(int m_x,int m_y,bool m_left,bool m_middle,bool m_right,bool click) {
3590 	GameState::mouseClick(m_x, m_y, m_left, m_middle, m_right, click);
3591 
3592 	//bool m_left = mouse_left(m_b);
3593 	//bool m_right = mouse_right(m_b);
3594 
3595 	if( ( m_left || m_right ) && click && !game_g->isStateChanged() ) {
3596 		this->requestQuit(false);
3597 	}
3598 }
3599 
requestQuit(bool force_quit)3600 void GameCompleteGameState::requestQuit(bool force_quit) {
3601 	if( force_quit ) {
3602 		game_g->saveState();
3603 	    game_g->getApplication()->setQuit();
3604 	}
3605 	else {
3606 		game_g->setStateChanged(true);
3607 		this->fadeScreen(true, 0, startNewGame_g);
3608 	}
3609 }
3610