calendar: fix bug when add new event text longer than last entry.
[kugel-rb.git] / apps / plugins / spacerocks.c
blob2e383c0d0d8235080bc09d0f70bda5b8a884ceb4
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 #else
204 #error No keymap defined!
205 #endif
207 #ifdef HAVE_TOUCHSCREEN
208 #ifndef AST_PAUSE
209 #define AST_PAUSE BUTTON_CENTER
210 #endif
211 #ifndef AST_QUIT
212 #define AST_QUIT BUTTON_TOPLEFT
213 #endif
214 #ifndef AST_THRUST_REP
215 #define AST_THRUST_REP (BUTTON_TOPMIDDLE | BUTTON_REPEAT)
216 #endif
217 #ifndef AST_THRUST
218 #define AST_THRUST BUTTON_TOPMIDDLE
219 #endif
220 #ifndef AST_HYPERSPACE
221 #define AST_HYPERSPACE BUTTON_TOPRIGHT
222 #endif
223 #ifndef AST_LEFT
224 #define AST_LEFT BUTTON_MIDLEFT
225 #endif
226 #ifndef AST_LEFT_REP
227 #define AST_LEFT_REP (BUTTON_MIDLEFT | BUTTON_REPEAT)
228 #endif
229 #ifndef AST_RIGHT
230 #define AST_RIGHT BUTTON_MIDRIGHT
231 #endif
232 #ifndef AST_RIGHT_REP
233 #define AST_RIGHT_REP (BUTTON_MIDRIGHT | BUTTON_REPEAT)
234 #endif
235 #ifndef AST_FIRE
236 #define AST_FIRE BUTTON_BOTTOMMIDDLE
237 #endif
238 #ifndef AST_FIRE_REP
240 #ifdef BUTTON_MENU
241 #define AST_FIRE_REP (BUTTON_BOTTOMMIDDLE | BUTTON_MENU)
242 #else
243 #define AST_FIRE_REP BUTTON_BOTTOMMIDDLE | BUTTON_REPEAT
244 #endif
246 #endif
247 #endif
249 #define RES MAX(LCD_WIDTH, LCD_HEIGHT)
250 #define LARGE_LCD RES >= 200
251 #define ENEMY_MISSILE_SURVIVAL_LENGTH RES/2
252 #define ASTEROID_SPEED RES/20
253 #define MISSILE_SURVIVAL_LENGTH 40
255 #define CYCLETIME 30
257 #define EXTRA_LIFE 250
258 #define SPAWN_TIME 30
259 #define BLINK_TIME 10
260 #define SCALE 5000
261 #define MISSILE_SCALE 5000
262 #define WRAP_GAP 12
263 #define EXPLOSION_LENGTH 20
264 #define SHOW_COL 0
265 #define POINT_SIZE 2
266 #define MAX_NUM_ASTEROIDS 25
267 #define MAX_NUM_MISSILES 6
268 #define ENEMY_BIG_PROBABILITY_START 10
269 #define ENEMY_APPEAR_PROBABILITY_START 35
270 #define ENEMY_APPEAR_TIMING_START 1800
271 #define LITTLE_SHIP 2
272 #define BIG_SHIP 1
273 #define SHOW_GAME_OVER_TIME 100
274 #define SHOW_LEVEL_TIME 50
275 #define START_LIVES 3
276 #define START_LEVEL 1
277 #define NUM_ASTEROID_VERTICES 10
278 #define NUM_SHIP_VERTICES 4
279 #define NUM_ENEMY_VERTICES 6
280 #define MAX_LEVEL MAX_NUM_ASTEROIDS
281 #define ENEMY_SPEED 4
282 #define SIZE_ENEMY_COLLISION 5*SCALE
283 #define NUM_STARS 50
284 #define NUM_TRAIL_POINTS 70
285 #define NUM_ROTATIONS 16
287 #define SIN_COS_SCALE 10000
289 #define FAST_ROT_CW_SIN 873
290 #define FAST_ROT_CW_COS 9963
291 #define FAST_ROT_ACW_SIN -873
292 #define FAST_ROT_ACW_COS 9963
294 #define MEDIUM_ROT_CW_SIN 350
295 #define MEDIUM_ROT_CW_COS 9994
296 #define MEDIUM_ROT_ACW_SIN -350
297 #define MEDIUM_ROT_ACW_COS 9994
299 #define SLOW_ROT_CW_SIN 350
300 #define SLOW_ROT_CW_COS 9994
301 #define SLOW_ROT_ACW_SIN - 350
302 #define SLOW_ROT_ACW_COS 9994
304 #ifdef HAVE_LCD_COLOR
305 #define SHIP_ROT_CW_SIN 2419
306 #define SHIP_ROT_CW_COS 9702
307 #define SHIP_ROT_ACW_SIN -2419
308 #define SHIP_ROT_ACW_COS 9702
309 #else
310 #define SHIP_ROT_CW_SIN 3827
311 #define SHIP_ROT_CW_COS 9239
312 #define SHIP_ROT_ACW_SIN -3827
313 #define SHIP_ROT_ACW_COS 9239
314 #endif
317 #define SCALED_WIDTH (LCD_WIDTH*SCALE)
318 #define SCALED_HEIGHT (LCD_HEIGHT*SCALE)
319 #define CENTER_LCD_X (LCD_WIDTH/2)
320 #define CENTER_LCD_Y (LCD_HEIGHT/2)
322 #define SHIP_EXPLOSION_COLOUR 1
323 #define ASTEROID_EXPLOSION_COLOUR 2
324 #define ENEMY_EXPLOSION_COLOUR 3
325 #define THRUST_COLOUR 4
327 #define ASTEROID_R 230
328 #define ASTEROID_G 200
329 #define ASTEROID_B 100
330 #define SHIP_R 255
331 #define SHIP_G 255
332 #define SHIP_B 255
333 #define ENEMY_R 50
334 #define ENEMY_G 220
335 #define ENEMY_B 50
336 #define THRUST_R 200
337 #define THRUST_G 200
338 #define THRUST_B 0
340 #ifdef HAVE_LCD_COLOR
341 #define COL_MISSILE LCD_RGBPACK(200,0,0)
342 #define COL_PLAYER LCD_RGBPACK(200,200,200)
343 #define COL_INVULN LCD_RGBPACK(100,100,200)
344 #define COL_STARS LCD_WHITE
345 #define COL_ASTEROID LCD_RGBPACK(ASTEROID_R,ASTEROID_G,ASTEROID_B)
346 #define COL_TEXT LCD_RGBPACK(200,200,255)
347 #define COL_ENEMY LCD_RGBPACK(ENEMY_R,ENEMY_G,ENEMY_B)
348 #define SET_FG rb->lcd_set_foreground
349 #define SET_BG rb->lcd_set_background
350 #else
351 #define SET_FG(x)
352 #define SET_BG(x)
353 #endif
355 #define MARGIN 5
357 #define HIGH_SCORE PLUGIN_GAMES_DIR "/spacerocks.score"
358 #define NUM_SCORES 5
360 struct highscore highest[NUM_SCORES];
362 /* The array of points that make up an asteroid */
363 static const short asteroid_one[NUM_ASTEROID_VERTICES*2] =
365 -2, -12,
366 4, -8,
367 8, -14,
368 16, -5,
369 14, 0,
370 20, 2,
371 12, 14,
372 -4, 14,
373 -10, 6,
374 -10, -8
377 /* The array of points that make up an asteroid */
378 static const short asteroid_two[NUM_ASTEROID_VERTICES*2] =
380 -2, -12,
381 4, -16,
382 6, -14,
383 16, -8,
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_three[NUM_ASTEROID_VERTICES*2] =
395 -2, -12,
396 4, -16,
397 6, -14,
398 2, -8,
399 14, 0,
400 20, 2,
401 12, 14,
402 -4, 14,
403 -16, 6,
404 -10, -8
407 /* The array od points the make up the ship */
408 static const short ship_vertices[NUM_SHIP_VERTICES*2] =
410 #if(LARGE_LCD)
411 0,-6,
412 4, 6,
413 0, 2,
414 -4, 6
415 #else
416 0,-4,
417 3, 4,
418 0, 1,
419 -3, 4
420 #endif
423 /* The array of points the make up the bad spaceship */
424 static const short enemy_vertices[NUM_ENEMY_VERTICES*2] =
426 #if(LARGE_LCD)
427 -8, 0,
428 -4, 4,
429 4, 4,
430 8, 0,
431 4, -4,
432 -4, -4
433 #else
434 -5, 0,
435 -2, 2,
436 2, 2,
437 5, 0,
438 2, -2,
439 -2, -2
440 #endif
444 enum asteroid_type
446 #if(LARGE_LCD)
447 SMALL = 2,
448 MEDIUM = 4,
449 LARGE = 6,
450 #else
451 SMALL = 1,
452 MEDIUM = 2,
453 LARGE = 3,
454 #endif
458 enum game_state
460 GAME_OVER,
461 SHOW_LEVEL,
462 PLAY_MODE,
463 PAUSE_MODE
466 struct Point
468 int x;
469 int y;
470 int dx;
471 int dy;
474 struct TrailPoint
476 int alive;
477 struct Point position;
478 short r;
479 short g;
480 short b;
481 short dec;
484 /* Asteroid structure, contains an array of points */
485 struct Asteroid
487 enum asteroid_type type;
488 bool exists;
489 struct Point position;
490 struct Point vertices[NUM_ASTEROID_VERTICES];
491 int radius;
492 long speed_cos;
493 long speed_sin;
494 int explode_countdown;
497 struct Ship
499 struct Point vertices[NUM_SHIP_VERTICES];
500 struct Point position;
501 bool waiting_for_space;
502 bool invulnerable;
503 int spawn_time;
504 int explode_countdown;
507 struct Enemy
509 struct Point vertices[NUM_ENEMY_VERTICES];
510 struct Point position;
511 int explode_countdown;
512 long last_time_appeared;
513 short size_probability;
514 short appear_probability;
515 short appear_timing;
518 struct Missile
520 struct Point position;
521 struct Point oldpoint;
522 int survived;
525 static enum game_state game_state;
526 static int asteroid_count;
527 static int next_missile_count;
528 static int next_thrust_count;
529 static int num_lives;
530 static int extra_life;
531 static int show_level_timeout;
532 static int current_level;
533 static int current_score;
534 static int space_check_size = 30*SCALE;
536 static bool enemy_on_screen;
537 static struct Ship ship;
538 static struct Point stars[NUM_STARS];
539 static struct Asteroid asteroids_array[MAX_NUM_ASTEROIDS];
540 static struct Missile missiles_array[MAX_NUM_MISSILES];
541 static struct Missile enemy_missile;
542 static struct Enemy enemy;
543 static struct Point lives_points[NUM_SHIP_VERTICES];
544 static struct TrailPoint trailPoints[NUM_TRAIL_POINTS];
546 void draw_and_move_asteroids(void);
547 void initialise_game(int nStartNum);
549 bool is_asteroid_near_ship(struct Asteroid* asteroid);
550 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point);
552 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type eType);
553 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices);
554 void rotate_asteroid(struct Asteroid* asteroid);
555 void create_asteroid(enum asteroid_type type, int x, int y);
556 void create_stars(void);
558 void initialise_ship(void);
559 void draw_and_move_ship(void);
560 void rotate_ship(int s, int c);
561 void thrust_ship(void);
563 void initialise_missile(struct Missile* missile);
564 void draw_and_move_missiles(void);
565 void fire_missile(void);
567 void animate_and_draw_explosion(struct Point* point, int num_points, int xoffset, int yoffset);
568 void initialise_explosion(struct Point* point, int num_points);
570 void move_point(struct Point* point);
571 void hyperspace(void);
572 void check_collisions(void);
573 void initialise_enemy(void);
574 void draw_and_move_enemy(void);
575 void draw_lives(void);
576 void drawstars(void);
577 bool is_ship_within_asteroid(struct Asteroid* asteroid);
580 void init(void)
582 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
583 enemy.appear_timing = ENEMY_APPEAR_TIMING_START;
584 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
585 current_level = START_LEVEL;
586 num_lives = START_LIVES;
587 current_score = 0;
588 initialise_ship();
589 initialise_game(current_level);
590 show_level_timeout = SHOW_LEVEL_TIME;
591 game_state = PLAY_MODE;
594 static bool spacerocks_help(void)
596 rb->lcd_setfont(FONT_UI);
597 #define WORDS (sizeof help_text / sizeof (char*))
598 static char *help_text[] = {
599 "Spacerocks", "", "Aim", "", "The", "goal", "of", "the", "game", "is",
600 "to", "blow", "up", "the", "asteroids", "and", "avoid", "being", "hit", "by",
601 "them.", "Also", "you'd", "better", "watch", "out", "for", "the", "UFOs!"
603 static struct style_text formation[]={
604 { 0, TEXT_CENTER|TEXT_UNDERLINE },
605 { 2, C_RED },
606 { -1, 0 }
608 #ifdef HAVE_LCD_COLOR
609 rb->lcd_set_background(LCD_BLACK);
610 rb->lcd_set_foreground(LCD_WHITE);
611 #endif
612 int button;
613 if (display_text(WORDS, help_text, formation, NULL)==PLUGIN_USB_CONNECTED)
614 return true;
615 do {
616 button = rb->button_get(true);
617 if (button == SYS_USB_CONNECTED) {
618 return true;
620 } while( ( button == BUTTON_NONE )
621 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
622 rb->lcd_setfont(FONT_SYSFIXED);
624 return false;
627 static bool _ingame;
628 static int spacerocks_menu_cb(int action, const struct menu_item_ex *this_item)
630 if(action == ACTION_REQUEST_MENUITEM
631 && !_ingame && ((intptr_t)this_item)==0)
632 return ACTION_EXIT_MENUITEM;
633 return action;
636 static int spacerocks_menu(bool ingame)
638 rb->button_clear_queue();
639 int choice = 0;
641 _ingame = ingame;
643 MENUITEM_STRINGLIST (main_menu, "Spacerocks Menu", spacerocks_menu_cb,
644 "Resume Game",
645 "Start New Game",
646 "Help",
647 "High Scores",
648 "Playback Control",
649 "Quit");
651 while (1) {
652 choice = rb->do_menu(&main_menu, &choice, NULL, false);
653 switch (choice) {
654 case 0:
655 return 0;
656 case 1:
657 init();
658 return 0;
659 case 2:
660 if(spacerocks_help())
661 return 1;
662 break;
663 case 3:
664 highscore_show(NUM_SCORES, highest, NUM_SCORES, true);
665 break;
666 case 4:
667 playback_control(NULL);
668 break;
669 case 5:
670 return 1;
671 case MENU_ATTACHED_USB:
672 return 1;
673 default:
674 break;
679 bool point_in_poly(struct Point* _point, int num_vertices, int x, int y)
681 struct Point* pi;
682 struct Point* pj;
683 int n;
684 bool c = false;
686 pi = _point;
687 pj = _point;
688 pj += num_vertices-1;
690 n = num_vertices;
691 while(n--)
693 if((((pi->y <= y) && (y < pj->y)) || ((pj->y <= y) && (y < pi->y))) &&
694 (x < (pj->x - pi->x) * (y - pi->y) / (pj->y - pi->y) + pi->x))
695 c = !c;
697 if(n == num_vertices - 1)
698 pj = _point;
699 else
700 pj++;
702 pi++;
705 return c;
708 void move_point(struct Point* point)
710 point->x += point->dx;
711 point->y += point->dy;
713 /*check bounds on the x-axis:*/
714 if(point->x >= SCALED_WIDTH)
715 point->x = 0;
716 else if(point->x <= 0)
717 point->x = SCALED_WIDTH;
719 /*Check bounds on the y-axis:*/
720 if(point->y >= SCALED_HEIGHT)
721 point->y = 0;
722 else if(point->y <= 0)
723 point->y = SCALED_HEIGHT;
726 void create_trail(struct TrailPoint* tpoint)
728 tpoint->position.dx = -( ship.vertices[0].x - ship.vertices[2].x )/10;
729 tpoint->position.dy = -( ship.vertices[0].y - ship.vertices[2].y )/10;
732 void create_explosion_trail(struct TrailPoint* tpoint)
734 tpoint->position.dx = (rb->rand()%5050)-2500;
735 tpoint->position.dy = (rb->rand()%5050)-2500;
738 void create_trail_blaze(int colour, struct Point* position)
740 int numtoadd;
741 struct TrailPoint* tpoint;
742 int n;
743 int xadd,yadd;
744 if(colour != SHIP_EXPLOSION_COLOUR)
746 numtoadd = NUM_TRAIL_POINTS/5;
747 xadd = position->x;
748 yadd = position->y;
750 else
752 numtoadd = NUM_TRAIL_POINTS/8;
753 xadd = ship.position.x;
754 yadd = ship.position.y;
757 /* give the point a random countdown timer, so they dissapears at different times */
758 tpoint = trailPoints;
759 n = NUM_TRAIL_POINTS;
760 while(--n)
762 if(tpoint->alive <= 0 && numtoadd)
764 numtoadd--;
765 /* take a random x point anywhere between bottom two points of ship. */
766 /* ship.position.x; */
767 tpoint->position.x = (ship.vertices[2].x + (rb->rand()%18000)-9000) + position->x;
768 tpoint->position.y = (ship.vertices[2].y + (rb->rand()%18000)-9000) + position->y;
770 switch(colour)
772 case SHIP_EXPLOSION_COLOUR:
773 tpoint->r = 255;
774 tpoint->g = 255;
775 tpoint->b = 255;
776 create_explosion_trail(tpoint);
777 tpoint->alive = 510;
778 tpoint->dec = 2;
779 break;
780 case ASTEROID_EXPLOSION_COLOUR:
781 tpoint->r = ASTEROID_R;
782 tpoint->g = ASTEROID_G;
783 tpoint->b = ASTEROID_B;
784 create_explosion_trail(tpoint);
785 tpoint->alive = 510;
786 tpoint->dec = 2;
787 break;
788 case ENEMY_EXPLOSION_COLOUR:
789 tpoint->r = ENEMY_R;
790 tpoint->g = ENEMY_G;
791 tpoint->b = ENEMY_B;
792 create_explosion_trail(tpoint);
793 tpoint->alive = 510;
794 tpoint->dec = 2;
795 break;
796 case THRUST_COLOUR:
797 tpoint->r = THRUST_R;
798 tpoint->g = THRUST_G;
799 tpoint->b = THRUST_B;
800 create_trail(tpoint);
801 tpoint->alive = 175;
802 tpoint->dec = 4;
803 break;
805 /* add a proportional bit to the x and y based on dx and dy */
807 /* give the points a speed based on direction of travel - i.e. opposite */
808 tpoint->position.dx += position->dx;
809 tpoint->position.dy += position->dy;
813 tpoint++;
815 /* find a space in the array of trail_points that is NULL or DEAD or whatever.
816 and place this one here. */
820 void draw_trail_blaze(void)
822 struct TrailPoint* tpoint;
823 /* loop through, if alive then move and draw.
824 when drawn, countdown it's timer.
825 if zero kill it! */
826 tpoint = trailPoints;
827 int n = NUM_TRAIL_POINTS;
829 while(--n)
831 if(tpoint->alive)
833 if(game_state != PAUSE_MODE)
835 tpoint->alive-=10;
836 move_point(&(tpoint->position));
838 #ifdef HAVE_LCD_COLOR
839 /* intensity = tpoint->alive/2; */
840 if(tpoint->r>0)tpoint->r-=tpoint->dec;
841 if(tpoint->g>0)tpoint->g-=tpoint->dec;
842 if(tpoint->b>0)tpoint->b-=tpoint->dec;
843 SET_FG(LCD_RGBPACK(tpoint->r, tpoint->g, tpoint->b));
844 #endif
845 rb->lcd_drawpixel(tpoint->position.x/SCALE , tpoint->position.y/SCALE);
847 tpoint++;
851 /*Check if point is within a rectangle*/
852 bool is_point_within_rectangle(struct Point* rect, struct Point* p, int size)
854 #if SHOW_COL
855 int aTLx = rect->x - size;
856 int aTLy = rect->y - size;
857 int aBRx = rect->x + size;
858 int aBRy = rect->y + size;
859 rb->lcd_hline( aTLx/SCALE, aBRx/SCALE, aTLy/SCALE);
860 rb->lcd_vline( aTLx/SCALE, aTLy/SCALE, aBRy/SCALE);
861 rb->lcd_hline( aTLx/SCALE, aBRx/SCALE, aBRy/SCALE);
862 rb->lcd_vline( aBRx/SCALE, aBRy/SCALE, aTLy/SCALE);
863 return (p->x > aTLx && p->x < aBRx && p->y > aTLy && p->y < aBRy);
864 #else
865 return (p->x > rect->x - size && p->x < rect->x + size &&
866 p->y > rect->y - size && p->y < rect->y + size);
867 #endif
870 /* Draw polygon */
871 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices)
873 int n, t1, t2, oldX, oldY;
874 struct Point *p;
875 bool bDrawAll = px < WRAP_GAP || LCD_WIDTH - px < WRAP_GAP ||
876 py < WRAP_GAP || LCD_HEIGHT - py < WRAP_GAP;
878 p = vertices;
879 p += num_vertices-1;
880 oldX = p->x/SCALE + px;
881 oldY = p->y/SCALE + py;
882 p = vertices;
883 for(n = num_vertices+1; --n;)
885 t1 = p->x/SCALE + px;
886 t2 = p->y/SCALE + py;
888 rb->lcd_drawline(oldX, oldY, t1, t2);
890 if(bDrawAll)
892 rb->lcd_drawline(oldX - LCD_WIDTH, oldY, t1 - LCD_WIDTH, t2);
893 rb->lcd_drawline(oldX + LCD_WIDTH, oldY, t1 + LCD_WIDTH, t2);
894 rb->lcd_drawline(oldX - LCD_WIDTH, oldY + LCD_HEIGHT,
895 t1 - LCD_WIDTH, t2 + LCD_HEIGHT);
896 rb->lcd_drawline(oldX + LCD_WIDTH, oldY + LCD_HEIGHT,
897 t1 + LCD_WIDTH, t2 + LCD_HEIGHT);
899 rb->lcd_drawline(oldX, oldY - LCD_HEIGHT, t1, t2 - LCD_HEIGHT);
900 rb->lcd_drawline(oldX, oldY + LCD_HEIGHT, t1, t2 + LCD_HEIGHT);
901 rb->lcd_drawline(oldX - LCD_WIDTH, oldY - LCD_HEIGHT,
902 t1 - LCD_WIDTH, t2 - LCD_HEIGHT);
903 rb->lcd_drawline(oldX + LCD_WIDTH, oldY - LCD_HEIGHT,
904 t1 + LCD_WIDTH, t2 - LCD_HEIGHT);
906 oldX = t1;
907 oldY = t2;
908 p++;
912 void animate_and_draw_explosion(struct Point* point, int num_points,
913 int xoffset, int yoffset)
915 int n;
916 for(n = num_points; --n;)
918 if(game_state != PAUSE_MODE)
920 point->x += point->dx;
921 point->y += point->dy;
923 rb->lcd_fillrect( point->x/SCALE + xoffset, point->y/SCALE + yoffset,
924 POINT_SIZE, POINT_SIZE);
925 point++;
929 /*stop movement of ship, 'cos that's what happens when you go into hyperspace.*/
930 void hyperspace(void)
932 ship.position.dx = ship.position.dy = 0;
933 ship.position.x = (rb->rand()%SCALED_WIDTH);
934 ship.position.y = (rb->rand()%SCALED_HEIGHT);
937 void initialise_enemy(void)
939 struct Point* point;
940 int n;
941 int size;
943 if(rb->rand()%100 > enemy.size_probability)
945 size = BIG_SHIP;
946 enemy.size_probability++;
947 if(enemy.size_probability < 90)
949 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
952 else
954 size = LITTLE_SHIP;
957 enemy_missile.survived = 0;
958 enemy_on_screen = true;
959 enemy.explode_countdown = 0;
960 enemy.last_time_appeared = *rb->current_tick;
961 point = enemy.vertices;
962 for(n = 0; n < NUM_ENEMY_VERTICES+NUM_ENEMY_VERTICES; n+=2)
964 point->x = enemy_vertices[n];
965 point->y = enemy_vertices[n+1];
966 point->x *= SCALE/size;
967 point->y *= SCALE/size;
968 point++;
971 if(ship.position.x >= SCALED_WIDTH/2)
973 enemy.position.dx = ENEMY_SPEED;
974 enemy.position.x = 0;
976 else
978 enemy.position.dx = -ENEMY_SPEED;
979 enemy.position.x = SCALED_WIDTH;
982 if(ship.position.y >= SCALED_HEIGHT/2)
984 enemy.position.dy = ENEMY_SPEED;
985 enemy.position.y = 0;
987 else
989 enemy.position.dy = -ENEMY_SPEED;
990 enemy.position.y = SCALED_HEIGHT;
993 enemy.position.dx *= SCALE/10;
994 enemy.position.dy *= SCALE/10;
997 void draw_and_move_enemy(void)
999 int enemy_x, enemy_y;
1000 struct Point *point;
1002 SET_FG(COL_ENEMY);
1004 if(enemy_on_screen)
1006 enemy_x = enemy.position.x/SCALE;
1007 enemy_y = enemy.position.y/SCALE;
1008 if(!enemy.explode_countdown)
1010 point = enemy.vertices;
1011 draw_polygon(enemy.vertices, enemy_x, enemy_y, NUM_ENEMY_VERTICES);
1012 rb->lcd_drawline(enemy.vertices[0].x/SCALE + enemy_x,
1013 enemy.vertices[0].y/SCALE + enemy_y,
1014 enemy.vertices[3].x/SCALE + enemy_x,
1015 enemy.vertices[3].y/SCALE + enemy_y);
1017 if(game_state != PAUSE_MODE)
1019 enemy.position.x += enemy.position.dx;
1020 enemy.position.y += enemy.position.dy;
1023 if(enemy.position.x > SCALED_WIDTH || enemy.position.x < 0)
1024 enemy_on_screen = false;
1026 if(enemy.position.y > SCALED_HEIGHT)
1027 enemy.position.y = 0;
1028 else if(enemy.position.y < 0)
1029 enemy.position.y = SCALED_HEIGHT;
1031 if( (rb->rand()%1000) < 10)
1032 enemy.position.dy = -enemy.position.dy;
1034 else
1037 /* animate_and_draw_explosion(enemy.vertices, NUM_ENEMY_VERTICES,
1038 enemy_x, enemy.position.y/SCALE); */
1039 if(game_state != PAUSE_MODE)
1041 enemy.explode_countdown--;
1042 if(!enemy.explode_countdown)
1043 enemy_on_screen = false;
1047 else
1049 if( (*rb->current_tick - enemy.last_time_appeared) > enemy.appear_timing)
1050 if(rb->rand()%100 > enemy.appear_probability) initialise_enemy();
1053 if(!enemy_missile.survived && game_state != GAME_OVER)
1055 /*if no missile and the enemy is here and not exploding..then shoot baby!*/
1056 if( !enemy.explode_countdown && enemy_on_screen &&
1057 !ship.waiting_for_space && (rb->rand()%10) > 5 )
1059 enemy_missile.position.x = enemy.position.x;
1060 enemy_missile.position.y = enemy.position.y;
1062 /*lame, needs to be sorted - it's trying to shoot at the ship*/
1063 if(ABS(enemy.position.y - ship.position.y) <= 5*SCALE)
1065 enemy_missile.position.dy = 0;
1067 else
1069 if( enemy.position.y < ship.position.y)
1070 enemy_missile.position.dy = 1;
1071 else
1072 enemy_missile.position.dy = -1;
1075 if(ABS(enemy.position.x - ship.position.x) <= 5*SCALE)
1076 enemy_missile.position.dx = 0;
1077 else
1079 if( enemy.position.x < ship.position.x)
1080 enemy_missile.position.dx = 1;
1081 else
1082 enemy_missile.position.dx = -1;
1085 if(enemy_missile.position.dx == 0 &&
1086 enemy_missile.position.dy == 0)
1087 enemy_missile.position.dx = enemy_missile.position.dy = -1;
1089 enemy_missile.position.dx *= SCALE;
1090 enemy_missile.position.dy *= SCALE;
1091 enemy_missile.survived = ENEMY_MISSILE_SURVIVAL_LENGTH;
1095 else
1097 rb->lcd_fillrect( enemy_missile.position.x/SCALE,
1098 enemy_missile.position.y/SCALE,
1099 POINT_SIZE, POINT_SIZE);
1100 if(game_state != PAUSE_MODE)
1102 move_point(&enemy_missile.position);
1103 enemy_missile.survived--;
1108 /******************
1109 * Lame method of collision
1110 * detection. It's checking for collision
1111 * between point and a big rectangle around the asteroid...
1112 *******************/
1113 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point)
1115 if( !is_point_within_rectangle(&asteroid->position, point,
1116 asteroid->radius+4*SCALE) )
1117 return false;
1119 if(point_in_poly(asteroid->vertices, NUM_ASTEROID_VERTICES,
1120 point->x - asteroid->position.x,
1121 point->y - asteroid->position.y))
1123 switch(asteroid->type)
1125 case(SMALL):
1126 asteroid->explode_countdown = EXPLOSION_LENGTH;
1127 create_trail_blaze(ASTEROID_EXPLOSION_COLOUR, &asteroid->position);
1128 break;
1130 case(LARGE):
1131 create_asteroid(MEDIUM, asteroid->position.x,
1132 asteroid->position.y);
1133 create_asteroid(MEDIUM, asteroid->position.x,
1134 asteroid->position.y);
1135 break;
1137 case(MEDIUM):
1138 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1139 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1140 break;
1143 current_score++;
1144 if(current_score > extra_life)
1146 num_lives++;
1147 extra_life = current_score+EXTRA_LIFE;
1149 asteroid_count--;
1150 asteroid->exists = false;
1151 return true;
1153 else
1154 return false;
1157 bool is_point_within_enemy(struct Point* point)
1159 if( is_point_within_rectangle(&enemy.position, point, 7*SCALE) )
1161 current_score += 5;
1162 /*enemy_missile.survived = 0;*/
1163 enemy.explode_countdown = EXPLOSION_LENGTH;
1164 /* initialise_explosion(enemy.vertices, NUM_ENEMY_VERTICES); */
1165 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1166 return true;
1168 else
1169 return false;
1172 bool is_ship_within_asteroid(struct Asteroid* asteroid)
1174 bool hit = false;
1175 struct Point p;
1177 p.x = ship.position.x + ship.vertices[0].x;
1178 p.y = ship.position.y + ship.vertices[0].y;
1179 hit |= is_point_within_asteroid(asteroid, &p);
1181 if(!hit)
1183 p.x = ship.position.x + ship.vertices[1].x;
1184 p.y = ship.position.y + ship.vertices[1].y;
1185 hit |= is_point_within_asteroid(asteroid, &p);
1186 if(!hit)
1188 p.x = ship.position.x + ship.vertices[3].x;
1189 p.y = ship.position.y + ship.vertices[3].y;
1190 hit |= is_point_within_asteroid(asteroid, &p);
1194 return hit;
1197 void initialise_explosion(struct Point* point, int num_points)
1199 int n;
1201 point->x += point->dx;
1202 point->y += point->dy;
1203 for(n = num_points; --n;)
1205 point->dx = point->x;
1206 point->dy = point->y;
1207 point++;
1212 /* Check for collsions between the missiles and the asteroids and the ship */
1213 void check_collisions(void)
1215 int m, n;
1216 bool asteroids_onscreen = false;
1217 struct Missile* missile;
1218 struct Asteroid* asteroid;
1219 bool ship_cant_be_placed = false;
1221 asteroid = asteroids_array;
1222 m = MAX_NUM_ASTEROIDS;
1223 while(--m)
1225 /*if the asteroids exists then test missile collision:*/
1226 if(asteroid->exists)
1228 missile = missiles_array;
1229 n = MAX_NUM_MISSILES;
1230 while(--n)
1232 /*if the missiles exists:*/
1233 if(missile->survived > 0)
1235 /*has the missile hit the asteroid?*/
1236 if(is_point_within_asteroid(asteroid, &missile->position)
1237 || is_point_within_asteroid(asteroid,
1238 &missile->oldpoint))
1240 missile->survived = 0;
1241 break;
1244 missile++;
1247 /*now check collision with ship:*/
1248 if(asteroid->exists && !ship.waiting_for_space && !ship.explode_countdown)
1250 if(is_ship_within_asteroid(asteroid))
1252 if (!ship.invulnerable)
1254 /*if not invulnerable, blow up ship*/
1255 ship.explode_countdown = EXPLOSION_LENGTH;
1256 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1257 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1261 /*has the enemy missile blown something up?*/
1262 if(asteroid->exists && enemy_missile.survived)
1264 if(is_point_within_asteroid(asteroid, &enemy_missile.position))
1266 /*take that score back then:*/
1267 if(current_score > 0) current_score--;
1268 enemy_missile.survived = 0;
1271 /*if it still exists, check if ship is waiting for space:*/
1272 if(asteroid->exists && ship.waiting_for_space)
1273 ship_cant_be_placed |=
1274 is_point_within_rectangle(&ship.position,
1275 &asteroid->position,
1276 space_check_size);
1280 /*is an asteroid still exploding?*/
1281 if(asteroid->explode_countdown)
1282 asteroids_onscreen = true;
1284 asteroid++;
1287 /*now check collision between ship and enemy*/
1288 if(enemy_on_screen && !ship.waiting_for_space &&
1289 !ship.explode_countdown && !enemy.explode_countdown)
1291 /*has the enemy collided with the ship?*/
1292 if(is_point_within_enemy(&ship.position))
1294 if (!ship.invulnerable)
1296 ship.explode_countdown = EXPLOSION_LENGTH;
1297 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1298 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1300 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1303 /*Now see if the enemy has been shot at by the ships missiles:*/
1304 missile = missiles_array;
1305 n = MAX_NUM_MISSILES;
1306 while(--n)
1308 if(missile->survived > 0 &&
1309 is_point_within_enemy(&missile->position))
1311 missile->survived = 0;
1312 break;
1314 missile++;
1318 /*test collision with enemy missile and ship:*/
1319 if(!ship_cant_be_placed && enemy_missile.survived > 0 &&
1320 point_in_poly(ship.vertices, NUM_SHIP_VERTICES,
1321 enemy_missile.position.x - ship.position.x,
1322 enemy_missile.position.y - ship.position.y))
1324 if (!ship.invulnerable)
1326 ship.explode_countdown = EXPLOSION_LENGTH;
1327 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1328 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1330 enemy_missile.survived = 0;
1331 enemy_missile.position.x = enemy_missile.position.y = 0;
1334 if(!ship_cant_be_placed)
1335 ship.waiting_for_space = false;
1337 /*if all asteroids cleared then start again:*/
1338 if(asteroid_count == 0 && !enemy_on_screen && !asteroids_onscreen)
1340 current_level++;
1341 game_state = SHOW_LEVEL;
1342 enemy.appear_probability += 5;
1343 enemy.appear_timing -= 200;
1344 if( enemy.appear_probability > 100)
1345 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1346 show_level_timeout = SHOW_LEVEL_TIME;
1350 /*************************************************
1351 ** Creates a new asteroid of the given 4type (size)
1352 ** and at the given location.
1353 *************************************************/
1354 void create_asteroid(enum asteroid_type type, int x, int y)
1356 struct Asteroid* asteroid;
1357 int n;
1359 asteroid = asteroids_array;
1360 n = MAX_NUM_ASTEROIDS;
1361 while(--n)
1363 if(!asteroid->exists && !asteroid->explode_countdown)
1365 initialise_asteroid(asteroid, type);
1366 asteroid->position.x = x;
1367 asteroid->position.y = y;
1368 break;
1370 asteroid++;
1374 /* Initialise a missile */
1375 void initialise_missile(struct Missile* missile)
1377 missile->position.x = ship.position.x + ship.vertices[0].x;
1378 missile->position.y = ship.position.y + ship.vertices[0].y;
1379 missile->position.dx = (ship.vertices[0].x - ship.vertices[2].x)/2;
1380 missile->position.dy = (ship.vertices[0].y - ship.vertices[2].y)/2;
1381 missile->survived = MISSILE_SURVIVAL_LENGTH;
1382 missile->oldpoint.x = missile->position.x;
1383 missile->oldpoint.y = missile->position.y;
1386 /* Draw and Move all the missiles */
1387 void draw_and_move_missiles(void)
1389 int n;
1390 int p1x, p1y;
1391 int p2x, p2y;
1393 struct Missile* missile;
1394 missile = missiles_array;
1396 SET_FG(COL_MISSILE);
1398 n = MAX_NUM_MISSILES;
1399 while(--n)
1401 if(missile->survived)
1403 if(missile->position.dx > 0)
1405 if(missile->position.x >= missile->oldpoint.x)
1407 p1x = missile->oldpoint.x;
1408 p2x = missile->position.x;
1410 else
1412 p1x = 0;
1413 p2x = missile->position.x;
1416 else
1418 if(missile->oldpoint.x >= missile->position.x)
1420 p1x = missile->oldpoint.x;
1421 p2x = missile->position.x;
1423 else
1425 p1x = missile->oldpoint.x;
1426 p2x = LCD_WIDTH;
1430 if(missile->position.dy > 0)
1432 if(missile->position.y >= missile->oldpoint.y)
1434 p1y = missile->oldpoint.y;
1435 p2y = missile->position.y;
1437 else
1439 p1y = 0;
1440 p2y = missile->position.y;
1443 else
1445 if(missile->oldpoint.y >= missile->position.y)
1447 p1y = missile->oldpoint.y;
1448 p2y = missile->position.y;
1450 else
1452 p1y = missile->oldpoint.y;
1453 p2y = LCD_HEIGHT;
1457 rb->lcd_drawline( p1x/SCALE, p1y/SCALE, p2x/SCALE, p2y/SCALE);
1459 if(game_state != PAUSE_MODE)
1461 missile->oldpoint.x = missile->position.x;
1462 missile->oldpoint.y = missile->position.y;
1463 move_point(&missile->position);
1464 missile->survived--;
1467 missile++;
1471 void draw_lives(void)
1473 int n;
1474 int px = (LCD_WIDTH - num_lives*4 - 1);
1475 #if(LARGE_LCD)
1476 int py = (LCD_HEIGHT-6);
1477 #else
1478 int py = (LCD_HEIGHT-4);
1479 #endif
1481 SET_FG(COL_PLAYER);
1483 n = num_lives;
1484 while(--n)
1486 draw_polygon(lives_points, px, py, NUM_SHIP_VERTICES);
1487 #if(LARGE_LCD)
1488 px += 8;
1489 #else
1490 px += 6;
1491 #endif
1495 /*Fire the next missile*/
1496 void fire_missile(void)
1498 int n;
1499 struct Missile* missile;
1501 if(!ship.explode_countdown && !ship.waiting_for_space)
1503 missile = missiles_array;
1504 n = MAX_NUM_MISSILES;
1505 while(--n)
1507 if(!missile->survived)
1509 initialise_missile(missile);
1510 break;
1512 missile++;
1517 /* Initialise the passed Asteroid */
1518 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type type)
1520 int n;
1521 bool b,b2;
1522 struct Point* point;
1523 asteroid->exists = true;
1524 asteroid->type = type;
1525 asteroid->explode_countdown = 0;
1527 /*Set the radius of the asteroid:*/
1528 asteroid->radius = (int)type*SCALE;
1530 /*shall we move Clockwise and Fast*/
1531 if((rb->rand()%100)>75)
1533 asteroid->speed_cos = FAST_ROT_CW_COS;
1534 asteroid->speed_sin = FAST_ROT_CW_SIN;
1536 else if((rb->rand()%100)>75)
1538 asteroid->speed_cos = FAST_ROT_ACW_COS;
1539 asteroid->speed_sin = FAST_ROT_ACW_SIN;
1541 else if((rb->rand()%100)>75)
1543 asteroid->speed_cos = SLOW_ROT_ACW_COS;
1544 asteroid->speed_sin = SLOW_ROT_ACW_SIN;
1546 else
1548 asteroid->speed_cos = SLOW_ROT_CW_COS;
1549 asteroid->speed_sin = SLOW_ROT_CW_SIN;
1552 b = (rb->rand()%100)>66;
1553 b2 = (rb->rand()%100)>66;
1554 point = asteroid->vertices;
1555 for(n = 0; n < NUM_ASTEROID_VERTICES*2; n+=2)
1557 if(b)
1559 point->x = asteroid_one[n];
1560 point->y = asteroid_one[n+1];
1562 else if( b2 )
1564 point->x = asteroid_two[n];
1565 point->y = asteroid_two[n+1];
1567 else
1569 point->x = asteroid_three[n];
1570 point->y = asteroid_three[n+1];
1573 point->x *= asteroid->radius/6;
1574 point->y *= asteroid->radius/6;
1575 point++;
1579 asteroid->radius += 6*SCALE;
1580 if(asteroid->type == SMALL)
1581 asteroid->radius /= 3;/*2*/
1582 else if(asteroid->type == LARGE)
1583 asteroid->radius += 3*SCALE;/*2*/
1584 b = true;
1585 while(b)
1587 /*Set the position randomly:*/
1588 asteroid->position.x = (rb->rand()%SCALED_WIDTH);
1589 asteroid->position.y = (rb->rand()%SCALED_HEIGHT);
1591 asteroid->position.dx = 0;
1592 while(asteroid->position.dx == 0)
1593 asteroid->position.dx = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1595 asteroid->position.dy = 0;
1596 while(asteroid->position.dy == 0)
1597 asteroid->position.dy = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1599 asteroid->position.dx *= SCALE/10;
1600 asteroid->position.dy *= SCALE/10;
1602 b = is_point_within_rectangle(&ship.position, &asteroid->position,
1603 space_check_size);
1606 /*Now rotate the asteroid a bit, so they all look a bit different*/
1607 for(n=(rb->rand()%30) + 2;--n;)
1608 rotate_asteroid(asteroid);
1610 /*great, we've created an asteroid, don't forget to increment the total:*/
1611 asteroid_count++;
1614 /*Initialise the ship*/
1615 void initialise_ship(void)
1617 struct Point* point;
1618 struct Point* lives_point;
1619 int n;
1621 ship.position.x = CENTER_LCD_X;
1622 ship.position.y = CENTER_LCD_Y;
1623 ship.position.x *= SCALE;
1624 ship.position.y *= SCALE;
1625 ship.position.dx = ship.position.dy = 0;
1626 ship.spawn_time = SPAWN_TIME;
1627 ship.invulnerable = 1;
1629 point = ship.vertices;
1630 lives_point = lives_points;
1631 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1633 point->x = ship_vertices[n];
1634 point->y = ship_vertices[n+1];
1635 point->x *= SCALE;
1636 point->y *= SCALE;
1637 point++;
1638 lives_point++;
1641 ship.position.dx = 0;
1642 ship.position.dy = 0;
1643 ship.explode_countdown = 0;
1645 /*grab a copy of the ships points for the lives display:*/
1646 point = ship.vertices;
1647 lives_point = lives_points;
1648 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1650 lives_point->x = point->x;
1651 lives_point->y = point->y;
1652 lives_point++;
1653 point++;
1657 void rotate_asteroid(struct Asteroid* asteroid)
1659 struct Point* point;
1660 int n;
1661 long xtemp;
1663 point = asteroid->vertices;
1664 for(n = NUM_ASTEROID_VERTICES+1; --n;)
1666 xtemp = point->x;
1667 point->x = xtemp*asteroid->speed_cos/SIN_COS_SCALE -
1668 point->y*asteroid->speed_sin/SIN_COS_SCALE;
1669 point->y = point->y*asteroid->speed_cos/SIN_COS_SCALE +
1670 xtemp*asteroid->speed_sin/SIN_COS_SCALE;
1671 point++;
1675 /*************************************************
1676 ** Draws the ship, moves the ship and creates a new
1677 ** one if it's finished exploding.
1678 **************************************************/
1679 void draw_and_move_ship(void)
1681 int nxoffset = ship.position.x/SCALE;
1682 int nyoffset = ship.position.y/SCALE;
1683 if (ship.invulnerable && (ship.spawn_time > BLINK_TIME || ship.spawn_time % 2 == 0))
1685 SET_FG(COL_INVULN);
1687 else
1689 SET_FG(COL_PLAYER);
1691 if(!ship.explode_countdown)
1693 /* make sure ship is invulnerable until spawn time over */
1694 if (ship.spawn_time)
1696 ship.spawn_time--;
1697 if (ship.spawn_time <= 0)
1699 ship.invulnerable = 0;
1702 if(!ship.waiting_for_space)
1704 draw_polygon(ship.vertices, nxoffset, nyoffset, NUM_SHIP_VERTICES);
1705 if(game_state != PAUSE_MODE && game_state != GAME_OVER)
1707 move_point(&ship.position);
1711 else
1713 /* animate_and_draw_explosion(ship.vertices, NUM_SHIP_VERTICES,
1714 ship.position.x/SCALE,
1715 ship.position.y/SCALE); */
1716 if(game_state != PAUSE_MODE)
1718 ship.explode_countdown--;
1719 if(!ship.explode_countdown)
1721 num_lives--;
1722 if(!num_lives)
1724 game_state = GAME_OVER;
1726 else
1728 initialise_ship();
1729 ship.waiting_for_space = true;
1736 void thrust_ship(void)
1738 if(!ship.waiting_for_space)
1740 ship.position.dx += ( ship.vertices[0].x - ship.vertices[2].x )/20;
1741 ship.position.dy += ( ship.vertices[0].y - ship.vertices[2].y )/20;
1742 /*if dx and dy are below a certain threshold, then set 'em to 0
1743 but to do this we need to ascertain if the spacehip as moved on screen
1744 for more than a certain amount. */
1746 create_trail_blaze(THRUST_COLOUR, &ship.position);
1750 /**************************************************
1751 ** Rotate the ship using the passed sin & cos values
1752 ***************************************************/
1753 void rotate_ship(int c, int s)
1755 struct Point* point;
1756 int n;
1757 double xtemp;
1759 if(!ship.waiting_for_space && !ship.explode_countdown)
1761 point = ship.vertices;
1762 for(n=NUM_SHIP_VERTICES+1;--n;)
1764 xtemp = point->x;
1765 point->x = xtemp*c/SIN_COS_SCALE - point->y*s/SIN_COS_SCALE;
1766 point->y = point->y*c/SIN_COS_SCALE + xtemp*s/SIN_COS_SCALE;
1767 point++;
1772 void drawstars()
1774 struct Point* p;
1775 int n = NUM_STARS;
1777 p = stars;
1778 SET_FG(COL_STARS);
1780 while(--n)
1782 rb->lcd_drawpixel(p->x , p->y);
1783 p++;
1787 /*************************************************
1788 ** Draw And Move all Asteroids
1789 *************************************************/
1790 void draw_and_move_asteroids(void)
1792 int n;
1793 struct Asteroid* asteroid;
1795 asteroid = asteroids_array;
1796 SET_FG(COL_ASTEROID);
1798 n = MAX_NUM_ASTEROIDS;
1799 while(--n)
1801 if(game_state != PAUSE_MODE)
1803 if(asteroid->exists)
1805 move_point(&asteroid->position);
1806 rotate_asteroid(asteroid);
1807 draw_polygon(asteroid->vertices, asteroid->position.x/SCALE,
1808 asteroid->position.y/SCALE,
1809 NUM_ASTEROID_VERTICES);
1811 else if(asteroid->explode_countdown)
1813 /* animate_and_draw_explosion(asteroid->vertices,
1814 NUM_ASTEROID_VERTICES,
1815 asteroid->position.x/SCALE,
1816 asteroid->position.y/SCALE); */
1817 asteroid->explode_countdown--;
1820 else
1822 if(asteroid->exists)
1823 draw_polygon(asteroid->vertices,
1824 asteroid->position.x/SCALE,
1825 asteroid->position.y/SCALE,
1826 NUM_ASTEROID_VERTICES);
1828 asteroid++;
1832 void create_stars(void)
1834 struct TrailPoint* tpoint;
1835 struct Point* p;
1836 int n;
1838 p = stars;
1839 n = NUM_STARS;
1840 while(--n)
1842 p->x = (rb->rand()%LCD_WIDTH);
1843 p->y = (rb->rand()%LCD_HEIGHT);
1844 p++;
1848 /* give the point a random countdown timer, so they dissapears at different
1849 times */
1850 tpoint = trailPoints;
1851 n = NUM_TRAIL_POINTS;
1852 while(--n)
1854 tpoint->alive = 0;
1855 tpoint++;
1859 /*************************************************
1860 ** Creates start_num number of new asteroids of
1861 ** full size.
1862 **************************************************/
1863 void initialise_game(int start_num)
1865 int n;
1866 asteroid_count = next_missile_count = next_thrust_count = 0;
1867 struct Asteroid* asteroid;
1868 struct Missile* missile;
1869 extra_life = EXTRA_LIFE;
1871 /*no enemy*/
1872 enemy_on_screen = 0;
1873 enemy_missile.survived = 0;
1875 /*clear asteroids*/
1876 asteroid = asteroids_array;
1877 n = MAX_NUM_ASTEROIDS;
1878 while(--n)
1880 asteroid->exists = false;
1881 asteroid++;
1884 /*make some LARGE asteroids*/
1885 for(n = 0; n < start_num; n++)
1886 initialise_asteroid(&asteroids_array[n], LARGE);
1888 /*ensure all missiles are out of action: */
1889 missile = missiles_array;
1890 n = MAX_NUM_MISSILES;
1891 while(--n)
1893 missile->survived=0;
1894 missile++;
1898 static int spacerocks_game_loop(void)
1900 char s[20];
1901 char level[10];
1902 int button;
1903 int end;
1904 int position;
1906 /*create stars once, and once only:*/
1907 create_stars();
1909 if (spacerocks_menu(false)!=0)
1910 return 0;
1912 SET_BG(LCD_BLACK);
1914 while(true)
1916 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1917 rb->lcd_clear_display();
1918 SET_FG(COL_TEXT);
1919 switch(game_state) {
1920 case(GAME_OVER):
1921 rb->splash (HZ * 2, "Game Over");
1922 rb->lcd_clear_display();
1923 position=highscore_update(current_score, current_level, "",
1924 highest,NUM_SCORES);
1925 if (position == 0)
1926 rb->splash(HZ*2, "New High Score");
1927 if (position != -1)
1928 highscore_show(position, highest, NUM_SCORES, true);
1929 if (spacerocks_menu(false)!=0)
1930 return 0;
1931 break;
1933 case(PAUSE_MODE):
1934 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1935 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1936 rb->lcd_putsxy(CENTER_LCD_X - 15,
1937 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "pause");
1938 draw_and_move_missiles();
1939 draw_lives();
1940 draw_and_move_ship();
1941 break;
1943 case(PLAY_MODE):
1944 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1945 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1946 draw_and_move_missiles();
1947 draw_lives();
1948 check_collisions();
1949 draw_and_move_ship();
1950 break;
1952 case(SHOW_LEVEL):
1953 show_level_timeout--;
1954 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1955 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1956 rb->snprintf(level, sizeof(level), "stage %d ", current_level);
1957 rb->lcd_putsxy(CENTER_LCD_X - 20,
1958 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, level);
1959 draw_and_move_ship();
1960 draw_lives();
1961 if(!show_level_timeout) {
1962 initialise_game(current_level);
1963 game_state = PLAY_MODE;
1964 draw_lives();
1966 break;
1968 draw_trail_blaze();
1969 drawstars();
1970 draw_and_move_asteroids();
1971 draw_and_move_enemy();
1973 rb->lcd_update();
1975 #ifdef HAS_BUTTON_HOLD
1976 if (rb->button_hold())
1977 game_state = PAUSE_MODE;
1979 #endif
1980 button = rb->button_get(false);
1981 switch(button) {
1982 case(AST_QUIT):
1983 if (spacerocks_menu(true)!=0)
1984 return 0;
1985 break;
1986 #ifdef AST_PAUSE
1987 case(AST_PAUSE):
1988 if (game_state == PAUSE_MODE) {
1989 game_state = PLAY_MODE;
1990 break;
1992 else if (game_state != PLAY_MODE)
1993 break;
1994 #endif
1995 case (AST_LEFT):
1996 case (AST_LEFT | BUTTON_REPEAT):
1997 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1998 rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN);
1999 break;
2001 case (AST_RIGHT):
2002 case (AST_RIGHT | BUTTON_REPEAT):
2003 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
2004 rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN);
2005 break;
2007 case (AST_THRUST):
2008 case (AST_THRUST | BUTTON_REPEAT):
2009 if((game_state == PLAY_MODE || game_state == SHOW_LEVEL) &&
2010 !next_thrust_count) {
2011 thrust_ship();
2012 next_thrust_count = 5;
2014 break;
2016 case (AST_HYPERSPACE):
2017 if(game_state == PLAY_MODE)
2018 hyperspace();
2019 /*maybe shield if it gets too hard */
2020 break;
2022 case (AST_FIRE):
2023 case (AST_FIRE | BUTTON_REPEAT):
2024 if(game_state == PLAY_MODE) {
2025 if(!next_missile_count) {
2026 fire_missile();
2027 next_missile_count = 10;
2030 else if(game_state == PAUSE_MODE) {
2031 game_state = PLAY_MODE;
2033 break;
2035 default:
2036 if (rb->default_event_handler(button)==SYS_USB_CONNECTED)
2037 return PLUGIN_USB_CONNECTED;
2038 break;
2041 if(next_missile_count)
2042 next_missile_count--;
2044 if(next_thrust_count)
2045 next_thrust_count--;
2047 if (end > *rb->current_tick)
2048 rb->sleep(end-*rb->current_tick);
2049 else
2050 rb->yield();
2054 enum plugin_status plugin_start(const void* parameter)
2056 (void)parameter;
2058 #if LCD_DEPTH > 1
2059 rb->lcd_set_backdrop(NULL);
2060 #endif
2061 /* universal font */
2062 rb->lcd_setfont(FONT_SYSFIXED);
2063 /* Turn off backlight timeout */
2064 backlight_force_on(); /* backlight control in lib/helper.c */
2065 highscore_load(HIGH_SCORE,highest,NUM_SCORES);
2066 spacerocks_game_loop();
2067 rb->lcd_setfont(FONT_UI);
2068 highscore_save(HIGH_SCORE,highest,NUM_SCORES);
2069 /* Turn on backlight timeout (revert to settings) */
2070 backlight_use_settings(); /* backlight control in lib/helper.c */
2072 return PLUGIN_OK;