some changes to use of display_text.
[kugel-rb.git] / apps / plugins / spacerocks.c
blob055bd782290f9beea888e4f5da23e59d825d02cd
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 #else
233 #error No keymap defined!
234 #endif
236 #ifdef HAVE_TOUCHSCREEN
237 #ifndef AST_PAUSE
238 #define AST_PAUSE BUTTON_CENTER
239 #endif
240 #ifndef AST_QUIT
241 #define AST_QUIT BUTTON_TOPLEFT
242 #endif
243 #ifndef AST_THRUST
244 #define AST_THRUST BUTTON_TOPMIDDLE
245 #endif
246 #ifndef AST_HYPERSPACE
247 #define AST_HYPERSPACE BUTTON_TOPRIGHT
248 #endif
249 #ifndef AST_LEFT
250 #define AST_LEFT BUTTON_MIDLEFT
251 #endif
252 #ifndef AST_RIGHT
253 #define AST_RIGHT BUTTON_MIDRIGHT
254 #endif
255 #ifndef AST_FIRE
256 #define AST_FIRE BUTTON_BOTTOMMIDDLE
257 #endif
258 #endif
260 #define RES MAX(LCD_WIDTH, LCD_HEIGHT)
261 #define LARGE_LCD (RES >= 200)
263 #define CYCLETIME 30
265 #define SHOW_COL 0
266 #define SCALE 5000
267 #define WRAP_GAP (LARGE*SCALE*3)
268 #define POINT_SIZE 2
269 #define START_LEVEL 1
270 #define SHOW_LEVEL_TIME 50
271 #define EXPLOSION_LENGTH 20
273 #define MAX_NUM_ASTEROIDS 25
274 #define MAX_NUM_MISSILES 6
275 #define NUM_STARS 50
276 #define NUM_TRAIL_POINTS 70
277 #define MAX_LEVEL MAX_NUM_ASTEROIDS
279 #define NUM_ASTEROID_VERTICES 10
280 #define NUM_SHIP_VERTICES 4
281 #define NUM_ENEMY_VERTICES 8
283 #define INVULNERABLE_TIME 30
284 #define BLINK_TIME 10
285 #define EXTRA_LIFE 250
286 #define START_LIVES 3
287 #define MISSILE_LIFE_LENGTH 40
289 #define ASTEROID_SPEED (RES/20)
290 #define SPACE_CHECK_SIZE 30*SCALE
292 #if (LARGE_LCD)
293 #define SIZE_SHIP_COLLISION 8*SCALE
294 #else
295 #define SIZE_SHIP_COLLISION 6*SCALE
296 #endif
298 #define LITTLE_SHIP 1
299 #define BIG_SHIP 2
300 #define ENEMY_BIG_PROBABILITY_START 10
301 #define ENEMY_APPEAR_PROBABILITY_START 35
302 #define ENEMY_APPEAR_TIMING_START 600
303 #define ENEMY_SPEED 4
304 #define ENEMY_MISSILE_LIFE_LENGTH (RES/2)
305 #if (LARGE_LCD)
306 #define SIZE_ENEMY_COLLISION 7*SCALE
307 #else
308 #define SIZE_ENEMY_COLLISION 5*SCALE
309 #endif
311 #define SIN_COS_SCALE 10000
313 #define FAST_ROT_CW_SIN 873
314 #define FAST_ROT_CW_COS 9963
315 #define FAST_ROT_ACW_SIN -873
316 #define FAST_ROT_ACW_COS 9963
318 #define MEDIUM_ROT_CW_SIN 350
319 #define MEDIUM_ROT_CW_COS 9994
320 #define MEDIUM_ROT_ACW_SIN -350
321 #define MEDIUM_ROT_ACW_COS 9994
323 #define SLOW_ROT_CW_SIN 350
324 #define SLOW_ROT_CW_COS 9994
325 #define SLOW_ROT_ACW_SIN -350
326 #define SLOW_ROT_ACW_COS 9994
328 #ifdef HAVE_LCD_COLOR
329 #define SHIP_ROT_CW_SIN 2419
330 #define SHIP_ROT_CW_COS 9702
331 #define SHIP_ROT_ACW_SIN -2419
332 #define SHIP_ROT_ACW_COS 9702
333 #else
334 #define SHIP_ROT_CW_SIN 3827
335 #define SHIP_ROT_CW_COS 9239
336 #define SHIP_ROT_ACW_SIN -3827
337 #define SHIP_ROT_ACW_COS 9239
338 #endif
341 #define SCALED_WIDTH (LCD_WIDTH*SCALE)
342 #define SCALED_HEIGHT (LCD_HEIGHT*SCALE)
343 #define CENTER_LCD_X (LCD_WIDTH/2)
344 #define CENTER_LCD_Y (LCD_HEIGHT/2)
346 #ifdef HAVE_LCD_COLOR
347 #define ASTEROID_R 230
348 #define ASTEROID_G 200
349 #define ASTEROID_B 100
350 #define SHIP_R 255
351 #define SHIP_G 255
352 #define SHIP_B 255
353 #define ENEMY_R 50
354 #define ENEMY_G 220
355 #define ENEMY_B 50
356 #define THRUST_R 200
357 #define THRUST_G 200
358 #define THRUST_B 0
360 #define COL_MISSILE LCD_RGBPACK(200,0,0)
361 #define COL_PLAYER LCD_RGBPACK(200,200,200)
362 #define COL_INVULN LCD_RGBPACK(100,100,200)
363 #define COL_STARS LCD_WHITE
364 #define COL_ASTEROID LCD_RGBPACK(ASTEROID_R,ASTEROID_G,ASTEROID_B)
365 #define COL_TEXT LCD_RGBPACK(200,200,255)
366 #define COL_ENEMY LCD_RGBPACK(ENEMY_R,ENEMY_G,ENEMY_B)
367 #define SET_FG rb->lcd_set_foreground
368 #define SET_BG rb->lcd_set_background
369 #else
370 #define SET_FG(x)
371 #define SET_BG(x)
372 #endif
374 #define HIGH_SCORE PLUGIN_GAMES_DIR "/spacerocks.score"
375 #define NUM_SCORES 5
377 static struct highscore highscores[NUM_SCORES];
379 /* The array of points that make up an asteroid */
380 static const short asteroid_one[NUM_ASTEROID_VERTICES*2] =
382 -2, -12,
383 4, -8,
384 8, -14,
385 16, -5,
386 14, 0,
387 20, 2,
388 12, 14,
389 -4, 14,
390 -10, 6,
391 -10, -8,
394 /* The array of points that make up an asteroid */
395 static const short asteroid_two[NUM_ASTEROID_VERTICES*2] =
397 -2, -12,
398 4, -16,
399 6, -14,
400 16, -8,
401 14, 0,
402 20, 2,
403 12, 14,
404 -4, 14,
405 -10, 6,
406 -10, -8,
409 /* The array of points that make up an asteroid */
410 static const short asteroid_three[NUM_ASTEROID_VERTICES*2] =
412 -2, -12,
413 4, -16,
414 6, -14,
415 2, -8,
416 14, 0,
417 20, 2,
418 12, 14,
419 -4, 14,
420 -16, 6,
421 -10, -8,
424 /* The array of points the make up the ship */
425 static const short ship_vertices[NUM_SHIP_VERTICES*2] =
427 #if (LARGE_LCD)
428 0, -6,
429 4, 6,
430 0, 2,
431 -4, 6,
432 #else
433 0, -4,
434 3, 4,
435 0, 1,
436 -3, 4,
437 #endif
440 /* The array of points the make up the bad spaceship */
441 static const short enemy_vertices[NUM_ENEMY_VERTICES*2] =
443 #if (LARGE_LCD)
444 -8, 0,
445 -4, 4,
446 4, 4,
447 8, 0,
448 -8, 0,
449 8, 0,
450 4, -4,
451 -4, -4,
452 #else
453 -5, 0,
454 -2, 2,
455 2, 2,
456 5, 0,
457 -5, 0,
458 5, 0,
459 2, -2,
460 -2, -2,
461 #endif
464 enum asteroid_type
466 #if (LARGE_LCD)
467 SMALL = 2,
468 MEDIUM = 4,
469 LARGE = 6,
470 #else
471 SMALL = 1,
472 MEDIUM = 2,
473 LARGE = 3,
474 #endif
477 enum explosion_type
479 EXPLOSION_SHIP,
480 EXPLOSION_ASTEROID,
481 EXPLOSION_ENEMY,
482 EXPLOSION_THRUST,
485 enum game_state
487 GAME_OVER,
488 SHOW_LEVEL,
489 PLAY_MODE,
490 PAUSE_MODE,
493 struct Point
495 int x;
496 int y;
497 int dx;
498 int dy;
501 struct TrailPoint
503 struct Point position;
504 int alive;
505 #ifdef HAVE_LCD_COLOR
506 short r;
507 short g;
508 short b;
509 short dec;
510 #endif
513 /* Asteroid structure, contains an array of points */
514 struct Asteroid
516 struct Point position;
517 struct Point rotation;
518 struct Point vertices[NUM_ASTEROID_VERTICES];
519 bool exists;
520 int explode_countdown;
521 enum asteroid_type type;
522 int radius;
523 long speed_cos;
524 long speed_sin;
527 struct Ship
529 struct Point position;
530 struct Point rotation;
531 struct Point vertices[NUM_SHIP_VERTICES];
532 bool exists;
533 int explode_countdown;
534 int invulnerable_time;
537 struct Enemy
539 struct Point position;
540 struct Point vertices[NUM_ENEMY_VERTICES];
541 bool exists;
542 int explode_countdown;
543 int appear_countdown;
544 short size_probability;
545 short appear_probability;
546 short appear_timing;
549 struct Missile
551 struct Point position;
552 struct Point oldpoint;
553 int alive;
556 static enum game_state game_state;
557 static int asteroid_count;
558 static int next_missile_count;
559 static int next_thrust_count;
560 static int num_lives;
561 static int extra_life;
562 static int show_level_timeout;
563 static int current_level;
564 static int current_score;
566 static struct Ship ship;
567 static struct Point stars[NUM_STARS];
568 static struct Asteroid asteroids_array[MAX_NUM_ASTEROIDS];
569 static struct Missile missiles_array[MAX_NUM_MISSILES];
570 static struct Missile enemy_missile;
571 static struct Enemy enemy;
572 static struct Point lives_points[NUM_SHIP_VERTICES];
573 static struct TrailPoint trail_points[NUM_TRAIL_POINTS];
575 /*************************************************
576 ** Handle polygon and point
577 *************************************************/
579 /* Check if point is in a polygon */
580 static bool is_point_in_polygon(struct Point* vertices, int num_vertices,
581 int x, int y)
583 struct Point* pi;
584 struct Point* pj;
585 int n;
586 bool c = false;
588 if (x < -SCALED_WIDTH/2) x += SCALED_WIDTH;
589 else if (x > SCALED_WIDTH/2) x -= SCALED_WIDTH;
590 if (y < -SCALED_HEIGHT/2) y += SCALED_HEIGHT;
591 else if (y > SCALED_HEIGHT/2) y -= SCALED_HEIGHT;
593 pi = vertices;
594 pj = vertices + num_vertices-1;
596 n = num_vertices;
597 while (n--)
599 if ((((pi->y <= y) && (y < pj->y)) || ((pj->y <= y) && (y < pi->y))) &&
600 (x < (pj->x - pi->x) * (y - pi->y) / (pj->y - pi->y) + pi->x))
601 c = !c;
603 pj = pi;
604 pi++;
607 return c;
610 /* Check if point is within a rectangle */
611 static bool is_point_within_rectangle(struct Point* rect, struct Point* p,
612 int size)
614 int dx = p->x - rect->x;
615 int dy = p->y - rect->y;
616 #if SHOW_COL
617 rb->lcd_drawrect((rect->x - size)/SCALE, (rect->y - size)/SCALE,
618 (size*2+1)/SCALE, (size*2+1)/SCALE);
619 #endif
620 if (dx < -SCALED_WIDTH/2) dx += SCALED_WIDTH;
621 else if (dx > SCALED_WIDTH/2) dx -= SCALED_WIDTH;
622 if (dy < -SCALED_HEIGHT/2) dy += SCALED_HEIGHT;
623 else if (dy > SCALED_HEIGHT/2) dy -= SCALED_HEIGHT;
624 return (dx > -size && dx < size && dy > -size && dy < size);
627 /* Rotate polygon */
628 static void rotate_polygon(struct Point* vertices, int num_vertices,
629 struct Point* rotation, int cos, int sin)
631 struct Point* point;
632 int n;
633 long temp_x, temp_y;
635 temp_x = rotation->x;
636 temp_y = rotation->y;
637 rotation->x = (temp_x*cos - temp_y*sin)/SIN_COS_SCALE;
638 rotation->y = (temp_y*cos + temp_x*sin)/SIN_COS_SCALE;
639 #define MIN_SCALE (SIN_COS_SCALE-10)
640 #define MAX_SCALE (SIN_COS_SCALE+10)
641 /* normalize vector. this is not accurate but would be enough. */
642 temp_x = rotation->x*rotation->x + rotation->y*rotation->y;
643 if (temp_x <= MIN_SCALE*MIN_SCALE)
645 rotation->x = rotation->x*SIN_COS_SCALE/MIN_SCALE;
646 rotation->y = rotation->y*SIN_COS_SCALE/MIN_SCALE;
648 else if (temp_x >= MAX_SCALE*MAX_SCALE)
650 rotation->x = rotation->x*SIN_COS_SCALE/MAX_SCALE;
651 rotation->y = rotation->y*SIN_COS_SCALE/MAX_SCALE;
653 #undef MIN_SCALE
654 #undef MAX_SCALE
656 point = vertices;
657 n = num_vertices;
658 while (n--)
660 point->x = (point->dx*rotation->x - point->dy*rotation->y)/SIN_COS_SCALE;
661 point->y = (point->dy*rotation->x + point->dx*rotation->y)/SIN_COS_SCALE;
662 point++;
666 /* Draw polygon */
667 static void draw_polygon(struct Point* vertices, int num_vertices,
668 int px, int py)
670 int n, new_x, new_y, old_x, old_y;
671 struct Point *p;
672 bool draw_wrap;
674 if (px > SCALED_WIDTH - WRAP_GAP)
675 px -= SCALED_WIDTH;
676 if (py > SCALED_HEIGHT - WRAP_GAP)
677 py -= SCALED_HEIGHT;
679 draw_wrap = (px < WRAP_GAP || py < WRAP_GAP);
681 p = vertices + num_vertices - 1;
682 old_x = (p->x + px)/SCALE;
683 old_y = (p->y + py)/SCALE;
684 p = vertices;
685 n = num_vertices;
686 while (n--)
688 new_x = (p->x + px)/SCALE;
689 new_y = (p->y + py)/SCALE;
691 rb->lcd_drawline(old_x, old_y, new_x, new_y);
692 if (draw_wrap)
694 rb->lcd_drawline(old_x + LCD_WIDTH, old_y, new_x + LCD_WIDTH, new_y);
695 rb->lcd_drawline(old_x, old_y + LCD_HEIGHT, new_x, new_y + LCD_HEIGHT);
696 rb->lcd_drawline(old_x + LCD_WIDTH, old_y + LCD_HEIGHT,
697 new_x + LCD_WIDTH, new_y + LCD_HEIGHT);
699 old_x = new_x;
700 old_y = new_y;
701 p++;
705 static void move_point(struct Point* point)
707 point->x += point->dx;
708 point->y += point->dy;
710 /* Check bounds on the x-axis: */
711 point->x %= SCALED_WIDTH;
712 if (point->x < 0)
713 point->x += SCALED_WIDTH;
715 /* Check bounds on the y-axis: */
716 point->y %= SCALED_HEIGHT;
717 if (point->y < 0)
718 point->y += SCALED_HEIGHT;
721 /*************************************************
722 ** Handle trail blaiz.
723 *************************************************/
725 static void create_ship_trail(struct TrailPoint* tpoint)
727 tpoint->position.x += ship.vertices[2].x;
728 tpoint->position.y += ship.vertices[2].y;
729 tpoint->position.dx = -( ship.vertices[0].x - ship.vertices[2].x )/10;
730 tpoint->position.dy = -( ship.vertices[0].y - ship.vertices[2].y )/10;
733 static void create_explosion_trail(struct TrailPoint* tpoint)
735 tpoint->position.dx = (rb->rand()%5001)-2500;
736 tpoint->position.dy = (rb->rand()%5001)-2500;
739 static void create_trail_blaze(int colour, struct Point* position)
741 int numtoadd;
742 struct TrailPoint* tpoint;
743 int n;
745 if (colour != EXPLOSION_SHIP)
747 numtoadd = NUM_TRAIL_POINTS/5;
749 else
751 numtoadd = NUM_TRAIL_POINTS/8;
754 /* give the point a random countdown timer, so they dissapears at different
755 times */
756 tpoint = trail_points;
757 n = NUM_TRAIL_POINTS;
758 while (n--)
760 /* find a space in the array of trail_points that is NULL or DEAD or
761 whatever and place this one here. */
762 if (tpoint->alive <= 0)
764 /* take a random point near the position. */
765 tpoint->position.x = (rb->rand()%18000)-9000 + position->x;
766 tpoint->position.y = (rb->rand()%18000)-9000 + position->y;
768 switch(colour)
770 case EXPLOSION_SHIP:
771 create_explosion_trail(tpoint);
772 tpoint->alive = 51;
773 #ifdef HAVE_LCD_COLOR
774 tpoint->r = SHIP_R;
775 tpoint->g = SHIP_G;
776 tpoint->b = SHIP_B;
777 tpoint->dec = 2;
778 #endif
779 break;
780 case EXPLOSION_ASTEROID:
781 create_explosion_trail(tpoint);
782 tpoint->alive = 51;
783 #ifdef HAVE_LCD_COLOR
784 tpoint->r = ASTEROID_R;
785 tpoint->g = ASTEROID_G;
786 tpoint->b = ASTEROID_B;
787 tpoint->dec = 2;
788 #endif
789 break;
790 case EXPLOSION_ENEMY:
791 create_explosion_trail(tpoint);
792 tpoint->alive = 51;
793 #ifdef HAVE_LCD_COLOR
794 tpoint->r = ENEMY_R;
795 tpoint->g = ENEMY_G;
796 tpoint->b = ENEMY_B;
797 tpoint->dec = 2;
798 #endif
799 break;
800 case EXPLOSION_THRUST:
801 create_ship_trail(tpoint);
802 tpoint->alive = 17;
803 #ifdef HAVE_LCD_COLOR
804 tpoint->r = THRUST_R;
805 tpoint->g = THRUST_G;
806 tpoint->b = THRUST_B;
807 tpoint->dec = 4;
808 #endif
809 break;
812 /* give the points a speed based on direction of travel
813 - i.e. opposite */
814 tpoint->position.dx += position->dx;
815 tpoint->position.dy += position->dy;
817 numtoadd--;
818 if (numtoadd <= 0)
819 break;
821 tpoint++;
825 static void draw_and_move_trail_blaze(void)
827 struct TrailPoint* tpoint;
828 int n;
830 /* loop through, if alive then move and draw.
831 when drawn, countdown it's timer.
832 if zero kill it! */
834 tpoint = trail_points;
835 n = NUM_TRAIL_POINTS;
836 while (n--)
838 if (tpoint->alive > 0)
840 if (game_state != PAUSE_MODE)
842 tpoint->alive--;
843 move_point(&(tpoint->position));
844 #ifdef HAVE_LCD_COLOR
845 /* intensity = tpoint->alive/2; */
846 if (tpoint->r >= tpoint->dec) tpoint->r -= tpoint->dec;
847 if (tpoint->g >= tpoint->dec) tpoint->g -= tpoint->dec;
848 if (tpoint->b >= tpoint->dec) tpoint->b -= tpoint->dec;
849 #endif
851 SET_FG(LCD_RGBPACK(tpoint->r, tpoint->g, tpoint->b));
852 rb->lcd_drawpixel(tpoint->position.x/SCALE, tpoint->position.y/SCALE);
854 tpoint++;
858 /*************************************************
859 ** Handle asteroid.
860 *************************************************/
862 static void rotate_asteroid(struct Asteroid* asteroid)
864 rotate_polygon(asteroid->vertices, NUM_ASTEROID_VERTICES,
865 &asteroid->rotation,
866 asteroid->speed_cos, asteroid->speed_sin);
869 /* Initialise the passed Asteroid.
870 * if position is NULL, place it at the random loacation
871 * where ship doesn't exist
873 static void initialise_asteroid(struct Asteroid* asteroid,
874 enum asteroid_type type, struct Point *position)
876 const short *asteroid_vertices;
877 struct Point* point;
878 int n;
880 asteroid->exists = true;
881 asteroid->explode_countdown = 0;
882 asteroid->type = type;
884 /* Set the radius of the asteroid: */
885 asteroid->radius = (int)type*SCALE*3;
887 /* shall we move Clockwise and Fast */
888 n = rb->rand()%100;
889 if (n < 25)
891 asteroid->speed_cos = FAST_ROT_CW_COS;
892 asteroid->speed_sin = FAST_ROT_CW_SIN;
894 else if (n < 50)
896 asteroid->speed_cos = FAST_ROT_ACW_COS;
897 asteroid->speed_sin = FAST_ROT_ACW_SIN;
899 else if (n < 75)
901 asteroid->speed_cos = SLOW_ROT_ACW_COS;
902 asteroid->speed_sin = SLOW_ROT_ACW_SIN;
904 else
906 asteroid->speed_cos = SLOW_ROT_CW_COS;
907 asteroid->speed_sin = SLOW_ROT_CW_SIN;
910 n = rb->rand()%99;
911 if (n < 33)
912 asteroid_vertices = asteroid_one;
913 else if (n < 66)
914 asteroid_vertices = asteroid_two;
915 else
916 asteroid_vertices = asteroid_three;
918 point = asteroid->vertices;
919 for(n = 0; n < NUM_ASTEROID_VERTICES*2; n += 2)
921 point->x = asteroid_vertices[n];
922 point->y = asteroid_vertices[n+1];
923 point->x *= asteroid->radius/20;
924 point->y *= asteroid->radius/20;
925 /* dx and dy are used when rotate polygon */
926 point->dx = point->x;
927 point->dy = point->y;
928 point++;
931 if (!position)
933 do {
934 /* Set the position randomly: */
935 asteroid->position.x = (rb->rand()%SCALED_WIDTH);
936 asteroid->position.y = (rb->rand()%SCALED_HEIGHT);
937 } while (is_point_within_rectangle(&ship.position, &asteroid->position,
938 SPACE_CHECK_SIZE));
940 else
942 asteroid->position.x = position->x;
943 asteroid->position.y = position->y;
946 do {
947 asteroid->position.dx = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
948 } while (asteroid->position.dx == 0);
950 do {
951 asteroid->position.dy = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
952 } while (asteroid->position.dy == 0);
954 asteroid->position.dx *= SCALE/10;
955 asteroid->position.dy *= SCALE/10;
957 asteroid->rotation.x = SIN_COS_SCALE;
958 asteroid->rotation.y = 0;
960 /* Now rotate the asteroid a bit, so they all look a bit different */
961 for(n = (rb->rand()%30)+2; n--; )
962 rotate_asteroid(asteroid);
964 /* great, we've created an asteroid, don't forget to increment the total: */
965 asteroid_count++;
969 * Creates a new asteroid of the given 4type (size) and at the given location.
971 static void create_asteroid(enum asteroid_type type, struct Point *position)
973 struct Asteroid* asteroid;
974 int n;
976 asteroid = asteroids_array;
977 n = MAX_NUM_ASTEROIDS;
978 while (n--)
980 if (!asteroid->exists && asteroid->explode_countdown <= 0)
982 initialise_asteroid(asteroid, type, position);
983 break;
985 asteroid++;
989 /* Draw and move all asteroids */
990 static void draw_and_move_asteroids(void)
992 struct Asteroid* asteroid;
993 int n;
995 SET_FG(COL_ASTEROID);
997 asteroid = asteroids_array;
998 n = MAX_NUM_ASTEROIDS;
999 while (n--)
1001 if (asteroid->exists)
1003 draw_polygon(asteroid->vertices, NUM_ASTEROID_VERTICES,
1004 asteroid->position.x, asteroid->position.y);
1006 if (game_state != PAUSE_MODE)
1008 if (asteroid->exists)
1010 move_point(&asteroid->position);
1011 rotate_asteroid(asteroid);
1013 else if (asteroid->explode_countdown > 0)
1015 asteroid->explode_countdown--;
1018 asteroid++;
1022 static void explode_asteroid(struct Asteroid* asteroid)
1024 struct Point p;
1025 p.dx = asteroid->position.dx;
1026 p.dy = asteroid->position.dy;
1027 p.x = asteroid->position.x;
1028 p.y = asteroid->position.y;
1030 asteroid_count--;
1031 asteroid->exists = false;
1033 switch(asteroid->type)
1035 case SMALL:
1036 asteroid->explode_countdown = EXPLOSION_LENGTH;
1037 create_trail_blaze(EXPLOSION_ASTEROID, &p);
1038 break;
1040 case MEDIUM:
1041 create_asteroid(SMALL, &p);
1042 create_asteroid(SMALL, &p);
1043 break;
1045 case LARGE:
1046 create_asteroid(MEDIUM, &p);
1047 create_asteroid(MEDIUM, &p);
1048 break;
1052 /*************************************************
1053 ** Handle ship.
1054 *************************************************/
1056 /* Initialise the ship */
1057 static void initialise_ship(void)
1059 struct Point* point;
1060 struct Point* lives_point;
1061 int n;
1063 ship.position.x = CENTER_LCD_X * SCALE;
1064 ship.position.y = CENTER_LCD_Y * SCALE;
1065 ship.position.dx = 0;
1066 ship.position.dy = 0;
1067 ship.rotation.x = SIN_COS_SCALE;
1068 ship.rotation.y = 0;
1069 ship.exists = true;
1070 ship.explode_countdown = 0;
1071 ship.invulnerable_time = INVULNERABLE_TIME;
1073 point = ship.vertices;
1074 lives_point = lives_points;
1075 for(n = 0; n < NUM_SHIP_VERTICES*2; n += 2)
1077 point->x = ship_vertices[n];
1078 point->y = ship_vertices[n+1];
1079 point->x *= SCALE;
1080 point->y *= SCALE;
1081 /* dx and dy are used when rotate polygon */
1082 point->dx = point->x;
1083 point->dy = point->y;
1084 /* grab a copy of the ships points for the lives display: */
1085 lives_point->x = point->x;
1086 lives_point->y = point->y;
1088 point++;
1089 lives_point++;
1094 * Draws the ship, moves the ship and creates a new
1095 * one if it's finished exploding.
1097 static void draw_and_move_ship(void)
1099 if (ship.invulnerable_time > BLINK_TIME || ship.invulnerable_time % 2 != 0)
1101 SET_FG(COL_INVULN);
1103 else
1105 SET_FG(COL_PLAYER);
1108 if (ship.exists)
1110 draw_polygon(ship.vertices, NUM_SHIP_VERTICES,
1111 ship.position.x, ship.position.y);
1114 if (game_state != PAUSE_MODE)
1116 if (ship.exists)
1118 if (ship.invulnerable_time > 0)
1119 ship.invulnerable_time--;
1120 move_point(&ship.position);
1122 else if (ship.explode_countdown > 0)
1124 ship.explode_countdown--;
1125 if (ship.explode_countdown <= 0)
1127 num_lives--;
1128 if (num_lives <= 0)
1130 game_state = GAME_OVER;
1132 else
1134 initialise_ship();
1141 static void explode_ship(void)
1143 if (!ship.invulnerable_time)
1145 /* if not invulnerable, blow up ship */
1146 ship.explode_countdown = EXPLOSION_LENGTH;
1147 ship.exists = false;
1148 create_trail_blaze(EXPLOSION_SHIP, &ship.position);
1152 /* Rotate the ship using the passed sin & cos values */
1153 static void rotate_ship(int cos, int sin)
1155 if (ship.exists)
1157 rotate_polygon(ship.vertices, NUM_SHIP_VERTICES,
1158 &ship.rotation, cos, sin);
1162 static void thrust_ship(void)
1164 if (ship.exists)
1166 ship.position.dx += ( ship.vertices[0].x - ship.vertices[2].x )/20;
1167 ship.position.dy += ( ship.vertices[0].y - ship.vertices[2].y )/20;
1169 /* if dx and dy are below a certain threshold, then set 'em to 0
1170 but to do this we need to ascertain if the spacehip as moved on
1171 screen for more than a certain amount. */
1173 create_trail_blaze(EXPLOSION_THRUST, &ship.position);
1177 /* stop movement of ship, 'cos that's what happens when you go into hyperspace. */
1178 static void hyperspace(void)
1180 if (ship.exists)
1182 ship.position.dx = ship.position.dy = 0;
1183 ship.position.x = (rb->rand()%SCALED_WIDTH);
1184 ship.position.y = (rb->rand()%SCALED_HEIGHT);
1188 static void draw_lives(void)
1190 int n;
1191 #if (LARGE_LCD)
1192 int px = (LCD_WIDTH-1 - 4)*SCALE;
1193 int py = (LCD_HEIGHT-1 - 6)*SCALE;
1194 #else
1195 int px = (LCD_WIDTH-1 - 3)*SCALE;
1196 int py = (LCD_HEIGHT-1 - 4)*SCALE;
1197 #endif
1199 SET_FG(COL_PLAYER);
1201 n = num_lives-1;
1202 while (n--)
1204 draw_polygon(lives_points, NUM_SHIP_VERTICES, px, py);
1205 #if (LARGE_LCD)
1206 px -= 8*SCALE;
1207 #else
1208 px -= 6*SCALE;
1209 #endif
1214 * missile
1217 /* Initialise a missile */
1218 static void initialise_missile(struct Missile* missile)
1220 missile->position.x = ship.position.x + ship.vertices[0].x;
1221 missile->position.y = ship.position.y + ship.vertices[0].y;
1222 missile->position.dx = (ship.vertices[0].x - ship.vertices[2].x)/2;
1223 missile->position.dy = (ship.vertices[0].y - ship.vertices[2].y)/2;
1224 missile->alive = MISSILE_LIFE_LENGTH;
1225 missile->oldpoint.x = missile->position.x;
1226 missile->oldpoint.y = missile->position.y;
1229 /* Fire the next missile */
1230 static void fire_missile(void)
1232 struct Missile* missile;
1233 int n;
1235 if (ship.exists)
1237 missile = missiles_array;
1238 n = MAX_NUM_MISSILES;
1239 while (n--)
1241 if (missile->alive <= 0)
1243 initialise_missile(missile);
1244 break;
1246 missile++;
1251 /* Draw and Move all the missiles */
1252 static void draw_and_move_missiles(void)
1254 struct Missile* missile;
1255 struct Point vertices[2];
1256 int n;
1258 SET_FG(COL_MISSILE);
1260 missile = missiles_array;
1261 n = MAX_NUM_MISSILES;
1262 while (n--)
1264 if (missile->alive > 0)
1266 vertices[0].x = 0;
1267 vertices[0].y = 0;
1268 vertices[1].x = -missile->position.dx;
1269 vertices[1].y = -missile->position.dy;
1270 draw_polygon(vertices, 2, missile->position.x, missile->position.y);
1272 if (game_state != PAUSE_MODE)
1274 missile->oldpoint.x = missile->position.x;
1275 missile->oldpoint.y = missile->position.y;
1276 move_point(&missile->position);
1277 missile->alive--;
1280 missile++;
1284 /*************************************************
1285 ** Handle enemy.
1286 *************************************************/
1288 static void initialise_enemy(void)
1290 struct Point* point;
1291 int n;
1292 int size;
1294 if (rb->rand()%100 > enemy.size_probability)
1296 size = BIG_SHIP;
1297 enemy.size_probability++;
1298 if (enemy.size_probability > 90)
1300 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
1303 else
1305 size = LITTLE_SHIP;
1306 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
1309 enemy.exists = true;
1310 enemy.explode_countdown = 0;
1311 enemy.appear_countdown = enemy.appear_timing;
1313 point = enemy.vertices;
1314 for(n = 0; n < NUM_ENEMY_VERTICES*2; n += 2)
1316 point->x = enemy_vertices[n];
1317 point->y = enemy_vertices[n+1];
1318 point->x *= size*SCALE/2;
1319 point->y *= size*SCALE/2;
1320 point++;
1323 if (ship.position.x >= SCALED_WIDTH/2)
1325 enemy.position.dx = ENEMY_SPEED;
1326 enemy.position.x = 0;
1328 else
1330 enemy.position.dx = -ENEMY_SPEED;
1331 enemy.position.x = SCALED_WIDTH;
1334 if (ship.position.y >= SCALED_HEIGHT/2)
1336 enemy.position.dy = ENEMY_SPEED;
1337 enemy.position.y = 0;
1339 else
1341 enemy.position.dy = -ENEMY_SPEED;
1342 enemy.position.y = SCALED_HEIGHT;
1345 enemy.position.dx *= SCALE/10;
1346 enemy.position.dy *= SCALE/10;
1349 static void draw_and_move_enemy(void)
1351 SET_FG(COL_ENEMY);
1353 if (enemy.exists)
1355 draw_polygon(enemy.vertices, NUM_ENEMY_VERTICES,
1356 enemy.position.x, enemy.position.y);
1359 if (game_state != PAUSE_MODE)
1361 if (enemy.exists)
1363 enemy.position.x += enemy.position.dx;
1364 enemy.position.y += enemy.position.dy;
1366 if (enemy.position.x > SCALED_WIDTH || enemy.position.x < 0)
1367 enemy.exists = false;
1369 enemy.position.y %= SCALED_HEIGHT;
1370 if (enemy.position.y < 0)
1371 enemy.position.y += SCALED_HEIGHT;
1373 if ((rb->rand()%1000) < 10)
1374 enemy.position.dy = -enemy.position.dy;
1376 else if (enemy.explode_countdown > 0)
1378 enemy.explode_countdown--;
1380 else
1382 if (enemy.appear_countdown > 0)
1383 enemy.appear_countdown--;
1384 else if (rb->rand()%100 >= enemy.appear_probability)
1385 initialise_enemy();
1389 if (enemy_missile.alive <= 0)
1391 /* if no missile and the enemy is here and not exploding..
1392 then shoot baby! */
1393 if (enemy.exists && ship.exists &&
1394 game_state == PLAY_MODE && (rb->rand()%10) >= 5 )
1396 int dx = ship.position.x - enemy.position.x;
1397 int dy = ship.position.y - enemy.position.y;
1399 if (dx < -SCALED_WIDTH/2) dx += SCALED_WIDTH;
1400 else if (dx > SCALED_WIDTH/2) dx -= SCALED_WIDTH;
1401 if (dy < -SCALED_HEIGHT/2) dy += SCALED_HEIGHT;
1402 else if (dy > SCALED_HEIGHT/2) dy -= SCALED_HEIGHT;
1404 enemy_missile.position.x = enemy.position.x;
1405 enemy_missile.position.y = enemy.position.y;
1407 /* lame, needs to be sorted - it's trying to shoot at the ship */
1408 if (dx < -5*SCALE)
1409 enemy_missile.position.dx = -1;
1410 else if (dx > 5*SCALE)
1411 enemy_missile.position.dx = 1;
1412 else
1413 enemy_missile.position.dx = 0;
1415 if (dy < -5*SCALE)
1416 enemy_missile.position.dy = -1;
1417 else if (dy > 5*SCALE)
1418 enemy_missile.position.dy = 1;
1419 else
1420 enemy_missile.position.dy = 0;
1422 while (enemy_missile.position.dx == 0 &&
1423 enemy_missile.position.dy == 0)
1425 enemy_missile.position.dx = rb->rand()%2-1;
1426 enemy_missile.position.dy = rb->rand()%2-1;
1429 enemy_missile.position.dx *= SCALE;
1430 enemy_missile.position.dy *= SCALE;
1431 enemy_missile.alive = ENEMY_MISSILE_LIFE_LENGTH;
1434 else
1436 rb->lcd_fillrect( enemy_missile.position.x/SCALE,
1437 enemy_missile.position.y/SCALE,
1438 POINT_SIZE, POINT_SIZE );
1439 if (game_state != PAUSE_MODE)
1441 move_point(&enemy_missile.position);
1442 enemy_missile.alive--;
1447 /*************************************************
1448 ** Check collisions.
1449 *************************************************/
1451 /* Add score if missile hit asteroid or enemy */
1452 static void add_score(int val)
1454 current_score += val;
1455 if (current_score >= extra_life)
1457 num_lives++;
1458 extra_life += EXTRA_LIFE;
1462 static bool is_point_within_asteroid(struct Asteroid* asteroid,
1463 struct Point* point)
1465 if (is_point_within_rectangle(&asteroid->position, point, asteroid->radius)
1466 && is_point_in_polygon(asteroid->vertices, NUM_ASTEROID_VERTICES,
1467 point->x - asteroid->position.x,
1468 point->y - asteroid->position.y))
1470 explode_asteroid(asteroid);
1471 return true;
1473 else
1474 return false;
1477 static bool is_point_within_ship(struct Point* point)
1479 if (is_point_within_rectangle(&ship.position, point, SIZE_SHIP_COLLISION)
1480 && is_point_in_polygon(ship.vertices, NUM_SHIP_VERTICES,
1481 point->x - ship.position.x,
1482 point->y - ship.position.y))
1484 return true;
1486 else
1487 return false;
1490 static bool is_point_within_enemy(struct Point* point)
1492 if (is_point_within_rectangle(&enemy.position, point, SIZE_ENEMY_COLLISION))
1494 add_score(5);
1495 enemy.explode_countdown = EXPLOSION_LENGTH;
1496 enemy.exists = false;
1497 create_trail_blaze(EXPLOSION_ENEMY, &enemy.position);
1498 return true;
1500 else
1501 return false;
1504 static bool is_ship_within_asteroid(struct Asteroid* asteroid)
1506 struct Point p;
1508 if (!is_point_within_rectangle(&asteroid->position, &ship.position,
1509 asteroid->radius+SIZE_SHIP_COLLISION))
1510 return false;
1512 p.x = ship.position.x + ship.vertices[0].x;
1513 p.y = ship.position.y + ship.vertices[0].y;
1514 if (is_point_within_asteroid(asteroid, &p))
1515 return true;
1517 p.x = ship.position.x + ship.vertices[1].x;
1518 p.y = ship.position.y + ship.vertices[1].y;
1519 if (is_point_within_asteroid(asteroid, &p))
1520 return true;
1522 p.x = ship.position.x + ship.vertices[3].x;
1523 p.y = ship.position.y + ship.vertices[3].y;
1524 if (is_point_within_asteroid(asteroid, &p))
1525 return true;
1527 return false;
1530 /* Check for collsions between the missiles and the asteroids and the ship */
1531 static void check_collisions(void)
1533 struct Missile* missile;
1534 struct Asteroid* asteroid;
1535 int m, n;
1536 bool asteroids_onscreen = false;
1538 asteroid = asteroids_array;
1539 m = MAX_NUM_ASTEROIDS;
1540 while (m--)
1542 /* if the asteroids exists then test missile collision: */
1543 if (asteroid->exists)
1545 missile = missiles_array;
1546 n = MAX_NUM_MISSILES;
1547 while (n--)
1549 /* if the missiles exists: */
1550 if (missile->alive > 0)
1552 /* has the missile hit the asteroid? */
1553 if (is_point_within_asteroid(asteroid, &missile->position) ||
1554 is_point_within_asteroid(asteroid, &missile->oldpoint))
1556 add_score(1);
1557 missile->alive = 0;
1558 break;
1561 missile++;
1564 /* now check collision with ship: */
1565 if (asteroid->exists && ship.exists)
1567 if (is_ship_within_asteroid(asteroid))
1569 add_score(1);
1570 explode_ship();
1574 /* has the enemy missile blown something up? */
1575 if (asteroid->exists && enemy_missile.alive > 0)
1577 if (is_point_within_asteroid(asteroid, &enemy_missile.position))
1579 enemy_missile.alive = 0;
1584 /* is an asteroid still exploding? */
1585 if (asteroid->explode_countdown > 0)
1586 asteroids_onscreen = true;
1588 asteroid++;
1591 /* now check collision between ship and enemy */
1592 if (enemy.exists && ship.exists)
1594 /* has the enemy collided with the ship? */
1595 if (is_point_within_enemy(&ship.position))
1597 explode_ship();
1598 create_trail_blaze(EXPLOSION_ENEMY, &enemy.position);
1601 if (enemy.exists)
1603 /* Now see if the enemy has been shot at by the ships missiles: */
1604 missile = missiles_array;
1605 n = MAX_NUM_MISSILES;
1606 while (n--)
1608 if (missile->alive > 0 &&
1609 is_point_within_enemy(&missile->position))
1611 missile->alive = 0;
1612 break;
1614 missile++;
1619 /* test collision with enemy missile and ship: */
1620 if (enemy_missile.alive > 0 && is_point_within_ship(&enemy_missile.position))
1622 explode_ship();
1623 enemy_missile.alive = 0;
1624 enemy_missile.position.x = enemy_missile.position.y = 0;
1627 /* if all asteroids cleared then start again: */
1628 if (asteroid_count == 0 && !asteroids_onscreen
1629 && !enemy.exists && enemy.explode_countdown <= 0)
1631 current_level++;
1632 if (current_level > MAX_LEVEL)
1633 current_level = START_LEVEL;
1634 enemy.appear_probability += 5;
1635 if (enemy.appear_probability >= 100)
1636 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1637 enemy.appear_timing -= 30;
1638 if (enemy.appear_timing < 30)
1639 enemy.appear_timing = 30;
1640 game_state = SHOW_LEVEL;
1641 show_level_timeout = SHOW_LEVEL_TIME;
1646 * stars
1649 static void create_stars(void)
1651 struct Point* p;
1652 int n;
1654 p = stars;
1655 n = NUM_STARS;
1656 while (n--)
1658 p->x = (rb->rand()%LCD_WIDTH);
1659 p->y = (rb->rand()%LCD_HEIGHT);
1660 p++;
1664 static void drawstars(void)
1666 struct Point* p;
1667 int n;
1669 SET_FG(COL_STARS);
1671 p = stars;
1672 n = NUM_STARS;
1673 while (n--)
1675 rb->lcd_drawpixel(p->x , p->y);
1676 p++;
1680 /*************************************************
1681 ** Creates start_num number of new asteroids of
1682 ** full size.
1683 **************************************************/
1684 static void initialise_level(int start_num)
1686 struct Asteroid* asteroid;
1687 struct Missile* missile;
1688 struct TrailPoint* tpoint;
1689 int n;
1690 asteroid_count = next_missile_count = next_thrust_count = 0;
1692 /* no enemy */
1693 enemy.exists = 0;
1694 enemy.explode_countdown = 0;
1695 enemy_missile.alive = 0;
1697 /* clear asteroids */
1698 asteroid = asteroids_array;
1699 n = MAX_NUM_ASTEROIDS;
1700 while (n--)
1702 asteroid->exists = false;
1703 asteroid++;
1706 /* make some LARGE asteroids */
1707 for(n = 0; n < start_num; n++)
1708 initialise_asteroid(&asteroids_array[n], LARGE, NULL);
1710 /* ensure all missiles are out of action: */
1711 missile = missiles_array;
1712 n = MAX_NUM_MISSILES;
1713 while (n--)
1715 missile->alive = 0;
1716 missile++;
1719 tpoint = trail_points;
1720 n = NUM_TRAIL_POINTS;
1721 while (n--)
1723 tpoint->alive = 0;
1724 tpoint++;
1728 static void initialise_game(void)
1730 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1731 enemy.appear_timing = ENEMY_APPEAR_TIMING_START;
1732 enemy.appear_countdown = enemy.appear_timing;
1733 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
1734 current_level = START_LEVEL;
1735 num_lives = START_LIVES;
1736 extra_life = EXTRA_LIFE;
1737 current_score = 0;
1738 initialise_ship();
1739 initialise_level(0);
1740 game_state = SHOW_LEVEL;
1741 show_level_timeout = SHOW_LEVEL_TIME;
1744 /* menu stuff */
1745 static bool spacerocks_help(void)
1747 static char *help_text[] = {
1748 "Spacerocks", "", "Aim", "",
1749 "The", "goal", "of", "the", "game", "is", "to", "blow", "up",
1750 "the", "asteroids", "and", "avoid", "being", "hit", "by", "them.",
1751 "Also", "you'd", "better", "watch", "out", "for", "the", "UFOs!"
1753 static struct style_text formation[]={
1754 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1755 { 2, C_RED },
1756 LAST_STYLE_ITEM
1759 rb->lcd_setfont(FONT_UI);
1760 SET_BG(LCD_BLACK);
1761 SET_FG(LCD_WHITE);
1762 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true))
1763 return true;
1764 rb->lcd_setfont(FONT_SYSFIXED);
1766 return false;
1769 #define PLUGIN_OTHER 10
1770 static bool ingame;
1771 static int spacerocks_menu_cb(int action, const struct menu_item_ex *this_item)
1773 if (action == ACTION_REQUEST_MENUITEM
1774 && !ingame && ((intptr_t)this_item)==0)
1775 return ACTION_EXIT_MENUITEM;
1776 return action;
1779 static int spacerocks_menu(void)
1781 int selection = 0;
1782 MENUITEM_STRINGLIST(main_menu, "Spacerocks Menu", spacerocks_menu_cb,
1783 "Resume Game", "Start New Game",
1784 "Help", "High Scores",
1785 "Playback Control", "Quit");
1786 rb->button_clear_queue();
1788 while (1)
1790 switch (rb->do_menu(&main_menu, &selection, NULL, false))
1792 case 0:
1793 return PLUGIN_OTHER;
1794 case 1:
1795 initialise_game();
1796 return PLUGIN_OTHER;
1797 case 2:
1798 if (spacerocks_help())
1799 return PLUGIN_USB_CONNECTED;
1800 break;
1801 case 3:
1802 highscore_show(NUM_SCORES, highscores, NUM_SCORES, true);
1803 break;
1804 case 4:
1805 playback_control(NULL);
1806 break;
1807 case 5:
1808 return PLUGIN_OK;
1809 case MENU_ATTACHED_USB:
1810 return PLUGIN_USB_CONNECTED;
1811 default:
1812 break;
1817 static int spacerocks_game_loop(void)
1819 char str[20];
1820 int button;
1821 int end;
1822 int position;
1823 int ret;
1825 if ((ret = spacerocks_menu()) != PLUGIN_OTHER)
1826 return ret;
1828 SET_BG(LCD_BLACK);
1830 ingame = true;
1831 while (true)
1833 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1834 rb->lcd_clear_display();
1835 SET_FG(COL_TEXT);
1836 switch(game_state)
1838 case GAME_OVER:
1839 ingame = false;
1840 rb->splash (HZ * 2, "Game Over");
1841 rb->lcd_clear_display();
1842 position = highscore_update(current_score, current_level, "",
1843 highscores, NUM_SCORES);
1844 if (position != -1)
1846 if (position == 0)
1847 rb->splash(HZ*2, "New High Score");
1848 highscore_show(position, highscores, NUM_SCORES, true);
1850 return PLUGIN_OTHER;
1851 break;
1853 case PAUSE_MODE:
1854 rb->snprintf(str, sizeof(str), "score %d ", current_score);
1855 rb->lcd_putsxy(1,LCD_HEIGHT-8, str);
1856 rb->lcd_putsxy(CENTER_LCD_X - 15,
1857 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "pause");
1858 draw_and_move_missiles();
1859 draw_lives();
1860 draw_and_move_ship();
1861 break;
1863 case PLAY_MODE:
1864 rb->snprintf(str, sizeof(str), "score %d ", current_score);
1865 rb->lcd_putsxy(1, LCD_HEIGHT-8, str);
1866 draw_and_move_missiles();
1867 draw_lives();
1868 check_collisions();
1869 draw_and_move_ship();
1870 break;
1872 case SHOW_LEVEL:
1873 rb->snprintf(str, sizeof(str), "score %d ", current_score);
1874 rb->lcd_putsxy(1, LCD_HEIGHT-8, str);
1875 rb->snprintf(str, sizeof(str), "stage %d ", current_level);
1876 rb->lcd_putsxy(CENTER_LCD_X - 20,
1877 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, str);
1878 draw_lives();
1879 draw_and_move_ship();
1880 show_level_timeout--;
1881 if (show_level_timeout <= 0)
1883 initialise_level(current_level);
1884 game_state = PLAY_MODE;
1886 break;
1888 draw_and_move_trail_blaze();
1889 drawstars();
1890 draw_and_move_asteroids();
1891 draw_and_move_enemy();
1893 rb->lcd_update();
1895 #ifdef HAS_BUTTON_HOLD
1896 if (rb->button_hold() && game_state == PLAY_MODE)
1897 game_state = PAUSE_MODE;
1898 #endif
1899 button = rb->button_get(false);
1900 switch(button)
1902 case(AST_QUIT):
1903 return PLUGIN_OTHER;
1904 break;
1905 #ifdef AST_PAUSE
1906 case(AST_PAUSE):
1907 if (game_state == PAUSE_MODE)
1908 game_state = PLAY_MODE;
1909 else if (game_state == PLAY_MODE)
1910 game_state = PAUSE_MODE;
1911 break;
1912 #endif
1913 case (AST_LEFT):
1914 case (AST_LEFT | BUTTON_REPEAT):
1915 if (game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1916 rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN);
1917 break;
1919 case (AST_RIGHT):
1920 case (AST_RIGHT | BUTTON_REPEAT):
1921 if (game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1922 rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN);
1923 break;
1925 case (AST_THRUST):
1926 case (AST_THRUST | BUTTON_REPEAT):
1927 if (game_state == PLAY_MODE || game_state == SHOW_LEVEL)
1929 if (next_thrust_count <= 0)
1931 next_thrust_count = 5;
1932 thrust_ship();
1935 break;
1937 case (AST_HYPERSPACE):
1938 if (game_state == PLAY_MODE)
1939 hyperspace();
1940 /* maybe shield if it gets too hard */
1941 break;
1943 case (AST_FIRE):
1944 case (AST_FIRE | BUTTON_REPEAT):
1945 if (game_state == PLAY_MODE)
1947 if (next_missile_count <= 0)
1949 fire_missile();
1950 next_missile_count = 10;
1953 else if(game_state == PAUSE_MODE)
1954 game_state = PLAY_MODE;
1955 break;
1957 default:
1958 if (rb->default_event_handler(button)==SYS_USB_CONNECTED)
1959 return PLUGIN_USB_CONNECTED;
1960 break;
1963 if (next_missile_count > 0)
1964 next_missile_count--;
1966 if (next_thrust_count > 0)
1967 next_thrust_count--;
1969 if (TIME_BEFORE(*rb->current_tick, end))
1970 rb->sleep(end-*rb->current_tick);
1971 else
1972 rb->yield();
1976 enum plugin_status plugin_start(const void* parameter)
1978 (void)parameter;
1979 int ret = PLUGIN_OTHER;
1981 #if LCD_DEPTH > 1
1982 rb->lcd_set_backdrop(NULL);
1983 #endif
1984 /* universal font */
1985 rb->lcd_setfont(FONT_SYSFIXED);
1986 /* Turn off backlight timeout */
1987 backlight_force_on(); /* backlight control in lib/helper.c */
1988 highscore_load(HIGH_SCORE, highscores, NUM_SCORES);
1989 rb->srand(*rb->current_tick);
1991 /* create stars once, and once only: */
1992 create_stars();
1994 while (ret == PLUGIN_OTHER)
1995 ret = spacerocks_game_loop();
1997 rb->lcd_setfont(FONT_UI);
1998 highscore_save(HIGH_SCORE, highscores, NUM_SCORES);
1999 /* Turn on backlight timeout (revert to settings) */
2000 backlight_use_settings(); /* backlight control in lib/helper.c */
2002 return ret;