Use wrap-safe TIME_BEFORE/TIME_AFTER macros to compare times with current_time, inste...
[kugel-rb.git] / apps / plugins / spacerocks.c
blob0061967f8b8e28d7dbd8ef6d7eee485653ab1164
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 by Mat Holton
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "plugin.h"
23 #include "lib/display_text.h"
24 #include "lib/helper.h"
25 #include "lib/highscore.h"
26 #include "lib/playback_control.h"
28 PLUGIN_HEADER
30 /* variable button definitions */
31 #if CONFIG_KEYPAD == RECORDER_PAD
32 #define AST_PAUSE BUTTON_ON
33 #define AST_QUIT BUTTON_OFF
34 #define AST_THRUST BUTTON_UP
35 #define AST_HYPERSPACE BUTTON_DOWN
36 #define AST_LEFT BUTTON_LEFT
37 #define AST_RIGHT BUTTON_RIGHT
38 #define AST_FIRE BUTTON_PLAY
40 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
41 #define AST_PAUSE BUTTON_ON
42 #define AST_QUIT BUTTON_OFF
43 #define AST_THRUST BUTTON_UP
44 #define AST_HYPERSPACE BUTTON_DOWN
45 #define AST_LEFT BUTTON_LEFT
46 #define AST_RIGHT BUTTON_RIGHT
47 #define AST_FIRE BUTTON_SELECT
49 #elif CONFIG_KEYPAD == ONDIO_PAD
50 #define AST_PAUSE (BUTTON_MENU | BUTTON_OFF)
51 #define AST_QUIT BUTTON_OFF
52 #define AST_THRUST BUTTON_UP
53 #define AST_HYPERSPACE BUTTON_DOWN
54 #define AST_LEFT BUTTON_LEFT
55 #define AST_RIGHT BUTTON_RIGHT
56 #define AST_FIRE BUTTON_MENU
58 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
59 (CONFIG_KEYPAD == IRIVER_H300_PAD)
60 #define AST_PAUSE BUTTON_REC
61 #define AST_QUIT BUTTON_OFF
62 #define AST_THRUST BUTTON_UP
63 #define AST_HYPERSPACE BUTTON_DOWN
64 #define AST_LEFT BUTTON_LEFT
65 #define AST_RIGHT BUTTON_RIGHT
66 #define AST_FIRE BUTTON_SELECT
68 #define AST_RC_QUIT BUTTON_RC_STOP
70 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
71 #define AST_PAUSE BUTTON_PLAY
72 #define AST_QUIT BUTTON_POWER
73 #define AST_THRUST BUTTON_UP
74 #define AST_HYPERSPACE BUTTON_DOWN
75 #define AST_LEFT BUTTON_LEFT
76 #define AST_RIGHT BUTTON_RIGHT
77 #define AST_FIRE BUTTON_SELECT
79 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
80 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
81 #define AST_PAUSE (BUTTON_SELECT | BUTTON_PLAY)
82 #define AST_QUIT (BUTTON_SELECT | BUTTON_MENU)
83 #define AST_THRUST BUTTON_MENU
84 #define AST_HYPERSPACE BUTTON_PLAY
85 #define AST_LEFT BUTTON_SCROLL_BACK
86 #define AST_RIGHT BUTTON_SCROLL_FWD
87 #define AST_FIRE BUTTON_SELECT
89 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
90 #define AST_PAUSE BUTTON_A
91 #define AST_QUIT BUTTON_POWER
92 #define AST_THRUST BUTTON_UP
93 #define AST_HYPERSPACE BUTTON_DOWN
94 #define AST_LEFT BUTTON_LEFT
95 #define AST_RIGHT BUTTON_RIGHT
96 #define AST_FIRE BUTTON_SELECT
98 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
99 #define AST_PAUSE BUTTON_REC
100 #define AST_QUIT BUTTON_POWER
101 #define AST_THRUST BUTTON_UP
102 #define AST_HYPERSPACE BUTTON_DOWN
103 #define AST_LEFT BUTTON_SCROLL_BACK
104 #define AST_RIGHT BUTTON_SCROLL_FWD
105 #define AST_FIRE BUTTON_SELECT
107 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
108 #define AST_PAUSE (BUTTON_SELECT | BUTTON_UP)
109 #define AST_QUIT (BUTTON_HOME|BUTTON_REPEAT)
110 #define AST_THRUST BUTTON_UP
111 #define AST_HYPERSPACE BUTTON_DOWN
112 #define AST_LEFT BUTTON_SCROLL_BACK
113 #define AST_RIGHT BUTTON_SCROLL_FWD
114 #define AST_FIRE BUTTON_SELECT
116 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
117 #define AST_PAUSE BUTTON_REC
118 #define AST_QUIT BUTTON_POWER
119 #define AST_THRUST BUTTON_UP
120 #define AST_HYPERSPACE BUTTON_DOWN
121 #define AST_LEFT BUTTON_LEFT
122 #define AST_RIGHT BUTTON_RIGHT
123 #define AST_FIRE BUTTON_SELECT
125 #elif (CONFIG_KEYPAD == SANSA_CLIP_PAD)
126 #define AST_PAUSE BUTTON_HOME
127 #define AST_QUIT BUTTON_POWER
128 #define AST_THRUST BUTTON_UP
129 #define AST_HYPERSPACE BUTTON_DOWN
130 #define AST_LEFT BUTTON_LEFT
131 #define AST_RIGHT BUTTON_RIGHT
132 #define AST_FIRE BUTTON_SELECT
134 #elif (CONFIG_KEYPAD == SANSA_M200_PAD)
135 #define AST_PAUSE (BUTTON_SELECT | BUTTON_UP)
136 #define AST_QUIT BUTTON_POWER
137 #define AST_THRUST BUTTON_UP
138 #define AST_HYPERSPACE BUTTON_DOWN
139 #define AST_LEFT BUTTON_LEFT
140 #define AST_RIGHT BUTTON_RIGHT
141 #define AST_FIRE (BUTTON_SELECT | BUTTON_REL)
143 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
144 #define AST_PAUSE BUTTON_PLAY
145 #define AST_QUIT BUTTON_POWER
146 #define AST_THRUST BUTTON_SCROLL_UP
147 #define AST_HYPERSPACE BUTTON_SCROLL_DOWN
148 #define AST_LEFT BUTTON_LEFT
149 #define AST_RIGHT BUTTON_RIGHT
150 #define AST_FIRE BUTTON_REW
152 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
153 #define AST_PAUSE BUTTON_PLAY
154 #define AST_QUIT BUTTON_BACK
155 #define AST_THRUST BUTTON_UP
156 #define AST_HYPERSPACE BUTTON_DOWN
157 #define AST_LEFT BUTTON_LEFT
158 #define AST_RIGHT BUTTON_RIGHT
159 #define AST_FIRE BUTTON_SELECT
161 #elif (CONFIG_KEYPAD == MROBE100_PAD)
162 #define AST_PAUSE BUTTON_DISPLAY
163 #define AST_QUIT BUTTON_POWER
164 #define AST_THRUST BUTTON_UP
165 #define AST_HYPERSPACE BUTTON_DOWN
166 #define AST_LEFT BUTTON_LEFT
167 #define AST_RIGHT BUTTON_RIGHT
168 #define AST_FIRE BUTTON_SELECT
170 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
171 #define AST_PAUSE BUTTON_RC_PLAY
172 #define AST_QUIT BUTTON_RC_REC
173 #define AST_THRUST BUTTON_RC_VOL_UP
174 #define AST_HYPERSPACE BUTTON_RC_VOL_DOWN
175 #define AST_LEFT BUTTON_RC_REW
176 #define AST_RIGHT BUTTON_RC_FF
177 #define AST_FIRE BUTTON_RC_MODE
179 #elif (CONFIG_KEYPAD == COWOND2_PAD)
180 #define AST_QUIT BUTTON_POWER
182 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
183 #define AST_PAUSE BUTTON_PLAY
184 #define AST_QUIT BUTTON_BACK
185 #define AST_THRUST BUTTON_UP
186 #define AST_HYPERSPACE BUTTON_DOWN
187 #define AST_LEFT BUTTON_LEFT
188 #define AST_RIGHT BUTTON_RIGHT
189 #define AST_FIRE BUTTON_SELECT
191 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
192 #define AST_PAUSE BUTTON_VIEW
193 #define AST_QUIT BUTTON_POWER
194 #define AST_THRUST BUTTON_UP
195 #define AST_HYPERSPACE BUTTON_DOWN
196 #define AST_LEFT BUTTON_LEFT
197 #define AST_RIGHT BUTTON_RIGHT
198 #define AST_FIRE BUTTON_PLAYLIST
200 #elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \
201 (CONFIG_KEYPAD == ONDAVX777_PAD) || \
202 CONFIG_KEYPAD == MROBE500_PAD
203 #define AST_QUIT BUTTON_POWER
205 #elif (CONFIG_KEYPAD == SAMSUNG_YH_PAD)
206 #define AST_PAUSE BUTTON_FFWD
207 #define AST_QUIT BUTTON_REC
208 #define AST_THRUST_REP (BUTTON_UP | BUTTON_REW)
209 #define AST_THRUST BUTTON_UP
210 #define AST_HYPERSPACE BUTTON_DOWN
211 #define AST_LEFT BUTTON_LEFT
212 #define AST_LEFT_REP (BUTTON_LEFT | BUTTON_REW)
213 #define AST_RIGHT BUTTON_RIGHT
214 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REW)
215 #define AST_FIRE BUTTON_PLAY
216 #define AST_FIRE_REP (BUTTON_PLAY | BUTTON_REW)
218 #else
219 #error No keymap defined!
220 #endif
222 #ifdef HAVE_TOUCHSCREEN
223 #ifndef AST_PAUSE
224 #define AST_PAUSE BUTTON_CENTER
225 #endif
226 #ifndef AST_QUIT
227 #define AST_QUIT BUTTON_TOPLEFT
228 #endif
229 #ifndef AST_THRUST_REP
230 #define AST_THRUST_REP (BUTTON_TOPMIDDLE | BUTTON_REPEAT)
231 #endif
232 #ifndef AST_THRUST
233 #define AST_THRUST BUTTON_TOPMIDDLE
234 #endif
235 #ifndef AST_HYPERSPACE
236 #define AST_HYPERSPACE BUTTON_TOPRIGHT
237 #endif
238 #ifndef AST_LEFT
239 #define AST_LEFT BUTTON_MIDLEFT
240 #endif
241 #ifndef AST_LEFT_REP
242 #define AST_LEFT_REP (BUTTON_MIDLEFT | BUTTON_REPEAT)
243 #endif
244 #ifndef AST_RIGHT
245 #define AST_RIGHT BUTTON_MIDRIGHT
246 #endif
247 #ifndef AST_RIGHT_REP
248 #define AST_RIGHT_REP (BUTTON_MIDRIGHT | BUTTON_REPEAT)
249 #endif
250 #ifndef AST_FIRE
251 #define AST_FIRE BUTTON_BOTTOMMIDDLE
252 #endif
253 #ifndef AST_FIRE_REP
255 #ifdef BUTTON_MENU
256 #define AST_FIRE_REP (BUTTON_BOTTOMMIDDLE | BUTTON_MENU)
257 #else
258 #define AST_FIRE_REP BUTTON_BOTTOMMIDDLE | BUTTON_REPEAT
259 #endif
261 #endif
262 #endif
264 #define RES MAX(LCD_WIDTH, LCD_HEIGHT)
265 #define LARGE_LCD RES >= 200
266 #define ENEMY_MISSILE_SURVIVAL_LENGTH RES/2
267 #define ASTEROID_SPEED RES/20
268 #define MISSILE_SURVIVAL_LENGTH 40
270 #define CYCLETIME 30
272 #define EXTRA_LIFE 250
273 #define SPAWN_TIME 30
274 #define BLINK_TIME 10
275 #define SCALE 5000
276 #define MISSILE_SCALE 5000
277 #define WRAP_GAP 12
278 #define EXPLOSION_LENGTH 20
279 #define SHOW_COL 0
280 #define POINT_SIZE 2
281 #define MAX_NUM_ASTEROIDS 25
282 #define MAX_NUM_MISSILES 6
283 #define ENEMY_BIG_PROBABILITY_START 10
284 #define ENEMY_APPEAR_PROBABILITY_START 35
285 #define ENEMY_APPEAR_TIMING_START 1800
286 #define LITTLE_SHIP 2
287 #define BIG_SHIP 1
288 #define SHOW_GAME_OVER_TIME 100
289 #define SHOW_LEVEL_TIME 50
290 #define START_LIVES 3
291 #define START_LEVEL 1
292 #define NUM_ASTEROID_VERTICES 10
293 #define NUM_SHIP_VERTICES 4
294 #define NUM_ENEMY_VERTICES 6
295 #define MAX_LEVEL MAX_NUM_ASTEROIDS
296 #define ENEMY_SPEED 4
297 #define SIZE_ENEMY_COLLISION 5*SCALE
298 #define NUM_STARS 50
299 #define NUM_TRAIL_POINTS 70
300 #define NUM_ROTATIONS 16
302 #define SIN_COS_SCALE 10000
304 #define FAST_ROT_CW_SIN 873
305 #define FAST_ROT_CW_COS 9963
306 #define FAST_ROT_ACW_SIN -873
307 #define FAST_ROT_ACW_COS 9963
309 #define MEDIUM_ROT_CW_SIN 350
310 #define MEDIUM_ROT_CW_COS 9994
311 #define MEDIUM_ROT_ACW_SIN -350
312 #define MEDIUM_ROT_ACW_COS 9994
314 #define SLOW_ROT_CW_SIN 350
315 #define SLOW_ROT_CW_COS 9994
316 #define SLOW_ROT_ACW_SIN - 350
317 #define SLOW_ROT_ACW_COS 9994
319 #ifdef HAVE_LCD_COLOR
320 #define SHIP_ROT_CW_SIN 2419
321 #define SHIP_ROT_CW_COS 9702
322 #define SHIP_ROT_ACW_SIN -2419
323 #define SHIP_ROT_ACW_COS 9702
324 #else
325 #define SHIP_ROT_CW_SIN 3827
326 #define SHIP_ROT_CW_COS 9239
327 #define SHIP_ROT_ACW_SIN -3827
328 #define SHIP_ROT_ACW_COS 9239
329 #endif
332 #define SCALED_WIDTH (LCD_WIDTH*SCALE)
333 #define SCALED_HEIGHT (LCD_HEIGHT*SCALE)
334 #define CENTER_LCD_X (LCD_WIDTH/2)
335 #define CENTER_LCD_Y (LCD_HEIGHT/2)
337 #define SHIP_EXPLOSION_COLOUR 1
338 #define ASTEROID_EXPLOSION_COLOUR 2
339 #define ENEMY_EXPLOSION_COLOUR 3
340 #define THRUST_COLOUR 4
342 #define ASTEROID_R 230
343 #define ASTEROID_G 200
344 #define ASTEROID_B 100
345 #define SHIP_R 255
346 #define SHIP_G 255
347 #define SHIP_B 255
348 #define ENEMY_R 50
349 #define ENEMY_G 220
350 #define ENEMY_B 50
351 #define THRUST_R 200
352 #define THRUST_G 200
353 #define THRUST_B 0
355 #ifdef HAVE_LCD_COLOR
356 #define COL_MISSILE LCD_RGBPACK(200,0,0)
357 #define COL_PLAYER LCD_RGBPACK(200,200,200)
358 #define COL_INVULN LCD_RGBPACK(100,100,200)
359 #define COL_STARS LCD_WHITE
360 #define COL_ASTEROID LCD_RGBPACK(ASTEROID_R,ASTEROID_G,ASTEROID_B)
361 #define COL_TEXT LCD_RGBPACK(200,200,255)
362 #define COL_ENEMY LCD_RGBPACK(ENEMY_R,ENEMY_G,ENEMY_B)
363 #define SET_FG rb->lcd_set_foreground
364 #define SET_BG rb->lcd_set_background
365 #else
366 #define SET_FG(x)
367 #define SET_BG(x)
368 #endif
370 #define MARGIN 5
372 #define HIGH_SCORE PLUGIN_GAMES_DIR "/spacerocks.score"
373 #define NUM_SCORES 5
375 struct highscore highest[NUM_SCORES];
377 /* The array of points that make up an asteroid */
378 static const short asteroid_one[NUM_ASTEROID_VERTICES*2] =
380 -2, -12,
381 4, -8,
382 8, -14,
383 16, -5,
384 14, 0,
385 20, 2,
386 12, 14,
387 -4, 14,
388 -10, 6,
389 -10, -8
392 /* The array of points that make up an asteroid */
393 static const short asteroid_two[NUM_ASTEROID_VERTICES*2] =
395 -2, -12,
396 4, -16,
397 6, -14,
398 16, -8,
399 14, 0,
400 20, 2,
401 12, 14,
402 -4, 14,
403 -10, 6,
404 -10, -8
407 /* The array of points that make up an asteroid */
408 static const short asteroid_three[NUM_ASTEROID_VERTICES*2] =
410 -2, -12,
411 4, -16,
412 6, -14,
413 2, -8,
414 14, 0,
415 20, 2,
416 12, 14,
417 -4, 14,
418 -16, 6,
419 -10, -8
422 /* The array od points the make up the ship */
423 static const short ship_vertices[NUM_SHIP_VERTICES*2] =
425 #if(LARGE_LCD)
426 0,-6,
427 4, 6,
428 0, 2,
429 -4, 6
430 #else
431 0,-4,
432 3, 4,
433 0, 1,
434 -3, 4
435 #endif
438 /* The array of points the make up the bad spaceship */
439 static const short enemy_vertices[NUM_ENEMY_VERTICES*2] =
441 #if(LARGE_LCD)
442 -8, 0,
443 -4, 4,
444 4, 4,
445 8, 0,
446 4, -4,
447 -4, -4
448 #else
449 -5, 0,
450 -2, 2,
451 2, 2,
452 5, 0,
453 2, -2,
454 -2, -2
455 #endif
459 enum asteroid_type
461 #if(LARGE_LCD)
462 SMALL = 2,
463 MEDIUM = 4,
464 LARGE = 6,
465 #else
466 SMALL = 1,
467 MEDIUM = 2,
468 LARGE = 3,
469 #endif
473 enum game_state
475 GAME_OVER,
476 SHOW_LEVEL,
477 PLAY_MODE,
478 PAUSE_MODE
481 struct Point
483 int x;
484 int y;
485 int dx;
486 int dy;
489 struct TrailPoint
491 int alive;
492 struct Point position;
493 short r;
494 short g;
495 short b;
496 short dec;
499 /* Asteroid structure, contains an array of points */
500 struct Asteroid
502 enum asteroid_type type;
503 bool exists;
504 struct Point position;
505 struct Point vertices[NUM_ASTEROID_VERTICES];
506 int radius;
507 long speed_cos;
508 long speed_sin;
509 int explode_countdown;
512 struct Ship
514 struct Point vertices[NUM_SHIP_VERTICES];
515 struct Point position;
516 bool waiting_for_space;
517 bool invulnerable;
518 int spawn_time;
519 int explode_countdown;
522 struct Enemy
524 struct Point vertices[NUM_ENEMY_VERTICES];
525 struct Point position;
526 int explode_countdown;
527 long last_time_appeared;
528 short size_probability;
529 short appear_probability;
530 short appear_timing;
533 struct Missile
535 struct Point position;
536 struct Point oldpoint;
537 int survived;
540 static enum game_state game_state;
541 static int asteroid_count;
542 static int next_missile_count;
543 static int next_thrust_count;
544 static int num_lives;
545 static int extra_life;
546 static int show_level_timeout;
547 static int current_level;
548 static int current_score;
549 static int space_check_size = 30*SCALE;
551 static bool enemy_on_screen;
552 static struct Ship ship;
553 static struct Point stars[NUM_STARS];
554 static struct Asteroid asteroids_array[MAX_NUM_ASTEROIDS];
555 static struct Missile missiles_array[MAX_NUM_MISSILES];
556 static struct Missile enemy_missile;
557 static struct Enemy enemy;
558 static struct Point lives_points[NUM_SHIP_VERTICES];
559 static struct TrailPoint trailPoints[NUM_TRAIL_POINTS];
561 void draw_and_move_asteroids(void);
562 void initialise_game(int nStartNum);
564 bool is_asteroid_near_ship(struct Asteroid* asteroid);
565 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point);
567 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type eType);
568 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices);
569 void rotate_asteroid(struct Asteroid* asteroid);
570 void create_asteroid(enum asteroid_type type, int x, int y);
571 void create_stars(void);
573 void initialise_ship(void);
574 void draw_and_move_ship(void);
575 void rotate_ship(int s, int c);
576 void thrust_ship(void);
578 void initialise_missile(struct Missile* missile);
579 void draw_and_move_missiles(void);
580 void fire_missile(void);
582 void animate_and_draw_explosion(struct Point* point, int num_points, int xoffset, int yoffset);
583 void initialise_explosion(struct Point* point, int num_points);
585 void move_point(struct Point* point);
586 void hyperspace(void);
587 void check_collisions(void);
588 void initialise_enemy(void);
589 void draw_and_move_enemy(void);
590 void draw_lives(void);
591 void drawstars(void);
592 bool is_ship_within_asteroid(struct Asteroid* asteroid);
595 void init(void)
597 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
598 enemy.appear_timing = ENEMY_APPEAR_TIMING_START;
599 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
600 current_level = START_LEVEL;
601 num_lives = START_LIVES;
602 current_score = 0;
603 initialise_ship();
604 initialise_game(current_level);
605 show_level_timeout = SHOW_LEVEL_TIME;
606 game_state = PLAY_MODE;
609 static bool spacerocks_help(void)
611 rb->lcd_setfont(FONT_UI);
612 #define WORDS (sizeof help_text / sizeof (char*))
613 static char *help_text[] = {
614 "Spacerocks", "", "Aim", "", "The", "goal", "of", "the", "game", "is",
615 "to", "blow", "up", "the", "asteroids", "and", "avoid", "being", "hit", "by",
616 "them.", "Also", "you'd", "better", "watch", "out", "for", "the", "UFOs!"
618 static struct style_text formation[]={
619 { 0, TEXT_CENTER|TEXT_UNDERLINE },
620 { 2, C_RED },
621 { -1, 0 }
623 #ifdef HAVE_LCD_COLOR
624 rb->lcd_set_background(LCD_BLACK);
625 rb->lcd_set_foreground(LCD_WHITE);
626 #endif
627 int button;
628 if (display_text(WORDS, help_text, formation, NULL)==PLUGIN_USB_CONNECTED)
629 return true;
630 do {
631 button = rb->button_get(true);
632 if (button == SYS_USB_CONNECTED) {
633 return true;
635 } while( ( button == BUTTON_NONE )
636 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
637 rb->lcd_setfont(FONT_SYSFIXED);
639 return false;
642 static bool _ingame;
643 static int spacerocks_menu_cb(int action, const struct menu_item_ex *this_item)
645 if(action == ACTION_REQUEST_MENUITEM
646 && !_ingame && ((intptr_t)this_item)==0)
647 return ACTION_EXIT_MENUITEM;
648 return action;
651 static int spacerocks_menu(bool ingame)
653 rb->button_clear_queue();
654 int choice = 0;
656 _ingame = ingame;
658 MENUITEM_STRINGLIST (main_menu, "Spacerocks Menu", spacerocks_menu_cb,
659 "Resume Game",
660 "Start New Game",
661 "Help",
662 "High Scores",
663 "Playback Control",
664 "Quit");
666 while (1) {
667 choice = rb->do_menu(&main_menu, &choice, NULL, false);
668 switch (choice) {
669 case 0:
670 return 0;
671 case 1:
672 init();
673 return 0;
674 case 2:
675 if(spacerocks_help())
676 return 1;
677 break;
678 case 3:
679 highscore_show(NUM_SCORES, highest, NUM_SCORES, true);
680 break;
681 case 4:
682 playback_control(NULL);
683 break;
684 case 5:
685 return 1;
686 case MENU_ATTACHED_USB:
687 return 1;
688 default:
689 break;
694 bool point_in_poly(struct Point* _point, int num_vertices, int x, int y)
696 struct Point* pi;
697 struct Point* pj;
698 int n;
699 bool c = false;
701 pi = _point;
702 pj = _point;
703 pj += num_vertices-1;
705 n = num_vertices;
706 while(n--)
708 if((((pi->y <= y) && (y < pj->y)) || ((pj->y <= y) && (y < pi->y))) &&
709 (x < (pj->x - pi->x) * (y - pi->y) / (pj->y - pi->y) + pi->x))
710 c = !c;
712 if(n == num_vertices - 1)
713 pj = _point;
714 else
715 pj++;
717 pi++;
720 return c;
723 void move_point(struct Point* point)
725 point->x += point->dx;
726 point->y += point->dy;
728 /*check bounds on the x-axis:*/
729 if(point->x >= SCALED_WIDTH)
730 point->x = 0;
731 else if(point->x <= 0)
732 point->x = SCALED_WIDTH;
734 /*Check bounds on the y-axis:*/
735 if(point->y >= SCALED_HEIGHT)
736 point->y = 0;
737 else if(point->y <= 0)
738 point->y = SCALED_HEIGHT;
741 void create_trail(struct TrailPoint* tpoint)
743 tpoint->position.dx = -( ship.vertices[0].x - ship.vertices[2].x )/10;
744 tpoint->position.dy = -( ship.vertices[0].y - ship.vertices[2].y )/10;
747 void create_explosion_trail(struct TrailPoint* tpoint)
749 tpoint->position.dx = (rb->rand()%5050)-2500;
750 tpoint->position.dy = (rb->rand()%5050)-2500;
753 void create_trail_blaze(int colour, struct Point* position)
755 int numtoadd;
756 struct TrailPoint* tpoint;
757 int n;
758 int xadd,yadd;
759 if(colour != SHIP_EXPLOSION_COLOUR)
761 numtoadd = NUM_TRAIL_POINTS/5;
762 xadd = position->x;
763 yadd = position->y;
765 else
767 numtoadd = NUM_TRAIL_POINTS/8;
768 xadd = ship.position.x;
769 yadd = ship.position.y;
772 /* give the point a random countdown timer, so they dissapears at different times */
773 tpoint = trailPoints;
774 n = NUM_TRAIL_POINTS;
775 while(--n)
777 if(tpoint->alive <= 0 && numtoadd)
779 numtoadd--;
780 /* take a random x point anywhere between bottom two points of ship. */
781 /* ship.position.x; */
782 tpoint->position.x = (ship.vertices[2].x + (rb->rand()%18000)-9000) + position->x;
783 tpoint->position.y = (ship.vertices[2].y + (rb->rand()%18000)-9000) + position->y;
785 switch(colour)
787 case SHIP_EXPLOSION_COLOUR:
788 tpoint->r = 255;
789 tpoint->g = 255;
790 tpoint->b = 255;
791 create_explosion_trail(tpoint);
792 tpoint->alive = 510;
793 tpoint->dec = 2;
794 break;
795 case ASTEROID_EXPLOSION_COLOUR:
796 tpoint->r = ASTEROID_R;
797 tpoint->g = ASTEROID_G;
798 tpoint->b = ASTEROID_B;
799 create_explosion_trail(tpoint);
800 tpoint->alive = 510;
801 tpoint->dec = 2;
802 break;
803 case ENEMY_EXPLOSION_COLOUR:
804 tpoint->r = ENEMY_R;
805 tpoint->g = ENEMY_G;
806 tpoint->b = ENEMY_B;
807 create_explosion_trail(tpoint);
808 tpoint->alive = 510;
809 tpoint->dec = 2;
810 break;
811 case THRUST_COLOUR:
812 tpoint->r = THRUST_R;
813 tpoint->g = THRUST_G;
814 tpoint->b = THRUST_B;
815 create_trail(tpoint);
816 tpoint->alive = 175;
817 tpoint->dec = 4;
818 break;
820 /* add a proportional bit to the x and y based on dx and dy */
822 /* give the points a speed based on direction of travel - i.e. opposite */
823 tpoint->position.dx += position->dx;
824 tpoint->position.dy += position->dy;
828 tpoint++;
830 /* find a space in the array of trail_points that is NULL or DEAD or whatever.
831 and place this one here. */
835 void draw_trail_blaze(void)
837 struct TrailPoint* tpoint;
838 /* loop through, if alive then move and draw.
839 when drawn, countdown it's timer.
840 if zero kill it! */
841 tpoint = trailPoints;
842 int n = NUM_TRAIL_POINTS;
844 while(--n)
846 if(tpoint->alive)
848 if(game_state != PAUSE_MODE)
850 tpoint->alive-=10;
851 move_point(&(tpoint->position));
853 #ifdef HAVE_LCD_COLOR
854 /* intensity = tpoint->alive/2; */
855 if(tpoint->r>0)tpoint->r-=tpoint->dec;
856 if(tpoint->g>0)tpoint->g-=tpoint->dec;
857 if(tpoint->b>0)tpoint->b-=tpoint->dec;
858 SET_FG(LCD_RGBPACK(tpoint->r, tpoint->g, tpoint->b));
859 #endif
860 rb->lcd_drawpixel(tpoint->position.x/SCALE , tpoint->position.y/SCALE);
862 tpoint++;
866 /*Check if point is within a rectangle*/
867 bool is_point_within_rectangle(struct Point* rect, struct Point* p, int size)
869 #if SHOW_COL
870 int aTLx = rect->x - size;
871 int aTLy = rect->y - size;
872 int aBRx = rect->x + size;
873 int aBRy = rect->y + size;
874 rb->lcd_hline( aTLx/SCALE, aBRx/SCALE, aTLy/SCALE);
875 rb->lcd_vline( aTLx/SCALE, aTLy/SCALE, aBRy/SCALE);
876 rb->lcd_hline( aTLx/SCALE, aBRx/SCALE, aBRy/SCALE);
877 rb->lcd_vline( aBRx/SCALE, aBRy/SCALE, aTLy/SCALE);
878 return (p->x > aTLx && p->x < aBRx && p->y > aTLy && p->y < aBRy);
879 #else
880 return (p->x > rect->x - size && p->x < rect->x + size &&
881 p->y > rect->y - size && p->y < rect->y + size);
882 #endif
885 /* Draw polygon */
886 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices)
888 int n, t1, t2, oldX, oldY;
889 struct Point *p;
890 bool bDrawAll = px < WRAP_GAP || LCD_WIDTH - px < WRAP_GAP ||
891 py < WRAP_GAP || LCD_HEIGHT - py < WRAP_GAP;
893 p = vertices;
894 p += num_vertices-1;
895 oldX = p->x/SCALE + px;
896 oldY = p->y/SCALE + py;
897 p = vertices;
898 for(n = num_vertices+1; --n;)
900 t1 = p->x/SCALE + px;
901 t2 = p->y/SCALE + py;
903 rb->lcd_drawline(oldX, oldY, t1, t2);
905 if(bDrawAll)
907 rb->lcd_drawline(oldX - LCD_WIDTH, oldY, t1 - LCD_WIDTH, t2);
908 rb->lcd_drawline(oldX + LCD_WIDTH, oldY, t1 + LCD_WIDTH, t2);
909 rb->lcd_drawline(oldX - LCD_WIDTH, oldY + LCD_HEIGHT,
910 t1 - LCD_WIDTH, t2 + LCD_HEIGHT);
911 rb->lcd_drawline(oldX + LCD_WIDTH, oldY + LCD_HEIGHT,
912 t1 + LCD_WIDTH, t2 + LCD_HEIGHT);
914 rb->lcd_drawline(oldX, oldY - LCD_HEIGHT, t1, t2 - LCD_HEIGHT);
915 rb->lcd_drawline(oldX, oldY + LCD_HEIGHT, t1, t2 + LCD_HEIGHT);
916 rb->lcd_drawline(oldX - LCD_WIDTH, oldY - LCD_HEIGHT,
917 t1 - LCD_WIDTH, t2 - LCD_HEIGHT);
918 rb->lcd_drawline(oldX + LCD_WIDTH, oldY - LCD_HEIGHT,
919 t1 + LCD_WIDTH, t2 - LCD_HEIGHT);
921 oldX = t1;
922 oldY = t2;
923 p++;
927 void animate_and_draw_explosion(struct Point* point, int num_points,
928 int xoffset, int yoffset)
930 int n;
931 for(n = num_points; --n;)
933 if(game_state != PAUSE_MODE)
935 point->x += point->dx;
936 point->y += point->dy;
938 rb->lcd_fillrect( point->x/SCALE + xoffset, point->y/SCALE + yoffset,
939 POINT_SIZE, POINT_SIZE);
940 point++;
944 /*stop movement of ship, 'cos that's what happens when you go into hyperspace.*/
945 void hyperspace(void)
947 ship.position.dx = ship.position.dy = 0;
948 ship.position.x = (rb->rand()%SCALED_WIDTH);
949 ship.position.y = (rb->rand()%SCALED_HEIGHT);
952 void initialise_enemy(void)
954 struct Point* point;
955 int n;
956 int size;
958 if(rb->rand()%100 > enemy.size_probability)
960 size = BIG_SHIP;
961 enemy.size_probability++;
962 if(enemy.size_probability < 90)
964 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
967 else
969 size = LITTLE_SHIP;
972 enemy_missile.survived = 0;
973 enemy_on_screen = true;
974 enemy.explode_countdown = 0;
975 enemy.last_time_appeared = *rb->current_tick;
976 point = enemy.vertices;
977 for(n = 0; n < NUM_ENEMY_VERTICES+NUM_ENEMY_VERTICES; n+=2)
979 point->x = enemy_vertices[n];
980 point->y = enemy_vertices[n+1];
981 point->x *= SCALE/size;
982 point->y *= SCALE/size;
983 point++;
986 if(ship.position.x >= SCALED_WIDTH/2)
988 enemy.position.dx = ENEMY_SPEED;
989 enemy.position.x = 0;
991 else
993 enemy.position.dx = -ENEMY_SPEED;
994 enemy.position.x = SCALED_WIDTH;
997 if(ship.position.y >= SCALED_HEIGHT/2)
999 enemy.position.dy = ENEMY_SPEED;
1000 enemy.position.y = 0;
1002 else
1004 enemy.position.dy = -ENEMY_SPEED;
1005 enemy.position.y = SCALED_HEIGHT;
1008 enemy.position.dx *= SCALE/10;
1009 enemy.position.dy *= SCALE/10;
1012 void draw_and_move_enemy(void)
1014 int enemy_x, enemy_y;
1015 struct Point *point;
1017 SET_FG(COL_ENEMY);
1019 if(enemy_on_screen)
1021 enemy_x = enemy.position.x/SCALE;
1022 enemy_y = enemy.position.y/SCALE;
1023 if(!enemy.explode_countdown)
1025 point = enemy.vertices;
1026 draw_polygon(enemy.vertices, enemy_x, enemy_y, NUM_ENEMY_VERTICES);
1027 rb->lcd_drawline(enemy.vertices[0].x/SCALE + enemy_x,
1028 enemy.vertices[0].y/SCALE + enemy_y,
1029 enemy.vertices[3].x/SCALE + enemy_x,
1030 enemy.vertices[3].y/SCALE + enemy_y);
1032 if(game_state != PAUSE_MODE)
1034 enemy.position.x += enemy.position.dx;
1035 enemy.position.y += enemy.position.dy;
1038 if(enemy.position.x > SCALED_WIDTH || enemy.position.x < 0)
1039 enemy_on_screen = false;
1041 if(enemy.position.y > SCALED_HEIGHT)
1042 enemy.position.y = 0;
1043 else if(enemy.position.y < 0)
1044 enemy.position.y = SCALED_HEIGHT;
1046 if( (rb->rand()%1000) < 10)
1047 enemy.position.dy = -enemy.position.dy;
1049 else
1052 /* animate_and_draw_explosion(enemy.vertices, NUM_ENEMY_VERTICES,
1053 enemy_x, enemy.position.y/SCALE); */
1054 if(game_state != PAUSE_MODE)
1056 enemy.explode_countdown--;
1057 if(!enemy.explode_countdown)
1058 enemy_on_screen = false;
1062 else
1064 if( (*rb->current_tick - enemy.last_time_appeared) > enemy.appear_timing)
1065 if(rb->rand()%100 > enemy.appear_probability) initialise_enemy();
1068 if(!enemy_missile.survived && game_state != GAME_OVER)
1070 /*if no missile and the enemy is here and not exploding..then shoot baby!*/
1071 if( !enemy.explode_countdown && enemy_on_screen &&
1072 !ship.waiting_for_space && (rb->rand()%10) > 5 )
1074 enemy_missile.position.x = enemy.position.x;
1075 enemy_missile.position.y = enemy.position.y;
1077 /*lame, needs to be sorted - it's trying to shoot at the ship*/
1078 if(ABS(enemy.position.y - ship.position.y) <= 5*SCALE)
1080 enemy_missile.position.dy = 0;
1082 else
1084 if( enemy.position.y < ship.position.y)
1085 enemy_missile.position.dy = 1;
1086 else
1087 enemy_missile.position.dy = -1;
1090 if(ABS(enemy.position.x - ship.position.x) <= 5*SCALE)
1091 enemy_missile.position.dx = 0;
1092 else
1094 if( enemy.position.x < ship.position.x)
1095 enemy_missile.position.dx = 1;
1096 else
1097 enemy_missile.position.dx = -1;
1100 if(enemy_missile.position.dx == 0 &&
1101 enemy_missile.position.dy == 0)
1102 enemy_missile.position.dx = enemy_missile.position.dy = -1;
1104 enemy_missile.position.dx *= SCALE;
1105 enemy_missile.position.dy *= SCALE;
1106 enemy_missile.survived = ENEMY_MISSILE_SURVIVAL_LENGTH;
1110 else
1112 rb->lcd_fillrect( enemy_missile.position.x/SCALE,
1113 enemy_missile.position.y/SCALE,
1114 POINT_SIZE, POINT_SIZE);
1115 if(game_state != PAUSE_MODE)
1117 move_point(&enemy_missile.position);
1118 enemy_missile.survived--;
1123 /******************
1124 * Lame method of collision
1125 * detection. It's checking for collision
1126 * between point and a big rectangle around the asteroid...
1127 *******************/
1128 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point)
1130 if( !is_point_within_rectangle(&asteroid->position, point,
1131 asteroid->radius+4*SCALE) )
1132 return false;
1134 if(point_in_poly(asteroid->vertices, NUM_ASTEROID_VERTICES,
1135 point->x - asteroid->position.x,
1136 point->y - asteroid->position.y))
1138 switch(asteroid->type)
1140 case(SMALL):
1141 asteroid->explode_countdown = EXPLOSION_LENGTH;
1142 create_trail_blaze(ASTEROID_EXPLOSION_COLOUR, &asteroid->position);
1143 break;
1145 case(LARGE):
1146 create_asteroid(MEDIUM, asteroid->position.x,
1147 asteroid->position.y);
1148 create_asteroid(MEDIUM, asteroid->position.x,
1149 asteroid->position.y);
1150 break;
1152 case(MEDIUM):
1153 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1154 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1155 break;
1158 current_score++;
1159 if(current_score > extra_life)
1161 num_lives++;
1162 extra_life = current_score+EXTRA_LIFE;
1164 asteroid_count--;
1165 asteroid->exists = false;
1166 return true;
1168 else
1169 return false;
1172 bool is_point_within_enemy(struct Point* point)
1174 if( is_point_within_rectangle(&enemy.position, point, 7*SCALE) )
1176 current_score += 5;
1177 /*enemy_missile.survived = 0;*/
1178 enemy.explode_countdown = EXPLOSION_LENGTH;
1179 /* initialise_explosion(enemy.vertices, NUM_ENEMY_VERTICES); */
1180 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1181 return true;
1183 else
1184 return false;
1187 bool is_ship_within_asteroid(struct Asteroid* asteroid)
1189 bool hit = false;
1190 struct Point p;
1192 p.x = ship.position.x + ship.vertices[0].x;
1193 p.y = ship.position.y + ship.vertices[0].y;
1194 hit |= is_point_within_asteroid(asteroid, &p);
1196 if(!hit)
1198 p.x = ship.position.x + ship.vertices[1].x;
1199 p.y = ship.position.y + ship.vertices[1].y;
1200 hit |= is_point_within_asteroid(asteroid, &p);
1201 if(!hit)
1203 p.x = ship.position.x + ship.vertices[3].x;
1204 p.y = ship.position.y + ship.vertices[3].y;
1205 hit |= is_point_within_asteroid(asteroid, &p);
1209 return hit;
1212 void initialise_explosion(struct Point* point, int num_points)
1214 int n;
1216 point->x += point->dx;
1217 point->y += point->dy;
1218 for(n = num_points; --n;)
1220 point->dx = point->x;
1221 point->dy = point->y;
1222 point++;
1227 /* Check for collsions between the missiles and the asteroids and the ship */
1228 void check_collisions(void)
1230 int m, n;
1231 bool asteroids_onscreen = false;
1232 struct Missile* missile;
1233 struct Asteroid* asteroid;
1234 bool ship_cant_be_placed = false;
1236 asteroid = asteroids_array;
1237 m = MAX_NUM_ASTEROIDS;
1238 while(--m)
1240 /*if the asteroids exists then test missile collision:*/
1241 if(asteroid->exists)
1243 missile = missiles_array;
1244 n = MAX_NUM_MISSILES;
1245 while(--n)
1247 /*if the missiles exists:*/
1248 if(missile->survived > 0)
1250 /*has the missile hit the asteroid?*/
1251 if(is_point_within_asteroid(asteroid, &missile->position)
1252 || is_point_within_asteroid(asteroid,
1253 &missile->oldpoint))
1255 missile->survived = 0;
1256 break;
1259 missile++;
1262 /*now check collision with ship:*/
1263 if(asteroid->exists && !ship.waiting_for_space && !ship.explode_countdown)
1265 if(is_ship_within_asteroid(asteroid))
1267 if (!ship.invulnerable)
1269 /*if not invulnerable, blow up ship*/
1270 ship.explode_countdown = EXPLOSION_LENGTH;
1271 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1272 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1276 /*has the enemy missile blown something up?*/
1277 if(asteroid->exists && enemy_missile.survived)
1279 if(is_point_within_asteroid(asteroid, &enemy_missile.position))
1281 /*take that score back then:*/
1282 if(current_score > 0) current_score--;
1283 enemy_missile.survived = 0;
1286 /*if it still exists, check if ship is waiting for space:*/
1287 if(asteroid->exists && ship.waiting_for_space)
1288 ship_cant_be_placed |=
1289 is_point_within_rectangle(&ship.position,
1290 &asteroid->position,
1291 space_check_size);
1295 /*is an asteroid still exploding?*/
1296 if(asteroid->explode_countdown)
1297 asteroids_onscreen = true;
1299 asteroid++;
1302 /*now check collision between ship and enemy*/
1303 if(enemy_on_screen && !ship.waiting_for_space &&
1304 !ship.explode_countdown && !enemy.explode_countdown)
1306 /*has the enemy collided with the ship?*/
1307 if(is_point_within_enemy(&ship.position))
1309 if (!ship.invulnerable)
1311 ship.explode_countdown = EXPLOSION_LENGTH;
1312 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1313 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1315 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1318 /*Now see if the enemy has been shot at by the ships missiles:*/
1319 missile = missiles_array;
1320 n = MAX_NUM_MISSILES;
1321 while(--n)
1323 if(missile->survived > 0 &&
1324 is_point_within_enemy(&missile->position))
1326 missile->survived = 0;
1327 break;
1329 missile++;
1333 /*test collision with enemy missile and ship:*/
1334 if(!ship_cant_be_placed && enemy_missile.survived > 0 &&
1335 point_in_poly(ship.vertices, NUM_SHIP_VERTICES,
1336 enemy_missile.position.x - ship.position.x,
1337 enemy_missile.position.y - ship.position.y))
1339 if (!ship.invulnerable)
1341 ship.explode_countdown = EXPLOSION_LENGTH;
1342 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1343 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1345 enemy_missile.survived = 0;
1346 enemy_missile.position.x = enemy_missile.position.y = 0;
1349 if(!ship_cant_be_placed)
1350 ship.waiting_for_space = false;
1352 /*if all asteroids cleared then start again:*/
1353 if(asteroid_count == 0 && !enemy_on_screen && !asteroids_onscreen)
1355 current_level++;
1356 game_state = SHOW_LEVEL;
1357 enemy.appear_probability += 5;
1358 enemy.appear_timing -= 200;
1359 if( enemy.appear_probability > 100)
1360 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1361 show_level_timeout = SHOW_LEVEL_TIME;
1365 /*************************************************
1366 ** Creates a new asteroid of the given 4type (size)
1367 ** and at the given location.
1368 *************************************************/
1369 void create_asteroid(enum asteroid_type type, int x, int y)
1371 struct Asteroid* asteroid;
1372 int n;
1374 asteroid = asteroids_array;
1375 n = MAX_NUM_ASTEROIDS;
1376 while(--n)
1378 if(!asteroid->exists && !asteroid->explode_countdown)
1380 initialise_asteroid(asteroid, type);
1381 asteroid->position.x = x;
1382 asteroid->position.y = y;
1383 break;
1385 asteroid++;
1389 /* Initialise a missile */
1390 void initialise_missile(struct Missile* missile)
1392 missile->position.x = ship.position.x + ship.vertices[0].x;
1393 missile->position.y = ship.position.y + ship.vertices[0].y;
1394 missile->position.dx = (ship.vertices[0].x - ship.vertices[2].x)/2;
1395 missile->position.dy = (ship.vertices[0].y - ship.vertices[2].y)/2;
1396 missile->survived = MISSILE_SURVIVAL_LENGTH;
1397 missile->oldpoint.x = missile->position.x;
1398 missile->oldpoint.y = missile->position.y;
1401 /* Draw and Move all the missiles */
1402 void draw_and_move_missiles(void)
1404 int n;
1405 int p1x, p1y;
1406 int p2x, p2y;
1408 struct Missile* missile;
1409 missile = missiles_array;
1411 SET_FG(COL_MISSILE);
1413 n = MAX_NUM_MISSILES;
1414 while(--n)
1416 if(missile->survived)
1418 if(missile->position.dx > 0)
1420 if(missile->position.x >= missile->oldpoint.x)
1422 p1x = missile->oldpoint.x;
1423 p2x = missile->position.x;
1425 else
1427 p1x = 0;
1428 p2x = missile->position.x;
1431 else
1433 if(missile->oldpoint.x >= missile->position.x)
1435 p1x = missile->oldpoint.x;
1436 p2x = missile->position.x;
1438 else
1440 p1x = missile->oldpoint.x;
1441 p2x = LCD_WIDTH;
1445 if(missile->position.dy > 0)
1447 if(missile->position.y >= missile->oldpoint.y)
1449 p1y = missile->oldpoint.y;
1450 p2y = missile->position.y;
1452 else
1454 p1y = 0;
1455 p2y = missile->position.y;
1458 else
1460 if(missile->oldpoint.y >= missile->position.y)
1462 p1y = missile->oldpoint.y;
1463 p2y = missile->position.y;
1465 else
1467 p1y = missile->oldpoint.y;
1468 p2y = LCD_HEIGHT;
1472 rb->lcd_drawline( p1x/SCALE, p1y/SCALE, p2x/SCALE, p2y/SCALE);
1474 if(game_state != PAUSE_MODE)
1476 missile->oldpoint.x = missile->position.x;
1477 missile->oldpoint.y = missile->position.y;
1478 move_point(&missile->position);
1479 missile->survived--;
1482 missile++;
1486 void draw_lives(void)
1488 int n;
1489 int px = (LCD_WIDTH - num_lives*4 - 1);
1490 #if(LARGE_LCD)
1491 int py = (LCD_HEIGHT-6);
1492 #else
1493 int py = (LCD_HEIGHT-4);
1494 #endif
1496 SET_FG(COL_PLAYER);
1498 n = num_lives;
1499 while(--n)
1501 draw_polygon(lives_points, px, py, NUM_SHIP_VERTICES);
1502 #if(LARGE_LCD)
1503 px += 8;
1504 #else
1505 px += 6;
1506 #endif
1510 /*Fire the next missile*/
1511 void fire_missile(void)
1513 int n;
1514 struct Missile* missile;
1516 if(!ship.explode_countdown && !ship.waiting_for_space)
1518 missile = missiles_array;
1519 n = MAX_NUM_MISSILES;
1520 while(--n)
1522 if(!missile->survived)
1524 initialise_missile(missile);
1525 break;
1527 missile++;
1532 /* Initialise the passed Asteroid */
1533 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type type)
1535 int n;
1536 bool b,b2;
1537 struct Point* point;
1538 asteroid->exists = true;
1539 asteroid->type = type;
1540 asteroid->explode_countdown = 0;
1542 /*Set the radius of the asteroid:*/
1543 asteroid->radius = (int)type*SCALE;
1545 /*shall we move Clockwise and Fast*/
1546 if((rb->rand()%100)>75)
1548 asteroid->speed_cos = FAST_ROT_CW_COS;
1549 asteroid->speed_sin = FAST_ROT_CW_SIN;
1551 else if((rb->rand()%100)>75)
1553 asteroid->speed_cos = FAST_ROT_ACW_COS;
1554 asteroid->speed_sin = FAST_ROT_ACW_SIN;
1556 else if((rb->rand()%100)>75)
1558 asteroid->speed_cos = SLOW_ROT_ACW_COS;
1559 asteroid->speed_sin = SLOW_ROT_ACW_SIN;
1561 else
1563 asteroid->speed_cos = SLOW_ROT_CW_COS;
1564 asteroid->speed_sin = SLOW_ROT_CW_SIN;
1567 b = (rb->rand()%100)>66;
1568 b2 = (rb->rand()%100)>66;
1569 point = asteroid->vertices;
1570 for(n = 0; n < NUM_ASTEROID_VERTICES*2; n+=2)
1572 if(b)
1574 point->x = asteroid_one[n];
1575 point->y = asteroid_one[n+1];
1577 else if( b2 )
1579 point->x = asteroid_two[n];
1580 point->y = asteroid_two[n+1];
1582 else
1584 point->x = asteroid_three[n];
1585 point->y = asteroid_three[n+1];
1588 point->x *= asteroid->radius/6;
1589 point->y *= asteroid->radius/6;
1590 point++;
1594 asteroid->radius += 6*SCALE;
1595 if(asteroid->type == SMALL)
1596 asteroid->radius /= 3;/*2*/
1597 else if(asteroid->type == LARGE)
1598 asteroid->radius += 3*SCALE;/*2*/
1599 b = true;
1600 while(b)
1602 /*Set the position randomly:*/
1603 asteroid->position.x = (rb->rand()%SCALED_WIDTH);
1604 asteroid->position.y = (rb->rand()%SCALED_HEIGHT);
1606 asteroid->position.dx = 0;
1607 while(asteroid->position.dx == 0)
1608 asteroid->position.dx = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1610 asteroid->position.dy = 0;
1611 while(asteroid->position.dy == 0)
1612 asteroid->position.dy = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1614 asteroid->position.dx *= SCALE/10;
1615 asteroid->position.dy *= SCALE/10;
1617 b = is_point_within_rectangle(&ship.position, &asteroid->position,
1618 space_check_size);
1621 /*Now rotate the asteroid a bit, so they all look a bit different*/
1622 for(n=(rb->rand()%30) + 2;--n;)
1623 rotate_asteroid(asteroid);
1625 /*great, we've created an asteroid, don't forget to increment the total:*/
1626 asteroid_count++;
1629 /*Initialise the ship*/
1630 void initialise_ship(void)
1632 struct Point* point;
1633 struct Point* lives_point;
1634 int n;
1636 ship.position.x = CENTER_LCD_X;
1637 ship.position.y = CENTER_LCD_Y;
1638 ship.position.x *= SCALE;
1639 ship.position.y *= SCALE;
1640 ship.position.dx = ship.position.dy = 0;
1641 ship.spawn_time = SPAWN_TIME;
1642 ship.invulnerable = 1;
1644 point = ship.vertices;
1645 lives_point = lives_points;
1646 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1648 point->x = ship_vertices[n];
1649 point->y = ship_vertices[n+1];
1650 point->x *= SCALE;
1651 point->y *= SCALE;
1652 point++;
1653 lives_point++;
1656 ship.position.dx = 0;
1657 ship.position.dy = 0;
1658 ship.explode_countdown = 0;
1660 /*grab a copy of the ships points for the lives display:*/
1661 point = ship.vertices;
1662 lives_point = lives_points;
1663 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1665 lives_point->x = point->x;
1666 lives_point->y = point->y;
1667 lives_point++;
1668 point++;
1672 void rotate_asteroid(struct Asteroid* asteroid)
1674 struct Point* point;
1675 int n;
1676 long xtemp;
1678 point = asteroid->vertices;
1679 for(n = NUM_ASTEROID_VERTICES+1; --n;)
1681 xtemp = point->x;
1682 point->x = xtemp*asteroid->speed_cos/SIN_COS_SCALE -
1683 point->y*asteroid->speed_sin/SIN_COS_SCALE;
1684 point->y = point->y*asteroid->speed_cos/SIN_COS_SCALE +
1685 xtemp*asteroid->speed_sin/SIN_COS_SCALE;
1686 point++;
1690 /*************************************************
1691 ** Draws the ship, moves the ship and creates a new
1692 ** one if it's finished exploding.
1693 **************************************************/
1694 void draw_and_move_ship(void)
1696 int nxoffset = ship.position.x/SCALE;
1697 int nyoffset = ship.position.y/SCALE;
1698 if (ship.invulnerable && (ship.spawn_time > BLINK_TIME || ship.spawn_time % 2 == 0))
1700 SET_FG(COL_INVULN);
1702 else
1704 SET_FG(COL_PLAYER);
1706 if(!ship.explode_countdown)
1708 /* make sure ship is invulnerable until spawn time over */
1709 if (ship.spawn_time)
1711 ship.spawn_time--;
1712 if (ship.spawn_time <= 0)
1714 ship.invulnerable = 0;
1717 if(!ship.waiting_for_space)
1719 draw_polygon(ship.vertices, nxoffset, nyoffset, NUM_SHIP_VERTICES);
1720 if(game_state != PAUSE_MODE && game_state != GAME_OVER)
1722 move_point(&ship.position);
1726 else
1728 /* animate_and_draw_explosion(ship.vertices, NUM_SHIP_VERTICES,
1729 ship.position.x/SCALE,
1730 ship.position.y/SCALE); */
1731 if(game_state != PAUSE_MODE)
1733 ship.explode_countdown--;
1734 if(!ship.explode_countdown)
1736 num_lives--;
1737 if(!num_lives)
1739 game_state = GAME_OVER;
1741 else
1743 initialise_ship();
1744 ship.waiting_for_space = true;
1751 void thrust_ship(void)
1753 if(!ship.waiting_for_space)
1755 ship.position.dx += ( ship.vertices[0].x - ship.vertices[2].x )/20;
1756 ship.position.dy += ( ship.vertices[0].y - ship.vertices[2].y )/20;
1757 /*if dx and dy are below a certain threshold, then set 'em to 0
1758 but to do this we need to ascertain if the spacehip as moved on screen
1759 for more than a certain amount. */
1761 create_trail_blaze(THRUST_COLOUR, &ship.position);
1765 /**************************************************
1766 ** Rotate the ship using the passed sin & cos values
1767 ***************************************************/
1768 void rotate_ship(int c, int s)
1770 struct Point* point;
1771 int n;
1772 double xtemp;
1774 if(!ship.waiting_for_space && !ship.explode_countdown)
1776 point = ship.vertices;
1777 for(n=NUM_SHIP_VERTICES+1;--n;)
1779 xtemp = point->x;
1780 point->x = xtemp*c/SIN_COS_SCALE - point->y*s/SIN_COS_SCALE;
1781 point->y = point->y*c/SIN_COS_SCALE + xtemp*s/SIN_COS_SCALE;
1782 point++;
1787 void drawstars()
1789 struct Point* p;
1790 int n = NUM_STARS;
1792 p = stars;
1793 SET_FG(COL_STARS);
1795 while(--n)
1797 rb->lcd_drawpixel(p->x , p->y);
1798 p++;
1802 /*************************************************
1803 ** Draw And Move all Asteroids
1804 *************************************************/
1805 void draw_and_move_asteroids(void)
1807 int n;
1808 struct Asteroid* asteroid;
1810 asteroid = asteroids_array;
1811 SET_FG(COL_ASTEROID);
1813 n = MAX_NUM_ASTEROIDS;
1814 while(--n)
1816 if(game_state != PAUSE_MODE)
1818 if(asteroid->exists)
1820 move_point(&asteroid->position);
1821 rotate_asteroid(asteroid);
1822 draw_polygon(asteroid->vertices, asteroid->position.x/SCALE,
1823 asteroid->position.y/SCALE,
1824 NUM_ASTEROID_VERTICES);
1826 else if(asteroid->explode_countdown)
1828 /* animate_and_draw_explosion(asteroid->vertices,
1829 NUM_ASTEROID_VERTICES,
1830 asteroid->position.x/SCALE,
1831 asteroid->position.y/SCALE); */
1832 asteroid->explode_countdown--;
1835 else
1837 if(asteroid->exists)
1838 draw_polygon(asteroid->vertices,
1839 asteroid->position.x/SCALE,
1840 asteroid->position.y/SCALE,
1841 NUM_ASTEROID_VERTICES);
1843 asteroid++;
1847 void create_stars(void)
1849 struct TrailPoint* tpoint;
1850 struct Point* p;
1851 int n;
1853 p = stars;
1854 n = NUM_STARS;
1855 while(--n)
1857 p->x = (rb->rand()%LCD_WIDTH);
1858 p->y = (rb->rand()%LCD_HEIGHT);
1859 p++;
1863 /* give the point a random countdown timer, so they dissapears at different
1864 times */
1865 tpoint = trailPoints;
1866 n = NUM_TRAIL_POINTS;
1867 while(--n)
1869 tpoint->alive = 0;
1870 tpoint++;
1874 /*************************************************
1875 ** Creates start_num number of new asteroids of
1876 ** full size.
1877 **************************************************/
1878 void initialise_game(int start_num)
1880 int n;
1881 asteroid_count = next_missile_count = next_thrust_count = 0;
1882 struct Asteroid* asteroid;
1883 struct Missile* missile;
1884 extra_life = EXTRA_LIFE;
1886 /*no enemy*/
1887 enemy_on_screen = 0;
1888 enemy_missile.survived = 0;
1890 /*clear asteroids*/
1891 asteroid = asteroids_array;
1892 n = MAX_NUM_ASTEROIDS;
1893 while(--n)
1895 asteroid->exists = false;
1896 asteroid++;
1899 /*make some LARGE asteroids*/
1900 for(n = 0; n < start_num; n++)
1901 initialise_asteroid(&asteroids_array[n], LARGE);
1903 /*ensure all missiles are out of action: */
1904 missile = missiles_array;
1905 n = MAX_NUM_MISSILES;
1906 while(--n)
1908 missile->survived=0;
1909 missile++;
1913 static int spacerocks_game_loop(void)
1915 char s[20];
1916 char level[10];
1917 int button;
1918 int end;
1919 int position;
1921 /*create stars once, and once only:*/
1922 create_stars();
1924 if (spacerocks_menu(false)!=0)
1925 return 0;
1927 SET_BG(LCD_BLACK);
1929 while(true)
1931 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1932 rb->lcd_clear_display();
1933 SET_FG(COL_TEXT);
1934 switch(game_state) {
1935 case(GAME_OVER):
1936 rb->splash (HZ * 2, "Game Over");
1937 rb->lcd_clear_display();
1938 position=highscore_update(current_score, current_level, "",
1939 highest,NUM_SCORES);
1940 if (position == 0)
1941 rb->splash(HZ*2, "New High Score");
1942 if (position != -1)
1943 highscore_show(position, highest, NUM_SCORES, true);
1944 if (spacerocks_menu(false)!=0)
1945 return 0;
1946 break;
1948 case(PAUSE_MODE):
1949 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1950 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1951 rb->lcd_putsxy(CENTER_LCD_X - 15,
1952 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "pause");
1953 draw_and_move_missiles();
1954 draw_lives();
1955 draw_and_move_ship();
1956 break;
1958 case(PLAY_MODE):
1959 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1960 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1961 draw_and_move_missiles();
1962 draw_lives();
1963 check_collisions();
1964 draw_and_move_ship();
1965 break;
1967 case(SHOW_LEVEL):
1968 show_level_timeout--;
1969 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1970 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1971 rb->snprintf(level, sizeof(level), "stage %d ", current_level);
1972 rb->lcd_putsxy(CENTER_LCD_X - 20,
1973 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, level);
1974 draw_and_move_ship();
1975 draw_lives();
1976 if(!show_level_timeout) {
1977 initialise_game(current_level);
1978 game_state = PLAY_MODE;
1979 draw_lives();
1981 break;
1983 draw_trail_blaze();
1984 drawstars();
1985 draw_and_move_asteroids();
1986 draw_and_move_enemy();
1988 rb->lcd_update();
1990 #ifdef HAS_BUTTON_HOLD
1991 if (rb->button_hold())
1992 game_state = PAUSE_MODE;
1994 #endif
1995 button = rb->button_get(false);
1996 switch(button) {
1997 case(AST_QUIT):
1998 if (spacerocks_menu(true)!=0)
1999 return 0;
2000 break;
2001 #ifdef AST_PAUSE
2002 case(AST_PAUSE):
2003 if (game_state == PAUSE_MODE) {
2004 game_state = PLAY_MODE;
2005 break;
2007 else if (game_state != PLAY_MODE)
2008 break;
2009 #endif
2010 case (AST_LEFT):
2011 case (AST_LEFT | BUTTON_REPEAT):
2012 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
2013 rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN);
2014 break;
2016 case (AST_RIGHT):
2017 case (AST_RIGHT | BUTTON_REPEAT):
2018 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
2019 rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN);
2020 break;
2022 case (AST_THRUST):
2023 case (AST_THRUST | BUTTON_REPEAT):
2024 if((game_state == PLAY_MODE || game_state == SHOW_LEVEL) &&
2025 !next_thrust_count) {
2026 thrust_ship();
2027 next_thrust_count = 5;
2029 break;
2031 case (AST_HYPERSPACE):
2032 if(game_state == PLAY_MODE)
2033 hyperspace();
2034 /*maybe shield if it gets too hard */
2035 break;
2037 case (AST_FIRE):
2038 case (AST_FIRE | BUTTON_REPEAT):
2039 if(game_state == PLAY_MODE) {
2040 if(!next_missile_count) {
2041 fire_missile();
2042 next_missile_count = 10;
2045 else if(game_state == PAUSE_MODE) {
2046 game_state = PLAY_MODE;
2048 break;
2050 default:
2051 if (rb->default_event_handler(button)==SYS_USB_CONNECTED)
2052 return PLUGIN_USB_CONNECTED;
2053 break;
2056 if(next_missile_count)
2057 next_missile_count--;
2059 if(next_thrust_count)
2060 next_thrust_count--;
2062 if (TIME_BEFORE(*rb->current_tick, end))
2063 rb->sleep(end-*rb->current_tick);
2064 else
2065 rb->yield();
2069 enum plugin_status plugin_start(const void* parameter)
2071 (void)parameter;
2073 #if LCD_DEPTH > 1
2074 rb->lcd_set_backdrop(NULL);
2075 #endif
2076 /* universal font */
2077 rb->lcd_setfont(FONT_SYSFIXED);
2078 /* Turn off backlight timeout */
2079 backlight_force_on(); /* backlight control in lib/helper.c */
2080 highscore_load(HIGH_SCORE,highest,NUM_SCORES);
2081 spacerocks_game_loop();
2082 rb->lcd_setfont(FONT_UI);
2083 highscore_save(HIGH_SCORE,highest,NUM_SCORES);
2084 /* Turn on backlight timeout (revert to settings) */
2085 backlight_use_settings(); /* backlight control in lib/helper.c */
2087 return PLUGIN_OK;