1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
23 #include "lib/display_text.h"
24 #include "lib/helper.h"
25 #include "lib/highscore.h"
26 #include "lib/playback_control.h"
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_HDD6330_PAD
201 #define AST_PAUSE BUTTON_PLAY
202 #define AST_QUIT BUTTON_POWER
203 #define AST_THRUST BUTTON_UP
204 #define AST_HYPERSPACE BUTTON_DOWN
205 #define AST_LEFT BUTTON_LEFT
206 #define AST_RIGHT BUTTON_RIGHT
207 #define AST_FIRE BUTTON_VOL_DOWN
209 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
210 #define AST_PAUSE BUTTON_RIGHT
211 #define AST_QUIT BUTTON_POWER
212 #define AST_THRUST BUTTON_UP
213 #define AST_HYPERSPACE BUTTON_DOWN
214 #define AST_LEFT BUTTON_PREV
215 #define AST_RIGHT BUTTON_NEXT
216 #define AST_FIRE BUTTON_LEFT
218 #elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \
219 (CONFIG_KEYPAD == ONDAVX777_PAD) || \
220 (CONFIG_KEYPAD == MROBE500_PAD)
221 #define AST_QUIT BUTTON_POWER
223 #elif (CONFIG_KEYPAD == SAMSUNG_YH_PAD)
224 #define AST_PAUSE BUTTON_FFWD
225 #define AST_QUIT BUTTON_REC
226 #define AST_THRUST BUTTON_UP
227 #define AST_HYPERSPACE BUTTON_DOWN
228 #define AST_LEFT BUTTON_LEFT
229 #define AST_RIGHT BUTTON_RIGHT
230 #define AST_FIRE BUTTON_PLAY
232 #elif (CONFIG_KEYPAD == PBELL_VIBE500_PAD)
233 #define AST_PAUSE BUTTON_PLAY
234 #define AST_QUIT BUTTON_REC
235 #define AST_THRUST BUTTON_UP
236 #define AST_HYPERSPACE BUTTON_DOWN
237 #define AST_LEFT BUTTON_PREV
238 #define AST_RIGHT BUTTON_NEXT
239 #define AST_FIRE BUTTON_OK
241 #elif (CONFIG_KEYPAD == MPIO_HD200_PAD)
243 #define AST_PAUSE (BUTTON_PLAY|BUTTON_FUNC)
244 #define AST_QUIT (BUTTON_REC|BUTTON_PLAY)
245 #define AST_THRUST BUTTON_REC
246 #define AST_HYPERSPACE BUTTON_PLAY
247 #define AST_LEFT BUTTON_REW
248 #define AST_RIGHT BUTTON_FF
249 #define AST_FIRE BUTTON_FUNC
251 #elif (CONFIG_KEYPAD == MPIO_HD300_PAD)
253 #define AST_PAUSE (BUTTON_PLAY|BUTTON_REL)
254 #define AST_QUIT (BUTTON_MENU|BUTTON_REPEAT)
255 #define AST_THRUST BUTTON_REC
256 #define AST_HYPERSPACE (BUTTON_PLAY|BUTTON_REPEAT)
257 #define AST_LEFT BUTTON_UP
258 #define AST_RIGHT BUTTON_DOWN
259 #define AST_FIRE BUTTON_ENTER
261 #elif (CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD)
263 #define AST_PAUSE BUTTON_PLAYPAUSE
264 #define AST_QUIT BUTTON_POWER
265 #define AST_THRUST BUTTON_UP
266 #define AST_HYPERSPACE BUTTON_BACK
267 #define AST_LEFT BUTTON_LEFT
268 #define AST_RIGHT BUTTON_RIGHT
269 #define AST_FIRE BUTTON_SELECT
271 #elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
273 #define ALT_PAUSE BUTTON_VOL_DOWN
274 #define AST_QUIT BUTTON_POWER
275 #define AST_THRUST BUTTON_UP
276 #define AST_HYPERSPACE BUTTON_DOWN
277 #define AST_LEFT BUTTON_LEFT
278 #define AST_RIGHT BUTTON_RIGHT
279 #define AST_FIRE BUTTON_SELECT
281 #elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)
282 #define AST_PAUSE BUTTON_MENU
283 #define AST_QUIT BUTTON_BACK
284 #define AST_THRUST BUTTON_UP
285 #define AST_HYPERSPACE BUTTON_DOWN
286 #define AST_LEFT BUTTON_LEFT
287 #define AST_RIGHT BUTTON_RIGHT
288 #define AST_FIRE BUTTON_SELECT
290 #elif (CONFIG_KEYPAD == HM60X_PAD)
291 #define AST_PAUSE (BUTTON_SELECT|BUTTON_POWER)
292 #define AST_QUIT BUTTON_POWER
293 #define AST_THRUST BUTTON_UP
294 #define AST_HYPERSPACE BUTTON_DOWN
295 #define AST_LEFT BUTTON_LEFT
296 #define AST_RIGHT BUTTON_RIGHT
297 #define AST_FIRE BUTTON_SELECT
299 #elif (CONFIG_KEYPAD == HM801_PAD)
300 #define AST_PAUSE BUTTON_PLAY
301 #define AST_QUIT BUTTON_POWER
302 #define AST_THRUST BUTTON_UP
303 #define AST_HYPERSPACE BUTTON_DOWN
304 #define AST_LEFT BUTTON_LEFT
305 #define AST_RIGHT BUTTON_RIGHT
306 #define AST_FIRE BUTTON_SELECT
309 #error No keymap defined!
312 #ifdef HAVE_TOUCHSCREEN
314 #define AST_PAUSE BUTTON_CENTER
317 #define AST_QUIT BUTTON_TOPLEFT
320 #define AST_THRUST BUTTON_TOPMIDDLE
322 #ifndef AST_HYPERSPACE
323 #define AST_HYPERSPACE BUTTON_TOPRIGHT
326 #define AST_LEFT BUTTON_MIDLEFT
329 #define AST_RIGHT BUTTON_MIDRIGHT
332 #define AST_FIRE BUTTON_BOTTOMMIDDLE
336 #define RES MAX(LCD_WIDTH, LCD_HEIGHT)
337 #define LARGE_LCD (RES >= 200)
343 #define WRAP_GAP (LARGE*SCALE*3)
345 #define START_LEVEL 1
346 #define SHOW_LEVEL_TIME 50
347 #define EXPLOSION_LENGTH 20
349 #define MAX_NUM_ASTEROIDS 25
350 #define MAX_NUM_MISSILES 6
352 #define NUM_TRAIL_POINTS 70
353 #define MAX_LEVEL MAX_NUM_ASTEROIDS
355 #define NUM_ASTEROID_VERTICES 10
356 #define NUM_SHIP_VERTICES 4
357 #define NUM_ENEMY_VERTICES 8
359 #define INVULNERABLE_TIME 30
360 #define BLINK_TIME 10
361 #define EXTRA_LIFE 250
362 #define START_LIVES 3
363 #define MISSILE_LIFE_LENGTH 40
365 #define ASTEROID_SPEED (RES/20)
366 #define SPACE_CHECK_SIZE 30*SCALE
369 #define SIZE_SHIP_COLLISION 8*SCALE
371 #define SIZE_SHIP_COLLISION 6*SCALE
374 #define LITTLE_SHIP 1
376 #define ENEMY_BIG_PROBABILITY_START 10
377 #define ENEMY_APPEAR_PROBABILITY_START 35
378 #define ENEMY_APPEAR_TIMING_START 600
379 #define ENEMY_SPEED 4
380 #define ENEMY_MISSILE_LIFE_LENGTH (RES/2)
382 #define SIZE_ENEMY_COLLISION 7*SCALE
384 #define SIZE_ENEMY_COLLISION 5*SCALE
387 #define SIN_COS_SCALE 10000
389 #define FAST_ROT_CW_SIN 873
390 #define FAST_ROT_CW_COS 9963
391 #define FAST_ROT_ACW_SIN -873
392 #define FAST_ROT_ACW_COS 9963
394 #define MEDIUM_ROT_CW_SIN 350
395 #define MEDIUM_ROT_CW_COS 9994
396 #define MEDIUM_ROT_ACW_SIN -350
397 #define MEDIUM_ROT_ACW_COS 9994
399 #define SLOW_ROT_CW_SIN 350
400 #define SLOW_ROT_CW_COS 9994
401 #define SLOW_ROT_ACW_SIN -350
402 #define SLOW_ROT_ACW_COS 9994
404 #ifdef HAVE_LCD_COLOR
405 #define SHIP_ROT_CW_SIN 2419
406 #define SHIP_ROT_CW_COS 9702
407 #define SHIP_ROT_ACW_SIN -2419
408 #define SHIP_ROT_ACW_COS 9702
410 #define SHIP_ROT_CW_SIN 3827
411 #define SHIP_ROT_CW_COS 9239
412 #define SHIP_ROT_ACW_SIN -3827
413 #define SHIP_ROT_ACW_COS 9239
417 #define SCALED_WIDTH (LCD_WIDTH*SCALE)
418 #define SCALED_HEIGHT (LCD_HEIGHT*SCALE)
419 #define CENTER_LCD_X (LCD_WIDTH/2)
420 #define CENTER_LCD_Y (LCD_HEIGHT/2)
422 #ifdef HAVE_LCD_COLOR
423 #define ASTEROID_R 230
424 #define ASTEROID_G 200
425 #define ASTEROID_B 100
436 #define COL_MISSILE LCD_RGBPACK(200,0,0)
437 #define COL_PLAYER LCD_RGBPACK(200,200,200)
438 #define COL_INVULN LCD_RGBPACK(100,100,200)
439 #define COL_STARS LCD_WHITE
440 #define COL_ASTEROID LCD_RGBPACK(ASTEROID_R,ASTEROID_G,ASTEROID_B)
441 #define COL_TEXT LCD_RGBPACK(200,200,255)
442 #define COL_ENEMY LCD_RGBPACK(ENEMY_R,ENEMY_G,ENEMY_B)
443 #define SET_FG rb->lcd_set_foreground
444 #define SET_BG rb->lcd_set_background
450 #define SCORE_FILE PLUGIN_GAMES_DATA_DIR "/spacerocks.score"
453 static struct highscore highscores
[NUM_SCORES
];
455 /* The array of points that make up an asteroid */
456 static const short asteroid_one
[NUM_ASTEROID_VERTICES
*2] =
470 /* The array of points that make up an asteroid */
471 static const short asteroid_two
[NUM_ASTEROID_VERTICES
*2] =
485 /* The array of points that make up an asteroid */
486 static const short asteroid_three
[NUM_ASTEROID_VERTICES
*2] =
500 /* The array of points the make up the ship */
501 static const short ship_vertices
[NUM_SHIP_VERTICES
*2] =
516 /* The array of points the make up the bad spaceship */
517 static const short enemy_vertices
[NUM_ENEMY_VERTICES
*2] =
579 struct Point position
;
581 #ifdef HAVE_LCD_COLOR
589 /* Asteroid structure, contains an array of points */
592 struct Point position
;
593 struct Point rotation
;
594 struct Point vertices
[NUM_ASTEROID_VERTICES
];
596 int explode_countdown
;
597 enum asteroid_type type
;
605 struct Point position
;
606 struct Point rotation
;
607 struct Point vertices
[NUM_SHIP_VERTICES
];
609 int explode_countdown
;
610 int invulnerable_time
;
615 struct Point position
;
616 struct Point vertices
[NUM_ENEMY_VERTICES
];
618 int explode_countdown
;
619 int appear_countdown
;
620 short size_probability
;
621 short appear_probability
;
627 struct Point position
;
628 struct Point oldpoint
;
632 static enum game_state game_state
;
633 static int asteroid_count
;
634 static int next_missile_count
;
635 static int next_thrust_count
;
636 static int num_lives
;
637 static int extra_life
;
638 static int show_level_timeout
;
639 static int current_level
;
640 static int current_score
;
642 static struct Ship ship
;
643 static struct Point stars
[NUM_STARS
];
644 static struct Asteroid asteroids_array
[MAX_NUM_ASTEROIDS
];
645 static struct Missile missiles_array
[MAX_NUM_MISSILES
];
646 static struct Missile enemy_missile
;
647 static struct Enemy enemy
;
648 static struct Point lives_points
[NUM_SHIP_VERTICES
];
649 static struct TrailPoint trail_points
[NUM_TRAIL_POINTS
];
651 /*************************************************
652 ** Handle polygon and point
653 *************************************************/
655 /* Check if point is in a polygon */
656 static bool is_point_in_polygon(struct Point
* vertices
, int num_vertices
,
664 if (x
< -SCALED_WIDTH
/2) x
+= SCALED_WIDTH
;
665 else if (x
> SCALED_WIDTH
/2) x
-= SCALED_WIDTH
;
666 if (y
< -SCALED_HEIGHT
/2) y
+= SCALED_HEIGHT
;
667 else if (y
> SCALED_HEIGHT
/2) y
-= SCALED_HEIGHT
;
670 pj
= vertices
+ num_vertices
-1;
675 if ((((pi
->y
<= y
) && (y
< pj
->y
)) || ((pj
->y
<= y
) && (y
< pi
->y
))) &&
676 (x
< (pj
->x
- pi
->x
) * (y
- pi
->y
) / (pj
->y
- pi
->y
) + pi
->x
))
686 /* Check if point is within a rectangle */
687 static bool is_point_within_rectangle(struct Point
* rect
, struct Point
* p
,
690 int dx
= p
->x
- rect
->x
;
691 int dy
= p
->y
- rect
->y
;
693 rb
->lcd_drawrect((rect
->x
- size
)/SCALE
, (rect
->y
- size
)/SCALE
,
694 (size
*2+1)/SCALE
, (size
*2+1)/SCALE
);
696 if (dx
< -SCALED_WIDTH
/2) dx
+= SCALED_WIDTH
;
697 else if (dx
> SCALED_WIDTH
/2) dx
-= SCALED_WIDTH
;
698 if (dy
< -SCALED_HEIGHT
/2) dy
+= SCALED_HEIGHT
;
699 else if (dy
> SCALED_HEIGHT
/2) dy
-= SCALED_HEIGHT
;
700 return (dx
> -size
&& dx
< size
&& dy
> -size
&& dy
< size
);
704 static void rotate_polygon(struct Point
* vertices
, int num_vertices
,
705 struct Point
* rotation
, int cos
, int sin
)
711 temp_x
= rotation
->x
;
712 temp_y
= rotation
->y
;
713 rotation
->x
= (temp_x
*cos
- temp_y
*sin
)/SIN_COS_SCALE
;
714 rotation
->y
= (temp_y
*cos
+ temp_x
*sin
)/SIN_COS_SCALE
;
715 #define MIN_SCALE (SIN_COS_SCALE-10)
716 #define MAX_SCALE (SIN_COS_SCALE+10)
717 /* normalize vector. this is not accurate but would be enough. */
718 temp_x
= rotation
->x
*rotation
->x
+ rotation
->y
*rotation
->y
;
719 if (temp_x
<= MIN_SCALE
*MIN_SCALE
)
721 rotation
->x
= rotation
->x
*SIN_COS_SCALE
/MIN_SCALE
;
722 rotation
->y
= rotation
->y
*SIN_COS_SCALE
/MIN_SCALE
;
724 else if (temp_x
>= MAX_SCALE
*MAX_SCALE
)
726 rotation
->x
= rotation
->x
*SIN_COS_SCALE
/MAX_SCALE
;
727 rotation
->y
= rotation
->y
*SIN_COS_SCALE
/MAX_SCALE
;
736 point
->x
= (point
->dx
*rotation
->x
- point
->dy
*rotation
->y
)/SIN_COS_SCALE
;
737 point
->y
= (point
->dy
*rotation
->x
+ point
->dx
*rotation
->y
)/SIN_COS_SCALE
;
743 static void draw_polygon(struct Point
* vertices
, int num_vertices
,
746 int n
, new_x
, new_y
, old_x
, old_y
;
750 if (px
> SCALED_WIDTH
- WRAP_GAP
)
752 if (py
> SCALED_HEIGHT
- WRAP_GAP
)
755 draw_wrap
= (px
< WRAP_GAP
|| py
< WRAP_GAP
);
757 p
= vertices
+ num_vertices
- 1;
758 old_x
= (p
->x
+ px
)/SCALE
;
759 old_y
= (p
->y
+ py
)/SCALE
;
764 new_x
= (p
->x
+ px
)/SCALE
;
765 new_y
= (p
->y
+ py
)/SCALE
;
767 rb
->lcd_drawline(old_x
, old_y
, new_x
, new_y
);
770 rb
->lcd_drawline(old_x
+ LCD_WIDTH
, old_y
, new_x
+ LCD_WIDTH
, new_y
);
771 rb
->lcd_drawline(old_x
, old_y
+ LCD_HEIGHT
, new_x
, new_y
+ LCD_HEIGHT
);
772 rb
->lcd_drawline(old_x
+ LCD_WIDTH
, old_y
+ LCD_HEIGHT
,
773 new_x
+ LCD_WIDTH
, new_y
+ LCD_HEIGHT
);
781 static void move_point(struct Point
* point
)
783 point
->x
+= point
->dx
;
784 point
->y
+= point
->dy
;
786 /* Check bounds on the x-axis: */
787 point
->x
%= SCALED_WIDTH
;
789 point
->x
+= SCALED_WIDTH
;
791 /* Check bounds on the y-axis: */
792 point
->y
%= SCALED_HEIGHT
;
794 point
->y
+= SCALED_HEIGHT
;
797 /*************************************************
798 ** Handle trail blaiz.
799 *************************************************/
801 static void create_ship_trail(struct TrailPoint
* tpoint
)
803 tpoint
->position
.x
+= ship
.vertices
[2].x
;
804 tpoint
->position
.y
+= ship
.vertices
[2].y
;
805 tpoint
->position
.dx
= -( ship
.vertices
[0].x
- ship
.vertices
[2].x
)/10;
806 tpoint
->position
.dy
= -( ship
.vertices
[0].y
- ship
.vertices
[2].y
)/10;
809 static void create_explosion_trail(struct TrailPoint
* tpoint
)
811 tpoint
->position
.dx
= (rb
->rand()%5001)-2500;
812 tpoint
->position
.dy
= (rb
->rand()%5001)-2500;
815 static void create_trail_blaze(int colour
, struct Point
* position
)
818 struct TrailPoint
* tpoint
;
821 if (colour
!= EXPLOSION_SHIP
)
823 numtoadd
= NUM_TRAIL_POINTS
/5;
827 numtoadd
= NUM_TRAIL_POINTS
/8;
830 /* give the point a random countdown timer, so they dissapears at different
832 tpoint
= trail_points
;
833 n
= NUM_TRAIL_POINTS
;
836 /* find a space in the array of trail_points that is NULL or DEAD or
837 whatever and place this one here. */
838 if (tpoint
->alive
<= 0)
840 /* take a random point near the position. */
841 tpoint
->position
.x
= (rb
->rand()%18000)-9000 + position
->x
;
842 tpoint
->position
.y
= (rb
->rand()%18000)-9000 + position
->y
;
847 create_explosion_trail(tpoint
);
849 #ifdef HAVE_LCD_COLOR
856 case EXPLOSION_ASTEROID
:
857 create_explosion_trail(tpoint
);
859 #ifdef HAVE_LCD_COLOR
860 tpoint
->r
= ASTEROID_R
;
861 tpoint
->g
= ASTEROID_G
;
862 tpoint
->b
= ASTEROID_B
;
866 case EXPLOSION_ENEMY
:
867 create_explosion_trail(tpoint
);
869 #ifdef HAVE_LCD_COLOR
876 case EXPLOSION_THRUST
:
877 create_ship_trail(tpoint
);
879 #ifdef HAVE_LCD_COLOR
880 tpoint
->r
= THRUST_R
;
881 tpoint
->g
= THRUST_G
;
882 tpoint
->b
= THRUST_B
;
888 /* give the points a speed based on direction of travel
890 tpoint
->position
.dx
+= position
->dx
;
891 tpoint
->position
.dy
+= position
->dy
;
901 static void draw_and_move_trail_blaze(void)
903 struct TrailPoint
* tpoint
;
906 /* loop through, if alive then move and draw.
907 when drawn, countdown it's timer.
910 tpoint
= trail_points
;
911 n
= NUM_TRAIL_POINTS
;
914 if (tpoint
->alive
> 0)
916 if (game_state
!= PAUSE_MODE
)
919 move_point(&(tpoint
->position
));
920 #ifdef HAVE_LCD_COLOR
921 /* intensity = tpoint->alive/2; */
922 if (tpoint
->r
>= tpoint
->dec
) tpoint
->r
-= tpoint
->dec
;
923 if (tpoint
->g
>= tpoint
->dec
) tpoint
->g
-= tpoint
->dec
;
924 if (tpoint
->b
>= tpoint
->dec
) tpoint
->b
-= tpoint
->dec
;
927 SET_FG(LCD_RGBPACK(tpoint
->r
, tpoint
->g
, tpoint
->b
));
928 rb
->lcd_drawpixel(tpoint
->position
.x
/SCALE
, tpoint
->position
.y
/SCALE
);
934 /*************************************************
936 *************************************************/
938 static void rotate_asteroid(struct Asteroid
* asteroid
)
940 rotate_polygon(asteroid
->vertices
, NUM_ASTEROID_VERTICES
,
942 asteroid
->speed_cos
, asteroid
->speed_sin
);
945 /* Initialise the passed Asteroid.
946 * if position is NULL, place it at the random loacation
947 * where ship doesn't exist
949 static void initialise_asteroid(struct Asteroid
* asteroid
,
950 enum asteroid_type type
, struct Point
*position
)
952 const short *asteroid_vertices
;
956 asteroid
->exists
= true;
957 asteroid
->explode_countdown
= 0;
958 asteroid
->type
= type
;
960 /* Set the radius of the asteroid: */
961 asteroid
->radius
= (int)type
*SCALE
*3;
963 /* shall we move Clockwise and Fast */
967 asteroid
->speed_cos
= FAST_ROT_CW_COS
;
968 asteroid
->speed_sin
= FAST_ROT_CW_SIN
;
972 asteroid
->speed_cos
= FAST_ROT_ACW_COS
;
973 asteroid
->speed_sin
= FAST_ROT_ACW_SIN
;
977 asteroid
->speed_cos
= SLOW_ROT_ACW_COS
;
978 asteroid
->speed_sin
= SLOW_ROT_ACW_SIN
;
982 asteroid
->speed_cos
= SLOW_ROT_CW_COS
;
983 asteroid
->speed_sin
= SLOW_ROT_CW_SIN
;
988 asteroid_vertices
= asteroid_one
;
990 asteroid_vertices
= asteroid_two
;
992 asteroid_vertices
= asteroid_three
;
994 point
= asteroid
->vertices
;
995 for(n
= 0; n
< NUM_ASTEROID_VERTICES
*2; n
+= 2)
997 point
->x
= asteroid_vertices
[n
];
998 point
->y
= asteroid_vertices
[n
+1];
999 point
->x
*= asteroid
->radius
/20;
1000 point
->y
*= asteroid
->radius
/20;
1001 /* dx and dy are used when rotate polygon */
1002 point
->dx
= point
->x
;
1003 point
->dy
= point
->y
;
1010 /* Set the position randomly: */
1011 asteroid
->position
.x
= (rb
->rand()%SCALED_WIDTH
);
1012 asteroid
->position
.y
= (rb
->rand()%SCALED_HEIGHT
);
1013 } while (is_point_within_rectangle(&ship
.position
, &asteroid
->position
,
1018 asteroid
->position
.x
= position
->x
;
1019 asteroid
->position
.y
= position
->y
;
1023 asteroid
->position
.dx
= (rb
->rand()%ASTEROID_SPEED
)-ASTEROID_SPEED
/2;
1024 } while (asteroid
->position
.dx
== 0);
1027 asteroid
->position
.dy
= (rb
->rand()%ASTEROID_SPEED
)-ASTEROID_SPEED
/2;
1028 } while (asteroid
->position
.dy
== 0);
1030 asteroid
->position
.dx
*= SCALE
/10;
1031 asteroid
->position
.dy
*= SCALE
/10;
1033 asteroid
->rotation
.x
= SIN_COS_SCALE
;
1034 asteroid
->rotation
.y
= 0;
1036 /* Now rotate the asteroid a bit, so they all look a bit different */
1037 for(n
= (rb
->rand()%30)+2; n
--; )
1038 rotate_asteroid(asteroid
);
1040 /* great, we've created an asteroid, don't forget to increment the total: */
1045 * Creates a new asteroid of the given 4type (size) and at the given location.
1047 static void create_asteroid(enum asteroid_type type
, struct Point
*position
)
1049 struct Asteroid
* asteroid
;
1052 asteroid
= asteroids_array
;
1053 n
= MAX_NUM_ASTEROIDS
;
1056 if (!asteroid
->exists
&& asteroid
->explode_countdown
<= 0)
1058 initialise_asteroid(asteroid
, type
, position
);
1065 /* Draw and move all asteroids */
1066 static void draw_and_move_asteroids(void)
1068 struct Asteroid
* asteroid
;
1071 SET_FG(COL_ASTEROID
);
1073 asteroid
= asteroids_array
;
1074 n
= MAX_NUM_ASTEROIDS
;
1077 if (asteroid
->exists
)
1079 draw_polygon(asteroid
->vertices
, NUM_ASTEROID_VERTICES
,
1080 asteroid
->position
.x
, asteroid
->position
.y
);
1082 if (game_state
!= PAUSE_MODE
)
1084 if (asteroid
->exists
)
1086 move_point(&asteroid
->position
);
1087 rotate_asteroid(asteroid
);
1089 else if (asteroid
->explode_countdown
> 0)
1091 asteroid
->explode_countdown
--;
1098 static void explode_asteroid(struct Asteroid
* asteroid
)
1101 p
.dx
= asteroid
->position
.dx
;
1102 p
.dy
= asteroid
->position
.dy
;
1103 p
.x
= asteroid
->position
.x
;
1104 p
.y
= asteroid
->position
.y
;
1107 asteroid
->exists
= false;
1109 switch(asteroid
->type
)
1112 asteroid
->explode_countdown
= EXPLOSION_LENGTH
;
1113 create_trail_blaze(EXPLOSION_ASTEROID
, &p
);
1117 create_asteroid(SMALL
, &p
);
1118 create_asteroid(SMALL
, &p
);
1122 create_asteroid(MEDIUM
, &p
);
1123 create_asteroid(MEDIUM
, &p
);
1128 /*************************************************
1130 *************************************************/
1132 /* Initialise the ship */
1133 static void initialise_ship(void)
1135 struct Point
* point
;
1136 struct Point
* lives_point
;
1139 ship
.position
.x
= CENTER_LCD_X
* SCALE
;
1140 ship
.position
.y
= CENTER_LCD_Y
* SCALE
;
1141 ship
.position
.dx
= 0;
1142 ship
.position
.dy
= 0;
1143 ship
.rotation
.x
= SIN_COS_SCALE
;
1144 ship
.rotation
.y
= 0;
1146 ship
.explode_countdown
= 0;
1147 ship
.invulnerable_time
= INVULNERABLE_TIME
;
1149 point
= ship
.vertices
;
1150 lives_point
= lives_points
;
1151 for(n
= 0; n
< NUM_SHIP_VERTICES
*2; n
+= 2)
1153 point
->x
= ship_vertices
[n
];
1154 point
->y
= ship_vertices
[n
+1];
1157 /* dx and dy are used when rotate polygon */
1158 point
->dx
= point
->x
;
1159 point
->dy
= point
->y
;
1160 /* grab a copy of the ships points for the lives display: */
1161 lives_point
->x
= point
->x
;
1162 lives_point
->y
= point
->y
;
1170 * Draws the ship, moves the ship and creates a new
1171 * one if it's finished exploding.
1173 static void draw_and_move_ship(void)
1175 if (ship
.invulnerable_time
> BLINK_TIME
|| ship
.invulnerable_time
% 2 != 0)
1186 draw_polygon(ship
.vertices
, NUM_SHIP_VERTICES
,
1187 ship
.position
.x
, ship
.position
.y
);
1190 if (game_state
!= PAUSE_MODE
)
1194 if (ship
.invulnerable_time
> 0)
1195 ship
.invulnerable_time
--;
1196 move_point(&ship
.position
);
1198 else if (ship
.explode_countdown
> 0)
1200 ship
.explode_countdown
--;
1201 if (ship
.explode_countdown
<= 0)
1206 game_state
= GAME_OVER
;
1217 static void explode_ship(void)
1219 if (!ship
.invulnerable_time
)
1221 /* if not invulnerable, blow up ship */
1222 ship
.explode_countdown
= EXPLOSION_LENGTH
;
1223 ship
.exists
= false;
1224 create_trail_blaze(EXPLOSION_SHIP
, &ship
.position
);
1228 /* Rotate the ship using the passed sin & cos values */
1229 static void rotate_ship(int cos
, int sin
)
1233 rotate_polygon(ship
.vertices
, NUM_SHIP_VERTICES
,
1234 &ship
.rotation
, cos
, sin
);
1238 static void thrust_ship(void)
1242 ship
.position
.dx
+= ( ship
.vertices
[0].x
- ship
.vertices
[2].x
)/20;
1243 ship
.position
.dy
+= ( ship
.vertices
[0].y
- ship
.vertices
[2].y
)/20;
1245 /* if dx and dy are below a certain threshold, then set 'em to 0
1246 but to do this we need to ascertain if the spacehip as moved on
1247 screen for more than a certain amount. */
1249 create_trail_blaze(EXPLOSION_THRUST
, &ship
.position
);
1253 /* stop movement of ship, 'cos that's what happens when you go into hyperspace. */
1254 static void hyperspace(void)
1258 ship
.position
.dx
= ship
.position
.dy
= 0;
1259 ship
.position
.x
= (rb
->rand()%SCALED_WIDTH
);
1260 ship
.position
.y
= (rb
->rand()%SCALED_HEIGHT
);
1264 static void draw_lives(void)
1268 int px
= (LCD_WIDTH
-1 - 4)*SCALE
;
1269 int py
= (LCD_HEIGHT
-1 - 6)*SCALE
;
1271 int px
= (LCD_WIDTH
-1 - 3)*SCALE
;
1272 int py
= (LCD_HEIGHT
-1 - 4)*SCALE
;
1280 draw_polygon(lives_points
, NUM_SHIP_VERTICES
, px
, py
);
1293 /* Initialise a missile */
1294 static void initialise_missile(struct Missile
* missile
)
1296 missile
->position
.x
= ship
.position
.x
+ ship
.vertices
[0].x
;
1297 missile
->position
.y
= ship
.position
.y
+ ship
.vertices
[0].y
;
1298 missile
->position
.dx
= (ship
.vertices
[0].x
- ship
.vertices
[2].x
)/2;
1299 missile
->position
.dy
= (ship
.vertices
[0].y
- ship
.vertices
[2].y
)/2;
1300 missile
->alive
= MISSILE_LIFE_LENGTH
;
1301 missile
->oldpoint
.x
= missile
->position
.x
;
1302 missile
->oldpoint
.y
= missile
->position
.y
;
1305 /* Fire the next missile */
1306 static void fire_missile(void)
1308 struct Missile
* missile
;
1313 missile
= missiles_array
;
1314 n
= MAX_NUM_MISSILES
;
1317 if (missile
->alive
<= 0)
1319 initialise_missile(missile
);
1327 /* Draw and Move all the missiles */
1328 static void draw_and_move_missiles(void)
1330 struct Missile
* missile
;
1331 struct Point vertices
[2];
1334 SET_FG(COL_MISSILE
);
1336 missile
= missiles_array
;
1337 n
= MAX_NUM_MISSILES
;
1340 if (missile
->alive
> 0)
1344 vertices
[1].x
= -missile
->position
.dx
;
1345 vertices
[1].y
= -missile
->position
.dy
;
1346 draw_polygon(vertices
, 2, missile
->position
.x
, missile
->position
.y
);
1348 if (game_state
!= PAUSE_MODE
)
1350 missile
->oldpoint
.x
= missile
->position
.x
;
1351 missile
->oldpoint
.y
= missile
->position
.y
;
1352 move_point(&missile
->position
);
1360 /*************************************************
1362 *************************************************/
1364 static void initialise_enemy(void)
1366 struct Point
* point
;
1370 if (rb
->rand()%100 > enemy
.size_probability
)
1373 enemy
.size_probability
++;
1374 if (enemy
.size_probability
> 90)
1376 enemy
.size_probability
= ENEMY_BIG_PROBABILITY_START
;
1382 enemy
.size_probability
= ENEMY_BIG_PROBABILITY_START
;
1385 enemy
.exists
= true;
1386 enemy
.explode_countdown
= 0;
1387 enemy
.appear_countdown
= enemy
.appear_timing
;
1389 point
= enemy
.vertices
;
1390 for(n
= 0; n
< NUM_ENEMY_VERTICES
*2; n
+= 2)
1392 point
->x
= enemy_vertices
[n
];
1393 point
->y
= enemy_vertices
[n
+1];
1394 point
->x
*= size
*SCALE
/2;
1395 point
->y
*= size
*SCALE
/2;
1399 if (ship
.position
.x
>= SCALED_WIDTH
/2)
1401 enemy
.position
.dx
= ENEMY_SPEED
;
1402 enemy
.position
.x
= 0;
1406 enemy
.position
.dx
= -ENEMY_SPEED
;
1407 enemy
.position
.x
= SCALED_WIDTH
;
1410 if (ship
.position
.y
>= SCALED_HEIGHT
/2)
1412 enemy
.position
.dy
= ENEMY_SPEED
;
1413 enemy
.position
.y
= 0;
1417 enemy
.position
.dy
= -ENEMY_SPEED
;
1418 enemy
.position
.y
= SCALED_HEIGHT
;
1421 enemy
.position
.dx
*= SCALE
/10;
1422 enemy
.position
.dy
*= SCALE
/10;
1425 static void draw_and_move_enemy(void)
1431 draw_polygon(enemy
.vertices
, NUM_ENEMY_VERTICES
,
1432 enemy
.position
.x
, enemy
.position
.y
);
1435 if (game_state
!= PAUSE_MODE
)
1439 enemy
.position
.x
+= enemy
.position
.dx
;
1440 enemy
.position
.y
+= enemy
.position
.dy
;
1442 if (enemy
.position
.x
> SCALED_WIDTH
|| enemy
.position
.x
< 0)
1443 enemy
.exists
= false;
1445 enemy
.position
.y
%= SCALED_HEIGHT
;
1446 if (enemy
.position
.y
< 0)
1447 enemy
.position
.y
+= SCALED_HEIGHT
;
1449 if ((rb
->rand()%1000) < 10)
1450 enemy
.position
.dy
= -enemy
.position
.dy
;
1452 else if (enemy
.explode_countdown
> 0)
1454 enemy
.explode_countdown
--;
1458 if (enemy
.appear_countdown
> 0)
1459 enemy
.appear_countdown
--;
1460 else if (rb
->rand()%100 >= enemy
.appear_probability
)
1465 if (enemy_missile
.alive
<= 0)
1467 /* if no missile and the enemy is here and not exploding..
1469 if (enemy
.exists
&& ship
.exists
&&
1470 game_state
== PLAY_MODE
&& (rb
->rand()%10) >= 5 )
1472 int dx
= ship
.position
.x
- enemy
.position
.x
;
1473 int dy
= ship
.position
.y
- enemy
.position
.y
;
1475 if (dx
< -SCALED_WIDTH
/2) dx
+= SCALED_WIDTH
;
1476 else if (dx
> SCALED_WIDTH
/2) dx
-= SCALED_WIDTH
;
1477 if (dy
< -SCALED_HEIGHT
/2) dy
+= SCALED_HEIGHT
;
1478 else if (dy
> SCALED_HEIGHT
/2) dy
-= SCALED_HEIGHT
;
1480 enemy_missile
.position
.x
= enemy
.position
.x
;
1481 enemy_missile
.position
.y
= enemy
.position
.y
;
1483 /* lame, needs to be sorted - it's trying to shoot at the ship */
1485 enemy_missile
.position
.dx
= -1;
1486 else if (dx
> 5*SCALE
)
1487 enemy_missile
.position
.dx
= 1;
1489 enemy_missile
.position
.dx
= 0;
1492 enemy_missile
.position
.dy
= -1;
1493 else if (dy
> 5*SCALE
)
1494 enemy_missile
.position
.dy
= 1;
1496 enemy_missile
.position
.dy
= 0;
1498 while (enemy_missile
.position
.dx
== 0 &&
1499 enemy_missile
.position
.dy
== 0)
1501 enemy_missile
.position
.dx
= rb
->rand()%2-1;
1502 enemy_missile
.position
.dy
= rb
->rand()%2-1;
1505 enemy_missile
.position
.dx
*= SCALE
;
1506 enemy_missile
.position
.dy
*= SCALE
;
1507 enemy_missile
.alive
= ENEMY_MISSILE_LIFE_LENGTH
;
1512 rb
->lcd_fillrect( enemy_missile
.position
.x
/SCALE
,
1513 enemy_missile
.position
.y
/SCALE
,
1514 POINT_SIZE
, POINT_SIZE
);
1515 if (game_state
!= PAUSE_MODE
)
1517 move_point(&enemy_missile
.position
);
1518 enemy_missile
.alive
--;
1523 /*************************************************
1524 ** Check collisions.
1525 *************************************************/
1527 /* Add score if missile hit asteroid or enemy */
1528 static void add_score(int val
)
1530 current_score
+= val
;
1531 if (current_score
>= extra_life
)
1534 extra_life
+= EXTRA_LIFE
;
1538 static bool is_point_within_asteroid(struct Asteroid
* asteroid
,
1539 struct Point
* point
)
1541 if (is_point_within_rectangle(&asteroid
->position
, point
, asteroid
->radius
)
1542 && is_point_in_polygon(asteroid
->vertices
, NUM_ASTEROID_VERTICES
,
1543 point
->x
- asteroid
->position
.x
,
1544 point
->y
- asteroid
->position
.y
))
1546 explode_asteroid(asteroid
);
1553 static bool is_point_within_ship(struct Point
* point
)
1555 if (is_point_within_rectangle(&ship
.position
, point
, SIZE_SHIP_COLLISION
)
1556 && is_point_in_polygon(ship
.vertices
, NUM_SHIP_VERTICES
,
1557 point
->x
- ship
.position
.x
,
1558 point
->y
- ship
.position
.y
))
1566 static bool is_point_within_enemy(struct Point
* point
)
1568 if (is_point_within_rectangle(&enemy
.position
, point
, SIZE_ENEMY_COLLISION
))
1571 enemy
.explode_countdown
= EXPLOSION_LENGTH
;
1572 enemy
.exists
= false;
1573 create_trail_blaze(EXPLOSION_ENEMY
, &enemy
.position
);
1580 static bool is_ship_within_asteroid(struct Asteroid
* asteroid
)
1584 if (!is_point_within_rectangle(&asteroid
->position
, &ship
.position
,
1585 asteroid
->radius
+SIZE_SHIP_COLLISION
))
1588 p
.x
= ship
.position
.x
+ ship
.vertices
[0].x
;
1589 p
.y
= ship
.position
.y
+ ship
.vertices
[0].y
;
1590 if (is_point_within_asteroid(asteroid
, &p
))
1593 p
.x
= ship
.position
.x
+ ship
.vertices
[1].x
;
1594 p
.y
= ship
.position
.y
+ ship
.vertices
[1].y
;
1595 if (is_point_within_asteroid(asteroid
, &p
))
1598 p
.x
= ship
.position
.x
+ ship
.vertices
[3].x
;
1599 p
.y
= ship
.position
.y
+ ship
.vertices
[3].y
;
1600 if (is_point_within_asteroid(asteroid
, &p
))
1606 /* Check for collsions between the missiles and the asteroids and the ship */
1607 static void check_collisions(void)
1609 struct Missile
* missile
;
1610 struct Asteroid
* asteroid
;
1612 bool asteroids_onscreen
= false;
1614 asteroid
= asteroids_array
;
1615 m
= MAX_NUM_ASTEROIDS
;
1618 /* if the asteroids exists then test missile collision: */
1619 if (asteroid
->exists
)
1621 missile
= missiles_array
;
1622 n
= MAX_NUM_MISSILES
;
1625 /* if the missiles exists: */
1626 if (missile
->alive
> 0)
1628 /* has the missile hit the asteroid? */
1629 if (is_point_within_asteroid(asteroid
, &missile
->position
) ||
1630 is_point_within_asteroid(asteroid
, &missile
->oldpoint
))
1640 /* now check collision with ship: */
1641 if (asteroid
->exists
&& ship
.exists
)
1643 if (is_ship_within_asteroid(asteroid
))
1650 /* has the enemy missile blown something up? */
1651 if (asteroid
->exists
&& enemy_missile
.alive
> 0)
1653 if (is_point_within_asteroid(asteroid
, &enemy_missile
.position
))
1655 enemy_missile
.alive
= 0;
1660 /* is an asteroid still exploding? */
1661 if (asteroid
->explode_countdown
> 0)
1662 asteroids_onscreen
= true;
1667 /* now check collision between ship and enemy */
1668 if (enemy
.exists
&& ship
.exists
)
1670 /* has the enemy collided with the ship? */
1671 if (is_point_within_enemy(&ship
.position
))
1674 create_trail_blaze(EXPLOSION_ENEMY
, &enemy
.position
);
1679 /* Now see if the enemy has been shot at by the ships missiles: */
1680 missile
= missiles_array
;
1681 n
= MAX_NUM_MISSILES
;
1684 if (missile
->alive
> 0 &&
1685 is_point_within_enemy(&missile
->position
))
1695 /* test collision with enemy missile and ship: */
1696 if (enemy_missile
.alive
> 0 && is_point_within_ship(&enemy_missile
.position
))
1699 enemy_missile
.alive
= 0;
1700 enemy_missile
.position
.x
= enemy_missile
.position
.y
= 0;
1703 /* if all asteroids cleared then start again: */
1704 if (asteroid_count
== 0 && !asteroids_onscreen
1705 && !enemy
.exists
&& enemy
.explode_countdown
<= 0)
1708 if (current_level
> MAX_LEVEL
)
1709 current_level
= START_LEVEL
;
1710 enemy
.appear_probability
+= 5;
1711 if (enemy
.appear_probability
>= 100)
1712 enemy
.appear_probability
= ENEMY_APPEAR_PROBABILITY_START
;
1713 enemy
.appear_timing
-= 30;
1714 if (enemy
.appear_timing
< 30)
1715 enemy
.appear_timing
= 30;
1716 game_state
= SHOW_LEVEL
;
1717 show_level_timeout
= SHOW_LEVEL_TIME
;
1725 static void create_stars(void)
1734 p
->x
= (rb
->rand()%LCD_WIDTH
);
1735 p
->y
= (rb
->rand()%LCD_HEIGHT
);
1740 static void drawstars(void)
1751 rb
->lcd_drawpixel(p
->x
, p
->y
);
1756 /*************************************************
1757 ** Creates start_num number of new asteroids of
1759 **************************************************/
1760 static void initialise_level(int start_num
)
1762 struct Asteroid
* asteroid
;
1763 struct Missile
* missile
;
1764 struct TrailPoint
* tpoint
;
1766 asteroid_count
= next_missile_count
= next_thrust_count
= 0;
1770 enemy
.explode_countdown
= 0;
1771 enemy_missile
.alive
= 0;
1773 /* clear asteroids */
1774 asteroid
= asteroids_array
;
1775 n
= MAX_NUM_ASTEROIDS
;
1778 asteroid
->exists
= false;
1782 /* make some LARGE asteroids */
1783 for(n
= 0; n
< start_num
; n
++)
1784 initialise_asteroid(&asteroids_array
[n
], LARGE
, NULL
);
1786 /* ensure all missiles are out of action: */
1787 missile
= missiles_array
;
1788 n
= MAX_NUM_MISSILES
;
1795 tpoint
= trail_points
;
1796 n
= NUM_TRAIL_POINTS
;
1804 static void initialise_game(void)
1806 enemy
.appear_probability
= ENEMY_APPEAR_PROBABILITY_START
;
1807 enemy
.appear_timing
= ENEMY_APPEAR_TIMING_START
;
1808 enemy
.appear_countdown
= enemy
.appear_timing
;
1809 enemy
.size_probability
= ENEMY_BIG_PROBABILITY_START
;
1810 current_level
= START_LEVEL
;
1811 num_lives
= START_LIVES
;
1812 extra_life
= EXTRA_LIFE
;
1815 initialise_level(0);
1816 game_state
= SHOW_LEVEL
;
1817 show_level_timeout
= SHOW_LEVEL_TIME
;
1821 static bool spacerocks_help(void)
1823 static char *help_text
[] = {
1824 "Spacerocks", "", "Aim", "",
1825 "The", "goal", "of", "the", "game", "is", "to", "blow", "up",
1826 "the", "asteroids", "and", "avoid", "being", "hit", "by", "them.",
1827 "Also", "you'd", "better", "watch", "out", "for", "the", "UFOs!"
1829 static struct style_text formation
[]={
1830 { 0, TEXT_CENTER
|TEXT_UNDERLINE
},
1835 rb
->lcd_setfont(FONT_UI
);
1838 if (display_text(ARRAYLEN(help_text
), help_text
, formation
, NULL
, true))
1840 rb
->lcd_setfont(FONT_SYSFIXED
);
1845 #define PLUGIN_OTHER 10
1847 static int spacerocks_menu_cb(int action
, const struct menu_item_ex
*this_item
)
1849 if (action
== ACTION_REQUEST_MENUITEM
1850 && !ingame
&& ((intptr_t)this_item
)==0)
1851 return ACTION_EXIT_MENUITEM
;
1855 static int spacerocks_menu(void)
1858 MENUITEM_STRINGLIST(main_menu
, "Spacerocks Menu", spacerocks_menu_cb
,
1859 "Resume Game", "Start New Game",
1860 "Help", "High Scores",
1861 "Playback Control", "Quit");
1862 rb
->button_clear_queue();
1866 switch (rb
->do_menu(&main_menu
, &selection
, NULL
, false))
1869 return PLUGIN_OTHER
;
1872 return PLUGIN_OTHER
;
1874 if (spacerocks_help())
1875 return PLUGIN_USB_CONNECTED
;
1878 highscore_show(-1, highscores
, NUM_SCORES
, true);
1881 playback_control(NULL
);
1885 case MENU_ATTACHED_USB
:
1886 return PLUGIN_USB_CONNECTED
;
1893 static int spacerocks_game_loop(void)
1900 if ((ret
= spacerocks_menu()) != PLUGIN_OTHER
)
1908 end
= *rb
->current_tick
+ (CYCLETIME
* HZ
) / 1000;
1909 rb
->lcd_clear_display();
1915 rb
->splash (HZ
* 2, "Game Over");
1916 rb
->lcd_clear_display();
1917 position
= highscore_update(current_score
, current_level
, "",
1918 highscores
, NUM_SCORES
);
1922 rb
->splash(HZ
*2, "New High Score");
1923 highscore_show(position
, highscores
, NUM_SCORES
, true);
1925 return PLUGIN_OTHER
;
1929 rb
->lcd_putsxyf(1,LCD_HEIGHT
-8, "score %d ", current_score
);
1930 rb
->lcd_putsxy(CENTER_LCD_X
- 15,
1931 CENTER_LCD_Y
+ CENTER_LCD_Y
/2 - 4, "pause");
1932 draw_and_move_missiles();
1934 draw_and_move_ship();
1938 rb
->lcd_putsxyf(1, LCD_HEIGHT
-8, "score %d ", current_score
);
1939 draw_and_move_missiles();
1942 draw_and_move_ship();
1946 rb
->lcd_putsxyf(1, LCD_HEIGHT
-8, "score %d ", current_score
);
1947 rb
->lcd_putsxyf(CENTER_LCD_X
- 20,
1948 CENTER_LCD_Y
+ CENTER_LCD_Y
/2 - 4,
1949 "stage %d ", current_level
);
1951 draw_and_move_ship();
1952 show_level_timeout
--;
1953 if (show_level_timeout
<= 0)
1955 initialise_level(current_level
);
1956 game_state
= PLAY_MODE
;
1960 draw_and_move_trail_blaze();
1962 draw_and_move_asteroids();
1963 draw_and_move_enemy();
1967 #ifdef HAS_BUTTON_HOLD
1968 if (rb
->button_hold() && game_state
== PLAY_MODE
)
1969 game_state
= PAUSE_MODE
;
1971 button
= rb
->button_get(false);
1975 return PLUGIN_OTHER
;
1979 if (game_state
== PAUSE_MODE
)
1980 game_state
= PLAY_MODE
;
1981 else if (game_state
== PLAY_MODE
)
1982 game_state
= PAUSE_MODE
;
1986 case (AST_LEFT
| BUTTON_REPEAT
):
1987 if (game_state
== PLAY_MODE
|| game_state
== SHOW_LEVEL
)
1988 rotate_ship(SHIP_ROT_ACW_COS
, SHIP_ROT_ACW_SIN
);
1992 case (AST_RIGHT
| BUTTON_REPEAT
):
1993 if (game_state
== PLAY_MODE
|| game_state
== SHOW_LEVEL
)
1994 rotate_ship(SHIP_ROT_CW_COS
, SHIP_ROT_CW_SIN
);
1998 case (AST_THRUST
| BUTTON_REPEAT
):
1999 if (game_state
== PLAY_MODE
|| game_state
== SHOW_LEVEL
)
2001 if (next_thrust_count
<= 0)
2003 next_thrust_count
= 5;
2009 case (AST_HYPERSPACE
):
2010 if (game_state
== PLAY_MODE
)
2012 /* maybe shield if it gets too hard */
2016 case (AST_FIRE
| BUTTON_REPEAT
):
2017 if (game_state
== PLAY_MODE
)
2019 if (next_missile_count
<= 0)
2022 next_missile_count
= 10;
2025 else if(game_state
== PAUSE_MODE
)
2026 game_state
= PLAY_MODE
;
2030 if (rb
->default_event_handler(button
)==SYS_USB_CONNECTED
)
2031 return PLUGIN_USB_CONNECTED
;
2035 if (next_missile_count
> 0)
2036 next_missile_count
--;
2038 if (next_thrust_count
> 0)
2039 next_thrust_count
--;
2041 if (TIME_BEFORE(*rb
->current_tick
, end
))
2042 rb
->sleep(end
-*rb
->current_tick
);
2048 enum plugin_status
plugin_start(const void* parameter
)
2051 int ret
= PLUGIN_OTHER
;
2054 rb
->lcd_set_backdrop(NULL
);
2056 /* universal font */
2057 rb
->lcd_setfont(FONT_SYSFIXED
);
2058 /* Turn off backlight timeout */
2059 backlight_ignore_timeout();
2060 highscore_load(SCORE_FILE
, highscores
, NUM_SCORES
);
2061 rb
->srand(*rb
->current_tick
);
2063 /* create stars once, and once only: */
2066 while (ret
== PLUGIN_OTHER
)
2067 ret
= spacerocks_game_loop();
2069 rb
->lcd_setfont(FONT_UI
);
2070 highscore_save(SCORE_FILE
, highscores
, NUM_SCORES
);
2071 /* Turn on backlight timeout (revert to settings) */
2072 backlight_use_settings();