Adapt most single-file plugins to the M3 keypad and screen. It's still preliminary...
[kugel-rb.git] / apps / plugins / spacerocks.c
blob7de18e545930dee06fdda1a60c8abd75c0464c5c
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 #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 #else
204 #error No keymap defined!
205 #endif
207 #define ABS(x) ((x)>0?(x):-(x))
209 #define RES MAX(LCD_WIDTH, LCD_HEIGHT)
210 #define LARGE_LCD RES >= 200
211 #define ENEMY_MISSILE_SURVIVAL_LENGTH RES/2
212 #define ASTEROID_SPEED RES/20
213 #define MISSILE_SURVIVAL_LENGTH 40
215 #define EXTRA_LIFE 250
216 #define SCALE 5000
217 #define MISSILE_SCALE 5000
218 #define WRAP_GAP 12
219 #define EXPLOSION_LENGTH 20
220 #define SHOW_COL 0
221 #define HISCORE_FILE PLUGIN_GAMES_DIR "/astrorocks.hs"
222 #define POINT_SIZE 2
223 #define MAX_NUM_ASTEROIDS 25
224 #define MAX_NUM_MISSILES 6
225 #define ENEMY_BIG_PROBABILITY_START 10
226 #define ENEMY_APPEAR_PROBABILITY_START 35
227 #define ENEMY_APPEAR_TIMING_START 1800
228 #define LITTLE_SHIP 2
229 #define BIG_SHIP 1
230 #define SHOW_GAME_OVER_TIME 100
231 #define SHOW_LEVEL_TIME 50
232 #define START_LIVES 3
233 #define START_LEVEL 1
234 #define NUM_ASTEROID_VERTICES 10
235 #define NUM_SHIP_VERTICES 4
236 #define NUM_ENEMY_VERTICES 6
237 #define MAX_LEVEL MAX_NUM_ASTEROIDS
238 #define ENEMY_SPEED 4
239 #define ENEMY_START_X 0
240 #define ENEMY_START_Y 0
241 #define SIZE_ENEMY_COLLISION 5*SCALE
242 #define ATTRACT_FLIP_TIME 100
243 #define NUM_STARS 50
244 #define NUM_TRAIL_POINTS 70
245 #define NUM_ROTATIONS 16
247 #define SIN_COS_SCALE 10000
249 #define FAST_ROT_CW_SIN 873
250 #define FAST_ROT_CW_COS 9963
251 #define FAST_ROT_ACW_SIN -873
252 #define FAST_ROT_ACW_COS 9963
254 #define MEDIUM_ROT_CW_SIN 350
255 #define MEDIUM_ROT_CW_COS 9994
256 #define MEDIUM_ROT_ACW_SIN -350
257 #define MEDIUM_ROT_ACW_COS 9994
259 #define SLOW_ROT_CW_SIN 350
260 #define SLOW_ROT_CW_COS 9994
261 #define SLOW_ROT_ACW_SIN - 350
262 #define SLOW_ROT_ACW_COS 9994
264 #ifdef HAVE_LCD_COLOR
265 #define SHIP_ROT_CW_SIN 2419
266 #define SHIP_ROT_CW_COS 9702
267 #define SHIP_ROT_ACW_SIN -2419
268 #define SHIP_ROT_ACW_COS 9702
269 #else
270 #define SHIP_ROT_CW_SIN 3827
271 #define SHIP_ROT_CW_COS 9239
272 #define SHIP_ROT_ACW_SIN -3827
273 #define SHIP_ROT_ACW_COS 9239
274 #endif
277 #define SCALED_WIDTH (LCD_WIDTH*SCALE)
278 #define SCALED_HEIGHT (LCD_HEIGHT*SCALE)
279 #define CENTER_LCD_X (LCD_WIDTH/2)
280 #define CENTER_LCD_Y (LCD_HEIGHT/2)
282 #define SHIP_EXPLOSION_COLOUR 1
283 #define ASTEROID_EXPLOSION_COLOUR 2
284 #define ENEMY_EXPLOSION_COLOUR 3
285 #define THRUST_COLOUR 4
287 #define ASTEROID_R 230
288 #define ASTEROID_G 200
289 #define ASTEROID_B 100
290 #define SHIP_R 255
291 #define SHIP_G 255
292 #define SHIP_B 255
293 #define ENEMY_R 50
294 #define ENEMY_G 220
295 #define ENEMY_B 50
296 #define THRUST_R 200
297 #define THRUST_G 200
298 #define THRUST_B 0
300 #ifdef HAVE_LCD_COLOR
301 #define COL_MISSILE LCD_RGBPACK(200,0,0)
302 #define COL_PLAYER LCD_RGBPACK(200,200,200)
303 #define COL_STARS LCD_WHITE
304 #define COL_ASTEROID LCD_RGBPACK(ASTEROID_R,ASTEROID_G,ASTEROID_B)
305 #define COL_TEXT LCD_RGBPACK(200,200,255)
306 #define COL_ENEMY LCD_RGBPACK(ENEMY_R,ENEMY_G,ENEMY_B)
307 #define SET_FG rb->lcd_set_foreground
308 #define SET_BG rb->lcd_set_background
309 #else
310 #define SET_FG(x)
311 #define SET_BG(x)
312 #endif
314 /* The array of points that make up an asteroid */
315 static const short asteroid_one[NUM_ASTEROID_VERTICES*2] =
317 -2, -12,
318 4, -8,
319 8, -14,
320 16, -5,
321 14, 0,
322 20, 2,
323 12, 14,
324 -4, 14,
325 -10, 6,
326 -10, -8
329 /* The array of points that make up an asteroid */
330 static const short asteroid_two[NUM_ASTEROID_VERTICES*2] =
332 -2, -12,
333 4, -16,
334 6, -14,
335 16, -8,
336 14, 0,
337 20, 2,
338 12, 14,
339 -4, 14,
340 -10, 6,
341 -10, -8
344 /* The array of points that make up an asteroid */
345 static const short asteroid_three[NUM_ASTEROID_VERTICES*2] =
347 -2, -12,
348 4, -16,
349 6, -14,
350 2, -8,
351 14, 0,
352 20, 2,
353 12, 14,
354 -4, 14,
355 -16, 6,
356 -10, -8
359 /* The array od points the make up the ship */
360 static const short ship_vertices[NUM_SHIP_VERTICES*2] =
362 #if(LARGE_LCD)
363 0,-6,
364 4, 6,
365 0, 2,
366 -4, 6
367 #else
368 0,-4,
369 3, 4,
370 0, 1,
371 -3, 4
372 #endif
375 /* The array of points the make up the bad spaceship */
376 static const short enemy_vertices[NUM_ENEMY_VERTICES*2] =
378 #if(LARGE_LCD)
379 -8, 0,
380 -4, 4,
381 4, 4,
382 8, 0,
383 4, -4,
384 -4, -4
385 #else
386 -5, 0,
387 -2, 2,
388 2, 2,
389 5, 0,
390 2, -2,
391 -2, -2
392 #endif
396 enum asteroid_type
398 #if(LARGE_LCD)
399 SMALL = 2,
400 MEDIUM = 4,
401 LARGE = 6,
402 #else
403 SMALL = 1,
404 MEDIUM = 2,
405 LARGE = 3,
406 #endif
410 enum game_state
412 GAME_OVER,
413 ATTRACT_MODE,
414 SHOW_LEVEL,
415 PLAY_MODE,
416 PAUSE_MODE
419 struct Point
421 int x;
422 int y;
423 int dx;
424 int dy;
427 struct TrailPoint
429 int alive;
430 struct Point position;
431 short r;
432 short g;
433 short b;
434 short dec;
437 /* Asteroid structure, contains an array of points */
438 struct Asteroid
440 enum asteroid_type type;
441 bool exists;
442 struct Point position;
443 struct Point vertices[NUM_ASTEROID_VERTICES];
444 int radius;
445 long speed_cos;
446 long speed_sin;
447 int explode_countdown;
450 struct Ship
452 struct Point vertices[NUM_SHIP_VERTICES];
453 struct Point position;
454 bool waiting_for_space;
455 int explode_countdown;
458 struct Enemy
460 struct Point vertices[NUM_ENEMY_VERTICES];
461 struct Point position;
462 int explode_countdown;
463 long last_time_appeared;
464 short size_probability;
465 short appear_probability;
466 short appear_timing;
469 struct Missile
471 struct Point position;
472 struct Point oldpoint;
473 int survived;
476 static enum game_state game_state;
477 static int asteroid_count;
478 static int next_missile_count;
479 static int next_thrust_count;
480 static int num_lives;
481 static int extra_life;
482 static int show_level_timeout;
483 static int attract_flip_timeout;
484 static int show_game_over;
485 static int current_level;
486 static int current_score;
487 static int high_score;
488 static int space_check_size = 30*SCALE;
490 static bool enemy_on_screen;
491 static char phscore[30];
492 static struct Ship ship;
493 static struct Point stars[NUM_STARS];
494 static struct Asteroid asteroids_array[MAX_NUM_ASTEROIDS];
495 static struct Missile missiles_array[MAX_NUM_MISSILES];
496 static struct Missile enemy_missile;
497 static struct Enemy enemy;
498 static struct Point lives_points[NUM_SHIP_VERTICES];
499 static struct TrailPoint trailPoints[NUM_TRAIL_POINTS];
501 void draw_and_move_asteroids(void);
502 void initialise_game(int nStartNum);
504 bool is_asteroid_near_ship(struct Asteroid* asteroid);
505 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point);
507 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type eType);
508 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices);
509 void rotate_asteroid(struct Asteroid* asteroid);
510 void create_asteroid(enum asteroid_type type, int x, int y);
511 void create_stars(void);
513 void initialise_ship(void);
514 void draw_and_move_ship(void);
515 void rotate_ship(int s, int c);
516 void thrust_ship(void);
518 void initialise_missile(struct Missile* missile);
519 void draw_and_move_missiles(void);
520 void fire_missile(void);
522 void animate_and_draw_explosion(struct Point* point, int num_points, int xoffset, int yoffset);
523 void initialise_explosion(struct Point* point, int num_points);
525 void move_point(struct Point* point);
526 void hyperspace(void);
527 void check_collisions(void);
528 void initialise_enemy(void);
529 void draw_and_move_enemy(void);
530 void draw_lives(void);
531 void drawstars(void);
532 bool is_ship_within_asteroid(struct Asteroid* asteroid);
536 /*Hi-Score reading and writing to file - this needs moving to the hi-score plugin lib as
537 a 3rd function */
538 void iohiscore(void)
540 int fd;
541 int compare;
543 /* clear the buffer we're about to load the highscore data into */
544 rb->memset(phscore, 0, sizeof(phscore));
546 fd = rb->open(HISCORE_FILE,O_RDWR | O_CREAT);
547 if(fd < 0)
549 rb->splash(HZ, "Highscore file read error");
550 return;
553 /* highscore used to %d, is now %d\n
554 Deal with no file or bad file */
555 rb->read(fd,phscore, sizeof(phscore));
557 compare = rb->atoi(phscore);
559 if(high_score > compare)
561 rb->lseek(fd,0,SEEK_SET);
562 rb->fdprintf(fd, "%d\n", high_score);
564 else
565 high_score = compare;
567 rb->close(fd);
570 bool point_in_poly(struct Point* _point, int num_vertices, int x, int y)
572 struct Point* pi;
573 struct Point* pj;
574 int n;
575 bool c = false;
577 pi = _point;
578 pj = _point;
579 pj += num_vertices-1;
581 n = num_vertices;
582 while(n--)
584 if((((pi->y <= y) && (y < pj->y)) || ((pj->y <= y) && (y < pi->y))) &&
585 (x < (pj->x - pi->x) * (y - pi->y) / (pj->y - pi->y) + pi->x))
586 c = !c;
588 if(n == num_vertices - 1)
589 pj = _point;
590 else
591 pj++;
593 pi++;
596 return c;
599 void move_point(struct Point* point)
601 point->x += point->dx;
602 point->y += point->dy;
604 /*check bounds on the x-axis:*/
605 if(point->x >= SCALED_WIDTH)
606 point->x = 0;
607 else if(point->x <= 0)
608 point->x = SCALED_WIDTH;
610 /*Check bounds on the y-axis:*/
611 if(point->y >= SCALED_HEIGHT)
612 point->y = 0;
613 else if(point->y <= 0)
614 point->y = SCALED_HEIGHT;
617 void create_trail(struct TrailPoint* tpoint)
619 tpoint->position.dx = -( ship.vertices[0].x - ship.vertices[2].x )/10;
620 tpoint->position.dy = -( ship.vertices[0].y - ship.vertices[2].y )/10;
623 void create_explosion_trail(struct TrailPoint* tpoint)
625 tpoint->position.dx = (rb->rand()%5050)-2500;
626 tpoint->position.dy = (rb->rand()%5050)-2500;
629 void create_trail_blaze(int colour, struct Point* position)
631 int numtoadd;
632 struct TrailPoint* tpoint;
633 int n;
634 int xadd,yadd;
635 if(colour != SHIP_EXPLOSION_COLOUR)
637 numtoadd = NUM_TRAIL_POINTS/5;
638 xadd = position->x;
639 yadd = position->y;
641 else
643 numtoadd = NUM_TRAIL_POINTS/8;
644 xadd = ship.position.x;
645 yadd = ship.position.y;
648 /* give the point a random countdown timer, so they dissapears at different times */
649 tpoint = trailPoints;
650 n = NUM_TRAIL_POINTS;
651 while(--n)
653 if(tpoint->alive <= 0 && numtoadd)
655 numtoadd--;
656 /* take a random x point anywhere between bottom two points of ship. */
657 /* ship.position.x; */
658 tpoint->position.x = (ship.vertices[2].x + (rb->rand()%18000)-9000) + position->x;
659 tpoint->position.y = (ship.vertices[2].y + (rb->rand()%18000)-9000) + position->y;
661 switch(colour)
663 case SHIP_EXPLOSION_COLOUR:
664 tpoint->r = 255;
665 tpoint->g = 255;
666 tpoint->b = 255;
667 create_explosion_trail(tpoint);
668 tpoint->alive = 510;
669 tpoint->dec = 2;
670 break;
671 case ASTEROID_EXPLOSION_COLOUR:
672 tpoint->r = ASTEROID_R;
673 tpoint->g = ASTEROID_G;
674 tpoint->b = ASTEROID_B;
675 create_explosion_trail(tpoint);
676 tpoint->alive = 510;
677 tpoint->dec = 2;
678 break;
679 case ENEMY_EXPLOSION_COLOUR:
680 tpoint->r = ENEMY_R;
681 tpoint->g = ENEMY_G;
682 tpoint->b = ENEMY_B;
683 create_explosion_trail(tpoint);
684 tpoint->alive = 510;
685 tpoint->dec = 2;
686 break;
687 case THRUST_COLOUR:
688 tpoint->r = THRUST_R;
689 tpoint->g = THRUST_G;
690 tpoint->b = THRUST_B;
691 create_trail(tpoint);
692 tpoint->alive = 175;
693 tpoint->dec = 4;
694 break;
696 /* add a proportional bit to the x and y based on dx and dy */
698 /* give the points a speed based on direction of travel - i.e. opposite */
699 tpoint->position.dx += position->dx;
700 tpoint->position.dy += position->dy;
704 tpoint++;
706 /* find a space in the array of trail_points that is NULL or DEAD or whatever.
707 and place this one here. */
711 void draw_trail_blaze(void)
713 struct TrailPoint* tpoint;
714 /* loop through, if alive then move and draw.
715 when drawn, countdown it's timer.
716 if zero kill it! */
717 tpoint = trailPoints;
718 int n = NUM_TRAIL_POINTS;
720 while(--n)
722 if(tpoint->alive)
724 if(game_state != PAUSE_MODE)
726 tpoint->alive-=10;
727 move_point(&(tpoint->position));
729 #ifdef HAVE_LCD_COLOR
730 /* intensity = tpoint->alive/2; */
731 if(tpoint->r>0)tpoint->r-=tpoint->dec;
732 if(tpoint->g>0)tpoint->g-=tpoint->dec;
733 if(tpoint->b>0)tpoint->b-=tpoint->dec;
734 SET_FG(LCD_RGBPACK(tpoint->r, tpoint->g, tpoint->b));
735 #endif
736 rb->lcd_drawpixel(tpoint->position.x/SCALE , tpoint->position.y/SCALE);
738 tpoint++;
742 /*Check if point is within a rectangle*/
743 bool is_point_within_rectangle(struct Point* rect, struct Point* p, int size)
745 #if SHOW_COL
746 int aTLx = rect->x - size;
747 int aTLy = rect->y - size;
748 int aBRx = rect->x + size;
749 int aBRy = rect->y + size;
750 rb->lcd_drawline( aTLx/SCALE, aTLy/SCALE, aBRx/SCALE, aTLy/SCALE);
751 rb->lcd_drawline( aTLx/SCALE, aTLy/SCALE, aTLx/SCALE, aBRy/SCALE);
752 rb->lcd_drawline( aTLx/SCALE, aBRy/SCALE, aBRx/SCALE, aBRy/SCALE);
753 rb->lcd_drawline( aBRx/SCALE, aBRy/SCALE, aBRx/SCALE, aTLy/SCALE);
754 return (p->x > aTLx && p->x < aBRx && p->y > aTLy && p->y < aBRy);
755 #else
756 return (p->x > rect->x - size && p->x < rect->x + size &&
757 p->y > rect->y - size && p->y < rect->y + size);
758 #endif
761 /* Draw polygon */
762 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices)
764 int n, t1, t2, oldX, oldY;
765 struct Point *p;
766 bool bDrawAll = px < WRAP_GAP || LCD_WIDTH - px < WRAP_GAP ||
767 py < WRAP_GAP || LCD_HEIGHT - py < WRAP_GAP;
769 p = vertices;
770 p += num_vertices-1;
771 oldX = p->x/SCALE + px;
772 oldY = p->y/SCALE + py;
773 p = vertices;
774 for(n = num_vertices+1; --n;)
776 t1 = p->x/SCALE + px;
777 t2 = p->y/SCALE + py;
779 rb->lcd_drawline(oldX, oldY, t1, t2);
781 if(bDrawAll)
783 rb->lcd_drawline(oldX - LCD_WIDTH, oldY, t1 - LCD_WIDTH, t2);
784 rb->lcd_drawline(oldX + LCD_WIDTH, oldY, t1 + LCD_WIDTH, t2);
785 rb->lcd_drawline(oldX - LCD_WIDTH, oldY + LCD_HEIGHT,
786 t1 - LCD_WIDTH, t2 + LCD_HEIGHT);
787 rb->lcd_drawline(oldX + LCD_WIDTH, oldY + LCD_HEIGHT,
788 t1 + LCD_WIDTH, t2 + LCD_HEIGHT);
790 rb->lcd_drawline(oldX, oldY - LCD_HEIGHT, t1, t2 - LCD_HEIGHT);
791 rb->lcd_drawline(oldX, oldY + LCD_HEIGHT, t1, t2 + LCD_HEIGHT);
792 rb->lcd_drawline(oldX - LCD_WIDTH, oldY - LCD_HEIGHT,
793 t1 - LCD_WIDTH, t2 - LCD_HEIGHT);
794 rb->lcd_drawline(oldX + LCD_WIDTH, oldY - LCD_HEIGHT,
795 t1 + LCD_WIDTH, t2 - LCD_HEIGHT);
797 oldX = t1;
798 oldY = t2;
799 p++;
803 void animate_and_draw_explosion(struct Point* point, int num_points,
804 int xoffset, int yoffset)
806 int n;
807 for(n = num_points; --n;)
809 if(game_state != PAUSE_MODE)
811 point->x += point->dx;
812 point->y += point->dy;
814 rb->lcd_fillrect( point->x/SCALE + xoffset, point->y/SCALE + yoffset,
815 POINT_SIZE, POINT_SIZE);
816 point++;
820 /*stop movement of ship, 'cos that's what happens when you go into hyperspace.*/
821 void hyperspace(void)
823 ship.position.dx = ship.position.dy = 0;
824 ship.position.x = (rb->rand()%SCALED_WIDTH);
825 ship.position.y = (rb->rand()%SCALED_HEIGHT);
828 void initialise_enemy(void)
830 struct Point* point;
831 int n;
832 int size;
834 if(rb->rand()%100 > enemy.size_probability)
836 size = BIG_SHIP;
837 enemy.size_probability++;
838 if(enemy.size_probability < 90)
840 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
843 else
845 size = LITTLE_SHIP;
848 enemy_missile.survived = 0;
849 enemy_on_screen = true;
850 enemy.explode_countdown = 0;
851 enemy.last_time_appeared = *rb->current_tick;
852 point = enemy.vertices;
853 for(n = 0; n < NUM_ENEMY_VERTICES+NUM_ENEMY_VERTICES; n+=2)
855 point->x = enemy_vertices[n];
856 point->y = enemy_vertices[n+1];
857 point->x *= SCALE/size;
858 point->y *= SCALE/size;
859 point++;
862 if(ship.position.x >= SCALED_WIDTH/2)
864 enemy.position.dx = ENEMY_SPEED;
865 enemy.position.x = 0;
867 else
869 enemy.position.dx = -ENEMY_SPEED;
870 enemy.position.x = SCALED_WIDTH;
873 if(ship.position.y >= SCALED_HEIGHT/2)
875 enemy.position.dy = ENEMY_SPEED;
876 enemy.position.y = 0;
878 else
880 enemy.position.dy = -ENEMY_SPEED;
881 enemy.position.y = SCALED_HEIGHT;
884 enemy.position.dx *= SCALE/10;
885 enemy.position.dy *= SCALE/10;
888 void draw_and_move_enemy(void)
890 int enemy_x, enemy_y;
891 struct Point *point;
893 SET_FG(COL_ENEMY);
895 if(enemy_on_screen)
897 enemy_x = enemy.position.x/SCALE;
898 enemy_y = enemy.position.y/SCALE;
899 if(!enemy.explode_countdown)
901 point = enemy.vertices;
902 draw_polygon(enemy.vertices, enemy_x, enemy_y, NUM_ENEMY_VERTICES);
903 rb->lcd_drawline(enemy.vertices[0].x/SCALE + enemy_x,
904 enemy.vertices[0].y/SCALE + enemy_y,
905 enemy.vertices[3].x/SCALE + enemy_x,
906 enemy.vertices[3].y/SCALE + enemy_y);
908 if(game_state != PAUSE_MODE)
910 enemy.position.x += enemy.position.dx;
911 enemy.position.y += enemy.position.dy;
914 if(enemy.position.x > SCALED_WIDTH || enemy.position.x < 0)
915 enemy_on_screen = false;
917 if(enemy.position.y > SCALED_HEIGHT)
918 enemy.position.y = 0;
919 else if(enemy.position.y < 0)
920 enemy.position.y = SCALED_HEIGHT;
922 if( (rb->rand()%1000) < 10)
923 enemy.position.dy = -enemy.position.dy;
925 else
928 /* animate_and_draw_explosion(enemy.vertices, NUM_ENEMY_VERTICES,
929 enemy_x, enemy.position.y/SCALE); */
930 if(game_state != PAUSE_MODE)
932 enemy.explode_countdown--;
933 if(!enemy.explode_countdown)
934 enemy_on_screen = false;
938 else
940 if( (*rb->current_tick - enemy.last_time_appeared) > enemy.appear_timing)
941 if(rb->rand()%100 > enemy.appear_probability) initialise_enemy();
944 if(!enemy_missile.survived && game_state != GAME_OVER)
946 /*if no missile and the enemy is here and not exploding..then shoot baby!*/
947 if( !enemy.explode_countdown && enemy_on_screen &&
948 !ship.waiting_for_space && (rb->rand()%10) > 5 )
950 enemy_missile.position.x = enemy.position.x;
951 enemy_missile.position.y = enemy.position.y;
953 /*lame, needs to be sorted - it's trying to shoot at the ship*/
954 if(ABS(enemy.position.y - ship.position.y) <= 5*SCALE)
956 enemy_missile.position.dy = 0;
958 else
960 if( enemy.position.y < ship.position.y)
961 enemy_missile.position.dy = 1;
962 else
963 enemy_missile.position.dy = -1;
966 if(ABS(enemy.position.x - ship.position.x) <= 5*SCALE)
967 enemy_missile.position.dx = 0;
968 else
970 if( enemy.position.x < ship.position.x)
971 enemy_missile.position.dx = 1;
972 else
973 enemy_missile.position.dx = -1;
976 if(enemy_missile.position.dx == 0 &&
977 enemy_missile.position.dy == 0)
978 enemy_missile.position.dx = enemy_missile.position.dy = -1;
980 enemy_missile.position.dx *= SCALE;
981 enemy_missile.position.dy *= SCALE;
982 enemy_missile.survived = ENEMY_MISSILE_SURVIVAL_LENGTH;
986 else
988 rb->lcd_fillrect( enemy_missile.position.x/SCALE,
989 enemy_missile.position.y/SCALE,
990 POINT_SIZE, POINT_SIZE);
991 if(game_state != PAUSE_MODE)
993 move_point(&enemy_missile.position);
994 enemy_missile.survived--;
999 /******************
1000 * Lame method of collision
1001 * detection. It's checking for collision
1002 * between point and a big rectangle around the asteroid...
1003 *******************/
1004 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point)
1006 if( !is_point_within_rectangle(&asteroid->position, point,
1007 asteroid->radius+4*SCALE) )
1008 return false;
1010 if(point_in_poly(asteroid->vertices, NUM_ASTEROID_VERTICES,
1011 point->x - asteroid->position.x,
1012 point->y - asteroid->position.y))
1014 switch(asteroid->type)
1016 case(SMALL):
1017 asteroid->explode_countdown = EXPLOSION_LENGTH;
1018 create_trail_blaze(ASTEROID_EXPLOSION_COLOUR, &asteroid->position);
1019 break;
1021 case(LARGE):
1022 create_asteroid(MEDIUM, asteroid->position.x,
1023 asteroid->position.y);
1024 create_asteroid(MEDIUM, asteroid->position.x,
1025 asteroid->position.y);
1026 break;
1028 case(MEDIUM):
1029 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1030 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1031 break;
1034 current_score++;
1035 if(current_score > extra_life)
1037 num_lives++;
1038 extra_life = current_score+EXTRA_LIFE;
1040 asteroid_count--;
1041 asteroid->exists = false;
1042 return true;
1044 else
1045 return false;
1048 bool is_point_within_enemy(struct Point* point)
1050 if( is_point_within_rectangle(&enemy.position, point, 7*SCALE) )
1052 current_score += 5;
1053 /*enemy_missile.survived = 0;*/
1054 enemy.explode_countdown = EXPLOSION_LENGTH;
1055 /* initialise_explosion(enemy.vertices, NUM_ENEMY_VERTICES); */
1056 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1057 return true;
1059 else
1060 return false;
1063 bool is_ship_within_asteroid(struct Asteroid* asteroid)
1065 bool hit = false;
1066 struct Point p;
1068 p.x = ship.position.x + ship.vertices[0].x;
1069 p.y = ship.position.y + ship.vertices[0].y;
1070 hit |= is_point_within_asteroid(asteroid, &p);
1072 if(!hit)
1074 p.x = ship.position.x + ship.vertices[1].x;
1075 p.y = ship.position.y + ship.vertices[1].y;
1076 hit |= is_point_within_asteroid(asteroid, &p);
1077 if(!hit)
1079 p.x = ship.position.x + ship.vertices[3].x;
1080 p.y = ship.position.y + ship.vertices[3].y;
1081 hit |= is_point_within_asteroid(asteroid, &p);
1085 return hit;
1088 void initialise_explosion(struct Point* point, int num_points)
1090 int n;
1092 point->x += point->dx;
1093 point->y += point->dy;
1094 for(n = num_points; --n;)
1096 point->dx = point->x;
1097 point->dy = point->y;
1098 point++;
1103 /* Check for collsions between the missiles and the asteroids and the ship */
1104 void check_collisions(void)
1106 int m, n;
1107 bool asteroids_onscreen = false;
1108 struct Missile* missile;
1109 struct Asteroid* asteroid;
1110 bool ship_cant_be_placed = false;
1112 asteroid = asteroids_array;
1113 m = MAX_NUM_ASTEROIDS;
1114 while(--m)
1116 /*if the asteroids exists then test missile collision:*/
1117 if(asteroid->exists)
1119 missile = missiles_array;
1120 n = MAX_NUM_MISSILES;
1121 while(--n)
1123 /*if the missiles exists:*/
1124 if(missile->survived > 0)
1126 /*has the missile hit the asteroid?*/
1127 if(is_point_within_asteroid(asteroid, &missile->position)
1128 || is_point_within_asteroid(asteroid,
1129 &missile->oldpoint))
1131 missile->survived = 0;
1132 break;
1135 missile++;
1138 /*now check collision with ship:*/
1139 if(asteroid->exists && !ship.waiting_for_space && !ship.explode_countdown)
1141 if(is_ship_within_asteroid(asteroid))
1143 /*blow up ship*/
1144 ship.explode_countdown = EXPLOSION_LENGTH;
1145 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1146 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1149 /*has the enemy missile blown something up?*/
1150 if(asteroid->exists && enemy_missile.survived)
1152 if(is_point_within_asteroid(asteroid, &enemy_missile.position))
1154 /*take that score back then:*/
1155 if(current_score > 0) current_score--;
1156 enemy_missile.survived = 0;
1159 /*if it still exists, check if ship is waiting for space:*/
1160 if(asteroid->exists && ship.waiting_for_space)
1161 ship_cant_be_placed |=
1162 is_point_within_rectangle(&ship.position,
1163 &asteroid->position,
1164 space_check_size);
1168 /*is an asteroid still exploding?*/
1169 if(asteroid->explode_countdown)
1170 asteroids_onscreen = true;
1172 asteroid++;
1175 /*now check collision between ship and enemy*/
1176 if(enemy_on_screen && !ship.waiting_for_space &&
1177 !ship.explode_countdown && !enemy.explode_countdown)
1179 /*has the enemy collided with the ship?*/
1180 if(is_point_within_enemy(&ship.position))
1182 ship.explode_countdown = EXPLOSION_LENGTH;
1183 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1184 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1185 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1188 /*Now see if the enemy has been shot at by the ships missiles:*/
1189 missile = missiles_array;
1190 n = MAX_NUM_MISSILES;
1191 while(--n)
1193 if(missile->survived > 0 &&
1194 is_point_within_enemy(&missile->position))
1196 missile->survived = 0;
1197 break;
1199 missile++;
1203 /*test collision with enemy missile and ship:*/
1204 if(!ship_cant_be_placed && enemy_missile.survived > 0 &&
1205 point_in_poly(ship.vertices, NUM_SHIP_VERTICES,
1206 enemy_missile.position.x - ship.position.x,
1207 enemy_missile.position.y - ship.position.y))
1209 ship.explode_countdown = EXPLOSION_LENGTH;
1210 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1211 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1212 enemy_missile.survived = 0;
1213 enemy_missile.position.x = enemy_missile.position.y = 0;
1216 if(!ship_cant_be_placed)
1217 ship.waiting_for_space = false;
1219 /*if all asteroids cleared then start again:*/
1220 if(asteroid_count == 0 && !enemy_on_screen && !asteroids_onscreen)
1222 current_level++;
1223 game_state = SHOW_LEVEL;
1224 enemy.appear_probability += 5;
1225 enemy.appear_timing -= 200;
1226 if( enemy.appear_probability > 100)
1227 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1228 show_level_timeout = SHOW_LEVEL_TIME;
1232 /*************************************************
1233 ** Creates a new asteroid of the given 4type (size)
1234 ** and at the given location.
1235 *************************************************/
1236 void create_asteroid(enum asteroid_type type, int x, int y)
1238 struct Asteroid* asteroid;
1239 int n;
1241 asteroid = asteroids_array;
1242 n = MAX_NUM_ASTEROIDS;
1243 while(--n)
1245 if(!asteroid->exists && !asteroid->explode_countdown)
1247 initialise_asteroid(asteroid, type);
1248 asteroid->position.x = x;
1249 asteroid->position.y = y;
1250 break;
1252 asteroid++;
1256 /* Initialise a missile */
1257 void initialise_missile(struct Missile* missile)
1259 missile->position.x = ship.position.x + ship.vertices[0].x;
1260 missile->position.y = ship.position.y + ship.vertices[0].y;
1261 missile->position.dx = (ship.vertices[0].x - ship.vertices[2].x)/2;
1262 missile->position.dy = (ship.vertices[0].y - ship.vertices[2].y)/2;
1263 missile->survived = MISSILE_SURVIVAL_LENGTH;
1264 missile->oldpoint.x = missile->position.x;
1265 missile->oldpoint.y = missile->position.y;
1268 /* Draw and Move all the missiles */
1269 void draw_and_move_missiles(void)
1271 int n;
1272 int p1x, p1y;
1273 int p2x, p2y;
1275 struct Missile* missile;
1276 missile = missiles_array;
1278 SET_FG(COL_MISSILE);
1280 n = MAX_NUM_MISSILES;
1281 while(--n)
1283 if(missile->survived)
1285 if(missile->position.dx > 0)
1287 if(missile->position.x >= missile->oldpoint.x)
1289 p1x = missile->oldpoint.x;
1290 p2x = missile->position.x;
1292 else
1294 p1x = 0;
1295 p2x = missile->position.x;
1298 else
1300 if(missile->oldpoint.x >= missile->position.x)
1302 p1x = missile->oldpoint.x;
1303 p2x = missile->position.x;
1305 else
1307 p1x = missile->oldpoint.x;
1308 p2x = LCD_WIDTH;
1312 if(missile->position.dy > 0)
1314 if(missile->position.y >= missile->oldpoint.y)
1316 p1y = missile->oldpoint.y;
1317 p2y = missile->position.y;
1319 else
1321 p1y = 0;
1322 p2y = missile->position.y;
1325 else
1327 if(missile->oldpoint.y >= missile->position.y)
1329 p1y = missile->oldpoint.y;
1330 p2y = missile->position.y;
1332 else
1334 p1y = missile->oldpoint.y;
1335 p2y = LCD_HEIGHT;
1339 rb->lcd_drawline( p1x/SCALE, p1y/SCALE, p2x/SCALE, p2y/SCALE);
1341 if(game_state != PAUSE_MODE)
1343 missile->oldpoint.x = missile->position.x;
1344 missile->oldpoint.y = missile->position.y;
1345 move_point(&missile->position);
1346 missile->survived--;
1349 missile++;
1353 void draw_lives(void)
1355 int n;
1356 int px = (LCD_WIDTH - num_lives*4 - 1);
1357 #if(LARGE_LCD)
1358 int py = (LCD_HEIGHT-6);
1359 #else
1360 int py = (LCD_HEIGHT-4);
1361 #endif
1363 SET_FG(COL_PLAYER);
1365 n = num_lives;
1366 while(--n)
1368 draw_polygon(lives_points, px, py, NUM_SHIP_VERTICES);
1369 #if(LARGE_LCD)
1370 px += 8;
1371 #else
1372 px += 6;
1373 #endif
1377 /*Fire the next missile*/
1378 void fire_missile(void)
1380 int n;
1381 struct Missile* missile;
1383 if(!ship.explode_countdown && !ship.waiting_for_space)
1385 missile = missiles_array;
1386 n = MAX_NUM_MISSILES;
1387 while(--n)
1389 if(!missile->survived)
1391 initialise_missile(missile);
1392 break;
1394 missile++;
1399 /* Initialise the passed Asteroid */
1400 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type type)
1402 int n;
1403 bool b,b2;
1404 struct Point* point;
1405 asteroid->exists = true;
1406 asteroid->type = type;
1407 asteroid->explode_countdown = 0;
1409 /*Set the radius of the asteroid:*/
1410 asteroid->radius = (int)type*SCALE;
1412 /*shall we move Clockwise and Fast*/
1413 if((rb->rand()%100)>75)
1415 asteroid->speed_cos = FAST_ROT_CW_COS;
1416 asteroid->speed_sin = FAST_ROT_CW_SIN;
1418 else if((rb->rand()%100)>75)
1420 asteroid->speed_cos = FAST_ROT_ACW_COS;
1421 asteroid->speed_sin = FAST_ROT_ACW_SIN;
1423 else if((rb->rand()%100)>75)
1425 asteroid->speed_cos = SLOW_ROT_ACW_COS;
1426 asteroid->speed_sin = SLOW_ROT_ACW_SIN;
1428 else
1430 asteroid->speed_cos = SLOW_ROT_CW_COS;
1431 asteroid->speed_sin = SLOW_ROT_CW_SIN;
1434 b = (rb->rand()%100)>66;
1435 b2 = (rb->rand()%100)>66;
1436 point = asteroid->vertices;
1437 for(n = 0; n < NUM_ASTEROID_VERTICES*2; n+=2)
1439 if(b)
1441 point->x = asteroid_one[n];
1442 point->y = asteroid_one[n+1];
1444 else if( b2 )
1446 point->x = asteroid_two[n];
1447 point->y = asteroid_two[n+1];
1449 else
1451 point->x = asteroid_three[n];
1452 point->y = asteroid_three[n+1];
1455 point->x *= asteroid->radius/6;
1456 point->y *= asteroid->radius/6;
1457 point++;
1461 asteroid->radius += 6*SCALE;
1462 if(asteroid->type == SMALL)
1463 asteroid->radius /= 3;/*2*/
1464 else if(asteroid->type == LARGE)
1465 asteroid->radius += 3*SCALE;/*2*/
1466 b = true;
1467 while(b)
1469 /*Set the position randomly:*/
1470 asteroid->position.x = (rb->rand()%SCALED_WIDTH);
1471 asteroid->position.y = (rb->rand()%SCALED_HEIGHT);
1473 asteroid->position.dx = 0;
1474 while(asteroid->position.dx == 0)
1475 asteroid->position.dx = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1477 asteroid->position.dy = 0;
1478 while(asteroid->position.dy == 0)
1479 asteroid->position.dy = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1481 asteroid->position.dx *= SCALE/10;
1482 asteroid->position.dy *= SCALE/10;
1484 b = is_point_within_rectangle(&ship.position, &asteroid->position,
1485 space_check_size);
1488 /*Now rotate the asteroid a bit, so they all look a bit different*/
1489 for(n=(rb->rand()%30) + 2;--n;)
1490 rotate_asteroid(asteroid);
1492 /*great, we've created an asteroid, don't forget to increment the total:*/
1493 asteroid_count++;
1496 /*Initialise the ship*/
1497 void initialise_ship(void)
1499 struct Point* point;
1500 struct Point* lives_point;
1501 int n;
1503 ship.position.x = CENTER_LCD_X;
1504 ship.position.y = CENTER_LCD_Y;
1505 ship.position.x *= SCALE;
1506 ship.position.y *= SCALE;
1507 ship.position.dx = ship.position.dy = 0;
1509 point = ship.vertices;
1510 lives_point = lives_points;
1511 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1513 point->x = ship_vertices[n];
1514 point->y = ship_vertices[n+1];
1515 point->x *= SCALE;
1516 point->y *= SCALE;
1517 point++;
1518 lives_point++;
1521 ship.position.dx = 0;
1522 ship.position.dy = 0;
1523 ship.explode_countdown = 0;
1525 /*grab a copy of the ships points for the lives display:*/
1526 point = ship.vertices;
1527 lives_point = lives_points;
1528 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1530 lives_point->x = point->x;
1531 lives_point->y = point->y;
1532 lives_point++;
1533 point++;
1537 void rotate_asteroid(struct Asteroid* asteroid)
1539 struct Point* point;
1540 int n;
1541 long xtemp;
1543 point = asteroid->vertices;
1544 for(n = NUM_ASTEROID_VERTICES+1; --n;)
1546 xtemp = point->x;
1547 point->x = xtemp*asteroid->speed_cos/SIN_COS_SCALE -
1548 point->y*asteroid->speed_sin/SIN_COS_SCALE;
1549 point->y = point->y*asteroid->speed_cos/SIN_COS_SCALE +
1550 xtemp*asteroid->speed_sin/SIN_COS_SCALE;
1551 point++;
1555 /*************************************************
1556 ** Draws the ship, moves the ship and creates a new
1557 ** one if it's finished exploding.
1558 **************************************************/
1559 void draw_and_move_ship(void)
1561 int nxoffset = ship.position.x/SCALE;
1562 int nyoffset = ship.position.y/SCALE;
1563 SET_FG(COL_PLAYER);
1564 if(!ship.explode_countdown)
1566 if(!ship.waiting_for_space)
1568 draw_polygon(ship.vertices, nxoffset, nyoffset, NUM_SHIP_VERTICES);
1569 if(game_state != PAUSE_MODE && game_state != GAME_OVER)
1571 move_point(&ship.position);
1575 else
1577 /* animate_and_draw_explosion(ship.vertices, NUM_SHIP_VERTICES,
1578 ship.position.x/SCALE,
1579 ship.position.y/SCALE); */
1580 if(game_state != PAUSE_MODE)
1582 ship.explode_countdown--;
1583 if(!ship.explode_countdown)
1585 num_lives--;
1586 if(!num_lives)
1588 show_game_over = SHOW_GAME_OVER_TIME;
1589 game_state = GAME_OVER;
1591 else
1593 initialise_ship();
1594 ship.waiting_for_space = true;
1601 void thrust_ship(void)
1603 if(!ship.waiting_for_space)
1605 ship.position.dx += ( ship.vertices[0].x - ship.vertices[2].x )/20;
1606 ship.position.dy += ( ship.vertices[0].y - ship.vertices[2].y )/20;
1607 /*if dx and dy are below a certain threshold, then set 'em to 0
1608 but to do this we need to ascertain if the spacehip as moved on screen
1609 for more than a certain amount. */
1611 create_trail_blaze(THRUST_COLOUR, &ship.position);
1615 /**************************************************
1616 ** Rotate the ship using the passed sin & cos values
1617 ***************************************************/
1618 void rotate_ship(int c, int s)
1620 struct Point* point;
1621 int n;
1622 double xtemp;
1624 if(!ship.waiting_for_space && !ship.explode_countdown)
1626 point = ship.vertices;
1627 for(n=NUM_SHIP_VERTICES+1;--n;)
1629 xtemp = point->x;
1630 point->x = xtemp*c/SIN_COS_SCALE - point->y*s/SIN_COS_SCALE;
1631 point->y = point->y*c/SIN_COS_SCALE + xtemp*s/SIN_COS_SCALE;
1632 point++;
1637 void drawstars()
1639 struct Point* p;
1640 int n = NUM_STARS;
1642 p = stars;
1643 SET_FG(COL_STARS);
1645 while(--n)
1647 rb->lcd_drawpixel(p->x , p->y);
1648 p++;
1652 /*************************************************
1653 ** Draw And Move all Asteroids
1654 *************************************************/
1655 void draw_and_move_asteroids(void)
1657 int n;
1658 struct Asteroid* asteroid;
1660 asteroid = asteroids_array;
1661 SET_FG(COL_ASTEROID);
1663 n = MAX_NUM_ASTEROIDS;
1664 while(--n)
1666 if(game_state != PAUSE_MODE)
1668 if(asteroid->exists)
1670 move_point(&asteroid->position);
1671 rotate_asteroid(asteroid);
1672 draw_polygon(asteroid->vertices, asteroid->position.x/SCALE,
1673 asteroid->position.y/SCALE,
1674 NUM_ASTEROID_VERTICES);
1676 else if(asteroid->explode_countdown)
1678 /* animate_and_draw_explosion(asteroid->vertices,
1679 NUM_ASTEROID_VERTICES,
1680 asteroid->position.x/SCALE,
1681 asteroid->position.y/SCALE); */
1682 asteroid->explode_countdown--;
1685 else
1687 if(asteroid->exists)
1688 draw_polygon(asteroid->vertices,
1689 asteroid->position.x/SCALE,
1690 asteroid->position.y/SCALE,
1691 NUM_ASTEROID_VERTICES);
1693 asteroid++;
1697 void create_stars(void)
1699 struct TrailPoint* tpoint;
1700 struct Point* p;
1701 int n;
1703 p = stars;
1704 n = NUM_STARS;
1705 while(--n)
1707 p->x = (rb->rand()%LCD_WIDTH);
1708 p->y = (rb->rand()%LCD_HEIGHT);
1709 p++;
1713 /* give the point a random countdown timer, so they dissapears at different
1714 times */
1715 tpoint = trailPoints;
1716 n = NUM_TRAIL_POINTS;
1717 while(--n)
1719 tpoint->alive = 0;
1720 tpoint++;
1724 /*************************************************
1725 ** Creates start_num number of new asteroids of
1726 ** full size.
1727 **************************************************/
1728 void initialise_game(int start_num)
1730 int n;
1731 asteroid_count = next_missile_count = next_thrust_count = 0;
1732 struct Asteroid* asteroid;
1733 struct Missile* missile;
1734 extra_life = EXTRA_LIFE;
1736 /*no enemy*/
1737 enemy_on_screen = 0;
1738 enemy_missile.survived = 0;
1740 /*clear asteroids*/
1741 asteroid = asteroids_array;
1742 n = MAX_NUM_ASTEROIDS;
1743 while(--n)
1745 asteroid->exists = false;
1746 asteroid++;
1749 /*make some LARGE asteroids*/
1750 for(n = 0; n < start_num; n++)
1751 initialise_asteroid(&asteroids_array[n], LARGE);
1753 /*ensure all missiles are out of action: */
1754 missile = missiles_array;
1755 n = MAX_NUM_MISSILES;
1756 while(--n)
1758 missile->survived=0;
1759 missile++;
1763 void start_attract_mode(void)
1765 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1766 enemy.appear_timing = ENEMY_APPEAR_TIMING_START;
1767 current_level = 5;
1768 num_lives = START_LIVES;
1769 current_score = 0;
1770 attract_flip_timeout = ATTRACT_FLIP_TIME;
1771 game_state = ATTRACT_MODE;
1772 if(asteroid_count < 3)
1773 initialise_game(current_level);
1776 enum plugin_status start_game(void)
1778 char s[20];
1779 char level[10];
1780 int button;
1781 int end;
1782 int CYCLETIME = 30;
1784 /*create stars once, and once only:*/
1785 create_stars();
1787 SET_BG(LCD_BLACK);
1789 while(true)
1791 /*game starts with at level 1
1792 with 1 asteroid.*/
1793 start_attract_mode();
1795 /*Main loop*/
1796 while(true)
1798 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1799 rb->lcd_clear_display();
1800 SET_FG(COL_TEXT);
1801 switch(game_state)
1803 case(ATTRACT_MODE):
1804 if(attract_flip_timeout < ATTRACT_FLIP_TIME/2)
1806 rb->lcd_putsxy(CENTER_LCD_X - 39,
1807 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4,
1808 "Fire to Start");
1809 if(!attract_flip_timeout)
1810 attract_flip_timeout = ATTRACT_FLIP_TIME;
1812 else
1814 rb->snprintf(s, sizeof(s), "Hi Score %d ", high_score);
1815 rb->lcd_putsxy(CENTER_LCD_X - 30,
1816 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, s);
1818 attract_flip_timeout--;
1819 break;
1821 case(GAME_OVER):
1822 rb->lcd_putsxy(CENTER_LCD_X - 25,
1823 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "Game Over");
1824 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1825 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1826 show_game_over--;
1827 if(!show_game_over)
1828 start_attract_mode();
1829 break;
1831 case(PAUSE_MODE):
1832 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1833 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1834 rb->lcd_putsxy(CENTER_LCD_X - 15,
1835 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "pause");
1836 draw_and_move_missiles();
1837 draw_lives();
1838 draw_and_move_ship();
1839 break;
1841 case(PLAY_MODE):
1842 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1843 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1844 draw_and_move_missiles();
1845 draw_lives();
1846 check_collisions();
1847 draw_and_move_ship();
1848 break;
1850 case(SHOW_LEVEL):
1851 show_level_timeout--;
1852 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1853 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1854 rb->snprintf(level, sizeof(level), "stage %d ", current_level);
1855 rb->lcd_putsxy(CENTER_LCD_X - 20,
1856 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, level);
1857 draw_and_move_ship();
1858 draw_lives();
1859 if(!show_level_timeout)
1861 initialise_game(current_level);
1862 game_state = PLAY_MODE;
1863 draw_lives();
1865 break;
1867 draw_trail_blaze();
1868 drawstars();
1869 draw_and_move_asteroids();
1870 draw_and_move_enemy();
1872 rb->lcd_update();
1873 button = rb->button_get(false);
1875 #ifdef HAS_BUTTON_HOLD
1876 if (rb->button_hold())
1877 game_state = PAUSE_MODE;
1878 #endif
1880 switch(button)
1882 case(AST_PAUSE):
1883 if(game_state == PLAY_MODE)
1884 game_state = PAUSE_MODE;
1885 else if(game_state == PAUSE_MODE)
1886 game_state = PLAY_MODE;
1887 break;
1889 #ifdef AST_RC_QUIT
1890 case AST_RC_QUIT:
1891 #endif
1892 case(AST_QUIT):
1893 if(game_state == ATTRACT_MODE)
1894 return PLUGIN_OK;
1895 else if(game_state == GAME_OVER)
1897 start_attract_mode();
1899 else
1901 show_game_over = SHOW_GAME_OVER_TIME;
1902 game_state = GAME_OVER;
1904 break;
1906 case (AST_LEFT_REP):
1907 case (AST_LEFT):
1908 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1909 rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN);
1910 break;
1912 case (AST_RIGHT_REP):
1913 case (AST_RIGHT):
1914 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1915 rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN);
1916 break;
1918 case (AST_THRUST_REP):
1919 case (AST_THRUST):
1920 if((game_state == PLAY_MODE || game_state == SHOW_LEVEL) && !next_thrust_count)
1922 thrust_ship();
1923 next_thrust_count = 5;
1925 break;
1927 case (AST_HYPERSPACE):
1928 if(game_state == PLAY_MODE)
1929 hyperspace();
1930 /*maybe shield if it gets too hard */
1931 break;
1933 case (AST_FIRE_REP):
1934 case (AST_FIRE):
1935 if(game_state == ATTRACT_MODE)
1937 current_level = START_LEVEL;
1938 initialise_ship();
1939 initialise_game(current_level);
1940 show_level_timeout = SHOW_LEVEL_TIME;
1941 game_state = PLAY_MODE;
1943 else if(game_state == PLAY_MODE)
1945 if(!next_missile_count)
1947 fire_missile();
1948 next_missile_count = 10;
1951 else if(game_state == PAUSE_MODE)
1953 game_state = PLAY_MODE;
1955 break;
1957 default:
1958 if (rb->default_event_handler(button)==SYS_USB_CONNECTED)
1959 return PLUGIN_USB_CONNECTED;
1960 break;
1963 if(!num_lives)
1965 if(high_score < current_score)
1966 high_score = current_score;
1967 if(!show_game_over)
1968 break;
1971 if(next_missile_count)
1972 next_missile_count--;
1974 if(next_thrust_count)
1975 next_thrust_count--;
1977 if (end > *rb->current_tick)
1978 rb->sleep(end-*rb->current_tick);
1979 else
1980 rb->yield();
1986 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1988 enum plugin_status retval;
1989 (void)(parameter);
1990 rb = api;
1992 game_state = ATTRACT_MODE;
1994 #if LCD_DEPTH > 1
1995 rb->lcd_set_backdrop(NULL);
1996 #endif
1997 /* universal font */
1998 rb->lcd_setfont(FONT_SYSFIXED);
1999 /* Turn off backlight timeout */
2000 backlight_force_on(rb); /* backlight control in lib/helper.c */
2001 iohiscore();
2002 retval = start_game();
2003 iohiscore();
2004 rb->lcd_setfont(FONT_UI);
2005 /* Turn on backlight timeout (revert to settings) */
2006 backlight_use_settings(rb); /* backlight control in lib/helper.c */
2007 return retval;