Pass plugin api pointer to funtion directly, fixes crashes when doing incremental...
[kugel-rb.git] / apps / plugins / spacerocks.c
blob1278a611ce3b0c2781a40c43dd609ce734beab69
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_UP
132 #define AST_LEFT_REP (BUTTON_SCROLL_UP | BUTTON_REPEAT)
133 #define AST_RIGHT BUTTON_SCROLL_DOWN
134 #define AST_RIGHT_REP (BUTTON_SCROLL_DOWN | BUTTON_REPEAT)
135 #define AST_FIRE BUTTON_SELECT
136 #define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT)
138 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
139 #define AST_PAUSE BUTTON_PLAY
140 #define AST_QUIT BUTTON_POWER
141 #define AST_THRUST_REP BUTTON_SCROLL_UP | BUTTON_REPEAT
142 #define AST_THRUST BUTTON_SCROLL_UP
143 #define AST_HYPERSPACE BUTTON_SCROLL_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_REW
149 #define AST_FIRE_REP BUTTON_REW | BUTTON_REPEAT
151 #endif
153 #define ABS(x) ((x)>0?(x):-(x))
155 #define RES MAX(LCD_WIDTH, LCD_HEIGHT)
156 #define LARGE_LCD RES >= 200
157 #define ENEMY_MISSILE_SURVIVAL_LENGTH RES/2
158 #define ASTEROID_SPEED RES/20
159 #define MISSILE_SURVIVAL_LENGTH 40
161 #define EXTRA_LIFE 250
162 #define SCALE 5000
163 #define MISSILE_SCALE 5000
164 #define WRAP_GAP 12
165 #define EXPLOSION_LENGTH 20
166 #define SHOW_COL 0
167 #define HISCORE_FILE PLUGIN_GAMES_DIR "/astrorocks.hs"
168 #define POINT_SIZE 2
169 #define MAX_NUM_ASTEROIDS 25
170 #define MAX_NUM_MISSILES 6
171 #define ENEMY_BIG_PROBABILITY_START 10
172 #define ENEMY_APPEAR_PROBABILITY_START 35
173 #define ENEMY_APPEAR_TIMING_START 1800
174 #define LITTLE_SHIP 2
175 #define BIG_SHIP 1
176 #define SHOW_GAME_OVER_TIME 100
177 #define SHOW_LEVEL_TIME 50
178 #define START_LIVES 3
179 #define START_LEVEL 1
180 #define NUM_ASTEROID_VERTICES 10
181 #define NUM_SHIP_VERTICES 4
182 #define NUM_ENEMY_VERTICES 6
183 #define MAX_LEVEL MAX_NUM_ASTEROIDS
184 #define ENEMY_SPEED 4
185 #define ENEMY_START_X 0
186 #define ENEMY_START_Y 0
187 #define SIZE_ENEMY_COLLISION 5*SCALE
188 #define ATTRACT_FLIP_TIME 100
189 #define NUM_STARS 50
190 #define NUM_TRAIL_POINTS 70
191 #define NUM_ROTATIONS 16
193 #define SIN_COS_SCALE 10000
195 #define FAST_ROT_CW_SIN 873
196 #define FAST_ROT_CW_COS 9963
197 #define FAST_ROT_ACW_SIN -873
198 #define FAST_ROT_ACW_COS 9963
200 #define MEDIUM_ROT_CW_SIN 350
201 #define MEDIUM_ROT_CW_COS 9994
202 #define MEDIUM_ROT_ACW_SIN -350
203 #define MEDIUM_ROT_ACW_COS 9994
205 #define SLOW_ROT_CW_SIN 350
206 #define SLOW_ROT_CW_COS 9994
207 #define SLOW_ROT_ACW_SIN - 350
208 #define SLOW_ROT_ACW_COS 9994
210 #ifdef HAVE_LCD_COLOR
211 #define SHIP_ROT_CW_SIN 2419
212 #define SHIP_ROT_CW_COS 9702
213 #define SHIP_ROT_ACW_SIN -2419
214 #define SHIP_ROT_ACW_COS 9702
215 #else
216 #define SHIP_ROT_CW_SIN 3827
217 #define SHIP_ROT_CW_COS 9239
218 #define SHIP_ROT_ACW_SIN -3827
219 #define SHIP_ROT_ACW_COS 9239
220 #endif
223 #define SCALED_WIDTH (LCD_WIDTH*SCALE)
224 #define SCALED_HEIGHT (LCD_HEIGHT*SCALE)
225 #define CENTER_LCD_X (LCD_WIDTH/2)
226 #define CENTER_LCD_Y (LCD_HEIGHT/2)
228 #define SHIP_EXPLOSION_COLOUR 1
229 #define ASTEROID_EXPLOSION_COLOUR 2
230 #define ENEMY_EXPLOSION_COLOUR 3
231 #define THRUST_COLOUR 4
233 #define ASTEROID_R 230
234 #define ASTEROID_G 200
235 #define ASTEROID_B 100
236 #define SHIP_R 255
237 #define SHIP_G 255
238 #define SHIP_B 255
239 #define ENEMY_R 50
240 #define ENEMY_G 220
241 #define ENEMY_B 50
242 #define THRUST_R 200
243 #define THRUST_G 200
244 #define THRUST_B 0
246 #ifdef HAVE_LCD_COLOR
247 #define COL_MISSILE LCD_RGBPACK(200,0,0)
248 #define COL_PLAYER LCD_RGBPACK(200,200,200)
249 #define COL_STARS LCD_WHITE
250 #define COL_ASTEROID LCD_RGBPACK(ASTEROID_R,ASTEROID_G,ASTEROID_B)
251 #define COL_TEXT LCD_RGBPACK(200,200,255)
252 #define COL_ENEMY LCD_RGBPACK(ENEMY_R,ENEMY_G,ENEMY_B)
253 #define SET_FG rb->lcd_set_foreground
254 #define SET_BG rb->lcd_set_background
255 #else
256 #define SET_FG(x)
257 #define SET_BG(x)
258 #endif
260 /* The array of points that make up an asteroid */
261 static const short asteroid_one[NUM_ASTEROID_VERTICES*2] =
263 -2, -12,
264 4, -8,
265 8, -14,
266 16, -5,
267 14, 0,
268 20, 2,
269 12, 14,
270 -4, 14,
271 -10, 6,
272 -10, -8
275 /* The array of points that make up an asteroid */
276 static const short asteroid_two[NUM_ASTEROID_VERTICES*2] =
278 -2, -12,
279 4, -16,
280 6, -14,
281 16, -8,
282 14, 0,
283 20, 2,
284 12, 14,
285 -4, 14,
286 -10, 6,
287 -10, -8
290 /* The array of points that make up an asteroid */
291 static const short asteroid_three[NUM_ASTEROID_VERTICES*2] =
293 -2, -12,
294 4, -16,
295 6, -14,
296 2, -8,
297 14, 0,
298 20, 2,
299 12, 14,
300 -4, 14,
301 -16, 6,
302 -10, -8
305 /* The array od points the make up the ship */
306 static const short ship_vertices[NUM_SHIP_VERTICES*2] =
308 #if(LARGE_LCD)
309 0,-6,
310 4, 6,
311 0, 2,
312 -4, 6
313 #else
314 0,-4,
315 3, 4,
316 0, 1,
317 -3, 4
318 #endif
321 /* The array of points the make up the bad spaceship */
322 static const short enemy_vertices[NUM_ENEMY_VERTICES*2] =
324 #if(LARGE_LCD)
325 -8, 0,
326 -4, 4,
327 4, 4,
328 8, 0,
329 4, -4,
330 -4, -4
331 #else
332 -5, 0,
333 -2, 2,
334 2, 2,
335 5, 0,
336 2, -2,
337 -2, -2
338 #endif
342 enum asteroid_type
344 #if(LARGE_LCD)
345 SMALL = 2,
346 MEDIUM = 4,
347 LARGE = 6,
348 #else
349 SMALL = 1,
350 MEDIUM = 2,
351 LARGE = 3,
352 #endif
356 enum game_state
358 GAME_OVER,
359 ATTRACT_MODE,
360 SHOW_LEVEL,
361 PLAY_MODE,
362 PAUSE_MODE
365 struct Point
367 int x;
368 int y;
369 int dx;
370 int dy;
373 struct TrailPoint
375 int alive;
376 struct Point position;
377 short r;
378 short g;
379 short b;
380 short dec;
383 /* Asteroid structure, contains an array of points */
384 struct Asteroid
386 enum asteroid_type type;
387 bool exists;
388 struct Point position;
389 struct Point vertices[NUM_ASTEROID_VERTICES];
390 int radius;
391 long speed_cos;
392 long speed_sin;
393 int explode_countdown;
396 struct Ship
398 struct Point vertices[NUM_SHIP_VERTICES];
399 struct Point position;
400 bool waiting_for_space;
401 int explode_countdown;
404 struct Enemy
406 struct Point vertices[NUM_ENEMY_VERTICES];
407 struct Point position;
408 int explode_countdown;
409 long last_time_appeared;
410 short size_probability;
411 short appear_probability;
412 short appear_timing;
415 struct Missile
417 struct Point position;
418 struct Point oldpoint;
419 int survived;
422 static enum game_state game_state;
423 static int asteroid_count;
424 static int next_missile_count;
425 static int next_thrust_count;
426 static int num_lives;
427 static int extra_life;
428 static int show_level_timeout;
429 static int attract_flip_timeout;
430 static int show_game_over;
431 static int current_level;
432 static int current_score;
433 static int high_score;
434 static int space_check_size = 30*SCALE;
436 static bool enemy_on_screen;
437 static char phscore[30];
438 static struct Ship ship;
439 static struct Point stars[NUM_STARS];
440 static struct Asteroid asteroids_array[MAX_NUM_ASTEROIDS];
441 static struct Missile missiles_array[MAX_NUM_MISSILES];
442 static struct Missile enemy_missile;
443 static struct Enemy enemy;
444 static struct Point lives_points[NUM_SHIP_VERTICES];
445 static struct TrailPoint trailPoints[NUM_TRAIL_POINTS];
447 void draw_and_move_asteroids(void);
448 void initialise_game(int nStartNum);
450 bool is_asteroid_near_ship(struct Asteroid* asteroid);
451 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point);
453 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type eType);
454 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices);
455 void rotate_asteroid(struct Asteroid* asteroid);
456 void create_asteroid(enum asteroid_type type, int x, int y);
457 void create_stars(void);
459 void initialise_ship(void);
460 void draw_and_move_ship(void);
461 void rotate_ship(int s, int c);
462 void thrust_ship(void);
464 void initialise_missile(struct Missile* missile);
465 void draw_and_move_missiles(void);
466 void fire_missile(void);
468 void animate_and_draw_explosion(struct Point* point, int num_points, int xoffset, int yoffset);
469 void initialise_explosion(struct Point* point, int num_points);
471 void move_point(struct Point* point);
472 void hyperspace(void);
473 void check_collisions(void);
474 void initialise_enemy(void);
475 void draw_and_move_enemy(void);
476 void draw_lives(void);
477 void drawstars(void);
478 bool is_ship_within_asteroid(struct Asteroid* asteroid);
482 /*Hi-Score reading and writing to file - this needs moving to the hi-score plugin lib as
483 a 3rd function */
484 void iohiscore(void)
486 int fd;
487 int compare;
489 /* clear the buffer we're about to load the highscore data into */
490 rb->memset(phscore, 0, sizeof(phscore));
492 fd = rb->open(HISCORE_FILE,O_RDWR | O_CREAT);
493 if(fd < 0)
495 rb->splash(HZ, "Highscore file read error");
496 return;
499 /* highscore used to %d, is now %d\n
500 Deal with no file or bad file */
501 rb->read(fd,phscore, sizeof(phscore));
503 compare = rb->atoi(phscore);
505 if(high_score > compare)
507 rb->lseek(fd,0,SEEK_SET);
508 rb->fdprintf(fd, "%d\n", high_score);
510 else
511 high_score = compare;
513 rb->close(fd);
516 bool point_in_poly(struct Point* _point, int num_vertices, int x, int y)
518 struct Point* pi;
519 struct Point* pj;
520 int n;
521 bool c = false;
523 pi = _point;
524 pj = _point;
525 pj += num_vertices-1;
527 n = num_vertices;
528 while(n--)
530 if((((pi->y <= y) && (y < pj->y)) || ((pj->y <= y) && (y < pi->y))) &&
531 (x < (pj->x - pi->x) * (y - pi->y) / (pj->y - pi->y) + pi->x))
532 c = !c;
534 if(n == num_vertices - 1)
535 pj = _point;
536 else
537 pj++;
539 pi++;
542 return c;
545 void move_point(struct Point* point)
547 point->x += point->dx;
548 point->y += point->dy;
550 /*check bounds on the x-axis:*/
551 if(point->x >= SCALED_WIDTH)
552 point->x = 0;
553 else if(point->x <= 0)
554 point->x = SCALED_WIDTH;
556 /*Check bounds on the y-axis:*/
557 if(point->y >= SCALED_HEIGHT)
558 point->y = 0;
559 else if(point->y <= 0)
560 point->y = SCALED_HEIGHT;
563 void create_trail(struct TrailPoint* tpoint)
565 tpoint->position.dx = -( ship.vertices[0].x - ship.vertices[2].x )/10;
566 tpoint->position.dy = -( ship.vertices[0].y - ship.vertices[2].y )/10;
569 void create_explosion_trail(struct TrailPoint* tpoint)
571 tpoint->position.dx = (rb->rand()%5050)-2500;
572 tpoint->position.dy = (rb->rand()%5050)-2500;
575 void create_trail_blaze(int colour, struct Point* position)
577 int numtoadd;
578 struct TrailPoint* tpoint;
579 int n;
580 int xadd,yadd;
581 if(colour != SHIP_EXPLOSION_COLOUR)
583 numtoadd = NUM_TRAIL_POINTS/5;
584 xadd = position->x;
585 yadd = position->y;
587 else
589 numtoadd = NUM_TRAIL_POINTS/8;
590 xadd = ship.position.x;
591 yadd = ship.position.y;
594 /* give the point a random countdown timer, so they dissapears at different times */
595 tpoint = trailPoints;
596 n = NUM_TRAIL_POINTS;
597 while(--n)
599 if(tpoint->alive <= 0 && numtoadd)
601 numtoadd--;
602 /* take a random x point anywhere between bottom two points of ship. */
603 /* ship.position.x; */
604 tpoint->position.x = (ship.vertices[2].x + (rb->rand()%18000)-9000) + position->x;
605 tpoint->position.y = (ship.vertices[2].y + (rb->rand()%18000)-9000) + position->y;
607 switch(colour)
609 case SHIP_EXPLOSION_COLOUR:
610 tpoint->r = 255;
611 tpoint->g = 255;
612 tpoint->b = 255;
613 create_explosion_trail(tpoint);
614 tpoint->alive = 510;
615 tpoint->dec = 2;
616 break;
617 case ASTEROID_EXPLOSION_COLOUR:
618 tpoint->r = ASTEROID_R;
619 tpoint->g = ASTEROID_G;
620 tpoint->b = ASTEROID_B;
621 create_explosion_trail(tpoint);
622 tpoint->alive = 510;
623 tpoint->dec = 2;
624 break;
625 case ENEMY_EXPLOSION_COLOUR:
626 tpoint->r = ENEMY_R;
627 tpoint->g = ENEMY_G;
628 tpoint->b = ENEMY_B;
629 create_explosion_trail(tpoint);
630 tpoint->alive = 510;
631 tpoint->dec = 2;
632 break;
633 case THRUST_COLOUR:
634 tpoint->r = THRUST_R;
635 tpoint->g = THRUST_G;
636 tpoint->b = THRUST_B;
637 create_trail(tpoint);
638 tpoint->alive = 175;
639 tpoint->dec = 4;
640 break;
642 /* add a proportional bit to the x and y based on dx and dy */
644 /* give the points a speed based on direction of travel - i.e. opposite */
645 tpoint->position.dx += position->dx;
646 tpoint->position.dy += position->dy;
650 tpoint++;
652 /* find a space in the array of trail_points that is NULL or DEAD or whatever.
653 and place this one here. */
657 void draw_trail_blaze(void)
659 struct TrailPoint* tpoint;
660 /* loop through, if alive then move and draw.
661 when drawn, countdown it's timer.
662 if zero kill it! */
663 tpoint = trailPoints;
664 int n = NUM_TRAIL_POINTS;
666 while(--n)
668 if(tpoint->alive)
670 if(game_state != PAUSE_MODE)
672 tpoint->alive-=10;
673 move_point(&(tpoint->position));
675 #ifdef HAVE_LCD_COLOR
676 /* intensity = tpoint->alive/2; */
677 if(tpoint->r>0)tpoint->r-=tpoint->dec;
678 if(tpoint->g>0)tpoint->g-=tpoint->dec;
679 if(tpoint->b>0)tpoint->b-=tpoint->dec;
680 SET_FG(LCD_RGBPACK(tpoint->r, tpoint->g, tpoint->b));
681 #endif
682 rb->lcd_drawpixel(tpoint->position.x/SCALE , tpoint->position.y/SCALE);
684 tpoint++;
688 /*Check if point is within a rectangle*/
689 bool is_point_within_rectangle(struct Point* rect, struct Point* p, int size)
691 #if SHOW_COL
692 int aTLx = rect->x - size;
693 int aTLy = rect->y - size;
694 int aBRx = rect->x + size;
695 int aBRy = rect->y + size;
696 rb->lcd_drawline( aTLx/SCALE, aTLy/SCALE, aBRx/SCALE, aTLy/SCALE);
697 rb->lcd_drawline( aTLx/SCALE, aTLy/SCALE, aTLx/SCALE, aBRy/SCALE);
698 rb->lcd_drawline( aTLx/SCALE, aBRy/SCALE, aBRx/SCALE, aBRy/SCALE);
699 rb->lcd_drawline( aBRx/SCALE, aBRy/SCALE, aBRx/SCALE, aTLy/SCALE);
700 return (p->x > aTLx && p->x < aBRx && p->y > aTLy && p->y < aBRy);
701 #else
702 return (p->x > rect->x - size && p->x < rect->x + size &&
703 p->y > rect->y - size && p->y < rect->y + size);
704 #endif
707 /* Draw polygon */
708 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices)
710 int n, t1, t2, oldX, oldY;
711 struct Point *p;
712 bool bDrawAll = px < WRAP_GAP || LCD_WIDTH - px < WRAP_GAP ||
713 py < WRAP_GAP || LCD_HEIGHT - py < WRAP_GAP;
715 p = vertices;
716 p += num_vertices-1;
717 oldX = p->x/SCALE + px;
718 oldY = p->y/SCALE + py;
719 p = vertices;
720 for(n = num_vertices+1; --n;)
722 t1 = p->x/SCALE + px;
723 t2 = p->y/SCALE + py;
725 rb->lcd_drawline(oldX, oldY, t1, t2);
727 if(bDrawAll)
729 rb->lcd_drawline(oldX - LCD_WIDTH, oldY, t1 - LCD_WIDTH, t2);
730 rb->lcd_drawline(oldX + LCD_WIDTH, oldY, t1 + LCD_WIDTH, t2);
731 rb->lcd_drawline(oldX - LCD_WIDTH, oldY + LCD_HEIGHT,
732 t1 - LCD_WIDTH, t2 + LCD_HEIGHT);
733 rb->lcd_drawline(oldX + LCD_WIDTH, oldY + LCD_HEIGHT,
734 t1 + LCD_WIDTH, t2 + LCD_HEIGHT);
736 rb->lcd_drawline(oldX, oldY - LCD_HEIGHT, t1, t2 - LCD_HEIGHT);
737 rb->lcd_drawline(oldX, oldY + LCD_HEIGHT, t1, t2 + LCD_HEIGHT);
738 rb->lcd_drawline(oldX - LCD_WIDTH, oldY - LCD_HEIGHT,
739 t1 - LCD_WIDTH, t2 - LCD_HEIGHT);
740 rb->lcd_drawline(oldX + LCD_WIDTH, oldY - LCD_HEIGHT,
741 t1 + LCD_WIDTH, t2 - LCD_HEIGHT);
743 oldX = t1;
744 oldY = t2;
745 p++;
749 void animate_and_draw_explosion(struct Point* point, int num_points,
750 int xoffset, int yoffset)
752 int n;
753 for(n = num_points; --n;)
755 if(game_state != PAUSE_MODE)
757 point->x += point->dx;
758 point->y += point->dy;
760 rb->lcd_fillrect( point->x/SCALE + xoffset, point->y/SCALE + yoffset,
761 POINT_SIZE, POINT_SIZE);
762 point++;
766 /*stop movement of ship, 'cos that's what happens when you go into hyperspace.*/
767 void hyperspace(void)
769 ship.position.dx = ship.position.dy = 0;
770 ship.position.x = (rb->rand()%SCALED_WIDTH);
771 ship.position.y = (rb->rand()%SCALED_HEIGHT);
774 void initialise_enemy(void)
776 struct Point* point;
777 int n;
778 int size;
780 if(rb->rand()%100 > enemy.size_probability)
782 size = BIG_SHIP;
783 enemy.size_probability++;
784 if(enemy.size_probability < 90)
786 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
789 else
791 size = LITTLE_SHIP;
794 enemy_missile.survived = 0;
795 enemy_on_screen = true;
796 enemy.explode_countdown = 0;
797 enemy.last_time_appeared = *rb->current_tick;
798 point = enemy.vertices;
799 for(n = 0; n < NUM_ENEMY_VERTICES+NUM_ENEMY_VERTICES; n+=2)
801 point->x = enemy_vertices[n];
802 point->y = enemy_vertices[n+1];
803 point->x *= SCALE/size;
804 point->y *= SCALE/size;
805 point++;
808 if(ship.position.x >= SCALED_WIDTH/2)
810 enemy.position.dx = ENEMY_SPEED;
811 enemy.position.x = 0;
813 else
815 enemy.position.dx = -ENEMY_SPEED;
816 enemy.position.x = SCALED_WIDTH;
819 if(ship.position.y >= SCALED_HEIGHT/2)
821 enemy.position.dy = ENEMY_SPEED;
822 enemy.position.y = 0;
824 else
826 enemy.position.dy = -ENEMY_SPEED;
827 enemy.position.y = SCALED_HEIGHT;
830 enemy.position.dx *= SCALE/10;
831 enemy.position.dy *= SCALE/10;
834 void draw_and_move_enemy(void)
836 int enemy_x, enemy_y;
837 struct Point *point;
839 SET_FG(COL_ENEMY);
841 if(enemy_on_screen)
843 enemy_x = enemy.position.x/SCALE;
844 enemy_y = enemy.position.y/SCALE;
845 if(!enemy.explode_countdown)
847 point = enemy.vertices;
848 draw_polygon(enemy.vertices, enemy_x, enemy_y, NUM_ENEMY_VERTICES);
849 rb->lcd_drawline(enemy.vertices[0].x/SCALE + enemy_x,
850 enemy.vertices[0].y/SCALE + enemy_y,
851 enemy.vertices[3].x/SCALE + enemy_x,
852 enemy.vertices[3].y/SCALE + enemy_y);
854 if(game_state != PAUSE_MODE)
856 enemy.position.x += enemy.position.dx;
857 enemy.position.y += enemy.position.dy;
860 if(enemy.position.x > SCALED_WIDTH || enemy.position.x < 0)
861 enemy_on_screen = false;
863 if(enemy.position.y > SCALED_HEIGHT)
864 enemy.position.y = 0;
865 else if(enemy.position.y < 0)
866 enemy.position.y = SCALED_HEIGHT;
868 if( (rb->rand()%1000) < 10)
869 enemy.position.dy = -enemy.position.dy;
871 else
874 /* animate_and_draw_explosion(enemy.vertices, NUM_ENEMY_VERTICES,
875 enemy_x, enemy.position.y/SCALE); */
876 if(game_state != PAUSE_MODE)
878 enemy.explode_countdown--;
879 if(!enemy.explode_countdown)
880 enemy_on_screen = false;
884 else
886 if( (*rb->current_tick - enemy.last_time_appeared) > enemy.appear_timing)
887 if(rb->rand()%100 > enemy.appear_probability) initialise_enemy();
890 if(!enemy_missile.survived && game_state != GAME_OVER)
892 /*if no missile and the enemy is here and not exploding..then shoot baby!*/
893 if( !enemy.explode_countdown && enemy_on_screen &&
894 !ship.waiting_for_space && (rb->rand()%10) > 5 )
896 enemy_missile.position.x = enemy.position.x;
897 enemy_missile.position.y = enemy.position.y;
899 /*lame, needs to be sorted - it's trying to shoot at the ship*/
900 if(ABS(enemy.position.y - ship.position.y) <= 5*SCALE)
902 enemy_missile.position.dy = 0;
904 else
906 if( enemy.position.y < ship.position.y)
907 enemy_missile.position.dy = 1;
908 else
909 enemy_missile.position.dy = -1;
912 if(ABS(enemy.position.x - ship.position.x) <= 5*SCALE)
913 enemy_missile.position.dx = 0;
914 else
916 if( enemy.position.x < ship.position.x)
917 enemy_missile.position.dx = 1;
918 else
919 enemy_missile.position.dx = -1;
922 if(enemy_missile.position.dx == 0 &&
923 enemy_missile.position.dy == 0)
924 enemy_missile.position.dx = enemy_missile.position.dy = -1;
926 enemy_missile.position.dx *= SCALE;
927 enemy_missile.position.dy *= SCALE;
928 enemy_missile.survived = ENEMY_MISSILE_SURVIVAL_LENGTH;
932 else
934 rb->lcd_fillrect( enemy_missile.position.x/SCALE,
935 enemy_missile.position.y/SCALE,
936 POINT_SIZE, POINT_SIZE);
937 if(game_state != PAUSE_MODE)
939 move_point(&enemy_missile.position);
940 enemy_missile.survived--;
945 /******************
946 * Lame method of collision
947 * detection. It's checking for collision
948 * between point and a big rectangle around the asteroid...
949 *******************/
950 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point)
952 if( !is_point_within_rectangle(&asteroid->position, point,
953 asteroid->radius+4*SCALE) )
954 return false;
956 if(point_in_poly(asteroid->vertices, NUM_ASTEROID_VERTICES,
957 point->x - asteroid->position.x,
958 point->y - asteroid->position.y))
960 switch(asteroid->type)
962 case(SMALL):
963 asteroid->explode_countdown = EXPLOSION_LENGTH;
964 create_trail_blaze(ASTEROID_EXPLOSION_COLOUR, &asteroid->position);
965 break;
967 case(LARGE):
968 create_asteroid(MEDIUM, asteroid->position.x,
969 asteroid->position.y);
970 create_asteroid(MEDIUM, asteroid->position.x,
971 asteroid->position.y);
972 break;
974 case(MEDIUM):
975 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
976 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
977 break;
980 current_score++;
981 if(current_score > extra_life)
983 num_lives++;
984 extra_life = current_score+EXTRA_LIFE;
986 asteroid_count--;
987 asteroid->exists = false;
988 return true;
990 else
991 return false;
994 bool is_point_within_enemy(struct Point* point)
996 if( is_point_within_rectangle(&enemy.position, point, 7*SCALE) )
998 current_score += 5;
999 /*enemy_missile.survived = 0;*/
1000 enemy.explode_countdown = EXPLOSION_LENGTH;
1001 /* initialise_explosion(enemy.vertices, NUM_ENEMY_VERTICES); */
1002 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1003 return true;
1005 else
1006 return false;
1009 bool is_ship_within_asteroid(struct Asteroid* asteroid)
1011 bool hit = false;
1012 struct Point p;
1014 p.x = ship.position.x + ship.vertices[0].x;
1015 p.y = ship.position.y + ship.vertices[0].y;
1016 hit |= is_point_within_asteroid(asteroid, &p);
1018 if(!hit)
1020 p.x = ship.position.x + ship.vertices[1].x;
1021 p.y = ship.position.y + ship.vertices[1].y;
1022 hit |= is_point_within_asteroid(asteroid, &p);
1023 if(!hit)
1025 p.x = ship.position.x + ship.vertices[3].x;
1026 p.y = ship.position.y + ship.vertices[3].y;
1027 hit |= is_point_within_asteroid(asteroid, &p);
1031 return hit;
1034 void initialise_explosion(struct Point* point, int num_points)
1036 int n;
1038 point->x += point->dx;
1039 point->y += point->dy;
1040 for(n = num_points; --n;)
1042 point->dx = point->x;
1043 point->dy = point->y;
1044 point++;
1049 /* Check for collsions between the missiles and the asteroids and the ship */
1050 void check_collisions(void)
1052 int m, n;
1053 bool asteroids_onscreen = false;
1054 struct Missile* missile;
1055 struct Asteroid* asteroid;
1056 bool ship_cant_be_placed = false;
1058 asteroid = asteroids_array;
1059 m = MAX_NUM_ASTEROIDS;
1060 while(--m)
1062 /*if the asteroids exists then test missile collision:*/
1063 if(asteroid->exists)
1065 missile = missiles_array;
1066 n = MAX_NUM_MISSILES;
1067 while(--n)
1069 /*if the missiles exists:*/
1070 if(missile->survived > 0)
1072 /*has the missile hit the asteroid?*/
1073 if(is_point_within_asteroid(asteroid, &missile->position)
1074 || is_point_within_asteroid(asteroid,
1075 &missile->oldpoint))
1077 missile->survived = 0;
1078 break;
1081 missile++;
1084 /*now check collision with ship:*/
1085 if(asteroid->exists && !ship.waiting_for_space && !ship.explode_countdown)
1087 if(is_ship_within_asteroid(asteroid))
1089 /*blow up ship*/
1090 ship.explode_countdown = EXPLOSION_LENGTH;
1091 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1092 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1095 /*has the enemy missile blown something up?*/
1096 if(asteroid->exists && enemy_missile.survived)
1098 if(is_point_within_asteroid(asteroid, &enemy_missile.position))
1100 /*take that score back then:*/
1101 if(current_score > 0) current_score--;
1102 enemy_missile.survived = 0;
1105 /*if it still exists, check if ship is waiting for space:*/
1106 if(asteroid->exists && ship.waiting_for_space)
1107 ship_cant_be_placed |=
1108 is_point_within_rectangle(&ship.position,
1109 &asteroid->position,
1110 space_check_size);
1114 /*is an asteroid still exploding?*/
1115 if(asteroid->explode_countdown)
1116 asteroids_onscreen = true;
1118 asteroid++;
1121 /*now check collision between ship and enemy*/
1122 if(enemy_on_screen && !ship.waiting_for_space &&
1123 !ship.explode_countdown && !enemy.explode_countdown)
1125 /*has the enemy collided with the ship?*/
1126 if(is_point_within_enemy(&ship.position))
1128 ship.explode_countdown = EXPLOSION_LENGTH;
1129 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1130 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1131 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1134 /*Now see if the enemy has been shot at by the ships missiles:*/
1135 missile = missiles_array;
1136 n = MAX_NUM_MISSILES;
1137 while(--n)
1139 if(missile->survived > 0 &&
1140 is_point_within_enemy(&missile->position))
1142 missile->survived = 0;
1143 break;
1145 missile++;
1149 /*test collision with enemy missile and ship:*/
1150 if(!ship_cant_be_placed && enemy_missile.survived > 0 &&
1151 point_in_poly(ship.vertices, NUM_SHIP_VERTICES,
1152 enemy_missile.position.x - ship.position.x,
1153 enemy_missile.position.y - ship.position.y))
1155 ship.explode_countdown = EXPLOSION_LENGTH;
1156 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1157 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1158 enemy_missile.survived = 0;
1159 enemy_missile.position.x = enemy_missile.position.y = 0;
1162 if(!ship_cant_be_placed)
1163 ship.waiting_for_space = false;
1165 /*if all asteroids cleared then start again:*/
1166 if(asteroid_count == 0 && !enemy_on_screen && !asteroids_onscreen)
1168 current_level++;
1169 game_state = SHOW_LEVEL;
1170 enemy.appear_probability += 5;
1171 enemy.appear_timing -= 200;
1172 if( enemy.appear_probability > 100)
1173 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1174 show_level_timeout = SHOW_LEVEL_TIME;
1178 /*************************************************
1179 ** Creates a new asteroid of the given 4type (size)
1180 ** and at the given location.
1181 *************************************************/
1182 void create_asteroid(enum asteroid_type type, int x, int y)
1184 struct Asteroid* asteroid;
1185 int n;
1187 asteroid = asteroids_array;
1188 n = MAX_NUM_ASTEROIDS;
1189 while(--n)
1191 if(!asteroid->exists && !asteroid->explode_countdown)
1193 initialise_asteroid(asteroid, type);
1194 asteroid->position.x = x;
1195 asteroid->position.y = y;
1196 break;
1198 asteroid++;
1202 /* Initialise a missile */
1203 void initialise_missile(struct Missile* missile)
1205 missile->position.x = ship.position.x + ship.vertices[0].x;
1206 missile->position.y = ship.position.y + ship.vertices[0].y;
1207 missile->position.dx = (ship.vertices[0].x - ship.vertices[2].x)/2;
1208 missile->position.dy = (ship.vertices[0].y - ship.vertices[2].y)/2;
1209 missile->survived = MISSILE_SURVIVAL_LENGTH;
1210 missile->oldpoint.x = missile->position.x;
1211 missile->oldpoint.y = missile->position.y;
1214 /* Draw and Move all the missiles */
1215 void draw_and_move_missiles(void)
1217 int n;
1218 int p1x, p1y;
1219 int p2x, p2y;
1221 struct Missile* missile;
1222 missile = missiles_array;
1224 SET_FG(COL_MISSILE);
1226 n = MAX_NUM_MISSILES;
1227 while(--n)
1229 if(missile->survived)
1231 if(missile->position.dx > 0)
1233 if(missile->position.x >= missile->oldpoint.x)
1235 p1x = missile->oldpoint.x;
1236 p2x = missile->position.x;
1238 else
1240 p1x = 0;
1241 p2x = missile->position.x;
1244 else
1246 if(missile->oldpoint.x >= missile->position.x)
1248 p1x = missile->oldpoint.x;
1249 p2x = missile->position.x;
1251 else
1253 p1x = missile->oldpoint.x;
1254 p2x = LCD_WIDTH;
1258 if(missile->position.dy > 0)
1260 if(missile->position.y >= missile->oldpoint.y)
1262 p1y = missile->oldpoint.y;
1263 p2y = missile->position.y;
1265 else
1267 p1y = 0;
1268 p2y = missile->position.y;
1271 else
1273 if(missile->oldpoint.y >= missile->position.y)
1275 p1y = missile->oldpoint.y;
1276 p2y = missile->position.y;
1278 else
1280 p1y = missile->oldpoint.y;
1281 p2y = LCD_HEIGHT;
1285 rb->lcd_drawline( p1x/SCALE, p1y/SCALE, p2x/SCALE, p2y/SCALE);
1287 if(game_state != PAUSE_MODE)
1289 missile->oldpoint.x = missile->position.x;
1290 missile->oldpoint.y = missile->position.y;
1291 move_point(&missile->position);
1292 missile->survived--;
1295 missile++;
1299 void draw_lives(void)
1301 int n;
1302 int px = (LCD_WIDTH - num_lives*4 - 1);
1303 #if(LARGE_LCD)
1304 int py = (LCD_HEIGHT-6);
1305 #else
1306 int py = (LCD_HEIGHT-4);
1307 #endif
1309 SET_FG(COL_PLAYER);
1311 n = num_lives;
1312 while(--n)
1314 draw_polygon(lives_points, px, py, NUM_SHIP_VERTICES);
1315 #if(LARGE_LCD)
1316 px += 8;
1317 #else
1318 px += 6;
1319 #endif
1323 /*Fire the next missile*/
1324 void fire_missile(void)
1326 int n;
1327 struct Missile* missile;
1329 if(!ship.explode_countdown && !ship.waiting_for_space)
1331 missile = missiles_array;
1332 n = MAX_NUM_MISSILES;
1333 while(--n)
1335 if(!missile->survived)
1337 initialise_missile(missile);
1338 break;
1340 missile++;
1345 /* Initialise the passed Asteroid */
1346 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type type)
1348 int n;
1349 bool b,b2;
1350 struct Point* point;
1351 asteroid->exists = true;
1352 asteroid->type = type;
1353 asteroid->explode_countdown = 0;
1355 /*Set the radius of the asteroid:*/
1356 asteroid->radius = (int)type*SCALE;
1358 /*shall we move Clockwise and Fast*/
1359 if((rb->rand()%100)>75)
1361 asteroid->speed_cos = FAST_ROT_CW_COS;
1362 asteroid->speed_sin = FAST_ROT_CW_SIN;
1364 else if((rb->rand()%100)>75)
1366 asteroid->speed_cos = FAST_ROT_ACW_COS;
1367 asteroid->speed_sin = FAST_ROT_ACW_SIN;
1369 else if((rb->rand()%100)>75)
1371 asteroid->speed_cos = SLOW_ROT_ACW_COS;
1372 asteroid->speed_sin = SLOW_ROT_ACW_SIN;
1374 else
1376 asteroid->speed_cos = SLOW_ROT_CW_COS;
1377 asteroid->speed_sin = SLOW_ROT_CW_SIN;
1380 b = (rb->rand()%100)>66;
1381 b2 = (rb->rand()%100)>66;
1382 point = asteroid->vertices;
1383 for(n = 0; n < NUM_ASTEROID_VERTICES*2; n+=2)
1385 if(b)
1387 point->x = asteroid_one[n];
1388 point->y = asteroid_one[n+1];
1390 else if( b2 )
1392 point->x = asteroid_two[n];
1393 point->y = asteroid_two[n+1];
1395 else
1397 point->x = asteroid_three[n];
1398 point->y = asteroid_three[n+1];
1401 point->x *= asteroid->radius/6;
1402 point->y *= asteroid->radius/6;
1403 point++;
1407 asteroid->radius += 6*SCALE;
1408 if(asteroid->type == SMALL)
1409 asteroid->radius /= 3;/*2*/
1410 else if(asteroid->type == LARGE)
1411 asteroid->radius += 3*SCALE;/*2*/
1412 b = true;
1413 while(b)
1415 /*Set the position randomly:*/
1416 asteroid->position.x = (rb->rand()%SCALED_WIDTH);
1417 asteroid->position.y = (rb->rand()%SCALED_HEIGHT);
1419 asteroid->position.dx = 0;
1420 while(asteroid->position.dx == 0)
1421 asteroid->position.dx = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1423 asteroid->position.dy = 0;
1424 while(asteroid->position.dy == 0)
1425 asteroid->position.dy = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1427 asteroid->position.dx *= SCALE/10;
1428 asteroid->position.dy *= SCALE/10;
1430 b = is_point_within_rectangle(&ship.position, &asteroid->position,
1431 space_check_size);
1434 /*Now rotate the asteroid a bit, so they all look a bit different*/
1435 for(n=(rb->rand()%30) + 2;--n;)
1436 rotate_asteroid(asteroid);
1438 /*great, we've created an asteroid, don't forget to increment the total:*/
1439 asteroid_count++;
1442 /*Initialise the ship*/
1443 void initialise_ship(void)
1445 struct Point* point;
1446 struct Point* lives_point;
1447 int n;
1449 ship.position.x = CENTER_LCD_X;
1450 ship.position.y = CENTER_LCD_Y;
1451 ship.position.x *= SCALE;
1452 ship.position.y *= SCALE;
1453 ship.position.dx = ship.position.dy = 0;
1455 point = ship.vertices;
1456 lives_point = lives_points;
1457 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1459 point->x = ship_vertices[n];
1460 point->y = ship_vertices[n+1];
1461 point->x *= SCALE;
1462 point->y *= SCALE;
1463 point++;
1464 lives_point++;
1467 ship.position.dx = 0;
1468 ship.position.dy = 0;
1469 ship.explode_countdown = 0;
1471 /*grab a copy of the ships points for the lives display:*/
1472 point = ship.vertices;
1473 lives_point = lives_points;
1474 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1476 lives_point->x = point->x;
1477 lives_point->y = point->y;
1478 lives_point++;
1479 point++;
1483 void rotate_asteroid(struct Asteroid* asteroid)
1485 struct Point* point;
1486 int n;
1487 long xtemp;
1489 point = asteroid->vertices;
1490 for(n = NUM_ASTEROID_VERTICES+1; --n;)
1492 xtemp = point->x;
1493 point->x = xtemp*asteroid->speed_cos/SIN_COS_SCALE -
1494 point->y*asteroid->speed_sin/SIN_COS_SCALE;
1495 point->y = point->y*asteroid->speed_cos/SIN_COS_SCALE +
1496 xtemp*asteroid->speed_sin/SIN_COS_SCALE;
1497 point++;
1501 /*************************************************
1502 ** Draws the ship, moves the ship and creates a new
1503 ** one if it's finished exploding.
1504 **************************************************/
1505 void draw_and_move_ship(void)
1507 int nxoffset = ship.position.x/SCALE;
1508 int nyoffset = ship.position.y/SCALE;
1509 SET_FG(COL_PLAYER);
1510 if(!ship.explode_countdown)
1512 if(!ship.waiting_for_space)
1514 draw_polygon(ship.vertices, nxoffset, nyoffset, NUM_SHIP_VERTICES);
1515 if(game_state != PAUSE_MODE && game_state != GAME_OVER)
1517 move_point(&ship.position);
1521 else
1523 /* animate_and_draw_explosion(ship.vertices, NUM_SHIP_VERTICES,
1524 ship.position.x/SCALE,
1525 ship.position.y/SCALE); */
1526 if(game_state != PAUSE_MODE)
1528 ship.explode_countdown--;
1529 if(!ship.explode_countdown)
1531 num_lives--;
1532 if(!num_lives)
1534 show_game_over = SHOW_GAME_OVER_TIME;
1535 game_state = GAME_OVER;
1537 else
1539 initialise_ship();
1540 ship.waiting_for_space = true;
1547 void thrust_ship(void)
1549 if(!ship.waiting_for_space)
1551 ship.position.dx += ( ship.vertices[0].x - ship.vertices[2].x )/20;
1552 ship.position.dy += ( ship.vertices[0].y - ship.vertices[2].y )/20;
1553 /*if dx and dy are below a certain threshold, then set 'em to 0
1554 but to do this we need to ascertain if the spacehip as moved on screen
1555 for more than a certain amount. */
1557 create_trail_blaze(THRUST_COLOUR, &ship.position);
1561 /**************************************************
1562 ** Rotate the ship using the passed sin & cos values
1563 ***************************************************/
1564 void rotate_ship(int c, int s)
1566 struct Point* point;
1567 int n;
1568 double xtemp;
1570 if(!ship.waiting_for_space && !ship.explode_countdown)
1572 point = ship.vertices;
1573 for(n=NUM_SHIP_VERTICES+1;--n;)
1575 xtemp = point->x;
1576 point->x = xtemp*c/SIN_COS_SCALE - point->y*s/SIN_COS_SCALE;
1577 point->y = point->y*c/SIN_COS_SCALE + xtemp*s/SIN_COS_SCALE;
1578 point++;
1583 void drawstars()
1585 struct Point* p;
1586 int n = NUM_STARS;
1588 p = stars;
1589 SET_FG(COL_STARS);
1591 while(--n)
1593 rb->lcd_drawpixel(p->x , p->y);
1594 p++;
1598 /*************************************************
1599 ** Draw And Move all Asteroids
1600 *************************************************/
1601 void draw_and_move_asteroids(void)
1603 int n;
1604 struct Asteroid* asteroid;
1606 asteroid = asteroids_array;
1607 SET_FG(COL_ASTEROID);
1609 n = MAX_NUM_ASTEROIDS;
1610 while(--n)
1612 if(game_state != PAUSE_MODE)
1614 if(asteroid->exists)
1616 move_point(&asteroid->position);
1617 rotate_asteroid(asteroid);
1618 draw_polygon(asteroid->vertices, asteroid->position.x/SCALE,
1619 asteroid->position.y/SCALE,
1620 NUM_ASTEROID_VERTICES);
1622 else if(asteroid->explode_countdown)
1624 /* animate_and_draw_explosion(asteroid->vertices,
1625 NUM_ASTEROID_VERTICES,
1626 asteroid->position.x/SCALE,
1627 asteroid->position.y/SCALE); */
1628 asteroid->explode_countdown--;
1631 else
1633 if(asteroid->exists)
1634 draw_polygon(asteroid->vertices,
1635 asteroid->position.x/SCALE,
1636 asteroid->position.y/SCALE,
1637 NUM_ASTEROID_VERTICES);
1639 asteroid++;
1643 void create_stars(void)
1645 struct TrailPoint* tpoint;
1646 struct Point* p;
1647 int n;
1649 p = stars;
1650 n = NUM_STARS;
1651 while(--n)
1653 p->x = (rb->rand()%LCD_WIDTH);
1654 p->y = (rb->rand()%LCD_HEIGHT);
1655 p++;
1659 /* give the point a random countdown timer, so they dissapears at different
1660 times */
1661 tpoint = trailPoints;
1662 n = NUM_TRAIL_POINTS;
1663 while(--n)
1665 tpoint->alive = 0;
1666 tpoint++;
1670 /*************************************************
1671 ** Creates start_num number of new asteroids of
1672 ** full size.
1673 **************************************************/
1674 void initialise_game(int start_num)
1676 int n;
1677 asteroid_count = next_missile_count = next_thrust_count = 0;
1678 struct Asteroid* asteroid;
1679 struct Missile* missile;
1680 extra_life = EXTRA_LIFE;
1682 /*no enemy*/
1683 enemy_on_screen = 0;
1684 enemy_missile.survived = 0;
1686 /*clear asteroids*/
1687 asteroid = asteroids_array;
1688 n = MAX_NUM_ASTEROIDS;
1689 while(--n)
1691 asteroid->exists = false;
1692 asteroid++;
1695 /*make some LARGE asteroids*/
1696 for(n = 0; n < start_num; n++)
1697 initialise_asteroid(&asteroids_array[n], LARGE);
1699 /*ensure all missiles are out of action: */
1700 missile = missiles_array;
1701 n = MAX_NUM_MISSILES;
1702 while(--n)
1704 missile->survived=0;
1705 missile++;
1709 void start_attract_mode(void)
1711 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1712 enemy.appear_timing = ENEMY_APPEAR_TIMING_START;
1713 current_level = 5;
1714 num_lives = START_LIVES;
1715 current_score = 0;
1716 attract_flip_timeout = ATTRACT_FLIP_TIME;
1717 game_state = ATTRACT_MODE;
1718 if(asteroid_count < 3)
1719 initialise_game(current_level);
1722 enum plugin_status start_game(void)
1724 char s[20];
1725 char level[10];
1726 int button;
1727 int end;
1728 int CYCLETIME = 30;
1730 /*create stars once, and once only:*/
1731 create_stars();
1733 SET_BG(LCD_BLACK);
1735 while(true)
1737 /*game starts with at level 1
1738 with 1 asteroid.*/
1739 start_attract_mode();
1741 /*Main loop*/
1742 while(true)
1744 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1745 rb->lcd_clear_display();
1746 SET_FG(COL_TEXT);
1747 switch(game_state)
1749 case(ATTRACT_MODE):
1750 if(attract_flip_timeout < ATTRACT_FLIP_TIME/2)
1752 rb->lcd_putsxy(CENTER_LCD_X - 39,
1753 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4,
1754 "Fire to Start");
1755 if(!attract_flip_timeout)
1756 attract_flip_timeout = ATTRACT_FLIP_TIME;
1758 else
1760 rb->snprintf(s, sizeof(s), "Hi Score %d ", high_score);
1761 rb->lcd_putsxy(CENTER_LCD_X - 30,
1762 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, s);
1764 attract_flip_timeout--;
1765 break;
1767 case(GAME_OVER):
1768 rb->lcd_putsxy(CENTER_LCD_X - 25,
1769 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "Game Over");
1770 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1771 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1772 show_game_over--;
1773 if(!show_game_over)
1774 start_attract_mode();
1775 break;
1777 case(PAUSE_MODE):
1778 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1779 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1780 rb->lcd_putsxy(CENTER_LCD_X - 15,
1781 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "pause");
1782 draw_and_move_missiles();
1783 draw_lives();
1784 draw_and_move_ship();
1785 break;
1787 case(PLAY_MODE):
1788 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1789 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1790 draw_and_move_missiles();
1791 draw_lives();
1792 check_collisions();
1793 draw_and_move_ship();
1794 break;
1796 case(SHOW_LEVEL):
1797 show_level_timeout--;
1798 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1799 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1800 rb->snprintf(level, sizeof(level), "stage %d ", current_level);
1801 rb->lcd_putsxy(CENTER_LCD_X - 20,
1802 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, level);
1803 draw_and_move_ship();
1804 draw_lives();
1805 if(!show_level_timeout)
1807 initialise_game(current_level);
1808 game_state = PLAY_MODE;
1809 draw_lives();
1811 break;
1813 draw_trail_blaze();
1814 drawstars();
1815 draw_and_move_asteroids();
1816 draw_and_move_enemy();
1818 rb->lcd_update();
1819 button = rb->button_get(false);
1821 #ifdef HAS_BUTTON_HOLD
1822 if (rb->button_hold())
1823 game_state = PAUSE_MODE;
1824 #endif
1826 switch(button)
1828 case(AST_PAUSE):
1829 if(game_state == PLAY_MODE)
1830 game_state = PAUSE_MODE;
1831 else if(game_state == PAUSE_MODE)
1832 game_state = PLAY_MODE;
1833 break;
1835 #ifdef AST_RC_QUIT
1836 case AST_RC_QUIT:
1837 #endif
1838 case(AST_QUIT):
1839 if(game_state == ATTRACT_MODE)
1840 return PLUGIN_OK;
1841 else if(game_state == GAME_OVER)
1843 start_attract_mode();
1845 else
1847 show_game_over = SHOW_GAME_OVER_TIME;
1848 game_state = GAME_OVER;
1850 break;
1852 case (AST_LEFT_REP):
1853 case (AST_LEFT):
1854 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1855 rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN);
1856 break;
1858 case (AST_RIGHT_REP):
1859 case (AST_RIGHT):
1860 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1861 rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN);
1862 break;
1864 case (AST_THRUST_REP):
1865 case (AST_THRUST):
1866 if((game_state == PLAY_MODE || game_state == SHOW_LEVEL) && !next_thrust_count)
1868 thrust_ship();
1869 next_thrust_count = 5;
1871 break;
1873 case (AST_HYPERSPACE):
1874 if(game_state == PLAY_MODE)
1875 hyperspace();
1876 /*maybe shield if it gets too hard */
1877 break;
1879 case (AST_FIRE_REP):
1880 case (AST_FIRE):
1881 if(game_state == ATTRACT_MODE)
1883 current_level = START_LEVEL;
1884 initialise_ship();
1885 initialise_game(current_level);
1886 show_level_timeout = SHOW_LEVEL_TIME;
1887 game_state = PLAY_MODE;
1889 else if(game_state == PLAY_MODE)
1891 if(!next_missile_count)
1893 fire_missile();
1894 next_missile_count = 10;
1897 else if(game_state == PAUSE_MODE)
1899 game_state = PLAY_MODE;
1901 break;
1903 default:
1904 if (rb->default_event_handler(button)==SYS_USB_CONNECTED)
1905 return PLUGIN_USB_CONNECTED;
1906 break;
1909 if(!num_lives)
1911 if(high_score < current_score)
1912 high_score = current_score;
1913 if(!show_game_over)
1914 break;
1917 if(next_missile_count)
1918 next_missile_count--;
1920 if(next_thrust_count)
1921 next_thrust_count--;
1923 if (end > *rb->current_tick)
1924 rb->sleep(end-*rb->current_tick);
1925 else
1926 rb->yield();
1932 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1934 enum plugin_status retval;
1935 (void)(parameter);
1936 rb = api;
1938 game_state = ATTRACT_MODE;
1940 #if LCD_DEPTH > 1
1941 rb->lcd_set_backdrop(NULL);
1942 #endif
1943 /* universal font */
1944 rb->lcd_setfont(FONT_SYSFIXED);
1945 /* Turn off backlight timeout */
1946 backlight_force_on(rb); /* backlight control in lib/helper.c */
1947 iohiscore();
1948 retval = start_game();
1949 iohiscore();
1950 rb->lcd_setfont(FONT_UI);
1951 /* Turn on backlight timeout (revert to settings) */
1952 backlight_use_settings(rb); /* backlight control in lib/helper.c */
1953 return retval;