Don't objcopy simulator plugins.
[kugel-rb.git] / apps / plugins / spacerocks.c
blobb8cf043125b6251f14ea8be1964937308572e02f
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 by Mat Holton
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "plugin.h"
23 #include "lib/helper.h"
25 PLUGIN_HEADER
27 /******************************* Globals ***********************************/
28 static const struct plugin_api* rb; /* global api struct pointer */
29 /* variable button definitions */
30 #if CONFIG_KEYPAD == RECORDER_PAD
31 #define AST_PAUSE BUTTON_ON
32 #define AST_QUIT BUTTON_OFF
33 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
34 #define AST_THRUST BUTTON_UP
35 #define AST_HYPERSPACE BUTTON_DOWN
36 #define AST_LEFT BUTTON_LEFT
37 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
38 #define AST_RIGHT BUTTON_RIGHT
39 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
40 #define AST_FIRE BUTTON_PLAY
41 #define AST_FIRE_REP BUTTON_PLAY | BUTTON_REPEAT
43 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
44 #define AST_PAUSE BUTTON_ON
45 #define AST_QUIT BUTTON_OFF
46 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
47 #define AST_THRUST BUTTON_UP
48 #define AST_HYPERSPACE BUTTON_DOWN
49 #define AST_LEFT BUTTON_LEFT
50 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
51 #define AST_RIGHT BUTTON_RIGHT
52 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
53 #define AST_FIRE BUTTON_SELECT
54 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
56 #elif CONFIG_KEYPAD == ONDIO_PAD
57 #define AST_PAUSE (BUTTON_MENU | BUTTON_OFF)
58 #define AST_QUIT BUTTON_OFF
59 #define AST_THRUST BUTTON_UP
60 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
61 #define AST_HYPERSPACE BUTTON_DOWN
62 #define AST_LEFT BUTTON_LEFT
63 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
64 #define AST_RIGHT BUTTON_RIGHT
65 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
66 #define AST_FIRE BUTTON_MENU
67 #define AST_FIRE_REP BUTTON_MENU | BUTTON_REPEAT
69 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
70 (CONFIG_KEYPAD == IRIVER_H300_PAD)
71 #define AST_PAUSE BUTTON_REC
72 #define AST_QUIT BUTTON_OFF
73 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
74 #define AST_THRUST BUTTON_UP
75 #define AST_HYPERSPACE BUTTON_DOWN
76 #define AST_LEFT BUTTON_LEFT
77 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
78 #define AST_RIGHT BUTTON_RIGHT
79 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
80 #define AST_FIRE BUTTON_SELECT
81 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
83 #define AST_RC_QUIT BUTTON_RC_STOP
85 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
86 #define AST_PAUSE BUTTON_PLAY
87 #define AST_QUIT BUTTON_POWER
88 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
89 #define AST_THRUST BUTTON_UP
90 #define AST_HYPERSPACE BUTTON_DOWN
91 #define AST_LEFT BUTTON_LEFT
92 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
93 #define AST_RIGHT BUTTON_RIGHT
94 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
95 #define AST_FIRE BUTTON_SELECT
96 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
98 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
99 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
100 #define AST_PAUSE (BUTTON_SELECT | BUTTON_PLAY)
101 #define AST_QUIT (BUTTON_SELECT | BUTTON_MENU)
102 #define AST_THRUST BUTTON_MENU
103 #define AST_THRUST_REP (BUTTON_MENU | BUTTON_REPEAT)
104 #define AST_HYPERSPACE BUTTON_PLAY
105 #define AST_LEFT BUTTON_SCROLL_BACK
106 #define AST_LEFT_REP (BUTTON_SCROLL_BACK | BUTTON_REPEAT)
107 #define AST_RIGHT BUTTON_SCROLL_FWD
108 #define AST_RIGHT_REP (BUTTON_SCROLL_FWD | BUTTON_REPEAT)
109 #define AST_FIRE BUTTON_SELECT
110 #define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT)
112 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
113 #define AST_PAUSE BUTTON_A
114 #define AST_QUIT BUTTON_POWER
115 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
116 #define AST_THRUST BUTTON_UP
117 #define AST_HYPERSPACE BUTTON_DOWN
118 #define AST_LEFT BUTTON_LEFT
119 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
120 #define AST_RIGHT BUTTON_RIGHT
121 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
122 #define AST_FIRE BUTTON_SELECT
123 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
125 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
126 #define AST_PAUSE BUTTON_REC
127 #define AST_QUIT BUTTON_POWER
128 #define AST_THRUST_REP (BUTTON_UP | BUTTON_REPEAT)
129 #define AST_THRUST BUTTON_UP
130 #define AST_HYPERSPACE BUTTON_DOWN
131 #define AST_LEFT BUTTON_SCROLL_BACK
132 #define AST_LEFT_REP (BUTTON_SCROLL_BACK | BUTTON_REPEAT)
133 #define AST_RIGHT BUTTON_SCROLL_FWD
134 #define AST_RIGHT_REP (BUTTON_SCROLL_FWD | BUTTON_REPEAT)
135 #define AST_FIRE BUTTON_SELECT
136 #define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT)
138 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
139 #define AST_PAUSE BUTTON_REC
140 #define AST_QUIT BUTTON_POWER
141 #define AST_THRUST_REP (BUTTON_UP | BUTTON_REPEAT)
142 #define AST_THRUST BUTTON_UP
143 #define AST_HYPERSPACE BUTTON_DOWN
144 #define AST_LEFT BUTTON_LEFT
145 #define AST_LEFT_REP (BUTTON_LEFT | BUTTON_REPEAT)
146 #define AST_RIGHT BUTTON_RIGHT
147 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
148 #define AST_FIRE BUTTON_SELECT
149 #define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT)
151 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
152 #define AST_PAUSE BUTTON_PLAY
153 #define AST_QUIT BUTTON_POWER
154 #define AST_THRUST_REP BUTTON_SCROLL_UP | BUTTON_REPEAT
155 #define AST_THRUST BUTTON_SCROLL_UP
156 #define AST_HYPERSPACE BUTTON_SCROLL_DOWN
157 #define AST_LEFT BUTTON_LEFT
158 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
159 #define AST_RIGHT BUTTON_RIGHT
160 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
161 #define AST_FIRE BUTTON_REW
162 #define AST_FIRE_REP BUTTON_REW | BUTTON_REPEAT
164 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
165 #define AST_PAUSE BUTTON_PLAY
166 #define AST_QUIT BUTTON_BACK
167 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
168 #define AST_THRUST BUTTON_UP
169 #define AST_HYPERSPACE BUTTON_DOWN
170 #define AST_LEFT BUTTON_LEFT
171 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
172 #define AST_RIGHT BUTTON_RIGHT
173 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
174 #define AST_FIRE BUTTON_SELECT
175 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
177 #elif (CONFIG_KEYPAD == MROBE100_PAD)
178 #define AST_PAUSE BUTTON_DISPLAY
179 #define AST_QUIT BUTTON_POWER
180 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
181 #define AST_THRUST BUTTON_UP
182 #define AST_HYPERSPACE BUTTON_DOWN
183 #define AST_LEFT BUTTON_LEFT
184 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
185 #define AST_RIGHT BUTTON_RIGHT
186 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
187 #define AST_FIRE BUTTON_SELECT
188 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
190 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
191 #define AST_PAUSE BUTTON_RC_PLAY
192 #define AST_QUIT BUTTON_RC_REC
193 #define AST_THRUST_REP BUTTON_RC_VOL_UP | BUTTON_REPEAT
194 #define AST_THRUST BUTTON_RC_VOL_UP
195 #define AST_HYPERSPACE BUTTON_RC_VOL_DOWN
196 #define AST_LEFT BUTTON_RC_REW
197 #define AST_LEFT_REP (BUTTON_RC_REW | BUTTON_REPEAT)
198 #define AST_RIGHT BUTTON_RC_FF
199 #define AST_RIGHT_REP (BUTTON_RC_FF | BUTTON_REPEAT)
200 #define AST_FIRE BUTTON_RC_MODE
201 #define AST_FIRE_REP (BUTTON_RC_MODE | BUTTON_REPEAT)
203 #elif (CONFIG_KEYPAD == COWOND2_PAD)
204 #define AST_QUIT BUTTON_POWER
206 #else
207 #error No keymap defined!
208 #endif
210 #ifdef HAVE_TOUCHSCREEN
211 #ifndef AST_PAUSE
212 #define AST_PAUSE BUTTON_CENTER
213 #endif
214 #ifndef AST_QUIT
215 #define AST_QUIT BUTTON_TOPLEFT
216 #endif
217 #ifndef AST_THRUST_REP
218 #define AST_THRUST_REP (BUTTON_TOPMIDDLE | BUTTON_REPEAT)
219 #endif
220 #ifndef AST_THRUST
221 #define AST_THRUST BUTTON_TOPMIDDLE
222 #endif
223 #ifndef AST_HYPERSPACE
224 #define AST_HYPERSPACE BUTTON_TOPRIGHT
225 #endif
226 #ifndef AST_LEFT
227 #define AST_LEFT BUTTON_MIDLEFT
228 #endif
229 #ifndef AST_LEFT_REP
230 #define AST_LEFT_REP (BUTTON_MIDLEFT | BUTTON_REPEAT)
231 #endif
232 #ifndef AST_RIGHT
233 #define AST_RIGHT BUTTON_MIDRIGHT
234 #endif
235 #ifndef AST_RIGHT_REP
236 #define AST_RIGHT_REP (BUTTON_MIDRIGHT | BUTTON_REPEAT)
237 #endif
238 #ifndef AST_FIRE
239 #define AST_FIRE BUTTON_BOTTOMMIDDLE
240 #endif
241 #ifndef AST_FIRE_REP
242 #define AST_FIRE_REP (BUTTON_BOTTOMMIDDLE | BUTTON_MENU)
243 #endif
244 #endif
246 #define ABS(x) ((x)>0?(x):-(x))
248 #define RES MAX(LCD_WIDTH, LCD_HEIGHT)
249 #define LARGE_LCD RES >= 200
250 #define ENEMY_MISSILE_SURVIVAL_LENGTH RES/2
251 #define ASTEROID_SPEED RES/20
252 #define MISSILE_SURVIVAL_LENGTH 40
254 #define EXTRA_LIFE 250
255 #define SCALE 5000
256 #define MISSILE_SCALE 5000
257 #define WRAP_GAP 12
258 #define EXPLOSION_LENGTH 20
259 #define SHOW_COL 0
260 #define HISCORE_FILE PLUGIN_GAMES_DIR "/astrorocks.hs"
261 #define POINT_SIZE 2
262 #define MAX_NUM_ASTEROIDS 25
263 #define MAX_NUM_MISSILES 6
264 #define ENEMY_BIG_PROBABILITY_START 10
265 #define ENEMY_APPEAR_PROBABILITY_START 35
266 #define ENEMY_APPEAR_TIMING_START 1800
267 #define LITTLE_SHIP 2
268 #define BIG_SHIP 1
269 #define SHOW_GAME_OVER_TIME 100
270 #define SHOW_LEVEL_TIME 50
271 #define START_LIVES 3
272 #define START_LEVEL 1
273 #define NUM_ASTEROID_VERTICES 10
274 #define NUM_SHIP_VERTICES 4
275 #define NUM_ENEMY_VERTICES 6
276 #define MAX_LEVEL MAX_NUM_ASTEROIDS
277 #define ENEMY_SPEED 4
278 #define ENEMY_START_X 0
279 #define ENEMY_START_Y 0
280 #define SIZE_ENEMY_COLLISION 5*SCALE
281 #define ATTRACT_FLIP_TIME 100
282 #define NUM_STARS 50
283 #define NUM_TRAIL_POINTS 70
284 #define NUM_ROTATIONS 16
286 #define SIN_COS_SCALE 10000
288 #define FAST_ROT_CW_SIN 873
289 #define FAST_ROT_CW_COS 9963
290 #define FAST_ROT_ACW_SIN -873
291 #define FAST_ROT_ACW_COS 9963
293 #define MEDIUM_ROT_CW_SIN 350
294 #define MEDIUM_ROT_CW_COS 9994
295 #define MEDIUM_ROT_ACW_SIN -350
296 #define MEDIUM_ROT_ACW_COS 9994
298 #define SLOW_ROT_CW_SIN 350
299 #define SLOW_ROT_CW_COS 9994
300 #define SLOW_ROT_ACW_SIN - 350
301 #define SLOW_ROT_ACW_COS 9994
303 #ifdef HAVE_LCD_COLOR
304 #define SHIP_ROT_CW_SIN 2419
305 #define SHIP_ROT_CW_COS 9702
306 #define SHIP_ROT_ACW_SIN -2419
307 #define SHIP_ROT_ACW_COS 9702
308 #else
309 #define SHIP_ROT_CW_SIN 3827
310 #define SHIP_ROT_CW_COS 9239
311 #define SHIP_ROT_ACW_SIN -3827
312 #define SHIP_ROT_ACW_COS 9239
313 #endif
316 #define SCALED_WIDTH (LCD_WIDTH*SCALE)
317 #define SCALED_HEIGHT (LCD_HEIGHT*SCALE)
318 #define CENTER_LCD_X (LCD_WIDTH/2)
319 #define CENTER_LCD_Y (LCD_HEIGHT/2)
321 #define SHIP_EXPLOSION_COLOUR 1
322 #define ASTEROID_EXPLOSION_COLOUR 2
323 #define ENEMY_EXPLOSION_COLOUR 3
324 #define THRUST_COLOUR 4
326 #define ASTEROID_R 230
327 #define ASTEROID_G 200
328 #define ASTEROID_B 100
329 #define SHIP_R 255
330 #define SHIP_G 255
331 #define SHIP_B 255
332 #define ENEMY_R 50
333 #define ENEMY_G 220
334 #define ENEMY_B 50
335 #define THRUST_R 200
336 #define THRUST_G 200
337 #define THRUST_B 0
339 #ifdef HAVE_LCD_COLOR
340 #define COL_MISSILE LCD_RGBPACK(200,0,0)
341 #define COL_PLAYER LCD_RGBPACK(200,200,200)
342 #define COL_STARS LCD_WHITE
343 #define COL_ASTEROID LCD_RGBPACK(ASTEROID_R,ASTEROID_G,ASTEROID_B)
344 #define COL_TEXT LCD_RGBPACK(200,200,255)
345 #define COL_ENEMY LCD_RGBPACK(ENEMY_R,ENEMY_G,ENEMY_B)
346 #define SET_FG rb->lcd_set_foreground
347 #define SET_BG rb->lcd_set_background
348 #else
349 #define SET_FG(x)
350 #define SET_BG(x)
351 #endif
353 /* The array of points that make up an asteroid */
354 static const short asteroid_one[NUM_ASTEROID_VERTICES*2] =
356 -2, -12,
357 4, -8,
358 8, -14,
359 16, -5,
360 14, 0,
361 20, 2,
362 12, 14,
363 -4, 14,
364 -10, 6,
365 -10, -8
368 /* The array of points that make up an asteroid */
369 static const short asteroid_two[NUM_ASTEROID_VERTICES*2] =
371 -2, -12,
372 4, -16,
373 6, -14,
374 16, -8,
375 14, 0,
376 20, 2,
377 12, 14,
378 -4, 14,
379 -10, 6,
380 -10, -8
383 /* The array of points that make up an asteroid */
384 static const short asteroid_three[NUM_ASTEROID_VERTICES*2] =
386 -2, -12,
387 4, -16,
388 6, -14,
389 2, -8,
390 14, 0,
391 20, 2,
392 12, 14,
393 -4, 14,
394 -16, 6,
395 -10, -8
398 /* The array od points the make up the ship */
399 static const short ship_vertices[NUM_SHIP_VERTICES*2] =
401 #if(LARGE_LCD)
402 0,-6,
403 4, 6,
404 0, 2,
405 -4, 6
406 #else
407 0,-4,
408 3, 4,
409 0, 1,
410 -3, 4
411 #endif
414 /* The array of points the make up the bad spaceship */
415 static const short enemy_vertices[NUM_ENEMY_VERTICES*2] =
417 #if(LARGE_LCD)
418 -8, 0,
419 -4, 4,
420 4, 4,
421 8, 0,
422 4, -4,
423 -4, -4
424 #else
425 -5, 0,
426 -2, 2,
427 2, 2,
428 5, 0,
429 2, -2,
430 -2, -2
431 #endif
435 enum asteroid_type
437 #if(LARGE_LCD)
438 SMALL = 2,
439 MEDIUM = 4,
440 LARGE = 6,
441 #else
442 SMALL = 1,
443 MEDIUM = 2,
444 LARGE = 3,
445 #endif
449 enum game_state
451 GAME_OVER,
452 ATTRACT_MODE,
453 SHOW_LEVEL,
454 PLAY_MODE,
455 PAUSE_MODE
458 struct Point
460 int x;
461 int y;
462 int dx;
463 int dy;
466 struct TrailPoint
468 int alive;
469 struct Point position;
470 short r;
471 short g;
472 short b;
473 short dec;
476 /* Asteroid structure, contains an array of points */
477 struct Asteroid
479 enum asteroid_type type;
480 bool exists;
481 struct Point position;
482 struct Point vertices[NUM_ASTEROID_VERTICES];
483 int radius;
484 long speed_cos;
485 long speed_sin;
486 int explode_countdown;
489 struct Ship
491 struct Point vertices[NUM_SHIP_VERTICES];
492 struct Point position;
493 bool waiting_for_space;
494 int explode_countdown;
497 struct Enemy
499 struct Point vertices[NUM_ENEMY_VERTICES];
500 struct Point position;
501 int explode_countdown;
502 long last_time_appeared;
503 short size_probability;
504 short appear_probability;
505 short appear_timing;
508 struct Missile
510 struct Point position;
511 struct Point oldpoint;
512 int survived;
515 static enum game_state game_state;
516 static int asteroid_count;
517 static int next_missile_count;
518 static int next_thrust_count;
519 static int num_lives;
520 static int extra_life;
521 static int show_level_timeout;
522 static int attract_flip_timeout;
523 static int show_game_over;
524 static int current_level;
525 static int current_score;
526 static int high_score;
527 static int space_check_size = 30*SCALE;
529 static bool enemy_on_screen;
530 static char phscore[30];
531 static struct Ship ship;
532 static struct Point stars[NUM_STARS];
533 static struct Asteroid asteroids_array[MAX_NUM_ASTEROIDS];
534 static struct Missile missiles_array[MAX_NUM_MISSILES];
535 static struct Missile enemy_missile;
536 static struct Enemy enemy;
537 static struct Point lives_points[NUM_SHIP_VERTICES];
538 static struct TrailPoint trailPoints[NUM_TRAIL_POINTS];
540 void draw_and_move_asteroids(void);
541 void initialise_game(int nStartNum);
543 bool is_asteroid_near_ship(struct Asteroid* asteroid);
544 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point);
546 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type eType);
547 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices);
548 void rotate_asteroid(struct Asteroid* asteroid);
549 void create_asteroid(enum asteroid_type type, int x, int y);
550 void create_stars(void);
552 void initialise_ship(void);
553 void draw_and_move_ship(void);
554 void rotate_ship(int s, int c);
555 void thrust_ship(void);
557 void initialise_missile(struct Missile* missile);
558 void draw_and_move_missiles(void);
559 void fire_missile(void);
561 void animate_and_draw_explosion(struct Point* point, int num_points, int xoffset, int yoffset);
562 void initialise_explosion(struct Point* point, int num_points);
564 void move_point(struct Point* point);
565 void hyperspace(void);
566 void check_collisions(void);
567 void initialise_enemy(void);
568 void draw_and_move_enemy(void);
569 void draw_lives(void);
570 void drawstars(void);
571 bool is_ship_within_asteroid(struct Asteroid* asteroid);
575 /*Hi-Score reading and writing to file - this needs moving to the hi-score plugin lib as
576 a 3rd function */
577 void iohiscore(void)
579 int fd;
580 int compare;
582 /* clear the buffer we're about to load the highscore data into */
583 rb->memset(phscore, 0, sizeof(phscore));
585 fd = rb->open(HISCORE_FILE,O_RDWR | O_CREAT);
586 if(fd < 0)
588 rb->splash(HZ, "Highscore file read error");
589 return;
592 /* highscore used to %d, is now %d\n
593 Deal with no file or bad file */
594 rb->read(fd,phscore, sizeof(phscore));
596 compare = rb->atoi(phscore);
598 if(high_score > compare)
600 rb->lseek(fd,0,SEEK_SET);
601 rb->fdprintf(fd, "%d\n", high_score);
603 else
604 high_score = compare;
606 rb->close(fd);
609 bool point_in_poly(struct Point* _point, int num_vertices, int x, int y)
611 struct Point* pi;
612 struct Point* pj;
613 int n;
614 bool c = false;
616 pi = _point;
617 pj = _point;
618 pj += num_vertices-1;
620 n = num_vertices;
621 while(n--)
623 if((((pi->y <= y) && (y < pj->y)) || ((pj->y <= y) && (y < pi->y))) &&
624 (x < (pj->x - pi->x) * (y - pi->y) / (pj->y - pi->y) + pi->x))
625 c = !c;
627 if(n == num_vertices - 1)
628 pj = _point;
629 else
630 pj++;
632 pi++;
635 return c;
638 void move_point(struct Point* point)
640 point->x += point->dx;
641 point->y += point->dy;
643 /*check bounds on the x-axis:*/
644 if(point->x >= SCALED_WIDTH)
645 point->x = 0;
646 else if(point->x <= 0)
647 point->x = SCALED_WIDTH;
649 /*Check bounds on the y-axis:*/
650 if(point->y >= SCALED_HEIGHT)
651 point->y = 0;
652 else if(point->y <= 0)
653 point->y = SCALED_HEIGHT;
656 void create_trail(struct TrailPoint* tpoint)
658 tpoint->position.dx = -( ship.vertices[0].x - ship.vertices[2].x )/10;
659 tpoint->position.dy = -( ship.vertices[0].y - ship.vertices[2].y )/10;
662 void create_explosion_trail(struct TrailPoint* tpoint)
664 tpoint->position.dx = (rb->rand()%5050)-2500;
665 tpoint->position.dy = (rb->rand()%5050)-2500;
668 void create_trail_blaze(int colour, struct Point* position)
670 int numtoadd;
671 struct TrailPoint* tpoint;
672 int n;
673 int xadd,yadd;
674 if(colour != SHIP_EXPLOSION_COLOUR)
676 numtoadd = NUM_TRAIL_POINTS/5;
677 xadd = position->x;
678 yadd = position->y;
680 else
682 numtoadd = NUM_TRAIL_POINTS/8;
683 xadd = ship.position.x;
684 yadd = ship.position.y;
687 /* give the point a random countdown timer, so they dissapears at different times */
688 tpoint = trailPoints;
689 n = NUM_TRAIL_POINTS;
690 while(--n)
692 if(tpoint->alive <= 0 && numtoadd)
694 numtoadd--;
695 /* take a random x point anywhere between bottom two points of ship. */
696 /* ship.position.x; */
697 tpoint->position.x = (ship.vertices[2].x + (rb->rand()%18000)-9000) + position->x;
698 tpoint->position.y = (ship.vertices[2].y + (rb->rand()%18000)-9000) + position->y;
700 switch(colour)
702 case SHIP_EXPLOSION_COLOUR:
703 tpoint->r = 255;
704 tpoint->g = 255;
705 tpoint->b = 255;
706 create_explosion_trail(tpoint);
707 tpoint->alive = 510;
708 tpoint->dec = 2;
709 break;
710 case ASTEROID_EXPLOSION_COLOUR:
711 tpoint->r = ASTEROID_R;
712 tpoint->g = ASTEROID_G;
713 tpoint->b = ASTEROID_B;
714 create_explosion_trail(tpoint);
715 tpoint->alive = 510;
716 tpoint->dec = 2;
717 break;
718 case ENEMY_EXPLOSION_COLOUR:
719 tpoint->r = ENEMY_R;
720 tpoint->g = ENEMY_G;
721 tpoint->b = ENEMY_B;
722 create_explosion_trail(tpoint);
723 tpoint->alive = 510;
724 tpoint->dec = 2;
725 break;
726 case THRUST_COLOUR:
727 tpoint->r = THRUST_R;
728 tpoint->g = THRUST_G;
729 tpoint->b = THRUST_B;
730 create_trail(tpoint);
731 tpoint->alive = 175;
732 tpoint->dec = 4;
733 break;
735 /* add a proportional bit to the x and y based on dx and dy */
737 /* give the points a speed based on direction of travel - i.e. opposite */
738 tpoint->position.dx += position->dx;
739 tpoint->position.dy += position->dy;
743 tpoint++;
745 /* find a space in the array of trail_points that is NULL or DEAD or whatever.
746 and place this one here. */
750 void draw_trail_blaze(void)
752 struct TrailPoint* tpoint;
753 /* loop through, if alive then move and draw.
754 when drawn, countdown it's timer.
755 if zero kill it! */
756 tpoint = trailPoints;
757 int n = NUM_TRAIL_POINTS;
759 while(--n)
761 if(tpoint->alive)
763 if(game_state != PAUSE_MODE)
765 tpoint->alive-=10;
766 move_point(&(tpoint->position));
768 #ifdef HAVE_LCD_COLOR
769 /* intensity = tpoint->alive/2; */
770 if(tpoint->r>0)tpoint->r-=tpoint->dec;
771 if(tpoint->g>0)tpoint->g-=tpoint->dec;
772 if(tpoint->b>0)tpoint->b-=tpoint->dec;
773 SET_FG(LCD_RGBPACK(tpoint->r, tpoint->g, tpoint->b));
774 #endif
775 rb->lcd_drawpixel(tpoint->position.x/SCALE , tpoint->position.y/SCALE);
777 tpoint++;
781 /*Check if point is within a rectangle*/
782 bool is_point_within_rectangle(struct Point* rect, struct Point* p, int size)
784 #if SHOW_COL
785 int aTLx = rect->x - size;
786 int aTLy = rect->y - size;
787 int aBRx = rect->x + size;
788 int aBRy = rect->y + size;
789 rb->lcd_hline( aTLx/SCALE, aBRx/SCALE, aTLy/SCALE);
790 rb->lcd_vline( aTLx/SCALE, aTLy/SCALE, aBRy/SCALE);
791 rb->lcd_hline( aTLx/SCALE, aBRx/SCALE, aBRy/SCALE);
792 rb->lcd_vline( aBRx/SCALE, aBRy/SCALE, aTLy/SCALE);
793 return (p->x > aTLx && p->x < aBRx && p->y > aTLy && p->y < aBRy);
794 #else
795 return (p->x > rect->x - size && p->x < rect->x + size &&
796 p->y > rect->y - size && p->y < rect->y + size);
797 #endif
800 /* Draw polygon */
801 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices)
803 int n, t1, t2, oldX, oldY;
804 struct Point *p;
805 bool bDrawAll = px < WRAP_GAP || LCD_WIDTH - px < WRAP_GAP ||
806 py < WRAP_GAP || LCD_HEIGHT - py < WRAP_GAP;
808 p = vertices;
809 p += num_vertices-1;
810 oldX = p->x/SCALE + px;
811 oldY = p->y/SCALE + py;
812 p = vertices;
813 for(n = num_vertices+1; --n;)
815 t1 = p->x/SCALE + px;
816 t2 = p->y/SCALE + py;
818 rb->lcd_drawline(oldX, oldY, t1, t2);
820 if(bDrawAll)
822 rb->lcd_drawline(oldX - LCD_WIDTH, oldY, t1 - LCD_WIDTH, t2);
823 rb->lcd_drawline(oldX + LCD_WIDTH, oldY, t1 + LCD_WIDTH, t2);
824 rb->lcd_drawline(oldX - LCD_WIDTH, oldY + LCD_HEIGHT,
825 t1 - LCD_WIDTH, t2 + LCD_HEIGHT);
826 rb->lcd_drawline(oldX + LCD_WIDTH, oldY + LCD_HEIGHT,
827 t1 + LCD_WIDTH, t2 + LCD_HEIGHT);
829 rb->lcd_drawline(oldX, oldY - LCD_HEIGHT, t1, t2 - LCD_HEIGHT);
830 rb->lcd_drawline(oldX, oldY + LCD_HEIGHT, t1, t2 + LCD_HEIGHT);
831 rb->lcd_drawline(oldX - LCD_WIDTH, oldY - LCD_HEIGHT,
832 t1 - LCD_WIDTH, t2 - LCD_HEIGHT);
833 rb->lcd_drawline(oldX + LCD_WIDTH, oldY - LCD_HEIGHT,
834 t1 + LCD_WIDTH, t2 - LCD_HEIGHT);
836 oldX = t1;
837 oldY = t2;
838 p++;
842 void animate_and_draw_explosion(struct Point* point, int num_points,
843 int xoffset, int yoffset)
845 int n;
846 for(n = num_points; --n;)
848 if(game_state != PAUSE_MODE)
850 point->x += point->dx;
851 point->y += point->dy;
853 rb->lcd_fillrect( point->x/SCALE + xoffset, point->y/SCALE + yoffset,
854 POINT_SIZE, POINT_SIZE);
855 point++;
859 /*stop movement of ship, 'cos that's what happens when you go into hyperspace.*/
860 void hyperspace(void)
862 ship.position.dx = ship.position.dy = 0;
863 ship.position.x = (rb->rand()%SCALED_WIDTH);
864 ship.position.y = (rb->rand()%SCALED_HEIGHT);
867 void initialise_enemy(void)
869 struct Point* point;
870 int n;
871 int size;
873 if(rb->rand()%100 > enemy.size_probability)
875 size = BIG_SHIP;
876 enemy.size_probability++;
877 if(enemy.size_probability < 90)
879 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
882 else
884 size = LITTLE_SHIP;
887 enemy_missile.survived = 0;
888 enemy_on_screen = true;
889 enemy.explode_countdown = 0;
890 enemy.last_time_appeared = *rb->current_tick;
891 point = enemy.vertices;
892 for(n = 0; n < NUM_ENEMY_VERTICES+NUM_ENEMY_VERTICES; n+=2)
894 point->x = enemy_vertices[n];
895 point->y = enemy_vertices[n+1];
896 point->x *= SCALE/size;
897 point->y *= SCALE/size;
898 point++;
901 if(ship.position.x >= SCALED_WIDTH/2)
903 enemy.position.dx = ENEMY_SPEED;
904 enemy.position.x = 0;
906 else
908 enemy.position.dx = -ENEMY_SPEED;
909 enemy.position.x = SCALED_WIDTH;
912 if(ship.position.y >= SCALED_HEIGHT/2)
914 enemy.position.dy = ENEMY_SPEED;
915 enemy.position.y = 0;
917 else
919 enemy.position.dy = -ENEMY_SPEED;
920 enemy.position.y = SCALED_HEIGHT;
923 enemy.position.dx *= SCALE/10;
924 enemy.position.dy *= SCALE/10;
927 void draw_and_move_enemy(void)
929 int enemy_x, enemy_y;
930 struct Point *point;
932 SET_FG(COL_ENEMY);
934 if(enemy_on_screen)
936 enemy_x = enemy.position.x/SCALE;
937 enemy_y = enemy.position.y/SCALE;
938 if(!enemy.explode_countdown)
940 point = enemy.vertices;
941 draw_polygon(enemy.vertices, enemy_x, enemy_y, NUM_ENEMY_VERTICES);
942 rb->lcd_drawline(enemy.vertices[0].x/SCALE + enemy_x,
943 enemy.vertices[0].y/SCALE + enemy_y,
944 enemy.vertices[3].x/SCALE + enemy_x,
945 enemy.vertices[3].y/SCALE + enemy_y);
947 if(game_state != PAUSE_MODE)
949 enemy.position.x += enemy.position.dx;
950 enemy.position.y += enemy.position.dy;
953 if(enemy.position.x > SCALED_WIDTH || enemy.position.x < 0)
954 enemy_on_screen = false;
956 if(enemy.position.y > SCALED_HEIGHT)
957 enemy.position.y = 0;
958 else if(enemy.position.y < 0)
959 enemy.position.y = SCALED_HEIGHT;
961 if( (rb->rand()%1000) < 10)
962 enemy.position.dy = -enemy.position.dy;
964 else
967 /* animate_and_draw_explosion(enemy.vertices, NUM_ENEMY_VERTICES,
968 enemy_x, enemy.position.y/SCALE); */
969 if(game_state != PAUSE_MODE)
971 enemy.explode_countdown--;
972 if(!enemy.explode_countdown)
973 enemy_on_screen = false;
977 else
979 if( (*rb->current_tick - enemy.last_time_appeared) > enemy.appear_timing)
980 if(rb->rand()%100 > enemy.appear_probability) initialise_enemy();
983 if(!enemy_missile.survived && game_state != GAME_OVER)
985 /*if no missile and the enemy is here and not exploding..then shoot baby!*/
986 if( !enemy.explode_countdown && enemy_on_screen &&
987 !ship.waiting_for_space && (rb->rand()%10) > 5 )
989 enemy_missile.position.x = enemy.position.x;
990 enemy_missile.position.y = enemy.position.y;
992 /*lame, needs to be sorted - it's trying to shoot at the ship*/
993 if(ABS(enemy.position.y - ship.position.y) <= 5*SCALE)
995 enemy_missile.position.dy = 0;
997 else
999 if( enemy.position.y < ship.position.y)
1000 enemy_missile.position.dy = 1;
1001 else
1002 enemy_missile.position.dy = -1;
1005 if(ABS(enemy.position.x - ship.position.x) <= 5*SCALE)
1006 enemy_missile.position.dx = 0;
1007 else
1009 if( enemy.position.x < ship.position.x)
1010 enemy_missile.position.dx = 1;
1011 else
1012 enemy_missile.position.dx = -1;
1015 if(enemy_missile.position.dx == 0 &&
1016 enemy_missile.position.dy == 0)
1017 enemy_missile.position.dx = enemy_missile.position.dy = -1;
1019 enemy_missile.position.dx *= SCALE;
1020 enemy_missile.position.dy *= SCALE;
1021 enemy_missile.survived = ENEMY_MISSILE_SURVIVAL_LENGTH;
1025 else
1027 rb->lcd_fillrect( enemy_missile.position.x/SCALE,
1028 enemy_missile.position.y/SCALE,
1029 POINT_SIZE, POINT_SIZE);
1030 if(game_state != PAUSE_MODE)
1032 move_point(&enemy_missile.position);
1033 enemy_missile.survived--;
1038 /******************
1039 * Lame method of collision
1040 * detection. It's checking for collision
1041 * between point and a big rectangle around the asteroid...
1042 *******************/
1043 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point)
1045 if( !is_point_within_rectangle(&asteroid->position, point,
1046 asteroid->radius+4*SCALE) )
1047 return false;
1049 if(point_in_poly(asteroid->vertices, NUM_ASTEROID_VERTICES,
1050 point->x - asteroid->position.x,
1051 point->y - asteroid->position.y))
1053 switch(asteroid->type)
1055 case(SMALL):
1056 asteroid->explode_countdown = EXPLOSION_LENGTH;
1057 create_trail_blaze(ASTEROID_EXPLOSION_COLOUR, &asteroid->position);
1058 break;
1060 case(LARGE):
1061 create_asteroid(MEDIUM, asteroid->position.x,
1062 asteroid->position.y);
1063 create_asteroid(MEDIUM, asteroid->position.x,
1064 asteroid->position.y);
1065 break;
1067 case(MEDIUM):
1068 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1069 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1070 break;
1073 current_score++;
1074 if(current_score > extra_life)
1076 num_lives++;
1077 extra_life = current_score+EXTRA_LIFE;
1079 asteroid_count--;
1080 asteroid->exists = false;
1081 return true;
1083 else
1084 return false;
1087 bool is_point_within_enemy(struct Point* point)
1089 if( is_point_within_rectangle(&enemy.position, point, 7*SCALE) )
1091 current_score += 5;
1092 /*enemy_missile.survived = 0;*/
1093 enemy.explode_countdown = EXPLOSION_LENGTH;
1094 /* initialise_explosion(enemy.vertices, NUM_ENEMY_VERTICES); */
1095 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1096 return true;
1098 else
1099 return false;
1102 bool is_ship_within_asteroid(struct Asteroid* asteroid)
1104 bool hit = false;
1105 struct Point p;
1107 p.x = ship.position.x + ship.vertices[0].x;
1108 p.y = ship.position.y + ship.vertices[0].y;
1109 hit |= is_point_within_asteroid(asteroid, &p);
1111 if(!hit)
1113 p.x = ship.position.x + ship.vertices[1].x;
1114 p.y = ship.position.y + ship.vertices[1].y;
1115 hit |= is_point_within_asteroid(asteroid, &p);
1116 if(!hit)
1118 p.x = ship.position.x + ship.vertices[3].x;
1119 p.y = ship.position.y + ship.vertices[3].y;
1120 hit |= is_point_within_asteroid(asteroid, &p);
1124 return hit;
1127 void initialise_explosion(struct Point* point, int num_points)
1129 int n;
1131 point->x += point->dx;
1132 point->y += point->dy;
1133 for(n = num_points; --n;)
1135 point->dx = point->x;
1136 point->dy = point->y;
1137 point++;
1142 /* Check for collsions between the missiles and the asteroids and the ship */
1143 void check_collisions(void)
1145 int m, n;
1146 bool asteroids_onscreen = false;
1147 struct Missile* missile;
1148 struct Asteroid* asteroid;
1149 bool ship_cant_be_placed = false;
1151 asteroid = asteroids_array;
1152 m = MAX_NUM_ASTEROIDS;
1153 while(--m)
1155 /*if the asteroids exists then test missile collision:*/
1156 if(asteroid->exists)
1158 missile = missiles_array;
1159 n = MAX_NUM_MISSILES;
1160 while(--n)
1162 /*if the missiles exists:*/
1163 if(missile->survived > 0)
1165 /*has the missile hit the asteroid?*/
1166 if(is_point_within_asteroid(asteroid, &missile->position)
1167 || is_point_within_asteroid(asteroid,
1168 &missile->oldpoint))
1170 missile->survived = 0;
1171 break;
1174 missile++;
1177 /*now check collision with ship:*/
1178 if(asteroid->exists && !ship.waiting_for_space && !ship.explode_countdown)
1180 if(is_ship_within_asteroid(asteroid))
1182 /*blow up ship*/
1183 ship.explode_countdown = EXPLOSION_LENGTH;
1184 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1185 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1188 /*has the enemy missile blown something up?*/
1189 if(asteroid->exists && enemy_missile.survived)
1191 if(is_point_within_asteroid(asteroid, &enemy_missile.position))
1193 /*take that score back then:*/
1194 if(current_score > 0) current_score--;
1195 enemy_missile.survived = 0;
1198 /*if it still exists, check if ship is waiting for space:*/
1199 if(asteroid->exists && ship.waiting_for_space)
1200 ship_cant_be_placed |=
1201 is_point_within_rectangle(&ship.position,
1202 &asteroid->position,
1203 space_check_size);
1207 /*is an asteroid still exploding?*/
1208 if(asteroid->explode_countdown)
1209 asteroids_onscreen = true;
1211 asteroid++;
1214 /*now check collision between ship and enemy*/
1215 if(enemy_on_screen && !ship.waiting_for_space &&
1216 !ship.explode_countdown && !enemy.explode_countdown)
1218 /*has the enemy collided with the ship?*/
1219 if(is_point_within_enemy(&ship.position))
1221 ship.explode_countdown = EXPLOSION_LENGTH;
1222 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1223 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1224 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1227 /*Now see if the enemy has been shot at by the ships missiles:*/
1228 missile = missiles_array;
1229 n = MAX_NUM_MISSILES;
1230 while(--n)
1232 if(missile->survived > 0 &&
1233 is_point_within_enemy(&missile->position))
1235 missile->survived = 0;
1236 break;
1238 missile++;
1242 /*test collision with enemy missile and ship:*/
1243 if(!ship_cant_be_placed && enemy_missile.survived > 0 &&
1244 point_in_poly(ship.vertices, NUM_SHIP_VERTICES,
1245 enemy_missile.position.x - ship.position.x,
1246 enemy_missile.position.y - ship.position.y))
1248 ship.explode_countdown = EXPLOSION_LENGTH;
1249 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1250 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1251 enemy_missile.survived = 0;
1252 enemy_missile.position.x = enemy_missile.position.y = 0;
1255 if(!ship_cant_be_placed)
1256 ship.waiting_for_space = false;
1258 /*if all asteroids cleared then start again:*/
1259 if(asteroid_count == 0 && !enemy_on_screen && !asteroids_onscreen)
1261 current_level++;
1262 game_state = SHOW_LEVEL;
1263 enemy.appear_probability += 5;
1264 enemy.appear_timing -= 200;
1265 if( enemy.appear_probability > 100)
1266 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1267 show_level_timeout = SHOW_LEVEL_TIME;
1271 /*************************************************
1272 ** Creates a new asteroid of the given 4type (size)
1273 ** and at the given location.
1274 *************************************************/
1275 void create_asteroid(enum asteroid_type type, int x, int y)
1277 struct Asteroid* asteroid;
1278 int n;
1280 asteroid = asteroids_array;
1281 n = MAX_NUM_ASTEROIDS;
1282 while(--n)
1284 if(!asteroid->exists && !asteroid->explode_countdown)
1286 initialise_asteroid(asteroid, type);
1287 asteroid->position.x = x;
1288 asteroid->position.y = y;
1289 break;
1291 asteroid++;
1295 /* Initialise a missile */
1296 void initialise_missile(struct Missile* missile)
1298 missile->position.x = ship.position.x + ship.vertices[0].x;
1299 missile->position.y = ship.position.y + ship.vertices[0].y;
1300 missile->position.dx = (ship.vertices[0].x - ship.vertices[2].x)/2;
1301 missile->position.dy = (ship.vertices[0].y - ship.vertices[2].y)/2;
1302 missile->survived = MISSILE_SURVIVAL_LENGTH;
1303 missile->oldpoint.x = missile->position.x;
1304 missile->oldpoint.y = missile->position.y;
1307 /* Draw and Move all the missiles */
1308 void draw_and_move_missiles(void)
1310 int n;
1311 int p1x, p1y;
1312 int p2x, p2y;
1314 struct Missile* missile;
1315 missile = missiles_array;
1317 SET_FG(COL_MISSILE);
1319 n = MAX_NUM_MISSILES;
1320 while(--n)
1322 if(missile->survived)
1324 if(missile->position.dx > 0)
1326 if(missile->position.x >= missile->oldpoint.x)
1328 p1x = missile->oldpoint.x;
1329 p2x = missile->position.x;
1331 else
1333 p1x = 0;
1334 p2x = missile->position.x;
1337 else
1339 if(missile->oldpoint.x >= missile->position.x)
1341 p1x = missile->oldpoint.x;
1342 p2x = missile->position.x;
1344 else
1346 p1x = missile->oldpoint.x;
1347 p2x = LCD_WIDTH;
1351 if(missile->position.dy > 0)
1353 if(missile->position.y >= missile->oldpoint.y)
1355 p1y = missile->oldpoint.y;
1356 p2y = missile->position.y;
1358 else
1360 p1y = 0;
1361 p2y = missile->position.y;
1364 else
1366 if(missile->oldpoint.y >= missile->position.y)
1368 p1y = missile->oldpoint.y;
1369 p2y = missile->position.y;
1371 else
1373 p1y = missile->oldpoint.y;
1374 p2y = LCD_HEIGHT;
1378 rb->lcd_drawline( p1x/SCALE, p1y/SCALE, p2x/SCALE, p2y/SCALE);
1380 if(game_state != PAUSE_MODE)
1382 missile->oldpoint.x = missile->position.x;
1383 missile->oldpoint.y = missile->position.y;
1384 move_point(&missile->position);
1385 missile->survived--;
1388 missile++;
1392 void draw_lives(void)
1394 int n;
1395 int px = (LCD_WIDTH - num_lives*4 - 1);
1396 #if(LARGE_LCD)
1397 int py = (LCD_HEIGHT-6);
1398 #else
1399 int py = (LCD_HEIGHT-4);
1400 #endif
1402 SET_FG(COL_PLAYER);
1404 n = num_lives;
1405 while(--n)
1407 draw_polygon(lives_points, px, py, NUM_SHIP_VERTICES);
1408 #if(LARGE_LCD)
1409 px += 8;
1410 #else
1411 px += 6;
1412 #endif
1416 /*Fire the next missile*/
1417 void fire_missile(void)
1419 int n;
1420 struct Missile* missile;
1422 if(!ship.explode_countdown && !ship.waiting_for_space)
1424 missile = missiles_array;
1425 n = MAX_NUM_MISSILES;
1426 while(--n)
1428 if(!missile->survived)
1430 initialise_missile(missile);
1431 break;
1433 missile++;
1438 /* Initialise the passed Asteroid */
1439 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type type)
1441 int n;
1442 bool b,b2;
1443 struct Point* point;
1444 asteroid->exists = true;
1445 asteroid->type = type;
1446 asteroid->explode_countdown = 0;
1448 /*Set the radius of the asteroid:*/
1449 asteroid->radius = (int)type*SCALE;
1451 /*shall we move Clockwise and Fast*/
1452 if((rb->rand()%100)>75)
1454 asteroid->speed_cos = FAST_ROT_CW_COS;
1455 asteroid->speed_sin = FAST_ROT_CW_SIN;
1457 else if((rb->rand()%100)>75)
1459 asteroid->speed_cos = FAST_ROT_ACW_COS;
1460 asteroid->speed_sin = FAST_ROT_ACW_SIN;
1462 else if((rb->rand()%100)>75)
1464 asteroid->speed_cos = SLOW_ROT_ACW_COS;
1465 asteroid->speed_sin = SLOW_ROT_ACW_SIN;
1467 else
1469 asteroid->speed_cos = SLOW_ROT_CW_COS;
1470 asteroid->speed_sin = SLOW_ROT_CW_SIN;
1473 b = (rb->rand()%100)>66;
1474 b2 = (rb->rand()%100)>66;
1475 point = asteroid->vertices;
1476 for(n = 0; n < NUM_ASTEROID_VERTICES*2; n+=2)
1478 if(b)
1480 point->x = asteroid_one[n];
1481 point->y = asteroid_one[n+1];
1483 else if( b2 )
1485 point->x = asteroid_two[n];
1486 point->y = asteroid_two[n+1];
1488 else
1490 point->x = asteroid_three[n];
1491 point->y = asteroid_three[n+1];
1494 point->x *= asteroid->radius/6;
1495 point->y *= asteroid->radius/6;
1496 point++;
1500 asteroid->radius += 6*SCALE;
1501 if(asteroid->type == SMALL)
1502 asteroid->radius /= 3;/*2*/
1503 else if(asteroid->type == LARGE)
1504 asteroid->radius += 3*SCALE;/*2*/
1505 b = true;
1506 while(b)
1508 /*Set the position randomly:*/
1509 asteroid->position.x = (rb->rand()%SCALED_WIDTH);
1510 asteroid->position.y = (rb->rand()%SCALED_HEIGHT);
1512 asteroid->position.dx = 0;
1513 while(asteroid->position.dx == 0)
1514 asteroid->position.dx = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1516 asteroid->position.dy = 0;
1517 while(asteroid->position.dy == 0)
1518 asteroid->position.dy = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1520 asteroid->position.dx *= SCALE/10;
1521 asteroid->position.dy *= SCALE/10;
1523 b = is_point_within_rectangle(&ship.position, &asteroid->position,
1524 space_check_size);
1527 /*Now rotate the asteroid a bit, so they all look a bit different*/
1528 for(n=(rb->rand()%30) + 2;--n;)
1529 rotate_asteroid(asteroid);
1531 /*great, we've created an asteroid, don't forget to increment the total:*/
1532 asteroid_count++;
1535 /*Initialise the ship*/
1536 void initialise_ship(void)
1538 struct Point* point;
1539 struct Point* lives_point;
1540 int n;
1542 ship.position.x = CENTER_LCD_X;
1543 ship.position.y = CENTER_LCD_Y;
1544 ship.position.x *= SCALE;
1545 ship.position.y *= SCALE;
1546 ship.position.dx = ship.position.dy = 0;
1548 point = ship.vertices;
1549 lives_point = lives_points;
1550 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1552 point->x = ship_vertices[n];
1553 point->y = ship_vertices[n+1];
1554 point->x *= SCALE;
1555 point->y *= SCALE;
1556 point++;
1557 lives_point++;
1560 ship.position.dx = 0;
1561 ship.position.dy = 0;
1562 ship.explode_countdown = 0;
1564 /*grab a copy of the ships points for the lives display:*/
1565 point = ship.vertices;
1566 lives_point = lives_points;
1567 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1569 lives_point->x = point->x;
1570 lives_point->y = point->y;
1571 lives_point++;
1572 point++;
1576 void rotate_asteroid(struct Asteroid* asteroid)
1578 struct Point* point;
1579 int n;
1580 long xtemp;
1582 point = asteroid->vertices;
1583 for(n = NUM_ASTEROID_VERTICES+1; --n;)
1585 xtemp = point->x;
1586 point->x = xtemp*asteroid->speed_cos/SIN_COS_SCALE -
1587 point->y*asteroid->speed_sin/SIN_COS_SCALE;
1588 point->y = point->y*asteroid->speed_cos/SIN_COS_SCALE +
1589 xtemp*asteroid->speed_sin/SIN_COS_SCALE;
1590 point++;
1594 /*************************************************
1595 ** Draws the ship, moves the ship and creates a new
1596 ** one if it's finished exploding.
1597 **************************************************/
1598 void draw_and_move_ship(void)
1600 int nxoffset = ship.position.x/SCALE;
1601 int nyoffset = ship.position.y/SCALE;
1602 SET_FG(COL_PLAYER);
1603 if(!ship.explode_countdown)
1605 if(!ship.waiting_for_space)
1607 draw_polygon(ship.vertices, nxoffset, nyoffset, NUM_SHIP_VERTICES);
1608 if(game_state != PAUSE_MODE && game_state != GAME_OVER)
1610 move_point(&ship.position);
1614 else
1616 /* animate_and_draw_explosion(ship.vertices, NUM_SHIP_VERTICES,
1617 ship.position.x/SCALE,
1618 ship.position.y/SCALE); */
1619 if(game_state != PAUSE_MODE)
1621 ship.explode_countdown--;
1622 if(!ship.explode_countdown)
1624 num_lives--;
1625 if(!num_lives)
1627 show_game_over = SHOW_GAME_OVER_TIME;
1628 game_state = GAME_OVER;
1630 else
1632 initialise_ship();
1633 ship.waiting_for_space = true;
1640 void thrust_ship(void)
1642 if(!ship.waiting_for_space)
1644 ship.position.dx += ( ship.vertices[0].x - ship.vertices[2].x )/20;
1645 ship.position.dy += ( ship.vertices[0].y - ship.vertices[2].y )/20;
1646 /*if dx and dy are below a certain threshold, then set 'em to 0
1647 but to do this we need to ascertain if the spacehip as moved on screen
1648 for more than a certain amount. */
1650 create_trail_blaze(THRUST_COLOUR, &ship.position);
1654 /**************************************************
1655 ** Rotate the ship using the passed sin & cos values
1656 ***************************************************/
1657 void rotate_ship(int c, int s)
1659 struct Point* point;
1660 int n;
1661 double xtemp;
1663 if(!ship.waiting_for_space && !ship.explode_countdown)
1665 point = ship.vertices;
1666 for(n=NUM_SHIP_VERTICES+1;--n;)
1668 xtemp = point->x;
1669 point->x = xtemp*c/SIN_COS_SCALE - point->y*s/SIN_COS_SCALE;
1670 point->y = point->y*c/SIN_COS_SCALE + xtemp*s/SIN_COS_SCALE;
1671 point++;
1676 void drawstars()
1678 struct Point* p;
1679 int n = NUM_STARS;
1681 p = stars;
1682 SET_FG(COL_STARS);
1684 while(--n)
1686 rb->lcd_drawpixel(p->x , p->y);
1687 p++;
1691 /*************************************************
1692 ** Draw And Move all Asteroids
1693 *************************************************/
1694 void draw_and_move_asteroids(void)
1696 int n;
1697 struct Asteroid* asteroid;
1699 asteroid = asteroids_array;
1700 SET_FG(COL_ASTEROID);
1702 n = MAX_NUM_ASTEROIDS;
1703 while(--n)
1705 if(game_state != PAUSE_MODE)
1707 if(asteroid->exists)
1709 move_point(&asteroid->position);
1710 rotate_asteroid(asteroid);
1711 draw_polygon(asteroid->vertices, asteroid->position.x/SCALE,
1712 asteroid->position.y/SCALE,
1713 NUM_ASTEROID_VERTICES);
1715 else if(asteroid->explode_countdown)
1717 /* animate_and_draw_explosion(asteroid->vertices,
1718 NUM_ASTEROID_VERTICES,
1719 asteroid->position.x/SCALE,
1720 asteroid->position.y/SCALE); */
1721 asteroid->explode_countdown--;
1724 else
1726 if(asteroid->exists)
1727 draw_polygon(asteroid->vertices,
1728 asteroid->position.x/SCALE,
1729 asteroid->position.y/SCALE,
1730 NUM_ASTEROID_VERTICES);
1732 asteroid++;
1736 void create_stars(void)
1738 struct TrailPoint* tpoint;
1739 struct Point* p;
1740 int n;
1742 p = stars;
1743 n = NUM_STARS;
1744 while(--n)
1746 p->x = (rb->rand()%LCD_WIDTH);
1747 p->y = (rb->rand()%LCD_HEIGHT);
1748 p++;
1752 /* give the point a random countdown timer, so they dissapears at different
1753 times */
1754 tpoint = trailPoints;
1755 n = NUM_TRAIL_POINTS;
1756 while(--n)
1758 tpoint->alive = 0;
1759 tpoint++;
1763 /*************************************************
1764 ** Creates start_num number of new asteroids of
1765 ** full size.
1766 **************************************************/
1767 void initialise_game(int start_num)
1769 int n;
1770 asteroid_count = next_missile_count = next_thrust_count = 0;
1771 struct Asteroid* asteroid;
1772 struct Missile* missile;
1773 extra_life = EXTRA_LIFE;
1775 /*no enemy*/
1776 enemy_on_screen = 0;
1777 enemy_missile.survived = 0;
1779 /*clear asteroids*/
1780 asteroid = asteroids_array;
1781 n = MAX_NUM_ASTEROIDS;
1782 while(--n)
1784 asteroid->exists = false;
1785 asteroid++;
1788 /*make some LARGE asteroids*/
1789 for(n = 0; n < start_num; n++)
1790 initialise_asteroid(&asteroids_array[n], LARGE);
1792 /*ensure all missiles are out of action: */
1793 missile = missiles_array;
1794 n = MAX_NUM_MISSILES;
1795 while(--n)
1797 missile->survived=0;
1798 missile++;
1802 void start_attract_mode(void)
1804 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1805 enemy.appear_timing = ENEMY_APPEAR_TIMING_START;
1806 current_level = 5;
1807 num_lives = START_LIVES;
1808 current_score = 0;
1809 attract_flip_timeout = ATTRACT_FLIP_TIME;
1810 game_state = ATTRACT_MODE;
1811 if(asteroid_count < 3)
1812 initialise_game(current_level);
1815 enum plugin_status start_game(void)
1817 char s[20];
1818 char level[10];
1819 int button;
1820 int end;
1821 int CYCLETIME = 30;
1823 /*create stars once, and once only:*/
1824 create_stars();
1826 SET_BG(LCD_BLACK);
1828 while(true)
1830 /*game starts with at level 1
1831 with 1 asteroid.*/
1832 start_attract_mode();
1834 /*Main loop*/
1835 while(true)
1837 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1838 rb->lcd_clear_display();
1839 SET_FG(COL_TEXT);
1840 switch(game_state)
1842 case(ATTRACT_MODE):
1843 if(attract_flip_timeout < ATTRACT_FLIP_TIME/2)
1845 rb->lcd_putsxy(CENTER_LCD_X - 39,
1846 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4,
1847 "Fire to Start");
1848 if(!attract_flip_timeout)
1849 attract_flip_timeout = ATTRACT_FLIP_TIME;
1851 else
1853 rb->snprintf(s, sizeof(s), "Hi Score %d ", high_score);
1854 rb->lcd_putsxy(CENTER_LCD_X - 30,
1855 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, s);
1857 attract_flip_timeout--;
1858 break;
1860 case(GAME_OVER):
1861 rb->lcd_putsxy(CENTER_LCD_X - 25,
1862 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "Game Over");
1863 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1864 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1865 show_game_over--;
1866 if(!show_game_over)
1867 start_attract_mode();
1868 break;
1870 case(PAUSE_MODE):
1871 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1872 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1873 rb->lcd_putsxy(CENTER_LCD_X - 15,
1874 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "pause");
1875 draw_and_move_missiles();
1876 draw_lives();
1877 draw_and_move_ship();
1878 break;
1880 case(PLAY_MODE):
1881 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1882 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1883 draw_and_move_missiles();
1884 draw_lives();
1885 check_collisions();
1886 draw_and_move_ship();
1887 break;
1889 case(SHOW_LEVEL):
1890 show_level_timeout--;
1891 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1892 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1893 rb->snprintf(level, sizeof(level), "stage %d ", current_level);
1894 rb->lcd_putsxy(CENTER_LCD_X - 20,
1895 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, level);
1896 draw_and_move_ship();
1897 draw_lives();
1898 if(!show_level_timeout)
1900 initialise_game(current_level);
1901 game_state = PLAY_MODE;
1902 draw_lives();
1904 break;
1906 draw_trail_blaze();
1907 drawstars();
1908 draw_and_move_asteroids();
1909 draw_and_move_enemy();
1911 rb->lcd_update();
1912 button = rb->button_get(false);
1914 #ifdef HAS_BUTTON_HOLD
1915 if (rb->button_hold())
1916 game_state = PAUSE_MODE;
1917 #endif
1919 switch(button)
1921 case(AST_PAUSE):
1922 if(game_state == PLAY_MODE)
1923 game_state = PAUSE_MODE;
1924 else if(game_state == PAUSE_MODE)
1925 game_state = PLAY_MODE;
1926 break;
1928 #ifdef AST_RC_QUIT
1929 case AST_RC_QUIT:
1930 #endif
1931 case(AST_QUIT):
1932 if(game_state == ATTRACT_MODE)
1933 return PLUGIN_OK;
1934 else if(game_state == GAME_OVER)
1936 start_attract_mode();
1938 else
1940 show_game_over = SHOW_GAME_OVER_TIME;
1941 game_state = GAME_OVER;
1943 break;
1945 case (AST_LEFT_REP):
1946 case (AST_LEFT):
1947 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1948 rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN);
1949 break;
1951 case (AST_RIGHT_REP):
1952 case (AST_RIGHT):
1953 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1954 rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN);
1955 break;
1957 case (AST_THRUST_REP):
1958 case (AST_THRUST):
1959 if((game_state == PLAY_MODE || game_state == SHOW_LEVEL) && !next_thrust_count)
1961 thrust_ship();
1962 next_thrust_count = 5;
1964 break;
1966 case (AST_HYPERSPACE):
1967 if(game_state == PLAY_MODE)
1968 hyperspace();
1969 /*maybe shield if it gets too hard */
1970 break;
1972 case (AST_FIRE_REP):
1973 case (AST_FIRE):
1974 if(game_state == ATTRACT_MODE)
1976 current_level = START_LEVEL;
1977 initialise_ship();
1978 initialise_game(current_level);
1979 show_level_timeout = SHOW_LEVEL_TIME;
1980 game_state = PLAY_MODE;
1982 else if(game_state == PLAY_MODE)
1984 if(!next_missile_count)
1986 fire_missile();
1987 next_missile_count = 10;
1990 else if(game_state == PAUSE_MODE)
1992 game_state = PLAY_MODE;
1994 break;
1996 default:
1997 if (rb->default_event_handler(button)==SYS_USB_CONNECTED)
1998 return PLUGIN_USB_CONNECTED;
1999 break;
2002 if(!num_lives)
2004 if(high_score < current_score)
2005 high_score = current_score;
2006 if(!show_game_over)
2007 break;
2010 if(next_missile_count)
2011 next_missile_count--;
2013 if(next_thrust_count)
2014 next_thrust_count--;
2016 if (end > *rb->current_tick)
2017 rb->sleep(end-*rb->current_tick);
2018 else
2019 rb->yield();
2025 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
2027 enum plugin_status retval;
2028 (void)(parameter);
2029 rb = api;
2031 game_state = ATTRACT_MODE;
2033 #if LCD_DEPTH > 1
2034 rb->lcd_set_backdrop(NULL);
2035 #endif
2036 /* universal font */
2037 rb->lcd_setfont(FONT_SYSFIXED);
2038 /* Turn off backlight timeout */
2039 backlight_force_on(rb); /* backlight control in lib/helper.c */
2040 iohiscore();
2041 retval = start_game();
2042 iohiscore();
2043 rb->lcd_setfont(FONT_UI);
2044 /* Turn on backlight timeout (revert to settings) */
2045 backlight_use_settings(rb); /* backlight control in lib/helper.c */
2046 return retval;