Accept FS#8341 - rename BUTTON_SCROLL_UP/DOWN to FWD/BACK on the e200 to make it...
[Rockbox.git] / apps / plugins / spacerocks.c
blob2ea1dc84e55191a91c1017e17626e50d44078186
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 #endif
166 #define ABS(x) ((x)>0?(x):-(x))
168 #define RES MAX(LCD_WIDTH, LCD_HEIGHT)
169 #define LARGE_LCD RES >= 200
170 #define ENEMY_MISSILE_SURVIVAL_LENGTH RES/2
171 #define ASTEROID_SPEED RES/20
172 #define MISSILE_SURVIVAL_LENGTH 40
174 #define EXTRA_LIFE 250
175 #define SCALE 5000
176 #define MISSILE_SCALE 5000
177 #define WRAP_GAP 12
178 #define EXPLOSION_LENGTH 20
179 #define SHOW_COL 0
180 #define HISCORE_FILE PLUGIN_GAMES_DIR "/astrorocks.hs"
181 #define POINT_SIZE 2
182 #define MAX_NUM_ASTEROIDS 25
183 #define MAX_NUM_MISSILES 6
184 #define ENEMY_BIG_PROBABILITY_START 10
185 #define ENEMY_APPEAR_PROBABILITY_START 35
186 #define ENEMY_APPEAR_TIMING_START 1800
187 #define LITTLE_SHIP 2
188 #define BIG_SHIP 1
189 #define SHOW_GAME_OVER_TIME 100
190 #define SHOW_LEVEL_TIME 50
191 #define START_LIVES 3
192 #define START_LEVEL 1
193 #define NUM_ASTEROID_VERTICES 10
194 #define NUM_SHIP_VERTICES 4
195 #define NUM_ENEMY_VERTICES 6
196 #define MAX_LEVEL MAX_NUM_ASTEROIDS
197 #define ENEMY_SPEED 4
198 #define ENEMY_START_X 0
199 #define ENEMY_START_Y 0
200 #define SIZE_ENEMY_COLLISION 5*SCALE
201 #define ATTRACT_FLIP_TIME 100
202 #define NUM_STARS 50
203 #define NUM_TRAIL_POINTS 70
204 #define NUM_ROTATIONS 16
206 #define SIN_COS_SCALE 10000
208 #define FAST_ROT_CW_SIN 873
209 #define FAST_ROT_CW_COS 9963
210 #define FAST_ROT_ACW_SIN -873
211 #define FAST_ROT_ACW_COS 9963
213 #define MEDIUM_ROT_CW_SIN 350
214 #define MEDIUM_ROT_CW_COS 9994
215 #define MEDIUM_ROT_ACW_SIN -350
216 #define MEDIUM_ROT_ACW_COS 9994
218 #define SLOW_ROT_CW_SIN 350
219 #define SLOW_ROT_CW_COS 9994
220 #define SLOW_ROT_ACW_SIN - 350
221 #define SLOW_ROT_ACW_COS 9994
223 #ifdef HAVE_LCD_COLOR
224 #define SHIP_ROT_CW_SIN 2419
225 #define SHIP_ROT_CW_COS 9702
226 #define SHIP_ROT_ACW_SIN -2419
227 #define SHIP_ROT_ACW_COS 9702
228 #else
229 #define SHIP_ROT_CW_SIN 3827
230 #define SHIP_ROT_CW_COS 9239
231 #define SHIP_ROT_ACW_SIN -3827
232 #define SHIP_ROT_ACW_COS 9239
233 #endif
236 #define SCALED_WIDTH (LCD_WIDTH*SCALE)
237 #define SCALED_HEIGHT (LCD_HEIGHT*SCALE)
238 #define CENTER_LCD_X (LCD_WIDTH/2)
239 #define CENTER_LCD_Y (LCD_HEIGHT/2)
241 #define SHIP_EXPLOSION_COLOUR 1
242 #define ASTEROID_EXPLOSION_COLOUR 2
243 #define ENEMY_EXPLOSION_COLOUR 3
244 #define THRUST_COLOUR 4
246 #define ASTEROID_R 230
247 #define ASTEROID_G 200
248 #define ASTEROID_B 100
249 #define SHIP_R 255
250 #define SHIP_G 255
251 #define SHIP_B 255
252 #define ENEMY_R 50
253 #define ENEMY_G 220
254 #define ENEMY_B 50
255 #define THRUST_R 200
256 #define THRUST_G 200
257 #define THRUST_B 0
259 #ifdef HAVE_LCD_COLOR
260 #define COL_MISSILE LCD_RGBPACK(200,0,0)
261 #define COL_PLAYER LCD_RGBPACK(200,200,200)
262 #define COL_STARS LCD_WHITE
263 #define COL_ASTEROID LCD_RGBPACK(ASTEROID_R,ASTEROID_G,ASTEROID_B)
264 #define COL_TEXT LCD_RGBPACK(200,200,255)
265 #define COL_ENEMY LCD_RGBPACK(ENEMY_R,ENEMY_G,ENEMY_B)
266 #define SET_FG rb->lcd_set_foreground
267 #define SET_BG rb->lcd_set_background
268 #else
269 #define SET_FG(x)
270 #define SET_BG(x)
271 #endif
273 /* The array of points that make up an asteroid */
274 static const short asteroid_one[NUM_ASTEROID_VERTICES*2] =
276 -2, -12,
277 4, -8,
278 8, -14,
279 16, -5,
280 14, 0,
281 20, 2,
282 12, 14,
283 -4, 14,
284 -10, 6,
285 -10, -8
288 /* The array of points that make up an asteroid */
289 static const short asteroid_two[NUM_ASTEROID_VERTICES*2] =
291 -2, -12,
292 4, -16,
293 6, -14,
294 16, -8,
295 14, 0,
296 20, 2,
297 12, 14,
298 -4, 14,
299 -10, 6,
300 -10, -8
303 /* The array of points that make up an asteroid */
304 static const short asteroid_three[NUM_ASTEROID_VERTICES*2] =
306 -2, -12,
307 4, -16,
308 6, -14,
309 2, -8,
310 14, 0,
311 20, 2,
312 12, 14,
313 -4, 14,
314 -16, 6,
315 -10, -8
318 /* The array od points the make up the ship */
319 static const short ship_vertices[NUM_SHIP_VERTICES*2] =
321 #if(LARGE_LCD)
322 0,-6,
323 4, 6,
324 0, 2,
325 -4, 6
326 #else
327 0,-4,
328 3, 4,
329 0, 1,
330 -3, 4
331 #endif
334 /* The array of points the make up the bad spaceship */
335 static const short enemy_vertices[NUM_ENEMY_VERTICES*2] =
337 #if(LARGE_LCD)
338 -8, 0,
339 -4, 4,
340 4, 4,
341 8, 0,
342 4, -4,
343 -4, -4
344 #else
345 -5, 0,
346 -2, 2,
347 2, 2,
348 5, 0,
349 2, -2,
350 -2, -2
351 #endif
355 enum asteroid_type
357 #if(LARGE_LCD)
358 SMALL = 2,
359 MEDIUM = 4,
360 LARGE = 6,
361 #else
362 SMALL = 1,
363 MEDIUM = 2,
364 LARGE = 3,
365 #endif
369 enum game_state
371 GAME_OVER,
372 ATTRACT_MODE,
373 SHOW_LEVEL,
374 PLAY_MODE,
375 PAUSE_MODE
378 struct Point
380 int x;
381 int y;
382 int dx;
383 int dy;
386 struct TrailPoint
388 int alive;
389 struct Point position;
390 short r;
391 short g;
392 short b;
393 short dec;
396 /* Asteroid structure, contains an array of points */
397 struct Asteroid
399 enum asteroid_type type;
400 bool exists;
401 struct Point position;
402 struct Point vertices[NUM_ASTEROID_VERTICES];
403 int radius;
404 long speed_cos;
405 long speed_sin;
406 int explode_countdown;
409 struct Ship
411 struct Point vertices[NUM_SHIP_VERTICES];
412 struct Point position;
413 bool waiting_for_space;
414 int explode_countdown;
417 struct Enemy
419 struct Point vertices[NUM_ENEMY_VERTICES];
420 struct Point position;
421 int explode_countdown;
422 long last_time_appeared;
423 short size_probability;
424 short appear_probability;
425 short appear_timing;
428 struct Missile
430 struct Point position;
431 struct Point oldpoint;
432 int survived;
435 static enum game_state game_state;
436 static int asteroid_count;
437 static int next_missile_count;
438 static int next_thrust_count;
439 static int num_lives;
440 static int extra_life;
441 static int show_level_timeout;
442 static int attract_flip_timeout;
443 static int show_game_over;
444 static int current_level;
445 static int current_score;
446 static int high_score;
447 static int space_check_size = 30*SCALE;
449 static bool enemy_on_screen;
450 static char phscore[30];
451 static struct Ship ship;
452 static struct Point stars[NUM_STARS];
453 static struct Asteroid asteroids_array[MAX_NUM_ASTEROIDS];
454 static struct Missile missiles_array[MAX_NUM_MISSILES];
455 static struct Missile enemy_missile;
456 static struct Enemy enemy;
457 static struct Point lives_points[NUM_SHIP_VERTICES];
458 static struct TrailPoint trailPoints[NUM_TRAIL_POINTS];
460 void draw_and_move_asteroids(void);
461 void initialise_game(int nStartNum);
463 bool is_asteroid_near_ship(struct Asteroid* asteroid);
464 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point);
466 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type eType);
467 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices);
468 void rotate_asteroid(struct Asteroid* asteroid);
469 void create_asteroid(enum asteroid_type type, int x, int y);
470 void create_stars(void);
472 void initialise_ship(void);
473 void draw_and_move_ship(void);
474 void rotate_ship(int s, int c);
475 void thrust_ship(void);
477 void initialise_missile(struct Missile* missile);
478 void draw_and_move_missiles(void);
479 void fire_missile(void);
481 void animate_and_draw_explosion(struct Point* point, int num_points, int xoffset, int yoffset);
482 void initialise_explosion(struct Point* point, int num_points);
484 void move_point(struct Point* point);
485 void hyperspace(void);
486 void check_collisions(void);
487 void initialise_enemy(void);
488 void draw_and_move_enemy(void);
489 void draw_lives(void);
490 void drawstars(void);
491 bool is_ship_within_asteroid(struct Asteroid* asteroid);
495 /*Hi-Score reading and writing to file - this needs moving to the hi-score plugin lib as
496 a 3rd function */
497 void iohiscore(void)
499 int fd;
500 int compare;
502 /* clear the buffer we're about to load the highscore data into */
503 rb->memset(phscore, 0, sizeof(phscore));
505 fd = rb->open(HISCORE_FILE,O_RDWR | O_CREAT);
506 if(fd < 0)
508 rb->splash(HZ, "Highscore file read error");
509 return;
512 /* highscore used to %d, is now %d\n
513 Deal with no file or bad file */
514 rb->read(fd,phscore, sizeof(phscore));
516 compare = rb->atoi(phscore);
518 if(high_score > compare)
520 rb->lseek(fd,0,SEEK_SET);
521 rb->fdprintf(fd, "%d\n", high_score);
523 else
524 high_score = compare;
526 rb->close(fd);
529 bool point_in_poly(struct Point* _point, int num_vertices, int x, int y)
531 struct Point* pi;
532 struct Point* pj;
533 int n;
534 bool c = false;
536 pi = _point;
537 pj = _point;
538 pj += num_vertices-1;
540 n = num_vertices;
541 while(n--)
543 if((((pi->y <= y) && (y < pj->y)) || ((pj->y <= y) && (y < pi->y))) &&
544 (x < (pj->x - pi->x) * (y - pi->y) / (pj->y - pi->y) + pi->x))
545 c = !c;
547 if(n == num_vertices - 1)
548 pj = _point;
549 else
550 pj++;
552 pi++;
555 return c;
558 void move_point(struct Point* point)
560 point->x += point->dx;
561 point->y += point->dy;
563 /*check bounds on the x-axis:*/
564 if(point->x >= SCALED_WIDTH)
565 point->x = 0;
566 else if(point->x <= 0)
567 point->x = SCALED_WIDTH;
569 /*Check bounds on the y-axis:*/
570 if(point->y >= SCALED_HEIGHT)
571 point->y = 0;
572 else if(point->y <= 0)
573 point->y = SCALED_HEIGHT;
576 void create_trail(struct TrailPoint* tpoint)
578 tpoint->position.dx = -( ship.vertices[0].x - ship.vertices[2].x )/10;
579 tpoint->position.dy = -( ship.vertices[0].y - ship.vertices[2].y )/10;
582 void create_explosion_trail(struct TrailPoint* tpoint)
584 tpoint->position.dx = (rb->rand()%5050)-2500;
585 tpoint->position.dy = (rb->rand()%5050)-2500;
588 void create_trail_blaze(int colour, struct Point* position)
590 int numtoadd;
591 struct TrailPoint* tpoint;
592 int n;
593 int xadd,yadd;
594 if(colour != SHIP_EXPLOSION_COLOUR)
596 numtoadd = NUM_TRAIL_POINTS/5;
597 xadd = position->x;
598 yadd = position->y;
600 else
602 numtoadd = NUM_TRAIL_POINTS/8;
603 xadd = ship.position.x;
604 yadd = ship.position.y;
607 /* give the point a random countdown timer, so they dissapears at different times */
608 tpoint = trailPoints;
609 n = NUM_TRAIL_POINTS;
610 while(--n)
612 if(tpoint->alive <= 0 && numtoadd)
614 numtoadd--;
615 /* take a random x point anywhere between bottom two points of ship. */
616 /* ship.position.x; */
617 tpoint->position.x = (ship.vertices[2].x + (rb->rand()%18000)-9000) + position->x;
618 tpoint->position.y = (ship.vertices[2].y + (rb->rand()%18000)-9000) + position->y;
620 switch(colour)
622 case SHIP_EXPLOSION_COLOUR:
623 tpoint->r = 255;
624 tpoint->g = 255;
625 tpoint->b = 255;
626 create_explosion_trail(tpoint);
627 tpoint->alive = 510;
628 tpoint->dec = 2;
629 break;
630 case ASTEROID_EXPLOSION_COLOUR:
631 tpoint->r = ASTEROID_R;
632 tpoint->g = ASTEROID_G;
633 tpoint->b = ASTEROID_B;
634 create_explosion_trail(tpoint);
635 tpoint->alive = 510;
636 tpoint->dec = 2;
637 break;
638 case ENEMY_EXPLOSION_COLOUR:
639 tpoint->r = ENEMY_R;
640 tpoint->g = ENEMY_G;
641 tpoint->b = ENEMY_B;
642 create_explosion_trail(tpoint);
643 tpoint->alive = 510;
644 tpoint->dec = 2;
645 break;
646 case THRUST_COLOUR:
647 tpoint->r = THRUST_R;
648 tpoint->g = THRUST_G;
649 tpoint->b = THRUST_B;
650 create_trail(tpoint);
651 tpoint->alive = 175;
652 tpoint->dec = 4;
653 break;
655 /* add a proportional bit to the x and y based on dx and dy */
657 /* give the points a speed based on direction of travel - i.e. opposite */
658 tpoint->position.dx += position->dx;
659 tpoint->position.dy += position->dy;
663 tpoint++;
665 /* find a space in the array of trail_points that is NULL or DEAD or whatever.
666 and place this one here. */
670 void draw_trail_blaze(void)
672 struct TrailPoint* tpoint;
673 /* loop through, if alive then move and draw.
674 when drawn, countdown it's timer.
675 if zero kill it! */
676 tpoint = trailPoints;
677 int n = NUM_TRAIL_POINTS;
679 while(--n)
681 if(tpoint->alive)
683 if(game_state != PAUSE_MODE)
685 tpoint->alive-=10;
686 move_point(&(tpoint->position));
688 #ifdef HAVE_LCD_COLOR
689 /* intensity = tpoint->alive/2; */
690 if(tpoint->r>0)tpoint->r-=tpoint->dec;
691 if(tpoint->g>0)tpoint->g-=tpoint->dec;
692 if(tpoint->b>0)tpoint->b-=tpoint->dec;
693 SET_FG(LCD_RGBPACK(tpoint->r, tpoint->g, tpoint->b));
694 #endif
695 rb->lcd_drawpixel(tpoint->position.x/SCALE , tpoint->position.y/SCALE);
697 tpoint++;
701 /*Check if point is within a rectangle*/
702 bool is_point_within_rectangle(struct Point* rect, struct Point* p, int size)
704 #if SHOW_COL
705 int aTLx = rect->x - size;
706 int aTLy = rect->y - size;
707 int aBRx = rect->x + size;
708 int aBRy = rect->y + size;
709 rb->lcd_drawline( aTLx/SCALE, aTLy/SCALE, aBRx/SCALE, aTLy/SCALE);
710 rb->lcd_drawline( aTLx/SCALE, aTLy/SCALE, aTLx/SCALE, aBRy/SCALE);
711 rb->lcd_drawline( aTLx/SCALE, aBRy/SCALE, aBRx/SCALE, aBRy/SCALE);
712 rb->lcd_drawline( aBRx/SCALE, aBRy/SCALE, aBRx/SCALE, aTLy/SCALE);
713 return (p->x > aTLx && p->x < aBRx && p->y > aTLy && p->y < aBRy);
714 #else
715 return (p->x > rect->x - size && p->x < rect->x + size &&
716 p->y > rect->y - size && p->y < rect->y + size);
717 #endif
720 /* Draw polygon */
721 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices)
723 int n, t1, t2, oldX, oldY;
724 struct Point *p;
725 bool bDrawAll = px < WRAP_GAP || LCD_WIDTH - px < WRAP_GAP ||
726 py < WRAP_GAP || LCD_HEIGHT - py < WRAP_GAP;
728 p = vertices;
729 p += num_vertices-1;
730 oldX = p->x/SCALE + px;
731 oldY = p->y/SCALE + py;
732 p = vertices;
733 for(n = num_vertices+1; --n;)
735 t1 = p->x/SCALE + px;
736 t2 = p->y/SCALE + py;
738 rb->lcd_drawline(oldX, oldY, t1, t2);
740 if(bDrawAll)
742 rb->lcd_drawline(oldX - LCD_WIDTH, oldY, t1 - LCD_WIDTH, t2);
743 rb->lcd_drawline(oldX + LCD_WIDTH, oldY, t1 + LCD_WIDTH, t2);
744 rb->lcd_drawline(oldX - LCD_WIDTH, oldY + LCD_HEIGHT,
745 t1 - LCD_WIDTH, t2 + LCD_HEIGHT);
746 rb->lcd_drawline(oldX + LCD_WIDTH, oldY + LCD_HEIGHT,
747 t1 + LCD_WIDTH, t2 + LCD_HEIGHT);
749 rb->lcd_drawline(oldX, oldY - LCD_HEIGHT, t1, t2 - LCD_HEIGHT);
750 rb->lcd_drawline(oldX, oldY + LCD_HEIGHT, t1, t2 + LCD_HEIGHT);
751 rb->lcd_drawline(oldX - LCD_WIDTH, oldY - LCD_HEIGHT,
752 t1 - LCD_WIDTH, t2 - LCD_HEIGHT);
753 rb->lcd_drawline(oldX + LCD_WIDTH, oldY - LCD_HEIGHT,
754 t1 + LCD_WIDTH, t2 - LCD_HEIGHT);
756 oldX = t1;
757 oldY = t2;
758 p++;
762 void animate_and_draw_explosion(struct Point* point, int num_points,
763 int xoffset, int yoffset)
765 int n;
766 for(n = num_points; --n;)
768 if(game_state != PAUSE_MODE)
770 point->x += point->dx;
771 point->y += point->dy;
773 rb->lcd_fillrect( point->x/SCALE + xoffset, point->y/SCALE + yoffset,
774 POINT_SIZE, POINT_SIZE);
775 point++;
779 /*stop movement of ship, 'cos that's what happens when you go into hyperspace.*/
780 void hyperspace(void)
782 ship.position.dx = ship.position.dy = 0;
783 ship.position.x = (rb->rand()%SCALED_WIDTH);
784 ship.position.y = (rb->rand()%SCALED_HEIGHT);
787 void initialise_enemy(void)
789 struct Point* point;
790 int n;
791 int size;
793 if(rb->rand()%100 > enemy.size_probability)
795 size = BIG_SHIP;
796 enemy.size_probability++;
797 if(enemy.size_probability < 90)
799 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
802 else
804 size = LITTLE_SHIP;
807 enemy_missile.survived = 0;
808 enemy_on_screen = true;
809 enemy.explode_countdown = 0;
810 enemy.last_time_appeared = *rb->current_tick;
811 point = enemy.vertices;
812 for(n = 0; n < NUM_ENEMY_VERTICES+NUM_ENEMY_VERTICES; n+=2)
814 point->x = enemy_vertices[n];
815 point->y = enemy_vertices[n+1];
816 point->x *= SCALE/size;
817 point->y *= SCALE/size;
818 point++;
821 if(ship.position.x >= SCALED_WIDTH/2)
823 enemy.position.dx = ENEMY_SPEED;
824 enemy.position.x = 0;
826 else
828 enemy.position.dx = -ENEMY_SPEED;
829 enemy.position.x = SCALED_WIDTH;
832 if(ship.position.y >= SCALED_HEIGHT/2)
834 enemy.position.dy = ENEMY_SPEED;
835 enemy.position.y = 0;
837 else
839 enemy.position.dy = -ENEMY_SPEED;
840 enemy.position.y = SCALED_HEIGHT;
843 enemy.position.dx *= SCALE/10;
844 enemy.position.dy *= SCALE/10;
847 void draw_and_move_enemy(void)
849 int enemy_x, enemy_y;
850 struct Point *point;
852 SET_FG(COL_ENEMY);
854 if(enemy_on_screen)
856 enemy_x = enemy.position.x/SCALE;
857 enemy_y = enemy.position.y/SCALE;
858 if(!enemy.explode_countdown)
860 point = enemy.vertices;
861 draw_polygon(enemy.vertices, enemy_x, enemy_y, NUM_ENEMY_VERTICES);
862 rb->lcd_drawline(enemy.vertices[0].x/SCALE + enemy_x,
863 enemy.vertices[0].y/SCALE + enemy_y,
864 enemy.vertices[3].x/SCALE + enemy_x,
865 enemy.vertices[3].y/SCALE + enemy_y);
867 if(game_state != PAUSE_MODE)
869 enemy.position.x += enemy.position.dx;
870 enemy.position.y += enemy.position.dy;
873 if(enemy.position.x > SCALED_WIDTH || enemy.position.x < 0)
874 enemy_on_screen = false;
876 if(enemy.position.y > SCALED_HEIGHT)
877 enemy.position.y = 0;
878 else if(enemy.position.y < 0)
879 enemy.position.y = SCALED_HEIGHT;
881 if( (rb->rand()%1000) < 10)
882 enemy.position.dy = -enemy.position.dy;
884 else
887 /* animate_and_draw_explosion(enemy.vertices, NUM_ENEMY_VERTICES,
888 enemy_x, enemy.position.y/SCALE); */
889 if(game_state != PAUSE_MODE)
891 enemy.explode_countdown--;
892 if(!enemy.explode_countdown)
893 enemy_on_screen = false;
897 else
899 if( (*rb->current_tick - enemy.last_time_appeared) > enemy.appear_timing)
900 if(rb->rand()%100 > enemy.appear_probability) initialise_enemy();
903 if(!enemy_missile.survived && game_state != GAME_OVER)
905 /*if no missile and the enemy is here and not exploding..then shoot baby!*/
906 if( !enemy.explode_countdown && enemy_on_screen &&
907 !ship.waiting_for_space && (rb->rand()%10) > 5 )
909 enemy_missile.position.x = enemy.position.x;
910 enemy_missile.position.y = enemy.position.y;
912 /*lame, needs to be sorted - it's trying to shoot at the ship*/
913 if(ABS(enemy.position.y - ship.position.y) <= 5*SCALE)
915 enemy_missile.position.dy = 0;
917 else
919 if( enemy.position.y < ship.position.y)
920 enemy_missile.position.dy = 1;
921 else
922 enemy_missile.position.dy = -1;
925 if(ABS(enemy.position.x - ship.position.x) <= 5*SCALE)
926 enemy_missile.position.dx = 0;
927 else
929 if( enemy.position.x < ship.position.x)
930 enemy_missile.position.dx = 1;
931 else
932 enemy_missile.position.dx = -1;
935 if(enemy_missile.position.dx == 0 &&
936 enemy_missile.position.dy == 0)
937 enemy_missile.position.dx = enemy_missile.position.dy = -1;
939 enemy_missile.position.dx *= SCALE;
940 enemy_missile.position.dy *= SCALE;
941 enemy_missile.survived = ENEMY_MISSILE_SURVIVAL_LENGTH;
945 else
947 rb->lcd_fillrect( enemy_missile.position.x/SCALE,
948 enemy_missile.position.y/SCALE,
949 POINT_SIZE, POINT_SIZE);
950 if(game_state != PAUSE_MODE)
952 move_point(&enemy_missile.position);
953 enemy_missile.survived--;
958 /******************
959 * Lame method of collision
960 * detection. It's checking for collision
961 * between point and a big rectangle around the asteroid...
962 *******************/
963 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point)
965 if( !is_point_within_rectangle(&asteroid->position, point,
966 asteroid->radius+4*SCALE) )
967 return false;
969 if(point_in_poly(asteroid->vertices, NUM_ASTEROID_VERTICES,
970 point->x - asteroid->position.x,
971 point->y - asteroid->position.y))
973 switch(asteroid->type)
975 case(SMALL):
976 asteroid->explode_countdown = EXPLOSION_LENGTH;
977 create_trail_blaze(ASTEROID_EXPLOSION_COLOUR, &asteroid->position);
978 break;
980 case(LARGE):
981 create_asteroid(MEDIUM, asteroid->position.x,
982 asteroid->position.y);
983 create_asteroid(MEDIUM, asteroid->position.x,
984 asteroid->position.y);
985 break;
987 case(MEDIUM):
988 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
989 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
990 break;
993 current_score++;
994 if(current_score > extra_life)
996 num_lives++;
997 extra_life = current_score+EXTRA_LIFE;
999 asteroid_count--;
1000 asteroid->exists = false;
1001 return true;
1003 else
1004 return false;
1007 bool is_point_within_enemy(struct Point* point)
1009 if( is_point_within_rectangle(&enemy.position, point, 7*SCALE) )
1011 current_score += 5;
1012 /*enemy_missile.survived = 0;*/
1013 enemy.explode_countdown = EXPLOSION_LENGTH;
1014 /* initialise_explosion(enemy.vertices, NUM_ENEMY_VERTICES); */
1015 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1016 return true;
1018 else
1019 return false;
1022 bool is_ship_within_asteroid(struct Asteroid* asteroid)
1024 bool hit = false;
1025 struct Point p;
1027 p.x = ship.position.x + ship.vertices[0].x;
1028 p.y = ship.position.y + ship.vertices[0].y;
1029 hit |= is_point_within_asteroid(asteroid, &p);
1031 if(!hit)
1033 p.x = ship.position.x + ship.vertices[1].x;
1034 p.y = ship.position.y + ship.vertices[1].y;
1035 hit |= is_point_within_asteroid(asteroid, &p);
1036 if(!hit)
1038 p.x = ship.position.x + ship.vertices[3].x;
1039 p.y = ship.position.y + ship.vertices[3].y;
1040 hit |= is_point_within_asteroid(asteroid, &p);
1044 return hit;
1047 void initialise_explosion(struct Point* point, int num_points)
1049 int n;
1051 point->x += point->dx;
1052 point->y += point->dy;
1053 for(n = num_points; --n;)
1055 point->dx = point->x;
1056 point->dy = point->y;
1057 point++;
1062 /* Check for collsions between the missiles and the asteroids and the ship */
1063 void check_collisions(void)
1065 int m, n;
1066 bool asteroids_onscreen = false;
1067 struct Missile* missile;
1068 struct Asteroid* asteroid;
1069 bool ship_cant_be_placed = false;
1071 asteroid = asteroids_array;
1072 m = MAX_NUM_ASTEROIDS;
1073 while(--m)
1075 /*if the asteroids exists then test missile collision:*/
1076 if(asteroid->exists)
1078 missile = missiles_array;
1079 n = MAX_NUM_MISSILES;
1080 while(--n)
1082 /*if the missiles exists:*/
1083 if(missile->survived > 0)
1085 /*has the missile hit the asteroid?*/
1086 if(is_point_within_asteroid(asteroid, &missile->position)
1087 || is_point_within_asteroid(asteroid,
1088 &missile->oldpoint))
1090 missile->survived = 0;
1091 break;
1094 missile++;
1097 /*now check collision with ship:*/
1098 if(asteroid->exists && !ship.waiting_for_space && !ship.explode_countdown)
1100 if(is_ship_within_asteroid(asteroid))
1102 /*blow up ship*/
1103 ship.explode_countdown = EXPLOSION_LENGTH;
1104 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1105 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1108 /*has the enemy missile blown something up?*/
1109 if(asteroid->exists && enemy_missile.survived)
1111 if(is_point_within_asteroid(asteroid, &enemy_missile.position))
1113 /*take that score back then:*/
1114 if(current_score > 0) current_score--;
1115 enemy_missile.survived = 0;
1118 /*if it still exists, check if ship is waiting for space:*/
1119 if(asteroid->exists && ship.waiting_for_space)
1120 ship_cant_be_placed |=
1121 is_point_within_rectangle(&ship.position,
1122 &asteroid->position,
1123 space_check_size);
1127 /*is an asteroid still exploding?*/
1128 if(asteroid->explode_countdown)
1129 asteroids_onscreen = true;
1131 asteroid++;
1134 /*now check collision between ship and enemy*/
1135 if(enemy_on_screen && !ship.waiting_for_space &&
1136 !ship.explode_countdown && !enemy.explode_countdown)
1138 /*has the enemy collided with the ship?*/
1139 if(is_point_within_enemy(&ship.position))
1141 ship.explode_countdown = EXPLOSION_LENGTH;
1142 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1143 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1144 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1147 /*Now see if the enemy has been shot at by the ships missiles:*/
1148 missile = missiles_array;
1149 n = MAX_NUM_MISSILES;
1150 while(--n)
1152 if(missile->survived > 0 &&
1153 is_point_within_enemy(&missile->position))
1155 missile->survived = 0;
1156 break;
1158 missile++;
1162 /*test collision with enemy missile and ship:*/
1163 if(!ship_cant_be_placed && enemy_missile.survived > 0 &&
1164 point_in_poly(ship.vertices, NUM_SHIP_VERTICES,
1165 enemy_missile.position.x - ship.position.x,
1166 enemy_missile.position.y - ship.position.y))
1168 ship.explode_countdown = EXPLOSION_LENGTH;
1169 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1170 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1171 enemy_missile.survived = 0;
1172 enemy_missile.position.x = enemy_missile.position.y = 0;
1175 if(!ship_cant_be_placed)
1176 ship.waiting_for_space = false;
1178 /*if all asteroids cleared then start again:*/
1179 if(asteroid_count == 0 && !enemy_on_screen && !asteroids_onscreen)
1181 current_level++;
1182 game_state = SHOW_LEVEL;
1183 enemy.appear_probability += 5;
1184 enemy.appear_timing -= 200;
1185 if( enemy.appear_probability > 100)
1186 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1187 show_level_timeout = SHOW_LEVEL_TIME;
1191 /*************************************************
1192 ** Creates a new asteroid of the given 4type (size)
1193 ** and at the given location.
1194 *************************************************/
1195 void create_asteroid(enum asteroid_type type, int x, int y)
1197 struct Asteroid* asteroid;
1198 int n;
1200 asteroid = asteroids_array;
1201 n = MAX_NUM_ASTEROIDS;
1202 while(--n)
1204 if(!asteroid->exists && !asteroid->explode_countdown)
1206 initialise_asteroid(asteroid, type);
1207 asteroid->position.x = x;
1208 asteroid->position.y = y;
1209 break;
1211 asteroid++;
1215 /* Initialise a missile */
1216 void initialise_missile(struct Missile* missile)
1218 missile->position.x = ship.position.x + ship.vertices[0].x;
1219 missile->position.y = ship.position.y + ship.vertices[0].y;
1220 missile->position.dx = (ship.vertices[0].x - ship.vertices[2].x)/2;
1221 missile->position.dy = (ship.vertices[0].y - ship.vertices[2].y)/2;
1222 missile->survived = MISSILE_SURVIVAL_LENGTH;
1223 missile->oldpoint.x = missile->position.x;
1224 missile->oldpoint.y = missile->position.y;
1227 /* Draw and Move all the missiles */
1228 void draw_and_move_missiles(void)
1230 int n;
1231 int p1x, p1y;
1232 int p2x, p2y;
1234 struct Missile* missile;
1235 missile = missiles_array;
1237 SET_FG(COL_MISSILE);
1239 n = MAX_NUM_MISSILES;
1240 while(--n)
1242 if(missile->survived)
1244 if(missile->position.dx > 0)
1246 if(missile->position.x >= missile->oldpoint.x)
1248 p1x = missile->oldpoint.x;
1249 p2x = missile->position.x;
1251 else
1253 p1x = 0;
1254 p2x = missile->position.x;
1257 else
1259 if(missile->oldpoint.x >= missile->position.x)
1261 p1x = missile->oldpoint.x;
1262 p2x = missile->position.x;
1264 else
1266 p1x = missile->oldpoint.x;
1267 p2x = LCD_WIDTH;
1271 if(missile->position.dy > 0)
1273 if(missile->position.y >= missile->oldpoint.y)
1275 p1y = missile->oldpoint.y;
1276 p2y = missile->position.y;
1278 else
1280 p1y = 0;
1281 p2y = missile->position.y;
1284 else
1286 if(missile->oldpoint.y >= missile->position.y)
1288 p1y = missile->oldpoint.y;
1289 p2y = missile->position.y;
1291 else
1293 p1y = missile->oldpoint.y;
1294 p2y = LCD_HEIGHT;
1298 rb->lcd_drawline( p1x/SCALE, p1y/SCALE, p2x/SCALE, p2y/SCALE);
1300 if(game_state != PAUSE_MODE)
1302 missile->oldpoint.x = missile->position.x;
1303 missile->oldpoint.y = missile->position.y;
1304 move_point(&missile->position);
1305 missile->survived--;
1308 missile++;
1312 void draw_lives(void)
1314 int n;
1315 int px = (LCD_WIDTH - num_lives*4 - 1);
1316 #if(LARGE_LCD)
1317 int py = (LCD_HEIGHT-6);
1318 #else
1319 int py = (LCD_HEIGHT-4);
1320 #endif
1322 SET_FG(COL_PLAYER);
1324 n = num_lives;
1325 while(--n)
1327 draw_polygon(lives_points, px, py, NUM_SHIP_VERTICES);
1328 #if(LARGE_LCD)
1329 px += 8;
1330 #else
1331 px += 6;
1332 #endif
1336 /*Fire the next missile*/
1337 void fire_missile(void)
1339 int n;
1340 struct Missile* missile;
1342 if(!ship.explode_countdown && !ship.waiting_for_space)
1344 missile = missiles_array;
1345 n = MAX_NUM_MISSILES;
1346 while(--n)
1348 if(!missile->survived)
1350 initialise_missile(missile);
1351 break;
1353 missile++;
1358 /* Initialise the passed Asteroid */
1359 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type type)
1361 int n;
1362 bool b,b2;
1363 struct Point* point;
1364 asteroid->exists = true;
1365 asteroid->type = type;
1366 asteroid->explode_countdown = 0;
1368 /*Set the radius of the asteroid:*/
1369 asteroid->radius = (int)type*SCALE;
1371 /*shall we move Clockwise and Fast*/
1372 if((rb->rand()%100)>75)
1374 asteroid->speed_cos = FAST_ROT_CW_COS;
1375 asteroid->speed_sin = FAST_ROT_CW_SIN;
1377 else if((rb->rand()%100)>75)
1379 asteroid->speed_cos = FAST_ROT_ACW_COS;
1380 asteroid->speed_sin = FAST_ROT_ACW_SIN;
1382 else if((rb->rand()%100)>75)
1384 asteroid->speed_cos = SLOW_ROT_ACW_COS;
1385 asteroid->speed_sin = SLOW_ROT_ACW_SIN;
1387 else
1389 asteroid->speed_cos = SLOW_ROT_CW_COS;
1390 asteroid->speed_sin = SLOW_ROT_CW_SIN;
1393 b = (rb->rand()%100)>66;
1394 b2 = (rb->rand()%100)>66;
1395 point = asteroid->vertices;
1396 for(n = 0; n < NUM_ASTEROID_VERTICES*2; n+=2)
1398 if(b)
1400 point->x = asteroid_one[n];
1401 point->y = asteroid_one[n+1];
1403 else if( b2 )
1405 point->x = asteroid_two[n];
1406 point->y = asteroid_two[n+1];
1408 else
1410 point->x = asteroid_three[n];
1411 point->y = asteroid_three[n+1];
1414 point->x *= asteroid->radius/6;
1415 point->y *= asteroid->radius/6;
1416 point++;
1420 asteroid->radius += 6*SCALE;
1421 if(asteroid->type == SMALL)
1422 asteroid->radius /= 3;/*2*/
1423 else if(asteroid->type == LARGE)
1424 asteroid->radius += 3*SCALE;/*2*/
1425 b = true;
1426 while(b)
1428 /*Set the position randomly:*/
1429 asteroid->position.x = (rb->rand()%SCALED_WIDTH);
1430 asteroid->position.y = (rb->rand()%SCALED_HEIGHT);
1432 asteroid->position.dx = 0;
1433 while(asteroid->position.dx == 0)
1434 asteroid->position.dx = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1436 asteroid->position.dy = 0;
1437 while(asteroid->position.dy == 0)
1438 asteroid->position.dy = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1440 asteroid->position.dx *= SCALE/10;
1441 asteroid->position.dy *= SCALE/10;
1443 b = is_point_within_rectangle(&ship.position, &asteroid->position,
1444 space_check_size);
1447 /*Now rotate the asteroid a bit, so they all look a bit different*/
1448 for(n=(rb->rand()%30) + 2;--n;)
1449 rotate_asteroid(asteroid);
1451 /*great, we've created an asteroid, don't forget to increment the total:*/
1452 asteroid_count++;
1455 /*Initialise the ship*/
1456 void initialise_ship(void)
1458 struct Point* point;
1459 struct Point* lives_point;
1460 int n;
1462 ship.position.x = CENTER_LCD_X;
1463 ship.position.y = CENTER_LCD_Y;
1464 ship.position.x *= SCALE;
1465 ship.position.y *= SCALE;
1466 ship.position.dx = ship.position.dy = 0;
1468 point = ship.vertices;
1469 lives_point = lives_points;
1470 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1472 point->x = ship_vertices[n];
1473 point->y = ship_vertices[n+1];
1474 point->x *= SCALE;
1475 point->y *= SCALE;
1476 point++;
1477 lives_point++;
1480 ship.position.dx = 0;
1481 ship.position.dy = 0;
1482 ship.explode_countdown = 0;
1484 /*grab a copy of the ships points for the lives display:*/
1485 point = ship.vertices;
1486 lives_point = lives_points;
1487 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1489 lives_point->x = point->x;
1490 lives_point->y = point->y;
1491 lives_point++;
1492 point++;
1496 void rotate_asteroid(struct Asteroid* asteroid)
1498 struct Point* point;
1499 int n;
1500 long xtemp;
1502 point = asteroid->vertices;
1503 for(n = NUM_ASTEROID_VERTICES+1; --n;)
1505 xtemp = point->x;
1506 point->x = xtemp*asteroid->speed_cos/SIN_COS_SCALE -
1507 point->y*asteroid->speed_sin/SIN_COS_SCALE;
1508 point->y = point->y*asteroid->speed_cos/SIN_COS_SCALE +
1509 xtemp*asteroid->speed_sin/SIN_COS_SCALE;
1510 point++;
1514 /*************************************************
1515 ** Draws the ship, moves the ship and creates a new
1516 ** one if it's finished exploding.
1517 **************************************************/
1518 void draw_and_move_ship(void)
1520 int nxoffset = ship.position.x/SCALE;
1521 int nyoffset = ship.position.y/SCALE;
1522 SET_FG(COL_PLAYER);
1523 if(!ship.explode_countdown)
1525 if(!ship.waiting_for_space)
1527 draw_polygon(ship.vertices, nxoffset, nyoffset, NUM_SHIP_VERTICES);
1528 if(game_state != PAUSE_MODE && game_state != GAME_OVER)
1530 move_point(&ship.position);
1534 else
1536 /* animate_and_draw_explosion(ship.vertices, NUM_SHIP_VERTICES,
1537 ship.position.x/SCALE,
1538 ship.position.y/SCALE); */
1539 if(game_state != PAUSE_MODE)
1541 ship.explode_countdown--;
1542 if(!ship.explode_countdown)
1544 num_lives--;
1545 if(!num_lives)
1547 show_game_over = SHOW_GAME_OVER_TIME;
1548 game_state = GAME_OVER;
1550 else
1552 initialise_ship();
1553 ship.waiting_for_space = true;
1560 void thrust_ship(void)
1562 if(!ship.waiting_for_space)
1564 ship.position.dx += ( ship.vertices[0].x - ship.vertices[2].x )/20;
1565 ship.position.dy += ( ship.vertices[0].y - ship.vertices[2].y )/20;
1566 /*if dx and dy are below a certain threshold, then set 'em to 0
1567 but to do this we need to ascertain if the spacehip as moved on screen
1568 for more than a certain amount. */
1570 create_trail_blaze(THRUST_COLOUR, &ship.position);
1574 /**************************************************
1575 ** Rotate the ship using the passed sin & cos values
1576 ***************************************************/
1577 void rotate_ship(int c, int s)
1579 struct Point* point;
1580 int n;
1581 double xtemp;
1583 if(!ship.waiting_for_space && !ship.explode_countdown)
1585 point = ship.vertices;
1586 for(n=NUM_SHIP_VERTICES+1;--n;)
1588 xtemp = point->x;
1589 point->x = xtemp*c/SIN_COS_SCALE - point->y*s/SIN_COS_SCALE;
1590 point->y = point->y*c/SIN_COS_SCALE + xtemp*s/SIN_COS_SCALE;
1591 point++;
1596 void drawstars()
1598 struct Point* p;
1599 int n = NUM_STARS;
1601 p = stars;
1602 SET_FG(COL_STARS);
1604 while(--n)
1606 rb->lcd_drawpixel(p->x , p->y);
1607 p++;
1611 /*************************************************
1612 ** Draw And Move all Asteroids
1613 *************************************************/
1614 void draw_and_move_asteroids(void)
1616 int n;
1617 struct Asteroid* asteroid;
1619 asteroid = asteroids_array;
1620 SET_FG(COL_ASTEROID);
1622 n = MAX_NUM_ASTEROIDS;
1623 while(--n)
1625 if(game_state != PAUSE_MODE)
1627 if(asteroid->exists)
1629 move_point(&asteroid->position);
1630 rotate_asteroid(asteroid);
1631 draw_polygon(asteroid->vertices, asteroid->position.x/SCALE,
1632 asteroid->position.y/SCALE,
1633 NUM_ASTEROID_VERTICES);
1635 else if(asteroid->explode_countdown)
1637 /* animate_and_draw_explosion(asteroid->vertices,
1638 NUM_ASTEROID_VERTICES,
1639 asteroid->position.x/SCALE,
1640 asteroid->position.y/SCALE); */
1641 asteroid->explode_countdown--;
1644 else
1646 if(asteroid->exists)
1647 draw_polygon(asteroid->vertices,
1648 asteroid->position.x/SCALE,
1649 asteroid->position.y/SCALE,
1650 NUM_ASTEROID_VERTICES);
1652 asteroid++;
1656 void create_stars(void)
1658 struct TrailPoint* tpoint;
1659 struct Point* p;
1660 int n;
1662 p = stars;
1663 n = NUM_STARS;
1664 while(--n)
1666 p->x = (rb->rand()%LCD_WIDTH);
1667 p->y = (rb->rand()%LCD_HEIGHT);
1668 p++;
1672 /* give the point a random countdown timer, so they dissapears at different
1673 times */
1674 tpoint = trailPoints;
1675 n = NUM_TRAIL_POINTS;
1676 while(--n)
1678 tpoint->alive = 0;
1679 tpoint++;
1683 /*************************************************
1684 ** Creates start_num number of new asteroids of
1685 ** full size.
1686 **************************************************/
1687 void initialise_game(int start_num)
1689 int n;
1690 asteroid_count = next_missile_count = next_thrust_count = 0;
1691 struct Asteroid* asteroid;
1692 struct Missile* missile;
1693 extra_life = EXTRA_LIFE;
1695 /*no enemy*/
1696 enemy_on_screen = 0;
1697 enemy_missile.survived = 0;
1699 /*clear asteroids*/
1700 asteroid = asteroids_array;
1701 n = MAX_NUM_ASTEROIDS;
1702 while(--n)
1704 asteroid->exists = false;
1705 asteroid++;
1708 /*make some LARGE asteroids*/
1709 for(n = 0; n < start_num; n++)
1710 initialise_asteroid(&asteroids_array[n], LARGE);
1712 /*ensure all missiles are out of action: */
1713 missile = missiles_array;
1714 n = MAX_NUM_MISSILES;
1715 while(--n)
1717 missile->survived=0;
1718 missile++;
1722 void start_attract_mode(void)
1724 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1725 enemy.appear_timing = ENEMY_APPEAR_TIMING_START;
1726 current_level = 5;
1727 num_lives = START_LIVES;
1728 current_score = 0;
1729 attract_flip_timeout = ATTRACT_FLIP_TIME;
1730 game_state = ATTRACT_MODE;
1731 if(asteroid_count < 3)
1732 initialise_game(current_level);
1735 enum plugin_status start_game(void)
1737 char s[20];
1738 char level[10];
1739 int button;
1740 int end;
1741 int CYCLETIME = 30;
1743 /*create stars once, and once only:*/
1744 create_stars();
1746 SET_BG(LCD_BLACK);
1748 while(true)
1750 /*game starts with at level 1
1751 with 1 asteroid.*/
1752 start_attract_mode();
1754 /*Main loop*/
1755 while(true)
1757 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1758 rb->lcd_clear_display();
1759 SET_FG(COL_TEXT);
1760 switch(game_state)
1762 case(ATTRACT_MODE):
1763 if(attract_flip_timeout < ATTRACT_FLIP_TIME/2)
1765 rb->lcd_putsxy(CENTER_LCD_X - 39,
1766 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4,
1767 "Fire to Start");
1768 if(!attract_flip_timeout)
1769 attract_flip_timeout = ATTRACT_FLIP_TIME;
1771 else
1773 rb->snprintf(s, sizeof(s), "Hi Score %d ", high_score);
1774 rb->lcd_putsxy(CENTER_LCD_X - 30,
1775 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, s);
1777 attract_flip_timeout--;
1778 break;
1780 case(GAME_OVER):
1781 rb->lcd_putsxy(CENTER_LCD_X - 25,
1782 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "Game Over");
1783 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1784 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1785 show_game_over--;
1786 if(!show_game_over)
1787 start_attract_mode();
1788 break;
1790 case(PAUSE_MODE):
1791 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1792 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1793 rb->lcd_putsxy(CENTER_LCD_X - 15,
1794 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "pause");
1795 draw_and_move_missiles();
1796 draw_lives();
1797 draw_and_move_ship();
1798 break;
1800 case(PLAY_MODE):
1801 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1802 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1803 draw_and_move_missiles();
1804 draw_lives();
1805 check_collisions();
1806 draw_and_move_ship();
1807 break;
1809 case(SHOW_LEVEL):
1810 show_level_timeout--;
1811 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1812 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1813 rb->snprintf(level, sizeof(level), "stage %d ", current_level);
1814 rb->lcd_putsxy(CENTER_LCD_X - 20,
1815 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, level);
1816 draw_and_move_ship();
1817 draw_lives();
1818 if(!show_level_timeout)
1820 initialise_game(current_level);
1821 game_state = PLAY_MODE;
1822 draw_lives();
1824 break;
1826 draw_trail_blaze();
1827 drawstars();
1828 draw_and_move_asteroids();
1829 draw_and_move_enemy();
1831 rb->lcd_update();
1832 button = rb->button_get(false);
1834 #ifdef HAS_BUTTON_HOLD
1835 if (rb->button_hold())
1836 game_state = PAUSE_MODE;
1837 #endif
1839 switch(button)
1841 case(AST_PAUSE):
1842 if(game_state == PLAY_MODE)
1843 game_state = PAUSE_MODE;
1844 else if(game_state == PAUSE_MODE)
1845 game_state = PLAY_MODE;
1846 break;
1848 #ifdef AST_RC_QUIT
1849 case AST_RC_QUIT:
1850 #endif
1851 case(AST_QUIT):
1852 if(game_state == ATTRACT_MODE)
1853 return PLUGIN_OK;
1854 else if(game_state == GAME_OVER)
1856 start_attract_mode();
1858 else
1860 show_game_over = SHOW_GAME_OVER_TIME;
1861 game_state = GAME_OVER;
1863 break;
1865 case (AST_LEFT_REP):
1866 case (AST_LEFT):
1867 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1868 rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN);
1869 break;
1871 case (AST_RIGHT_REP):
1872 case (AST_RIGHT):
1873 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1874 rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN);
1875 break;
1877 case (AST_THRUST_REP):
1878 case (AST_THRUST):
1879 if((game_state == PLAY_MODE || game_state == SHOW_LEVEL) && !next_thrust_count)
1881 thrust_ship();
1882 next_thrust_count = 5;
1884 break;
1886 case (AST_HYPERSPACE):
1887 if(game_state == PLAY_MODE)
1888 hyperspace();
1889 /*maybe shield if it gets too hard */
1890 break;
1892 case (AST_FIRE_REP):
1893 case (AST_FIRE):
1894 if(game_state == ATTRACT_MODE)
1896 current_level = START_LEVEL;
1897 initialise_ship();
1898 initialise_game(current_level);
1899 show_level_timeout = SHOW_LEVEL_TIME;
1900 game_state = PLAY_MODE;
1902 else if(game_state == PLAY_MODE)
1904 if(!next_missile_count)
1906 fire_missile();
1907 next_missile_count = 10;
1910 else if(game_state == PAUSE_MODE)
1912 game_state = PLAY_MODE;
1914 break;
1916 default:
1917 if (rb->default_event_handler(button)==SYS_USB_CONNECTED)
1918 return PLUGIN_USB_CONNECTED;
1919 break;
1922 if(!num_lives)
1924 if(high_score < current_score)
1925 high_score = current_score;
1926 if(!show_game_over)
1927 break;
1930 if(next_missile_count)
1931 next_missile_count--;
1933 if(next_thrust_count)
1934 next_thrust_count--;
1936 if (end > *rb->current_tick)
1937 rb->sleep(end-*rb->current_tick);
1938 else
1939 rb->yield();
1945 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1947 enum plugin_status retval;
1948 (void)(parameter);
1949 rb = api;
1951 game_state = ATTRACT_MODE;
1953 #if LCD_DEPTH > 1
1954 rb->lcd_set_backdrop(NULL);
1955 #endif
1956 /* universal font */
1957 rb->lcd_setfont(FONT_SYSFIXED);
1958 /* Turn off backlight timeout */
1959 backlight_force_on(rb); /* backlight control in lib/helper.c */
1960 iohiscore();
1961 retval = start_game();
1962 iohiscore();
1963 rb->lcd_setfont(FONT_UI);
1964 /* Turn on backlight timeout (revert to settings) */
1965 backlight_use_settings(rb); /* backlight control in lib/helper.c */
1966 return retval;