when changing settings from the Talk and Voice window also update the main widgets...
[Rockbox.git] / apps / plugins / spacerocks.c
blob5d5a1bac6b85b68e45bfab54595dd053d438845f
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 by Mat Holton
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "plugin.h"
21 #include "math.h"
22 #include "stdio.h"
23 #include "helper.h"
25 PLUGIN_HEADER
27 /******************************* Globals ***********************************/
28 static 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 #else
191 #error No keymap defined!
192 #endif
194 #define ABS(x) ((x)>0?(x):-(x))
196 #define RES MAX(LCD_WIDTH, LCD_HEIGHT)
197 #define LARGE_LCD RES >= 200
198 #define ENEMY_MISSILE_SURVIVAL_LENGTH RES/2
199 #define ASTEROID_SPEED RES/20
200 #define MISSILE_SURVIVAL_LENGTH 40
202 #define EXTRA_LIFE 250
203 #define SCALE 5000
204 #define MISSILE_SCALE 5000
205 #define WRAP_GAP 12
206 #define EXPLOSION_LENGTH 20
207 #define SHOW_COL 0
208 #define HISCORE_FILE PLUGIN_GAMES_DIR "/astrorocks.hs"
209 #define POINT_SIZE 2
210 #define MAX_NUM_ASTEROIDS 25
211 #define MAX_NUM_MISSILES 6
212 #define ENEMY_BIG_PROBABILITY_START 10
213 #define ENEMY_APPEAR_PROBABILITY_START 35
214 #define ENEMY_APPEAR_TIMING_START 1800
215 #define LITTLE_SHIP 2
216 #define BIG_SHIP 1
217 #define SHOW_GAME_OVER_TIME 100
218 #define SHOW_LEVEL_TIME 50
219 #define START_LIVES 3
220 #define START_LEVEL 1
221 #define NUM_ASTEROID_VERTICES 10
222 #define NUM_SHIP_VERTICES 4
223 #define NUM_ENEMY_VERTICES 6
224 #define MAX_LEVEL MAX_NUM_ASTEROIDS
225 #define ENEMY_SPEED 4
226 #define ENEMY_START_X 0
227 #define ENEMY_START_Y 0
228 #define SIZE_ENEMY_COLLISION 5*SCALE
229 #define ATTRACT_FLIP_TIME 100
230 #define NUM_STARS 50
231 #define NUM_TRAIL_POINTS 70
232 #define NUM_ROTATIONS 16
234 #define SIN_COS_SCALE 10000
236 #define FAST_ROT_CW_SIN 873
237 #define FAST_ROT_CW_COS 9963
238 #define FAST_ROT_ACW_SIN -873
239 #define FAST_ROT_ACW_COS 9963
241 #define MEDIUM_ROT_CW_SIN 350
242 #define MEDIUM_ROT_CW_COS 9994
243 #define MEDIUM_ROT_ACW_SIN -350
244 #define MEDIUM_ROT_ACW_COS 9994
246 #define SLOW_ROT_CW_SIN 350
247 #define SLOW_ROT_CW_COS 9994
248 #define SLOW_ROT_ACW_SIN - 350
249 #define SLOW_ROT_ACW_COS 9994
251 #ifdef HAVE_LCD_COLOR
252 #define SHIP_ROT_CW_SIN 2419
253 #define SHIP_ROT_CW_COS 9702
254 #define SHIP_ROT_ACW_SIN -2419
255 #define SHIP_ROT_ACW_COS 9702
256 #else
257 #define SHIP_ROT_CW_SIN 3827
258 #define SHIP_ROT_CW_COS 9239
259 #define SHIP_ROT_ACW_SIN -3827
260 #define SHIP_ROT_ACW_COS 9239
261 #endif
264 #define SCALED_WIDTH (LCD_WIDTH*SCALE)
265 #define SCALED_HEIGHT (LCD_HEIGHT*SCALE)
266 #define CENTER_LCD_X (LCD_WIDTH/2)
267 #define CENTER_LCD_Y (LCD_HEIGHT/2)
269 #define SHIP_EXPLOSION_COLOUR 1
270 #define ASTEROID_EXPLOSION_COLOUR 2
271 #define ENEMY_EXPLOSION_COLOUR 3
272 #define THRUST_COLOUR 4
274 #define ASTEROID_R 230
275 #define ASTEROID_G 200
276 #define ASTEROID_B 100
277 #define SHIP_R 255
278 #define SHIP_G 255
279 #define SHIP_B 255
280 #define ENEMY_R 50
281 #define ENEMY_G 220
282 #define ENEMY_B 50
283 #define THRUST_R 200
284 #define THRUST_G 200
285 #define THRUST_B 0
287 #ifdef HAVE_LCD_COLOR
288 #define COL_MISSILE LCD_RGBPACK(200,0,0)
289 #define COL_PLAYER LCD_RGBPACK(200,200,200)
290 #define COL_STARS LCD_WHITE
291 #define COL_ASTEROID LCD_RGBPACK(ASTEROID_R,ASTEROID_G,ASTEROID_B)
292 #define COL_TEXT LCD_RGBPACK(200,200,255)
293 #define COL_ENEMY LCD_RGBPACK(ENEMY_R,ENEMY_G,ENEMY_B)
294 #define SET_FG rb->lcd_set_foreground
295 #define SET_BG rb->lcd_set_background
296 #else
297 #define SET_FG(x)
298 #define SET_BG(x)
299 #endif
301 /* The array of points that make up an asteroid */
302 static const short asteroid_one[NUM_ASTEROID_VERTICES*2] =
304 -2, -12,
305 4, -8,
306 8, -14,
307 16, -5,
308 14, 0,
309 20, 2,
310 12, 14,
311 -4, 14,
312 -10, 6,
313 -10, -8
316 /* The array of points that make up an asteroid */
317 static const short asteroid_two[NUM_ASTEROID_VERTICES*2] =
319 -2, -12,
320 4, -16,
321 6, -14,
322 16, -8,
323 14, 0,
324 20, 2,
325 12, 14,
326 -4, 14,
327 -10, 6,
328 -10, -8
331 /* The array of points that make up an asteroid */
332 static const short asteroid_three[NUM_ASTEROID_VERTICES*2] =
334 -2, -12,
335 4, -16,
336 6, -14,
337 2, -8,
338 14, 0,
339 20, 2,
340 12, 14,
341 -4, 14,
342 -16, 6,
343 -10, -8
346 /* The array od points the make up the ship */
347 static const short ship_vertices[NUM_SHIP_VERTICES*2] =
349 #if(LARGE_LCD)
350 0,-6,
351 4, 6,
352 0, 2,
353 -4, 6
354 #else
355 0,-4,
356 3, 4,
357 0, 1,
358 -3, 4
359 #endif
362 /* The array of points the make up the bad spaceship */
363 static const short enemy_vertices[NUM_ENEMY_VERTICES*2] =
365 #if(LARGE_LCD)
366 -8, 0,
367 -4, 4,
368 4, 4,
369 8, 0,
370 4, -4,
371 -4, -4
372 #else
373 -5, 0,
374 -2, 2,
375 2, 2,
376 5, 0,
377 2, -2,
378 -2, -2
379 #endif
383 enum asteroid_type
385 #if(LARGE_LCD)
386 SMALL = 2,
387 MEDIUM = 4,
388 LARGE = 6,
389 #else
390 SMALL = 1,
391 MEDIUM = 2,
392 LARGE = 3,
393 #endif
397 enum game_state
399 GAME_OVER,
400 ATTRACT_MODE,
401 SHOW_LEVEL,
402 PLAY_MODE,
403 PAUSE_MODE
406 struct Point
408 int x;
409 int y;
410 int dx;
411 int dy;
414 struct TrailPoint
416 int alive;
417 struct Point position;
418 short r;
419 short g;
420 short b;
421 short dec;
424 /* Asteroid structure, contains an array of points */
425 struct Asteroid
427 enum asteroid_type type;
428 bool exists;
429 struct Point position;
430 struct Point vertices[NUM_ASTEROID_VERTICES];
431 int radius;
432 long speed_cos;
433 long speed_sin;
434 int explode_countdown;
437 struct Ship
439 struct Point vertices[NUM_SHIP_VERTICES];
440 struct Point position;
441 bool waiting_for_space;
442 int explode_countdown;
445 struct Enemy
447 struct Point vertices[NUM_ENEMY_VERTICES];
448 struct Point position;
449 int explode_countdown;
450 long last_time_appeared;
451 short size_probability;
452 short appear_probability;
453 short appear_timing;
456 struct Missile
458 struct Point position;
459 struct Point oldpoint;
460 int survived;
463 static enum game_state game_state;
464 static int asteroid_count;
465 static int next_missile_count;
466 static int next_thrust_count;
467 static int num_lives;
468 static int extra_life;
469 static int show_level_timeout;
470 static int attract_flip_timeout;
471 static int show_game_over;
472 static int current_level;
473 static int current_score;
474 static int high_score;
475 static int space_check_size = 30*SCALE;
477 static bool enemy_on_screen;
478 static char phscore[30];
479 static struct Ship ship;
480 static struct Point stars[NUM_STARS];
481 static struct Asteroid asteroids_array[MAX_NUM_ASTEROIDS];
482 static struct Missile missiles_array[MAX_NUM_MISSILES];
483 static struct Missile enemy_missile;
484 static struct Enemy enemy;
485 static struct Point lives_points[NUM_SHIP_VERTICES];
486 static struct TrailPoint trailPoints[NUM_TRAIL_POINTS];
488 void draw_and_move_asteroids(void);
489 void initialise_game(int nStartNum);
491 bool is_asteroid_near_ship(struct Asteroid* asteroid);
492 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point);
494 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type eType);
495 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices);
496 void rotate_asteroid(struct Asteroid* asteroid);
497 void create_asteroid(enum asteroid_type type, int x, int y);
498 void create_stars(void);
500 void initialise_ship(void);
501 void draw_and_move_ship(void);
502 void rotate_ship(int s, int c);
503 void thrust_ship(void);
505 void initialise_missile(struct Missile* missile);
506 void draw_and_move_missiles(void);
507 void fire_missile(void);
509 void animate_and_draw_explosion(struct Point* point, int num_points, int xoffset, int yoffset);
510 void initialise_explosion(struct Point* point, int num_points);
512 void move_point(struct Point* point);
513 void hyperspace(void);
514 void check_collisions(void);
515 void initialise_enemy(void);
516 void draw_and_move_enemy(void);
517 void draw_lives(void);
518 void drawstars(void);
519 bool is_ship_within_asteroid(struct Asteroid* asteroid);
523 /*Hi-Score reading and writing to file - this needs moving to the hi-score plugin lib as
524 a 3rd function */
525 void iohiscore(void)
527 int fd;
528 int compare;
530 /* clear the buffer we're about to load the highscore data into */
531 rb->memset(phscore, 0, sizeof(phscore));
533 fd = rb->open(HISCORE_FILE,O_RDWR | O_CREAT);
534 if(fd < 0)
536 rb->splash(HZ, "Highscore file read error");
537 return;
540 /* highscore used to %d, is now %d\n
541 Deal with no file or bad file */
542 rb->read(fd,phscore, sizeof(phscore));
544 compare = rb->atoi(phscore);
546 if(high_score > compare)
548 rb->lseek(fd,0,SEEK_SET);
549 rb->fdprintf(fd, "%d\n", high_score);
551 else
552 high_score = compare;
554 rb->close(fd);
557 bool point_in_poly(struct Point* _point, int num_vertices, int x, int y)
559 struct Point* pi;
560 struct Point* pj;
561 int n;
562 bool c = false;
564 pi = _point;
565 pj = _point;
566 pj += num_vertices-1;
568 n = num_vertices;
569 while(n--)
571 if((((pi->y <= y) && (y < pj->y)) || ((pj->y <= y) && (y < pi->y))) &&
572 (x < (pj->x - pi->x) * (y - pi->y) / (pj->y - pi->y) + pi->x))
573 c = !c;
575 if(n == num_vertices - 1)
576 pj = _point;
577 else
578 pj++;
580 pi++;
583 return c;
586 void move_point(struct Point* point)
588 point->x += point->dx;
589 point->y += point->dy;
591 /*check bounds on the x-axis:*/
592 if(point->x >= SCALED_WIDTH)
593 point->x = 0;
594 else if(point->x <= 0)
595 point->x = SCALED_WIDTH;
597 /*Check bounds on the y-axis:*/
598 if(point->y >= SCALED_HEIGHT)
599 point->y = 0;
600 else if(point->y <= 0)
601 point->y = SCALED_HEIGHT;
604 void create_trail(struct TrailPoint* tpoint)
606 tpoint->position.dx = -( ship.vertices[0].x - ship.vertices[2].x )/10;
607 tpoint->position.dy = -( ship.vertices[0].y - ship.vertices[2].y )/10;
610 void create_explosion_trail(struct TrailPoint* tpoint)
612 tpoint->position.dx = (rb->rand()%5050)-2500;
613 tpoint->position.dy = (rb->rand()%5050)-2500;
616 void create_trail_blaze(int colour, struct Point* position)
618 int numtoadd;
619 struct TrailPoint* tpoint;
620 int n;
621 int xadd,yadd;
622 if(colour != SHIP_EXPLOSION_COLOUR)
624 numtoadd = NUM_TRAIL_POINTS/5;
625 xadd = position->x;
626 yadd = position->y;
628 else
630 numtoadd = NUM_TRAIL_POINTS/8;
631 xadd = ship.position.x;
632 yadd = ship.position.y;
635 /* give the point a random countdown timer, so they dissapears at different times */
636 tpoint = trailPoints;
637 n = NUM_TRAIL_POINTS;
638 while(--n)
640 if(tpoint->alive <= 0 && numtoadd)
642 numtoadd--;
643 /* take a random x point anywhere between bottom two points of ship. */
644 /* ship.position.x; */
645 tpoint->position.x = (ship.vertices[2].x + (rb->rand()%18000)-9000) + position->x;
646 tpoint->position.y = (ship.vertices[2].y + (rb->rand()%18000)-9000) + position->y;
648 switch(colour)
650 case SHIP_EXPLOSION_COLOUR:
651 tpoint->r = 255;
652 tpoint->g = 255;
653 tpoint->b = 255;
654 create_explosion_trail(tpoint);
655 tpoint->alive = 510;
656 tpoint->dec = 2;
657 break;
658 case ASTEROID_EXPLOSION_COLOUR:
659 tpoint->r = ASTEROID_R;
660 tpoint->g = ASTEROID_G;
661 tpoint->b = ASTEROID_B;
662 create_explosion_trail(tpoint);
663 tpoint->alive = 510;
664 tpoint->dec = 2;
665 break;
666 case ENEMY_EXPLOSION_COLOUR:
667 tpoint->r = ENEMY_R;
668 tpoint->g = ENEMY_G;
669 tpoint->b = ENEMY_B;
670 create_explosion_trail(tpoint);
671 tpoint->alive = 510;
672 tpoint->dec = 2;
673 break;
674 case THRUST_COLOUR:
675 tpoint->r = THRUST_R;
676 tpoint->g = THRUST_G;
677 tpoint->b = THRUST_B;
678 create_trail(tpoint);
679 tpoint->alive = 175;
680 tpoint->dec = 4;
681 break;
683 /* add a proportional bit to the x and y based on dx and dy */
685 /* give the points a speed based on direction of travel - i.e. opposite */
686 tpoint->position.dx += position->dx;
687 tpoint->position.dy += position->dy;
691 tpoint++;
693 /* find a space in the array of trail_points that is NULL or DEAD or whatever.
694 and place this one here. */
698 void draw_trail_blaze(void)
700 struct TrailPoint* tpoint;
701 /* loop through, if alive then move and draw.
702 when drawn, countdown it's timer.
703 if zero kill it! */
704 tpoint = trailPoints;
705 int n = NUM_TRAIL_POINTS;
707 while(--n)
709 if(tpoint->alive)
711 if(game_state != PAUSE_MODE)
713 tpoint->alive-=10;
714 move_point(&(tpoint->position));
716 #ifdef HAVE_LCD_COLOR
717 /* intensity = tpoint->alive/2; */
718 if(tpoint->r>0)tpoint->r-=tpoint->dec;
719 if(tpoint->g>0)tpoint->g-=tpoint->dec;
720 if(tpoint->b>0)tpoint->b-=tpoint->dec;
721 SET_FG(LCD_RGBPACK(tpoint->r, tpoint->g, tpoint->b));
722 #endif
723 rb->lcd_drawpixel(tpoint->position.x/SCALE , tpoint->position.y/SCALE);
725 tpoint++;
729 /*Check if point is within a rectangle*/
730 bool is_point_within_rectangle(struct Point* rect, struct Point* p, int size)
732 #if SHOW_COL
733 int aTLx = rect->x - size;
734 int aTLy = rect->y - size;
735 int aBRx = rect->x + size;
736 int aBRy = rect->y + size;
737 rb->lcd_drawline( aTLx/SCALE, aTLy/SCALE, aBRx/SCALE, aTLy/SCALE);
738 rb->lcd_drawline( aTLx/SCALE, aTLy/SCALE, aTLx/SCALE, aBRy/SCALE);
739 rb->lcd_drawline( aTLx/SCALE, aBRy/SCALE, aBRx/SCALE, aBRy/SCALE);
740 rb->lcd_drawline( aBRx/SCALE, aBRy/SCALE, aBRx/SCALE, aTLy/SCALE);
741 return (p->x > aTLx && p->x < aBRx && p->y > aTLy && p->y < aBRy);
742 #else
743 return (p->x > rect->x - size && p->x < rect->x + size &&
744 p->y > rect->y - size && p->y < rect->y + size);
745 #endif
748 /* Draw polygon */
749 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices)
751 int n, t1, t2, oldX, oldY;
752 struct Point *p;
753 bool bDrawAll = px < WRAP_GAP || LCD_WIDTH - px < WRAP_GAP ||
754 py < WRAP_GAP || LCD_HEIGHT - py < WRAP_GAP;
756 p = vertices;
757 p += num_vertices-1;
758 oldX = p->x/SCALE + px;
759 oldY = p->y/SCALE + py;
760 p = vertices;
761 for(n = num_vertices+1; --n;)
763 t1 = p->x/SCALE + px;
764 t2 = p->y/SCALE + py;
766 rb->lcd_drawline(oldX, oldY, t1, t2);
768 if(bDrawAll)
770 rb->lcd_drawline(oldX - LCD_WIDTH, oldY, t1 - LCD_WIDTH, t2);
771 rb->lcd_drawline(oldX + LCD_WIDTH, oldY, t1 + LCD_WIDTH, t2);
772 rb->lcd_drawline(oldX - LCD_WIDTH, oldY + LCD_HEIGHT,
773 t1 - LCD_WIDTH, t2 + LCD_HEIGHT);
774 rb->lcd_drawline(oldX + LCD_WIDTH, oldY + LCD_HEIGHT,
775 t1 + LCD_WIDTH, t2 + LCD_HEIGHT);
777 rb->lcd_drawline(oldX, oldY - LCD_HEIGHT, t1, t2 - LCD_HEIGHT);
778 rb->lcd_drawline(oldX, oldY + LCD_HEIGHT, t1, t2 + LCD_HEIGHT);
779 rb->lcd_drawline(oldX - LCD_WIDTH, oldY - LCD_HEIGHT,
780 t1 - LCD_WIDTH, t2 - LCD_HEIGHT);
781 rb->lcd_drawline(oldX + LCD_WIDTH, oldY - LCD_HEIGHT,
782 t1 + LCD_WIDTH, t2 - LCD_HEIGHT);
784 oldX = t1;
785 oldY = t2;
786 p++;
790 void animate_and_draw_explosion(struct Point* point, int num_points,
791 int xoffset, int yoffset)
793 int n;
794 for(n = num_points; --n;)
796 if(game_state != PAUSE_MODE)
798 point->x += point->dx;
799 point->y += point->dy;
801 rb->lcd_fillrect( point->x/SCALE + xoffset, point->y/SCALE + yoffset,
802 POINT_SIZE, POINT_SIZE);
803 point++;
807 /*stop movement of ship, 'cos that's what happens when you go into hyperspace.*/
808 void hyperspace(void)
810 ship.position.dx = ship.position.dy = 0;
811 ship.position.x = (rb->rand()%SCALED_WIDTH);
812 ship.position.y = (rb->rand()%SCALED_HEIGHT);
815 void initialise_enemy(void)
817 struct Point* point;
818 int n;
819 int size;
821 if(rb->rand()%100 > enemy.size_probability)
823 size = BIG_SHIP;
824 enemy.size_probability++;
825 if(enemy.size_probability < 90)
827 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
830 else
832 size = LITTLE_SHIP;
835 enemy_missile.survived = 0;
836 enemy_on_screen = true;
837 enemy.explode_countdown = 0;
838 enemy.last_time_appeared = *rb->current_tick;
839 point = enemy.vertices;
840 for(n = 0; n < NUM_ENEMY_VERTICES+NUM_ENEMY_VERTICES; n+=2)
842 point->x = enemy_vertices[n];
843 point->y = enemy_vertices[n+1];
844 point->x *= SCALE/size;
845 point->y *= SCALE/size;
846 point++;
849 if(ship.position.x >= SCALED_WIDTH/2)
851 enemy.position.dx = ENEMY_SPEED;
852 enemy.position.x = 0;
854 else
856 enemy.position.dx = -ENEMY_SPEED;
857 enemy.position.x = SCALED_WIDTH;
860 if(ship.position.y >= SCALED_HEIGHT/2)
862 enemy.position.dy = ENEMY_SPEED;
863 enemy.position.y = 0;
865 else
867 enemy.position.dy = -ENEMY_SPEED;
868 enemy.position.y = SCALED_HEIGHT;
871 enemy.position.dx *= SCALE/10;
872 enemy.position.dy *= SCALE/10;
875 void draw_and_move_enemy(void)
877 int enemy_x, enemy_y;
878 struct Point *point;
880 SET_FG(COL_ENEMY);
882 if(enemy_on_screen)
884 enemy_x = enemy.position.x/SCALE;
885 enemy_y = enemy.position.y/SCALE;
886 if(!enemy.explode_countdown)
888 point = enemy.vertices;
889 draw_polygon(enemy.vertices, enemy_x, enemy_y, NUM_ENEMY_VERTICES);
890 rb->lcd_drawline(enemy.vertices[0].x/SCALE + enemy_x,
891 enemy.vertices[0].y/SCALE + enemy_y,
892 enemy.vertices[3].x/SCALE + enemy_x,
893 enemy.vertices[3].y/SCALE + enemy_y);
895 if(game_state != PAUSE_MODE)
897 enemy.position.x += enemy.position.dx;
898 enemy.position.y += enemy.position.dy;
901 if(enemy.position.x > SCALED_WIDTH || enemy.position.x < 0)
902 enemy_on_screen = false;
904 if(enemy.position.y > SCALED_HEIGHT)
905 enemy.position.y = 0;
906 else if(enemy.position.y < 0)
907 enemy.position.y = SCALED_HEIGHT;
909 if( (rb->rand()%1000) < 10)
910 enemy.position.dy = -enemy.position.dy;
912 else
915 /* animate_and_draw_explosion(enemy.vertices, NUM_ENEMY_VERTICES,
916 enemy_x, enemy.position.y/SCALE); */
917 if(game_state != PAUSE_MODE)
919 enemy.explode_countdown--;
920 if(!enemy.explode_countdown)
921 enemy_on_screen = false;
925 else
927 if( (*rb->current_tick - enemy.last_time_appeared) > enemy.appear_timing)
928 if(rb->rand()%100 > enemy.appear_probability) initialise_enemy();
931 if(!enemy_missile.survived && game_state != GAME_OVER)
933 /*if no missile and the enemy is here and not exploding..then shoot baby!*/
934 if( !enemy.explode_countdown && enemy_on_screen &&
935 !ship.waiting_for_space && (rb->rand()%10) > 5 )
937 enemy_missile.position.x = enemy.position.x;
938 enemy_missile.position.y = enemy.position.y;
940 /*lame, needs to be sorted - it's trying to shoot at the ship*/
941 if(ABS(enemy.position.y - ship.position.y) <= 5*SCALE)
943 enemy_missile.position.dy = 0;
945 else
947 if( enemy.position.y < ship.position.y)
948 enemy_missile.position.dy = 1;
949 else
950 enemy_missile.position.dy = -1;
953 if(ABS(enemy.position.x - ship.position.x) <= 5*SCALE)
954 enemy_missile.position.dx = 0;
955 else
957 if( enemy.position.x < ship.position.x)
958 enemy_missile.position.dx = 1;
959 else
960 enemy_missile.position.dx = -1;
963 if(enemy_missile.position.dx == 0 &&
964 enemy_missile.position.dy == 0)
965 enemy_missile.position.dx = enemy_missile.position.dy = -1;
967 enemy_missile.position.dx *= SCALE;
968 enemy_missile.position.dy *= SCALE;
969 enemy_missile.survived = ENEMY_MISSILE_SURVIVAL_LENGTH;
973 else
975 rb->lcd_fillrect( enemy_missile.position.x/SCALE,
976 enemy_missile.position.y/SCALE,
977 POINT_SIZE, POINT_SIZE);
978 if(game_state != PAUSE_MODE)
980 move_point(&enemy_missile.position);
981 enemy_missile.survived--;
986 /******************
987 * Lame method of collision
988 * detection. It's checking for collision
989 * between point and a big rectangle around the asteroid...
990 *******************/
991 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point)
993 if( !is_point_within_rectangle(&asteroid->position, point,
994 asteroid->radius+4*SCALE) )
995 return false;
997 if(point_in_poly(asteroid->vertices, NUM_ASTEROID_VERTICES,
998 point->x - asteroid->position.x,
999 point->y - asteroid->position.y))
1001 switch(asteroid->type)
1003 case(SMALL):
1004 asteroid->explode_countdown = EXPLOSION_LENGTH;
1005 create_trail_blaze(ASTEROID_EXPLOSION_COLOUR, &asteroid->position);
1006 break;
1008 case(LARGE):
1009 create_asteroid(MEDIUM, asteroid->position.x,
1010 asteroid->position.y);
1011 create_asteroid(MEDIUM, asteroid->position.x,
1012 asteroid->position.y);
1013 break;
1015 case(MEDIUM):
1016 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1017 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1018 break;
1021 current_score++;
1022 if(current_score > extra_life)
1024 num_lives++;
1025 extra_life = current_score+EXTRA_LIFE;
1027 asteroid_count--;
1028 asteroid->exists = false;
1029 return true;
1031 else
1032 return false;
1035 bool is_point_within_enemy(struct Point* point)
1037 if( is_point_within_rectangle(&enemy.position, point, 7*SCALE) )
1039 current_score += 5;
1040 /*enemy_missile.survived = 0;*/
1041 enemy.explode_countdown = EXPLOSION_LENGTH;
1042 /* initialise_explosion(enemy.vertices, NUM_ENEMY_VERTICES); */
1043 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1044 return true;
1046 else
1047 return false;
1050 bool is_ship_within_asteroid(struct Asteroid* asteroid)
1052 bool hit = false;
1053 struct Point p;
1055 p.x = ship.position.x + ship.vertices[0].x;
1056 p.y = ship.position.y + ship.vertices[0].y;
1057 hit |= is_point_within_asteroid(asteroid, &p);
1059 if(!hit)
1061 p.x = ship.position.x + ship.vertices[1].x;
1062 p.y = ship.position.y + ship.vertices[1].y;
1063 hit |= is_point_within_asteroid(asteroid, &p);
1064 if(!hit)
1066 p.x = ship.position.x + ship.vertices[3].x;
1067 p.y = ship.position.y + ship.vertices[3].y;
1068 hit |= is_point_within_asteroid(asteroid, &p);
1072 return hit;
1075 void initialise_explosion(struct Point* point, int num_points)
1077 int n;
1079 point->x += point->dx;
1080 point->y += point->dy;
1081 for(n = num_points; --n;)
1083 point->dx = point->x;
1084 point->dy = point->y;
1085 point++;
1090 /* Check for collsions between the missiles and the asteroids and the ship */
1091 void check_collisions(void)
1093 int m, n;
1094 bool asteroids_onscreen = false;
1095 struct Missile* missile;
1096 struct Asteroid* asteroid;
1097 bool ship_cant_be_placed = false;
1099 asteroid = asteroids_array;
1100 m = MAX_NUM_ASTEROIDS;
1101 while(--m)
1103 /*if the asteroids exists then test missile collision:*/
1104 if(asteroid->exists)
1106 missile = missiles_array;
1107 n = MAX_NUM_MISSILES;
1108 while(--n)
1110 /*if the missiles exists:*/
1111 if(missile->survived > 0)
1113 /*has the missile hit the asteroid?*/
1114 if(is_point_within_asteroid(asteroid, &missile->position)
1115 || is_point_within_asteroid(asteroid,
1116 &missile->oldpoint))
1118 missile->survived = 0;
1119 break;
1122 missile++;
1125 /*now check collision with ship:*/
1126 if(asteroid->exists && !ship.waiting_for_space && !ship.explode_countdown)
1128 if(is_ship_within_asteroid(asteroid))
1130 /*blow up ship*/
1131 ship.explode_countdown = EXPLOSION_LENGTH;
1132 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1133 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1136 /*has the enemy missile blown something up?*/
1137 if(asteroid->exists && enemy_missile.survived)
1139 if(is_point_within_asteroid(asteroid, &enemy_missile.position))
1141 /*take that score back then:*/
1142 if(current_score > 0) current_score--;
1143 enemy_missile.survived = 0;
1146 /*if it still exists, check if ship is waiting for space:*/
1147 if(asteroid->exists && ship.waiting_for_space)
1148 ship_cant_be_placed |=
1149 is_point_within_rectangle(&ship.position,
1150 &asteroid->position,
1151 space_check_size);
1155 /*is an asteroid still exploding?*/
1156 if(asteroid->explode_countdown)
1157 asteroids_onscreen = true;
1159 asteroid++;
1162 /*now check collision between ship and enemy*/
1163 if(enemy_on_screen && !ship.waiting_for_space &&
1164 !ship.explode_countdown && !enemy.explode_countdown)
1166 /*has the enemy collided with the ship?*/
1167 if(is_point_within_enemy(&ship.position))
1169 ship.explode_countdown = EXPLOSION_LENGTH;
1170 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1171 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1172 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1175 /*Now see if the enemy has been shot at by the ships missiles:*/
1176 missile = missiles_array;
1177 n = MAX_NUM_MISSILES;
1178 while(--n)
1180 if(missile->survived > 0 &&
1181 is_point_within_enemy(&missile->position))
1183 missile->survived = 0;
1184 break;
1186 missile++;
1190 /*test collision with enemy missile and ship:*/
1191 if(!ship_cant_be_placed && enemy_missile.survived > 0 &&
1192 point_in_poly(ship.vertices, NUM_SHIP_VERTICES,
1193 enemy_missile.position.x - ship.position.x,
1194 enemy_missile.position.y - ship.position.y))
1196 ship.explode_countdown = EXPLOSION_LENGTH;
1197 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1198 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1199 enemy_missile.survived = 0;
1200 enemy_missile.position.x = enemy_missile.position.y = 0;
1203 if(!ship_cant_be_placed)
1204 ship.waiting_for_space = false;
1206 /*if all asteroids cleared then start again:*/
1207 if(asteroid_count == 0 && !enemy_on_screen && !asteroids_onscreen)
1209 current_level++;
1210 game_state = SHOW_LEVEL;
1211 enemy.appear_probability += 5;
1212 enemy.appear_timing -= 200;
1213 if( enemy.appear_probability > 100)
1214 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1215 show_level_timeout = SHOW_LEVEL_TIME;
1219 /*************************************************
1220 ** Creates a new asteroid of the given 4type (size)
1221 ** and at the given location.
1222 *************************************************/
1223 void create_asteroid(enum asteroid_type type, int x, int y)
1225 struct Asteroid* asteroid;
1226 int n;
1228 asteroid = asteroids_array;
1229 n = MAX_NUM_ASTEROIDS;
1230 while(--n)
1232 if(!asteroid->exists && !asteroid->explode_countdown)
1234 initialise_asteroid(asteroid, type);
1235 asteroid->position.x = x;
1236 asteroid->position.y = y;
1237 break;
1239 asteroid++;
1243 /* Initialise a missile */
1244 void initialise_missile(struct Missile* missile)
1246 missile->position.x = ship.position.x + ship.vertices[0].x;
1247 missile->position.y = ship.position.y + ship.vertices[0].y;
1248 missile->position.dx = (ship.vertices[0].x - ship.vertices[2].x)/2;
1249 missile->position.dy = (ship.vertices[0].y - ship.vertices[2].y)/2;
1250 missile->survived = MISSILE_SURVIVAL_LENGTH;
1251 missile->oldpoint.x = missile->position.x;
1252 missile->oldpoint.y = missile->position.y;
1255 /* Draw and Move all the missiles */
1256 void draw_and_move_missiles(void)
1258 int n;
1259 int p1x, p1y;
1260 int p2x, p2y;
1262 struct Missile* missile;
1263 missile = missiles_array;
1265 SET_FG(COL_MISSILE);
1267 n = MAX_NUM_MISSILES;
1268 while(--n)
1270 if(missile->survived)
1272 if(missile->position.dx > 0)
1274 if(missile->position.x >= missile->oldpoint.x)
1276 p1x = missile->oldpoint.x;
1277 p2x = missile->position.x;
1279 else
1281 p1x = 0;
1282 p2x = missile->position.x;
1285 else
1287 if(missile->oldpoint.x >= missile->position.x)
1289 p1x = missile->oldpoint.x;
1290 p2x = missile->position.x;
1292 else
1294 p1x = missile->oldpoint.x;
1295 p2x = LCD_WIDTH;
1299 if(missile->position.dy > 0)
1301 if(missile->position.y >= missile->oldpoint.y)
1303 p1y = missile->oldpoint.y;
1304 p2y = missile->position.y;
1306 else
1308 p1y = 0;
1309 p2y = missile->position.y;
1312 else
1314 if(missile->oldpoint.y >= missile->position.y)
1316 p1y = missile->oldpoint.y;
1317 p2y = missile->position.y;
1319 else
1321 p1y = missile->oldpoint.y;
1322 p2y = LCD_HEIGHT;
1326 rb->lcd_drawline( p1x/SCALE, p1y/SCALE, p2x/SCALE, p2y/SCALE);
1328 if(game_state != PAUSE_MODE)
1330 missile->oldpoint.x = missile->position.x;
1331 missile->oldpoint.y = missile->position.y;
1332 move_point(&missile->position);
1333 missile->survived--;
1336 missile++;
1340 void draw_lives(void)
1342 int n;
1343 int px = (LCD_WIDTH - num_lives*4 - 1);
1344 #if(LARGE_LCD)
1345 int py = (LCD_HEIGHT-6);
1346 #else
1347 int py = (LCD_HEIGHT-4);
1348 #endif
1350 SET_FG(COL_PLAYER);
1352 n = num_lives;
1353 while(--n)
1355 draw_polygon(lives_points, px, py, NUM_SHIP_VERTICES);
1356 #if(LARGE_LCD)
1357 px += 8;
1358 #else
1359 px += 6;
1360 #endif
1364 /*Fire the next missile*/
1365 void fire_missile(void)
1367 int n;
1368 struct Missile* missile;
1370 if(!ship.explode_countdown && !ship.waiting_for_space)
1372 missile = missiles_array;
1373 n = MAX_NUM_MISSILES;
1374 while(--n)
1376 if(!missile->survived)
1378 initialise_missile(missile);
1379 break;
1381 missile++;
1386 /* Initialise the passed Asteroid */
1387 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type type)
1389 int n;
1390 bool b,b2;
1391 struct Point* point;
1392 asteroid->exists = true;
1393 asteroid->type = type;
1394 asteroid->explode_countdown = 0;
1396 /*Set the radius of the asteroid:*/
1397 asteroid->radius = (int)type*SCALE;
1399 /*shall we move Clockwise and Fast*/
1400 if((rb->rand()%100)>75)
1402 asteroid->speed_cos = FAST_ROT_CW_COS;
1403 asteroid->speed_sin = FAST_ROT_CW_SIN;
1405 else if((rb->rand()%100)>75)
1407 asteroid->speed_cos = FAST_ROT_ACW_COS;
1408 asteroid->speed_sin = FAST_ROT_ACW_SIN;
1410 else if((rb->rand()%100)>75)
1412 asteroid->speed_cos = SLOW_ROT_ACW_COS;
1413 asteroid->speed_sin = SLOW_ROT_ACW_SIN;
1415 else
1417 asteroid->speed_cos = SLOW_ROT_CW_COS;
1418 asteroid->speed_sin = SLOW_ROT_CW_SIN;
1421 b = (rb->rand()%100)>66;
1422 b2 = (rb->rand()%100)>66;
1423 point = asteroid->vertices;
1424 for(n = 0; n < NUM_ASTEROID_VERTICES*2; n+=2)
1426 if(b)
1428 point->x = asteroid_one[n];
1429 point->y = asteroid_one[n+1];
1431 else if( b2 )
1433 point->x = asteroid_two[n];
1434 point->y = asteroid_two[n+1];
1436 else
1438 point->x = asteroid_three[n];
1439 point->y = asteroid_three[n+1];
1442 point->x *= asteroid->radius/6;
1443 point->y *= asteroid->radius/6;
1444 point++;
1448 asteroid->radius += 6*SCALE;
1449 if(asteroid->type == SMALL)
1450 asteroid->radius /= 3;/*2*/
1451 else if(asteroid->type == LARGE)
1452 asteroid->radius += 3*SCALE;/*2*/
1453 b = true;
1454 while(b)
1456 /*Set the position randomly:*/
1457 asteroid->position.x = (rb->rand()%SCALED_WIDTH);
1458 asteroid->position.y = (rb->rand()%SCALED_HEIGHT);
1460 asteroid->position.dx = 0;
1461 while(asteroid->position.dx == 0)
1462 asteroid->position.dx = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1464 asteroid->position.dy = 0;
1465 while(asteroid->position.dy == 0)
1466 asteroid->position.dy = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1468 asteroid->position.dx *= SCALE/10;
1469 asteroid->position.dy *= SCALE/10;
1471 b = is_point_within_rectangle(&ship.position, &asteroid->position,
1472 space_check_size);
1475 /*Now rotate the asteroid a bit, so they all look a bit different*/
1476 for(n=(rb->rand()%30) + 2;--n;)
1477 rotate_asteroid(asteroid);
1479 /*great, we've created an asteroid, don't forget to increment the total:*/
1480 asteroid_count++;
1483 /*Initialise the ship*/
1484 void initialise_ship(void)
1486 struct Point* point;
1487 struct Point* lives_point;
1488 int n;
1490 ship.position.x = CENTER_LCD_X;
1491 ship.position.y = CENTER_LCD_Y;
1492 ship.position.x *= SCALE;
1493 ship.position.y *= SCALE;
1494 ship.position.dx = ship.position.dy = 0;
1496 point = ship.vertices;
1497 lives_point = lives_points;
1498 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1500 point->x = ship_vertices[n];
1501 point->y = ship_vertices[n+1];
1502 point->x *= SCALE;
1503 point->y *= SCALE;
1504 point++;
1505 lives_point++;
1508 ship.position.dx = 0;
1509 ship.position.dy = 0;
1510 ship.explode_countdown = 0;
1512 /*grab a copy of the ships points for the lives display:*/
1513 point = ship.vertices;
1514 lives_point = lives_points;
1515 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1517 lives_point->x = point->x;
1518 lives_point->y = point->y;
1519 lives_point++;
1520 point++;
1524 void rotate_asteroid(struct Asteroid* asteroid)
1526 struct Point* point;
1527 int n;
1528 long xtemp;
1530 point = asteroid->vertices;
1531 for(n = NUM_ASTEROID_VERTICES+1; --n;)
1533 xtemp = point->x;
1534 point->x = xtemp*asteroid->speed_cos/SIN_COS_SCALE -
1535 point->y*asteroid->speed_sin/SIN_COS_SCALE;
1536 point->y = point->y*asteroid->speed_cos/SIN_COS_SCALE +
1537 xtemp*asteroid->speed_sin/SIN_COS_SCALE;
1538 point++;
1542 /*************************************************
1543 ** Draws the ship, moves the ship and creates a new
1544 ** one if it's finished exploding.
1545 **************************************************/
1546 void draw_and_move_ship(void)
1548 int nxoffset = ship.position.x/SCALE;
1549 int nyoffset = ship.position.y/SCALE;
1550 SET_FG(COL_PLAYER);
1551 if(!ship.explode_countdown)
1553 if(!ship.waiting_for_space)
1555 draw_polygon(ship.vertices, nxoffset, nyoffset, NUM_SHIP_VERTICES);
1556 if(game_state != PAUSE_MODE && game_state != GAME_OVER)
1558 move_point(&ship.position);
1562 else
1564 /* animate_and_draw_explosion(ship.vertices, NUM_SHIP_VERTICES,
1565 ship.position.x/SCALE,
1566 ship.position.y/SCALE); */
1567 if(game_state != PAUSE_MODE)
1569 ship.explode_countdown--;
1570 if(!ship.explode_countdown)
1572 num_lives--;
1573 if(!num_lives)
1575 show_game_over = SHOW_GAME_OVER_TIME;
1576 game_state = GAME_OVER;
1578 else
1580 initialise_ship();
1581 ship.waiting_for_space = true;
1588 void thrust_ship(void)
1590 if(!ship.waiting_for_space)
1592 ship.position.dx += ( ship.vertices[0].x - ship.vertices[2].x )/20;
1593 ship.position.dy += ( ship.vertices[0].y - ship.vertices[2].y )/20;
1594 /*if dx and dy are below a certain threshold, then set 'em to 0
1595 but to do this we need to ascertain if the spacehip as moved on screen
1596 for more than a certain amount. */
1598 create_trail_blaze(THRUST_COLOUR, &ship.position);
1602 /**************************************************
1603 ** Rotate the ship using the passed sin & cos values
1604 ***************************************************/
1605 void rotate_ship(int c, int s)
1607 struct Point* point;
1608 int n;
1609 double xtemp;
1611 if(!ship.waiting_for_space && !ship.explode_countdown)
1613 point = ship.vertices;
1614 for(n=NUM_SHIP_VERTICES+1;--n;)
1616 xtemp = point->x;
1617 point->x = xtemp*c/SIN_COS_SCALE - point->y*s/SIN_COS_SCALE;
1618 point->y = point->y*c/SIN_COS_SCALE + xtemp*s/SIN_COS_SCALE;
1619 point++;
1624 void drawstars()
1626 struct Point* p;
1627 int n = NUM_STARS;
1629 p = stars;
1630 SET_FG(COL_STARS);
1632 while(--n)
1634 rb->lcd_drawpixel(p->x , p->y);
1635 p++;
1639 /*************************************************
1640 ** Draw And Move all Asteroids
1641 *************************************************/
1642 void draw_and_move_asteroids(void)
1644 int n;
1645 struct Asteroid* asteroid;
1647 asteroid = asteroids_array;
1648 SET_FG(COL_ASTEROID);
1650 n = MAX_NUM_ASTEROIDS;
1651 while(--n)
1653 if(game_state != PAUSE_MODE)
1655 if(asteroid->exists)
1657 move_point(&asteroid->position);
1658 rotate_asteroid(asteroid);
1659 draw_polygon(asteroid->vertices, asteroid->position.x/SCALE,
1660 asteroid->position.y/SCALE,
1661 NUM_ASTEROID_VERTICES);
1663 else if(asteroid->explode_countdown)
1665 /* animate_and_draw_explosion(asteroid->vertices,
1666 NUM_ASTEROID_VERTICES,
1667 asteroid->position.x/SCALE,
1668 asteroid->position.y/SCALE); */
1669 asteroid->explode_countdown--;
1672 else
1674 if(asteroid->exists)
1675 draw_polygon(asteroid->vertices,
1676 asteroid->position.x/SCALE,
1677 asteroid->position.y/SCALE,
1678 NUM_ASTEROID_VERTICES);
1680 asteroid++;
1684 void create_stars(void)
1686 struct TrailPoint* tpoint;
1687 struct Point* p;
1688 int n;
1690 p = stars;
1691 n = NUM_STARS;
1692 while(--n)
1694 p->x = (rb->rand()%LCD_WIDTH);
1695 p->y = (rb->rand()%LCD_HEIGHT);
1696 p++;
1700 /* give the point a random countdown timer, so they dissapears at different
1701 times */
1702 tpoint = trailPoints;
1703 n = NUM_TRAIL_POINTS;
1704 while(--n)
1706 tpoint->alive = 0;
1707 tpoint++;
1711 /*************************************************
1712 ** Creates start_num number of new asteroids of
1713 ** full size.
1714 **************************************************/
1715 void initialise_game(int start_num)
1717 int n;
1718 asteroid_count = next_missile_count = next_thrust_count = 0;
1719 struct Asteroid* asteroid;
1720 struct Missile* missile;
1721 extra_life = EXTRA_LIFE;
1723 /*no enemy*/
1724 enemy_on_screen = 0;
1725 enemy_missile.survived = 0;
1727 /*clear asteroids*/
1728 asteroid = asteroids_array;
1729 n = MAX_NUM_ASTEROIDS;
1730 while(--n)
1732 asteroid->exists = false;
1733 asteroid++;
1736 /*make some LARGE asteroids*/
1737 for(n = 0; n < start_num; n++)
1738 initialise_asteroid(&asteroids_array[n], LARGE);
1740 /*ensure all missiles are out of action: */
1741 missile = missiles_array;
1742 n = MAX_NUM_MISSILES;
1743 while(--n)
1745 missile->survived=0;
1746 missile++;
1750 void start_attract_mode(void)
1752 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1753 enemy.appear_timing = ENEMY_APPEAR_TIMING_START;
1754 current_level = 5;
1755 num_lives = START_LIVES;
1756 current_score = 0;
1757 attract_flip_timeout = ATTRACT_FLIP_TIME;
1758 game_state = ATTRACT_MODE;
1759 if(asteroid_count < 3)
1760 initialise_game(current_level);
1763 enum plugin_status start_game(void)
1765 char s[20];
1766 char level[10];
1767 int button;
1768 int end;
1769 int CYCLETIME = 30;
1771 /*create stars once, and once only:*/
1772 create_stars();
1774 SET_BG(LCD_BLACK);
1776 while(true)
1778 /*game starts with at level 1
1779 with 1 asteroid.*/
1780 start_attract_mode();
1782 /*Main loop*/
1783 while(true)
1785 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1786 rb->lcd_clear_display();
1787 SET_FG(COL_TEXT);
1788 switch(game_state)
1790 case(ATTRACT_MODE):
1791 if(attract_flip_timeout < ATTRACT_FLIP_TIME/2)
1793 rb->lcd_putsxy(CENTER_LCD_X - 39,
1794 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4,
1795 "Fire to Start");
1796 if(!attract_flip_timeout)
1797 attract_flip_timeout = ATTRACT_FLIP_TIME;
1799 else
1801 rb->snprintf(s, sizeof(s), "Hi Score %d ", high_score);
1802 rb->lcd_putsxy(CENTER_LCD_X - 30,
1803 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, s);
1805 attract_flip_timeout--;
1806 break;
1808 case(GAME_OVER):
1809 rb->lcd_putsxy(CENTER_LCD_X - 25,
1810 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "Game Over");
1811 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1812 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1813 show_game_over--;
1814 if(!show_game_over)
1815 start_attract_mode();
1816 break;
1818 case(PAUSE_MODE):
1819 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1820 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1821 rb->lcd_putsxy(CENTER_LCD_X - 15,
1822 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "pause");
1823 draw_and_move_missiles();
1824 draw_lives();
1825 draw_and_move_ship();
1826 break;
1828 case(PLAY_MODE):
1829 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1830 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1831 draw_and_move_missiles();
1832 draw_lives();
1833 check_collisions();
1834 draw_and_move_ship();
1835 break;
1837 case(SHOW_LEVEL):
1838 show_level_timeout--;
1839 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1840 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1841 rb->snprintf(level, sizeof(level), "stage %d ", current_level);
1842 rb->lcd_putsxy(CENTER_LCD_X - 20,
1843 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, level);
1844 draw_and_move_ship();
1845 draw_lives();
1846 if(!show_level_timeout)
1848 initialise_game(current_level);
1849 game_state = PLAY_MODE;
1850 draw_lives();
1852 break;
1854 draw_trail_blaze();
1855 drawstars();
1856 draw_and_move_asteroids();
1857 draw_and_move_enemy();
1859 rb->lcd_update();
1860 button = rb->button_get(false);
1862 #ifdef HAS_BUTTON_HOLD
1863 if (rb->button_hold())
1864 game_state = PAUSE_MODE;
1865 #endif
1867 switch(button)
1869 case(AST_PAUSE):
1870 if(game_state == PLAY_MODE)
1871 game_state = PAUSE_MODE;
1872 else if(game_state == PAUSE_MODE)
1873 game_state = PLAY_MODE;
1874 break;
1876 #ifdef AST_RC_QUIT
1877 case AST_RC_QUIT:
1878 #endif
1879 case(AST_QUIT):
1880 if(game_state == ATTRACT_MODE)
1881 return PLUGIN_OK;
1882 else if(game_state == GAME_OVER)
1884 start_attract_mode();
1886 else
1888 show_game_over = SHOW_GAME_OVER_TIME;
1889 game_state = GAME_OVER;
1891 break;
1893 case (AST_LEFT_REP):
1894 case (AST_LEFT):
1895 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1896 rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN);
1897 break;
1899 case (AST_RIGHT_REP):
1900 case (AST_RIGHT):
1901 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1902 rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN);
1903 break;
1905 case (AST_THRUST_REP):
1906 case (AST_THRUST):
1907 if((game_state == PLAY_MODE || game_state == SHOW_LEVEL) && !next_thrust_count)
1909 thrust_ship();
1910 next_thrust_count = 5;
1912 break;
1914 case (AST_HYPERSPACE):
1915 if(game_state == PLAY_MODE)
1916 hyperspace();
1917 /*maybe shield if it gets too hard */
1918 break;
1920 case (AST_FIRE_REP):
1921 case (AST_FIRE):
1922 if(game_state == ATTRACT_MODE)
1924 current_level = START_LEVEL;
1925 initialise_ship();
1926 initialise_game(current_level);
1927 show_level_timeout = SHOW_LEVEL_TIME;
1928 game_state = PLAY_MODE;
1930 else if(game_state == PLAY_MODE)
1932 if(!next_missile_count)
1934 fire_missile();
1935 next_missile_count = 10;
1938 else if(game_state == PAUSE_MODE)
1940 game_state = PLAY_MODE;
1942 break;
1944 default:
1945 if (rb->default_event_handler(button)==SYS_USB_CONNECTED)
1946 return PLUGIN_USB_CONNECTED;
1947 break;
1950 if(!num_lives)
1952 if(high_score < current_score)
1953 high_score = current_score;
1954 if(!show_game_over)
1955 break;
1958 if(next_missile_count)
1959 next_missile_count--;
1961 if(next_thrust_count)
1962 next_thrust_count--;
1964 if (end > *rb->current_tick)
1965 rb->sleep(end-*rb->current_tick);
1966 else
1967 rb->yield();
1973 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1975 enum plugin_status retval;
1976 (void)(parameter);
1977 rb = api;
1979 game_state = ATTRACT_MODE;
1981 #if LCD_DEPTH > 1
1982 rb->lcd_set_backdrop(NULL);
1983 #endif
1984 /* universal font */
1985 rb->lcd_setfont(FONT_SYSFIXED);
1986 /* Turn off backlight timeout */
1987 backlight_force_on(rb); /* backlight control in lib/helper.c */
1988 iohiscore();
1989 retval = start_game();
1990 iohiscore();
1991 rb->lcd_setfont(FONT_UI);
1992 /* Turn on backlight timeout (revert to settings) */
1993 backlight_use_settings(rb); /* backlight control in lib/helper.c */
1994 return retval;