1 /* factoroids.c
2 
3    The main game loop for a factoring game resembling the
4    arcade classic "Asteroids".
5 
6    Some code adapted from the GPL-licensed game "vectoroids"
7    by Bill Kendrick (http://www.newbreedsoftware.com).
8 
9    Copyright 2001, 2002, 2008, 2009, 2010.
10 Authors: Bill Kendrick, Jesus M. Mager H., Tim Holy, David Bruce
11 Project email: <tuxmath-devel@lists.sourceforge.net>
12 Project website: http://tux4kids.alioth.debian.org
13 
14 
15 factoroids.c is part of "Tux, of Math Command", a.k.a. "tuxmath".
16 
17 Tuxmath is free software: you can redistribute it and/or modify
18 it under the terms of the GNU General Public License as published by
19 the Free Software Foundation; either version 3 of the License, or
20 (at your option) any later version.
21 
22 Tuxmath is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25 GNU General Public License for more details.
26 
27 You should have received a copy of the GNU General Public License
28 along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
29 
30 
31 
32 #include "tuxmath.h"
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include "SDL.h"
39 #ifndef NOSOUND
40 #include "SDL_mixer.h"
41 #endif
42 #include "SDL_image.h"
43 #include "SDL_rotozoom.h"
44 
45 #include "credits.h"
46 #include "game.h"
47 #include "fileops.h"
48 #include "setup.h"
49 #include "mathcards.h"
50 #include "titlescreen.h"
51 #include "options.h"
52 
53 #define FPS 15                     /* 15 frames per second */
54 #define MS_PER_FRAME (1000 / FPS)
55 #define BASE_RES_X 1280
56 #define ASTEROID_NUM_SIZE 48
57 
58 #define MAX_LASER 5
59 #define MAX_ASTEROIDS 50
60 #define NUM_TUXSHIPS 2
61 #define NUM_SPRITES 11
62 #define TUXSHIP_LIVES 3
63 #define DEG_PER_ROTATION 2
64 #define NUM_OF_ROTO_IMGS 360/DEG_PER_ROTATION
65 /* TUXSHIP_DECEL controls "friction" - 1 means ship glides infinitely, 0 stops it instantly */
66 #define TUXSHIP_DECEL 0.95
67 #define DEG_TO_RAD 0.0174532925
68 #define MAX(a,b)           (((a) > (b)) ? (a) : (b))
69 //the prime set keeps increasing till its size reaches this value
70 #define PRIME_MAX_LIMIT 6
71 
72 #define CTRL_NEXT SDLK_f
73 #define CTRL_PREV SDLK_d
74 
75 /* definitions of level message */
76 #define MAX_CHAR_MSG 256
77 #define LVL_WIDTH_MSG 350
78 #define LVL_HEIGHT_MSG 200
79 #define LVL_OBJ_X_OFFSET 20
80 #define LVL_OBJ_Y_OFFSET 20
81 #define LVL_HINT_X_OFFSET 20
82 #define LVL_HINT_Y_OFFSET 130
83 
84 /* definitions for cockpit buttons */
85 #define BUTTONW 24
86 #define BUTTONH 24
87 #define BUTTON2_X 65
88 #define BUTTON2_Y 45
89 #define BUTTON3_X 53
90 #define BUTTON3_Y 65
91 #define BUTTON5_X 30
92 #define BUTTON5_Y 77
93 #define BUTTON7_X 8
94 #define BUTTON7_Y 77
95 #define BUTTON11_X 30
96 #define BUTTON11_Y 65
97 #define BUTTON13_X 45
98 #define BUTTON13_Y 45
99 #define NUMBUTTONS 6
100 
101 //a value (float) indicating the sensitivity of the mouse
102 //0 = disable mouse; 0.1 high ... 1 low, 2 lower, so on
103 //FIXME - this is a very quick/dirty response to my observation
104 //that the mouse sensitivity is too high in my initial tests
105 //of the win32 build. We ought to figure out if we can get
106 //some info from the OS under SDL to set this better, and
107 //also provide a way for users to adjust this setting.
108 #if defined BUILD_MINGW32 || defined __APPLE__
109 #define MOUSE_SENSITIVITY 2
110 #else
111 #define MOUSE_SENSITIVITY 0.5
112 #endif
113 
114 //a special value indicating that a bonus hasn't been used yet
115 #define BONUS_NOTUSED -1
116 
117 /********* Enumerations ***********/
118 
119 enum{
120     FACTOROIDS_GAME,
121     FRACTIONS_GAME
122 };
123 
124 /* Enumerations for Button Types in Cockpit */
125 enum BUTTON_TYPE
126 {
127     ACTIVE,
128     SELECTED,
129     PRESSED,
130     DISABLED
131 };
132 
133 enum FF_STATUS
134 {
135     FF_OVER_SDL_QUIT,
136     FF_OVER_ESCAPE,
137     FF_OVER_LOST,
138     FF_OVER_WON,
139     FF_OVER_ERROR,
140     FF_OVER_OTHER,
141     FF_IN_PROGRESS
142 };
143 
144 /********* Structures *********/
145 
146 typedef struct colorRGBA_type {
147     Uint8 r;
148     Uint8 g;
149     Uint8 b;
150     Uint8 a;
151 } ColorRGBA_type;
152 
153 typedef struct asteroid_type {
154     int alive, size;
155     int angle, angle_speed;
156     int xspeed, yspeed;
157     int x, y;
158     int rx, ry;
159     int centerx, centery;
160     int radius;
161     int fact_number;
162     int isprime;
163     int a, b; /*  a / b */
164     int count;
165     int xdead, ydead, isdead, countdead;
166 } asteroid_type;
167 
168 
169 typedef struct tuxship_type {
170     int lives, size;
171     int xspeed, yspeed;
172     int x, y;
173     int rx, ry;
174     int x1,y1,x2,y2,x3,y3;
175     int radius;
176     int centerx, centery;
177     int angle;
178     int hurt, hurt_count;
179     int count;
180     bool thrust;
181 } tuxship_type;
182 
183 
184 typedef struct FF_laser_type{
185     int alive;
186     int x, y;
187     int destx,desty;
188     int r, g, b;
189     int count;
190     int angle;
191     int m;
192     int n;
193 } FF_laser_type;
194 
195 
196 typedef struct {
197     int x_is_blinking;
198     int extra_life_is_blinking;
199     int laser_enabled;
200 } help_controls_type;
201 
202 /* Structures for Buttons on Cockpit */
203 struct ButtonType
204 {
205     int img_id;
206     int x;
207     int y;
208     int prime;
209 };
210 
211 /********* Enums ******************/
212 
213 typedef enum _TuxBonus {
214     TB_CLOAKING, TB_FORCEFIELD, TB_POWERBOMB, TB_SIZE
215 } TuxBonus;
216 
217 int bonus_img_ids[] = {
218     IMG_BONUS_CLOAKING, IMG_BONUS_FORCEFIELD, IMG_BONUS_POWERBOMB
219 };
220 
221 /********* Global vars ************/
222 
223 /* Trig junk:  (thanks to Atari BASIC for this) */
224 
225 static int trig[12] = {
226     1024,
227     1014,
228     984,
229     935,
230     868,
231     784,
232     685,
233     572,
234     448,
235     316,
236     117,
237     0
238 };
239 
240 static int bonus = -1;
241 static int bonus_time = BONUS_NOTUSED;
242 
243 static const int prime_numbers[] = {2, 3, 5, 7, 11, 13};
244 static const int prime_power_limit[] = {7, 4, 3, 3, 2, 2}; //custom calibrated power limits for extra "goodness"
245 
246 static const int prime_next[] = {2, 2, 3, 5, 5, 7, 7, 11, 11, 11, 11, 13, 13, 2};
247 static const int prime_prev[] = {13, 13, 13, 2, 3, 3, 3, 5, 5, 7, 7, 7, 7, 11, 11};
248 
249 static char* game_music_filenames[NUM_MUSICS] = {
250     "01_rush.ogg",
251     "02_on_the_edge_of_the_universe.ogg",
252     "03_gravity.ogg",
253     "game.mod",
254     "game2.mod",
255     "game3.mod",
256 };
257 
258 static int laser_coeffs[][3] = {
259     {0, 0, 0},	// 0
260     {0, 0, 0},	// 1
261     {18, 0, 0},	// 2
262     {0, 18, 0},	// 3
263     {0, 0, 0},	// 4
264     {0, 0, 18},	// 5
265     {0, 0, 0},	// 6
266     {18, 18, 0},// 7
267     {0, 0, 0},	// 8
268     {0, 0, 0},	// 9
269     {0, 0, 0},	// 10
270     {0, 18, 18},// 11
271     {0, 0, 0},	// 12
272     {18, 0, 18}	// 13
273 };
274 
275 // ControlKeys
276 static int mouseroto;
277 static int left_pressed;
278 static int right_pressed;
279 static int up_pressed;
280 static int shift_pressed;
281 static int shoot_pressed;
282 static int button_pressed;
283 
284 // GameControl
285 static int game_status;
286 //static int gameover_counter;
287 static int escape_received;
288 
289 //SDL_Surfaces:
290 static SDL_Surface* IMG_lives_ship = NULL;
291 static SDL_Surface* IMG_tuxship[NUM_OF_ROTO_IMGS];
292 static SDL_Surface* IMG_tuxship_cloaked[NUM_OF_ROTO_IMGS];
293 static SDL_Surface* IMG_tuxship_thrust[NUM_OF_ROTO_IMGS];
294 static SDL_Surface* IMG_tuxship_thrust_cloaked[NUM_OF_ROTO_IMGS];
295 static SDL_Surface* IMG_asteroids1[NUM_OF_ROTO_IMGS];
296 static SDL_Surface* IMG_asteroids2[NUM_OF_ROTO_IMGS];
297 static SDL_Surface* bkgd = NULL; //640x480 background (windowed)
298 static SDL_Surface* scaled_bkgd = NULL; //native resolution (fullscreen)
299 
300 //Scale factor for window size/resolution
301 static float zoom;
302 
303 // Game type
304 static int FF_game;
305 
306 // Game vars
307 static int score;
308 static int wave;
309 static int paused;
310 static int escape_received;
311 static int game_status;
312 static int SDL_quit_received;
313 static int quit;
314 static int digits[3];
315 static int num;
316 static int mouse_reset;
317 
318 static int neg_answer_picked;
319 static int tux_pressing;
320 static int doing_answer;
321 static int tux_img;
322 //static int FF_level;
323 
324 static asteroid_type* asteroid = NULL;
325 static tuxship_type tuxship;
326 static FF_laser_type laser[MAX_LASER];
327 
328 static int NUM_ASTEROIDS;
329 static int counter;
330 static int roto_speed;
331 
332 static struct ButtonType buttons[NUMBUTTONS];
333 
334 /*************** The Factor and Fraction Activity Game Functions ***************/
335 
336 /* Local function prototypes: */
337 
338 static int FF_init(void);
339 static void FF_intro(void);
340 
341 static void FF_handle_ship(void);
342 static void FF_handle_asteroids(void);
343 static void FF_handle_answer(void);
344 static int check_exit_conditions(void);
345 static void FF_draw(void);
346 static void FF_draw_bkgr(void);
347 static void FF_draw_led_console(void);
348 static void draw_console_image(int i);
349 void draw_nums(const char* str, int x, int y, SDL_Color* col);
350 
351 static void FF_DrawButton(int img_id, enum BUTTON_TYPE type, int x, int y);
352 static void FF_DrawButtonLayout(void);
353 static void FF_ButtonInit(void);
354 static int FF_CockpitTux(int prime);
355 
current_bkgd()356 static SDL_Surface* current_bkgd()
357 { return screen->flags & SDL_FULLSCREEN ? scaled_bkgd : bkgd; }
358 
359 static void FF_add_level(void);
360 static int FF_over(int game_status);
361 static void FF_exit_free(void);
362 
363 static int FF_add_laser(void);
364 static int FF_add_asteroid(int x, int y, int xspeed, int yspeed, int size, int angle, int 				   angle_speed, int fact_num, int a, int b, int new_wave);
365 static int FF_destroy_asteroid(int i, float xspeed, float yspeed);
366 
367 static void FF_ShowMessage(char* str);
368 static void FF_LevelMessage(void);
369 static void FF_LevelObjsHints(char *label, char *contents, int x, int y);
370 
371 static SDL_Surface* get_asteroid_image(int size,int angle);
372 static int AsteroidColl(int astW,int astH,int astX,int astY,
373 	int x, int y);
374 static int is_prime(int num);
375 static int fast_cos(int angle);
376 static int fast_sin(int angle);
377 static int generatenumber(int wave);
378 static int validate_number(int num, int wave);
379 static void game_handle_user_events(void);
380 static int game_mouse_event(SDL_Event event);
game_mouseroto(SDL_Event event)381 static int game_mouseroto(SDL_Event event) {return event.motion.xrel;}
382 static void _tb_PowerBomb(int n);
383 
384 /************** factors(): The factor main function ********************/
factors(void)385 void factors(void)
386 {
387     Uint32 timer = 0;
388 
389     quit = 0;
390     counter = 0;
391 
392     DEBUGMSG(debug_factoroids, "Entering factors():\n");
393 
394     FF_game = FACTOROIDS_GAME;
395 
396     if (!FF_init())
397     {
398 	fprintf(stderr, "FF_init() failed!\n");
399 	FF_exit_free();
400 	return;
401     }
402     FF_LevelMessage();
403 
404     while (game_status == FF_IN_PROGRESS)
405     {
406 	counter++;
407 
408 	game_handle_user_events();
409 	if(SDL_GetTicks() > bonus_time && bonus_time != -1) {bonus_time = 0;}
410 
411 	FF_handle_ship();
412 	FF_handle_asteroids();
413 	FF_handle_answer();
414 
415 	tux_img = FF_CockpitTux(num);
416 
417 	FF_draw();
418 	SDL_Flip(screen);
419 
420 	game_status = check_exit_conditions();
421 
422 	if (paused)
423 	{
424 	    pause_game();
425 	    paused = 0;
426 	}
427 
428 
429 #ifndef NOSOUND
430 	if (Opts_UsingSound())
431 	{
432 	    //...when the music's over, turn out the lights!
433 	    //...oops, wrong song! Actually, we just pick next music at random:
434 	    if (!Mix_PlayingMusic())
435 	    {
436 		T4K_AudioMusicLoad(game_music_filenames[(rand() % NUM_MUSICS)], T4K_AUDIO_PLAY_ONCE);
437 	    }
438 	}
439 #endif
440 
441 	/* Pause (keep frame-rate event) */
442 	T4K_Throttle(MS_PER_FRAME, &timer);
443     }
444     FF_over(game_status);
445 }
446 
447 
448 /************** fractions(): The fractions main function ********************/
fractions(void)449 void fractions(void)
450 {
451     Uint32 timer = 0;
452     quit = 0;
453     counter = 0;
454     tux_img = IMG_TUX_CONSOLE1;
455 
456     DEBUGMSG(debug_factoroids, "Entering factors():\n");
457     /*****Initalizing the Factor activiy *****/
458     FF_game = FRACTIONS_GAME;
459 
460     if (!FF_init())
461     {
462 	fprintf(stderr, "FF_init() failed!\n");
463 	FF_exit_free();
464 	return;
465     }
466 
467     /************ Main Loop **************/
468     while (game_status == FF_IN_PROGRESS)
469     {
470 	counter++;
471 
472 	if(counter%15 == 0)
473 	{
474 	    if(tux_img < IMG_TUX_CONSOLE4)
475 		tux_img++;
476 	    else
477 		tux_img = IMG_TUX_CONSOLE1;
478 	}
479 
480 	game_handle_user_events();
481 
482 	FF_handle_ship();
483 	FF_handle_asteroids();
484 	FF_handle_answer();
485 	FF_draw();
486 	SDL_Flip(screen);
487 
488 	game_status = check_exit_conditions();
489 
490 	if (paused)
491 	{
492 	    pause_game();
493 	    paused = 0;
494 	}
495 
496 
497 #ifndef NOSOUND
498 	if (Opts_UsingSound())
499 	{
500 	    if (!Mix_PlayingMusic())
501 	    {
502 		T4K_AudioMusicLoad(game_music_filenames[(rand() % 3)], T4K_AUDIO_PLAY_ONCE);
503 	    }
504 	}
505 #endif
506 
507 	/* Pause (keep frame-rate event) */
508 	T4K_Throttle(MS_PER_FRAME, &timer);
509     }
510     FF_over(game_status);
511 }
512 
FF_LevelMessage(void)513 static void FF_LevelMessage(void)
514 {
515     SDL_Event event;
516     SDL_Rect rect;
517     SDL_Surface *bgsurf=NULL;
518     int nwave;
519     Uint32 timer =0;
520     int waiting = 1;
521 
522     char objs_str[PRIME_MAX_LIMIT][MAX_CHAR_MSG] =
523     {
524 	N_("Powers of 2"),
525 	N_("Products of 2 and 3"),
526 	N_("Products of 2, 3 and 5"),
527 	N_("Products of 2, 3, 5 and 7"),
528 	N_("Products of 2, 3, 5, 7, and 11"),
529 	N_("Products of 2, 3, 5, 7, 11 and 13")
530     };
531 
532     char hints_str[PRIME_MAX_LIMIT][MAX_CHAR_MSG] =
533     {
534 	N_("All multiples of 2 end in 2, 4, 6, 8, or 0"),
535 	N_("The digits of a multiple of 3 add up to a multiple of 3"),
536 	N_("All multiples of 5 end in 0 or 5"),
537 	N_("Sorry - there is no simple rule to identify multiples of 7."),
538 	N_("Under 100, multiples of 11 have equal digits, such as 55 or 88."),
539 	N_("Sorry - there is no simple rule to identify multiples of 13."),
540     };
541 
542     rect.x = (screen->w/2)-(LVL_WIDTH_MSG/2);
543     rect.y = (screen->h/2)-(LVL_HEIGHT_MSG/2);
544 
545     FF_draw();
546     bgsurf = T4K_CreateButton(LVL_WIDTH_MSG,LVL_HEIGHT_MSG,12,19,19,96,96);
547 
548     if(bgsurf)
549     {
550 	SDL_BlitSurface(bgsurf, NULL, screen, &rect );
551 	SDL_FreeSurface(bgsurf);
552     }
553 
554     nwave = (wave > PRIME_MAX_LIMIT) ? PRIME_MAX_LIMIT : wave;
555 
556     FF_LevelObjsHints(_("Objectives:"), _(objs_str[nwave-1]), rect.x+LVL_OBJ_X_OFFSET, rect.y+LVL_OBJ_Y_OFFSET);
557     FF_LevelObjsHints(_("Hints:"), _(hints_str[nwave-1]), rect.x+LVL_HINT_X_OFFSET, rect.y+LVL_HINT_Y_OFFSET);
558 
559     SDL_Flip(screen);
560 
561     /* wait for user events */
562     while(waiting)
563     {
564 	while(SDL_PollEvent(&event))
565 	{
566 	    if (event.type == SDL_QUIT)
567 	    {
568 		SDL_quit_received = 1;
569 		quit = 1;
570 		waiting = 0;
571 		break;
572 	    }
573 	    else if (event.type == SDL_MOUSEBUTTONDOWN)
574 	    {
575 		waiting = 0;
576 		break;
577 	    }
578 	    else if (event.type == SDL_KEYDOWN)
579 	    {
580 		if (event.key.keysym.sym == SDLK_ESCAPE)
581 		    escape_received = 1;
582 		waiting = 0;
583 		break;
584 	    }
585 	}
586 	/* keep from eating all CPU: */
587 	T4K_Throttle(MS_PER_FRAME, &timer);
588     }
589 }
590 
591 /************ Initialize all vars... ****************/
FF_init(void)592 static int FF_init(void)
593 {
594     Uint32 timer = 0;
595     int i;
596     mouse_reset = 0;
597 
598     SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
599     SDL_Flip(screen);
600     SDL_ShowCursor(0);
601 
602     /* Settings to let us track mouse movement even beyond edge of screen
603      * for control of ship rotation.  Note that SDL reportedly supports
604      * this only on "Windows and Unix-alikes", i.e. maybe not OS-X
605      */
606     SDL_WM_GrabInput(SDL_GRAB_ON);
607 
608     /********   Set up properly scaled and optimized background surfaces: *********/
609     /* NOTE - optimization code moved into LoadBothBkgds() so rest of program     */
610     /* can take advantage of it - DSB                                             */
611 
612     T4K_LoadBothBkgds("factoroids/gbstars.png", &scaled_bkgd, &bkgd);
613 
614     if (bkgd == NULL || scaled_bkgd == NULL)
615     {
616 	fprintf(stderr,
617 		"\nError: could not scale background\n");
618 	return 0;
619     }
620 
621     FF_intro();
622 
623     if(screen->h < 600 && screen->w < 800)
624 	zoom = 0.65;
625     else
626 	zoom = (float)screen->w/(float)BASE_RES_X;
627 
628     DEBUGCODE(debug_factoroids)
629 	fprintf(stderr, "The zoom factor is: %f\n", zoom);
630 
631     /*************** Precalculating software rotation ***************/
632 
633     for(i = 0; i < NUM_OF_ROTO_IMGS; i++)
634     {
635 	//rotozoomSurface (SDL_Surface *src, double angle, double zoom, int smooth);
636 	IMG_tuxship[i] = rotozoomSurface(images[IMG_SHIP01], i * DEG_PER_ROTATION, zoom, 1);
637 	IMG_tuxship_cloaked[i] = rotozoomSurface(images[IMG_SHIP_CLOAKED], i * DEG_PER_ROTATION, zoom, 1);
638 	IMG_tuxship_thrust[i] = rotozoomSurface(images[IMG_SHIP_THRUST], i * DEG_PER_ROTATION, zoom, 1);
639 	IMG_tuxship_thrust_cloaked[i] = rotozoomSurface(images[IMG_SHIP_THRUST_CLOAKED], i * DEG_PER_ROTATION, zoom, 1);
640 
641 	if (IMG_tuxship[i] == NULL)
642 	{
643 	    fprintf(stderr,
644 		    "\nError: rotozoomSurface() of images[IMG_SHIP01] for i = %d returned NULL\n", i);
645 	    return 0;
646 	}
647 
648 	IMG_asteroids1[i] = rotozoomSurface(images[IMG_ASTEROID1], i * DEG_PER_ROTATION, zoom, 1);
649 
650 	if (IMG_asteroids1[i] == NULL)
651 	{
652 	    fprintf(stderr,
653 		    "\nError: rotozoomSurface() of images[IMG_ASTEROID1] for i = %d returned NULL\n", i);
654 	    return 0;
655 	}
656 
657 	IMG_asteroids2[i] = rotozoomSurface(images[IMG_ASTEROID2], i*DEG_PER_ROTATION, zoom, 1);
658 
659 	if (IMG_asteroids2[i] == NULL)
660 	{
661 	    fprintf(stderr,
662 		    "\nError: rotozoomSurface() of images[IMG_ASTEROID2] for i = %d returned NULL\n", i);
663 	    return 0;
664 	}
665     }
666 
667 
668     /* Create zoomed and scaled ship image for "lives" counter */
669     IMG_lives_ship = rotozoomSurface(images[IMG_SHIP_CLOAKED], 90, zoom * 0.7, 1);
670 
671 
672     /********   Set up properly scaled and optimized background surfaces: *********/
673     /* NOTE - optimization code moved into LoadBothBkgds() so rest of program     */
674     /* can take advantage of it - DSB                                             */
675 
676     T4K_LoadBothBkgds("factoroids/gbstars.png", &scaled_bkgd, &bkgd);
677 
678     if (bkgd == NULL || scaled_bkgd == NULL)
679     {
680 	fprintf(stderr,
681 		"\nError: could not scale background\n");
682 	return 0;
683     }
684 
685 
686     // Allocate memory
687     asteroid = NULL;  // set in case allocation fails partway through
688     asteroid = (asteroid_type *) malloc(MAX_ASTEROIDS * sizeof(asteroid_type));
689 
690     if (asteroid == NULL)
691     {
692 	fprintf(stderr, "Allocation of asteroids failed");
693 	return 0;
694     }
695 
696     memset(asteroid, 0, MAX_ASTEROIDS * sizeof(asteroid_type));
697 
698     NUM_ASTEROIDS = 4;
699 
700     /**************Setting up the ship values! **************/
701     tuxship.x = ((screen->w)/2) - 20;
702     tuxship.y = ((screen->h)/2) - 20;
703     tuxship.lives = TUXSHIP_LIVES;
704     tuxship.hurt = 0;
705     tuxship.hurt_count = 0;
706     tuxship.angle = 90;
707     tuxship.xspeed = 0;
708     tuxship.yspeed = 0;
709     tuxship.radius = (images[IMG_SHIP01]->h)/2;
710     tuxship.thrust = 0;
711 
712     tuxship.x1 = images[IMG_SHIP01]->w-(images[IMG_SHIP01]->w/8);
713     tuxship.y1 = images[IMG_SHIP01]->h/2;
714     tuxship.x2 = images[IMG_SHIP01]->w/8;
715     tuxship.y2 = images[IMG_SHIP01]->h/8;
716     tuxship.x3 = images[IMG_SHIP01]->w/8;
717     tuxship.y3 = images[IMG_SHIP01]->h-(images[IMG_SHIP01]->h/8);
718 
719     /*  --- reset all controls:  ---  */
720     left_pressed = 0;
721     right_pressed = 0;
722     up_pressed = 0;
723     shift_pressed = 0;
724     shoot_pressed = 0;
725     button_pressed = 0;
726     SDL_quit_received = 0;
727     score = 0;
728     wave = 0;
729     escape_received = 0;
730     game_status = FF_IN_PROGRESS;
731 
732     FF_add_level();
733 
734     for (i = 0; i < MAX_LASER; i++)
735 	laser[i].alive = 0;
736 
737     // Wait for click or keypress to start (get out if user presses Esc) :
738     while(1)
739     {
740 	SDL_PollEvent(&event);
741 	if (event.type == SDL_QUIT)
742 	{
743 	    SDL_quit_received = 1;
744 	    quit = 1;
745 	    return 1;
746 	}
747 	else if (event.type == SDL_MOUSEBUTTONDOWN)
748 	{
749 	    return 1;
750 	}
751 	else if (event.type == SDL_KEYDOWN)
752 	{
753 	    if (event.key.keysym.sym == SDLK_ESCAPE)
754 		escape_received = 1;
755 	    return 1;
756 	}
757 	/* Don't eat all available CPU: */
758 	T4K_Throttle(MS_PER_FRAME, &timer);
759     }
760     T4K_Throttle(MS_PER_FRAME, &timer);
761 }
762 
763 
FF_intro(void)764 static void FF_intro(void)
765 {
766     static SDL_Surface* IMG_factors;
767     static SDL_Surface* IMG_fractions;
768 
769     SDL_Rect rect;
770 
771     float zoom;
772 
773     if(screen->h < 600 && screen->w < 800)
774 	zoom = 0.65;
775     else
776 	zoom=(float)screen->w/(float)BASE_RES_X;
777 
778     IMG_factors   = rotozoomSurface(images[IMG_FACTOROIDS], 0, zoom, 1);
779     IMG_fractions = rotozoomSurface(images[IMG_FACTORS], 0, zoom, 1);
780 
781     FF_draw_bkgr();
782     if(FF_game == FACTOROIDS_GAME)
783     {
784 
785 	rect.x = (screen->w/2) - (IMG_factors->w/2);
786 	rect.y = (screen->h)/7;
787 	SDL_BlitSurface(IMG_factors, NULL, screen, &rect);
788 	FF_ShowMessage(_("To win, you must destroy all the asteroids.\n"
789 		    "Turn: arrow keys or mouse movement.\n"
790 		    "Thrust: up arrow or right mouse button.\n"
791 		    "Shoot: [Enter], [Space], or left mouse button.\n"
792 		    "Switch Prime Number Gun: [D], [F], or mouse scroll wheel.\n"
793 		    "Activate Powerup: [Shift].\n"
794 		    "Shoot the rocks with their prime factors until they are all destroyed."));
795 	SDL_BlitSurface(IMG_asteroids1[3],NULL,screen,&rect);
796     }
797     else if (FF_game == FRACTIONS_GAME)
798     {
799 	rect.x = (screen->w/2)-(IMG_fractions->w/2);
800 	rect.y = (screen->h)/7;
801 	SDL_BlitSurface(IMG_fractions,NULL,screen,&rect);
802 	FF_ShowMessage(_("FRACTIONS: to win, you need destroy all the asteroids. "
803 		    "Use the arrow keys to turn or go forward.  Aim at an asteroid, "
804 		    "type a number that can simplify the fraction, and press space or return "
805 		    "to split it.  Destroy fractions that can not be further simplified in a single shot!"));
806     }
807 
808     SDL_FreeSurface(IMG_factors);
809     SDL_FreeSurface(IMG_fractions);
810 }
811 
FF_handle_ship(void)812 static void FF_handle_ship(void)
813 {
814     //FIXME - am I missing something -- doesn't this just reduce to
815     //"tuxship.centerx = tuxship.x" and likewise for y???
816     /****************** Ship center... ******************/
817 
818     tuxship.centerx = ((IMG_tuxship[tuxship.angle/DEG_PER_ROTATION]->w)/2) +
819 	(tuxship.x - (IMG_tuxship[tuxship.angle/DEG_PER_ROTATION]->w/2));
820     tuxship.centery = ((IMG_tuxship[tuxship.angle/DEG_PER_ROTATION]->h)/2) +
821 	(tuxship.y - (IMG_tuxship[tuxship.angle/DEG_PER_ROTATION]->h/2));
822 
823     /******************* Ship live *********************/
824 
825     if(tuxship.hurt)
826     {
827 	tuxship.hurt_count--;
828 	if(tuxship.hurt_count <= 0)
829 	    tuxship.hurt = 0;
830     }
831     /****************** Rotate Ship *********************/
832 
833     if(right_pressed || left_pressed)
834     {
835 	if(roto_speed < 10)
836 	{
837 	    roto_speed = roto_speed + 2;
838 	}
839     }
840     else
841     {
842 	roto_speed = 1;
843     }
844 
845     if (right_pressed)
846     {
847 	tuxship.angle = tuxship.angle - DEG_PER_ROTATION * roto_speed;
848 	if (tuxship.angle < 0)
849 	    tuxship.angle = tuxship.angle + 360;
850 
851 	tuxship.x1= fast_cos(DEG_PER_ROTATION*-roto_speed) * tuxship.centerx
852 	    -fast_sin(DEG_PER_ROTATION*-roto_speed) * tuxship.centery;
853 	tuxship.y1= fast_sin(DEG_PER_ROTATION*-roto_speed) * tuxship.centerx
854 	    +fast_cos(DEG_PER_ROTATION*-roto_speed) * tuxship.centery;
855 
856     }
857     else if (left_pressed)
858     {
859 	tuxship.angle=tuxship.angle + DEG_PER_ROTATION * roto_speed;
860 	if (tuxship.angle >= 360)
861 	    tuxship.angle = tuxship.angle - 360;
862 
863 	tuxship.x1= fast_cos(DEG_PER_ROTATION*roto_speed) * tuxship.centerx
864 	    -fast_sin(DEG_PER_ROTATION*roto_speed) * tuxship.centery;
865 	tuxship.y1= fast_sin(DEG_PER_ROTATION*roto_speed * tuxship.centerx
866 		+fast_cos(DEG_PER_ROTATION*roto_speed)) * tuxship.centery;
867 
868     }
869 
870     /**************** Mouse Rotation ************************/
871     tuxship.angle = (tuxship.angle + DEG_PER_ROTATION * -mouseroto) % 360;
872     tuxship.angle += tuxship.angle < 0 ? 360 : 0;
873 
874     tuxship.x1= fast_cos(DEG_PER_ROTATION*roto_speed) * tuxship.centerx
875 	-fast_sin(DEG_PER_ROTATION*roto_speed) * tuxship.centery;
876     tuxship.y1= fast_sin(DEG_PER_ROTATION*roto_speed * tuxship.centerx
877 	    +fast_cos(DEG_PER_ROTATION*roto_speed)) * tuxship.centery;
878 
879     /**************** Move, and increse speed ***************/
880 
881 
882     if (up_pressed && (tuxship.lives > 0))
883     {
884 	tuxship.xspeed = tuxship.xspeed + ((fast_cos(tuxship.angle >> 3) * 3) >> 10);
885 	tuxship.yspeed = tuxship.yspeed - ((fast_sin(tuxship.angle >> 3) * 3) >> 10);
886 
887 	//Google Code-In 2010 Task: Add sound for ship's thrust
888 	//Sound taken from http://www.freesound.org 20/12/2010
889 	playsound(SND_ENGINE);
890 	tuxship.thrust = 1;
891     }
892     else
893     {
894 	if ((counter % 2) == 0)
895 	{
896 	    tuxship.xspeed = tuxship.xspeed * TUXSHIP_DECEL;
897 	    tuxship.yspeed = tuxship.yspeed * TUXSHIP_DECEL;
898 	    tuxship.thrust = 0;
899 	}
900     }
901 
902     tuxship.x = tuxship.x + tuxship.xspeed;
903     tuxship.y = tuxship.y + tuxship.yspeed;
904 
905     /*************** Wrap ship around edges of screen ****************/
906 
907     if(tuxship.x >= (screen->w))
908 	tuxship.x = tuxship.x - (screen->w);
909     else if (tuxship.x < -60)
910 	tuxship.x = tuxship.x + (screen->w);
911 
912     if(tuxship.y >= (screen->h))
913 	tuxship.y = tuxship.y - (screen->h);
914     else if (tuxship.y < -60)
915 	tuxship.y = tuxship.y + (screen->h);
916 
917     /**************** Shoot ***************/
918     if(shoot_pressed)
919     {
920 	FF_add_laser();
921 	shoot_pressed=0;
922     }
923 }
924 
925 
FF_handle_asteroids(void)926 static void FF_handle_asteroids(void){
927 
928     SDL_Surface* surf;
929     int i, found=0;
930     for (i = 0; i < MAX_ASTEROIDS; i++){
931 	if (asteroid[i].alive)
932 	{
933 
934 	    found=1;
935 
936 	    /*************** Rotate asteroid ****************/
937 
938 	    asteroid[i].angle = (asteroid[i].angle + asteroid[i].angle_speed);
939 
940 	    // Wrap rotation angle...
941 
942 	    if (asteroid[i].angle < 0)
943 		asteroid[i].angle = asteroid[i].angle + 360;
944 	    else if (asteroid[i].angle >= 360)
945 		asteroid[i].angle = asteroid[i].angle - 360;
946 
947 	    /**************Move the astroids ****************/
948 	    surf=get_asteroid_image(asteroid[i].size,asteroid[i].angle);
949 
950 	    asteroid[i].rx = asteroid[i].rx + asteroid[i].xspeed;
951 	    asteroid[i].ry = asteroid[i].ry + asteroid[i].yspeed;
952 
953 	    asteroid[i].x  = (asteroid[i].rx - (surf->w/2));
954 	    asteroid[i].y  = (asteroid[i].ry - (surf->h/2));
955 
956 	    // Wrap asteroid around edges of screen:
957 
958 	    if (asteroid[i].x >= (screen->w))
959 		asteroid[i].rx = asteroid[i].rx - (screen->w);
960 	    else if (asteroid[i].x < 0)
961 		asteroid[i].rx = asteroid[i].rx + (screen->w);
962 
963 	    if (asteroid[i].y >= (screen->h))
964 		asteroid[i].ry = asteroid[i].ry - (screen->h);
965 	    else if (asteroid[i].ry < 0)
966 		asteroid[i].ry = asteroid[i].ry + (screen->h);
967 	    /**************Center Asteroids**************/
968 
969 	    asteroid[i].centerx=((surf->w)/2)+(asteroid[i].x-5);
970 	    asteroid[i].centery=((surf->h)/2)+(asteroid[i].y-5);
971 
972 	    /*************** Collisions! ****************/
973 
974 	    if(AsteroidColl(surf->w, surf->h, asteroid[i].x, asteroid[i].y, tuxship.centerx, tuxship.centery) &&
975 		    !(bonus == TB_CLOAKING && bonus_time > 0))
976 	    {
977 		if(!tuxship.hurt)
978 		{
979 		    asteroid[i].xdead=asteroid[i].centerx;
980 		    asteroid[i].ydead=asteroid[i].centery;
981 
982 		    if(!(bonus == TB_FORCEFIELD && bonus_time > 0)) {
983 			tuxship.lives--;
984 			tuxship.hurt=1;
985 			tuxship.hurt_count=50;
986 		    }
987 		    FF_destroy_asteroid(i, tuxship.xspeed, tuxship.yspeed);
988 		    playsound(SND_EXPLOSION);
989 
990 		}
991 	    }
992 	}
993     }
994     if(!found)
995 	FF_add_level();
996 }
997 
FF_handle_answer(void)998 static void FF_handle_answer(void)
999 {
1000 
1001     num = (digits[0] * 100 +
1002 	    digits[1] * 10 +
1003 	    digits[2]);
1004     /* negative answer support DSB */
1005     if (neg_answer_picked)
1006     {
1007 	num = -num;
1008     }
1009 
1010     if (!doing_answer)
1011     {
1012 	return;
1013     }
1014 
1015     doing_answer = 0;
1016 
1017     neg_answer_picked = 0;
1018 
1019 }
1020 
get_asteroid_image(int size,int angle)1021 static SDL_Surface* get_asteroid_image(int size,int angle)
1022 {
1023     if (size == 0)
1024 	return IMG_asteroids1[angle/DEG_PER_ROTATION];
1025     else
1026 	return IMG_asteroids2[angle/DEG_PER_ROTATION];
1027 }
1028 
FF_draw(void)1029 static void FF_draw(void){
1030 
1031     int i, offset;
1032     int xnum, ynum;
1033     char str[64];
1034     SDL_Surface* surf;
1035     SDL_Rect dest;
1036 
1037     SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
1038 
1039     /************ Draw Background ***************/
1040 
1041     FF_draw_bkgr();
1042 
1043     /******************* Draw laser *************************/
1044     for (i=0;i<MAX_LASER;i++){
1045 	if(laser[i].alive)
1046 	{
1047 	    if(laser[i].count>0)
1048 	    {
1049 		laser[i].count--;
1050 		laser[i].x=laser[i].x+tuxship.xspeed;
1051 		laser[i].y=laser[i].y+tuxship.yspeed;
1052 		laser[i].destx=laser[i].destx+tuxship.xspeed;
1053 		laser[i].desty=laser[i].desty+tuxship.yspeed;
1054 		draw_line(laser[i].x, laser[i].y, laser[i].destx, laser[i].desty,
1055 			laser[i].count*laser_coeffs[laser[i].n][0], laser[i].count*laser_coeffs[laser[i].n][1], laser[i].count*laser_coeffs[laser[i].n][2]);
1056 	    } else if (laser[i].count <= 0)
1057 	    {
1058 		laser[i].alive=0;
1059 	    }
1060 	}
1061     }
1062     /*************** Draw Ship ******************/
1063 
1064     if(!tuxship.hurt || (tuxship.hurt && tuxship.hurt_count%2==0)){
1065 	dest.x = (tuxship.x - (IMG_tuxship[tuxship.angle/DEG_PER_ROTATION]->w/2));
1066 	dest.y = (tuxship.y - (IMG_tuxship[tuxship.angle/DEG_PER_ROTATION]->h/2));
1067 	dest.w = IMG_tuxship[tuxship.angle/DEG_PER_ROTATION]->w;
1068 	dest.h = IMG_tuxship[tuxship.angle/DEG_PER_ROTATION]->h;
1069 
1070 	//Change the image based on if the rocket is thrusting
1071 	//Google code in task
1072 
1073 	if(!tuxship.thrust) {
1074 	    SDL_Surface **_IMG_ship = bonus == TB_CLOAKING && bonus_time>0 ? IMG_tuxship_cloaked : IMG_tuxship;
1075 	    SDL_BlitSurface(_IMG_ship[tuxship.angle/DEG_PER_ROTATION], NULL, screen, &dest);
1076 	} else {
1077 	    SDL_Surface **_IMG_ship = bonus == TB_CLOAKING && bonus_time>0 ? IMG_tuxship_thrust_cloaked : IMG_tuxship_thrust;
1078 	    SDL_BlitSurface(_IMG_ship[tuxship.angle/DEG_PER_ROTATION], NULL, screen, &dest);
1079 	}
1080 
1081 
1082 
1083 	if(bonus == TB_FORCEFIELD && bonus_time > 0) {
1084 	    SDL_Rect tmp = {tuxship.x - images[IMG_FORCEFIELD]->w/2, tuxship.y - images[IMG_FORCEFIELD]->h/2};
1085 	    SDL_BlitSurface(images[IMG_FORCEFIELD], NULL, screen, &tmp);
1086 	}
1087     }
1088 
1089     /************* Draw Asteroids ***************/
1090     for(i=0; i<MAX_ASTEROIDS; i++){
1091 	if(asteroid[i].alive>0){
1092 
1093 	    xnum=0;
1094 	    ynum=0;
1095 
1096 	    dest.x = asteroid[i].x;
1097 	    dest.y = asteroid[i].y;
1098 
1099 	    surf=get_asteroid_image(asteroid[i].size,asteroid[i].angle);
1100 
1101 	    dest.w = surf->w;
1102 	    dest.h = surf->h;
1103 
1104 	    SDL_BlitSurface(surf, NULL, screen, &dest);
1105 
1106 	    // Wrap the numbers of the asteroids
1107 	    if((asteroid[i].centery)>23 && (asteroid[i].centery)<screen->h)
1108 	    {
1109 		if((asteroid[i].centerx)>0 && (asteroid[i].centerx)<screen->w)
1110 		{
1111 		    xnum=asteroid[i].centerx-3;
1112 		    ynum=asteroid[i].centery;
1113 		}
1114 		else if((asteroid[i].centerx)<=0){
1115 		    xnum=20;
1116 		    ynum=asteroid[i].centery;
1117 		}
1118 		else if((asteroid[i].centerx)<=screen->w){
1119 		    xnum=screen->w-20;
1120 		    ynum=asteroid[i].centery;
1121 		}
1122 	    }
1123 	    else if((asteroid[i].centery)<=23)
1124 	    {
1125 		xnum=asteroid[i].centerx;
1126 		ynum=23;
1127 	    }
1128 	    else if((asteroid[i].centery)>=screen->h)
1129 	    {
1130 		xnum=asteroid[i].centerx;
1131 		ynum=screen->h-7;
1132 	    }
1133 
1134 	    //Draw Numbers
1135 	    if(FF_game==FACTOROIDS_GAME)
1136 	    {
1137 		sprintf(str, "%.1d", asteroid[i].fact_number);
1138 		draw_nums(str, xnum, ynum, &white);
1139 	    }
1140 	    else if (FF_game==FRACTIONS_GAME)
1141 	    {
1142 		sprintf(str, "%d", asteroid[i].a);
1143 		draw_nums(str, xnum, ynum, &white);
1144 		draw_line(xnum, ynum + 4, xnum + 30, ynum + 4,
1145 			255, 255, 255);
1146 		sprintf(str, "%d", asteroid[i].b);
1147 		draw_nums(str, xnum, ynum + 35, &white);
1148 	    }
1149 	}
1150     }
1151     /*************** Draw Steam ***************/
1152     for(i=0; i<MAX_ASTEROIDS; i++)
1153     {
1154 	if(asteroid[i].isdead) {
1155 	    dest.x = asteroid[i].xdead;
1156 	    dest.y = asteroid[i].ydead;
1157 	    SDL_BlitSurface(images[IMG_STEAM1+asteroid[i].countdead], NULL, screen, &dest);
1158 	    if(bonus == TB_POWERBOMB && bonus_time > 0)
1159 		draw_line(asteroid[i].x, asteroid[i].y, tuxship.x, tuxship.y,
1160 			(5 - asteroid[i].countdead)*4*laser_coeffs[digits[1]*10+digits[2]][0],
1161 			(5 - asteroid[i].countdead)*4*laser_coeffs[digits[1]*10+digits[2]][1],
1162 			(5 - asteroid[i].countdead)*4*laser_coeffs[digits[1]*10+digits[2]][2]);
1163 	}
1164 
1165 
1166 	if(asteroid[i].isdead) {
1167 	    dest.x = asteroid[i].xdead;
1168 	    dest.y = asteroid[i].ydead;
1169 	    SDL_BlitSurface(images[IMG_STEAM1+asteroid[i].countdead], NULL, screen, &dest);
1170 	    asteroid[i].countdead++;
1171 	    if(asteroid[i].countdead > 5)
1172 	    {
1173 		asteroid[i].isdead = 0;
1174 		asteroid[i].countdead = 0;
1175 	    }
1176 	}
1177     }
1178 
1179     /* Draw wave: */
1180     if (1)//Opts_BonusCometInterval())
1181 	offset = images[IMG_EXTRA_LIFE]->w + 5;
1182     else
1183 	offset = 0;
1184 
1185     dest.x = offset;
1186 
1187     dest.y = 0;
1188     dest.w = images[IMG_WAVE]->w;
1189     dest.h = images[IMG_WAVE]->h;
1190 
1191     SDL_BlitSurface(images[IMG_WAVE], NULL, screen, &dest);
1192 
1193     sprintf(str, "%d", wave);
1194     draw_numbers(str, offset+images[IMG_WAVE]->w + (images[IMG_NUMBERS]->w / 10), 0);
1195 
1196     /* Draw "score" label: */
1197     dest.x = (screen->w - ((images[IMG_NUMBERS]->w/10) * 7) -
1198 	    images[IMG_SCORE]->w -
1199 	    images[IMG_STOP]->w - 5);
1200     dest.y = 0;
1201     dest.w = images[IMG_SCORE]->w;
1202     dest.h = images[IMG_SCORE]->h;
1203 
1204     SDL_BlitSurface(images[IMG_SCORE], NULL, screen, &dest);
1205 
1206     sprintf(str, "%.6d", score);
1207     draw_numbers(str,
1208 	    screen->w - ((images[IMG_NUMBERS]->w / 10) * 6) - images[IMG_STOP]->w - 5,
1209 	    0);
1210 
1211     /* Draw stop button: */
1212     //  if (!help_controls.x_is_blinking || (frame % 10 < 5)) {
1213     dest.x = (screen->w - images[IMG_STOP]->w);
1214     dest.y = 0;
1215     dest.w = images[IMG_STOP]->w;
1216     dest.h = images[IMG_STOP]->h;
1217 
1218     SDL_BlitSurface(images[IMG_STOP], NULL, screen, &dest);
1219     // }
1220 
1221     /************* Draw pre answer ************/
1222 
1223 
1224     if(screen->w < 800 && screen->h < 600)
1225     {
1226 	sprintf(str, "%.3d", num);
1227 	draw_numbers(str, ((screen->w)/2) - 50, (screen->h) - 30);
1228     }
1229     else
1230     {
1231 	FF_draw_led_console();
1232 	draw_console_image(tux_img);
1233     }
1234 
1235     /************** Draw lives ***************/
1236     dest.y = screen->h;
1237     dest.x = 0;
1238 
1239     for(i = 1; i <= tuxship.lives; i++)
1240     {
1241 	if(tuxship.lives <= 5)
1242 	{
1243 	    dest.y = dest.y - (IMG_lives_ship->h);
1244 	    SDL_BlitSurface(IMG_lives_ship, NULL, screen, &dest);
1245 	}
1246 	else if(tuxship.lives > 4)
1247 	{
1248 	    dest.y = screen->h - (IMG_lives_ship->h);
1249 	    SDL_BlitSurface(IMG_lives_ship, NULL, screen, &dest);
1250 	    sprintf(str, "%d", tuxship.lives);
1251 	    draw_numbers(str, 10, (screen->h) - 30);
1252 	}
1253     }
1254 
1255     /*** Draw Bonus Indicator ***/
1256     static int blink = 0;
1257     if(bonus_time == 0)
1258 	blink = 0;
1259     else if(bonus_time - SDL_GetTicks() > 3000)
1260 	blink = 5;
1261     else
1262 	blink = (blink + 1) % 10;
1263     if(bonus != -1 && blink>4) {
1264 	SDL_Surface *indicator = images[bonus_img_ids[bonus]];
1265 	SDL_Rect pos = {screen->w - indicator->w, screen->h - indicator->h};
1266 	SDL_BlitSurface(indicator, NULL, screen, &pos);
1267     }
1268 }
1269 
FF_DrawButton(int img_id,enum BUTTON_TYPE type,int x,int y)1270 static void FF_DrawButton(int img_id, enum BUTTON_TYPE type, int x, int y)
1271 {
1272     SDL_Rect rect, scr;
1273     rect.y = 0;
1274     rect.w = BUTTONW;
1275     rect.h = BUTTONH;
1276 
1277     scr.x = x;
1278     scr.y = y;
1279 
1280     if(type == ACTIVE)
1281     {
1282 	rect.x = 0;
1283 	SDL_BlitSurface(images[img_id], &rect, screen, &scr);
1284     }
1285     else if(type == SELECTED)
1286     {
1287 	rect.x = BUTTONW;
1288 	SDL_BlitSurface(images[img_id], &rect, screen, &scr);
1289     }
1290     else if(type == PRESSED)
1291     {
1292 	rect.x = BUTTONW * 2;
1293 	SDL_BlitSurface(images[img_id], &rect, screen, &scr);
1294     }
1295     else if(type == DISABLED)
1296     {
1297 	rect.x = BUTTONW * 3;
1298 	SDL_BlitSurface(images[img_id], &rect, screen, &scr);
1299     }
1300 }
1301 
FF_ButtonInit(void)1302 static void FF_ButtonInit(void)
1303 {
1304 
1305     buttons[0].img_id = IMG_BUTTON2;
1306     buttons[0].x = screen->w/2 - BUTTON2_X;
1307     buttons[0].y = screen->h - BUTTON2_Y;
1308     buttons[0].prime = 2;
1309 
1310     buttons[1].img_id = IMG_BUTTON3;
1311     buttons[1].x = screen->w/2 - BUTTON3_X;
1312     buttons[1].y = screen->h - BUTTON3_Y;
1313     buttons[1].prime = 3;
1314 
1315     buttons[2].img_id = IMG_BUTTON5;
1316     buttons[2].x = screen->w/2 - BUTTON5_X;
1317     buttons[2].y = screen->h - BUTTON5_Y;
1318     buttons[2].prime = 5;
1319 
1320     buttons[3].img_id = IMG_BUTTON7;
1321     buttons[3].x = screen->w/2 + BUTTON7_X;
1322     buttons[3].y = screen->h - BUTTON7_Y;
1323     buttons[3].prime = 7;
1324 
1325     buttons[4].img_id = IMG_BUTTON11;
1326     buttons[4].x = screen->w/2 + BUTTON11_X;
1327     buttons[4].y = screen->h - BUTTON11_Y;
1328     buttons[4].prime = 11;
1329 
1330     buttons[5].img_id = IMG_BUTTON13;
1331     buttons[5].x = screen->w/2 + BUTTON13_X;
1332     buttons[5].y = screen->h - BUTTON13_Y;
1333     buttons[5].prime = 13;
1334 
1335 }
1336 
FF_DrawButtonLayout(void)1337 static void FF_DrawButtonLayout(void)
1338 {
1339     int i;
1340     enum BUTTON_TYPE type;
1341 
1342     FF_ButtonInit();
1343 
1344     for(i=0; i<6; i++)
1345     {
1346 	if(i < wave)
1347 	{
1348 	    if(button_pressed && num==buttons[i].prime)
1349 	    {
1350 		type=PRESSED;
1351 	    }
1352 	    else if(num==buttons[i].prime)
1353 	    {
1354 		type=SELECTED;
1355 	    }
1356 	    else
1357 	    {
1358 		type = ACTIVE;
1359 	    }
1360 	}
1361 	else
1362 	{
1363 	    type = DISABLED;
1364 	}
1365 	FF_DrawButton(buttons[i].img_id,type,buttons[i].x,buttons[i].y);
1366     }
1367 }
1368 
FF_CockpitTux(int prime)1369 static int FF_CockpitTux( int prime )
1370 {
1371     switch( prime )
1372     {
1373 	case 2:
1374 	    return IMG_TUX1;
1375 	case 3:
1376 	    return IMG_TUX2;
1377 	case 5:
1378 	    return IMG_TUX3;
1379 	case 7:
1380 	    return IMG_TUX4;
1381 	case 11:
1382 	    return IMG_TUX5;
1383 	case 13:
1384 	    return IMG_TUX6;
1385 	default:
1386 	    return IMG_TUX1;
1387     }
1388 }
1389 
1390 /*Modified from game.c*/
FF_draw_led_console(void)1391 void FF_draw_led_console(void)
1392 {
1393     int i;
1394     SDL_Rect src, dest;
1395     int y;
1396 
1397 
1398     if(FF_game == FACTOROIDS_GAME)
1399     {
1400 	draw_console_image(IMG_COCKPIT);
1401 	FF_DrawButtonLayout();
1402     }
1403     else
1404     {
1405 	/* draw new console image with "monitor" for LED numbers: */
1406 	draw_console_image(IMG_CONSOLE_LED);
1407 
1408 	/* set y to draw LED numbers into Tux's "monitor": */
1409 	y = (screen->h
1410 		- images[IMG_CONSOLE_LED]->h
1411 		+ 4);  /* "monitor" has 4 pixel margin */
1412 
1413 	/* begin drawing so as to center display depending on whether minus */
1414 	/* sign needed (4 digit slots) or not (3 digit slots) DSB */
1415 	if (MC_GetOpt(ALLOW_NEGATIVES) )
1416 	    dest.x = ((screen->w - ((images[IMG_LEDNUMS]->w) / 10) * 4) / 2);
1417 	else
1418 	    dest.x = ((screen->w - ((images[IMG_LEDNUMS]->w) / 10) * 3) / 2);
1419 
1420 	for (i = -1; i < MC_MAX_DIGITS; i++) /* -1 is special case to allow minus sign */
1421 	    /* with minimal modification of existing code DSB */
1422 	{
1423 	    if (-1 == i)
1424 	    {
1425 		if (MC_GetOpt(ALLOW_NEGATIVES))
1426 		{
1427 		    if (neg_answer_picked)
1428 			src.x =  (images[IMG_LED_NEG_SIGN]->w) / 2;
1429 		    else
1430 			src.x = 0;
1431 		    src.y = 0;
1432 		    src.w = (images[IMG_LED_NEG_SIGN]->w) / 2;
1433 		    src.h = images[IMG_LED_NEG_SIGN]->h;
1434 
1435 		    dest.y = y;
1436 		    dest.w = src.w;
1437 		    dest.h = src.h;
1438 
1439 		    SDL_BlitSurface(images[IMG_LED_NEG_SIGN], &src, screen, &dest);
1440 		    /* move "cursor" */
1441 		    dest.x += src.w;
1442 		}
1443 	    }
1444 	    else
1445 	    {
1446 		src.x = digits[i] * ((images[IMG_LEDNUMS]->w) / 10);
1447 		src.y = 0;
1448 		src.w = (images[IMG_LEDNUMS]->w) / 10;
1449 		src.h = images[IMG_LEDNUMS]->h;
1450 
1451 		/* dest.x already set */
1452 		dest.y = y;
1453 		dest.w = src.w;
1454 		dest.h = src.h;
1455 
1456 		SDL_BlitSurface(images[IMG_LEDNUMS], &src, screen, &dest);
1457 		/* move "cursor" */
1458 		dest.x += src.w;
1459 	    }
1460 	}
1461     }
1462 }
1463 
1464 /* Draw image at lower center of screen: */
draw_console_image(int i)1465 void draw_console_image(int i)
1466 {
1467     SDL_Rect dest;
1468 
1469     dest.x = (screen->w - images[i]->w) / 2;
1470     dest.y = (screen->h - images[i]->h);
1471     dest.w = images[i]->w;
1472     dest.h = images[i]->h;
1473 
1474     SDL_BlitSurface(images[i], NULL, screen, &dest);
1475 }
1476 
FF_draw_bkgr(void)1477 static void FF_draw_bkgr(void)
1478 {
1479 
1480     SDL_BlitSurface(current_bkgd(), NULL, screen, NULL);
1481     //if(bgSrc.y>bkg_h)
1482     //  SDL_BlitSurface(images[BG_STARS], NULL, screen, &bgScreen);
1483 
1484 }
1485 
1486 /*Tree rectangle vs a point collitions
1487   returns 1 if the collitions is detected
1488   and 0 if not*/
1489 
AsteroidColl(int astW,int astH,int astX,int astY,int x,int y)1490 int AsteroidColl(int astW,int astH,int astX,int astY,
1491 	int x, int y)
1492 {
1493     int astWq=astW/8;
1494     int astHq=astH/8;
1495     int x1, y1, x2, y2;
1496 
1497     x1=astX+astWq*3;
1498     y1=astY;
1499 
1500     x2=astX+astWq*6;
1501     y2=astY+astH;
1502 
1503     if(x>x1 && x<x2 && y>y1 && y<y2)
1504 	return 1;
1505 
1506     x1=astX;
1507     y1=astY+astHq*3;
1508 
1509     x2=astW;
1510     y2=astY+astHq*6;
1511 
1512     if(x>x1 && x<x2 && y>y1 && y<y2)
1513 	return 1;
1514 
1515     x1=astX+astWq;
1516     y1=astY+astHq;
1517 
1518     x2=astX+astWq*7;
1519     y2=astY+astHq*7;
1520 
1521     if(x>x1 && x<x2 && y>y1 && y<y2)
1522 	return 1;
1523 
1524     return 0;
1525 }
1526 
1527 // Returns x % w but in the range [-w/2, w/2]
modwrap(int x,int w)1528 static int modwrap(int x,int w)
1529 {
1530     x = x % w;
1531     if (x > (w/2))
1532 	x -= w;
1533     else if (x < -(w/2))
1534 	x += w;
1535     return x;
1536 }
1537 
FF_add_level(void)1538 static void FF_add_level(void)
1539 {
1540     int i = 0;
1541     int x, y, xvel, yvel, dx, dy;
1542     int ok;
1543     int width;
1544     int safety_radius2, speed2;
1545     int max_speed;
1546     Uint32 timer = 0;
1547     SDL_Rect rect;
1548 
1549     wave++;
1550 
1551     // New lives per wave!
1552     if (wave%5==0)
1553     {
1554 	tuxship.lives++;
1555     }
1556 
1557     // Clear all bonuses obtained in a wave
1558     bonus_time = BONUS_NOTUSED; // Reset the timer for the bonus
1559     // And now reward a new bonus
1560     bonus = rand()%TB_SIZE;
1561 
1562     // Set active number to newly added prime
1563     int wave_i = wave - 1;
1564     if(wave>=PRIME_MAX_LIMIT) {
1565 	wave_i = PRIME_MAX_LIMIT - 1;
1566     }
1567     int c_prime = prime_numbers[wave_i];
1568     digits[2] = c_prime % 10;
1569     digits[1] = c_prime / 10;
1570 
1571     //Limit the new asteroids
1572     if(NUM_ASTEROIDS<MAX_ASTEROIDS)
1573 	NUM_ASTEROIDS=NUM_ASTEROIDS+wave;
1574     else
1575 	NUM_ASTEROIDS=MAX_ASTEROIDS;
1576 
1577     width = screen->w;
1578     if (screen->h < width)
1579 	width = screen->h;
1580 
1581     // Define the "safety radius" as one third of the screen width
1582     safety_radius2 = width/3;
1583     safety_radius2 = safety_radius2*safety_radius2; // the square distance
1584 
1585     // Define the max speed in terms of the screen width
1586     max_speed = width/100;
1587     if (max_speed == 0)
1588 	max_speed = 1;
1589 
1590     for (i=0; i<MAX_ASTEROIDS; i++)
1591 	asteroid[i].alive=0;
1592     for (i=0; i<NUM_ASTEROIDS && NUM_ASTEROIDS<MAX_ASTEROIDS; i++){
1593 	// Generate the new position, avoiding the location of the ship
1594 	ok = 0;
1595 	while (!ok) {
1596 	    x = rand()%(screen->w);
1597 	    y = rand()%(screen->h);
1598 	    dx = modwrap(x - tuxship.x,screen->w);
1599 	    dy = modwrap(y - tuxship.y,screen->h);
1600 	    if (dx*dx + dy*dy > safety_radius2)
1601 		ok = 1;
1602 	}
1603 	// Generate the new speed, making none of them stationary but none
1604 	// of them too fast
1605 	ok = 0;
1606 	while (!ok) {
1607 	    xvel = rand()%(2*max_speed+1) - max_speed;
1608 	    yvel = rand()%(2*max_speed+1) - max_speed;
1609 	    speed2 = xvel*xvel + yvel*yvel;
1610 	    if (speed2 != 0 && speed2 < max_speed*max_speed)
1611 		ok = 1;
1612 	}
1613 	if(FF_game == FACTOROIDS_GAME){
1614 	    FF_add_asteroid(x,y,
1615 		    xvel,yvel,
1616 		    rand()%2,
1617 		    rand()%360, rand()%3,
1618 		    generatenumber(wave),
1619 		    0, 0,
1620 		    1);
1621 	}
1622 	else if(FF_game==FRACTIONS_GAME){
1623 	    FF_add_asteroid(x,y,
1624 		    xvel,yvel,
1625 		    rand()%2,
1626 		    rand()%360, rand()%3,
1627 		    0,
1628 		    (rand()%(31+(wave*2))), (rand()%(80+(wave*wave))),
1629 		    1);
1630 	}
1631     }
1632 
1633     if(wave != 1)
1634     {
1635 	while(i < 35)
1636 	{
1637 	    i++;
1638 	    rect.x=(screen->w/2)-(images[IMG_GOOD]->w/2);
1639 	    rect.y=(screen->h/2)-(images[IMG_GOOD]->h/2);
1640 	    FF_draw();
1641 	    SDL_BlitSurface(images[IMG_GOOD],NULL,screen,&rect);
1642 	    SDL_Flip(screen);
1643 	    T4K_Throttle(MS_PER_FRAME, &timer);
1644 	}
1645 	FF_LevelMessage();
1646     }
1647 }
1648 
FF_over(int game_status)1649 static int FF_over(int game_status)
1650 {
1651     Uint32 timer = 0;
1652     SDL_Rect dest_message;
1653     SDL_Event event;
1654 
1655 
1656     /* TODO: need better "victory" screen with animation, special music, etc., */
1657     /* as well as options to review missed questions, play again using missed  */
1658     /* questions as question list, etc.                                        */
1659     /* TODO: also, some of these cases just redraw the background on every     */
1660     /* frame with nothing else - just copy-and-pasted code without much        */
1661     /* further attention.                                                      */
1662 
1663     /* Turn mouse cursor back on before we go back to menus: */
1664     SDL_ShowCursor(1);
1665     SDL_WM_GrabInput(SDL_GRAB_OFF);
1666 
1667 
1668     switch (game_status)
1669     {
1670 	case FF_OVER_WON:
1671 	    {
1672 		int looping = 1;
1673 
1674 		DEBUGMSG(debug_factoroids, "Loop exited with GAME_OVER_WON\n");
1675 
1676 		/* set up victory message: */
1677 		dest_message.x = (screen->w - images[IMG_GAMEOVER_WON]->w) / 2;
1678 		dest_message.y = (screen->h - images[IMG_GAMEOVER_WON]->h) / 2;
1679 		dest_message.w = images[IMG_GAMEOVER_WON]->w;
1680 		dest_message.h = images[IMG_GAMEOVER_WON]->h;
1681 
1682 		do
1683 		{
1684 		    //frame++;
1685 
1686 		    /* draw flashing victory message: */
1687 		    //if (((frame / 2) % 4))
1688 		    //{
1689 		    SDL_BlitSurface(images[IMG_GAMEOVER_WON], NULL, screen, &dest_message);
1690 		    //}
1691 
1692 
1693 		    SDL_Flip(screen);
1694 
1695 		    while (1)
1696 		    {
1697 			SDL_PollEvent(&event);
1698 			if  (event.type == SDL_QUIT
1699 				|| event.type == SDL_KEYDOWN
1700 				|| event.type == SDL_MOUSEBUTTONDOWN)
1701 			{
1702 			    looping = 0;
1703 			    break;
1704 			}
1705 			T4K_Throttle(MS_PER_FRAME, &timer);
1706 		    }
1707 		    T4K_Throttle(MS_PER_FRAME, &timer);
1708 		}
1709 		while (looping);
1710 		break;
1711 	    }
1712 
1713 	case FF_OVER_ERROR:
1714 	    {
1715 		DEBUGMSG(debug_factoroids, "Loop exited with  FF_OVER_ERROR\n");
1716 	    }
1717 	case FF_OVER_LOST:
1718 	case FF_OVER_OTHER:
1719 	    {
1720 		int looping = 1;
1721 
1722 		DEBUGMSG(debug_factoroids, "Loop exited with FF_OVER_LOST or FF_OVER_OTHER\n");
1723 
1724 		/* set up GAMEOVER message: */
1725 		dest_message.x = (screen->w - images[IMG_GAMEOVER]->w) / 2;
1726 		dest_message.y = (screen->h - images[IMG_GAMEOVER]->h) / 2;
1727 		dest_message.w = images[IMG_GAMEOVER]->w;
1728 		dest_message.h = images[IMG_GAMEOVER]->h;
1729 
1730 		do
1731 		{
1732 		    //frame++;
1733 		    SDL_BlitSurface(images[IMG_GAMEOVER], NULL, screen, &dest_message);
1734 		    SDL_Flip(screen);
1735 
1736 		    while (1)
1737 		    {
1738 			SDL_PollEvent(&event);
1739 			if  (event.type == SDL_QUIT
1740 				|| event.type == SDL_KEYDOWN
1741 				|| event.type == SDL_MOUSEBUTTONDOWN)
1742 			{
1743 			    looping = 0;
1744 			    break;
1745 			}
1746 			T4K_Throttle(MS_PER_FRAME, &timer);
1747 		    }
1748 		    T4K_Throttle(MS_PER_FRAME, &timer);
1749 		}
1750 		while (looping);
1751 
1752 		break;
1753 	    }
1754 
1755 	case FF_OVER_ESCAPE:
1756 	    {
1757 		DEBUGMSG(debug_factoroids, "Loop exited with FF_OVER_ESCAPE\n");
1758 		break;
1759 	    }
1760 
1761 	case FF_OVER_SDL_QUIT:
1762 	    {
1763 		DEBUGMSG(debug_factoroids, "Loop exited with FF_OVER_SDL_QUIT\n");
1764 		break;
1765 	    }
1766 
1767 	default:
1768 	    {
1769 		DEBUGMSG(debug_factoroids, "Loop exited with unrecognized status value: %dn", game_status);
1770 	    }
1771     }
1772 
1773     FF_exit_free();
1774 
1775     /* Save score in case needed for high score table: */
1776     Opts_SetLastScore(score);
1777 
1778     /* Return the chosen command: */
1779     if (GAME_OVER_WINDOW_CLOSE == game_status)
1780     {
1781 	/* program exits: */
1782 	FF_exit_free();;
1783 	return 1;
1784     }
1785     else
1786     {
1787 	/* return to title() screen: */
1788 	return 0;
1789     }
1790 }
1791 
1792 
FF_exit_free()1793 static void FF_exit_free()
1794 {
1795     int i = 0;
1796 
1797     free(asteroid);
1798 
1799     for(i = 0; i < NUM_OF_ROTO_IMGS; i++)
1800     {
1801 	if (IMG_tuxship[i])
1802 	{
1803 	    SDL_FreeSurface(IMG_tuxship[i]);
1804 	    IMG_tuxship[i] = NULL;
1805 	}
1806 	if (IMG_tuxship_thrust[i])
1807 	{
1808 	    SDL_FreeSurface(IMG_tuxship_thrust[i]);
1809 	    IMG_tuxship_thrust[i] = NULL;
1810 	}
1811 	if (IMG_tuxship_cloaked[i])
1812 	{
1813 	    SDL_FreeSurface(IMG_tuxship_cloaked[i]);
1814 	    IMG_tuxship_cloaked[i] = NULL;
1815 	}
1816 	if (IMG_tuxship_thrust_cloaked[i])
1817 	{
1818 	    SDL_FreeSurface(IMG_tuxship_thrust_cloaked[i]);
1819 	    IMG_tuxship_thrust_cloaked[i] = NULL;
1820 	}
1821 	if (IMG_asteroids1[i])
1822 	{
1823 	    SDL_FreeSurface(IMG_asteroids1[i]);
1824 	    IMG_asteroids1[i] = NULL;
1825 	}
1826 	if (IMG_asteroids2[i])
1827 	{
1828 	    SDL_FreeSurface(IMG_asteroids2[i]);
1829 	    IMG_asteroids2[i] = NULL;
1830 	}
1831     }
1832 
1833     if (IMG_lives_ship)
1834     {
1835 	SDL_FreeSurface(IMG_lives_ship);
1836 	IMG_lives_ship = NULL;
1837     }
1838 
1839     //  SDL_FreeSurface(*IMG_asteroids1);
1840     //  SDL_FreeSurface(*IMG_asteroids2);
1841     //  SDL_FreeSurface(*IMG_tuxship);
1842 
1843     if (bkgd)
1844     {
1845 	SDL_FreeSurface(bkgd);
1846 	bkgd = NULL;
1847     }
1848     if (scaled_bkgd)
1849     {
1850 	SDL_FreeSurface(scaled_bkgd);
1851 	scaled_bkgd = NULL;
1852     }
1853 
1854     /* Resume "normal" settings when we leave:
1855     */
1856     SDL_ShowCursor(1);
1857     SDL_WM_GrabInput(SDL_GRAB_OFF);
1858 }
1859 
1860 /******************* Math Funcs ***********************/
1861 
1862 /* Return 1 if the number is prime and 0 if its not */
is_prime(int num)1863 int is_prime(int num)
1864 {
1865     int i;
1866     if (num==0 || num==1 || num==-1) return 1;
1867     else if (num > 0)
1868     {
1869 
1870 	for(i = 2; i < num; i++)
1871 	{
1872 	    if(num%i == 0) return 0;
1873 	}
1874     }
1875     else if (num < 0)
1876     {
1877 	for(i = 2; i > num; i--)
1878 	{
1879 	    if(num%i == 0) return 0;
1880 	}
1881     }
1882     return 1;
1883 }
1884 
is_simplified(int a,int b)1885 int is_simplified(int a, int b)
1886 {
1887     int i;
1888     for(i=2; i<1000; i++)
1889 	if(((a%i)==0)&&((b%i)==0))
1890 	    return 0;
1891     return 1;
1892 }
1893 /*** Fast cos by Bill***/
1894 
fast_cos(int angle)1895 int fast_cos(int angle)
1896 {
1897     angle = (angle % 45);
1898 
1899     if (angle < 12)
1900 	return(trig[angle]);
1901     else if (angle < 23)
1902 	return(-trig[10 - (angle - 12)]);
1903     else if (angle < 34)
1904 	return(-trig[angle - 22]);
1905     else
1906 	return(trig[45 - angle]);
1907 }
1908 
1909 
1910 /*** Sine based on fast cosine..., by Bill ***/
1911 
fast_sin(int angle)1912 int fast_sin(int angle)
1913 {
1914     return(- fast_cos((angle + 11) % 45));
1915 }
1916 
1917 /*** fact_number generator by aviraldg ***/
1918 
generatenumber(int wave)1919 static int generatenumber(int wave) {
1920     if(wave > PRIME_MAX_LIMIT) wave = PRIME_MAX_LIMIT;
1921     int n=1, i;
1922     for(i=0; i<wave; i++)
1923 	n *= pow(prime_numbers[i], rand()%prime_power_limit[i]);
1924     /* If we somehow got a bogus number, try again: */
1925     if(validate_number(n, wave))
1926 	return n;
1927     else
1928     {
1929 	if (n > 1)  /* 1 can be generated without bugs and is innocuous */
1930 	    DEBUGMSG(debug_factoroids, "generatenumber() - wrn - invalid number: %d\n", n);
1931 	return generatenumber(wave);
1932     }
1933 }
1934 
1935 /*** For some reason, we have sometimes seen rocks with numbers */
1936 /*** that are not multiples of the desired primes.  Here we     */
1937 /*** factor those primes out and see what's left.               */
1938 /*** Returns 0 (false) if number is invalid.    DSB             */
validate_number(int num,int wave)1939 static int validate_number(int num, int wave)
1940 {
1941     int i = 0;
1942     if(num < 2)
1943 	return 0;
1944     if(wave > PRIME_MAX_LIMIT)
1945 	wave = PRIME_MAX_LIMIT;
1946     for(i = 0; i < wave; i++)
1947     {
1948 	while(num % prime_numbers[i] == 0)
1949 	    num /= prime_numbers[i];
1950     }
1951 
1952     /* If we aren't left with 1, the number is invalid: */
1953     if(num == 1)
1954 	return 1;
1955     else
1956 	return 0;
1957 }
1958 
1959 //implementation of the powerbomb powerup
_tb_PowerBomb(int num)1960 void _tb_PowerBomb (int num) {
1961     int i;
1962 
1963     for(i=0; i<MAX_ASTEROIDS; i++) {
1964 	if(asteroid[i].alive == 1) {
1965 	    if((FF_game==FACTOROIDS_GAME && (asteroid[i].isprime && ((num==asteroid[i].fact_number)||(num==0)))) ||
1966 		    (FF_game==FRACTIONS_GAME && (asteroid[i].isprime && num==0))) {
1967 		FF_destroy_asteroid(i, 0, 0);
1968 	    } else if((FF_game==FACTOROIDS_GAME && num > 1 && ((asteroid[i].fact_number%num)==0) && (num!=asteroid[i].fact_number)) ||
1969 		    (FF_game==FRACTIONS_GAME && num > 1 && ((asteroid[i].a%num)==0) && ((asteroid[i].b%num)==0) && (num!=asteroid[i].fact_number))) {
1970 		FF_destroy_asteroid(i, 0, 0);
1971 	    }
1972 	}
1973     }
1974 }
1975 
1976 /******************* LASER FUNCTIONS *********************/
1977 /*Return -1 if no laser is available*/
FF_add_laser(void)1978 int FF_add_laser(void)
1979 {
1980     int i, k, zapIndex, zapScore;
1981     float ux, uy, s, smin,dx,dy,dx2, dy2, d2, thresh;
1982     int screensize;
1983     SDL_Surface *asteroid_image;
1984 
1985     const float inside_factor = 0.9*0.9;
1986 
1987     screensize = screen->w;
1988     if (screensize < screen->h)
1989 	screensize = screen->h;
1990 
1991     for(i=0; i<=MAX_LASER; i++)
1992     {
1993 	if(laser[i].alive==0)
1994 	{
1995 	    // Fire the laser
1996 	    laser[i].alive=1;
1997 	    laser[i].x=tuxship.centerx;
1998 	    laser[i].y=tuxship.centery;
1999 	    laser[i].angle=tuxship.angle;
2000 	    laser[i].count=15;
2001 	    laser[i].n = num;
2002 
2003 	    ux = cos((float)laser[i].angle * DEG_TO_RAD);
2004 	    uy = -sin((float)laser[i].angle * DEG_TO_RAD);
2005 	    laser[i].destx = laser[i].x + (int)(ux * screensize);
2006 	    laser[i].desty = laser[i].y + (int)(uy * screensize);
2007 
2008 	    // Check to see if it hits asteroids---we only check when it
2009 	    // just starts firing, "drift" later doesn't count!
2010 	    // We describe the laser path as p = p0 + s*u, where
2011 	    //   p0 = (x0,y0) is the initial position vector (i.e., the ship)
2012 	    //   u = (ux,uy) is the unit vector of the laser's direction
2013 	    //   s (a scalar) is the distance along the laser (s >= 0)
2014 	    // With this parametrization, it's easy to calculate the
2015 	    // closest approach to the asteroid center, etc.
2016 	    zapIndex = -1;  // keep track of the closest "hit" asteroid
2017 	    zapScore = 0;
2018 	    smin = 10*screensize;
2019 
2020 
2021 	    for (k=0; k<MAX_ASTEROIDS; k++)
2022 	    {
2023 		if (!asteroid[k].alive)
2024 		    continue;
2025 		asteroid_image = get_asteroid_image(asteroid[k].size,asteroid[k].angle);
2026 		dx = asteroid[k].x + asteroid_image->w/2 - laser[i].x;
2027 		dy = asteroid[k].y + asteroid_image->h/2 - laser[i].y;
2028 		// Find distance along laser of closest approach to asteroid center
2029 		s = dx*ux + dy*uy;
2030 		if (s >= 0)  // don't worry about it if it's in the opposite direction! (i.e., behind the ship)
2031 		{
2032 		    // Find the distance to the asteroid center at closest approach
2033 		    dx2 = dx - s*ux;
2034 		    dy2 = dy - s*uy;
2035 		    d2 = dx2*dx2 + dy2*dy2;
2036 		    thresh = (asteroid_image->h)/2;
2037 		    thresh = thresh*thresh*inside_factor;
2038 		    if (d2 < thresh)
2039 		    {
2040 			// The laser intersects the asteroid. Check to see if
2041 			// the answer works
2042 
2043 			if( (FF_game==FACTOROIDS_GAME && (asteroid[k].isprime && ((num==asteroid[k].fact_number)||(num==0)))) ||
2044 				(FF_game==FRACTIONS_GAME && (asteroid[k].isprime && num==0))
2045 			  )
2046 			{
2047 			    // It's valid, check to see if it's closest
2048 			    if (s < smin)
2049 			    {
2050 				// It's the closest yet examined but has not score
2051 				smin = s;
2052 				zapIndex = k;
2053 				zapScore = 0;
2054 			    }
2055 			}
2056 			else if((FF_game==FACTOROIDS_GAME && num > 1 && ((asteroid[k].fact_number%num)==0) && (num!=asteroid[k].fact_number)) ||
2057 				(FF_game==FRACTIONS_GAME && num > 1 && ((asteroid[k].a%num)==0) && ((asteroid[k].b%num)==0) && (num!=asteroid[k].fact_number)))
2058 			{
2059 			    // It's valid, check to see if it's closest
2060 			    if (s < smin)
2061 			    {
2062 				// It's the closest yet examined and has socre
2063 				smin = s;
2064 				zapIndex = k;
2065 				zapScore = 1;
2066 			    }
2067 			}
2068 		    }
2069 		}
2070 	    }
2071 
2072 	    // Handle the destruction, score, and extra lives
2073 	    if (zapIndex >= 0)  // did we zap one?
2074 	    {
2075 		asteroid[zapIndex].isdead = 1;
2076 		laser[i].destx = laser[i].x + (int)(ux * smin);
2077 		laser[i].desty = laser[i].y + (int)(uy * smin);
2078 		FF_destroy_asteroid(zapIndex,2*ux,2*uy);
2079 		playsound(SND_SIZZLE);
2080 
2081 		if (floor((float)score/100) < floor((float)(score+num)/100))
2082 		    tuxship.lives++;
2083 		if(zapScore)
2084 		{
2085 		    score += num;
2086 		}
2087 	    }
2088 	    return 1;
2089 	}
2090     }
2091     DEBUGMSG(debug_factoroids, "Laser could't be created!\n");
2092     return -1;
2093 }
2094 
2095 /******************* ASTEROIDS FUNCTIONS *******************/
2096 
2097 
2098 
FF_add_asteroid(int x,int y,int xspeed,int yspeed,int size,int angle,int angle_speed,int fact_number,int a,int b,int new_wave)2099 static int FF_add_asteroid(int x, int y, int xspeed, int yspeed, int size, int angle, int angle_speed, int fact_number, int a, int b, int new_wave)
2100 {
2101     int i;
2102     for(i=0; i<MAX_ASTEROIDS; i++){
2103 	if(asteroid[i].alive==0)
2104 	{
2105 	    asteroid[i].alive=1;
2106 	    asteroid[i].rx=x;
2107 	    asteroid[i].ry=y;
2108 	    asteroid[i].angle=angle;
2109 	    asteroid[i].angle_speed=angle_speed;
2110 	    asteroid[i].y=(asteroid[i].ry - (IMG_tuxship[asteroid[i].angle/DEG_PER_ROTATION]->h/2));
2111 	    asteroid[i].x=(asteroid[i].rx - (IMG_tuxship[asteroid[i].angle/DEG_PER_ROTATION]->w/2));
2112 	    asteroid[i].yspeed=yspeed;
2113 	    asteroid[i].xspeed=xspeed;
2114 	    asteroid[i].xdead = 0;
2115 	    asteroid[i].ydead = 0;
2116 	    asteroid[i].isdead = 0;
2117 	    asteroid[i].countdead = 0;
2118 
2119 	    if(FF_game==FACTOROIDS_GAME){
2120 
2121 		if(!validate_number(fact_number, wave))
2122 		{
2123 		    DEBUGMSG(debug_factoroids, "Invalid asteroid number: %d\n", fact_number);
2124 		    return -1;
2125 		}
2126 		//while(!asteroid[i].fact_number)
2127 		//  asteroid[i].fact_number=rand()%80;
2128 
2129 		asteroid[i].fact_number=fact_number;
2130 		asteroid[i].isprime=is_prime(asteroid[i].fact_number);
2131 
2132 	    }else if(FF_game==FRACTIONS_GAME){
2133 
2134 		asteroid[i].a=a;
2135 		asteroid[i].b=b;
2136 
2137 		while(!asteroid[i].a)
2138 		    asteroid[i].a=rand()%80;
2139 		while(!asteroid[i].b)
2140 		    asteroid[i].b=rand()%80;
2141 
2142 		asteroid[i].isprime=is_simplified(asteroid[i].a,asteroid[i].b);
2143 	    }
2144 
2145 	    if(new_wave){
2146 		if(tuxship.x-50<asteroid[i].x+80 &&
2147 			tuxship.x+50>asteroid[i].x &&
2148 			tuxship.y-50<asteroid[i].y+80 &&
2149 			tuxship.y+50>asteroid[i].y &&
2150 			tuxship.lives>0 &&
2151 			asteroid[i].alive){
2152 		    asteroid[i].rx=asteroid[i].rx+300;
2153 		    asteroid[i].ry=asteroid[i].ry+300;
2154 		}
2155 	    }
2156 
2157 	    if(asteroid[i].isprime)
2158 	    {
2159 		asteroid[i].size=0;
2160 		asteroid[i].centerx=(images[IMG_ASTEROID1]->w/2)+asteroid[i].x;
2161 		asteroid[i].centery=(images[IMG_ASTEROID1]->h/2)+asteroid[i].y;
2162 		asteroid[i].radius=(images[IMG_ASTEROID1]->h/2);
2163 
2164 	    }
2165 	    else if(!asteroid[i].isprime)
2166 	    {
2167 		asteroid[i].size=1;
2168 		asteroid[i].centerx=(images[IMG_ASTEROID2]->w/2)+asteroid[i].x;
2169 		asteroid[i].centery=(images[IMG_ASTEROID2]->h/2)+asteroid[i].y;
2170 		asteroid[i].radius=(images[IMG_ASTEROID1]->h/2);
2171 	    }
2172 
2173 	    while (asteroid[i].xspeed==0)
2174 	    {
2175 		asteroid[i].xspeed = ((rand() % 3) - 1)*2;
2176 	    }
2177 	    return 1;
2178 	}
2179     }
2180     fprintf(stderr, "Asteroid could't be created!\n");
2181     return -1;
2182 }
2183 
FF_destroy_asteroid(int i,float xspeed,float yspeed)2184 int FF_destroy_asteroid(int i, float xspeed, float yspeed)
2185 {
2186     if(asteroid[i].alive==1){
2187 	asteroid[i].isdead=1;
2188 	asteroid[i].xdead=asteroid[i].x;
2189 	asteroid[i].ydead=asteroid[i].y;
2190 	if(asteroid[i].size>0){
2191 	    /* Break the rock into two smaller ones! */
2192 	    if(num!=0){
2193 
2194 
2195 
2196 		if(FF_game==FACTOROIDS_GAME){
2197 		    FF_add_asteroid(asteroid[i].rx,
2198 			    asteroid[i].ry,
2199 			    asteroid[i].xspeed + (xspeed - yspeed)/2,
2200 			    asteroid[i].yspeed + (yspeed + xspeed)/2,
2201 			    0,
2202 			    rand()%360, rand()%3, (int)(asteroid[i].fact_number/num),
2203 			    0, 0,
2204 			    0);
2205 
2206 		    FF_add_asteroid(asteroid[i].rx,
2207 			    asteroid[i].ry,
2208 			    asteroid[i].xspeed + (xspeed + yspeed)/2,
2209 			    asteroid[i].yspeed + (yspeed - xspeed)/2,
2210 			    0,
2211 			    rand()%360, rand()%3, num,
2212 			    0, 0,
2213 			    0);
2214 		}
2215 		else if(FF_game==FRACTIONS_GAME){
2216 		    FF_add_asteroid(asteroid[i].rx,
2217 			    asteroid[i].ry,
2218 			    ((asteroid[i].xspeed + xspeed) / 2),
2219 			    (asteroid[i].yspeed + yspeed),
2220 			    0,
2221 			    rand()%360, rand()%3, 0,
2222 			    (int)(asteroid[i].a/num), (int)(asteroid[i].b/num),
2223 			    0);
2224 
2225 		    FF_add_asteroid(asteroid[i].rx,
2226 			    asteroid[i].ry,
2227 			    (asteroid[i].xspeed + xspeed),
2228 			    ((asteroid[i].yspeed + yspeed) / 2),
2229 			    0,
2230 			    rand()%360, rand()%3, 0,
2231 			    (int)(asteroid[i].b/num), (int)(asteroid[i].a/num),
2232 			    0);
2233 		}
2234 	    }
2235 	}
2236 
2237 	/* Destroy the old asteroid */
2238 
2239 	asteroid[i].alive=0;
2240 	return 1;
2241     }
2242     return 0;
2243 }
2244 
2245 /************** MODIFIED FUNCS FROM game.c and titlescreen.c ******************/
2246 
FF_ShowMessage(char * str)2247 void FF_ShowMessage(char* str)
2248 {
2249     SDL_Surface* s1 = NULL;
2250     SDL_Rect loc;
2251     char wrapped_str[1024];
2252     int char_width;
2253 
2254     if(str == NULL)
2255 	return;
2256 
2257     char_width = T4K_CharsForWidth(DEFAULT_MENU_FONT_SIZE, screen->w * 0.75);
2258     T4K_LineWrapInsBreaks(str, wrapped_str, char_width, 64, 64);
2259     s1 = T4K_BlackOutline(wrapped_str, DEFAULT_MENU_FONT_SIZE, &yellow);
2260     if (s1)
2261     {
2262 	loc.x = screen->w/2 - s1->w/2;
2263 	loc.y = screen->h/4;
2264 	SDL_BlitSurface(s1, NULL, screen, &loc);
2265 	SDL_FreeSurface(s1);
2266     }
2267     SDL_UpdateRect(screen, 0, 0, 0, 0);
2268 }
2269 
FF_LevelObjsHints(char * label,char * contents,int x,int y)2270 static void FF_LevelObjsHints(char *label, char *contents, int x, int y )
2271 {
2272     SDL_Surface *s1 = NULL, *s2 = NULL;
2273     SDL_Rect loc;
2274     char wrapped_label[256];
2275     char wrapped_contents[256];
2276     int char_width;
2277 
2278     if(label == NULL || contents == NULL)
2279 	return;
2280 
2281     char_width = T4K_CharsForWidth(DEFAULT_MENU_FONT_SIZE, LVL_WIDTH_MSG);
2282     T4K_LineWrapInsBreaks(label, wrapped_label, char_width, 64, 64);
2283     T4K_LineWrapInsBreaks(contents, wrapped_contents, char_width, 64, 64);
2284 
2285     s1 = T4K_BlackOutline(wrapped_label, DEFAULT_MENU_FONT_SIZE, &white);
2286     s2 = T4K_BlackOutline(wrapped_contents, DEFAULT_MENU_FONT_SIZE, &white);
2287 
2288     if(s1)
2289     {
2290 	loc.x = x;
2291 	loc.y = y;
2292 	SDL_BlitSurface(s1, NULL, screen, &loc);
2293     }
2294     if(s2)
2295     {
2296 	loc.x = x;
2297 	loc.y = s1->h + loc.y ;
2298 	SDL_BlitSurface(s2, NULL, screen, &loc);
2299     }
2300 
2301     SDL_UpdateRect(screen, 0, 0, 0, 0);
2302 
2303     SDL_FreeSurface(s1);
2304     SDL_FreeSurface(s2);
2305 }
2306 
game_handle_user_events(void)2307 void game_handle_user_events(void)
2308 {
2309     SDL_Event event;
2310     SDLKey key;
2311     int roto = 0; //rotation flag
2312 
2313     while (SDL_PollEvent(&event) > 0)
2314     {
2315 	T4K_HandleStdEvents(&event);
2316 	if (event.type == SDL_QUIT)
2317 	{
2318 	    SDL_quit_received = 1;
2319 	    quit = 1;
2320 	}
2321 	if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP)
2322 	{
2323 	    key = game_mouse_event(event);
2324 	    //the code transforms a mouse event into a keyboard event,
2325 	    //so the same modification should be made with the event structure
2326 	    // -- aviraldg 14/12/10
2327 	    int state = event.button.state;
2328 	    event.key.keysym.sym = key;
2329 	    event.type = state == SDL_PRESSED ? SDL_KEYDOWN : SDL_KEYUP;
2330 	}
2331 	if(event.type == SDL_MOUSEMOTION) {
2332 	    //NOTE: in SDL 1.2 this repositioning is only needed for
2333 	    //OS-X.  Not sure if it will be needed at all in SDL 1.3
2334 
2335 	    //If we are near edge of the screen, reset mouse to center
2336 	    if(event.motion.x <= 10
2337 		    || event.motion.x >= (screen->w - 10)
2338 		    || event.motion.y <= 10
2339 		    || event.motion.y >= (screen->h - 10))
2340 	    {
2341 		mouse_reset = 1;
2342 		SDL_WarpMouse(screen->w/2, screen->h/2);
2343 		continue;
2344 	    }
2345 	    //If this was an event generated by our reset-to-center,
2346 	    //ignore it:
2347 	    if(mouse_reset)
2348 	    {
2349 		mouse_reset = 0;
2350 		continue;
2351 	    }
2352 	    //otherwise, valid event - handle mouse rotation
2353 	    roto = 1;
2354 	    mouseroto = game_mouseroto(event) / MOUSE_SENSITIVITY;
2355 	}
2356 	if (event.type == SDL_KEYDOWN ||
2357 		event.type == SDL_KEYUP)
2358 	{
2359 	    key = event.key.keysym.sym;
2360 
2361 	    if (event.type == SDL_KEYDOWN)
2362 	    {
2363 		if (key == SDLK_ESCAPE)
2364 		{
2365 		    // Return to menu!
2366 		    escape_received = 1;
2367 
2368 		}
2369 
2370 		// Key press...
2371 
2372 		if (key == SDLK_RIGHT)
2373 		{
2374 		    // Rotate CW
2375 
2376 		    left_pressed = 0;
2377 		    right_pressed = 1;
2378 		}
2379 		else if (key == SDLK_LEFT)
2380 		{
2381 		    // Rotate CCW
2382 
2383 		    left_pressed = 1;
2384 		    right_pressed = 0;
2385 		}
2386 		else if (key == SDLK_UP)
2387 		{
2388 		    // Thrust!
2389 
2390 		    up_pressed = 1;
2391 		}
2392 
2393 		if (key == SDLK_LSHIFT || key == SDLK_RSHIFT)
2394 		{
2395 		    // Respawn now (if applicable)
2396 		    shift_pressed = 1;
2397 		}
2398 
2399 		if (key == SDLK_TAB || key == SDLK_p)
2400 		{
2401 		    /* [TAB] or [P]: Pause! (if settings allow) */
2402 		    if (Opts_AllowPause())
2403 		    {
2404 			paused = 1;
2405 		    }
2406 		}
2407 
2408 		if (key == CTRL_NEXT) {
2409 		    int n = prime_next[digits[1]*10 + digits[2]];
2410 		    if(n <= prime_numbers[wave - 1]) {
2411 			digits[2] = n % 10;
2412 			digits[1] = n / 10;
2413 			tux_pressing = 1;
2414 			playsound(SND_SHIELDSDOWN);
2415 		    } else {
2416 			digits[2] = 2;
2417 			digits[1] = 0;
2418 			tux_pressing = 1;
2419 			playsound(SND_SHIELDSDOWN);
2420 		    }
2421 		}
2422 
2423 		if (key == CTRL_PREV) {
2424 		    int n = prime_prev[digits[1]*10 + digits[2]];
2425 		    if(n <= prime_numbers[wave - 1]) {
2426 			digits[2] = n % 10;
2427 			digits[1] = n / 10;
2428 			tux_pressing = 1;
2429 			playsound(SND_SHIELDSDOWN);
2430 		    } else {
2431 			digits[2] = prime_numbers[wave - 1] % 10;
2432 			digits[1] = prime_numbers[wave - 1] / 10;
2433 			tux_pressing = 1;
2434 			playsound(SND_SHIELDSDOWN);
2435 		    }
2436 		}
2437 		// TODO this code only deals with the first 6 primes, we'd probably want a
2438 		// more generic solution
2439 		int _tmp = digits[0]*100 + digits[1]*10 + digits[2];
2440 		int digit, exec_digits = 0;
2441 		if(key >= SDLK_0 && key <= SDLK_9) {
2442 		    digit = key - SDLK_0;
2443 		    tux_pressing = 1;
2444 		    exec_digits = 1;
2445 		    playsound(SND_SHIELDSDOWN);
2446 		} else if (key >= SDLK_KP0 && key <= SDLK_KP9) {
2447 		    digit = key - SDLK_KP0;
2448 		    tux_pressing = 1;
2449 		    exec_digits = 1;
2450 		    playsound(SND_SHIELDSDOWN);
2451 		}
2452 		if(exec_digits == 1) {
2453 		    if(digits[1] == 1 && (digit == 2 || digit == 5 || digit == 7)) {
2454 			digits[1] = 0;
2455 			digits[2] = digit;
2456 		    } else if(digits[1] == 1 && digit == 1) {
2457 			digits[2] = 1;
2458 		    } else if(digit==1) {
2459 			digits[1] = 1;
2460 			digits[2] = 0;
2461 		    }
2462 		    if(digit == 2 || digit == 3 || digit == 5 || digit == 7) {
2463 			digits[2] = digit;
2464 		    }
2465 		}
2466 		//cancel if requested digit forms larger prime than allowed
2467 		if((digits[1]*10 + digits[2]) > prime_numbers[wave - 1]) {
2468 		    digits[2] = _tmp % 10;
2469 		    digits[1] = _tmp / 10;
2470 		}
2471 
2472 		/* activate bonus/powerup */
2473 		if((key == SDLK_LSHIFT || key == SDLK_RSHIFT) && bonus_time == -1) {
2474 		    playsound(SND_HARP);
2475 		    bonus_time = SDL_GetTicks() + 10000; //10sec bonus
2476 
2477 		    //special handling for the powerbomb, since it happens "at once"
2478 		    if(bonus == TB_POWERBOMB) {
2479 			_tb_PowerBomb(digits[1]*10 + digits[2]);
2480 			bonus_time = SDL_GetTicks() + 1000;
2481 			/* FIXME ugly hack to allow multiple lasers to display */
2482 		    }
2483 		}
2484 		/* support for negative answer input DSB */
2485 		else if ((key == SDLK_MINUS || key == SDLK_KP_MINUS))
2486 		    //&& MC_AllowNegatives())  /* do nothing unless neg answers allowed */
2487 		{
2488 		    /* allow player to make answer negative: */
2489 		    neg_answer_picked = 1;
2490 		    tux_pressing = 1;
2491 		    playsound(SND_SHIELDSDOWN);
2492 		}
2493 		else if ((key == SDLK_PLUS || key == SDLK_KP_PLUS))
2494 		    //&& MC_AllowNegatives())  /* do nothing unless neg answers allowed */
2495 		{
2496 		    /* allow player to make answer positive: */
2497 		    neg_answer_picked = 0;
2498 		    tux_pressing = 1;
2499 		    playsound(SND_SHIELDSDOWN);
2500 		}
2501 		else if (key == SDLK_RETURN ||
2502 			key == SDLK_KP_ENTER ||
2503 			key == SDLK_SPACE)
2504 		{
2505 		    shoot_pressed = 1;
2506 		    doing_answer = 1;
2507 		    button_pressed = 1;
2508 		    playsound(SND_LASER);
2509 		}
2510 
2511 
2512 	    }
2513 	    else if (event.type == SDL_KEYUP)
2514 	    {
2515 		// Key release...
2516 
2517 		if (key == SDLK_RIGHT)
2518 		{
2519 		    right_pressed = 0;
2520 		}
2521 		else if (key == SDLK_LEFT)
2522 		{
2523 		    left_pressed = 0;
2524 		}
2525 		else if (key == SDLK_UP)
2526 		{
2527 		    up_pressed = 0;
2528 		}
2529 		if (key == SDLK_LSHIFT ||
2530 			key == SDLK_RSHIFT)
2531 		{
2532 		    // Respawn now (if applicable)
2533 		    shift_pressed = 0;
2534 		}
2535 		if ( key == SDLK_RETURN || key == SDLK_KP_ENTER || key == SDLK_SPACE )
2536 		{
2537 		    button_pressed = 0;
2538 		}
2539 	    }
2540 	}
2541 
2542 #ifdef JOY_YES
2543 	else if (event.type == SDL_JOYBUTTONDOWN &&
2544 		player_alive)
2545 	{
2546 	    if (event.jbutton.button == JOY_B)
2547 	    {
2548 		shoot_pressed = 1;
2549 	    }
2550 	    else if (event.jbutton.button == JOY_A)
2551 	    {
2552 		// Thrust:
2553 
2554 		up_pressed = 1;
2555 	    }
2556 	    else
2557 	    {
2558 		shift_pressed = 1;
2559 	    }
2560 	}
2561 	else if (event.type == SDL_JOYBUTTONUP)
2562 	{
2563 	    if (event.jbutton.button == JOY_A)
2564 	    {
2565 		// Stop thrust:
2566 
2567 		up_pressed = 0;
2568 	    }
2569 	    else if (event.jbutton.button != JOY_B)
2570 	    {
2571 		shift_pressed = 0;
2572 	    }
2573 	}
2574 	else if (event.type == SDL_JOYAXISMOTION)
2575 	{
2576 	    if (event.jaxis.axis == JOY_X)
2577 	    {
2578 		if (event.jaxis.value < -256)
2579 		{
2580 		    left_pressed = 1;
2581 		    right_pressed = 0;
2582 		}
2583 		else if (event.jaxis.value > 256)
2584 		{
2585 		    left_pressed = 0;
2586 		    right_pressed = 1;
2587 		}
2588 		else
2589 		{
2590 		    left_pressed = 0;
2591 		    right_pressed = 0;
2592 		}
2593 	    }
2594 	}
2595 #endif
2596 
2597     }
2598     if(roto == 0) mouseroto = 0;
2599 }
2600 
2601 
game_mouse_event(SDL_Event event)2602 static int game_mouse_event(SDL_Event event)
2603 {
2604     if(event.button.button == SDL_BUTTON_LEFT) return  SDLK_RETURN;
2605     else if(event.button.button == SDL_BUTTON_MIDDLE) return SDLK_LSHIFT;
2606     else if(event.button.button == SDL_BUTTON_RIGHT) return SDLK_UP;
2607     else if(event.button.button == SDL_BUTTON_WHEELUP) return CTRL_NEXT;
2608     else if(event.button.button == SDL_BUTTON_WHEELDOWN) return CTRL_PREV;
2609     else return SDLK_UNKNOWN;
2610 }
2611 
2612 
check_exit_conditions(void)2613 static int check_exit_conditions(void)
2614 {
2615     if(SDL_quit_received)
2616     {
2617 	return FF_OVER_SDL_QUIT;
2618     }
2619 
2620     if(escape_received)
2621     {
2622 	return FF_OVER_ESCAPE;
2623     }
2624     if(tuxship.lives<=0)
2625     {
2626 	return FF_OVER_LOST;
2627     }
2628     if(wave > 6 )
2629     {
2630 	return FF_OVER_WON;
2631     }
2632 
2633     /* if we made it to here, the game goes on! */
2634     return FF_IN_PROGRESS;
2635 }
2636 
2637 
2638 /* Draw numbers/symbols over the attacker: */
draw_nums(const char * str,int x,int y,SDL_Color * col)2639 void draw_nums(const char* str, int x, int y, SDL_Color* col)
2640 {
2641     if(!str || !col)
2642 	return;
2643 
2644     SDL_Surface* surf = NULL;
2645     surf = T4K_BlackOutline(str, ASTEROID_NUM_SIZE * zoom, col);
2646     if(surf)
2647     {
2648 	int w = T4K_GetScreen()->w;
2649 	x -= surf->w/2;
2650 	// Keep formula at least 8 pixels inside screen:
2651 	if(surf->w + x > (w - 8))
2652 	    x -= (surf->w + x - (w - 8));
2653 	if(x < 8)
2654 	    x = 8;
2655 
2656 	SDL_Rect pos = {x, y};
2657 	SDL_BlitSurface(surf, NULL, T4K_GetScreen(), &pos);
2658 	SDL_FreeSurface(surf);
2659     }
2660 }
2661