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_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
243 #error No keymap defined!
246 #ifdef HAVE_TOUCHSCREEN
248 #define AST_PAUSE BUTTON_CENTER
251 #define AST_QUIT BUTTON_TOPLEFT
254 #define AST_THRUST BUTTON_TOPMIDDLE
256 #ifndef AST_HYPERSPACE
257 #define AST_HYPERSPACE BUTTON_TOPRIGHT
260 #define AST_LEFT BUTTON_MIDLEFT
263 #define AST_RIGHT BUTTON_MIDRIGHT
266 #define AST_FIRE BUTTON_BOTTOMMIDDLE
270 #define RES MAX(LCD_WIDTH, LCD_HEIGHT)
271 #define LARGE_LCD (RES >= 200)
277 #define WRAP_GAP (LARGE*SCALE*3)
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
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
303 #define SIZE_SHIP_COLLISION 8*SCALE
305 #define SIZE_SHIP_COLLISION 6*SCALE
308 #define LITTLE_SHIP 1
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)
316 #define SIZE_ENEMY_COLLISION 7*SCALE
318 #define SIZE_ENEMY_COLLISION 5*SCALE
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
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
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
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
384 #define SCORE_FILE PLUGIN_GAMES_DIR "/spacerocks.score"
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] =
404 /* The array of points that make up an asteroid */
405 static const short asteroid_two
[NUM_ASTEROID_VERTICES
*2] =
419 /* The array of points that make up an asteroid */
420 static const short asteroid_three
[NUM_ASTEROID_VERTICES
*2] =
434 /* The array of points the make up the ship */
435 static const short ship_vertices
[NUM_SHIP_VERTICES
*2] =
450 /* The array of points the make up the bad spaceship */
451 static const short enemy_vertices
[NUM_ENEMY_VERTICES
*2] =
513 struct Point position
;
515 #ifdef HAVE_LCD_COLOR
523 /* Asteroid structure, contains an array of points */
526 struct Point position
;
527 struct Point rotation
;
528 struct Point vertices
[NUM_ASTEROID_VERTICES
];
530 int explode_countdown
;
531 enum asteroid_type type
;
539 struct Point position
;
540 struct Point rotation
;
541 struct Point vertices
[NUM_SHIP_VERTICES
];
543 int explode_countdown
;
544 int invulnerable_time
;
549 struct Point position
;
550 struct Point vertices
[NUM_ENEMY_VERTICES
];
552 int explode_countdown
;
553 int appear_countdown
;
554 short size_probability
;
555 short appear_probability
;
561 struct Point position
;
562 struct Point oldpoint
;
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
,
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
;
604 pj
= vertices
+ num_vertices
-1;
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
))
620 /* Check if point is within a rectangle */
621 static bool is_point_within_rectangle(struct Point
* rect
, struct Point
* p
,
624 int dx
= p
->x
- rect
->x
;
625 int dy
= p
->y
- rect
->y
;
627 rb
->lcd_drawrect((rect
->x
- size
)/SCALE
, (rect
->y
- size
)/SCALE
,
628 (size
*2+1)/SCALE
, (size
*2+1)/SCALE
);
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
);
638 static void rotate_polygon(struct Point
* vertices
, int num_vertices
,
639 struct Point
* rotation
, int cos
, int sin
)
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
;
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
;
677 static void draw_polygon(struct Point
* vertices
, int num_vertices
,
680 int n
, new_x
, new_y
, old_x
, old_y
;
684 if (px
> SCALED_WIDTH
- WRAP_GAP
)
686 if (py
> SCALED_HEIGHT
- WRAP_GAP
)
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
;
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
);
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
);
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
;
723 point
->x
+= SCALED_WIDTH
;
725 /* Check bounds on the y-axis: */
726 point
->y
%= SCALED_HEIGHT
;
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
)
752 struct TrailPoint
* tpoint
;
755 if (colour
!= EXPLOSION_SHIP
)
757 numtoadd
= NUM_TRAIL_POINTS
/5;
761 numtoadd
= NUM_TRAIL_POINTS
/8;
764 /* give the point a random countdown timer, so they dissapears at different
766 tpoint
= trail_points
;
767 n
= NUM_TRAIL_POINTS
;
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
;
781 create_explosion_trail(tpoint
);
783 #ifdef HAVE_LCD_COLOR
790 case EXPLOSION_ASTEROID
:
791 create_explosion_trail(tpoint
);
793 #ifdef HAVE_LCD_COLOR
794 tpoint
->r
= ASTEROID_R
;
795 tpoint
->g
= ASTEROID_G
;
796 tpoint
->b
= ASTEROID_B
;
800 case EXPLOSION_ENEMY
:
801 create_explosion_trail(tpoint
);
803 #ifdef HAVE_LCD_COLOR
810 case EXPLOSION_THRUST
:
811 create_ship_trail(tpoint
);
813 #ifdef HAVE_LCD_COLOR
814 tpoint
->r
= THRUST_R
;
815 tpoint
->g
= THRUST_G
;
816 tpoint
->b
= THRUST_B
;
822 /* give the points a speed based on direction of travel
824 tpoint
->position
.dx
+= position
->dx
;
825 tpoint
->position
.dy
+= position
->dy
;
835 static void draw_and_move_trail_blaze(void)
837 struct TrailPoint
* tpoint
;
840 /* loop through, if alive then move and draw.
841 when drawn, countdown it's timer.
844 tpoint
= trail_points
;
845 n
= NUM_TRAIL_POINTS
;
848 if (tpoint
->alive
> 0)
850 if (game_state
!= PAUSE_MODE
)
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
;
861 SET_FG(LCD_RGBPACK(tpoint
->r
, tpoint
->g
, tpoint
->b
));
862 rb
->lcd_drawpixel(tpoint
->position
.x
/SCALE
, tpoint
->position
.y
/SCALE
);
868 /*************************************************
870 *************************************************/
872 static void rotate_asteroid(struct Asteroid
* asteroid
)
874 rotate_polygon(asteroid
->vertices
, NUM_ASTEROID_VERTICES
,
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
;
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 */
901 asteroid
->speed_cos
= FAST_ROT_CW_COS
;
902 asteroid
->speed_sin
= FAST_ROT_CW_SIN
;
906 asteroid
->speed_cos
= FAST_ROT_ACW_COS
;
907 asteroid
->speed_sin
= FAST_ROT_ACW_SIN
;
911 asteroid
->speed_cos
= SLOW_ROT_ACW_COS
;
912 asteroid
->speed_sin
= SLOW_ROT_ACW_SIN
;
916 asteroid
->speed_cos
= SLOW_ROT_CW_COS
;
917 asteroid
->speed_sin
= SLOW_ROT_CW_SIN
;
922 asteroid_vertices
= asteroid_one
;
924 asteroid_vertices
= asteroid_two
;
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
;
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
,
952 asteroid
->position
.x
= position
->x
;
953 asteroid
->position
.y
= position
->y
;
957 asteroid
->position
.dx
= (rb
->rand()%ASTEROID_SPEED
)-ASTEROID_SPEED
/2;
958 } while (asteroid
->position
.dx
== 0);
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: */
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
;
986 asteroid
= asteroids_array
;
987 n
= MAX_NUM_ASTEROIDS
;
990 if (!asteroid
->exists
&& asteroid
->explode_countdown
<= 0)
992 initialise_asteroid(asteroid
, type
, position
);
999 /* Draw and move all asteroids */
1000 static void draw_and_move_asteroids(void)
1002 struct Asteroid
* asteroid
;
1005 SET_FG(COL_ASTEROID
);
1007 asteroid
= asteroids_array
;
1008 n
= MAX_NUM_ASTEROIDS
;
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
--;
1032 static void explode_asteroid(struct Asteroid
* asteroid
)
1035 p
.dx
= asteroid
->position
.dx
;
1036 p
.dy
= asteroid
->position
.dy
;
1037 p
.x
= asteroid
->position
.x
;
1038 p
.y
= asteroid
->position
.y
;
1041 asteroid
->exists
= false;
1043 switch(asteroid
->type
)
1046 asteroid
->explode_countdown
= EXPLOSION_LENGTH
;
1047 create_trail_blaze(EXPLOSION_ASTEROID
, &p
);
1051 create_asteroid(SMALL
, &p
);
1052 create_asteroid(SMALL
, &p
);
1056 create_asteroid(MEDIUM
, &p
);
1057 create_asteroid(MEDIUM
, &p
);
1062 /*************************************************
1064 *************************************************/
1066 /* Initialise the ship */
1067 static void initialise_ship(void)
1069 struct Point
* point
;
1070 struct Point
* lives_point
;
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;
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];
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
;
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)
1120 draw_polygon(ship
.vertices
, NUM_SHIP_VERTICES
,
1121 ship
.position
.x
, ship
.position
.y
);
1124 if (game_state
!= PAUSE_MODE
)
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)
1140 game_state
= GAME_OVER
;
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
)
1167 rotate_polygon(ship
.vertices
, NUM_SHIP_VERTICES
,
1168 &ship
.rotation
, cos
, sin
);
1172 static void thrust_ship(void)
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)
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)
1202 int px
= (LCD_WIDTH
-1 - 4)*SCALE
;
1203 int py
= (LCD_HEIGHT
-1 - 6)*SCALE
;
1205 int px
= (LCD_WIDTH
-1 - 3)*SCALE
;
1206 int py
= (LCD_HEIGHT
-1 - 4)*SCALE
;
1214 draw_polygon(lives_points
, NUM_SHIP_VERTICES
, px
, py
);
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
;
1247 missile
= missiles_array
;
1248 n
= MAX_NUM_MISSILES
;
1251 if (missile
->alive
<= 0)
1253 initialise_missile(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];
1268 SET_FG(COL_MISSILE
);
1270 missile
= missiles_array
;
1271 n
= MAX_NUM_MISSILES
;
1274 if (missile
->alive
> 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
);
1294 /*************************************************
1296 *************************************************/
1298 static void initialise_enemy(void)
1300 struct Point
* point
;
1304 if (rb
->rand()%100 > enemy
.size_probability
)
1307 enemy
.size_probability
++;
1308 if (enemy
.size_probability
> 90)
1310 enemy
.size_probability
= ENEMY_BIG_PROBABILITY_START
;
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;
1333 if (ship
.position
.x
>= SCALED_WIDTH
/2)
1335 enemy
.position
.dx
= ENEMY_SPEED
;
1336 enemy
.position
.x
= 0;
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;
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)
1365 draw_polygon(enemy
.vertices
, NUM_ENEMY_VERTICES
,
1366 enemy
.position
.x
, enemy
.position
.y
);
1369 if (game_state
!= PAUSE_MODE
)
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
--;
1392 if (enemy
.appear_countdown
> 0)
1393 enemy
.appear_countdown
--;
1394 else if (rb
->rand()%100 >= enemy
.appear_probability
)
1399 if (enemy_missile
.alive
<= 0)
1401 /* if no missile and the enemy is here and not exploding..
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 */
1419 enemy_missile
.position
.dx
= -1;
1420 else if (dx
> 5*SCALE
)
1421 enemy_missile
.position
.dx
= 1;
1423 enemy_missile
.position
.dx
= 0;
1426 enemy_missile
.position
.dy
= -1;
1427 else if (dy
> 5*SCALE
)
1428 enemy_missile
.position
.dy
= 1;
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
;
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
)
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
);
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
))
1500 static bool is_point_within_enemy(struct Point
* point
)
1502 if (is_point_within_rectangle(&enemy
.position
, point
, SIZE_ENEMY_COLLISION
))
1505 enemy
.explode_countdown
= EXPLOSION_LENGTH
;
1506 enemy
.exists
= false;
1507 create_trail_blaze(EXPLOSION_ENEMY
, &enemy
.position
);
1514 static bool is_ship_within_asteroid(struct Asteroid
* asteroid
)
1518 if (!is_point_within_rectangle(&asteroid
->position
, &ship
.position
,
1519 asteroid
->radius
+SIZE_SHIP_COLLISION
))
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
))
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
))
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
))
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
;
1546 bool asteroids_onscreen
= false;
1548 asteroid
= asteroids_array
;
1549 m
= MAX_NUM_ASTEROIDS
;
1552 /* if the asteroids exists then test missile collision: */
1553 if (asteroid
->exists
)
1555 missile
= missiles_array
;
1556 n
= MAX_NUM_MISSILES
;
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
))
1574 /* now check collision with ship: */
1575 if (asteroid
->exists
&& ship
.exists
)
1577 if (is_ship_within_asteroid(asteroid
))
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;
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
))
1608 create_trail_blaze(EXPLOSION_ENEMY
, &enemy
.position
);
1613 /* Now see if the enemy has been shot at by the ships missiles: */
1614 missile
= missiles_array
;
1615 n
= MAX_NUM_MISSILES
;
1618 if (missile
->alive
> 0 &&
1619 is_point_within_enemy(&missile
->position
))
1629 /* test collision with enemy missile and ship: */
1630 if (enemy_missile
.alive
> 0 && is_point_within_ship(&enemy_missile
.position
))
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)
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
;
1659 static void create_stars(void)
1668 p
->x
= (rb
->rand()%LCD_WIDTH
);
1669 p
->y
= (rb
->rand()%LCD_HEIGHT
);
1674 static void drawstars(void)
1685 rb
->lcd_drawpixel(p
->x
, p
->y
);
1690 /*************************************************
1691 ** Creates start_num number of new asteroids of
1693 **************************************************/
1694 static void initialise_level(int start_num
)
1696 struct Asteroid
* asteroid
;
1697 struct Missile
* missile
;
1698 struct TrailPoint
* tpoint
;
1700 asteroid_count
= next_missile_count
= next_thrust_count
= 0;
1704 enemy
.explode_countdown
= 0;
1705 enemy_missile
.alive
= 0;
1707 /* clear asteroids */
1708 asteroid
= asteroids_array
;
1709 n
= MAX_NUM_ASTEROIDS
;
1712 asteroid
->exists
= false;
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
;
1729 tpoint
= trail_points
;
1730 n
= NUM_TRAIL_POINTS
;
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
;
1749 initialise_level(0);
1750 game_state
= SHOW_LEVEL
;
1751 show_level_timeout
= SHOW_LEVEL_TIME
;
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
},
1769 rb
->lcd_setfont(FONT_UI
);
1772 if (display_text(ARRAYLEN(help_text
), help_text
, formation
, NULL
, true))
1774 rb
->lcd_setfont(FONT_SYSFIXED
);
1779 #define PLUGIN_OTHER 10
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
;
1789 static int spacerocks_menu(void)
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();
1800 switch (rb
->do_menu(&main_menu
, &selection
, NULL
, false))
1803 return PLUGIN_OTHER
;
1806 return PLUGIN_OTHER
;
1808 if (spacerocks_help())
1809 return PLUGIN_USB_CONNECTED
;
1812 highscore_show(-1, highscores
, NUM_SCORES
, true);
1815 playback_control(NULL
);
1819 case MENU_ATTACHED_USB
:
1820 return PLUGIN_USB_CONNECTED
;
1827 static int spacerocks_game_loop(void)
1835 if ((ret
= spacerocks_menu()) != PLUGIN_OTHER
)
1843 end
= *rb
->current_tick
+ (CYCLETIME
* HZ
) / 1000;
1844 rb
->lcd_clear_display();
1850 rb
->splash (HZ
* 2, "Game Over");
1851 rb
->lcd_clear_display();
1852 position
= highscore_update(current_score
, current_level
, "",
1853 highscores
, NUM_SCORES
);
1857 rb
->splash(HZ
*2, "New High Score");
1858 highscore_show(position
, highscores
, NUM_SCORES
, true);
1860 return PLUGIN_OTHER
;
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();
1870 draw_and_move_ship();
1874 rb
->snprintf(str
, sizeof(str
), "score %d ", current_score
);
1875 rb
->lcd_putsxy(1, LCD_HEIGHT
-8, str
);
1876 draw_and_move_missiles();
1879 draw_and_move_ship();
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
);
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
;
1898 draw_and_move_trail_blaze();
1900 draw_and_move_asteroids();
1901 draw_and_move_enemy();
1905 #ifdef HAS_BUTTON_HOLD
1906 if (rb
->button_hold() && game_state
== PLAY_MODE
)
1907 game_state
= PAUSE_MODE
;
1909 button
= rb
->button_get(false);
1913 return PLUGIN_OTHER
;
1917 if (game_state
== PAUSE_MODE
)
1918 game_state
= PLAY_MODE
;
1919 else if (game_state
== PLAY_MODE
)
1920 game_state
= PAUSE_MODE
;
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
);
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
);
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;
1947 case (AST_HYPERSPACE
):
1948 if (game_state
== PLAY_MODE
)
1950 /* maybe shield if it gets too hard */
1954 case (AST_FIRE
| BUTTON_REPEAT
):
1955 if (game_state
== PLAY_MODE
)
1957 if (next_missile_count
<= 0)
1960 next_missile_count
= 10;
1963 else if(game_state
== PAUSE_MODE
)
1964 game_state
= PLAY_MODE
;
1968 if (rb
->default_event_handler(button
)==SYS_USB_CONNECTED
)
1969 return PLUGIN_USB_CONNECTED
;
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
);
1986 enum plugin_status
plugin_start(const void* parameter
)
1989 int ret
= PLUGIN_OTHER
;
1992 rb
->lcd_set_backdrop(NULL
);
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: */
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 */