fix red.
[kugel-rb/myfork.git] / apps / plugins / spacerocks.c
blobb0c9a4d60477f68306991e04b3881d733abf099d
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) || CONFIG_KEYPAD == MROBE500_PAD
201 #define AST_QUIT BUTTON_POWER
203 #elif (CONFIG_KEYPAD == SAMSUNG_YH_PAD)
204 #define AST_PAUSE BUTTON_FFWD
205 #define AST_QUIT BUTTON_REC
206 #define AST_THRUST_REP (BUTTON_UP | BUTTON_REW)
207 #define AST_THRUST BUTTON_UP
208 #define AST_HYPERSPACE BUTTON_DOWN
209 #define AST_LEFT BUTTON_LEFT
210 #define AST_LEFT_REP (BUTTON_LEFT | BUTTON_REW)
211 #define AST_RIGHT BUTTON_RIGHT
212 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REW)
213 #define AST_FIRE BUTTON_PLAY
214 #define AST_FIRE_REP (BUTTON_PLAY | BUTTON_REW)
216 #else
217 #error No keymap defined!
218 #endif
220 #ifdef HAVE_TOUCHSCREEN
221 #ifndef AST_PAUSE
222 #define AST_PAUSE BUTTON_CENTER
223 #endif
224 #ifndef AST_QUIT
225 #define AST_QUIT BUTTON_TOPLEFT
226 #endif
227 #ifndef AST_THRUST_REP
228 #define AST_THRUST_REP (BUTTON_TOPMIDDLE | BUTTON_REPEAT)
229 #endif
230 #ifndef AST_THRUST
231 #define AST_THRUST BUTTON_TOPMIDDLE
232 #endif
233 #ifndef AST_HYPERSPACE
234 #define AST_HYPERSPACE BUTTON_TOPRIGHT
235 #endif
236 #ifndef AST_LEFT
237 #define AST_LEFT BUTTON_MIDLEFT
238 #endif
239 #ifndef AST_LEFT_REP
240 #define AST_LEFT_REP (BUTTON_MIDLEFT | BUTTON_REPEAT)
241 #endif
242 #ifndef AST_RIGHT
243 #define AST_RIGHT BUTTON_MIDRIGHT
244 #endif
245 #ifndef AST_RIGHT_REP
246 #define AST_RIGHT_REP (BUTTON_MIDRIGHT | BUTTON_REPEAT)
247 #endif
248 #ifndef AST_FIRE
249 #define AST_FIRE BUTTON_BOTTOMMIDDLE
250 #endif
251 #ifndef AST_FIRE_REP
253 #ifdef BUTTON_MENU
254 #define AST_FIRE_REP (BUTTON_BOTTOMMIDDLE | BUTTON_MENU)
255 #else
256 #define AST_FIRE_REP BUTTON_BOTTOMMIDDLE | BUTTON_REPEAT
257 #endif
259 #endif
260 #endif
262 #define RES MAX(LCD_WIDTH, LCD_HEIGHT)
263 #define LARGE_LCD RES >= 200
264 #define ENEMY_MISSILE_SURVIVAL_LENGTH RES/2
265 #define ASTEROID_SPEED RES/20
266 #define MISSILE_SURVIVAL_LENGTH 40
268 #define CYCLETIME 30
270 #define EXTRA_LIFE 250
271 #define SPAWN_TIME 30
272 #define BLINK_TIME 10
273 #define SCALE 5000
274 #define MISSILE_SCALE 5000
275 #define WRAP_GAP 12
276 #define EXPLOSION_LENGTH 20
277 #define SHOW_COL 0
278 #define POINT_SIZE 2
279 #define MAX_NUM_ASTEROIDS 25
280 #define MAX_NUM_MISSILES 6
281 #define ENEMY_BIG_PROBABILITY_START 10
282 #define ENEMY_APPEAR_PROBABILITY_START 35
283 #define ENEMY_APPEAR_TIMING_START 1800
284 #define LITTLE_SHIP 2
285 #define BIG_SHIP 1
286 #define SHOW_GAME_OVER_TIME 100
287 #define SHOW_LEVEL_TIME 50
288 #define START_LIVES 3
289 #define START_LEVEL 1
290 #define NUM_ASTEROID_VERTICES 10
291 #define NUM_SHIP_VERTICES 4
292 #define NUM_ENEMY_VERTICES 6
293 #define MAX_LEVEL MAX_NUM_ASTEROIDS
294 #define ENEMY_SPEED 4
295 #define SIZE_ENEMY_COLLISION 5*SCALE
296 #define NUM_STARS 50
297 #define NUM_TRAIL_POINTS 70
298 #define NUM_ROTATIONS 16
300 #define SIN_COS_SCALE 10000
302 #define FAST_ROT_CW_SIN 873
303 #define FAST_ROT_CW_COS 9963
304 #define FAST_ROT_ACW_SIN -873
305 #define FAST_ROT_ACW_COS 9963
307 #define MEDIUM_ROT_CW_SIN 350
308 #define MEDIUM_ROT_CW_COS 9994
309 #define MEDIUM_ROT_ACW_SIN -350
310 #define MEDIUM_ROT_ACW_COS 9994
312 #define SLOW_ROT_CW_SIN 350
313 #define SLOW_ROT_CW_COS 9994
314 #define SLOW_ROT_ACW_SIN - 350
315 #define SLOW_ROT_ACW_COS 9994
317 #ifdef HAVE_LCD_COLOR
318 #define SHIP_ROT_CW_SIN 2419
319 #define SHIP_ROT_CW_COS 9702
320 #define SHIP_ROT_ACW_SIN -2419
321 #define SHIP_ROT_ACW_COS 9702
322 #else
323 #define SHIP_ROT_CW_SIN 3827
324 #define SHIP_ROT_CW_COS 9239
325 #define SHIP_ROT_ACW_SIN -3827
326 #define SHIP_ROT_ACW_COS 9239
327 #endif
330 #define SCALED_WIDTH (LCD_WIDTH*SCALE)
331 #define SCALED_HEIGHT (LCD_HEIGHT*SCALE)
332 #define CENTER_LCD_X (LCD_WIDTH/2)
333 #define CENTER_LCD_Y (LCD_HEIGHT/2)
335 #define SHIP_EXPLOSION_COLOUR 1
336 #define ASTEROID_EXPLOSION_COLOUR 2
337 #define ENEMY_EXPLOSION_COLOUR 3
338 #define THRUST_COLOUR 4
340 #define ASTEROID_R 230
341 #define ASTEROID_G 200
342 #define ASTEROID_B 100
343 #define SHIP_R 255
344 #define SHIP_G 255
345 #define SHIP_B 255
346 #define ENEMY_R 50
347 #define ENEMY_G 220
348 #define ENEMY_B 50
349 #define THRUST_R 200
350 #define THRUST_G 200
351 #define THRUST_B 0
353 #ifdef HAVE_LCD_COLOR
354 #define COL_MISSILE LCD_RGBPACK(200,0,0)
355 #define COL_PLAYER LCD_RGBPACK(200,200,200)
356 #define COL_INVULN LCD_RGBPACK(100,100,200)
357 #define COL_STARS LCD_WHITE
358 #define COL_ASTEROID LCD_RGBPACK(ASTEROID_R,ASTEROID_G,ASTEROID_B)
359 #define COL_TEXT LCD_RGBPACK(200,200,255)
360 #define COL_ENEMY LCD_RGBPACK(ENEMY_R,ENEMY_G,ENEMY_B)
361 #define SET_FG rb->lcd_set_foreground
362 #define SET_BG rb->lcd_set_background
363 #else
364 #define SET_FG(x)
365 #define SET_BG(x)
366 #endif
368 #define MARGIN 5
370 #define HIGH_SCORE PLUGIN_GAMES_DIR "/spacerocks.score"
371 #define NUM_SCORES 5
373 struct highscore highest[NUM_SCORES];
375 /* The array of points that make up an asteroid */
376 static const short asteroid_one[NUM_ASTEROID_VERTICES*2] =
378 -2, -12,
379 4, -8,
380 8, -14,
381 16, -5,
382 14, 0,
383 20, 2,
384 12, 14,
385 -4, 14,
386 -10, 6,
387 -10, -8
390 /* The array of points that make up an asteroid */
391 static const short asteroid_two[NUM_ASTEROID_VERTICES*2] =
393 -2, -12,
394 4, -16,
395 6, -14,
396 16, -8,
397 14, 0,
398 20, 2,
399 12, 14,
400 -4, 14,
401 -10, 6,
402 -10, -8
405 /* The array of points that make up an asteroid */
406 static const short asteroid_three[NUM_ASTEROID_VERTICES*2] =
408 -2, -12,
409 4, -16,
410 6, -14,
411 2, -8,
412 14, 0,
413 20, 2,
414 12, 14,
415 -4, 14,
416 -16, 6,
417 -10, -8
420 /* The array od points the make up the ship */
421 static const short ship_vertices[NUM_SHIP_VERTICES*2] =
423 #if(LARGE_LCD)
424 0,-6,
425 4, 6,
426 0, 2,
427 -4, 6
428 #else
429 0,-4,
430 3, 4,
431 0, 1,
432 -3, 4
433 #endif
436 /* The array of points the make up the bad spaceship */
437 static const short enemy_vertices[NUM_ENEMY_VERTICES*2] =
439 #if(LARGE_LCD)
440 -8, 0,
441 -4, 4,
442 4, 4,
443 8, 0,
444 4, -4,
445 -4, -4
446 #else
447 -5, 0,
448 -2, 2,
449 2, 2,
450 5, 0,
451 2, -2,
452 -2, -2
453 #endif
457 enum asteroid_type
459 #if(LARGE_LCD)
460 SMALL = 2,
461 MEDIUM = 4,
462 LARGE = 6,
463 #else
464 SMALL = 1,
465 MEDIUM = 2,
466 LARGE = 3,
467 #endif
471 enum game_state
473 GAME_OVER,
474 SHOW_LEVEL,
475 PLAY_MODE,
476 PAUSE_MODE
479 struct Point
481 int x;
482 int y;
483 int dx;
484 int dy;
487 struct TrailPoint
489 int alive;
490 struct Point position;
491 short r;
492 short g;
493 short b;
494 short dec;
497 /* Asteroid structure, contains an array of points */
498 struct Asteroid
500 enum asteroid_type type;
501 bool exists;
502 struct Point position;
503 struct Point vertices[NUM_ASTEROID_VERTICES];
504 int radius;
505 long speed_cos;
506 long speed_sin;
507 int explode_countdown;
510 struct Ship
512 struct Point vertices[NUM_SHIP_VERTICES];
513 struct Point position;
514 bool waiting_for_space;
515 bool invulnerable;
516 int spawn_time;
517 int explode_countdown;
520 struct Enemy
522 struct Point vertices[NUM_ENEMY_VERTICES];
523 struct Point position;
524 int explode_countdown;
525 long last_time_appeared;
526 short size_probability;
527 short appear_probability;
528 short appear_timing;
531 struct Missile
533 struct Point position;
534 struct Point oldpoint;
535 int survived;
538 static enum game_state game_state;
539 static int asteroid_count;
540 static int next_missile_count;
541 static int next_thrust_count;
542 static int num_lives;
543 static int extra_life;
544 static int show_level_timeout;
545 static int current_level;
546 static int current_score;
547 static int space_check_size = 30*SCALE;
549 static bool enemy_on_screen;
550 static struct Ship ship;
551 static struct Point stars[NUM_STARS];
552 static struct Asteroid asteroids_array[MAX_NUM_ASTEROIDS];
553 static struct Missile missiles_array[MAX_NUM_MISSILES];
554 static struct Missile enemy_missile;
555 static struct Enemy enemy;
556 static struct Point lives_points[NUM_SHIP_VERTICES];
557 static struct TrailPoint trailPoints[NUM_TRAIL_POINTS];
559 void draw_and_move_asteroids(void);
560 void initialise_game(int nStartNum);
562 bool is_asteroid_near_ship(struct Asteroid* asteroid);
563 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point);
565 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type eType);
566 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices);
567 void rotate_asteroid(struct Asteroid* asteroid);
568 void create_asteroid(enum asteroid_type type, int x, int y);
569 void create_stars(void);
571 void initialise_ship(void);
572 void draw_and_move_ship(void);
573 void rotate_ship(int s, int c);
574 void thrust_ship(void);
576 void initialise_missile(struct Missile* missile);
577 void draw_and_move_missiles(void);
578 void fire_missile(void);
580 void animate_and_draw_explosion(struct Point* point, int num_points, int xoffset, int yoffset);
581 void initialise_explosion(struct Point* point, int num_points);
583 void move_point(struct Point* point);
584 void hyperspace(void);
585 void check_collisions(void);
586 void initialise_enemy(void);
587 void draw_and_move_enemy(void);
588 void draw_lives(void);
589 void drawstars(void);
590 bool is_ship_within_asteroid(struct Asteroid* asteroid);
593 void init(void)
595 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
596 enemy.appear_timing = ENEMY_APPEAR_TIMING_START;
597 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
598 current_level = START_LEVEL;
599 num_lives = START_LIVES;
600 current_score = 0;
601 initialise_ship();
602 initialise_game(current_level);
603 show_level_timeout = SHOW_LEVEL_TIME;
604 game_state = PLAY_MODE;
607 static bool spacerocks_help(void)
609 rb->lcd_setfont(FONT_UI);
610 #define WORDS (sizeof help_text / sizeof (char*))
611 static char *help_text[] = {
612 "Spacerocks", "", "Aim", "", "The", "goal", "of", "the", "game", "is",
613 "to", "blow", "up", "the", "asteroids", "and", "avoid", "being", "hit", "by",
614 "them.", "Also", "you'd", "better", "watch", "out", "for", "the", "UFOs!"
616 static struct style_text formation[]={
617 { 0, TEXT_CENTER|TEXT_UNDERLINE },
618 { 2, C_RED },
619 { -1, 0 }
621 #ifdef HAVE_LCD_COLOR
622 rb->lcd_set_background(LCD_BLACK);
623 rb->lcd_set_foreground(LCD_WHITE);
624 #endif
625 int button;
626 if (display_text(WORDS, help_text, formation, NULL)==PLUGIN_USB_CONNECTED)
627 return true;
628 do {
629 button = rb->button_get(true);
630 if (button == SYS_USB_CONNECTED) {
631 return true;
633 } while( ( button == BUTTON_NONE )
634 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
635 rb->lcd_setfont(FONT_SYSFIXED);
637 return false;
640 static bool _ingame;
641 static int spacerocks_menu_cb(int action, const struct menu_item_ex *this_item)
643 if(action == ACTION_REQUEST_MENUITEM
644 && !_ingame && ((intptr_t)this_item)==0)
645 return ACTION_EXIT_MENUITEM;
646 return action;
649 static int spacerocks_menu(bool ingame)
651 rb->button_clear_queue();
652 int choice = 0;
654 _ingame = ingame;
656 MENUITEM_STRINGLIST (main_menu, "Spacerocks Menu", spacerocks_menu_cb,
657 "Resume Game",
658 "Start New Game",
659 "Help",
660 "High Scores",
661 "Playback Control",
662 "Quit");
664 while (1) {
665 choice = rb->do_menu(&main_menu, &choice, NULL, false);
666 switch (choice) {
667 case 0:
668 return 0;
669 case 1:
670 init();
671 return 0;
672 case 2:
673 if(spacerocks_help())
674 return 1;
675 break;
676 case 3:
677 highscore_show(NUM_SCORES, highest, NUM_SCORES, true);
678 break;
679 case 4:
680 playback_control(NULL);
681 break;
682 case 5:
683 return 1;
684 case MENU_ATTACHED_USB:
685 return 1;
686 default:
687 break;
692 bool point_in_poly(struct Point* _point, int num_vertices, int x, int y)
694 struct Point* pi;
695 struct Point* pj;
696 int n;
697 bool c = false;
699 pi = _point;
700 pj = _point;
701 pj += num_vertices-1;
703 n = num_vertices;
704 while(n--)
706 if((((pi->y <= y) && (y < pj->y)) || ((pj->y <= y) && (y < pi->y))) &&
707 (x < (pj->x - pi->x) * (y - pi->y) / (pj->y - pi->y) + pi->x))
708 c = !c;
710 if(n == num_vertices - 1)
711 pj = _point;
712 else
713 pj++;
715 pi++;
718 return c;
721 void move_point(struct Point* point)
723 point->x += point->dx;
724 point->y += point->dy;
726 /*check bounds on the x-axis:*/
727 if(point->x >= SCALED_WIDTH)
728 point->x = 0;
729 else if(point->x <= 0)
730 point->x = SCALED_WIDTH;
732 /*Check bounds on the y-axis:*/
733 if(point->y >= SCALED_HEIGHT)
734 point->y = 0;
735 else if(point->y <= 0)
736 point->y = SCALED_HEIGHT;
739 void create_trail(struct TrailPoint* tpoint)
741 tpoint->position.dx = -( ship.vertices[0].x - ship.vertices[2].x )/10;
742 tpoint->position.dy = -( ship.vertices[0].y - ship.vertices[2].y )/10;
745 void create_explosion_trail(struct TrailPoint* tpoint)
747 tpoint->position.dx = (rb->rand()%5050)-2500;
748 tpoint->position.dy = (rb->rand()%5050)-2500;
751 void create_trail_blaze(int colour, struct Point* position)
753 int numtoadd;
754 struct TrailPoint* tpoint;
755 int n;
756 int xadd,yadd;
757 if(colour != SHIP_EXPLOSION_COLOUR)
759 numtoadd = NUM_TRAIL_POINTS/5;
760 xadd = position->x;
761 yadd = position->y;
763 else
765 numtoadd = NUM_TRAIL_POINTS/8;
766 xadd = ship.position.x;
767 yadd = ship.position.y;
770 /* give the point a random countdown timer, so they dissapears at different times */
771 tpoint = trailPoints;
772 n = NUM_TRAIL_POINTS;
773 while(--n)
775 if(tpoint->alive <= 0 && numtoadd)
777 numtoadd--;
778 /* take a random x point anywhere between bottom two points of ship. */
779 /* ship.position.x; */
780 tpoint->position.x = (ship.vertices[2].x + (rb->rand()%18000)-9000) + position->x;
781 tpoint->position.y = (ship.vertices[2].y + (rb->rand()%18000)-9000) + position->y;
783 switch(colour)
785 case SHIP_EXPLOSION_COLOUR:
786 tpoint->r = 255;
787 tpoint->g = 255;
788 tpoint->b = 255;
789 create_explosion_trail(tpoint);
790 tpoint->alive = 510;
791 tpoint->dec = 2;
792 break;
793 case ASTEROID_EXPLOSION_COLOUR:
794 tpoint->r = ASTEROID_R;
795 tpoint->g = ASTEROID_G;
796 tpoint->b = ASTEROID_B;
797 create_explosion_trail(tpoint);
798 tpoint->alive = 510;
799 tpoint->dec = 2;
800 break;
801 case ENEMY_EXPLOSION_COLOUR:
802 tpoint->r = ENEMY_R;
803 tpoint->g = ENEMY_G;
804 tpoint->b = ENEMY_B;
805 create_explosion_trail(tpoint);
806 tpoint->alive = 510;
807 tpoint->dec = 2;
808 break;
809 case THRUST_COLOUR:
810 tpoint->r = THRUST_R;
811 tpoint->g = THRUST_G;
812 tpoint->b = THRUST_B;
813 create_trail(tpoint);
814 tpoint->alive = 175;
815 tpoint->dec = 4;
816 break;
818 /* add a proportional bit to the x and y based on dx and dy */
820 /* give the points a speed based on direction of travel - i.e. opposite */
821 tpoint->position.dx += position->dx;
822 tpoint->position.dy += position->dy;
826 tpoint++;
828 /* find a space in the array of trail_points that is NULL or DEAD or whatever.
829 and place this one here. */
833 void draw_trail_blaze(void)
835 struct TrailPoint* tpoint;
836 /* loop through, if alive then move and draw.
837 when drawn, countdown it's timer.
838 if zero kill it! */
839 tpoint = trailPoints;
840 int n = NUM_TRAIL_POINTS;
842 while(--n)
844 if(tpoint->alive)
846 if(game_state != PAUSE_MODE)
848 tpoint->alive-=10;
849 move_point(&(tpoint->position));
851 #ifdef HAVE_LCD_COLOR
852 /* intensity = tpoint->alive/2; */
853 if(tpoint->r>0)tpoint->r-=tpoint->dec;
854 if(tpoint->g>0)tpoint->g-=tpoint->dec;
855 if(tpoint->b>0)tpoint->b-=tpoint->dec;
856 SET_FG(LCD_RGBPACK(tpoint->r, tpoint->g, tpoint->b));
857 #endif
858 rb->lcd_drawpixel(tpoint->position.x/SCALE , tpoint->position.y/SCALE);
860 tpoint++;
864 /*Check if point is within a rectangle*/
865 bool is_point_within_rectangle(struct Point* rect, struct Point* p, int size)
867 #if SHOW_COL
868 int aTLx = rect->x - size;
869 int aTLy = rect->y - size;
870 int aBRx = rect->x + size;
871 int aBRy = rect->y + size;
872 rb->lcd_hline( aTLx/SCALE, aBRx/SCALE, aTLy/SCALE);
873 rb->lcd_vline( aTLx/SCALE, aTLy/SCALE, aBRy/SCALE);
874 rb->lcd_hline( aTLx/SCALE, aBRx/SCALE, aBRy/SCALE);
875 rb->lcd_vline( aBRx/SCALE, aBRy/SCALE, aTLy/SCALE);
876 return (p->x > aTLx && p->x < aBRx && p->y > aTLy && p->y < aBRy);
877 #else
878 return (p->x > rect->x - size && p->x < rect->x + size &&
879 p->y > rect->y - size && p->y < rect->y + size);
880 #endif
883 /* Draw polygon */
884 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices)
886 int n, t1, t2, oldX, oldY;
887 struct Point *p;
888 bool bDrawAll = px < WRAP_GAP || LCD_WIDTH - px < WRAP_GAP ||
889 py < WRAP_GAP || LCD_HEIGHT - py < WRAP_GAP;
891 p = vertices;
892 p += num_vertices-1;
893 oldX = p->x/SCALE + px;
894 oldY = p->y/SCALE + py;
895 p = vertices;
896 for(n = num_vertices+1; --n;)
898 t1 = p->x/SCALE + px;
899 t2 = p->y/SCALE + py;
901 rb->lcd_drawline(oldX, oldY, t1, t2);
903 if(bDrawAll)
905 rb->lcd_drawline(oldX - LCD_WIDTH, oldY, t1 - LCD_WIDTH, t2);
906 rb->lcd_drawline(oldX + LCD_WIDTH, oldY, t1 + LCD_WIDTH, t2);
907 rb->lcd_drawline(oldX - LCD_WIDTH, oldY + LCD_HEIGHT,
908 t1 - LCD_WIDTH, t2 + LCD_HEIGHT);
909 rb->lcd_drawline(oldX + LCD_WIDTH, oldY + LCD_HEIGHT,
910 t1 + LCD_WIDTH, t2 + LCD_HEIGHT);
912 rb->lcd_drawline(oldX, oldY - LCD_HEIGHT, t1, t2 - LCD_HEIGHT);
913 rb->lcd_drawline(oldX, oldY + LCD_HEIGHT, t1, t2 + LCD_HEIGHT);
914 rb->lcd_drawline(oldX - LCD_WIDTH, oldY - LCD_HEIGHT,
915 t1 - LCD_WIDTH, t2 - LCD_HEIGHT);
916 rb->lcd_drawline(oldX + LCD_WIDTH, oldY - LCD_HEIGHT,
917 t1 + LCD_WIDTH, t2 - LCD_HEIGHT);
919 oldX = t1;
920 oldY = t2;
921 p++;
925 void animate_and_draw_explosion(struct Point* point, int num_points,
926 int xoffset, int yoffset)
928 int n;
929 for(n = num_points; --n;)
931 if(game_state != PAUSE_MODE)
933 point->x += point->dx;
934 point->y += point->dy;
936 rb->lcd_fillrect( point->x/SCALE + xoffset, point->y/SCALE + yoffset,
937 POINT_SIZE, POINT_SIZE);
938 point++;
942 /*stop movement of ship, 'cos that's what happens when you go into hyperspace.*/
943 void hyperspace(void)
945 ship.position.dx = ship.position.dy = 0;
946 ship.position.x = (rb->rand()%SCALED_WIDTH);
947 ship.position.y = (rb->rand()%SCALED_HEIGHT);
950 void initialise_enemy(void)
952 struct Point* point;
953 int n;
954 int size;
956 if(rb->rand()%100 > enemy.size_probability)
958 size = BIG_SHIP;
959 enemy.size_probability++;
960 if(enemy.size_probability < 90)
962 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
965 else
967 size = LITTLE_SHIP;
970 enemy_missile.survived = 0;
971 enemy_on_screen = true;
972 enemy.explode_countdown = 0;
973 enemy.last_time_appeared = *rb->current_tick;
974 point = enemy.vertices;
975 for(n = 0; n < NUM_ENEMY_VERTICES+NUM_ENEMY_VERTICES; n+=2)
977 point->x = enemy_vertices[n];
978 point->y = enemy_vertices[n+1];
979 point->x *= SCALE/size;
980 point->y *= SCALE/size;
981 point++;
984 if(ship.position.x >= SCALED_WIDTH/2)
986 enemy.position.dx = ENEMY_SPEED;
987 enemy.position.x = 0;
989 else
991 enemy.position.dx = -ENEMY_SPEED;
992 enemy.position.x = SCALED_WIDTH;
995 if(ship.position.y >= SCALED_HEIGHT/2)
997 enemy.position.dy = ENEMY_SPEED;
998 enemy.position.y = 0;
1000 else
1002 enemy.position.dy = -ENEMY_SPEED;
1003 enemy.position.y = SCALED_HEIGHT;
1006 enemy.position.dx *= SCALE/10;
1007 enemy.position.dy *= SCALE/10;
1010 void draw_and_move_enemy(void)
1012 int enemy_x, enemy_y;
1013 struct Point *point;
1015 SET_FG(COL_ENEMY);
1017 if(enemy_on_screen)
1019 enemy_x = enemy.position.x/SCALE;
1020 enemy_y = enemy.position.y/SCALE;
1021 if(!enemy.explode_countdown)
1023 point = enemy.vertices;
1024 draw_polygon(enemy.vertices, enemy_x, enemy_y, NUM_ENEMY_VERTICES);
1025 rb->lcd_drawline(enemy.vertices[0].x/SCALE + enemy_x,
1026 enemy.vertices[0].y/SCALE + enemy_y,
1027 enemy.vertices[3].x/SCALE + enemy_x,
1028 enemy.vertices[3].y/SCALE + enemy_y);
1030 if(game_state != PAUSE_MODE)
1032 enemy.position.x += enemy.position.dx;
1033 enemy.position.y += enemy.position.dy;
1036 if(enemy.position.x > SCALED_WIDTH || enemy.position.x < 0)
1037 enemy_on_screen = false;
1039 if(enemy.position.y > SCALED_HEIGHT)
1040 enemy.position.y = 0;
1041 else if(enemy.position.y < 0)
1042 enemy.position.y = SCALED_HEIGHT;
1044 if( (rb->rand()%1000) < 10)
1045 enemy.position.dy = -enemy.position.dy;
1047 else
1050 /* animate_and_draw_explosion(enemy.vertices, NUM_ENEMY_VERTICES,
1051 enemy_x, enemy.position.y/SCALE); */
1052 if(game_state != PAUSE_MODE)
1054 enemy.explode_countdown--;
1055 if(!enemy.explode_countdown)
1056 enemy_on_screen = false;
1060 else
1062 if( (*rb->current_tick - enemy.last_time_appeared) > enemy.appear_timing)
1063 if(rb->rand()%100 > enemy.appear_probability) initialise_enemy();
1066 if(!enemy_missile.survived && game_state != GAME_OVER)
1068 /*if no missile and the enemy is here and not exploding..then shoot baby!*/
1069 if( !enemy.explode_countdown && enemy_on_screen &&
1070 !ship.waiting_for_space && (rb->rand()%10) > 5 )
1072 enemy_missile.position.x = enemy.position.x;
1073 enemy_missile.position.y = enemy.position.y;
1075 /*lame, needs to be sorted - it's trying to shoot at the ship*/
1076 if(ABS(enemy.position.y - ship.position.y) <= 5*SCALE)
1078 enemy_missile.position.dy = 0;
1080 else
1082 if( enemy.position.y < ship.position.y)
1083 enemy_missile.position.dy = 1;
1084 else
1085 enemy_missile.position.dy = -1;
1088 if(ABS(enemy.position.x - ship.position.x) <= 5*SCALE)
1089 enemy_missile.position.dx = 0;
1090 else
1092 if( enemy.position.x < ship.position.x)
1093 enemy_missile.position.dx = 1;
1094 else
1095 enemy_missile.position.dx = -1;
1098 if(enemy_missile.position.dx == 0 &&
1099 enemy_missile.position.dy == 0)
1100 enemy_missile.position.dx = enemy_missile.position.dy = -1;
1102 enemy_missile.position.dx *= SCALE;
1103 enemy_missile.position.dy *= SCALE;
1104 enemy_missile.survived = ENEMY_MISSILE_SURVIVAL_LENGTH;
1108 else
1110 rb->lcd_fillrect( enemy_missile.position.x/SCALE,
1111 enemy_missile.position.y/SCALE,
1112 POINT_SIZE, POINT_SIZE);
1113 if(game_state != PAUSE_MODE)
1115 move_point(&enemy_missile.position);
1116 enemy_missile.survived--;
1121 /******************
1122 * Lame method of collision
1123 * detection. It's checking for collision
1124 * between point and a big rectangle around the asteroid...
1125 *******************/
1126 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point)
1128 if( !is_point_within_rectangle(&asteroid->position, point,
1129 asteroid->radius+4*SCALE) )
1130 return false;
1132 if(point_in_poly(asteroid->vertices, NUM_ASTEROID_VERTICES,
1133 point->x - asteroid->position.x,
1134 point->y - asteroid->position.y))
1136 switch(asteroid->type)
1138 case(SMALL):
1139 asteroid->explode_countdown = EXPLOSION_LENGTH;
1140 create_trail_blaze(ASTEROID_EXPLOSION_COLOUR, &asteroid->position);
1141 break;
1143 case(LARGE):
1144 create_asteroid(MEDIUM, asteroid->position.x,
1145 asteroid->position.y);
1146 create_asteroid(MEDIUM, asteroid->position.x,
1147 asteroid->position.y);
1148 break;
1150 case(MEDIUM):
1151 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1152 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1153 break;
1156 current_score++;
1157 if(current_score > extra_life)
1159 num_lives++;
1160 extra_life = current_score+EXTRA_LIFE;
1162 asteroid_count--;
1163 asteroid->exists = false;
1164 return true;
1166 else
1167 return false;
1170 bool is_point_within_enemy(struct Point* point)
1172 if( is_point_within_rectangle(&enemy.position, point, 7*SCALE) )
1174 current_score += 5;
1175 /*enemy_missile.survived = 0;*/
1176 enemy.explode_countdown = EXPLOSION_LENGTH;
1177 /* initialise_explosion(enemy.vertices, NUM_ENEMY_VERTICES); */
1178 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1179 return true;
1181 else
1182 return false;
1185 bool is_ship_within_asteroid(struct Asteroid* asteroid)
1187 bool hit = false;
1188 struct Point p;
1190 p.x = ship.position.x + ship.vertices[0].x;
1191 p.y = ship.position.y + ship.vertices[0].y;
1192 hit |= is_point_within_asteroid(asteroid, &p);
1194 if(!hit)
1196 p.x = ship.position.x + ship.vertices[1].x;
1197 p.y = ship.position.y + ship.vertices[1].y;
1198 hit |= is_point_within_asteroid(asteroid, &p);
1199 if(!hit)
1201 p.x = ship.position.x + ship.vertices[3].x;
1202 p.y = ship.position.y + ship.vertices[3].y;
1203 hit |= is_point_within_asteroid(asteroid, &p);
1207 return hit;
1210 void initialise_explosion(struct Point* point, int num_points)
1212 int n;
1214 point->x += point->dx;
1215 point->y += point->dy;
1216 for(n = num_points; --n;)
1218 point->dx = point->x;
1219 point->dy = point->y;
1220 point++;
1225 /* Check for collsions between the missiles and the asteroids and the ship */
1226 void check_collisions(void)
1228 int m, n;
1229 bool asteroids_onscreen = false;
1230 struct Missile* missile;
1231 struct Asteroid* asteroid;
1232 bool ship_cant_be_placed = false;
1234 asteroid = asteroids_array;
1235 m = MAX_NUM_ASTEROIDS;
1236 while(--m)
1238 /*if the asteroids exists then test missile collision:*/
1239 if(asteroid->exists)
1241 missile = missiles_array;
1242 n = MAX_NUM_MISSILES;
1243 while(--n)
1245 /*if the missiles exists:*/
1246 if(missile->survived > 0)
1248 /*has the missile hit the asteroid?*/
1249 if(is_point_within_asteroid(asteroid, &missile->position)
1250 || is_point_within_asteroid(asteroid,
1251 &missile->oldpoint))
1253 missile->survived = 0;
1254 break;
1257 missile++;
1260 /*now check collision with ship:*/
1261 if(asteroid->exists && !ship.waiting_for_space && !ship.explode_countdown)
1263 if(is_ship_within_asteroid(asteroid))
1265 if (!ship.invulnerable)
1267 /*if not invulnerable, blow up ship*/
1268 ship.explode_countdown = EXPLOSION_LENGTH;
1269 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1270 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1274 /*has the enemy missile blown something up?*/
1275 if(asteroid->exists && enemy_missile.survived)
1277 if(is_point_within_asteroid(asteroid, &enemy_missile.position))
1279 /*take that score back then:*/
1280 if(current_score > 0) current_score--;
1281 enemy_missile.survived = 0;
1284 /*if it still exists, check if ship is waiting for space:*/
1285 if(asteroid->exists && ship.waiting_for_space)
1286 ship_cant_be_placed |=
1287 is_point_within_rectangle(&ship.position,
1288 &asteroid->position,
1289 space_check_size);
1293 /*is an asteroid still exploding?*/
1294 if(asteroid->explode_countdown)
1295 asteroids_onscreen = true;
1297 asteroid++;
1300 /*now check collision between ship and enemy*/
1301 if(enemy_on_screen && !ship.waiting_for_space &&
1302 !ship.explode_countdown && !enemy.explode_countdown)
1304 /*has the enemy collided with the ship?*/
1305 if(is_point_within_enemy(&ship.position))
1307 if (!ship.invulnerable)
1309 ship.explode_countdown = EXPLOSION_LENGTH;
1310 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1311 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1313 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1316 /*Now see if the enemy has been shot at by the ships missiles:*/
1317 missile = missiles_array;
1318 n = MAX_NUM_MISSILES;
1319 while(--n)
1321 if(missile->survived > 0 &&
1322 is_point_within_enemy(&missile->position))
1324 missile->survived = 0;
1325 break;
1327 missile++;
1331 /*test collision with enemy missile and ship:*/
1332 if(!ship_cant_be_placed && enemy_missile.survived > 0 &&
1333 point_in_poly(ship.vertices, NUM_SHIP_VERTICES,
1334 enemy_missile.position.x - ship.position.x,
1335 enemy_missile.position.y - ship.position.y))
1337 if (!ship.invulnerable)
1339 ship.explode_countdown = EXPLOSION_LENGTH;
1340 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1341 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1343 enemy_missile.survived = 0;
1344 enemy_missile.position.x = enemy_missile.position.y = 0;
1347 if(!ship_cant_be_placed)
1348 ship.waiting_for_space = false;
1350 /*if all asteroids cleared then start again:*/
1351 if(asteroid_count == 0 && !enemy_on_screen && !asteroids_onscreen)
1353 current_level++;
1354 game_state = SHOW_LEVEL;
1355 enemy.appear_probability += 5;
1356 enemy.appear_timing -= 200;
1357 if( enemy.appear_probability > 100)
1358 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1359 show_level_timeout = SHOW_LEVEL_TIME;
1363 /*************************************************
1364 ** Creates a new asteroid of the given 4type (size)
1365 ** and at the given location.
1366 *************************************************/
1367 void create_asteroid(enum asteroid_type type, int x, int y)
1369 struct Asteroid* asteroid;
1370 int n;
1372 asteroid = asteroids_array;
1373 n = MAX_NUM_ASTEROIDS;
1374 while(--n)
1376 if(!asteroid->exists && !asteroid->explode_countdown)
1378 initialise_asteroid(asteroid, type);
1379 asteroid->position.x = x;
1380 asteroid->position.y = y;
1381 break;
1383 asteroid++;
1387 /* Initialise a missile */
1388 void initialise_missile(struct Missile* missile)
1390 missile->position.x = ship.position.x + ship.vertices[0].x;
1391 missile->position.y = ship.position.y + ship.vertices[0].y;
1392 missile->position.dx = (ship.vertices[0].x - ship.vertices[2].x)/2;
1393 missile->position.dy = (ship.vertices[0].y - ship.vertices[2].y)/2;
1394 missile->survived = MISSILE_SURVIVAL_LENGTH;
1395 missile->oldpoint.x = missile->position.x;
1396 missile->oldpoint.y = missile->position.y;
1399 /* Draw and Move all the missiles */
1400 void draw_and_move_missiles(void)
1402 int n;
1403 int p1x, p1y;
1404 int p2x, p2y;
1406 struct Missile* missile;
1407 missile = missiles_array;
1409 SET_FG(COL_MISSILE);
1411 n = MAX_NUM_MISSILES;
1412 while(--n)
1414 if(missile->survived)
1416 if(missile->position.dx > 0)
1418 if(missile->position.x >= missile->oldpoint.x)
1420 p1x = missile->oldpoint.x;
1421 p2x = missile->position.x;
1423 else
1425 p1x = 0;
1426 p2x = missile->position.x;
1429 else
1431 if(missile->oldpoint.x >= missile->position.x)
1433 p1x = missile->oldpoint.x;
1434 p2x = missile->position.x;
1436 else
1438 p1x = missile->oldpoint.x;
1439 p2x = LCD_WIDTH;
1443 if(missile->position.dy > 0)
1445 if(missile->position.y >= missile->oldpoint.y)
1447 p1y = missile->oldpoint.y;
1448 p2y = missile->position.y;
1450 else
1452 p1y = 0;
1453 p2y = missile->position.y;
1456 else
1458 if(missile->oldpoint.y >= missile->position.y)
1460 p1y = missile->oldpoint.y;
1461 p2y = missile->position.y;
1463 else
1465 p1y = missile->oldpoint.y;
1466 p2y = LCD_HEIGHT;
1470 rb->lcd_drawline( p1x/SCALE, p1y/SCALE, p2x/SCALE, p2y/SCALE);
1472 if(game_state != PAUSE_MODE)
1474 missile->oldpoint.x = missile->position.x;
1475 missile->oldpoint.y = missile->position.y;
1476 move_point(&missile->position);
1477 missile->survived--;
1480 missile++;
1484 void draw_lives(void)
1486 int n;
1487 int px = (LCD_WIDTH - num_lives*4 - 1);
1488 #if(LARGE_LCD)
1489 int py = (LCD_HEIGHT-6);
1490 #else
1491 int py = (LCD_HEIGHT-4);
1492 #endif
1494 SET_FG(COL_PLAYER);
1496 n = num_lives;
1497 while(--n)
1499 draw_polygon(lives_points, px, py, NUM_SHIP_VERTICES);
1500 #if(LARGE_LCD)
1501 px += 8;
1502 #else
1503 px += 6;
1504 #endif
1508 /*Fire the next missile*/
1509 void fire_missile(void)
1511 int n;
1512 struct Missile* missile;
1514 if(!ship.explode_countdown && !ship.waiting_for_space)
1516 missile = missiles_array;
1517 n = MAX_NUM_MISSILES;
1518 while(--n)
1520 if(!missile->survived)
1522 initialise_missile(missile);
1523 break;
1525 missile++;
1530 /* Initialise the passed Asteroid */
1531 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type type)
1533 int n;
1534 bool b,b2;
1535 struct Point* point;
1536 asteroid->exists = true;
1537 asteroid->type = type;
1538 asteroid->explode_countdown = 0;
1540 /*Set the radius of the asteroid:*/
1541 asteroid->radius = (int)type*SCALE;
1543 /*shall we move Clockwise and Fast*/
1544 if((rb->rand()%100)>75)
1546 asteroid->speed_cos = FAST_ROT_CW_COS;
1547 asteroid->speed_sin = FAST_ROT_CW_SIN;
1549 else if((rb->rand()%100)>75)
1551 asteroid->speed_cos = FAST_ROT_ACW_COS;
1552 asteroid->speed_sin = FAST_ROT_ACW_SIN;
1554 else if((rb->rand()%100)>75)
1556 asteroid->speed_cos = SLOW_ROT_ACW_COS;
1557 asteroid->speed_sin = SLOW_ROT_ACW_SIN;
1559 else
1561 asteroid->speed_cos = SLOW_ROT_CW_COS;
1562 asteroid->speed_sin = SLOW_ROT_CW_SIN;
1565 b = (rb->rand()%100)>66;
1566 b2 = (rb->rand()%100)>66;
1567 point = asteroid->vertices;
1568 for(n = 0; n < NUM_ASTEROID_VERTICES*2; n+=2)
1570 if(b)
1572 point->x = asteroid_one[n];
1573 point->y = asteroid_one[n+1];
1575 else if( b2 )
1577 point->x = asteroid_two[n];
1578 point->y = asteroid_two[n+1];
1580 else
1582 point->x = asteroid_three[n];
1583 point->y = asteroid_three[n+1];
1586 point->x *= asteroid->radius/6;
1587 point->y *= asteroid->radius/6;
1588 point++;
1592 asteroid->radius += 6*SCALE;
1593 if(asteroid->type == SMALL)
1594 asteroid->radius /= 3;/*2*/
1595 else if(asteroid->type == LARGE)
1596 asteroid->radius += 3*SCALE;/*2*/
1597 b = true;
1598 while(b)
1600 /*Set the position randomly:*/
1601 asteroid->position.x = (rb->rand()%SCALED_WIDTH);
1602 asteroid->position.y = (rb->rand()%SCALED_HEIGHT);
1604 asteroid->position.dx = 0;
1605 while(asteroid->position.dx == 0)
1606 asteroid->position.dx = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1608 asteroid->position.dy = 0;
1609 while(asteroid->position.dy == 0)
1610 asteroid->position.dy = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1612 asteroid->position.dx *= SCALE/10;
1613 asteroid->position.dy *= SCALE/10;
1615 b = is_point_within_rectangle(&ship.position, &asteroid->position,
1616 space_check_size);
1619 /*Now rotate the asteroid a bit, so they all look a bit different*/
1620 for(n=(rb->rand()%30) + 2;--n;)
1621 rotate_asteroid(asteroid);
1623 /*great, we've created an asteroid, don't forget to increment the total:*/
1624 asteroid_count++;
1627 /*Initialise the ship*/
1628 void initialise_ship(void)
1630 struct Point* point;
1631 struct Point* lives_point;
1632 int n;
1634 ship.position.x = CENTER_LCD_X;
1635 ship.position.y = CENTER_LCD_Y;
1636 ship.position.x *= SCALE;
1637 ship.position.y *= SCALE;
1638 ship.position.dx = ship.position.dy = 0;
1639 ship.spawn_time = SPAWN_TIME;
1640 ship.invulnerable = 1;
1642 point = ship.vertices;
1643 lives_point = lives_points;
1644 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1646 point->x = ship_vertices[n];
1647 point->y = ship_vertices[n+1];
1648 point->x *= SCALE;
1649 point->y *= SCALE;
1650 point++;
1651 lives_point++;
1654 ship.position.dx = 0;
1655 ship.position.dy = 0;
1656 ship.explode_countdown = 0;
1658 /*grab a copy of the ships points for the lives display:*/
1659 point = ship.vertices;
1660 lives_point = lives_points;
1661 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1663 lives_point->x = point->x;
1664 lives_point->y = point->y;
1665 lives_point++;
1666 point++;
1670 void rotate_asteroid(struct Asteroid* asteroid)
1672 struct Point* point;
1673 int n;
1674 long xtemp;
1676 point = asteroid->vertices;
1677 for(n = NUM_ASTEROID_VERTICES+1; --n;)
1679 xtemp = point->x;
1680 point->x = xtemp*asteroid->speed_cos/SIN_COS_SCALE -
1681 point->y*asteroid->speed_sin/SIN_COS_SCALE;
1682 point->y = point->y*asteroid->speed_cos/SIN_COS_SCALE +
1683 xtemp*asteroid->speed_sin/SIN_COS_SCALE;
1684 point++;
1688 /*************************************************
1689 ** Draws the ship, moves the ship and creates a new
1690 ** one if it's finished exploding.
1691 **************************************************/
1692 void draw_and_move_ship(void)
1694 int nxoffset = ship.position.x/SCALE;
1695 int nyoffset = ship.position.y/SCALE;
1696 if (ship.invulnerable && (ship.spawn_time > BLINK_TIME || ship.spawn_time % 2 == 0))
1698 SET_FG(COL_INVULN);
1700 else
1702 SET_FG(COL_PLAYER);
1704 if(!ship.explode_countdown)
1706 /* make sure ship is invulnerable until spawn time over */
1707 if (ship.spawn_time)
1709 ship.spawn_time--;
1710 if (ship.spawn_time <= 0)
1712 ship.invulnerable = 0;
1715 if(!ship.waiting_for_space)
1717 draw_polygon(ship.vertices, nxoffset, nyoffset, NUM_SHIP_VERTICES);
1718 if(game_state != PAUSE_MODE && game_state != GAME_OVER)
1720 move_point(&ship.position);
1724 else
1726 /* animate_and_draw_explosion(ship.vertices, NUM_SHIP_VERTICES,
1727 ship.position.x/SCALE,
1728 ship.position.y/SCALE); */
1729 if(game_state != PAUSE_MODE)
1731 ship.explode_countdown--;
1732 if(!ship.explode_countdown)
1734 num_lives--;
1735 if(!num_lives)
1737 game_state = GAME_OVER;
1739 else
1741 initialise_ship();
1742 ship.waiting_for_space = true;
1749 void thrust_ship(void)
1751 if(!ship.waiting_for_space)
1753 ship.position.dx += ( ship.vertices[0].x - ship.vertices[2].x )/20;
1754 ship.position.dy += ( ship.vertices[0].y - ship.vertices[2].y )/20;
1755 /*if dx and dy are below a certain threshold, then set 'em to 0
1756 but to do this we need to ascertain if the spacehip as moved on screen
1757 for more than a certain amount. */
1759 create_trail_blaze(THRUST_COLOUR, &ship.position);
1763 /**************************************************
1764 ** Rotate the ship using the passed sin & cos values
1765 ***************************************************/
1766 void rotate_ship(int c, int s)
1768 struct Point* point;
1769 int n;
1770 double xtemp;
1772 if(!ship.waiting_for_space && !ship.explode_countdown)
1774 point = ship.vertices;
1775 for(n=NUM_SHIP_VERTICES+1;--n;)
1777 xtemp = point->x;
1778 point->x = xtemp*c/SIN_COS_SCALE - point->y*s/SIN_COS_SCALE;
1779 point->y = point->y*c/SIN_COS_SCALE + xtemp*s/SIN_COS_SCALE;
1780 point++;
1785 void drawstars()
1787 struct Point* p;
1788 int n = NUM_STARS;
1790 p = stars;
1791 SET_FG(COL_STARS);
1793 while(--n)
1795 rb->lcd_drawpixel(p->x , p->y);
1796 p++;
1800 /*************************************************
1801 ** Draw And Move all Asteroids
1802 *************************************************/
1803 void draw_and_move_asteroids(void)
1805 int n;
1806 struct Asteroid* asteroid;
1808 asteroid = asteroids_array;
1809 SET_FG(COL_ASTEROID);
1811 n = MAX_NUM_ASTEROIDS;
1812 while(--n)
1814 if(game_state != PAUSE_MODE)
1816 if(asteroid->exists)
1818 move_point(&asteroid->position);
1819 rotate_asteroid(asteroid);
1820 draw_polygon(asteroid->vertices, asteroid->position.x/SCALE,
1821 asteroid->position.y/SCALE,
1822 NUM_ASTEROID_VERTICES);
1824 else if(asteroid->explode_countdown)
1826 /* animate_and_draw_explosion(asteroid->vertices,
1827 NUM_ASTEROID_VERTICES,
1828 asteroid->position.x/SCALE,
1829 asteroid->position.y/SCALE); */
1830 asteroid->explode_countdown--;
1833 else
1835 if(asteroid->exists)
1836 draw_polygon(asteroid->vertices,
1837 asteroid->position.x/SCALE,
1838 asteroid->position.y/SCALE,
1839 NUM_ASTEROID_VERTICES);
1841 asteroid++;
1845 void create_stars(void)
1847 struct TrailPoint* tpoint;
1848 struct Point* p;
1849 int n;
1851 p = stars;
1852 n = NUM_STARS;
1853 while(--n)
1855 p->x = (rb->rand()%LCD_WIDTH);
1856 p->y = (rb->rand()%LCD_HEIGHT);
1857 p++;
1861 /* give the point a random countdown timer, so they dissapears at different
1862 times */
1863 tpoint = trailPoints;
1864 n = NUM_TRAIL_POINTS;
1865 while(--n)
1867 tpoint->alive = 0;
1868 tpoint++;
1872 /*************************************************
1873 ** Creates start_num number of new asteroids of
1874 ** full size.
1875 **************************************************/
1876 void initialise_game(int start_num)
1878 int n;
1879 asteroid_count = next_missile_count = next_thrust_count = 0;
1880 struct Asteroid* asteroid;
1881 struct Missile* missile;
1882 extra_life = EXTRA_LIFE;
1884 /*no enemy*/
1885 enemy_on_screen = 0;
1886 enemy_missile.survived = 0;
1888 /*clear asteroids*/
1889 asteroid = asteroids_array;
1890 n = MAX_NUM_ASTEROIDS;
1891 while(--n)
1893 asteroid->exists = false;
1894 asteroid++;
1897 /*make some LARGE asteroids*/
1898 for(n = 0; n < start_num; n++)
1899 initialise_asteroid(&asteroids_array[n], LARGE);
1901 /*ensure all missiles are out of action: */
1902 missile = missiles_array;
1903 n = MAX_NUM_MISSILES;
1904 while(--n)
1906 missile->survived=0;
1907 missile++;
1911 static int spacerocks_game_loop(void)
1913 char s[20];
1914 char level[10];
1915 int button;
1916 int end;
1917 int position;
1919 /*create stars once, and once only:*/
1920 create_stars();
1922 if (spacerocks_menu(false)!=0)
1923 return 0;
1925 SET_BG(LCD_BLACK);
1927 while(true)
1929 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1930 rb->lcd_clear_display();
1931 SET_FG(COL_TEXT);
1932 switch(game_state) {
1933 case(GAME_OVER):
1934 rb->splash (HZ * 2, "Game Over");
1935 rb->lcd_clear_display();
1936 position=highscore_update(current_score, current_level, "",
1937 highest,NUM_SCORES);
1938 if (position == 0)
1939 rb->splash(HZ*2, "New High Score");
1940 if (position != -1)
1941 highscore_show(position, highest, NUM_SCORES, true);
1942 if (spacerocks_menu(false)!=0)
1943 return 0;
1944 break;
1946 case(PAUSE_MODE):
1947 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1948 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1949 rb->lcd_putsxy(CENTER_LCD_X - 15,
1950 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "pause");
1951 draw_and_move_missiles();
1952 draw_lives();
1953 draw_and_move_ship();
1954 break;
1956 case(PLAY_MODE):
1957 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1958 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1959 draw_and_move_missiles();
1960 draw_lives();
1961 check_collisions();
1962 draw_and_move_ship();
1963 break;
1965 case(SHOW_LEVEL):
1966 show_level_timeout--;
1967 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1968 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1969 rb->snprintf(level, sizeof(level), "stage %d ", current_level);
1970 rb->lcd_putsxy(CENTER_LCD_X - 20,
1971 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, level);
1972 draw_and_move_ship();
1973 draw_lives();
1974 if(!show_level_timeout) {
1975 initialise_game(current_level);
1976 game_state = PLAY_MODE;
1977 draw_lives();
1979 break;
1981 draw_trail_blaze();
1982 drawstars();
1983 draw_and_move_asteroids();
1984 draw_and_move_enemy();
1986 rb->lcd_update();
1988 #ifdef HAS_BUTTON_HOLD
1989 if (rb->button_hold())
1990 game_state = PAUSE_MODE;
1992 #endif
1993 button = rb->button_get(false);
1994 switch(button) {
1995 case(AST_QUIT):
1996 if (spacerocks_menu(true)!=0)
1997 return 0;
1998 break;
1999 #ifdef AST_PAUSE
2000 case(AST_PAUSE):
2001 if (game_state == PAUSE_MODE) {
2002 game_state = PLAY_MODE;
2003 break;
2005 else if (game_state != PLAY_MODE)
2006 break;
2007 #endif
2008 case (AST_LEFT):
2009 case (AST_LEFT | BUTTON_REPEAT):
2010 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
2011 rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN);
2012 break;
2014 case (AST_RIGHT):
2015 case (AST_RIGHT | BUTTON_REPEAT):
2016 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
2017 rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN);
2018 break;
2020 case (AST_THRUST):
2021 case (AST_THRUST | BUTTON_REPEAT):
2022 if((game_state == PLAY_MODE || game_state == SHOW_LEVEL) &&
2023 !next_thrust_count) {
2024 thrust_ship();
2025 next_thrust_count = 5;
2027 break;
2029 case (AST_HYPERSPACE):
2030 if(game_state == PLAY_MODE)
2031 hyperspace();
2032 /*maybe shield if it gets too hard */
2033 break;
2035 case (AST_FIRE):
2036 case (AST_FIRE | BUTTON_REPEAT):
2037 if(game_state == PLAY_MODE) {
2038 if(!next_missile_count) {
2039 fire_missile();
2040 next_missile_count = 10;
2043 else if(game_state == PAUSE_MODE) {
2044 game_state = PLAY_MODE;
2046 break;
2048 default:
2049 if (rb->default_event_handler(button)==SYS_USB_CONNECTED)
2050 return PLUGIN_USB_CONNECTED;
2051 break;
2054 if(next_missile_count)
2055 next_missile_count--;
2057 if(next_thrust_count)
2058 next_thrust_count--;
2060 if (end > *rb->current_tick)
2061 rb->sleep(end-*rb->current_tick);
2062 else
2063 rb->yield();
2067 enum plugin_status plugin_start(const void* parameter)
2069 (void)parameter;
2071 #if LCD_DEPTH > 1
2072 rb->lcd_set_backdrop(NULL);
2073 #endif
2074 /* universal font */
2075 rb->lcd_setfont(FONT_SYSFIXED);
2076 /* Turn off backlight timeout */
2077 backlight_force_on(); /* backlight control in lib/helper.c */
2078 highscore_load(HIGH_SCORE,highest,NUM_SCORES);
2079 spacerocks_game_loop();
2080 rb->lcd_setfont(FONT_UI);
2081 highscore_save(HIGH_SCORE,highest,NUM_SCORES);
2082 /* Turn on backlight timeout (revert to settings) */
2083 backlight_use_settings(); /* backlight control in lib/helper.c */
2085 return PLUGIN_OK;