Fix yellow
[Rockbox.git] / apps / plugins / spacerocks.c
blob5c01c1680ff16b4a57d0cf917c987bea8403c23a
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 #elif (CONFIG_KEYPAD == COWOND2_PAD)
204 #define AST_PAUSE BUTTON_SELECT
205 #define AST_QUIT BUTTON_POWER
206 #define AST_THRUST_REP BUTTON_UP | BUTTON_MENU
207 #define AST_THRUST BUTTON_UP
208 #define AST_HYPERSPACE BUTTON_DOWN
209 #define AST_LEFT BUTTON_LEFT
210 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_MENU
211 #define AST_RIGHT BUTTON_RIGHT
212 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_MENU)
213 #define AST_FIRE BUTTON_PLUS
214 #define AST_FIRE_REP BUTTON_PLUS | BUTTON_MENU
216 #else
217 #error No keymap defined!
218 #endif
220 #define ABS(x) ((x)>0?(x):-(x))
222 #define RES MAX(LCD_WIDTH, LCD_HEIGHT)
223 #define LARGE_LCD RES >= 200
224 #define ENEMY_MISSILE_SURVIVAL_LENGTH RES/2
225 #define ASTEROID_SPEED RES/20
226 #define MISSILE_SURVIVAL_LENGTH 40
228 #define EXTRA_LIFE 250
229 #define SCALE 5000
230 #define MISSILE_SCALE 5000
231 #define WRAP_GAP 12
232 #define EXPLOSION_LENGTH 20
233 #define SHOW_COL 0
234 #define HISCORE_FILE PLUGIN_GAMES_DIR "/astrorocks.hs"
235 #define POINT_SIZE 2
236 #define MAX_NUM_ASTEROIDS 25
237 #define MAX_NUM_MISSILES 6
238 #define ENEMY_BIG_PROBABILITY_START 10
239 #define ENEMY_APPEAR_PROBABILITY_START 35
240 #define ENEMY_APPEAR_TIMING_START 1800
241 #define LITTLE_SHIP 2
242 #define BIG_SHIP 1
243 #define SHOW_GAME_OVER_TIME 100
244 #define SHOW_LEVEL_TIME 50
245 #define START_LIVES 3
246 #define START_LEVEL 1
247 #define NUM_ASTEROID_VERTICES 10
248 #define NUM_SHIP_VERTICES 4
249 #define NUM_ENEMY_VERTICES 6
250 #define MAX_LEVEL MAX_NUM_ASTEROIDS
251 #define ENEMY_SPEED 4
252 #define ENEMY_START_X 0
253 #define ENEMY_START_Y 0
254 #define SIZE_ENEMY_COLLISION 5*SCALE
255 #define ATTRACT_FLIP_TIME 100
256 #define NUM_STARS 50
257 #define NUM_TRAIL_POINTS 70
258 #define NUM_ROTATIONS 16
260 #define SIN_COS_SCALE 10000
262 #define FAST_ROT_CW_SIN 873
263 #define FAST_ROT_CW_COS 9963
264 #define FAST_ROT_ACW_SIN -873
265 #define FAST_ROT_ACW_COS 9963
267 #define MEDIUM_ROT_CW_SIN 350
268 #define MEDIUM_ROT_CW_COS 9994
269 #define MEDIUM_ROT_ACW_SIN -350
270 #define MEDIUM_ROT_ACW_COS 9994
272 #define SLOW_ROT_CW_SIN 350
273 #define SLOW_ROT_CW_COS 9994
274 #define SLOW_ROT_ACW_SIN - 350
275 #define SLOW_ROT_ACW_COS 9994
277 #ifdef HAVE_LCD_COLOR
278 #define SHIP_ROT_CW_SIN 2419
279 #define SHIP_ROT_CW_COS 9702
280 #define SHIP_ROT_ACW_SIN -2419
281 #define SHIP_ROT_ACW_COS 9702
282 #else
283 #define SHIP_ROT_CW_SIN 3827
284 #define SHIP_ROT_CW_COS 9239
285 #define SHIP_ROT_ACW_SIN -3827
286 #define SHIP_ROT_ACW_COS 9239
287 #endif
290 #define SCALED_WIDTH (LCD_WIDTH*SCALE)
291 #define SCALED_HEIGHT (LCD_HEIGHT*SCALE)
292 #define CENTER_LCD_X (LCD_WIDTH/2)
293 #define CENTER_LCD_Y (LCD_HEIGHT/2)
295 #define SHIP_EXPLOSION_COLOUR 1
296 #define ASTEROID_EXPLOSION_COLOUR 2
297 #define ENEMY_EXPLOSION_COLOUR 3
298 #define THRUST_COLOUR 4
300 #define ASTEROID_R 230
301 #define ASTEROID_G 200
302 #define ASTEROID_B 100
303 #define SHIP_R 255
304 #define SHIP_G 255
305 #define SHIP_B 255
306 #define ENEMY_R 50
307 #define ENEMY_G 220
308 #define ENEMY_B 50
309 #define THRUST_R 200
310 #define THRUST_G 200
311 #define THRUST_B 0
313 #ifdef HAVE_LCD_COLOR
314 #define COL_MISSILE LCD_RGBPACK(200,0,0)
315 #define COL_PLAYER LCD_RGBPACK(200,200,200)
316 #define COL_STARS LCD_WHITE
317 #define COL_ASTEROID LCD_RGBPACK(ASTEROID_R,ASTEROID_G,ASTEROID_B)
318 #define COL_TEXT LCD_RGBPACK(200,200,255)
319 #define COL_ENEMY LCD_RGBPACK(ENEMY_R,ENEMY_G,ENEMY_B)
320 #define SET_FG rb->lcd_set_foreground
321 #define SET_BG rb->lcd_set_background
322 #else
323 #define SET_FG(x)
324 #define SET_BG(x)
325 #endif
327 /* The array of points that make up an asteroid */
328 static const short asteroid_one[NUM_ASTEROID_VERTICES*2] =
330 -2, -12,
331 4, -8,
332 8, -14,
333 16, -5,
334 14, 0,
335 20, 2,
336 12, 14,
337 -4, 14,
338 -10, 6,
339 -10, -8
342 /* The array of points that make up an asteroid */
343 static const short asteroid_two[NUM_ASTEROID_VERTICES*2] =
345 -2, -12,
346 4, -16,
347 6, -14,
348 16, -8,
349 14, 0,
350 20, 2,
351 12, 14,
352 -4, 14,
353 -10, 6,
354 -10, -8
357 /* The array of points that make up an asteroid */
358 static const short asteroid_three[NUM_ASTEROID_VERTICES*2] =
360 -2, -12,
361 4, -16,
362 6, -14,
363 2, -8,
364 14, 0,
365 20, 2,
366 12, 14,
367 -4, 14,
368 -16, 6,
369 -10, -8
372 /* The array od points the make up the ship */
373 static const short ship_vertices[NUM_SHIP_VERTICES*2] =
375 #if(LARGE_LCD)
376 0,-6,
377 4, 6,
378 0, 2,
379 -4, 6
380 #else
381 0,-4,
382 3, 4,
383 0, 1,
384 -3, 4
385 #endif
388 /* The array of points the make up the bad spaceship */
389 static const short enemy_vertices[NUM_ENEMY_VERTICES*2] =
391 #if(LARGE_LCD)
392 -8, 0,
393 -4, 4,
394 4, 4,
395 8, 0,
396 4, -4,
397 -4, -4
398 #else
399 -5, 0,
400 -2, 2,
401 2, 2,
402 5, 0,
403 2, -2,
404 -2, -2
405 #endif
409 enum asteroid_type
411 #if(LARGE_LCD)
412 SMALL = 2,
413 MEDIUM = 4,
414 LARGE = 6,
415 #else
416 SMALL = 1,
417 MEDIUM = 2,
418 LARGE = 3,
419 #endif
423 enum game_state
425 GAME_OVER,
426 ATTRACT_MODE,
427 SHOW_LEVEL,
428 PLAY_MODE,
429 PAUSE_MODE
432 struct Point
434 int x;
435 int y;
436 int dx;
437 int dy;
440 struct TrailPoint
442 int alive;
443 struct Point position;
444 short r;
445 short g;
446 short b;
447 short dec;
450 /* Asteroid structure, contains an array of points */
451 struct Asteroid
453 enum asteroid_type type;
454 bool exists;
455 struct Point position;
456 struct Point vertices[NUM_ASTEROID_VERTICES];
457 int radius;
458 long speed_cos;
459 long speed_sin;
460 int explode_countdown;
463 struct Ship
465 struct Point vertices[NUM_SHIP_VERTICES];
466 struct Point position;
467 bool waiting_for_space;
468 int explode_countdown;
471 struct Enemy
473 struct Point vertices[NUM_ENEMY_VERTICES];
474 struct Point position;
475 int explode_countdown;
476 long last_time_appeared;
477 short size_probability;
478 short appear_probability;
479 short appear_timing;
482 struct Missile
484 struct Point position;
485 struct Point oldpoint;
486 int survived;
489 static enum game_state game_state;
490 static int asteroid_count;
491 static int next_missile_count;
492 static int next_thrust_count;
493 static int num_lives;
494 static int extra_life;
495 static int show_level_timeout;
496 static int attract_flip_timeout;
497 static int show_game_over;
498 static int current_level;
499 static int current_score;
500 static int high_score;
501 static int space_check_size = 30*SCALE;
503 static bool enemy_on_screen;
504 static char phscore[30];
505 static struct Ship ship;
506 static struct Point stars[NUM_STARS];
507 static struct Asteroid asteroids_array[MAX_NUM_ASTEROIDS];
508 static struct Missile missiles_array[MAX_NUM_MISSILES];
509 static struct Missile enemy_missile;
510 static struct Enemy enemy;
511 static struct Point lives_points[NUM_SHIP_VERTICES];
512 static struct TrailPoint trailPoints[NUM_TRAIL_POINTS];
514 void draw_and_move_asteroids(void);
515 void initialise_game(int nStartNum);
517 bool is_asteroid_near_ship(struct Asteroid* asteroid);
518 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point);
520 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type eType);
521 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices);
522 void rotate_asteroid(struct Asteroid* asteroid);
523 void create_asteroid(enum asteroid_type type, int x, int y);
524 void create_stars(void);
526 void initialise_ship(void);
527 void draw_and_move_ship(void);
528 void rotate_ship(int s, int c);
529 void thrust_ship(void);
531 void initialise_missile(struct Missile* missile);
532 void draw_and_move_missiles(void);
533 void fire_missile(void);
535 void animate_and_draw_explosion(struct Point* point, int num_points, int xoffset, int yoffset);
536 void initialise_explosion(struct Point* point, int num_points);
538 void move_point(struct Point* point);
539 void hyperspace(void);
540 void check_collisions(void);
541 void initialise_enemy(void);
542 void draw_and_move_enemy(void);
543 void draw_lives(void);
544 void drawstars(void);
545 bool is_ship_within_asteroid(struct Asteroid* asteroid);
549 /*Hi-Score reading and writing to file - this needs moving to the hi-score plugin lib as
550 a 3rd function */
551 void iohiscore(void)
553 int fd;
554 int compare;
556 /* clear the buffer we're about to load the highscore data into */
557 rb->memset(phscore, 0, sizeof(phscore));
559 fd = rb->open(HISCORE_FILE,O_RDWR | O_CREAT);
560 if(fd < 0)
562 rb->splash(HZ, "Highscore file read error");
563 return;
566 /* highscore used to %d, is now %d\n
567 Deal with no file or bad file */
568 rb->read(fd,phscore, sizeof(phscore));
570 compare = rb->atoi(phscore);
572 if(high_score > compare)
574 rb->lseek(fd,0,SEEK_SET);
575 rb->fdprintf(fd, "%d\n", high_score);
577 else
578 high_score = compare;
580 rb->close(fd);
583 bool point_in_poly(struct Point* _point, int num_vertices, int x, int y)
585 struct Point* pi;
586 struct Point* pj;
587 int n;
588 bool c = false;
590 pi = _point;
591 pj = _point;
592 pj += num_vertices-1;
594 n = num_vertices;
595 while(n--)
597 if((((pi->y <= y) && (y < pj->y)) || ((pj->y <= y) && (y < pi->y))) &&
598 (x < (pj->x - pi->x) * (y - pi->y) / (pj->y - pi->y) + pi->x))
599 c = !c;
601 if(n == num_vertices - 1)
602 pj = _point;
603 else
604 pj++;
606 pi++;
609 return c;
612 void move_point(struct Point* point)
614 point->x += point->dx;
615 point->y += point->dy;
617 /*check bounds on the x-axis:*/
618 if(point->x >= SCALED_WIDTH)
619 point->x = 0;
620 else if(point->x <= 0)
621 point->x = SCALED_WIDTH;
623 /*Check bounds on the y-axis:*/
624 if(point->y >= SCALED_HEIGHT)
625 point->y = 0;
626 else if(point->y <= 0)
627 point->y = SCALED_HEIGHT;
630 void create_trail(struct TrailPoint* tpoint)
632 tpoint->position.dx = -( ship.vertices[0].x - ship.vertices[2].x )/10;
633 tpoint->position.dy = -( ship.vertices[0].y - ship.vertices[2].y )/10;
636 void create_explosion_trail(struct TrailPoint* tpoint)
638 tpoint->position.dx = (rb->rand()%5050)-2500;
639 tpoint->position.dy = (rb->rand()%5050)-2500;
642 void create_trail_blaze(int colour, struct Point* position)
644 int numtoadd;
645 struct TrailPoint* tpoint;
646 int n;
647 int xadd,yadd;
648 if(colour != SHIP_EXPLOSION_COLOUR)
650 numtoadd = NUM_TRAIL_POINTS/5;
651 xadd = position->x;
652 yadd = position->y;
654 else
656 numtoadd = NUM_TRAIL_POINTS/8;
657 xadd = ship.position.x;
658 yadd = ship.position.y;
661 /* give the point a random countdown timer, so they dissapears at different times */
662 tpoint = trailPoints;
663 n = NUM_TRAIL_POINTS;
664 while(--n)
666 if(tpoint->alive <= 0 && numtoadd)
668 numtoadd--;
669 /* take a random x point anywhere between bottom two points of ship. */
670 /* ship.position.x; */
671 tpoint->position.x = (ship.vertices[2].x + (rb->rand()%18000)-9000) + position->x;
672 tpoint->position.y = (ship.vertices[2].y + (rb->rand()%18000)-9000) + position->y;
674 switch(colour)
676 case SHIP_EXPLOSION_COLOUR:
677 tpoint->r = 255;
678 tpoint->g = 255;
679 tpoint->b = 255;
680 create_explosion_trail(tpoint);
681 tpoint->alive = 510;
682 tpoint->dec = 2;
683 break;
684 case ASTEROID_EXPLOSION_COLOUR:
685 tpoint->r = ASTEROID_R;
686 tpoint->g = ASTEROID_G;
687 tpoint->b = ASTEROID_B;
688 create_explosion_trail(tpoint);
689 tpoint->alive = 510;
690 tpoint->dec = 2;
691 break;
692 case ENEMY_EXPLOSION_COLOUR:
693 tpoint->r = ENEMY_R;
694 tpoint->g = ENEMY_G;
695 tpoint->b = ENEMY_B;
696 create_explosion_trail(tpoint);
697 tpoint->alive = 510;
698 tpoint->dec = 2;
699 break;
700 case THRUST_COLOUR:
701 tpoint->r = THRUST_R;
702 tpoint->g = THRUST_G;
703 tpoint->b = THRUST_B;
704 create_trail(tpoint);
705 tpoint->alive = 175;
706 tpoint->dec = 4;
707 break;
709 /* add a proportional bit to the x and y based on dx and dy */
711 /* give the points a speed based on direction of travel - i.e. opposite */
712 tpoint->position.dx += position->dx;
713 tpoint->position.dy += position->dy;
717 tpoint++;
719 /* find a space in the array of trail_points that is NULL or DEAD or whatever.
720 and place this one here. */
724 void draw_trail_blaze(void)
726 struct TrailPoint* tpoint;
727 /* loop through, if alive then move and draw.
728 when drawn, countdown it's timer.
729 if zero kill it! */
730 tpoint = trailPoints;
731 int n = NUM_TRAIL_POINTS;
733 while(--n)
735 if(tpoint->alive)
737 if(game_state != PAUSE_MODE)
739 tpoint->alive-=10;
740 move_point(&(tpoint->position));
742 #ifdef HAVE_LCD_COLOR
743 /* intensity = tpoint->alive/2; */
744 if(tpoint->r>0)tpoint->r-=tpoint->dec;
745 if(tpoint->g>0)tpoint->g-=tpoint->dec;
746 if(tpoint->b>0)tpoint->b-=tpoint->dec;
747 SET_FG(LCD_RGBPACK(tpoint->r, tpoint->g, tpoint->b));
748 #endif
749 rb->lcd_drawpixel(tpoint->position.x/SCALE , tpoint->position.y/SCALE);
751 tpoint++;
755 /*Check if point is within a rectangle*/
756 bool is_point_within_rectangle(struct Point* rect, struct Point* p, int size)
758 #if SHOW_COL
759 int aTLx = rect->x - size;
760 int aTLy = rect->y - size;
761 int aBRx = rect->x + size;
762 int aBRy = rect->y + size;
763 rb->lcd_drawline( aTLx/SCALE, aTLy/SCALE, aBRx/SCALE, aTLy/SCALE);
764 rb->lcd_drawline( aTLx/SCALE, aTLy/SCALE, aTLx/SCALE, aBRy/SCALE);
765 rb->lcd_drawline( aTLx/SCALE, aBRy/SCALE, aBRx/SCALE, aBRy/SCALE);
766 rb->lcd_drawline( aBRx/SCALE, aBRy/SCALE, aBRx/SCALE, aTLy/SCALE);
767 return (p->x > aTLx && p->x < aBRx && p->y > aTLy && p->y < aBRy);
768 #else
769 return (p->x > rect->x - size && p->x < rect->x + size &&
770 p->y > rect->y - size && p->y < rect->y + size);
771 #endif
774 /* Draw polygon */
775 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices)
777 int n, t1, t2, oldX, oldY;
778 struct Point *p;
779 bool bDrawAll = px < WRAP_GAP || LCD_WIDTH - px < WRAP_GAP ||
780 py < WRAP_GAP || LCD_HEIGHT - py < WRAP_GAP;
782 p = vertices;
783 p += num_vertices-1;
784 oldX = p->x/SCALE + px;
785 oldY = p->y/SCALE + py;
786 p = vertices;
787 for(n = num_vertices+1; --n;)
789 t1 = p->x/SCALE + px;
790 t2 = p->y/SCALE + py;
792 rb->lcd_drawline(oldX, oldY, t1, t2);
794 if(bDrawAll)
796 rb->lcd_drawline(oldX - LCD_WIDTH, oldY, t1 - LCD_WIDTH, t2);
797 rb->lcd_drawline(oldX + LCD_WIDTH, oldY, t1 + LCD_WIDTH, t2);
798 rb->lcd_drawline(oldX - LCD_WIDTH, oldY + LCD_HEIGHT,
799 t1 - LCD_WIDTH, t2 + LCD_HEIGHT);
800 rb->lcd_drawline(oldX + LCD_WIDTH, oldY + LCD_HEIGHT,
801 t1 + LCD_WIDTH, t2 + LCD_HEIGHT);
803 rb->lcd_drawline(oldX, oldY - LCD_HEIGHT, t1, t2 - LCD_HEIGHT);
804 rb->lcd_drawline(oldX, oldY + LCD_HEIGHT, t1, t2 + LCD_HEIGHT);
805 rb->lcd_drawline(oldX - LCD_WIDTH, oldY - LCD_HEIGHT,
806 t1 - LCD_WIDTH, t2 - LCD_HEIGHT);
807 rb->lcd_drawline(oldX + LCD_WIDTH, oldY - LCD_HEIGHT,
808 t1 + LCD_WIDTH, t2 - LCD_HEIGHT);
810 oldX = t1;
811 oldY = t2;
812 p++;
816 void animate_and_draw_explosion(struct Point* point, int num_points,
817 int xoffset, int yoffset)
819 int n;
820 for(n = num_points; --n;)
822 if(game_state != PAUSE_MODE)
824 point->x += point->dx;
825 point->y += point->dy;
827 rb->lcd_fillrect( point->x/SCALE + xoffset, point->y/SCALE + yoffset,
828 POINT_SIZE, POINT_SIZE);
829 point++;
833 /*stop movement of ship, 'cos that's what happens when you go into hyperspace.*/
834 void hyperspace(void)
836 ship.position.dx = ship.position.dy = 0;
837 ship.position.x = (rb->rand()%SCALED_WIDTH);
838 ship.position.y = (rb->rand()%SCALED_HEIGHT);
841 void initialise_enemy(void)
843 struct Point* point;
844 int n;
845 int size;
847 if(rb->rand()%100 > enemy.size_probability)
849 size = BIG_SHIP;
850 enemy.size_probability++;
851 if(enemy.size_probability < 90)
853 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
856 else
858 size = LITTLE_SHIP;
861 enemy_missile.survived = 0;
862 enemy_on_screen = true;
863 enemy.explode_countdown = 0;
864 enemy.last_time_appeared = *rb->current_tick;
865 point = enemy.vertices;
866 for(n = 0; n < NUM_ENEMY_VERTICES+NUM_ENEMY_VERTICES; n+=2)
868 point->x = enemy_vertices[n];
869 point->y = enemy_vertices[n+1];
870 point->x *= SCALE/size;
871 point->y *= SCALE/size;
872 point++;
875 if(ship.position.x >= SCALED_WIDTH/2)
877 enemy.position.dx = ENEMY_SPEED;
878 enemy.position.x = 0;
880 else
882 enemy.position.dx = -ENEMY_SPEED;
883 enemy.position.x = SCALED_WIDTH;
886 if(ship.position.y >= SCALED_HEIGHT/2)
888 enemy.position.dy = ENEMY_SPEED;
889 enemy.position.y = 0;
891 else
893 enemy.position.dy = -ENEMY_SPEED;
894 enemy.position.y = SCALED_HEIGHT;
897 enemy.position.dx *= SCALE/10;
898 enemy.position.dy *= SCALE/10;
901 void draw_and_move_enemy(void)
903 int enemy_x, enemy_y;
904 struct Point *point;
906 SET_FG(COL_ENEMY);
908 if(enemy_on_screen)
910 enemy_x = enemy.position.x/SCALE;
911 enemy_y = enemy.position.y/SCALE;
912 if(!enemy.explode_countdown)
914 point = enemy.vertices;
915 draw_polygon(enemy.vertices, enemy_x, enemy_y, NUM_ENEMY_VERTICES);
916 rb->lcd_drawline(enemy.vertices[0].x/SCALE + enemy_x,
917 enemy.vertices[0].y/SCALE + enemy_y,
918 enemy.vertices[3].x/SCALE + enemy_x,
919 enemy.vertices[3].y/SCALE + enemy_y);
921 if(game_state != PAUSE_MODE)
923 enemy.position.x += enemy.position.dx;
924 enemy.position.y += enemy.position.dy;
927 if(enemy.position.x > SCALED_WIDTH || enemy.position.x < 0)
928 enemy_on_screen = false;
930 if(enemy.position.y > SCALED_HEIGHT)
931 enemy.position.y = 0;
932 else if(enemy.position.y < 0)
933 enemy.position.y = SCALED_HEIGHT;
935 if( (rb->rand()%1000) < 10)
936 enemy.position.dy = -enemy.position.dy;
938 else
941 /* animate_and_draw_explosion(enemy.vertices, NUM_ENEMY_VERTICES,
942 enemy_x, enemy.position.y/SCALE); */
943 if(game_state != PAUSE_MODE)
945 enemy.explode_countdown--;
946 if(!enemy.explode_countdown)
947 enemy_on_screen = false;
951 else
953 if( (*rb->current_tick - enemy.last_time_appeared) > enemy.appear_timing)
954 if(rb->rand()%100 > enemy.appear_probability) initialise_enemy();
957 if(!enemy_missile.survived && game_state != GAME_OVER)
959 /*if no missile and the enemy is here and not exploding..then shoot baby!*/
960 if( !enemy.explode_countdown && enemy_on_screen &&
961 !ship.waiting_for_space && (rb->rand()%10) > 5 )
963 enemy_missile.position.x = enemy.position.x;
964 enemy_missile.position.y = enemy.position.y;
966 /*lame, needs to be sorted - it's trying to shoot at the ship*/
967 if(ABS(enemy.position.y - ship.position.y) <= 5*SCALE)
969 enemy_missile.position.dy = 0;
971 else
973 if( enemy.position.y < ship.position.y)
974 enemy_missile.position.dy = 1;
975 else
976 enemy_missile.position.dy = -1;
979 if(ABS(enemy.position.x - ship.position.x) <= 5*SCALE)
980 enemy_missile.position.dx = 0;
981 else
983 if( enemy.position.x < ship.position.x)
984 enemy_missile.position.dx = 1;
985 else
986 enemy_missile.position.dx = -1;
989 if(enemy_missile.position.dx == 0 &&
990 enemy_missile.position.dy == 0)
991 enemy_missile.position.dx = enemy_missile.position.dy = -1;
993 enemy_missile.position.dx *= SCALE;
994 enemy_missile.position.dy *= SCALE;
995 enemy_missile.survived = ENEMY_MISSILE_SURVIVAL_LENGTH;
999 else
1001 rb->lcd_fillrect( enemy_missile.position.x/SCALE,
1002 enemy_missile.position.y/SCALE,
1003 POINT_SIZE, POINT_SIZE);
1004 if(game_state != PAUSE_MODE)
1006 move_point(&enemy_missile.position);
1007 enemy_missile.survived--;
1012 /******************
1013 * Lame method of collision
1014 * detection. It's checking for collision
1015 * between point and a big rectangle around the asteroid...
1016 *******************/
1017 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point)
1019 if( !is_point_within_rectangle(&asteroid->position, point,
1020 asteroid->radius+4*SCALE) )
1021 return false;
1023 if(point_in_poly(asteroid->vertices, NUM_ASTEROID_VERTICES,
1024 point->x - asteroid->position.x,
1025 point->y - asteroid->position.y))
1027 switch(asteroid->type)
1029 case(SMALL):
1030 asteroid->explode_countdown = EXPLOSION_LENGTH;
1031 create_trail_blaze(ASTEROID_EXPLOSION_COLOUR, &asteroid->position);
1032 break;
1034 case(LARGE):
1035 create_asteroid(MEDIUM, asteroid->position.x,
1036 asteroid->position.y);
1037 create_asteroid(MEDIUM, asteroid->position.x,
1038 asteroid->position.y);
1039 break;
1041 case(MEDIUM):
1042 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1043 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1044 break;
1047 current_score++;
1048 if(current_score > extra_life)
1050 num_lives++;
1051 extra_life = current_score+EXTRA_LIFE;
1053 asteroid_count--;
1054 asteroid->exists = false;
1055 return true;
1057 else
1058 return false;
1061 bool is_point_within_enemy(struct Point* point)
1063 if( is_point_within_rectangle(&enemy.position, point, 7*SCALE) )
1065 current_score += 5;
1066 /*enemy_missile.survived = 0;*/
1067 enemy.explode_countdown = EXPLOSION_LENGTH;
1068 /* initialise_explosion(enemy.vertices, NUM_ENEMY_VERTICES); */
1069 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1070 return true;
1072 else
1073 return false;
1076 bool is_ship_within_asteroid(struct Asteroid* asteroid)
1078 bool hit = false;
1079 struct Point p;
1081 p.x = ship.position.x + ship.vertices[0].x;
1082 p.y = ship.position.y + ship.vertices[0].y;
1083 hit |= is_point_within_asteroid(asteroid, &p);
1085 if(!hit)
1087 p.x = ship.position.x + ship.vertices[1].x;
1088 p.y = ship.position.y + ship.vertices[1].y;
1089 hit |= is_point_within_asteroid(asteroid, &p);
1090 if(!hit)
1092 p.x = ship.position.x + ship.vertices[3].x;
1093 p.y = ship.position.y + ship.vertices[3].y;
1094 hit |= is_point_within_asteroid(asteroid, &p);
1098 return hit;
1101 void initialise_explosion(struct Point* point, int num_points)
1103 int n;
1105 point->x += point->dx;
1106 point->y += point->dy;
1107 for(n = num_points; --n;)
1109 point->dx = point->x;
1110 point->dy = point->y;
1111 point++;
1116 /* Check for collsions between the missiles and the asteroids and the ship */
1117 void check_collisions(void)
1119 int m, n;
1120 bool asteroids_onscreen = false;
1121 struct Missile* missile;
1122 struct Asteroid* asteroid;
1123 bool ship_cant_be_placed = false;
1125 asteroid = asteroids_array;
1126 m = MAX_NUM_ASTEROIDS;
1127 while(--m)
1129 /*if the asteroids exists then test missile collision:*/
1130 if(asteroid->exists)
1132 missile = missiles_array;
1133 n = MAX_NUM_MISSILES;
1134 while(--n)
1136 /*if the missiles exists:*/
1137 if(missile->survived > 0)
1139 /*has the missile hit the asteroid?*/
1140 if(is_point_within_asteroid(asteroid, &missile->position)
1141 || is_point_within_asteroid(asteroid,
1142 &missile->oldpoint))
1144 missile->survived = 0;
1145 break;
1148 missile++;
1151 /*now check collision with ship:*/
1152 if(asteroid->exists && !ship.waiting_for_space && !ship.explode_countdown)
1154 if(is_ship_within_asteroid(asteroid))
1156 /*blow up ship*/
1157 ship.explode_countdown = EXPLOSION_LENGTH;
1158 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1159 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1162 /*has the enemy missile blown something up?*/
1163 if(asteroid->exists && enemy_missile.survived)
1165 if(is_point_within_asteroid(asteroid, &enemy_missile.position))
1167 /*take that score back then:*/
1168 if(current_score > 0) current_score--;
1169 enemy_missile.survived = 0;
1172 /*if it still exists, check if ship is waiting for space:*/
1173 if(asteroid->exists && ship.waiting_for_space)
1174 ship_cant_be_placed |=
1175 is_point_within_rectangle(&ship.position,
1176 &asteroid->position,
1177 space_check_size);
1181 /*is an asteroid still exploding?*/
1182 if(asteroid->explode_countdown)
1183 asteroids_onscreen = true;
1185 asteroid++;
1188 /*now check collision between ship and enemy*/
1189 if(enemy_on_screen && !ship.waiting_for_space &&
1190 !ship.explode_countdown && !enemy.explode_countdown)
1192 /*has the enemy collided with the ship?*/
1193 if(is_point_within_enemy(&ship.position))
1195 ship.explode_countdown = EXPLOSION_LENGTH;
1196 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1197 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1198 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1201 /*Now see if the enemy has been shot at by the ships missiles:*/
1202 missile = missiles_array;
1203 n = MAX_NUM_MISSILES;
1204 while(--n)
1206 if(missile->survived > 0 &&
1207 is_point_within_enemy(&missile->position))
1209 missile->survived = 0;
1210 break;
1212 missile++;
1216 /*test collision with enemy missile and ship:*/
1217 if(!ship_cant_be_placed && enemy_missile.survived > 0 &&
1218 point_in_poly(ship.vertices, NUM_SHIP_VERTICES,
1219 enemy_missile.position.x - ship.position.x,
1220 enemy_missile.position.y - ship.position.y))
1222 ship.explode_countdown = EXPLOSION_LENGTH;
1223 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1224 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1225 enemy_missile.survived = 0;
1226 enemy_missile.position.x = enemy_missile.position.y = 0;
1229 if(!ship_cant_be_placed)
1230 ship.waiting_for_space = false;
1232 /*if all asteroids cleared then start again:*/
1233 if(asteroid_count == 0 && !enemy_on_screen && !asteroids_onscreen)
1235 current_level++;
1236 game_state = SHOW_LEVEL;
1237 enemy.appear_probability += 5;
1238 enemy.appear_timing -= 200;
1239 if( enemy.appear_probability > 100)
1240 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1241 show_level_timeout = SHOW_LEVEL_TIME;
1245 /*************************************************
1246 ** Creates a new asteroid of the given 4type (size)
1247 ** and at the given location.
1248 *************************************************/
1249 void create_asteroid(enum asteroid_type type, int x, int y)
1251 struct Asteroid* asteroid;
1252 int n;
1254 asteroid = asteroids_array;
1255 n = MAX_NUM_ASTEROIDS;
1256 while(--n)
1258 if(!asteroid->exists && !asteroid->explode_countdown)
1260 initialise_asteroid(asteroid, type);
1261 asteroid->position.x = x;
1262 asteroid->position.y = y;
1263 break;
1265 asteroid++;
1269 /* Initialise a missile */
1270 void initialise_missile(struct Missile* missile)
1272 missile->position.x = ship.position.x + ship.vertices[0].x;
1273 missile->position.y = ship.position.y + ship.vertices[0].y;
1274 missile->position.dx = (ship.vertices[0].x - ship.vertices[2].x)/2;
1275 missile->position.dy = (ship.vertices[0].y - ship.vertices[2].y)/2;
1276 missile->survived = MISSILE_SURVIVAL_LENGTH;
1277 missile->oldpoint.x = missile->position.x;
1278 missile->oldpoint.y = missile->position.y;
1281 /* Draw and Move all the missiles */
1282 void draw_and_move_missiles(void)
1284 int n;
1285 int p1x, p1y;
1286 int p2x, p2y;
1288 struct Missile* missile;
1289 missile = missiles_array;
1291 SET_FG(COL_MISSILE);
1293 n = MAX_NUM_MISSILES;
1294 while(--n)
1296 if(missile->survived)
1298 if(missile->position.dx > 0)
1300 if(missile->position.x >= missile->oldpoint.x)
1302 p1x = missile->oldpoint.x;
1303 p2x = missile->position.x;
1305 else
1307 p1x = 0;
1308 p2x = missile->position.x;
1311 else
1313 if(missile->oldpoint.x >= missile->position.x)
1315 p1x = missile->oldpoint.x;
1316 p2x = missile->position.x;
1318 else
1320 p1x = missile->oldpoint.x;
1321 p2x = LCD_WIDTH;
1325 if(missile->position.dy > 0)
1327 if(missile->position.y >= missile->oldpoint.y)
1329 p1y = missile->oldpoint.y;
1330 p2y = missile->position.y;
1332 else
1334 p1y = 0;
1335 p2y = missile->position.y;
1338 else
1340 if(missile->oldpoint.y >= missile->position.y)
1342 p1y = missile->oldpoint.y;
1343 p2y = missile->position.y;
1345 else
1347 p1y = missile->oldpoint.y;
1348 p2y = LCD_HEIGHT;
1352 rb->lcd_drawline( p1x/SCALE, p1y/SCALE, p2x/SCALE, p2y/SCALE);
1354 if(game_state != PAUSE_MODE)
1356 missile->oldpoint.x = missile->position.x;
1357 missile->oldpoint.y = missile->position.y;
1358 move_point(&missile->position);
1359 missile->survived--;
1362 missile++;
1366 void draw_lives(void)
1368 int n;
1369 int px = (LCD_WIDTH - num_lives*4 - 1);
1370 #if(LARGE_LCD)
1371 int py = (LCD_HEIGHT-6);
1372 #else
1373 int py = (LCD_HEIGHT-4);
1374 #endif
1376 SET_FG(COL_PLAYER);
1378 n = num_lives;
1379 while(--n)
1381 draw_polygon(lives_points, px, py, NUM_SHIP_VERTICES);
1382 #if(LARGE_LCD)
1383 px += 8;
1384 #else
1385 px += 6;
1386 #endif
1390 /*Fire the next missile*/
1391 void fire_missile(void)
1393 int n;
1394 struct Missile* missile;
1396 if(!ship.explode_countdown && !ship.waiting_for_space)
1398 missile = missiles_array;
1399 n = MAX_NUM_MISSILES;
1400 while(--n)
1402 if(!missile->survived)
1404 initialise_missile(missile);
1405 break;
1407 missile++;
1412 /* Initialise the passed Asteroid */
1413 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type type)
1415 int n;
1416 bool b,b2;
1417 struct Point* point;
1418 asteroid->exists = true;
1419 asteroid->type = type;
1420 asteroid->explode_countdown = 0;
1422 /*Set the radius of the asteroid:*/
1423 asteroid->radius = (int)type*SCALE;
1425 /*shall we move Clockwise and Fast*/
1426 if((rb->rand()%100)>75)
1428 asteroid->speed_cos = FAST_ROT_CW_COS;
1429 asteroid->speed_sin = FAST_ROT_CW_SIN;
1431 else if((rb->rand()%100)>75)
1433 asteroid->speed_cos = FAST_ROT_ACW_COS;
1434 asteroid->speed_sin = FAST_ROT_ACW_SIN;
1436 else if((rb->rand()%100)>75)
1438 asteroid->speed_cos = SLOW_ROT_ACW_COS;
1439 asteroid->speed_sin = SLOW_ROT_ACW_SIN;
1441 else
1443 asteroid->speed_cos = SLOW_ROT_CW_COS;
1444 asteroid->speed_sin = SLOW_ROT_CW_SIN;
1447 b = (rb->rand()%100)>66;
1448 b2 = (rb->rand()%100)>66;
1449 point = asteroid->vertices;
1450 for(n = 0; n < NUM_ASTEROID_VERTICES*2; n+=2)
1452 if(b)
1454 point->x = asteroid_one[n];
1455 point->y = asteroid_one[n+1];
1457 else if( b2 )
1459 point->x = asteroid_two[n];
1460 point->y = asteroid_two[n+1];
1462 else
1464 point->x = asteroid_three[n];
1465 point->y = asteroid_three[n+1];
1468 point->x *= asteroid->radius/6;
1469 point->y *= asteroid->radius/6;
1470 point++;
1474 asteroid->radius += 6*SCALE;
1475 if(asteroid->type == SMALL)
1476 asteroid->radius /= 3;/*2*/
1477 else if(asteroid->type == LARGE)
1478 asteroid->radius += 3*SCALE;/*2*/
1479 b = true;
1480 while(b)
1482 /*Set the position randomly:*/
1483 asteroid->position.x = (rb->rand()%SCALED_WIDTH);
1484 asteroid->position.y = (rb->rand()%SCALED_HEIGHT);
1486 asteroid->position.dx = 0;
1487 while(asteroid->position.dx == 0)
1488 asteroid->position.dx = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1490 asteroid->position.dy = 0;
1491 while(asteroid->position.dy == 0)
1492 asteroid->position.dy = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1494 asteroid->position.dx *= SCALE/10;
1495 asteroid->position.dy *= SCALE/10;
1497 b = is_point_within_rectangle(&ship.position, &asteroid->position,
1498 space_check_size);
1501 /*Now rotate the asteroid a bit, so they all look a bit different*/
1502 for(n=(rb->rand()%30) + 2;--n;)
1503 rotate_asteroid(asteroid);
1505 /*great, we've created an asteroid, don't forget to increment the total:*/
1506 asteroid_count++;
1509 /*Initialise the ship*/
1510 void initialise_ship(void)
1512 struct Point* point;
1513 struct Point* lives_point;
1514 int n;
1516 ship.position.x = CENTER_LCD_X;
1517 ship.position.y = CENTER_LCD_Y;
1518 ship.position.x *= SCALE;
1519 ship.position.y *= SCALE;
1520 ship.position.dx = ship.position.dy = 0;
1522 point = ship.vertices;
1523 lives_point = lives_points;
1524 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1526 point->x = ship_vertices[n];
1527 point->y = ship_vertices[n+1];
1528 point->x *= SCALE;
1529 point->y *= SCALE;
1530 point++;
1531 lives_point++;
1534 ship.position.dx = 0;
1535 ship.position.dy = 0;
1536 ship.explode_countdown = 0;
1538 /*grab a copy of the ships points for the lives display:*/
1539 point = ship.vertices;
1540 lives_point = lives_points;
1541 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1543 lives_point->x = point->x;
1544 lives_point->y = point->y;
1545 lives_point++;
1546 point++;
1550 void rotate_asteroid(struct Asteroid* asteroid)
1552 struct Point* point;
1553 int n;
1554 long xtemp;
1556 point = asteroid->vertices;
1557 for(n = NUM_ASTEROID_VERTICES+1; --n;)
1559 xtemp = point->x;
1560 point->x = xtemp*asteroid->speed_cos/SIN_COS_SCALE -
1561 point->y*asteroid->speed_sin/SIN_COS_SCALE;
1562 point->y = point->y*asteroid->speed_cos/SIN_COS_SCALE +
1563 xtemp*asteroid->speed_sin/SIN_COS_SCALE;
1564 point++;
1568 /*************************************************
1569 ** Draws the ship, moves the ship and creates a new
1570 ** one if it's finished exploding.
1571 **************************************************/
1572 void draw_and_move_ship(void)
1574 int nxoffset = ship.position.x/SCALE;
1575 int nyoffset = ship.position.y/SCALE;
1576 SET_FG(COL_PLAYER);
1577 if(!ship.explode_countdown)
1579 if(!ship.waiting_for_space)
1581 draw_polygon(ship.vertices, nxoffset, nyoffset, NUM_SHIP_VERTICES);
1582 if(game_state != PAUSE_MODE && game_state != GAME_OVER)
1584 move_point(&ship.position);
1588 else
1590 /* animate_and_draw_explosion(ship.vertices, NUM_SHIP_VERTICES,
1591 ship.position.x/SCALE,
1592 ship.position.y/SCALE); */
1593 if(game_state != PAUSE_MODE)
1595 ship.explode_countdown--;
1596 if(!ship.explode_countdown)
1598 num_lives--;
1599 if(!num_lives)
1601 show_game_over = SHOW_GAME_OVER_TIME;
1602 game_state = GAME_OVER;
1604 else
1606 initialise_ship();
1607 ship.waiting_for_space = true;
1614 void thrust_ship(void)
1616 if(!ship.waiting_for_space)
1618 ship.position.dx += ( ship.vertices[0].x - ship.vertices[2].x )/20;
1619 ship.position.dy += ( ship.vertices[0].y - ship.vertices[2].y )/20;
1620 /*if dx and dy are below a certain threshold, then set 'em to 0
1621 but to do this we need to ascertain if the spacehip as moved on screen
1622 for more than a certain amount. */
1624 create_trail_blaze(THRUST_COLOUR, &ship.position);
1628 /**************************************************
1629 ** Rotate the ship using the passed sin & cos values
1630 ***************************************************/
1631 void rotate_ship(int c, int s)
1633 struct Point* point;
1634 int n;
1635 double xtemp;
1637 if(!ship.waiting_for_space && !ship.explode_countdown)
1639 point = ship.vertices;
1640 for(n=NUM_SHIP_VERTICES+1;--n;)
1642 xtemp = point->x;
1643 point->x = xtemp*c/SIN_COS_SCALE - point->y*s/SIN_COS_SCALE;
1644 point->y = point->y*c/SIN_COS_SCALE + xtemp*s/SIN_COS_SCALE;
1645 point++;
1650 void drawstars()
1652 struct Point* p;
1653 int n = NUM_STARS;
1655 p = stars;
1656 SET_FG(COL_STARS);
1658 while(--n)
1660 rb->lcd_drawpixel(p->x , p->y);
1661 p++;
1665 /*************************************************
1666 ** Draw And Move all Asteroids
1667 *************************************************/
1668 void draw_and_move_asteroids(void)
1670 int n;
1671 struct Asteroid* asteroid;
1673 asteroid = asteroids_array;
1674 SET_FG(COL_ASTEROID);
1676 n = MAX_NUM_ASTEROIDS;
1677 while(--n)
1679 if(game_state != PAUSE_MODE)
1681 if(asteroid->exists)
1683 move_point(&asteroid->position);
1684 rotate_asteroid(asteroid);
1685 draw_polygon(asteroid->vertices, asteroid->position.x/SCALE,
1686 asteroid->position.y/SCALE,
1687 NUM_ASTEROID_VERTICES);
1689 else if(asteroid->explode_countdown)
1691 /* animate_and_draw_explosion(asteroid->vertices,
1692 NUM_ASTEROID_VERTICES,
1693 asteroid->position.x/SCALE,
1694 asteroid->position.y/SCALE); */
1695 asteroid->explode_countdown--;
1698 else
1700 if(asteroid->exists)
1701 draw_polygon(asteroid->vertices,
1702 asteroid->position.x/SCALE,
1703 asteroid->position.y/SCALE,
1704 NUM_ASTEROID_VERTICES);
1706 asteroid++;
1710 void create_stars(void)
1712 struct TrailPoint* tpoint;
1713 struct Point* p;
1714 int n;
1716 p = stars;
1717 n = NUM_STARS;
1718 while(--n)
1720 p->x = (rb->rand()%LCD_WIDTH);
1721 p->y = (rb->rand()%LCD_HEIGHT);
1722 p++;
1726 /* give the point a random countdown timer, so they dissapears at different
1727 times */
1728 tpoint = trailPoints;
1729 n = NUM_TRAIL_POINTS;
1730 while(--n)
1732 tpoint->alive = 0;
1733 tpoint++;
1737 /*************************************************
1738 ** Creates start_num number of new asteroids of
1739 ** full size.
1740 **************************************************/
1741 void initialise_game(int start_num)
1743 int n;
1744 asteroid_count = next_missile_count = next_thrust_count = 0;
1745 struct Asteroid* asteroid;
1746 struct Missile* missile;
1747 extra_life = EXTRA_LIFE;
1749 /*no enemy*/
1750 enemy_on_screen = 0;
1751 enemy_missile.survived = 0;
1753 /*clear asteroids*/
1754 asteroid = asteroids_array;
1755 n = MAX_NUM_ASTEROIDS;
1756 while(--n)
1758 asteroid->exists = false;
1759 asteroid++;
1762 /*make some LARGE asteroids*/
1763 for(n = 0; n < start_num; n++)
1764 initialise_asteroid(&asteroids_array[n], LARGE);
1766 /*ensure all missiles are out of action: */
1767 missile = missiles_array;
1768 n = MAX_NUM_MISSILES;
1769 while(--n)
1771 missile->survived=0;
1772 missile++;
1776 void start_attract_mode(void)
1778 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1779 enemy.appear_timing = ENEMY_APPEAR_TIMING_START;
1780 current_level = 5;
1781 num_lives = START_LIVES;
1782 current_score = 0;
1783 attract_flip_timeout = ATTRACT_FLIP_TIME;
1784 game_state = ATTRACT_MODE;
1785 if(asteroid_count < 3)
1786 initialise_game(current_level);
1789 enum plugin_status start_game(void)
1791 char s[20];
1792 char level[10];
1793 int button;
1794 int end;
1795 int CYCLETIME = 30;
1797 /*create stars once, and once only:*/
1798 create_stars();
1800 SET_BG(LCD_BLACK);
1802 while(true)
1804 /*game starts with at level 1
1805 with 1 asteroid.*/
1806 start_attract_mode();
1808 /*Main loop*/
1809 while(true)
1811 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1812 rb->lcd_clear_display();
1813 SET_FG(COL_TEXT);
1814 switch(game_state)
1816 case(ATTRACT_MODE):
1817 if(attract_flip_timeout < ATTRACT_FLIP_TIME/2)
1819 rb->lcd_putsxy(CENTER_LCD_X - 39,
1820 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4,
1821 "Fire to Start");
1822 if(!attract_flip_timeout)
1823 attract_flip_timeout = ATTRACT_FLIP_TIME;
1825 else
1827 rb->snprintf(s, sizeof(s), "Hi Score %d ", high_score);
1828 rb->lcd_putsxy(CENTER_LCD_X - 30,
1829 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, s);
1831 attract_flip_timeout--;
1832 break;
1834 case(GAME_OVER):
1835 rb->lcd_putsxy(CENTER_LCD_X - 25,
1836 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "Game Over");
1837 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1838 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1839 show_game_over--;
1840 if(!show_game_over)
1841 start_attract_mode();
1842 break;
1844 case(PAUSE_MODE):
1845 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1846 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1847 rb->lcd_putsxy(CENTER_LCD_X - 15,
1848 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "pause");
1849 draw_and_move_missiles();
1850 draw_lives();
1851 draw_and_move_ship();
1852 break;
1854 case(PLAY_MODE):
1855 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1856 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1857 draw_and_move_missiles();
1858 draw_lives();
1859 check_collisions();
1860 draw_and_move_ship();
1861 break;
1863 case(SHOW_LEVEL):
1864 show_level_timeout--;
1865 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1866 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1867 rb->snprintf(level, sizeof(level), "stage %d ", current_level);
1868 rb->lcd_putsxy(CENTER_LCD_X - 20,
1869 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, level);
1870 draw_and_move_ship();
1871 draw_lives();
1872 if(!show_level_timeout)
1874 initialise_game(current_level);
1875 game_state = PLAY_MODE;
1876 draw_lives();
1878 break;
1880 draw_trail_blaze();
1881 drawstars();
1882 draw_and_move_asteroids();
1883 draw_and_move_enemy();
1885 rb->lcd_update();
1886 button = rb->button_get(false);
1888 #ifdef HAS_BUTTON_HOLD
1889 if (rb->button_hold())
1890 game_state = PAUSE_MODE;
1891 #endif
1893 switch(button)
1895 case(AST_PAUSE):
1896 if(game_state == PLAY_MODE)
1897 game_state = PAUSE_MODE;
1898 else if(game_state == PAUSE_MODE)
1899 game_state = PLAY_MODE;
1900 break;
1902 #ifdef AST_RC_QUIT
1903 case AST_RC_QUIT:
1904 #endif
1905 case(AST_QUIT):
1906 if(game_state == ATTRACT_MODE)
1907 return PLUGIN_OK;
1908 else if(game_state == GAME_OVER)
1910 start_attract_mode();
1912 else
1914 show_game_over = SHOW_GAME_OVER_TIME;
1915 game_state = GAME_OVER;
1917 break;
1919 case (AST_LEFT_REP):
1920 case (AST_LEFT):
1921 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1922 rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN);
1923 break;
1925 case (AST_RIGHT_REP):
1926 case (AST_RIGHT):
1927 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1928 rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN);
1929 break;
1931 case (AST_THRUST_REP):
1932 case (AST_THRUST):
1933 if((game_state == PLAY_MODE || game_state == SHOW_LEVEL) && !next_thrust_count)
1935 thrust_ship();
1936 next_thrust_count = 5;
1938 break;
1940 case (AST_HYPERSPACE):
1941 if(game_state == PLAY_MODE)
1942 hyperspace();
1943 /*maybe shield if it gets too hard */
1944 break;
1946 case (AST_FIRE_REP):
1947 case (AST_FIRE):
1948 if(game_state == ATTRACT_MODE)
1950 current_level = START_LEVEL;
1951 initialise_ship();
1952 initialise_game(current_level);
1953 show_level_timeout = SHOW_LEVEL_TIME;
1954 game_state = PLAY_MODE;
1956 else if(game_state == PLAY_MODE)
1958 if(!next_missile_count)
1960 fire_missile();
1961 next_missile_count = 10;
1964 else if(game_state == PAUSE_MODE)
1966 game_state = PLAY_MODE;
1968 break;
1970 default:
1971 if (rb->default_event_handler(button)==SYS_USB_CONNECTED)
1972 return PLUGIN_USB_CONNECTED;
1973 break;
1976 if(!num_lives)
1978 if(high_score < current_score)
1979 high_score = current_score;
1980 if(!show_game_over)
1981 break;
1984 if(next_missile_count)
1985 next_missile_count--;
1987 if(next_thrust_count)
1988 next_thrust_count--;
1990 if (end > *rb->current_tick)
1991 rb->sleep(end-*rb->current_tick);
1992 else
1993 rb->yield();
1999 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
2001 enum plugin_status retval;
2002 (void)(parameter);
2003 rb = api;
2005 game_state = ATTRACT_MODE;
2007 #if LCD_DEPTH > 1
2008 rb->lcd_set_backdrop(NULL);
2009 #endif
2010 /* universal font */
2011 rb->lcd_setfont(FONT_SYSFIXED);
2012 /* Turn off backlight timeout */
2013 backlight_force_on(rb); /* backlight control in lib/helper.c */
2014 iohiscore();
2015 retval = start_game();
2016 iohiscore();
2017 rb->lcd_setfont(FONT_UI);
2018 /* Turn on backlight timeout (revert to settings) */
2019 backlight_use_settings(rb); /* backlight control in lib/helper.c */
2020 return retval;