Use normal apostrophes for code. Thanks to fml for pointing out (also for previoys...
[kugel-rb.git] / apps / plugins / spacerocks.c
blob0ade406b59ffa329899076d6410616ffad35b015
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 == COWON_D2_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 == PHILIPS_SA9200_PAD
201 #define AST_PAUSE BUTTON_RIGHT
202 #define AST_QUIT BUTTON_POWER
203 #define AST_THRUST BUTTON_UP
204 #define AST_HYPERSPACE BUTTON_DOWN
205 #define AST_LEFT BUTTON_PREV
206 #define AST_RIGHT BUTTON_NEXT
207 #define AST_FIRE BUTTON_LEFT
209 #elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \
210 (CONFIG_KEYPAD == ONDAVX777_PAD) || \
211 (CONFIG_KEYPAD == MROBE500_PAD)
212 #define AST_QUIT BUTTON_POWER
214 #elif (CONFIG_KEYPAD == SAMSUNG_YH_PAD)
215 #define AST_PAUSE BUTTON_FFWD
216 #define AST_QUIT BUTTON_REC
217 #define AST_THRUST BUTTON_UP
218 #define AST_HYPERSPACE BUTTON_DOWN
219 #define AST_LEFT BUTTON_LEFT
220 #define AST_RIGHT BUTTON_RIGHT
221 #define AST_FIRE BUTTON_PLAY
223 #elif (CONFIG_KEYPAD == PBELL_VIBE500_PAD)
224 #define AST_PAUSE BUTTON_PLAY
225 #define AST_QUIT BUTTON_REC
226 #define AST_THRUST BUTTON_UP
227 #define AST_HYPERSPACE BUTTON_DOWN
228 #define AST_LEFT BUTTON_PREV
229 #define AST_RIGHT BUTTON_NEXT
230 #define AST_FIRE BUTTON_OK
232 #elif (CONFIG_KEYPAD == MPIO_HD200_PAD)
234 #define AST_PAUSE (BUTTON_PLAY|BUTTON_SELECT)
235 #define AST_QUIT (BUTTON_REC|BUTTON_PLAY)
236 #define AST_THRUST BUTTON_REC
237 #define AST_HYPERSPACE BUTTON_PLAY
238 #define AST_LEFT BUTTON_PREV
239 #define AST_RIGHT BUTTON_NEXT
240 #define AST_FIRE BUTTON_SELECT
242 #else
243 #error No keymap defined!
244 #endif
246 #ifdef HAVE_TOUCHSCREEN
247 #ifndef AST_PAUSE
248 #define AST_PAUSE BUTTON_CENTER
249 #endif
250 #ifndef AST_QUIT
251 #define AST_QUIT BUTTON_TOPLEFT
252 #endif
253 #ifndef AST_THRUST
254 #define AST_THRUST BUTTON_TOPMIDDLE
255 #endif
256 #ifndef AST_HYPERSPACE
257 #define AST_HYPERSPACE BUTTON_TOPRIGHT
258 #endif
259 #ifndef AST_LEFT
260 #define AST_LEFT BUTTON_MIDLEFT
261 #endif
262 #ifndef AST_RIGHT
263 #define AST_RIGHT BUTTON_MIDRIGHT
264 #endif
265 #ifndef AST_FIRE
266 #define AST_FIRE BUTTON_BOTTOMMIDDLE
267 #endif
268 #endif
270 #define RES MAX(LCD_WIDTH, LCD_HEIGHT)
271 #define LARGE_LCD (RES >= 200)
273 #define CYCLETIME 30
275 #define SHOW_COL 0
276 #define SCALE 5000
277 #define WRAP_GAP (LARGE*SCALE*3)
278 #define POINT_SIZE 2
279 #define START_LEVEL 1
280 #define SHOW_LEVEL_TIME 50
281 #define EXPLOSION_LENGTH 20
283 #define MAX_NUM_ASTEROIDS 25
284 #define MAX_NUM_MISSILES 6
285 #define NUM_STARS 50
286 #define NUM_TRAIL_POINTS 70
287 #define MAX_LEVEL MAX_NUM_ASTEROIDS
289 #define NUM_ASTEROID_VERTICES 10
290 #define NUM_SHIP_VERTICES 4
291 #define NUM_ENEMY_VERTICES 8
293 #define INVULNERABLE_TIME 30
294 #define BLINK_TIME 10
295 #define EXTRA_LIFE 250
296 #define START_LIVES 3
297 #define MISSILE_LIFE_LENGTH 40
299 #define ASTEROID_SPEED (RES/20)
300 #define SPACE_CHECK_SIZE 30*SCALE
302 #if (LARGE_LCD)
303 #define SIZE_SHIP_COLLISION 8*SCALE
304 #else
305 #define SIZE_SHIP_COLLISION 6*SCALE
306 #endif
308 #define LITTLE_SHIP 1
309 #define BIG_SHIP 2
310 #define ENEMY_BIG_PROBABILITY_START 10
311 #define ENEMY_APPEAR_PROBABILITY_START 35
312 #define ENEMY_APPEAR_TIMING_START 600
313 #define ENEMY_SPEED 4
314 #define ENEMY_MISSILE_LIFE_LENGTH (RES/2)
315 #if (LARGE_LCD)
316 #define SIZE_ENEMY_COLLISION 7*SCALE
317 #else
318 #define SIZE_ENEMY_COLLISION 5*SCALE
319 #endif
321 #define SIN_COS_SCALE 10000
323 #define FAST_ROT_CW_SIN 873
324 #define FAST_ROT_CW_COS 9963
325 #define FAST_ROT_ACW_SIN -873
326 #define FAST_ROT_ACW_COS 9963
328 #define MEDIUM_ROT_CW_SIN 350
329 #define MEDIUM_ROT_CW_COS 9994
330 #define MEDIUM_ROT_ACW_SIN -350
331 #define MEDIUM_ROT_ACW_COS 9994
333 #define SLOW_ROT_CW_SIN 350
334 #define SLOW_ROT_CW_COS 9994
335 #define SLOW_ROT_ACW_SIN -350
336 #define SLOW_ROT_ACW_COS 9994
338 #ifdef HAVE_LCD_COLOR
339 #define SHIP_ROT_CW_SIN 2419
340 #define SHIP_ROT_CW_COS 9702
341 #define SHIP_ROT_ACW_SIN -2419
342 #define SHIP_ROT_ACW_COS 9702
343 #else
344 #define SHIP_ROT_CW_SIN 3827
345 #define SHIP_ROT_CW_COS 9239
346 #define SHIP_ROT_ACW_SIN -3827
347 #define SHIP_ROT_ACW_COS 9239
348 #endif
351 #define SCALED_WIDTH (LCD_WIDTH*SCALE)
352 #define SCALED_HEIGHT (LCD_HEIGHT*SCALE)
353 #define CENTER_LCD_X (LCD_WIDTH/2)
354 #define CENTER_LCD_Y (LCD_HEIGHT/2)
356 #ifdef HAVE_LCD_COLOR
357 #define ASTEROID_R 230
358 #define ASTEROID_G 200
359 #define ASTEROID_B 100
360 #define SHIP_R 255
361 #define SHIP_G 255
362 #define SHIP_B 255
363 #define ENEMY_R 50
364 #define ENEMY_G 220
365 #define ENEMY_B 50
366 #define THRUST_R 200
367 #define THRUST_G 200
368 #define THRUST_B 0
370 #define COL_MISSILE LCD_RGBPACK(200,0,0)
371 #define COL_PLAYER LCD_RGBPACK(200,200,200)
372 #define COL_INVULN LCD_RGBPACK(100,100,200)
373 #define COL_STARS LCD_WHITE
374 #define COL_ASTEROID LCD_RGBPACK(ASTEROID_R,ASTEROID_G,ASTEROID_B)
375 #define COL_TEXT LCD_RGBPACK(200,200,255)
376 #define COL_ENEMY LCD_RGBPACK(ENEMY_R,ENEMY_G,ENEMY_B)
377 #define SET_FG rb->lcd_set_foreground
378 #define SET_BG rb->lcd_set_background
379 #else
380 #define SET_FG(x)
381 #define SET_BG(x)
382 #endif
384 #define SCORE_FILE PLUGIN_GAMES_DIR "/spacerocks.score"
385 #define NUM_SCORES 5
387 static struct highscore highscores[NUM_SCORES];
389 /* The array of points that make up an asteroid */
390 static const short asteroid_one[NUM_ASTEROID_VERTICES*2] =
392 -2, -12,
393 4, -8,
394 8, -14,
395 16, -5,
396 14, 0,
397 20, 2,
398 12, 14,
399 -4, 14,
400 -10, 6,
401 -10, -8,
404 /* The array of points that make up an asteroid */
405 static const short asteroid_two[NUM_ASTEROID_VERTICES*2] =
407 -2, -12,
408 4, -16,
409 6, -14,
410 16, -8,
411 14, 0,
412 20, 2,
413 12, 14,
414 -4, 14,
415 -10, 6,
416 -10, -8,
419 /* The array of points that make up an asteroid */
420 static const short asteroid_three[NUM_ASTEROID_VERTICES*2] =
422 -2, -12,
423 4, -16,
424 6, -14,
425 2, -8,
426 14, 0,
427 20, 2,
428 12, 14,
429 -4, 14,
430 -16, 6,
431 -10, -8,
434 /* The array of points the make up the ship */
435 static const short ship_vertices[NUM_SHIP_VERTICES*2] =
437 #if (LARGE_LCD)
438 0, -6,
439 4, 6,
440 0, 2,
441 -4, 6,
442 #else
443 0, -4,
444 3, 4,
445 0, 1,
446 -3, 4,
447 #endif
450 /* The array of points the make up the bad spaceship */
451 static const short enemy_vertices[NUM_ENEMY_VERTICES*2] =
453 #if (LARGE_LCD)
454 -8, 0,
455 -4, 4,
456 4, 4,
457 8, 0,
458 -8, 0,
459 8, 0,
460 4, -4,
461 -4, -4,
462 #else
463 -5, 0,
464 -2, 2,
465 2, 2,
466 5, 0,
467 -5, 0,
468 5, 0,
469 2, -2,
470 -2, -2,
471 #endif
474 enum asteroid_type
476 #if (LARGE_LCD)
477 SMALL = 2,
478 MEDIUM = 4,
479 LARGE = 6,
480 #else
481 SMALL = 1,
482 MEDIUM = 2,
483 LARGE = 3,
484 #endif
487 enum explosion_type
489 EXPLOSION_SHIP,
490 EXPLOSION_ASTEROID,
491 EXPLOSION_ENEMY,
492 EXPLOSION_THRUST,
495 enum game_state
497 GAME_OVER,
498 SHOW_LEVEL,
499 PLAY_MODE,
500 PAUSE_MODE,
503 struct Point
505 int x;
506 int y;
507 int dx;
508 int dy;
511 struct TrailPoint
513 struct Point position;
514 int alive;
515 #ifdef HAVE_LCD_COLOR
516 short r;
517 short g;
518 short b;
519 short dec;
520 #endif
523 /* Asteroid structure, contains an array of points */
524 struct Asteroid
526 struct Point position;
527 struct Point rotation;
528 struct Point vertices[NUM_ASTEROID_VERTICES];
529 bool exists;
530 int explode_countdown;
531 enum asteroid_type type;
532 int radius;
533 long speed_cos;
534 long speed_sin;
537 struct Ship
539 struct Point position;
540 struct Point rotation;
541 struct Point vertices[NUM_SHIP_VERTICES];
542 bool exists;
543 int explode_countdown;
544 int invulnerable_time;
547 struct Enemy
549 struct Point position;
550 struct Point vertices[NUM_ENEMY_VERTICES];
551 bool exists;
552 int explode_countdown;
553 int appear_countdown;
554 short size_probability;
555 short appear_probability;
556 short appear_timing;
559 struct Missile
561 struct Point position;
562 struct Point oldpoint;
563 int alive;
566 static enum game_state game_state;
567 static int asteroid_count;
568 static int next_missile_count;
569 static int next_thrust_count;
570 static int num_lives;
571 static int extra_life;
572 static int show_level_timeout;
573 static int current_level;
574 static int current_score;
576 static struct Ship ship;
577 static struct Point stars[NUM_STARS];
578 static struct Asteroid asteroids_array[MAX_NUM_ASTEROIDS];
579 static struct Missile missiles_array[MAX_NUM_MISSILES];
580 static struct Missile enemy_missile;
581 static struct Enemy enemy;
582 static struct Point lives_points[NUM_SHIP_VERTICES];
583 static struct TrailPoint trail_points[NUM_TRAIL_POINTS];
585 /*************************************************
586 ** Handle polygon and point
587 *************************************************/
589 /* Check if point is in a polygon */
590 static bool is_point_in_polygon(struct Point* vertices, int num_vertices,
591 int x, int y)
593 struct Point* pi;
594 struct Point* pj;
595 int n;
596 bool c = false;
598 if (x < -SCALED_WIDTH/2) x += SCALED_WIDTH;
599 else if (x > SCALED_WIDTH/2) x -= SCALED_WIDTH;
600 if (y < -SCALED_HEIGHT/2) y += SCALED_HEIGHT;
601 else if (y > SCALED_HEIGHT/2) y -= SCALED_HEIGHT;
603 pi = vertices;
604 pj = vertices + num_vertices-1;
606 n = num_vertices;
607 while (n--)
609 if ((((pi->y <= y) && (y < pj->y)) || ((pj->y <= y) && (y < pi->y))) &&
610 (x < (pj->x - pi->x) * (y - pi->y) / (pj->y - pi->y) + pi->x))
611 c = !c;
613 pj = pi;
614 pi++;
617 return c;
620 /* Check if point is within a rectangle */
621 static bool is_point_within_rectangle(struct Point* rect, struct Point* p,
622 int size)
624 int dx = p->x - rect->x;
625 int dy = p->y - rect->y;
626 #if SHOW_COL
627 rb->lcd_drawrect((rect->x - size)/SCALE, (rect->y - size)/SCALE,
628 (size*2+1)/SCALE, (size*2+1)/SCALE);
629 #endif
630 if (dx < -SCALED_WIDTH/2) dx += SCALED_WIDTH;
631 else if (dx > SCALED_WIDTH/2) dx -= SCALED_WIDTH;
632 if (dy < -SCALED_HEIGHT/2) dy += SCALED_HEIGHT;
633 else if (dy > SCALED_HEIGHT/2) dy -= SCALED_HEIGHT;
634 return (dx > -size && dx < size && dy > -size && dy < size);
637 /* Rotate polygon */
638 static void rotate_polygon(struct Point* vertices, int num_vertices,
639 struct Point* rotation, int cos, int sin)
641 struct Point* point;
642 int n;
643 long temp_x, temp_y;
645 temp_x = rotation->x;
646 temp_y = rotation->y;
647 rotation->x = (temp_x*cos - temp_y*sin)/SIN_COS_SCALE;
648 rotation->y = (temp_y*cos + temp_x*sin)/SIN_COS_SCALE;
649 #define MIN_SCALE (SIN_COS_SCALE-10)
650 #define MAX_SCALE (SIN_COS_SCALE+10)
651 /* normalize vector. this is not accurate but would be enough. */
652 temp_x = rotation->x*rotation->x + rotation->y*rotation->y;
653 if (temp_x <= MIN_SCALE*MIN_SCALE)
655 rotation->x = rotation->x*SIN_COS_SCALE/MIN_SCALE;
656 rotation->y = rotation->y*SIN_COS_SCALE/MIN_SCALE;
658 else if (temp_x >= MAX_SCALE*MAX_SCALE)
660 rotation->x = rotation->x*SIN_COS_SCALE/MAX_SCALE;
661 rotation->y = rotation->y*SIN_COS_SCALE/MAX_SCALE;
663 #undef MIN_SCALE
664 #undef MAX_SCALE
666 point = vertices;
667 n = num_vertices;
668 while (n--)
670 point->x = (point->dx*rotation->x - point->dy*rotation->y)/SIN_COS_SCALE;
671 point->y = (point->dy*rotation->x + point->dx*rotation->y)/SIN_COS_SCALE;
672 point++;
676 /* Draw polygon */
677 static void draw_polygon(struct Point* vertices, int num_vertices,
678 int px, int py)
680 int n, new_x, new_y, old_x, old_y;
681 struct Point *p;
682 bool draw_wrap;
684 if (px > SCALED_WIDTH - WRAP_GAP)
685 px -= SCALED_WIDTH;
686 if (py > SCALED_HEIGHT - WRAP_GAP)
687 py -= SCALED_HEIGHT;
689 draw_wrap = (px < WRAP_GAP || py < WRAP_GAP);
691 p = vertices + num_vertices - 1;
692 old_x = (p->x + px)/SCALE;
693 old_y = (p->y + py)/SCALE;
694 p = vertices;
695 n = num_vertices;
696 while (n--)
698 new_x = (p->x + px)/SCALE;
699 new_y = (p->y + py)/SCALE;
701 rb->lcd_drawline(old_x, old_y, new_x, new_y);
702 if (draw_wrap)
704 rb->lcd_drawline(old_x + LCD_WIDTH, old_y, new_x + LCD_WIDTH, new_y);
705 rb->lcd_drawline(old_x, old_y + LCD_HEIGHT, new_x, new_y + LCD_HEIGHT);
706 rb->lcd_drawline(old_x + LCD_WIDTH, old_y + LCD_HEIGHT,
707 new_x + LCD_WIDTH, new_y + LCD_HEIGHT);
709 old_x = new_x;
710 old_y = new_y;
711 p++;
715 static void move_point(struct Point* point)
717 point->x += point->dx;
718 point->y += point->dy;
720 /* Check bounds on the x-axis: */
721 point->x %= SCALED_WIDTH;
722 if (point->x < 0)
723 point->x += SCALED_WIDTH;
725 /* Check bounds on the y-axis: */
726 point->y %= SCALED_HEIGHT;
727 if (point->y < 0)
728 point->y += SCALED_HEIGHT;
731 /*************************************************
732 ** Handle trail blaiz.
733 *************************************************/
735 static void create_ship_trail(struct TrailPoint* tpoint)
737 tpoint->position.x += ship.vertices[2].x;
738 tpoint->position.y += ship.vertices[2].y;
739 tpoint->position.dx = -( ship.vertices[0].x - ship.vertices[2].x )/10;
740 tpoint->position.dy = -( ship.vertices[0].y - ship.vertices[2].y )/10;
743 static void create_explosion_trail(struct TrailPoint* tpoint)
745 tpoint->position.dx = (rb->rand()%5001)-2500;
746 tpoint->position.dy = (rb->rand()%5001)-2500;
749 static void create_trail_blaze(int colour, struct Point* position)
751 int numtoadd;
752 struct TrailPoint* tpoint;
753 int n;
755 if (colour != EXPLOSION_SHIP)
757 numtoadd = NUM_TRAIL_POINTS/5;
759 else
761 numtoadd = NUM_TRAIL_POINTS/8;
764 /* give the point a random countdown timer, so they dissapears at different
765 times */
766 tpoint = trail_points;
767 n = NUM_TRAIL_POINTS;
768 while (n--)
770 /* find a space in the array of trail_points that is NULL or DEAD or
771 whatever and place this one here. */
772 if (tpoint->alive <= 0)
774 /* take a random point near the position. */
775 tpoint->position.x = (rb->rand()%18000)-9000 + position->x;
776 tpoint->position.y = (rb->rand()%18000)-9000 + position->y;
778 switch(colour)
780 case EXPLOSION_SHIP:
781 create_explosion_trail(tpoint);
782 tpoint->alive = 51;
783 #ifdef HAVE_LCD_COLOR
784 tpoint->r = SHIP_R;
785 tpoint->g = SHIP_G;
786 tpoint->b = SHIP_B;
787 tpoint->dec = 2;
788 #endif
789 break;
790 case EXPLOSION_ASTEROID:
791 create_explosion_trail(tpoint);
792 tpoint->alive = 51;
793 #ifdef HAVE_LCD_COLOR
794 tpoint->r = ASTEROID_R;
795 tpoint->g = ASTEROID_G;
796 tpoint->b = ASTEROID_B;
797 tpoint->dec = 2;
798 #endif
799 break;
800 case EXPLOSION_ENEMY:
801 create_explosion_trail(tpoint);
802 tpoint->alive = 51;
803 #ifdef HAVE_LCD_COLOR
804 tpoint->r = ENEMY_R;
805 tpoint->g = ENEMY_G;
806 tpoint->b = ENEMY_B;
807 tpoint->dec = 2;
808 #endif
809 break;
810 case EXPLOSION_THRUST:
811 create_ship_trail(tpoint);
812 tpoint->alive = 17;
813 #ifdef HAVE_LCD_COLOR
814 tpoint->r = THRUST_R;
815 tpoint->g = THRUST_G;
816 tpoint->b = THRUST_B;
817 tpoint->dec = 4;
818 #endif
819 break;
822 /* give the points a speed based on direction of travel
823 - i.e. opposite */
824 tpoint->position.dx += position->dx;
825 tpoint->position.dy += position->dy;
827 numtoadd--;
828 if (numtoadd <= 0)
829 break;
831 tpoint++;
835 static void draw_and_move_trail_blaze(void)
837 struct TrailPoint* tpoint;
838 int n;
840 /* loop through, if alive then move and draw.
841 when drawn, countdown it's timer.
842 if zero kill it! */
844 tpoint = trail_points;
845 n = NUM_TRAIL_POINTS;
846 while (n--)
848 if (tpoint->alive > 0)
850 if (game_state != PAUSE_MODE)
852 tpoint->alive--;
853 move_point(&(tpoint->position));
854 #ifdef HAVE_LCD_COLOR
855 /* intensity = tpoint->alive/2; */
856 if (tpoint->r >= tpoint->dec) tpoint->r -= tpoint->dec;
857 if (tpoint->g >= tpoint->dec) tpoint->g -= tpoint->dec;
858 if (tpoint->b >= tpoint->dec) tpoint->b -= tpoint->dec;
859 #endif
861 SET_FG(LCD_RGBPACK(tpoint->r, tpoint->g, tpoint->b));
862 rb->lcd_drawpixel(tpoint->position.x/SCALE, tpoint->position.y/SCALE);
864 tpoint++;
868 /*************************************************
869 ** Handle asteroid.
870 *************************************************/
872 static void rotate_asteroid(struct Asteroid* asteroid)
874 rotate_polygon(asteroid->vertices, NUM_ASTEROID_VERTICES,
875 &asteroid->rotation,
876 asteroid->speed_cos, asteroid->speed_sin);
879 /* Initialise the passed Asteroid.
880 * if position is NULL, place it at the random loacation
881 * where ship doesn't exist
883 static void initialise_asteroid(struct Asteroid* asteroid,
884 enum asteroid_type type, struct Point *position)
886 const short *asteroid_vertices;
887 struct Point* point;
888 int n;
890 asteroid->exists = true;
891 asteroid->explode_countdown = 0;
892 asteroid->type = type;
894 /* Set the radius of the asteroid: */
895 asteroid->radius = (int)type*SCALE*3;
897 /* shall we move Clockwise and Fast */
898 n = rb->rand()%100;
899 if (n < 25)
901 asteroid->speed_cos = FAST_ROT_CW_COS;
902 asteroid->speed_sin = FAST_ROT_CW_SIN;
904 else if (n < 50)
906 asteroid->speed_cos = FAST_ROT_ACW_COS;
907 asteroid->speed_sin = FAST_ROT_ACW_SIN;
909 else if (n < 75)
911 asteroid->speed_cos = SLOW_ROT_ACW_COS;
912 asteroid->speed_sin = SLOW_ROT_ACW_SIN;
914 else
916 asteroid->speed_cos = SLOW_ROT_CW_COS;
917 asteroid->speed_sin = SLOW_ROT_CW_SIN;
920 n = rb->rand()%99;
921 if (n < 33)
922 asteroid_vertices = asteroid_one;
923 else if (n < 66)
924 asteroid_vertices = asteroid_two;
925 else
926 asteroid_vertices = asteroid_three;
928 point = asteroid->vertices;
929 for(n = 0; n < NUM_ASTEROID_VERTICES*2; n += 2)
931 point->x = asteroid_vertices[n];
932 point->y = asteroid_vertices[n+1];
933 point->x *= asteroid->radius/20;
934 point->y *= asteroid->radius/20;
935 /* dx and dy are used when rotate polygon */
936 point->dx = point->x;
937 point->dy = point->y;
938 point++;
941 if (!position)
943 do {
944 /* Set the position randomly: */
945 asteroid->position.x = (rb->rand()%SCALED_WIDTH);
946 asteroid->position.y = (rb->rand()%SCALED_HEIGHT);
947 } while (is_point_within_rectangle(&ship.position, &asteroid->position,
948 SPACE_CHECK_SIZE));
950 else
952 asteroid->position.x = position->x;
953 asteroid->position.y = position->y;
956 do {
957 asteroid->position.dx = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
958 } while (asteroid->position.dx == 0);
960 do {
961 asteroid->position.dy = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
962 } while (asteroid->position.dy == 0);
964 asteroid->position.dx *= SCALE/10;
965 asteroid->position.dy *= SCALE/10;
967 asteroid->rotation.x = SIN_COS_SCALE;
968 asteroid->rotation.y = 0;
970 /* Now rotate the asteroid a bit, so they all look a bit different */
971 for(n = (rb->rand()%30)+2; n--; )
972 rotate_asteroid(asteroid);
974 /* great, we've created an asteroid, don't forget to increment the total: */
975 asteroid_count++;
979 * Creates a new asteroid of the given 4type (size) and at the given location.
981 static void create_asteroid(enum asteroid_type type, struct Point *position)
983 struct Asteroid* asteroid;
984 int n;
986 asteroid = asteroids_array;
987 n = MAX_NUM_ASTEROIDS;
988 while (n--)
990 if (!asteroid->exists && asteroid->explode_countdown <= 0)
992 initialise_asteroid(asteroid, type, position);
993 break;
995 asteroid++;
999 /* Draw and move all asteroids */
1000 static void draw_and_move_asteroids(void)
1002 struct Asteroid* asteroid;
1003 int n;
1005 SET_FG(COL_ASTEROID);
1007 asteroid = asteroids_array;
1008 n = MAX_NUM_ASTEROIDS;
1009 while (n--)
1011 if (asteroid->exists)
1013 draw_polygon(asteroid->vertices, NUM_ASTEROID_VERTICES,
1014 asteroid->position.x, asteroid->position.y);
1016 if (game_state != PAUSE_MODE)
1018 if (asteroid->exists)
1020 move_point(&asteroid->position);
1021 rotate_asteroid(asteroid);
1023 else if (asteroid->explode_countdown > 0)
1025 asteroid->explode_countdown--;
1028 asteroid++;
1032 static void explode_asteroid(struct Asteroid* asteroid)
1034 struct Point p;
1035 p.dx = asteroid->position.dx;
1036 p.dy = asteroid->position.dy;
1037 p.x = asteroid->position.x;
1038 p.y = asteroid->position.y;
1040 asteroid_count--;
1041 asteroid->exists = false;
1043 switch(asteroid->type)
1045 case SMALL:
1046 asteroid->explode_countdown = EXPLOSION_LENGTH;
1047 create_trail_blaze(EXPLOSION_ASTEROID, &p);
1048 break;
1050 case MEDIUM:
1051 create_asteroid(SMALL, &p);
1052 create_asteroid(SMALL, &p);
1053 break;
1055 case LARGE:
1056 create_asteroid(MEDIUM, &p);
1057 create_asteroid(MEDIUM, &p);
1058 break;
1062 /*************************************************
1063 ** Handle ship.
1064 *************************************************/
1066 /* Initialise the ship */
1067 static void initialise_ship(void)
1069 struct Point* point;
1070 struct Point* lives_point;
1071 int n;
1073 ship.position.x = CENTER_LCD_X * SCALE;
1074 ship.position.y = CENTER_LCD_Y * SCALE;
1075 ship.position.dx = 0;
1076 ship.position.dy = 0;
1077 ship.rotation.x = SIN_COS_SCALE;
1078 ship.rotation.y = 0;
1079 ship.exists = true;
1080 ship.explode_countdown = 0;
1081 ship.invulnerable_time = INVULNERABLE_TIME;
1083 point = ship.vertices;
1084 lives_point = lives_points;
1085 for(n = 0; n < NUM_SHIP_VERTICES*2; n += 2)
1087 point->x = ship_vertices[n];
1088 point->y = ship_vertices[n+1];
1089 point->x *= SCALE;
1090 point->y *= SCALE;
1091 /* dx and dy are used when rotate polygon */
1092 point->dx = point->x;
1093 point->dy = point->y;
1094 /* grab a copy of the ships points for the lives display: */
1095 lives_point->x = point->x;
1096 lives_point->y = point->y;
1098 point++;
1099 lives_point++;
1104 * Draws the ship, moves the ship and creates a new
1105 * one if it's finished exploding.
1107 static void draw_and_move_ship(void)
1109 if (ship.invulnerable_time > BLINK_TIME || ship.invulnerable_time % 2 != 0)
1111 SET_FG(COL_INVULN);
1113 else
1115 SET_FG(COL_PLAYER);
1118 if (ship.exists)
1120 draw_polygon(ship.vertices, NUM_SHIP_VERTICES,
1121 ship.position.x, ship.position.y);
1124 if (game_state != PAUSE_MODE)
1126 if (ship.exists)
1128 if (ship.invulnerable_time > 0)
1129 ship.invulnerable_time--;
1130 move_point(&ship.position);
1132 else if (ship.explode_countdown > 0)
1134 ship.explode_countdown--;
1135 if (ship.explode_countdown <= 0)
1137 num_lives--;
1138 if (num_lives <= 0)
1140 game_state = GAME_OVER;
1142 else
1144 initialise_ship();
1151 static void explode_ship(void)
1153 if (!ship.invulnerable_time)
1155 /* if not invulnerable, blow up ship */
1156 ship.explode_countdown = EXPLOSION_LENGTH;
1157 ship.exists = false;
1158 create_trail_blaze(EXPLOSION_SHIP, &ship.position);
1162 /* Rotate the ship using the passed sin & cos values */
1163 static void rotate_ship(int cos, int sin)
1165 if (ship.exists)
1167 rotate_polygon(ship.vertices, NUM_SHIP_VERTICES,
1168 &ship.rotation, cos, sin);
1172 static void thrust_ship(void)
1174 if (ship.exists)
1176 ship.position.dx += ( ship.vertices[0].x - ship.vertices[2].x )/20;
1177 ship.position.dy += ( ship.vertices[0].y - ship.vertices[2].y )/20;
1179 /* if dx and dy are below a certain threshold, then set 'em to 0
1180 but to do this we need to ascertain if the spacehip as moved on
1181 screen for more than a certain amount. */
1183 create_trail_blaze(EXPLOSION_THRUST, &ship.position);
1187 /* stop movement of ship, 'cos that's what happens when you go into hyperspace. */
1188 static void hyperspace(void)
1190 if (ship.exists)
1192 ship.position.dx = ship.position.dy = 0;
1193 ship.position.x = (rb->rand()%SCALED_WIDTH);
1194 ship.position.y = (rb->rand()%SCALED_HEIGHT);
1198 static void draw_lives(void)
1200 int n;
1201 #if (LARGE_LCD)
1202 int px = (LCD_WIDTH-1 - 4)*SCALE;
1203 int py = (LCD_HEIGHT-1 - 6)*SCALE;
1204 #else
1205 int px = (LCD_WIDTH-1 - 3)*SCALE;
1206 int py = (LCD_HEIGHT-1 - 4)*SCALE;
1207 #endif
1209 SET_FG(COL_PLAYER);
1211 n = num_lives-1;
1212 while (n--)
1214 draw_polygon(lives_points, NUM_SHIP_VERTICES, px, py);
1215 #if (LARGE_LCD)
1216 px -= 8*SCALE;
1217 #else
1218 px -= 6*SCALE;
1219 #endif
1224 * missile
1227 /* Initialise a missile */
1228 static void initialise_missile(struct Missile* missile)
1230 missile->position.x = ship.position.x + ship.vertices[0].x;
1231 missile->position.y = ship.position.y + ship.vertices[0].y;
1232 missile->position.dx = (ship.vertices[0].x - ship.vertices[2].x)/2;
1233 missile->position.dy = (ship.vertices[0].y - ship.vertices[2].y)/2;
1234 missile->alive = MISSILE_LIFE_LENGTH;
1235 missile->oldpoint.x = missile->position.x;
1236 missile->oldpoint.y = missile->position.y;
1239 /* Fire the next missile */
1240 static void fire_missile(void)
1242 struct Missile* missile;
1243 int n;
1245 if (ship.exists)
1247 missile = missiles_array;
1248 n = MAX_NUM_MISSILES;
1249 while (n--)
1251 if (missile->alive <= 0)
1253 initialise_missile(missile);
1254 break;
1256 missile++;
1261 /* Draw and Move all the missiles */
1262 static void draw_and_move_missiles(void)
1264 struct Missile* missile;
1265 struct Point vertices[2];
1266 int n;
1268 SET_FG(COL_MISSILE);
1270 missile = missiles_array;
1271 n = MAX_NUM_MISSILES;
1272 while (n--)
1274 if (missile->alive > 0)
1276 vertices[0].x = 0;
1277 vertices[0].y = 0;
1278 vertices[1].x = -missile->position.dx;
1279 vertices[1].y = -missile->position.dy;
1280 draw_polygon(vertices, 2, missile->position.x, missile->position.y);
1282 if (game_state != PAUSE_MODE)
1284 missile->oldpoint.x = missile->position.x;
1285 missile->oldpoint.y = missile->position.y;
1286 move_point(&missile->position);
1287 missile->alive--;
1290 missile++;
1294 /*************************************************
1295 ** Handle enemy.
1296 *************************************************/
1298 static void initialise_enemy(void)
1300 struct Point* point;
1301 int n;
1302 int size;
1304 if (rb->rand()%100 > enemy.size_probability)
1306 size = BIG_SHIP;
1307 enemy.size_probability++;
1308 if (enemy.size_probability > 90)
1310 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
1313 else
1315 size = LITTLE_SHIP;
1316 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
1319 enemy.exists = true;
1320 enemy.explode_countdown = 0;
1321 enemy.appear_countdown = enemy.appear_timing;
1323 point = enemy.vertices;
1324 for(n = 0; n < NUM_ENEMY_VERTICES*2; n += 2)
1326 point->x = enemy_vertices[n];
1327 point->y = enemy_vertices[n+1];
1328 point->x *= size*SCALE/2;
1329 point->y *= size*SCALE/2;
1330 point++;
1333 if (ship.position.x >= SCALED_WIDTH/2)
1335 enemy.position.dx = ENEMY_SPEED;
1336 enemy.position.x = 0;
1338 else
1340 enemy.position.dx = -ENEMY_SPEED;
1341 enemy.position.x = SCALED_WIDTH;
1344 if (ship.position.y >= SCALED_HEIGHT/2)
1346 enemy.position.dy = ENEMY_SPEED;
1347 enemy.position.y = 0;
1349 else
1351 enemy.position.dy = -ENEMY_SPEED;
1352 enemy.position.y = SCALED_HEIGHT;
1355 enemy.position.dx *= SCALE/10;
1356 enemy.position.dy *= SCALE/10;
1359 static void draw_and_move_enemy(void)
1361 SET_FG(COL_ENEMY);
1363 if (enemy.exists)
1365 draw_polygon(enemy.vertices, NUM_ENEMY_VERTICES,
1366 enemy.position.x, enemy.position.y);
1369 if (game_state != PAUSE_MODE)
1371 if (enemy.exists)
1373 enemy.position.x += enemy.position.dx;
1374 enemy.position.y += enemy.position.dy;
1376 if (enemy.position.x > SCALED_WIDTH || enemy.position.x < 0)
1377 enemy.exists = false;
1379 enemy.position.y %= SCALED_HEIGHT;
1380 if (enemy.position.y < 0)
1381 enemy.position.y += SCALED_HEIGHT;
1383 if ((rb->rand()%1000) < 10)
1384 enemy.position.dy = -enemy.position.dy;
1386 else if (enemy.explode_countdown > 0)
1388 enemy.explode_countdown--;
1390 else
1392 if (enemy.appear_countdown > 0)
1393 enemy.appear_countdown--;
1394 else if (rb->rand()%100 >= enemy.appear_probability)
1395 initialise_enemy();
1399 if (enemy_missile.alive <= 0)
1401 /* if no missile and the enemy is here and not exploding..
1402 then shoot baby! */
1403 if (enemy.exists && ship.exists &&
1404 game_state == PLAY_MODE && (rb->rand()%10) >= 5 )
1406 int dx = ship.position.x - enemy.position.x;
1407 int dy = ship.position.y - enemy.position.y;
1409 if (dx < -SCALED_WIDTH/2) dx += SCALED_WIDTH;
1410 else if (dx > SCALED_WIDTH/2) dx -= SCALED_WIDTH;
1411 if (dy < -SCALED_HEIGHT/2) dy += SCALED_HEIGHT;
1412 else if (dy > SCALED_HEIGHT/2) dy -= SCALED_HEIGHT;
1414 enemy_missile.position.x = enemy.position.x;
1415 enemy_missile.position.y = enemy.position.y;
1417 /* lame, needs to be sorted - it's trying to shoot at the ship */
1418 if (dx < -5*SCALE)
1419 enemy_missile.position.dx = -1;
1420 else if (dx > 5*SCALE)
1421 enemy_missile.position.dx = 1;
1422 else
1423 enemy_missile.position.dx = 0;
1425 if (dy < -5*SCALE)
1426 enemy_missile.position.dy = -1;
1427 else if (dy > 5*SCALE)
1428 enemy_missile.position.dy = 1;
1429 else
1430 enemy_missile.position.dy = 0;
1432 while (enemy_missile.position.dx == 0 &&
1433 enemy_missile.position.dy == 0)
1435 enemy_missile.position.dx = rb->rand()%2-1;
1436 enemy_missile.position.dy = rb->rand()%2-1;
1439 enemy_missile.position.dx *= SCALE;
1440 enemy_missile.position.dy *= SCALE;
1441 enemy_missile.alive = ENEMY_MISSILE_LIFE_LENGTH;
1444 else
1446 rb->lcd_fillrect( enemy_missile.position.x/SCALE,
1447 enemy_missile.position.y/SCALE,
1448 POINT_SIZE, POINT_SIZE );
1449 if (game_state != PAUSE_MODE)
1451 move_point(&enemy_missile.position);
1452 enemy_missile.alive--;
1457 /*************************************************
1458 ** Check collisions.
1459 *************************************************/
1461 /* Add score if missile hit asteroid or enemy */
1462 static void add_score(int val)
1464 current_score += val;
1465 if (current_score >= extra_life)
1467 num_lives++;
1468 extra_life += EXTRA_LIFE;
1472 static bool is_point_within_asteroid(struct Asteroid* asteroid,
1473 struct Point* point)
1475 if (is_point_within_rectangle(&asteroid->position, point, asteroid->radius)
1476 && is_point_in_polygon(asteroid->vertices, NUM_ASTEROID_VERTICES,
1477 point->x - asteroid->position.x,
1478 point->y - asteroid->position.y))
1480 explode_asteroid(asteroid);
1481 return true;
1483 else
1484 return false;
1487 static bool is_point_within_ship(struct Point* point)
1489 if (is_point_within_rectangle(&ship.position, point, SIZE_SHIP_COLLISION)
1490 && is_point_in_polygon(ship.vertices, NUM_SHIP_VERTICES,
1491 point->x - ship.position.x,
1492 point->y - ship.position.y))
1494 return true;
1496 else
1497 return false;
1500 static bool is_point_within_enemy(struct Point* point)
1502 if (is_point_within_rectangle(&enemy.position, point, SIZE_ENEMY_COLLISION))
1504 add_score(5);
1505 enemy.explode_countdown = EXPLOSION_LENGTH;
1506 enemy.exists = false;
1507 create_trail_blaze(EXPLOSION_ENEMY, &enemy.position);
1508 return true;
1510 else
1511 return false;
1514 static bool is_ship_within_asteroid(struct Asteroid* asteroid)
1516 struct Point p;
1518 if (!is_point_within_rectangle(&asteroid->position, &ship.position,
1519 asteroid->radius+SIZE_SHIP_COLLISION))
1520 return false;
1522 p.x = ship.position.x + ship.vertices[0].x;
1523 p.y = ship.position.y + ship.vertices[0].y;
1524 if (is_point_within_asteroid(asteroid, &p))
1525 return true;
1527 p.x = ship.position.x + ship.vertices[1].x;
1528 p.y = ship.position.y + ship.vertices[1].y;
1529 if (is_point_within_asteroid(asteroid, &p))
1530 return true;
1532 p.x = ship.position.x + ship.vertices[3].x;
1533 p.y = ship.position.y + ship.vertices[3].y;
1534 if (is_point_within_asteroid(asteroid, &p))
1535 return true;
1537 return false;
1540 /* Check for collsions between the missiles and the asteroids and the ship */
1541 static void check_collisions(void)
1543 struct Missile* missile;
1544 struct Asteroid* asteroid;
1545 int m, n;
1546 bool asteroids_onscreen = false;
1548 asteroid = asteroids_array;
1549 m = MAX_NUM_ASTEROIDS;
1550 while (m--)
1552 /* if the asteroids exists then test missile collision: */
1553 if (asteroid->exists)
1555 missile = missiles_array;
1556 n = MAX_NUM_MISSILES;
1557 while (n--)
1559 /* if the missiles exists: */
1560 if (missile->alive > 0)
1562 /* has the missile hit the asteroid? */
1563 if (is_point_within_asteroid(asteroid, &missile->position) ||
1564 is_point_within_asteroid(asteroid, &missile->oldpoint))
1566 add_score(1);
1567 missile->alive = 0;
1568 break;
1571 missile++;
1574 /* now check collision with ship: */
1575 if (asteroid->exists && ship.exists)
1577 if (is_ship_within_asteroid(asteroid))
1579 add_score(1);
1580 explode_ship();
1584 /* has the enemy missile blown something up? */
1585 if (asteroid->exists && enemy_missile.alive > 0)
1587 if (is_point_within_asteroid(asteroid, &enemy_missile.position))
1589 enemy_missile.alive = 0;
1594 /* is an asteroid still exploding? */
1595 if (asteroid->explode_countdown > 0)
1596 asteroids_onscreen = true;
1598 asteroid++;
1601 /* now check collision between ship and enemy */
1602 if (enemy.exists && ship.exists)
1604 /* has the enemy collided with the ship? */
1605 if (is_point_within_enemy(&ship.position))
1607 explode_ship();
1608 create_trail_blaze(EXPLOSION_ENEMY, &enemy.position);
1611 if (enemy.exists)
1613 /* Now see if the enemy has been shot at by the ships missiles: */
1614 missile = missiles_array;
1615 n = MAX_NUM_MISSILES;
1616 while (n--)
1618 if (missile->alive > 0 &&
1619 is_point_within_enemy(&missile->position))
1621 missile->alive = 0;
1622 break;
1624 missile++;
1629 /* test collision with enemy missile and ship: */
1630 if (enemy_missile.alive > 0 && is_point_within_ship(&enemy_missile.position))
1632 explode_ship();
1633 enemy_missile.alive = 0;
1634 enemy_missile.position.x = enemy_missile.position.y = 0;
1637 /* if all asteroids cleared then start again: */
1638 if (asteroid_count == 0 && !asteroids_onscreen
1639 && !enemy.exists && enemy.explode_countdown <= 0)
1641 current_level++;
1642 if (current_level > MAX_LEVEL)
1643 current_level = START_LEVEL;
1644 enemy.appear_probability += 5;
1645 if (enemy.appear_probability >= 100)
1646 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1647 enemy.appear_timing -= 30;
1648 if (enemy.appear_timing < 30)
1649 enemy.appear_timing = 30;
1650 game_state = SHOW_LEVEL;
1651 show_level_timeout = SHOW_LEVEL_TIME;
1656 * stars
1659 static void create_stars(void)
1661 struct Point* p;
1662 int n;
1664 p = stars;
1665 n = NUM_STARS;
1666 while (n--)
1668 p->x = (rb->rand()%LCD_WIDTH);
1669 p->y = (rb->rand()%LCD_HEIGHT);
1670 p++;
1674 static void drawstars(void)
1676 struct Point* p;
1677 int n;
1679 SET_FG(COL_STARS);
1681 p = stars;
1682 n = NUM_STARS;
1683 while (n--)
1685 rb->lcd_drawpixel(p->x , p->y);
1686 p++;
1690 /*************************************************
1691 ** Creates start_num number of new asteroids of
1692 ** full size.
1693 **************************************************/
1694 static void initialise_level(int start_num)
1696 struct Asteroid* asteroid;
1697 struct Missile* missile;
1698 struct TrailPoint* tpoint;
1699 int n;
1700 asteroid_count = next_missile_count = next_thrust_count = 0;
1702 /* no enemy */
1703 enemy.exists = 0;
1704 enemy.explode_countdown = 0;
1705 enemy_missile.alive = 0;
1707 /* clear asteroids */
1708 asteroid = asteroids_array;
1709 n = MAX_NUM_ASTEROIDS;
1710 while (n--)
1712 asteroid->exists = false;
1713 asteroid++;
1716 /* make some LARGE asteroids */
1717 for(n = 0; n < start_num; n++)
1718 initialise_asteroid(&asteroids_array[n], LARGE, NULL);
1720 /* ensure all missiles are out of action: */
1721 missile = missiles_array;
1722 n = MAX_NUM_MISSILES;
1723 while (n--)
1725 missile->alive = 0;
1726 missile++;
1729 tpoint = trail_points;
1730 n = NUM_TRAIL_POINTS;
1731 while (n--)
1733 tpoint->alive = 0;
1734 tpoint++;
1738 static void initialise_game(void)
1740 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1741 enemy.appear_timing = ENEMY_APPEAR_TIMING_START;
1742 enemy.appear_countdown = enemy.appear_timing;
1743 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
1744 current_level = START_LEVEL;
1745 num_lives = START_LIVES;
1746 extra_life = EXTRA_LIFE;
1747 current_score = 0;
1748 initialise_ship();
1749 initialise_level(0);
1750 game_state = SHOW_LEVEL;
1751 show_level_timeout = SHOW_LEVEL_TIME;
1754 /* menu stuff */
1755 static bool spacerocks_help(void)
1757 static char *help_text[] = {
1758 "Spacerocks", "", "Aim", "",
1759 "The", "goal", "of", "the", "game", "is", "to", "blow", "up",
1760 "the", "asteroids", "and", "avoid", "being", "hit", "by", "them.",
1761 "Also", "you'd", "better", "watch", "out", "for", "the", "UFOs!"
1763 static struct style_text formation[]={
1764 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1765 { 2, C_RED },
1766 LAST_STYLE_ITEM
1769 rb->lcd_setfont(FONT_UI);
1770 SET_BG(LCD_BLACK);
1771 SET_FG(LCD_WHITE);
1772 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true))
1773 return true;
1774 rb->lcd_setfont(FONT_SYSFIXED);
1776 return false;
1779 #define PLUGIN_OTHER 10
1780 static bool ingame;
1781 static int spacerocks_menu_cb(int action, const struct menu_item_ex *this_item)
1783 if (action == ACTION_REQUEST_MENUITEM
1784 && !ingame && ((intptr_t)this_item)==0)
1785 return ACTION_EXIT_MENUITEM;
1786 return action;
1789 static int spacerocks_menu(void)
1791 int selection = 0;
1792 MENUITEM_STRINGLIST(main_menu, "Spacerocks Menu", spacerocks_menu_cb,
1793 "Resume Game", "Start New Game",
1794 "Help", "High Scores",
1795 "Playback Control", "Quit");
1796 rb->button_clear_queue();
1798 while (1)
1800 switch (rb->do_menu(&main_menu, &selection, NULL, false))
1802 case 0:
1803 return PLUGIN_OTHER;
1804 case 1:
1805 initialise_game();
1806 return PLUGIN_OTHER;
1807 case 2:
1808 if (spacerocks_help())
1809 return PLUGIN_USB_CONNECTED;
1810 break;
1811 case 3:
1812 highscore_show(-1, highscores, NUM_SCORES, true);
1813 break;
1814 case 4:
1815 playback_control(NULL);
1816 break;
1817 case 5:
1818 return PLUGIN_OK;
1819 case MENU_ATTACHED_USB:
1820 return PLUGIN_USB_CONNECTED;
1821 default:
1822 break;
1827 static int spacerocks_game_loop(void)
1829 char str[20];
1830 int button;
1831 int end;
1832 int position;
1833 int ret;
1835 if ((ret = spacerocks_menu()) != PLUGIN_OTHER)
1836 return ret;
1838 SET_BG(LCD_BLACK);
1840 ingame = true;
1841 while (true)
1843 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1844 rb->lcd_clear_display();
1845 SET_FG(COL_TEXT);
1846 switch(game_state)
1848 case GAME_OVER:
1849 ingame = false;
1850 rb->splash (HZ * 2, "Game Over");
1851 rb->lcd_clear_display();
1852 position = highscore_update(current_score, current_level, "",
1853 highscores, NUM_SCORES);
1854 if (position != -1)
1856 if (position == 0)
1857 rb->splash(HZ*2, "New High Score");
1858 highscore_show(position, highscores, NUM_SCORES, true);
1860 return PLUGIN_OTHER;
1861 break;
1863 case PAUSE_MODE:
1864 rb->snprintf(str, sizeof(str), "score %d ", current_score);
1865 rb->lcd_putsxy(1,LCD_HEIGHT-8, str);
1866 rb->lcd_putsxy(CENTER_LCD_X - 15,
1867 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "pause");
1868 draw_and_move_missiles();
1869 draw_lives();
1870 draw_and_move_ship();
1871 break;
1873 case PLAY_MODE:
1874 rb->snprintf(str, sizeof(str), "score %d ", current_score);
1875 rb->lcd_putsxy(1, LCD_HEIGHT-8, str);
1876 draw_and_move_missiles();
1877 draw_lives();
1878 check_collisions();
1879 draw_and_move_ship();
1880 break;
1882 case SHOW_LEVEL:
1883 rb->snprintf(str, sizeof(str), "score %d ", current_score);
1884 rb->lcd_putsxy(1, LCD_HEIGHT-8, str);
1885 rb->snprintf(str, sizeof(str), "stage %d ", current_level);
1886 rb->lcd_putsxy(CENTER_LCD_X - 20,
1887 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, str);
1888 draw_lives();
1889 draw_and_move_ship();
1890 show_level_timeout--;
1891 if (show_level_timeout <= 0)
1893 initialise_level(current_level);
1894 game_state = PLAY_MODE;
1896 break;
1898 draw_and_move_trail_blaze();
1899 drawstars();
1900 draw_and_move_asteroids();
1901 draw_and_move_enemy();
1903 rb->lcd_update();
1905 #ifdef HAS_BUTTON_HOLD
1906 if (rb->button_hold() && game_state == PLAY_MODE)
1907 game_state = PAUSE_MODE;
1908 #endif
1909 button = rb->button_get(false);
1910 switch(button)
1912 case(AST_QUIT):
1913 return PLUGIN_OTHER;
1914 break;
1915 #ifdef AST_PAUSE
1916 case(AST_PAUSE):
1917 if (game_state == PAUSE_MODE)
1918 game_state = PLAY_MODE;
1919 else if (game_state == PLAY_MODE)
1920 game_state = PAUSE_MODE;
1921 break;
1922 #endif
1923 case (AST_LEFT):
1924 case (AST_LEFT | BUTTON_REPEAT):
1925 if (game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1926 rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN);
1927 break;
1929 case (AST_RIGHT):
1930 case (AST_RIGHT | BUTTON_REPEAT):
1931 if (game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1932 rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN);
1933 break;
1935 case (AST_THRUST):
1936 case (AST_THRUST | BUTTON_REPEAT):
1937 if (game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1939 if (next_thrust_count <= 0)
1941 next_thrust_count = 5;
1942 thrust_ship();
1945 break;
1947 case (AST_HYPERSPACE):
1948 if (game_state == PLAY_MODE)
1949 hyperspace();
1950 /* maybe shield if it gets too hard */
1951 break;
1953 case (AST_FIRE):
1954 case (AST_FIRE | BUTTON_REPEAT):
1955 if (game_state == PLAY_MODE)
1957 if (next_missile_count <= 0)
1959 fire_missile();
1960 next_missile_count = 10;
1963 else if(game_state == PAUSE_MODE)
1964 game_state = PLAY_MODE;
1965 break;
1967 default:
1968 if (rb->default_event_handler(button)==SYS_USB_CONNECTED)
1969 return PLUGIN_USB_CONNECTED;
1970 break;
1973 if (next_missile_count > 0)
1974 next_missile_count--;
1976 if (next_thrust_count > 0)
1977 next_thrust_count--;
1979 if (TIME_BEFORE(*rb->current_tick, end))
1980 rb->sleep(end-*rb->current_tick);
1981 else
1982 rb->yield();
1986 enum plugin_status plugin_start(const void* parameter)
1988 (void)parameter;
1989 int ret = PLUGIN_OTHER;
1991 #if LCD_DEPTH > 1
1992 rb->lcd_set_backdrop(NULL);
1993 #endif
1994 /* universal font */
1995 rb->lcd_setfont(FONT_SYSFIXED);
1996 /* Turn off backlight timeout */
1997 backlight_force_on(); /* backlight control in lib/helper.c */
1998 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
1999 rb->srand(*rb->current_tick);
2001 /* create stars once, and once only: */
2002 create_stars();
2004 while (ret == PLUGIN_OTHER)
2005 ret = spacerocks_game_loop();
2007 rb->lcd_setfont(FONT_UI);
2008 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
2009 /* Turn on backlight timeout (revert to settings) */
2010 backlight_use_settings(); /* backlight control in lib/helper.c */
2012 return ret;