fix some problems with the menu code:
[kugel-rb.git] / apps / plugins / spacerocks.c
blob21cfb1e7944ef186dde48d2969b3804a5047e7a5
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 by Mat Holton
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "plugin.h"
23 #include "math.h"
24 #include "stdio.h"
25 #include "helper.h"
27 PLUGIN_HEADER
29 /******************************* Globals ***********************************/
30 static const struct plugin_api* rb; /* global api struct pointer */
31 /* variable button definitions */
32 #if CONFIG_KEYPAD == RECORDER_PAD
33 #define AST_PAUSE BUTTON_ON
34 #define AST_QUIT BUTTON_OFF
35 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
36 #define AST_THRUST BUTTON_UP
37 #define AST_HYPERSPACE BUTTON_DOWN
38 #define AST_LEFT BUTTON_LEFT
39 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
40 #define AST_RIGHT BUTTON_RIGHT
41 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
42 #define AST_FIRE BUTTON_PLAY
43 #define AST_FIRE_REP BUTTON_PLAY | BUTTON_REPEAT
45 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
46 #define AST_PAUSE BUTTON_ON
47 #define AST_QUIT BUTTON_OFF
48 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
49 #define AST_THRUST BUTTON_UP
50 #define AST_HYPERSPACE BUTTON_DOWN
51 #define AST_LEFT BUTTON_LEFT
52 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
53 #define AST_RIGHT BUTTON_RIGHT
54 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
55 #define AST_FIRE BUTTON_SELECT
56 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
58 #elif CONFIG_KEYPAD == ONDIO_PAD
59 #define AST_PAUSE (BUTTON_MENU | BUTTON_OFF)
60 #define AST_QUIT BUTTON_OFF
61 #define AST_THRUST BUTTON_UP
62 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
63 #define AST_HYPERSPACE BUTTON_DOWN
64 #define AST_LEFT BUTTON_LEFT
65 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
66 #define AST_RIGHT BUTTON_RIGHT
67 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
68 #define AST_FIRE BUTTON_MENU
69 #define AST_FIRE_REP BUTTON_MENU | BUTTON_REPEAT
71 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
72 (CONFIG_KEYPAD == IRIVER_H300_PAD)
73 #define AST_PAUSE BUTTON_REC
74 #define AST_QUIT BUTTON_OFF
75 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
76 #define AST_THRUST BUTTON_UP
77 #define AST_HYPERSPACE BUTTON_DOWN
78 #define AST_LEFT BUTTON_LEFT
79 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
80 #define AST_RIGHT BUTTON_RIGHT
81 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
82 #define AST_FIRE BUTTON_SELECT
83 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
85 #define AST_RC_QUIT BUTTON_RC_STOP
87 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
88 #define AST_PAUSE BUTTON_PLAY
89 #define AST_QUIT BUTTON_POWER
90 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
91 #define AST_THRUST BUTTON_UP
92 #define AST_HYPERSPACE BUTTON_DOWN
93 #define AST_LEFT BUTTON_LEFT
94 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
95 #define AST_RIGHT BUTTON_RIGHT
96 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
97 #define AST_FIRE BUTTON_SELECT
98 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
100 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
101 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
102 #define AST_PAUSE (BUTTON_SELECT | BUTTON_PLAY)
103 #define AST_QUIT (BUTTON_SELECT | BUTTON_MENU)
104 #define AST_THRUST BUTTON_MENU
105 #define AST_THRUST_REP (BUTTON_MENU | BUTTON_REPEAT)
106 #define AST_HYPERSPACE BUTTON_PLAY
107 #define AST_LEFT BUTTON_SCROLL_BACK
108 #define AST_LEFT_REP (BUTTON_SCROLL_BACK | BUTTON_REPEAT)
109 #define AST_RIGHT BUTTON_SCROLL_FWD
110 #define AST_RIGHT_REP (BUTTON_SCROLL_FWD | BUTTON_REPEAT)
111 #define AST_FIRE BUTTON_SELECT
112 #define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT)
114 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
115 #define AST_PAUSE BUTTON_A
116 #define AST_QUIT BUTTON_POWER
117 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
118 #define AST_THRUST BUTTON_UP
119 #define AST_HYPERSPACE BUTTON_DOWN
120 #define AST_LEFT BUTTON_LEFT
121 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
122 #define AST_RIGHT BUTTON_RIGHT
123 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
124 #define AST_FIRE BUTTON_SELECT
125 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
127 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
128 #define AST_PAUSE BUTTON_REC
129 #define AST_QUIT BUTTON_POWER
130 #define AST_THRUST_REP (BUTTON_UP | BUTTON_REPEAT)
131 #define AST_THRUST BUTTON_UP
132 #define AST_HYPERSPACE BUTTON_DOWN
133 #define AST_LEFT BUTTON_SCROLL_BACK
134 #define AST_LEFT_REP (BUTTON_SCROLL_BACK | BUTTON_REPEAT)
135 #define AST_RIGHT BUTTON_SCROLL_FWD
136 #define AST_RIGHT_REP (BUTTON_SCROLL_FWD | BUTTON_REPEAT)
137 #define AST_FIRE BUTTON_SELECT
138 #define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT)
140 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
141 #define AST_PAUSE BUTTON_REC
142 #define AST_QUIT BUTTON_POWER
143 #define AST_THRUST_REP (BUTTON_UP | BUTTON_REPEAT)
144 #define AST_THRUST BUTTON_UP
145 #define AST_HYPERSPACE BUTTON_DOWN
146 #define AST_LEFT BUTTON_LEFT
147 #define AST_LEFT_REP (BUTTON_LEFT | BUTTON_REPEAT)
148 #define AST_RIGHT BUTTON_RIGHT
149 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
150 #define AST_FIRE BUTTON_SELECT
151 #define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT)
153 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
154 #define AST_PAUSE BUTTON_PLAY
155 #define AST_QUIT BUTTON_POWER
156 #define AST_THRUST_REP BUTTON_SCROLL_UP | BUTTON_REPEAT
157 #define AST_THRUST BUTTON_SCROLL_UP
158 #define AST_HYPERSPACE BUTTON_SCROLL_DOWN
159 #define AST_LEFT BUTTON_LEFT
160 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
161 #define AST_RIGHT BUTTON_RIGHT
162 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
163 #define AST_FIRE BUTTON_REW
164 #define AST_FIRE_REP BUTTON_REW | BUTTON_REPEAT
166 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
167 #define AST_PAUSE BUTTON_PLAY
168 #define AST_QUIT BUTTON_BACK
169 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
170 #define AST_THRUST BUTTON_UP
171 #define AST_HYPERSPACE BUTTON_DOWN
172 #define AST_LEFT BUTTON_LEFT
173 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
174 #define AST_RIGHT BUTTON_RIGHT
175 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
176 #define AST_FIRE BUTTON_SELECT
177 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
179 #elif (CONFIG_KEYPAD == MROBE100_PAD)
180 #define AST_PAUSE BUTTON_DISPLAY
181 #define AST_QUIT BUTTON_POWER
182 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
183 #define AST_THRUST BUTTON_UP
184 #define AST_HYPERSPACE BUTTON_DOWN
185 #define AST_LEFT BUTTON_LEFT
186 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
187 #define AST_RIGHT BUTTON_RIGHT
188 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
189 #define AST_FIRE BUTTON_SELECT
190 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
192 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
193 #define AST_PAUSE BUTTON_RC_PLAY
194 #define AST_QUIT BUTTON_RC_REC
195 #define AST_THRUST_REP BUTTON_RC_VOL_UP | BUTTON_REPEAT
196 #define AST_THRUST BUTTON_RC_VOL_UP
197 #define AST_HYPERSPACE BUTTON_RC_VOL_DOWN
198 #define AST_LEFT BUTTON_RC_REW
199 #define AST_LEFT_REP (BUTTON_RC_REW | BUTTON_REPEAT)
200 #define AST_RIGHT BUTTON_RC_FF
201 #define AST_RIGHT_REP (BUTTON_RC_FF | BUTTON_REPEAT)
202 #define AST_FIRE BUTTON_RC_MODE
203 #define AST_FIRE_REP (BUTTON_RC_MODE | BUTTON_REPEAT)
205 #elif (CONFIG_KEYPAD == COWOND2_PAD)
206 #define AST_QUIT BUTTON_POWER
208 #else
209 #error No keymap defined!
210 #endif
212 #ifdef HAVE_TOUCHSCREEN
213 #ifndef AST_PAUSE
214 #define AST_PAUSE BUTTON_CENTER
215 #endif
216 #ifndef AST_QUIT
217 #define AST_QUIT BUTTON_TOPLEFT
218 #endif
219 #ifndef AST_THRUST_REP
220 #define AST_THRUST_REP (BUTTON_TOPMIDDLE | BUTTON_REPEAT)
221 #endif
222 #ifndef AST_THRUST
223 #define AST_THRUST BUTTON_TOPMIDDLE
224 #endif
225 #ifndef AST_HYPERSPACE
226 #define AST_HYPERSPACE BUTTON_TOPRIGHT
227 #endif
228 #ifndef AST_LEFT
229 #define AST_LEFT BUTTON_MIDLEFT
230 #endif
231 #ifndef AST_LEFT_REP
232 #define AST_LEFT_REP (BUTTON_MIDLEFT | BUTTON_REPEAT)
233 #endif
234 #ifndef AST_RIGHT
235 #define AST_RIGHT BUTTON_MIDRIGHT
236 #endif
237 #ifndef AST_RIGHT_REP
238 #define AST_RIGHT_REP (BUTTON_MIDRIGHT | BUTTON_REPEAT)
239 #endif
240 #ifndef AST_FIRE
241 #define AST_FIRE BUTTON_BOTTOMMIDDLE
242 #endif
243 #ifndef AST_FIRE_REP
244 #define AST_FIRE_REP (BUTTON_BOTTOMMIDDLE | BUTTON_MENU)
245 #endif
246 #endif
248 #define ABS(x) ((x)>0?(x):-(x))
250 #define RES MAX(LCD_WIDTH, LCD_HEIGHT)
251 #define LARGE_LCD RES >= 200
252 #define ENEMY_MISSILE_SURVIVAL_LENGTH RES/2
253 #define ASTEROID_SPEED RES/20
254 #define MISSILE_SURVIVAL_LENGTH 40
256 #define EXTRA_LIFE 250
257 #define SCALE 5000
258 #define MISSILE_SCALE 5000
259 #define WRAP_GAP 12
260 #define EXPLOSION_LENGTH 20
261 #define SHOW_COL 0
262 #define HISCORE_FILE PLUGIN_GAMES_DIR "/astrorocks.hs"
263 #define POINT_SIZE 2
264 #define MAX_NUM_ASTEROIDS 25
265 #define MAX_NUM_MISSILES 6
266 #define ENEMY_BIG_PROBABILITY_START 10
267 #define ENEMY_APPEAR_PROBABILITY_START 35
268 #define ENEMY_APPEAR_TIMING_START 1800
269 #define LITTLE_SHIP 2
270 #define BIG_SHIP 1
271 #define SHOW_GAME_OVER_TIME 100
272 #define SHOW_LEVEL_TIME 50
273 #define START_LIVES 3
274 #define START_LEVEL 1
275 #define NUM_ASTEROID_VERTICES 10
276 #define NUM_SHIP_VERTICES 4
277 #define NUM_ENEMY_VERTICES 6
278 #define MAX_LEVEL MAX_NUM_ASTEROIDS
279 #define ENEMY_SPEED 4
280 #define ENEMY_START_X 0
281 #define ENEMY_START_Y 0
282 #define SIZE_ENEMY_COLLISION 5*SCALE
283 #define ATTRACT_FLIP_TIME 100
284 #define NUM_STARS 50
285 #define NUM_TRAIL_POINTS 70
286 #define NUM_ROTATIONS 16
288 #define SIN_COS_SCALE 10000
290 #define FAST_ROT_CW_SIN 873
291 #define FAST_ROT_CW_COS 9963
292 #define FAST_ROT_ACW_SIN -873
293 #define FAST_ROT_ACW_COS 9963
295 #define MEDIUM_ROT_CW_SIN 350
296 #define MEDIUM_ROT_CW_COS 9994
297 #define MEDIUM_ROT_ACW_SIN -350
298 #define MEDIUM_ROT_ACW_COS 9994
300 #define SLOW_ROT_CW_SIN 350
301 #define SLOW_ROT_CW_COS 9994
302 #define SLOW_ROT_ACW_SIN - 350
303 #define SLOW_ROT_ACW_COS 9994
305 #ifdef HAVE_LCD_COLOR
306 #define SHIP_ROT_CW_SIN 2419
307 #define SHIP_ROT_CW_COS 9702
308 #define SHIP_ROT_ACW_SIN -2419
309 #define SHIP_ROT_ACW_COS 9702
310 #else
311 #define SHIP_ROT_CW_SIN 3827
312 #define SHIP_ROT_CW_COS 9239
313 #define SHIP_ROT_ACW_SIN -3827
314 #define SHIP_ROT_ACW_COS 9239
315 #endif
318 #define SCALED_WIDTH (LCD_WIDTH*SCALE)
319 #define SCALED_HEIGHT (LCD_HEIGHT*SCALE)
320 #define CENTER_LCD_X (LCD_WIDTH/2)
321 #define CENTER_LCD_Y (LCD_HEIGHT/2)
323 #define SHIP_EXPLOSION_COLOUR 1
324 #define ASTEROID_EXPLOSION_COLOUR 2
325 #define ENEMY_EXPLOSION_COLOUR 3
326 #define THRUST_COLOUR 4
328 #define ASTEROID_R 230
329 #define ASTEROID_G 200
330 #define ASTEROID_B 100
331 #define SHIP_R 255
332 #define SHIP_G 255
333 #define SHIP_B 255
334 #define ENEMY_R 50
335 #define ENEMY_G 220
336 #define ENEMY_B 50
337 #define THRUST_R 200
338 #define THRUST_G 200
339 #define THRUST_B 0
341 #ifdef HAVE_LCD_COLOR
342 #define COL_MISSILE LCD_RGBPACK(200,0,0)
343 #define COL_PLAYER LCD_RGBPACK(200,200,200)
344 #define COL_STARS LCD_WHITE
345 #define COL_ASTEROID LCD_RGBPACK(ASTEROID_R,ASTEROID_G,ASTEROID_B)
346 #define COL_TEXT LCD_RGBPACK(200,200,255)
347 #define COL_ENEMY LCD_RGBPACK(ENEMY_R,ENEMY_G,ENEMY_B)
348 #define SET_FG rb->lcd_set_foreground
349 #define SET_BG rb->lcd_set_background
350 #else
351 #define SET_FG(x)
352 #define SET_BG(x)
353 #endif
355 /* The array of points that make up an asteroid */
356 static const short asteroid_one[NUM_ASTEROID_VERTICES*2] =
358 -2, -12,
359 4, -8,
360 8, -14,
361 16, -5,
362 14, 0,
363 20, 2,
364 12, 14,
365 -4, 14,
366 -10, 6,
367 -10, -8
370 /* The array of points that make up an asteroid */
371 static const short asteroid_two[NUM_ASTEROID_VERTICES*2] =
373 -2, -12,
374 4, -16,
375 6, -14,
376 16, -8,
377 14, 0,
378 20, 2,
379 12, 14,
380 -4, 14,
381 -10, 6,
382 -10, -8
385 /* The array of points that make up an asteroid */
386 static const short asteroid_three[NUM_ASTEROID_VERTICES*2] =
388 -2, -12,
389 4, -16,
390 6, -14,
391 2, -8,
392 14, 0,
393 20, 2,
394 12, 14,
395 -4, 14,
396 -16, 6,
397 -10, -8
400 /* The array od points the make up the ship */
401 static const short ship_vertices[NUM_SHIP_VERTICES*2] =
403 #if(LARGE_LCD)
404 0,-6,
405 4, 6,
406 0, 2,
407 -4, 6
408 #else
409 0,-4,
410 3, 4,
411 0, 1,
412 -3, 4
413 #endif
416 /* The array of points the make up the bad spaceship */
417 static const short enemy_vertices[NUM_ENEMY_VERTICES*2] =
419 #if(LARGE_LCD)
420 -8, 0,
421 -4, 4,
422 4, 4,
423 8, 0,
424 4, -4,
425 -4, -4
426 #else
427 -5, 0,
428 -2, 2,
429 2, 2,
430 5, 0,
431 2, -2,
432 -2, -2
433 #endif
437 enum asteroid_type
439 #if(LARGE_LCD)
440 SMALL = 2,
441 MEDIUM = 4,
442 LARGE = 6,
443 #else
444 SMALL = 1,
445 MEDIUM = 2,
446 LARGE = 3,
447 #endif
451 enum game_state
453 GAME_OVER,
454 ATTRACT_MODE,
455 SHOW_LEVEL,
456 PLAY_MODE,
457 PAUSE_MODE
460 struct Point
462 int x;
463 int y;
464 int dx;
465 int dy;
468 struct TrailPoint
470 int alive;
471 struct Point position;
472 short r;
473 short g;
474 short b;
475 short dec;
478 /* Asteroid structure, contains an array of points */
479 struct Asteroid
481 enum asteroid_type type;
482 bool exists;
483 struct Point position;
484 struct Point vertices[NUM_ASTEROID_VERTICES];
485 int radius;
486 long speed_cos;
487 long speed_sin;
488 int explode_countdown;
491 struct Ship
493 struct Point vertices[NUM_SHIP_VERTICES];
494 struct Point position;
495 bool waiting_for_space;
496 int explode_countdown;
499 struct Enemy
501 struct Point vertices[NUM_ENEMY_VERTICES];
502 struct Point position;
503 int explode_countdown;
504 long last_time_appeared;
505 short size_probability;
506 short appear_probability;
507 short appear_timing;
510 struct Missile
512 struct Point position;
513 struct Point oldpoint;
514 int survived;
517 static enum game_state game_state;
518 static int asteroid_count;
519 static int next_missile_count;
520 static int next_thrust_count;
521 static int num_lives;
522 static int extra_life;
523 static int show_level_timeout;
524 static int attract_flip_timeout;
525 static int show_game_over;
526 static int current_level;
527 static int current_score;
528 static int high_score;
529 static int space_check_size = 30*SCALE;
531 static bool enemy_on_screen;
532 static char phscore[30];
533 static struct Ship ship;
534 static struct Point stars[NUM_STARS];
535 static struct Asteroid asteroids_array[MAX_NUM_ASTEROIDS];
536 static struct Missile missiles_array[MAX_NUM_MISSILES];
537 static struct Missile enemy_missile;
538 static struct Enemy enemy;
539 static struct Point lives_points[NUM_SHIP_VERTICES];
540 static struct TrailPoint trailPoints[NUM_TRAIL_POINTS];
542 void draw_and_move_asteroids(void);
543 void initialise_game(int nStartNum);
545 bool is_asteroid_near_ship(struct Asteroid* asteroid);
546 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point);
548 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type eType);
549 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices);
550 void rotate_asteroid(struct Asteroid* asteroid);
551 void create_asteroid(enum asteroid_type type, int x, int y);
552 void create_stars(void);
554 void initialise_ship(void);
555 void draw_and_move_ship(void);
556 void rotate_ship(int s, int c);
557 void thrust_ship(void);
559 void initialise_missile(struct Missile* missile);
560 void draw_and_move_missiles(void);
561 void fire_missile(void);
563 void animate_and_draw_explosion(struct Point* point, int num_points, int xoffset, int yoffset);
564 void initialise_explosion(struct Point* point, int num_points);
566 void move_point(struct Point* point);
567 void hyperspace(void);
568 void check_collisions(void);
569 void initialise_enemy(void);
570 void draw_and_move_enemy(void);
571 void draw_lives(void);
572 void drawstars(void);
573 bool is_ship_within_asteroid(struct Asteroid* asteroid);
577 /*Hi-Score reading and writing to file - this needs moving to the hi-score plugin lib as
578 a 3rd function */
579 void iohiscore(void)
581 int fd;
582 int compare;
584 /* clear the buffer we're about to load the highscore data into */
585 rb->memset(phscore, 0, sizeof(phscore));
587 fd = rb->open(HISCORE_FILE,O_RDWR | O_CREAT);
588 if(fd < 0)
590 rb->splash(HZ, "Highscore file read error");
591 return;
594 /* highscore used to %d, is now %d\n
595 Deal with no file or bad file */
596 rb->read(fd,phscore, sizeof(phscore));
598 compare = rb->atoi(phscore);
600 if(high_score > compare)
602 rb->lseek(fd,0,SEEK_SET);
603 rb->fdprintf(fd, "%d\n", high_score);
605 else
606 high_score = compare;
608 rb->close(fd);
611 bool point_in_poly(struct Point* _point, int num_vertices, int x, int y)
613 struct Point* pi;
614 struct Point* pj;
615 int n;
616 bool c = false;
618 pi = _point;
619 pj = _point;
620 pj += num_vertices-1;
622 n = num_vertices;
623 while(n--)
625 if((((pi->y <= y) && (y < pj->y)) || ((pj->y <= y) && (y < pi->y))) &&
626 (x < (pj->x - pi->x) * (y - pi->y) / (pj->y - pi->y) + pi->x))
627 c = !c;
629 if(n == num_vertices - 1)
630 pj = _point;
631 else
632 pj++;
634 pi++;
637 return c;
640 void move_point(struct Point* point)
642 point->x += point->dx;
643 point->y += point->dy;
645 /*check bounds on the x-axis:*/
646 if(point->x >= SCALED_WIDTH)
647 point->x = 0;
648 else if(point->x <= 0)
649 point->x = SCALED_WIDTH;
651 /*Check bounds on the y-axis:*/
652 if(point->y >= SCALED_HEIGHT)
653 point->y = 0;
654 else if(point->y <= 0)
655 point->y = SCALED_HEIGHT;
658 void create_trail(struct TrailPoint* tpoint)
660 tpoint->position.dx = -( ship.vertices[0].x - ship.vertices[2].x )/10;
661 tpoint->position.dy = -( ship.vertices[0].y - ship.vertices[2].y )/10;
664 void create_explosion_trail(struct TrailPoint* tpoint)
666 tpoint->position.dx = (rb->rand()%5050)-2500;
667 tpoint->position.dy = (rb->rand()%5050)-2500;
670 void create_trail_blaze(int colour, struct Point* position)
672 int numtoadd;
673 struct TrailPoint* tpoint;
674 int n;
675 int xadd,yadd;
676 if(colour != SHIP_EXPLOSION_COLOUR)
678 numtoadd = NUM_TRAIL_POINTS/5;
679 xadd = position->x;
680 yadd = position->y;
682 else
684 numtoadd = NUM_TRAIL_POINTS/8;
685 xadd = ship.position.x;
686 yadd = ship.position.y;
689 /* give the point a random countdown timer, so they dissapears at different times */
690 tpoint = trailPoints;
691 n = NUM_TRAIL_POINTS;
692 while(--n)
694 if(tpoint->alive <= 0 && numtoadd)
696 numtoadd--;
697 /* take a random x point anywhere between bottom two points of ship. */
698 /* ship.position.x; */
699 tpoint->position.x = (ship.vertices[2].x + (rb->rand()%18000)-9000) + position->x;
700 tpoint->position.y = (ship.vertices[2].y + (rb->rand()%18000)-9000) + position->y;
702 switch(colour)
704 case SHIP_EXPLOSION_COLOUR:
705 tpoint->r = 255;
706 tpoint->g = 255;
707 tpoint->b = 255;
708 create_explosion_trail(tpoint);
709 tpoint->alive = 510;
710 tpoint->dec = 2;
711 break;
712 case ASTEROID_EXPLOSION_COLOUR:
713 tpoint->r = ASTEROID_R;
714 tpoint->g = ASTEROID_G;
715 tpoint->b = ASTEROID_B;
716 create_explosion_trail(tpoint);
717 tpoint->alive = 510;
718 tpoint->dec = 2;
719 break;
720 case ENEMY_EXPLOSION_COLOUR:
721 tpoint->r = ENEMY_R;
722 tpoint->g = ENEMY_G;
723 tpoint->b = ENEMY_B;
724 create_explosion_trail(tpoint);
725 tpoint->alive = 510;
726 tpoint->dec = 2;
727 break;
728 case THRUST_COLOUR:
729 tpoint->r = THRUST_R;
730 tpoint->g = THRUST_G;
731 tpoint->b = THRUST_B;
732 create_trail(tpoint);
733 tpoint->alive = 175;
734 tpoint->dec = 4;
735 break;
737 /* add a proportional bit to the x and y based on dx and dy */
739 /* give the points a speed based on direction of travel - i.e. opposite */
740 tpoint->position.dx += position->dx;
741 tpoint->position.dy += position->dy;
745 tpoint++;
747 /* find a space in the array of trail_points that is NULL or DEAD or whatever.
748 and place this one here. */
752 void draw_trail_blaze(void)
754 struct TrailPoint* tpoint;
755 /* loop through, if alive then move and draw.
756 when drawn, countdown it's timer.
757 if zero kill it! */
758 tpoint = trailPoints;
759 int n = NUM_TRAIL_POINTS;
761 while(--n)
763 if(tpoint->alive)
765 if(game_state != PAUSE_MODE)
767 tpoint->alive-=10;
768 move_point(&(tpoint->position));
770 #ifdef HAVE_LCD_COLOR
771 /* intensity = tpoint->alive/2; */
772 if(tpoint->r>0)tpoint->r-=tpoint->dec;
773 if(tpoint->g>0)tpoint->g-=tpoint->dec;
774 if(tpoint->b>0)tpoint->b-=tpoint->dec;
775 SET_FG(LCD_RGBPACK(tpoint->r, tpoint->g, tpoint->b));
776 #endif
777 rb->lcd_drawpixel(tpoint->position.x/SCALE , tpoint->position.y/SCALE);
779 tpoint++;
783 /*Check if point is within a rectangle*/
784 bool is_point_within_rectangle(struct Point* rect, struct Point* p, int size)
786 #if SHOW_COL
787 int aTLx = rect->x - size;
788 int aTLy = rect->y - size;
789 int aBRx = rect->x + size;
790 int aBRy = rect->y + size;
791 rb->lcd_hline( aTLx/SCALE, aBRx/SCALE, aTLy/SCALE);
792 rb->lcd_vline( aTLx/SCALE, aTLy/SCALE, aBRy/SCALE);
793 rb->lcd_hline( aTLx/SCALE, aBRx/SCALE, aBRy/SCALE);
794 rb->lcd_vline( aBRx/SCALE, aBRy/SCALE, aTLy/SCALE);
795 return (p->x > aTLx && p->x < aBRx && p->y > aTLy && p->y < aBRy);
796 #else
797 return (p->x > rect->x - size && p->x < rect->x + size &&
798 p->y > rect->y - size && p->y < rect->y + size);
799 #endif
802 /* Draw polygon */
803 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices)
805 int n, t1, t2, oldX, oldY;
806 struct Point *p;
807 bool bDrawAll = px < WRAP_GAP || LCD_WIDTH - px < WRAP_GAP ||
808 py < WRAP_GAP || LCD_HEIGHT - py < WRAP_GAP;
810 p = vertices;
811 p += num_vertices-1;
812 oldX = p->x/SCALE + px;
813 oldY = p->y/SCALE + py;
814 p = vertices;
815 for(n = num_vertices+1; --n;)
817 t1 = p->x/SCALE + px;
818 t2 = p->y/SCALE + py;
820 rb->lcd_drawline(oldX, oldY, t1, t2);
822 if(bDrawAll)
824 rb->lcd_drawline(oldX - LCD_WIDTH, oldY, t1 - LCD_WIDTH, t2);
825 rb->lcd_drawline(oldX + LCD_WIDTH, oldY, t1 + LCD_WIDTH, t2);
826 rb->lcd_drawline(oldX - LCD_WIDTH, oldY + LCD_HEIGHT,
827 t1 - LCD_WIDTH, t2 + LCD_HEIGHT);
828 rb->lcd_drawline(oldX + LCD_WIDTH, oldY + LCD_HEIGHT,
829 t1 + LCD_WIDTH, t2 + LCD_HEIGHT);
831 rb->lcd_drawline(oldX, oldY - LCD_HEIGHT, t1, t2 - LCD_HEIGHT);
832 rb->lcd_drawline(oldX, oldY + LCD_HEIGHT, t1, t2 + LCD_HEIGHT);
833 rb->lcd_drawline(oldX - LCD_WIDTH, oldY - LCD_HEIGHT,
834 t1 - LCD_WIDTH, t2 - LCD_HEIGHT);
835 rb->lcd_drawline(oldX + LCD_WIDTH, oldY - LCD_HEIGHT,
836 t1 + LCD_WIDTH, t2 - LCD_HEIGHT);
838 oldX = t1;
839 oldY = t2;
840 p++;
844 void animate_and_draw_explosion(struct Point* point, int num_points,
845 int xoffset, int yoffset)
847 int n;
848 for(n = num_points; --n;)
850 if(game_state != PAUSE_MODE)
852 point->x += point->dx;
853 point->y += point->dy;
855 rb->lcd_fillrect( point->x/SCALE + xoffset, point->y/SCALE + yoffset,
856 POINT_SIZE, POINT_SIZE);
857 point++;
861 /*stop movement of ship, 'cos that's what happens when you go into hyperspace.*/
862 void hyperspace(void)
864 ship.position.dx = ship.position.dy = 0;
865 ship.position.x = (rb->rand()%SCALED_WIDTH);
866 ship.position.y = (rb->rand()%SCALED_HEIGHT);
869 void initialise_enemy(void)
871 struct Point* point;
872 int n;
873 int size;
875 if(rb->rand()%100 > enemy.size_probability)
877 size = BIG_SHIP;
878 enemy.size_probability++;
879 if(enemy.size_probability < 90)
881 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
884 else
886 size = LITTLE_SHIP;
889 enemy_missile.survived = 0;
890 enemy_on_screen = true;
891 enemy.explode_countdown = 0;
892 enemy.last_time_appeared = *rb->current_tick;
893 point = enemy.vertices;
894 for(n = 0; n < NUM_ENEMY_VERTICES+NUM_ENEMY_VERTICES; n+=2)
896 point->x = enemy_vertices[n];
897 point->y = enemy_vertices[n+1];
898 point->x *= SCALE/size;
899 point->y *= SCALE/size;
900 point++;
903 if(ship.position.x >= SCALED_WIDTH/2)
905 enemy.position.dx = ENEMY_SPEED;
906 enemy.position.x = 0;
908 else
910 enemy.position.dx = -ENEMY_SPEED;
911 enemy.position.x = SCALED_WIDTH;
914 if(ship.position.y >= SCALED_HEIGHT/2)
916 enemy.position.dy = ENEMY_SPEED;
917 enemy.position.y = 0;
919 else
921 enemy.position.dy = -ENEMY_SPEED;
922 enemy.position.y = SCALED_HEIGHT;
925 enemy.position.dx *= SCALE/10;
926 enemy.position.dy *= SCALE/10;
929 void draw_and_move_enemy(void)
931 int enemy_x, enemy_y;
932 struct Point *point;
934 SET_FG(COL_ENEMY);
936 if(enemy_on_screen)
938 enemy_x = enemy.position.x/SCALE;
939 enemy_y = enemy.position.y/SCALE;
940 if(!enemy.explode_countdown)
942 point = enemy.vertices;
943 draw_polygon(enemy.vertices, enemy_x, enemy_y, NUM_ENEMY_VERTICES);
944 rb->lcd_drawline(enemy.vertices[0].x/SCALE + enemy_x,
945 enemy.vertices[0].y/SCALE + enemy_y,
946 enemy.vertices[3].x/SCALE + enemy_x,
947 enemy.vertices[3].y/SCALE + enemy_y);
949 if(game_state != PAUSE_MODE)
951 enemy.position.x += enemy.position.dx;
952 enemy.position.y += enemy.position.dy;
955 if(enemy.position.x > SCALED_WIDTH || enemy.position.x < 0)
956 enemy_on_screen = false;
958 if(enemy.position.y > SCALED_HEIGHT)
959 enemy.position.y = 0;
960 else if(enemy.position.y < 0)
961 enemy.position.y = SCALED_HEIGHT;
963 if( (rb->rand()%1000) < 10)
964 enemy.position.dy = -enemy.position.dy;
966 else
969 /* animate_and_draw_explosion(enemy.vertices, NUM_ENEMY_VERTICES,
970 enemy_x, enemy.position.y/SCALE); */
971 if(game_state != PAUSE_MODE)
973 enemy.explode_countdown--;
974 if(!enemy.explode_countdown)
975 enemy_on_screen = false;
979 else
981 if( (*rb->current_tick - enemy.last_time_appeared) > enemy.appear_timing)
982 if(rb->rand()%100 > enemy.appear_probability) initialise_enemy();
985 if(!enemy_missile.survived && game_state != GAME_OVER)
987 /*if no missile and the enemy is here and not exploding..then shoot baby!*/
988 if( !enemy.explode_countdown && enemy_on_screen &&
989 !ship.waiting_for_space && (rb->rand()%10) > 5 )
991 enemy_missile.position.x = enemy.position.x;
992 enemy_missile.position.y = enemy.position.y;
994 /*lame, needs to be sorted - it's trying to shoot at the ship*/
995 if(ABS(enemy.position.y - ship.position.y) <= 5*SCALE)
997 enemy_missile.position.dy = 0;
999 else
1001 if( enemy.position.y < ship.position.y)
1002 enemy_missile.position.dy = 1;
1003 else
1004 enemy_missile.position.dy = -1;
1007 if(ABS(enemy.position.x - ship.position.x) <= 5*SCALE)
1008 enemy_missile.position.dx = 0;
1009 else
1011 if( enemy.position.x < ship.position.x)
1012 enemy_missile.position.dx = 1;
1013 else
1014 enemy_missile.position.dx = -1;
1017 if(enemy_missile.position.dx == 0 &&
1018 enemy_missile.position.dy == 0)
1019 enemy_missile.position.dx = enemy_missile.position.dy = -1;
1021 enemy_missile.position.dx *= SCALE;
1022 enemy_missile.position.dy *= SCALE;
1023 enemy_missile.survived = ENEMY_MISSILE_SURVIVAL_LENGTH;
1027 else
1029 rb->lcd_fillrect( enemy_missile.position.x/SCALE,
1030 enemy_missile.position.y/SCALE,
1031 POINT_SIZE, POINT_SIZE);
1032 if(game_state != PAUSE_MODE)
1034 move_point(&enemy_missile.position);
1035 enemy_missile.survived--;
1040 /******************
1041 * Lame method of collision
1042 * detection. It's checking for collision
1043 * between point and a big rectangle around the asteroid...
1044 *******************/
1045 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point)
1047 if( !is_point_within_rectangle(&asteroid->position, point,
1048 asteroid->radius+4*SCALE) )
1049 return false;
1051 if(point_in_poly(asteroid->vertices, NUM_ASTEROID_VERTICES,
1052 point->x - asteroid->position.x,
1053 point->y - asteroid->position.y))
1055 switch(asteroid->type)
1057 case(SMALL):
1058 asteroid->explode_countdown = EXPLOSION_LENGTH;
1059 create_trail_blaze(ASTEROID_EXPLOSION_COLOUR, &asteroid->position);
1060 break;
1062 case(LARGE):
1063 create_asteroid(MEDIUM, asteroid->position.x,
1064 asteroid->position.y);
1065 create_asteroid(MEDIUM, asteroid->position.x,
1066 asteroid->position.y);
1067 break;
1069 case(MEDIUM):
1070 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1071 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1072 break;
1075 current_score++;
1076 if(current_score > extra_life)
1078 num_lives++;
1079 extra_life = current_score+EXTRA_LIFE;
1081 asteroid_count--;
1082 asteroid->exists = false;
1083 return true;
1085 else
1086 return false;
1089 bool is_point_within_enemy(struct Point* point)
1091 if( is_point_within_rectangle(&enemy.position, point, 7*SCALE) )
1093 current_score += 5;
1094 /*enemy_missile.survived = 0;*/
1095 enemy.explode_countdown = EXPLOSION_LENGTH;
1096 /* initialise_explosion(enemy.vertices, NUM_ENEMY_VERTICES); */
1097 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1098 return true;
1100 else
1101 return false;
1104 bool is_ship_within_asteroid(struct Asteroid* asteroid)
1106 bool hit = false;
1107 struct Point p;
1109 p.x = ship.position.x + ship.vertices[0].x;
1110 p.y = ship.position.y + ship.vertices[0].y;
1111 hit |= is_point_within_asteroid(asteroid, &p);
1113 if(!hit)
1115 p.x = ship.position.x + ship.vertices[1].x;
1116 p.y = ship.position.y + ship.vertices[1].y;
1117 hit |= is_point_within_asteroid(asteroid, &p);
1118 if(!hit)
1120 p.x = ship.position.x + ship.vertices[3].x;
1121 p.y = ship.position.y + ship.vertices[3].y;
1122 hit |= is_point_within_asteroid(asteroid, &p);
1126 return hit;
1129 void initialise_explosion(struct Point* point, int num_points)
1131 int n;
1133 point->x += point->dx;
1134 point->y += point->dy;
1135 for(n = num_points; --n;)
1137 point->dx = point->x;
1138 point->dy = point->y;
1139 point++;
1144 /* Check for collsions between the missiles and the asteroids and the ship */
1145 void check_collisions(void)
1147 int m, n;
1148 bool asteroids_onscreen = false;
1149 struct Missile* missile;
1150 struct Asteroid* asteroid;
1151 bool ship_cant_be_placed = false;
1153 asteroid = asteroids_array;
1154 m = MAX_NUM_ASTEROIDS;
1155 while(--m)
1157 /*if the asteroids exists then test missile collision:*/
1158 if(asteroid->exists)
1160 missile = missiles_array;
1161 n = MAX_NUM_MISSILES;
1162 while(--n)
1164 /*if the missiles exists:*/
1165 if(missile->survived > 0)
1167 /*has the missile hit the asteroid?*/
1168 if(is_point_within_asteroid(asteroid, &missile->position)
1169 || is_point_within_asteroid(asteroid,
1170 &missile->oldpoint))
1172 missile->survived = 0;
1173 break;
1176 missile++;
1179 /*now check collision with ship:*/
1180 if(asteroid->exists && !ship.waiting_for_space && !ship.explode_countdown)
1182 if(is_ship_within_asteroid(asteroid))
1184 /*blow up ship*/
1185 ship.explode_countdown = EXPLOSION_LENGTH;
1186 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1187 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1190 /*has the enemy missile blown something up?*/
1191 if(asteroid->exists && enemy_missile.survived)
1193 if(is_point_within_asteroid(asteroid, &enemy_missile.position))
1195 /*take that score back then:*/
1196 if(current_score > 0) current_score--;
1197 enemy_missile.survived = 0;
1200 /*if it still exists, check if ship is waiting for space:*/
1201 if(asteroid->exists && ship.waiting_for_space)
1202 ship_cant_be_placed |=
1203 is_point_within_rectangle(&ship.position,
1204 &asteroid->position,
1205 space_check_size);
1209 /*is an asteroid still exploding?*/
1210 if(asteroid->explode_countdown)
1211 asteroids_onscreen = true;
1213 asteroid++;
1216 /*now check collision between ship and enemy*/
1217 if(enemy_on_screen && !ship.waiting_for_space &&
1218 !ship.explode_countdown && !enemy.explode_countdown)
1220 /*has the enemy collided with the ship?*/
1221 if(is_point_within_enemy(&ship.position))
1223 ship.explode_countdown = EXPLOSION_LENGTH;
1224 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1225 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1226 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1229 /*Now see if the enemy has been shot at by the ships missiles:*/
1230 missile = missiles_array;
1231 n = MAX_NUM_MISSILES;
1232 while(--n)
1234 if(missile->survived > 0 &&
1235 is_point_within_enemy(&missile->position))
1237 missile->survived = 0;
1238 break;
1240 missile++;
1244 /*test collision with enemy missile and ship:*/
1245 if(!ship_cant_be_placed && enemy_missile.survived > 0 &&
1246 point_in_poly(ship.vertices, NUM_SHIP_VERTICES,
1247 enemy_missile.position.x - ship.position.x,
1248 enemy_missile.position.y - ship.position.y))
1250 ship.explode_countdown = EXPLOSION_LENGTH;
1251 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1252 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1253 enemy_missile.survived = 0;
1254 enemy_missile.position.x = enemy_missile.position.y = 0;
1257 if(!ship_cant_be_placed)
1258 ship.waiting_for_space = false;
1260 /*if all asteroids cleared then start again:*/
1261 if(asteroid_count == 0 && !enemy_on_screen && !asteroids_onscreen)
1263 current_level++;
1264 game_state = SHOW_LEVEL;
1265 enemy.appear_probability += 5;
1266 enemy.appear_timing -= 200;
1267 if( enemy.appear_probability > 100)
1268 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1269 show_level_timeout = SHOW_LEVEL_TIME;
1273 /*************************************************
1274 ** Creates a new asteroid of the given 4type (size)
1275 ** and at the given location.
1276 *************************************************/
1277 void create_asteroid(enum asteroid_type type, int x, int y)
1279 struct Asteroid* asteroid;
1280 int n;
1282 asteroid = asteroids_array;
1283 n = MAX_NUM_ASTEROIDS;
1284 while(--n)
1286 if(!asteroid->exists && !asteroid->explode_countdown)
1288 initialise_asteroid(asteroid, type);
1289 asteroid->position.x = x;
1290 asteroid->position.y = y;
1291 break;
1293 asteroid++;
1297 /* Initialise a missile */
1298 void initialise_missile(struct Missile* missile)
1300 missile->position.x = ship.position.x + ship.vertices[0].x;
1301 missile->position.y = ship.position.y + ship.vertices[0].y;
1302 missile->position.dx = (ship.vertices[0].x - ship.vertices[2].x)/2;
1303 missile->position.dy = (ship.vertices[0].y - ship.vertices[2].y)/2;
1304 missile->survived = MISSILE_SURVIVAL_LENGTH;
1305 missile->oldpoint.x = missile->position.x;
1306 missile->oldpoint.y = missile->position.y;
1309 /* Draw and Move all the missiles */
1310 void draw_and_move_missiles(void)
1312 int n;
1313 int p1x, p1y;
1314 int p2x, p2y;
1316 struct Missile* missile;
1317 missile = missiles_array;
1319 SET_FG(COL_MISSILE);
1321 n = MAX_NUM_MISSILES;
1322 while(--n)
1324 if(missile->survived)
1326 if(missile->position.dx > 0)
1328 if(missile->position.x >= missile->oldpoint.x)
1330 p1x = missile->oldpoint.x;
1331 p2x = missile->position.x;
1333 else
1335 p1x = 0;
1336 p2x = missile->position.x;
1339 else
1341 if(missile->oldpoint.x >= missile->position.x)
1343 p1x = missile->oldpoint.x;
1344 p2x = missile->position.x;
1346 else
1348 p1x = missile->oldpoint.x;
1349 p2x = LCD_WIDTH;
1353 if(missile->position.dy > 0)
1355 if(missile->position.y >= missile->oldpoint.y)
1357 p1y = missile->oldpoint.y;
1358 p2y = missile->position.y;
1360 else
1362 p1y = 0;
1363 p2y = missile->position.y;
1366 else
1368 if(missile->oldpoint.y >= missile->position.y)
1370 p1y = missile->oldpoint.y;
1371 p2y = missile->position.y;
1373 else
1375 p1y = missile->oldpoint.y;
1376 p2y = LCD_HEIGHT;
1380 rb->lcd_drawline( p1x/SCALE, p1y/SCALE, p2x/SCALE, p2y/SCALE);
1382 if(game_state != PAUSE_MODE)
1384 missile->oldpoint.x = missile->position.x;
1385 missile->oldpoint.y = missile->position.y;
1386 move_point(&missile->position);
1387 missile->survived--;
1390 missile++;
1394 void draw_lives(void)
1396 int n;
1397 int px = (LCD_WIDTH - num_lives*4 - 1);
1398 #if(LARGE_LCD)
1399 int py = (LCD_HEIGHT-6);
1400 #else
1401 int py = (LCD_HEIGHT-4);
1402 #endif
1404 SET_FG(COL_PLAYER);
1406 n = num_lives;
1407 while(--n)
1409 draw_polygon(lives_points, px, py, NUM_SHIP_VERTICES);
1410 #if(LARGE_LCD)
1411 px += 8;
1412 #else
1413 px += 6;
1414 #endif
1418 /*Fire the next missile*/
1419 void fire_missile(void)
1421 int n;
1422 struct Missile* missile;
1424 if(!ship.explode_countdown && !ship.waiting_for_space)
1426 missile = missiles_array;
1427 n = MAX_NUM_MISSILES;
1428 while(--n)
1430 if(!missile->survived)
1432 initialise_missile(missile);
1433 break;
1435 missile++;
1440 /* Initialise the passed Asteroid */
1441 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type type)
1443 int n;
1444 bool b,b2;
1445 struct Point* point;
1446 asteroid->exists = true;
1447 asteroid->type = type;
1448 asteroid->explode_countdown = 0;
1450 /*Set the radius of the asteroid:*/
1451 asteroid->radius = (int)type*SCALE;
1453 /*shall we move Clockwise and Fast*/
1454 if((rb->rand()%100)>75)
1456 asteroid->speed_cos = FAST_ROT_CW_COS;
1457 asteroid->speed_sin = FAST_ROT_CW_SIN;
1459 else if((rb->rand()%100)>75)
1461 asteroid->speed_cos = FAST_ROT_ACW_COS;
1462 asteroid->speed_sin = FAST_ROT_ACW_SIN;
1464 else if((rb->rand()%100)>75)
1466 asteroid->speed_cos = SLOW_ROT_ACW_COS;
1467 asteroid->speed_sin = SLOW_ROT_ACW_SIN;
1469 else
1471 asteroid->speed_cos = SLOW_ROT_CW_COS;
1472 asteroid->speed_sin = SLOW_ROT_CW_SIN;
1475 b = (rb->rand()%100)>66;
1476 b2 = (rb->rand()%100)>66;
1477 point = asteroid->vertices;
1478 for(n = 0; n < NUM_ASTEROID_VERTICES*2; n+=2)
1480 if(b)
1482 point->x = asteroid_one[n];
1483 point->y = asteroid_one[n+1];
1485 else if( b2 )
1487 point->x = asteroid_two[n];
1488 point->y = asteroid_two[n+1];
1490 else
1492 point->x = asteroid_three[n];
1493 point->y = asteroid_three[n+1];
1496 point->x *= asteroid->radius/6;
1497 point->y *= asteroid->radius/6;
1498 point++;
1502 asteroid->radius += 6*SCALE;
1503 if(asteroid->type == SMALL)
1504 asteroid->radius /= 3;/*2*/
1505 else if(asteroid->type == LARGE)
1506 asteroid->radius += 3*SCALE;/*2*/
1507 b = true;
1508 while(b)
1510 /*Set the position randomly:*/
1511 asteroid->position.x = (rb->rand()%SCALED_WIDTH);
1512 asteroid->position.y = (rb->rand()%SCALED_HEIGHT);
1514 asteroid->position.dx = 0;
1515 while(asteroid->position.dx == 0)
1516 asteroid->position.dx = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1518 asteroid->position.dy = 0;
1519 while(asteroid->position.dy == 0)
1520 asteroid->position.dy = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1522 asteroid->position.dx *= SCALE/10;
1523 asteroid->position.dy *= SCALE/10;
1525 b = is_point_within_rectangle(&ship.position, &asteroid->position,
1526 space_check_size);
1529 /*Now rotate the asteroid a bit, so they all look a bit different*/
1530 for(n=(rb->rand()%30) + 2;--n;)
1531 rotate_asteroid(asteroid);
1533 /*great, we've created an asteroid, don't forget to increment the total:*/
1534 asteroid_count++;
1537 /*Initialise the ship*/
1538 void initialise_ship(void)
1540 struct Point* point;
1541 struct Point* lives_point;
1542 int n;
1544 ship.position.x = CENTER_LCD_X;
1545 ship.position.y = CENTER_LCD_Y;
1546 ship.position.x *= SCALE;
1547 ship.position.y *= SCALE;
1548 ship.position.dx = ship.position.dy = 0;
1550 point = ship.vertices;
1551 lives_point = lives_points;
1552 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1554 point->x = ship_vertices[n];
1555 point->y = ship_vertices[n+1];
1556 point->x *= SCALE;
1557 point->y *= SCALE;
1558 point++;
1559 lives_point++;
1562 ship.position.dx = 0;
1563 ship.position.dy = 0;
1564 ship.explode_countdown = 0;
1566 /*grab a copy of the ships points for the lives display:*/
1567 point = ship.vertices;
1568 lives_point = lives_points;
1569 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1571 lives_point->x = point->x;
1572 lives_point->y = point->y;
1573 lives_point++;
1574 point++;
1578 void rotate_asteroid(struct Asteroid* asteroid)
1580 struct Point* point;
1581 int n;
1582 long xtemp;
1584 point = asteroid->vertices;
1585 for(n = NUM_ASTEROID_VERTICES+1; --n;)
1587 xtemp = point->x;
1588 point->x = xtemp*asteroid->speed_cos/SIN_COS_SCALE -
1589 point->y*asteroid->speed_sin/SIN_COS_SCALE;
1590 point->y = point->y*asteroid->speed_cos/SIN_COS_SCALE +
1591 xtemp*asteroid->speed_sin/SIN_COS_SCALE;
1592 point++;
1596 /*************************************************
1597 ** Draws the ship, moves the ship and creates a new
1598 ** one if it's finished exploding.
1599 **************************************************/
1600 void draw_and_move_ship(void)
1602 int nxoffset = ship.position.x/SCALE;
1603 int nyoffset = ship.position.y/SCALE;
1604 SET_FG(COL_PLAYER);
1605 if(!ship.explode_countdown)
1607 if(!ship.waiting_for_space)
1609 draw_polygon(ship.vertices, nxoffset, nyoffset, NUM_SHIP_VERTICES);
1610 if(game_state != PAUSE_MODE && game_state != GAME_OVER)
1612 move_point(&ship.position);
1616 else
1618 /* animate_and_draw_explosion(ship.vertices, NUM_SHIP_VERTICES,
1619 ship.position.x/SCALE,
1620 ship.position.y/SCALE); */
1621 if(game_state != PAUSE_MODE)
1623 ship.explode_countdown--;
1624 if(!ship.explode_countdown)
1626 num_lives--;
1627 if(!num_lives)
1629 show_game_over = SHOW_GAME_OVER_TIME;
1630 game_state = GAME_OVER;
1632 else
1634 initialise_ship();
1635 ship.waiting_for_space = true;
1642 void thrust_ship(void)
1644 if(!ship.waiting_for_space)
1646 ship.position.dx += ( ship.vertices[0].x - ship.vertices[2].x )/20;
1647 ship.position.dy += ( ship.vertices[0].y - ship.vertices[2].y )/20;
1648 /*if dx and dy are below a certain threshold, then set 'em to 0
1649 but to do this we need to ascertain if the spacehip as moved on screen
1650 for more than a certain amount. */
1652 create_trail_blaze(THRUST_COLOUR, &ship.position);
1656 /**************************************************
1657 ** Rotate the ship using the passed sin & cos values
1658 ***************************************************/
1659 void rotate_ship(int c, int s)
1661 struct Point* point;
1662 int n;
1663 double xtemp;
1665 if(!ship.waiting_for_space && !ship.explode_countdown)
1667 point = ship.vertices;
1668 for(n=NUM_SHIP_VERTICES+1;--n;)
1670 xtemp = point->x;
1671 point->x = xtemp*c/SIN_COS_SCALE - point->y*s/SIN_COS_SCALE;
1672 point->y = point->y*c/SIN_COS_SCALE + xtemp*s/SIN_COS_SCALE;
1673 point++;
1678 void drawstars()
1680 struct Point* p;
1681 int n = NUM_STARS;
1683 p = stars;
1684 SET_FG(COL_STARS);
1686 while(--n)
1688 rb->lcd_drawpixel(p->x , p->y);
1689 p++;
1693 /*************************************************
1694 ** Draw And Move all Asteroids
1695 *************************************************/
1696 void draw_and_move_asteroids(void)
1698 int n;
1699 struct Asteroid* asteroid;
1701 asteroid = asteroids_array;
1702 SET_FG(COL_ASTEROID);
1704 n = MAX_NUM_ASTEROIDS;
1705 while(--n)
1707 if(game_state != PAUSE_MODE)
1709 if(asteroid->exists)
1711 move_point(&asteroid->position);
1712 rotate_asteroid(asteroid);
1713 draw_polygon(asteroid->vertices, asteroid->position.x/SCALE,
1714 asteroid->position.y/SCALE,
1715 NUM_ASTEROID_VERTICES);
1717 else if(asteroid->explode_countdown)
1719 /* animate_and_draw_explosion(asteroid->vertices,
1720 NUM_ASTEROID_VERTICES,
1721 asteroid->position.x/SCALE,
1722 asteroid->position.y/SCALE); */
1723 asteroid->explode_countdown--;
1726 else
1728 if(asteroid->exists)
1729 draw_polygon(asteroid->vertices,
1730 asteroid->position.x/SCALE,
1731 asteroid->position.y/SCALE,
1732 NUM_ASTEROID_VERTICES);
1734 asteroid++;
1738 void create_stars(void)
1740 struct TrailPoint* tpoint;
1741 struct Point* p;
1742 int n;
1744 p = stars;
1745 n = NUM_STARS;
1746 while(--n)
1748 p->x = (rb->rand()%LCD_WIDTH);
1749 p->y = (rb->rand()%LCD_HEIGHT);
1750 p++;
1754 /* give the point a random countdown timer, so they dissapears at different
1755 times */
1756 tpoint = trailPoints;
1757 n = NUM_TRAIL_POINTS;
1758 while(--n)
1760 tpoint->alive = 0;
1761 tpoint++;
1765 /*************************************************
1766 ** Creates start_num number of new asteroids of
1767 ** full size.
1768 **************************************************/
1769 void initialise_game(int start_num)
1771 int n;
1772 asteroid_count = next_missile_count = next_thrust_count = 0;
1773 struct Asteroid* asteroid;
1774 struct Missile* missile;
1775 extra_life = EXTRA_LIFE;
1777 /*no enemy*/
1778 enemy_on_screen = 0;
1779 enemy_missile.survived = 0;
1781 /*clear asteroids*/
1782 asteroid = asteroids_array;
1783 n = MAX_NUM_ASTEROIDS;
1784 while(--n)
1786 asteroid->exists = false;
1787 asteroid++;
1790 /*make some LARGE asteroids*/
1791 for(n = 0; n < start_num; n++)
1792 initialise_asteroid(&asteroids_array[n], LARGE);
1794 /*ensure all missiles are out of action: */
1795 missile = missiles_array;
1796 n = MAX_NUM_MISSILES;
1797 while(--n)
1799 missile->survived=0;
1800 missile++;
1804 void start_attract_mode(void)
1806 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1807 enemy.appear_timing = ENEMY_APPEAR_TIMING_START;
1808 current_level = 5;
1809 num_lives = START_LIVES;
1810 current_score = 0;
1811 attract_flip_timeout = ATTRACT_FLIP_TIME;
1812 game_state = ATTRACT_MODE;
1813 if(asteroid_count < 3)
1814 initialise_game(current_level);
1817 enum plugin_status start_game(void)
1819 char s[20];
1820 char level[10];
1821 int button;
1822 int end;
1823 int CYCLETIME = 30;
1825 /*create stars once, and once only:*/
1826 create_stars();
1828 SET_BG(LCD_BLACK);
1830 while(true)
1832 /*game starts with at level 1
1833 with 1 asteroid.*/
1834 start_attract_mode();
1836 /*Main loop*/
1837 while(true)
1839 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1840 rb->lcd_clear_display();
1841 SET_FG(COL_TEXT);
1842 switch(game_state)
1844 case(ATTRACT_MODE):
1845 if(attract_flip_timeout < ATTRACT_FLIP_TIME/2)
1847 rb->lcd_putsxy(CENTER_LCD_X - 39,
1848 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4,
1849 "Fire to Start");
1850 if(!attract_flip_timeout)
1851 attract_flip_timeout = ATTRACT_FLIP_TIME;
1853 else
1855 rb->snprintf(s, sizeof(s), "Hi Score %d ", high_score);
1856 rb->lcd_putsxy(CENTER_LCD_X - 30,
1857 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, s);
1859 attract_flip_timeout--;
1860 break;
1862 case(GAME_OVER):
1863 rb->lcd_putsxy(CENTER_LCD_X - 25,
1864 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "Game Over");
1865 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1866 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1867 show_game_over--;
1868 if(!show_game_over)
1869 start_attract_mode();
1870 break;
1872 case(PAUSE_MODE):
1873 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1874 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1875 rb->lcd_putsxy(CENTER_LCD_X - 15,
1876 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "pause");
1877 draw_and_move_missiles();
1878 draw_lives();
1879 draw_and_move_ship();
1880 break;
1882 case(PLAY_MODE):
1883 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1884 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1885 draw_and_move_missiles();
1886 draw_lives();
1887 check_collisions();
1888 draw_and_move_ship();
1889 break;
1891 case(SHOW_LEVEL):
1892 show_level_timeout--;
1893 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1894 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1895 rb->snprintf(level, sizeof(level), "stage %d ", current_level);
1896 rb->lcd_putsxy(CENTER_LCD_X - 20,
1897 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, level);
1898 draw_and_move_ship();
1899 draw_lives();
1900 if(!show_level_timeout)
1902 initialise_game(current_level);
1903 game_state = PLAY_MODE;
1904 draw_lives();
1906 break;
1908 draw_trail_blaze();
1909 drawstars();
1910 draw_and_move_asteroids();
1911 draw_and_move_enemy();
1913 rb->lcd_update();
1914 button = rb->button_get(false);
1916 #ifdef HAS_BUTTON_HOLD
1917 if (rb->button_hold())
1918 game_state = PAUSE_MODE;
1919 #endif
1921 switch(button)
1923 case(AST_PAUSE):
1924 if(game_state == PLAY_MODE)
1925 game_state = PAUSE_MODE;
1926 else if(game_state == PAUSE_MODE)
1927 game_state = PLAY_MODE;
1928 break;
1930 #ifdef AST_RC_QUIT
1931 case AST_RC_QUIT:
1932 #endif
1933 case(AST_QUIT):
1934 if(game_state == ATTRACT_MODE)
1935 return PLUGIN_OK;
1936 else if(game_state == GAME_OVER)
1938 start_attract_mode();
1940 else
1942 show_game_over = SHOW_GAME_OVER_TIME;
1943 game_state = GAME_OVER;
1945 break;
1947 case (AST_LEFT_REP):
1948 case (AST_LEFT):
1949 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1950 rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN);
1951 break;
1953 case (AST_RIGHT_REP):
1954 case (AST_RIGHT):
1955 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1956 rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN);
1957 break;
1959 case (AST_THRUST_REP):
1960 case (AST_THRUST):
1961 if((game_state == PLAY_MODE || game_state == SHOW_LEVEL) && !next_thrust_count)
1963 thrust_ship();
1964 next_thrust_count = 5;
1966 break;
1968 case (AST_HYPERSPACE):
1969 if(game_state == PLAY_MODE)
1970 hyperspace();
1971 /*maybe shield if it gets too hard */
1972 break;
1974 case (AST_FIRE_REP):
1975 case (AST_FIRE):
1976 if(game_state == ATTRACT_MODE)
1978 current_level = START_LEVEL;
1979 initialise_ship();
1980 initialise_game(current_level);
1981 show_level_timeout = SHOW_LEVEL_TIME;
1982 game_state = PLAY_MODE;
1984 else if(game_state == PLAY_MODE)
1986 if(!next_missile_count)
1988 fire_missile();
1989 next_missile_count = 10;
1992 else if(game_state == PAUSE_MODE)
1994 game_state = PLAY_MODE;
1996 break;
1998 default:
1999 if (rb->default_event_handler(button)==SYS_USB_CONNECTED)
2000 return PLUGIN_USB_CONNECTED;
2001 break;
2004 if(!num_lives)
2006 if(high_score < current_score)
2007 high_score = current_score;
2008 if(!show_game_over)
2009 break;
2012 if(next_missile_count)
2013 next_missile_count--;
2015 if(next_thrust_count)
2016 next_thrust_count--;
2018 if (end > *rb->current_tick)
2019 rb->sleep(end-*rb->current_tick);
2020 else
2021 rb->yield();
2027 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
2029 enum plugin_status retval;
2030 (void)(parameter);
2031 rb = api;
2033 game_state = ATTRACT_MODE;
2035 #if LCD_DEPTH > 1
2036 rb->lcd_set_backdrop(NULL);
2037 #endif
2038 /* universal font */
2039 rb->lcd_setfont(FONT_SYSFIXED);
2040 /* Turn off backlight timeout */
2041 backlight_force_on(rb); /* backlight control in lib/helper.c */
2042 iohiscore();
2043 retval = start_game();
2044 iohiscore();
2045 rb->lcd_setfont(FONT_UI);
2046 /* Turn on backlight timeout (revert to settings) */
2047 backlight_use_settings(rb); /* backlight control in lib/helper.c */
2048 return retval;