diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/plugins/SOURCES | 2 | ||||
-rwxr-xr-x | apps/plugins/spacerocks.c | 1601 |
2 files changed, 1603 insertions, 0 deletions
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index 70edca4dc1..e0f1c5ba83 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES | |||
@@ -94,6 +94,8 @@ rockboy.c | |||
94 | xobox.c | 94 | xobox.c |
95 | #endif | 95 | #endif |
96 | 96 | ||
97 | spacerocks.c | ||
98 | |||
97 | #endif /* HAVE_LCD_BITMAP */ | 99 | #endif /* HAVE_LCD_BITMAP */ |
98 | 100 | ||
99 | #ifdef HAVE_LCD_CHARCELLS /* Player model only */ | 101 | #ifdef HAVE_LCD_CHARCELLS /* Player model only */ |
diff --git a/apps/plugins/spacerocks.c b/apps/plugins/spacerocks.c new file mode 100755 index 0000000000..67b5dd047e --- /dev/null +++ b/apps/plugins/spacerocks.c | |||
@@ -0,0 +1,1601 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Mat Holton | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include "plugin.h" | ||
21 | #include "math.h" | ||
22 | #include "stdio.h" | ||
23 | PLUGIN_HEADER | ||
24 | |||
25 | /******************************* Globals ***********************************/ | ||
26 | static struct plugin_api* rb; /* global api struct pointer */ | ||
27 | /* variable button definitions */ | ||
28 | #if CONFIG_KEYPAD == RECORDER_PAD | ||
29 | #define AST_PAUSE BUTTON_ON | ||
30 | #define AST_QUIT BUTTON_OFF | ||
31 | #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT | ||
32 | #define AST_THRUST BUTTON_UP | ||
33 | #define AST_HYPERSPACE BUTTON_DOWN | ||
34 | #define AST_LEFT BUTTON_LEFT | ||
35 | #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT | ||
36 | #define AST_RIGHT BUTTON_RIGHT | ||
37 | #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT) | ||
38 | #define AST_FIRE BUTTON_PLAY | ||
39 | #define AST_FIRE_REP BUTTON_PLAY | BUTTON_REPEAT | ||
40 | |||
41 | #elif CONFIG_KEYPAD == ONDIO_PAD | ||
42 | #define AST_PAUSE BUTTON_ON | ||
43 | #define AST_QUIT BUTTON_OFF | ||
44 | #define AST_THRUST BUTTON_UP | ||
45 | #define AST_HYPERSPACE BUTTON_DOWN | ||
46 | #define AST_LEFT BUTTON_LEFT | ||
47 | #define AST_RIGHT BUTTON_RIGHT | ||
48 | #define AST_FIRE BUTTON_MENU | ||
49 | |||
50 | #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ | ||
51 | (CONFIG_KEYPAD == IRIVER_H300_PAD) | ||
52 | #define AST_PAUSE BUTTON_REC | ||
53 | #define AST_QUIT BUTTON_OFF | ||
54 | #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT | ||
55 | #define AST_THRUST BUTTON_UP | ||
56 | #define AST_HYPERSPACE BUTTON_DOWN | ||
57 | #define AST_LEFT BUTTON_LEFT | ||
58 | #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT | ||
59 | #define AST_RIGHT BUTTON_RIGHT | ||
60 | #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT) | ||
61 | #define AST_FIRE BUTTON_SELECT | ||
62 | #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT | ||
63 | |||
64 | #elif (CONFIG_KEYPAD == IAUDIO_X5_PAD) | ||
65 | #define AST_PAUSE BUTTON_PLAY | ||
66 | #define AST_QUIT BUTTON_POWER | ||
67 | #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT | ||
68 | #define AST_THRUST BUTTON_UP | ||
69 | #define AST_HYPERSPACE BUTTON_DOWN | ||
70 | #define AST_LEFT BUTTON_LEFT | ||
71 | #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT | ||
72 | #define AST_RIGHT BUTTON_RIGHT | ||
73 | #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT) | ||
74 | #define AST_FIRE BUTTON_SELECT | ||
75 | #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT | ||
76 | |||
77 | #elif (CONFIG_KEYPAD == IPOD_4G_PAD) | ||
78 | #define AST_PAUSE (BUTTON_SELECT | BUTTON_PLAY) | ||
79 | #define AST_QUIT (BUTTON_SELECT | BUTTON_MENU) | ||
80 | #define AST_THRUST BUTTON_MENU | ||
81 | #define AST_THRUST_REP (BUTTON_MENU | BUTTON_REPEAT) | ||
82 | #define AST_HYPERSPACE BUTTON_PLAY | ||
83 | #define AST_LEFT BUTTON_SCROLL_BACK | ||
84 | #define AST_LEFT_REP (BUTTON_SCROLL_BACK | BUTTON_REPEAT) | ||
85 | #define AST_RIGHT BUTTON_SCROLL_FWD | ||
86 | #define AST_RIGHT_REP (BUTTON_SCROLL_FWD | BUTTON_REPEAT) | ||
87 | #define AST_FIRE BUTTON_SELECT | ||
88 | #define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT) | ||
89 | #endif | ||
90 | |||
91 | #define SHOW_COL 0 | ||
92 | #define HISCORE_FILE PLUGIN_DIR "/astrorocks.hs" | ||
93 | #define POINT_SIZE 2 | ||
94 | #define MAX_NUM_ASTEROIDS 25 | ||
95 | #define MAX_NUM_MISSILES 6 | ||
96 | #define ABS(x) ((x)>0?(x):-(x)) | ||
97 | |||
98 | #define SCALE 5000 | ||
99 | #define MISSILE_SCALE 5000 | ||
100 | #define WRAP_GAP 12 | ||
101 | #define EXPLOSION_LENGTH 35 | ||
102 | |||
103 | #if CONFIG_KEYPAD == RECORDER_PAD || CONFIG_KEYPAD == ONDIO_PAD | ||
104 | #define ENEMY_MISSILE_SURVIVAL_LENGTH 65 | ||
105 | #define MISSILE_SURVIVAL_LENGTH 40 | ||
106 | #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ | ||
107 | (CONFIG_KEYPAD == IRIVER_H300_PAD) || \ | ||
108 | (CONFIG_KEYPAD == IAUDIO_X5_PAD) || \ | ||
109 | (CONFIG_KEYPAD == IPOD_4G_PAD) | ||
110 | #define ENEMY_MISSILE_SURVIVAL_LENGTH 120 | ||
111 | #define MISSILE_SURVIVAL_LENGTH 80 | ||
112 | #endif | ||
113 | |||
114 | #define SHOW_GAME_OVER_TIME 100 | ||
115 | #define SHOW_LEVEL_TIME 50 | ||
116 | #define START_LIVES 3 | ||
117 | #define START_LEVEL 1 | ||
118 | #define NUM_ASTEROID_VERTICES 10 | ||
119 | #define NUM_SHIP_VERTICES 4 | ||
120 | #define NUM_ENEMY_VERTICES 6 | ||
121 | #define MAX_LEVEL MAX_NUM_ASTEROIDS | ||
122 | #define ENEMY_SPEED 4 | ||
123 | #define ENEMY_START_X 0 | ||
124 | #define ENEMY_START_Y 0 | ||
125 | #define SIZE_ENEMY_COLLISION 5*SCALE | ||
126 | #define ATTRACT_FLIP_TIME 100 | ||
127 | #define NUM_STARS 50 | ||
128 | #define NUM_ROTATIONS 16 | ||
129 | |||
130 | #define SIN_COS_SCALE 10000 | ||
131 | #define SHIP_ROT_CW_SIN 3827 | ||
132 | #define SHIP_ROT_CW_COS 9239 | ||
133 | #define SHIP_ROT_ACW_SIN -3827 | ||
134 | #define SHIP_ROT_ACW_COS 9239 | ||
135 | |||
136 | #define FAST_ROT_CW_SIN 873 | ||
137 | #define FAST_ROT_CW_COS 9963 | ||
138 | #define FAST_ROT_ACW_SIN -873 | ||
139 | #define FAST_ROT_ACW_COS 9963 | ||
140 | |||
141 | #define MEDIUM_ROT_CW_SIN 350 | ||
142 | #define MEDIUM_ROT_CW_COS 9994 | ||
143 | #define MEDIUM_ROT_ACW_SIN -350 | ||
144 | #define MEDIUM_ROT_ACW_COS 9994 | ||
145 | |||
146 | #define SLOW_ROT_CW_SIN 350 | ||
147 | #define SLOW_ROT_CW_COS 9994 | ||
148 | #define SLOW_ROT_ACW_SIN - 350 | ||
149 | #define SLOW_ROT_ACW_COS 9994 | ||
150 | |||
151 | #define SCALED_WIDTH (LCD_WIDTH*SCALE) | ||
152 | #define SCALED_HEIGHT (LCD_HEIGHT*SCALE) | ||
153 | #define CENTER_LCD_X (LCD_WIDTH/2) | ||
154 | #define CENTER_LCD_Y (LCD_HEIGHT/2) | ||
155 | |||
156 | enum asteroid_type | ||
157 | { | ||
158 | SMALL = 1, | ||
159 | MEDIUM = 2, | ||
160 | LARGE = 3, | ||
161 | }; | ||
162 | |||
163 | enum game_state | ||
164 | { | ||
165 | GAME_OVER, | ||
166 | ATTRACT_MODE, | ||
167 | SHOW_LEVEL, | ||
168 | PLAY_MODE, | ||
169 | PAUSE_MODE | ||
170 | }; | ||
171 | |||
172 | struct Point | ||
173 | { | ||
174 | int x; | ||
175 | int y; | ||
176 | int dx; | ||
177 | int dy; | ||
178 | }; | ||
179 | |||
180 | /* Asteroid structure, contains an array of points */ | ||
181 | struct Asteroid | ||
182 | { | ||
183 | enum asteroid_type type; | ||
184 | bool exists; | ||
185 | struct Point position; | ||
186 | struct Point vertices[NUM_ASTEROID_VERTICES]; | ||
187 | int radius; | ||
188 | long speed_cos; | ||
189 | long speed_sin; | ||
190 | int explode_countdown; | ||
191 | }; | ||
192 | |||
193 | struct Ship | ||
194 | { | ||
195 | struct Point vertices[NUM_SHIP_VERTICES]; | ||
196 | struct Point position; | ||
197 | bool waiting_for_space; | ||
198 | int explode_countdown; | ||
199 | }; | ||
200 | |||
201 | struct Enemy | ||
202 | { | ||
203 | struct Point vertices[NUM_ENEMY_VERTICES]; | ||
204 | struct Point position; | ||
205 | int explode_countdown; | ||
206 | }; | ||
207 | |||
208 | struct Missile | ||
209 | { | ||
210 | struct Point position; | ||
211 | struct Point oldpoint; | ||
212 | int survived; | ||
213 | }; | ||
214 | |||
215 | static enum game_state game_state; | ||
216 | static int asteroid_count; | ||
217 | static int next_missile_count; | ||
218 | static int next_thrust_count; | ||
219 | static int num_lives; | ||
220 | static int show_level_timeout; | ||
221 | static int attract_flip_timeout; | ||
222 | static int show_game_over; | ||
223 | static int current_level; | ||
224 | static int current_score; | ||
225 | static int high_score; | ||
226 | static int space_check_size = 20*SCALE; | ||
227 | |||
228 | static bool enemy_on_screen; | ||
229 | static char phscore[30]; | ||
230 | static struct Ship ship; | ||
231 | static struct Point stars[NUM_STARS]; | ||
232 | static struct Asteroid asteroids_array[MAX_NUM_ASTEROIDS]; | ||
233 | static struct Missile missiles_array[MAX_NUM_MISSILES]; | ||
234 | static struct Missile enemy_missile; | ||
235 | static struct Enemy enemy; | ||
236 | static struct Point lives_points[NUM_SHIP_VERTICES]; | ||
237 | |||
238 | void draw_and_move_asteroids(void); | ||
239 | void initialise_game(int nStartNum); | ||
240 | |||
241 | bool is_asteroid_near_ship(struct Asteroid* asteroid); | ||
242 | bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point); | ||
243 | |||
244 | void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type eType); | ||
245 | void draw_polygon(struct Point* vertices, int px, int py, int num_vertices); | ||
246 | void rotate_asteroid(struct Asteroid* asteroid); | ||
247 | void create_asteroid(enum asteroid_type type, int x, int y); | ||
248 | void create_stars(void); | ||
249 | |||
250 | void initialise_ship(void); | ||
251 | void draw_and_move_ship(void); | ||
252 | void rotate_ship(int s, int c); | ||
253 | void thrust_ship(void); | ||
254 | |||
255 | void initialise_missile(struct Missile* missile); | ||
256 | void draw_and_move_missiles(void); | ||
257 | void fire_missile(void); | ||
258 | |||
259 | void animate_and_draw_explosion(struct Point* point, int num_points, int xoffset, int yoffset); | ||
260 | void initialise_explosion(struct Point* point, int num_points); | ||
261 | |||
262 | void move_point(struct Point* point); | ||
263 | void hyperspace(void); | ||
264 | void check_collisions(void); | ||
265 | void initialise_enemy(void); | ||
266 | void draw_and_move_enemy(void); | ||
267 | void draw_lives(void); | ||
268 | void drawstars(void); | ||
269 | bool is_ship_within_asteroid(struct Asteroid* asteroid); | ||
270 | |||
271 | /* The array of points that make up an asteroid */ | ||
272 | static const short asteroid_one[NUM_ASTEROID_VERTICES*2] = | ||
273 | { | ||
274 | -1, -6, | ||
275 | 2, -4, | ||
276 | 4, -7, | ||
277 | 8, -4, | ||
278 | 7, 0, | ||
279 | 10, 1, | ||
280 | 6, 7, | ||
281 | -2, 7, | ||
282 | -5, 3, | ||
283 | -5, -4 | ||
284 | }; | ||
285 | |||
286 | /* The array of points that make up an asteroid */ | ||
287 | static const short asteroid_two[NUM_ASTEROID_VERTICES*2] = | ||
288 | { | ||
289 | -1, -6, | ||
290 | 2, -8, | ||
291 | 3, -7, | ||
292 | 8, -4, | ||
293 | 7, 0, | ||
294 | 10, 1, | ||
295 | 6, 7, | ||
296 | -2, 7, | ||
297 | -5, 3, | ||
298 | -5, -4 | ||
299 | }; | ||
300 | |||
301 | /* The array of points that make up an asteroid */ | ||
302 | static const short asteroid_three[NUM_ASTEROID_VERTICES*2] = | ||
303 | { | ||
304 | -1, -6, | ||
305 | 2, -8, | ||
306 | 3, -7, | ||
307 | 1, -4, | ||
308 | 7, 0, | ||
309 | 10, 1, | ||
310 | 6, 7, | ||
311 | -2, 7, | ||
312 | -8, 3, | ||
313 | -5, -4 | ||
314 | }; | ||
315 | |||
316 | /* The array od points the make up the ship */ | ||
317 | static const short ship_vertices[NUM_SHIP_VERTICES*2] = | ||
318 | { | ||
319 | 0,-4, | ||
320 | 3, 4, | ||
321 | 0, 1, | ||
322 | -3, 4 | ||
323 | }; | ||
324 | |||
325 | /* The array of points the make up the bad spaceship */ | ||
326 | static const short enemy_vertices[NUM_ENEMY_VERTICES*2] = | ||
327 | { | ||
328 | -5, 0, | ||
329 | -2, 2, | ||
330 | 2, 2, | ||
331 | 5, 0, | ||
332 | 2, -2, | ||
333 | -2, -2 | ||
334 | }; | ||
335 | |||
336 | /*Hi-Score reading and writing to file - this needs moving to the hi-score plugin lib as | ||
337 | a 3rd function */ | ||
338 | void iohiscore(void) | ||
339 | { | ||
340 | int fd; | ||
341 | int compare; | ||
342 | |||
343 | /* clear the buffer we're about to load the highscore data into */ | ||
344 | rb->memset(phscore, 0, sizeof(phscore)); | ||
345 | |||
346 | fd = rb->open(HISCORE_FILE,O_RDWR | O_CREAT); | ||
347 | |||
348 | /* highscore used to %d, is now %d\n | ||
349 | Deal with no file or bad file */ | ||
350 | rb->read(fd,phscore, sizeof(phscore)); | ||
351 | |||
352 | compare = rb->atoi(phscore); | ||
353 | |||
354 | if(high_score > compare){ | ||
355 | rb->lseek(fd,0,SEEK_SET); | ||
356 | rb->fdprintf(fd, "%d\n", high_score); | ||
357 | } | ||
358 | else | ||
359 | high_score = compare; | ||
360 | |||
361 | rb->close(fd); | ||
362 | } | ||
363 | |||
364 | bool point_in_poly(struct Point* _point, int num_vertices, int x, int y) | ||
365 | { | ||
366 | struct Point* pi; | ||
367 | struct Point* pj; | ||
368 | int n; | ||
369 | bool c = false; | ||
370 | |||
371 | pi = _point; | ||
372 | pj = _point; | ||
373 | pj += num_vertices-1; | ||
374 | |||
375 | n = num_vertices; | ||
376 | while(n--) | ||
377 | { | ||
378 | if((((pi->y <= y) && (y < pj->y)) || ((pj->y <= y) && (y < pi->y))) && | ||
379 | (x < (pj->x - pi->x) * (y - pi->y) / (pj->y - pi->y) + pi->x)) | ||
380 | c = !c; | ||
381 | |||
382 | if(n == num_vertices - 1) | ||
383 | pj = _point; | ||
384 | else | ||
385 | pj++; | ||
386 | |||
387 | pi++; | ||
388 | } | ||
389 | |||
390 | return c; | ||
391 | } | ||
392 | |||
393 | void move_point(struct Point* point) | ||
394 | { | ||
395 | point->x += point->dx; | ||
396 | point->y += point->dy; | ||
397 | |||
398 | /*check bounds on the x-axis:*/ | ||
399 | if(point->x >= SCALED_WIDTH) | ||
400 | point->x = 0; | ||
401 | else if(point->x <= 0) | ||
402 | point->x = SCALED_WIDTH; | ||
403 | |||
404 | /*Check bounds on the y-axis:*/ | ||
405 | if(point->y >= SCALED_HEIGHT) | ||
406 | point->y = 0; | ||
407 | else if(point->y <= 0) | ||
408 | point->y = SCALED_HEIGHT; | ||
409 | } | ||
410 | |||
411 | /*Check if point is within a rectangle*/ | ||
412 | bool is_point_within_rectangle(struct Point* rect, struct Point* p, int size) | ||
413 | { | ||
414 | #if SHOW_COL | ||
415 | int aTLx = rect->x - size; | ||
416 | int aTLy = rect->y - size; | ||
417 | int aBRx = rect->x + size; | ||
418 | int aBRy = rect->y + size; | ||
419 | rb->lcd_drawline( aTLx/SCALE, aTLy/SCALE, aBRx/SCALE, aTLy/SCALE); | ||
420 | rb->lcd_drawline( aTLx/SCALE, aTLy/SCALE, aTLx/SCALE, aBRy/SCALE); | ||
421 | rb->lcd_drawline( aTLx/SCALE, aBRy/SCALE, aBRx/SCALE, aBRy/SCALE); | ||
422 | rb->lcd_drawline( aBRx/SCALE, aBRy/SCALE, aBRx/SCALE, aTLy/SCALE); | ||
423 | return (p->x > aTLx && p->x < aBRx && p->y > aTLy && p->y < aBRy); | ||
424 | #else | ||
425 | return (p->x > rect->x - size && p->x < rect->x + size && | ||
426 | p->y > rect->y - size && p->y < rect->y + size); | ||
427 | #endif | ||
428 | } | ||
429 | |||
430 | /* Draw polygon */ | ||
431 | void draw_polygon(struct Point* vertices, int px, int py, int num_vertices) | ||
432 | { | ||
433 | int n, t1, t2, oldX, oldY; | ||
434 | struct Point *p; | ||
435 | bool bDrawAll = px < WRAP_GAP || LCD_WIDTH - px < WRAP_GAP || | ||
436 | py < WRAP_GAP || LCD_HEIGHT - py < WRAP_GAP; | ||
437 | |||
438 | p = vertices; | ||
439 | p += num_vertices-1; | ||
440 | oldX = p->x/SCALE + px; | ||
441 | oldY = p->y/SCALE + py; | ||
442 | p = vertices; | ||
443 | for(n = num_vertices+1; --n;) | ||
444 | { | ||
445 | t1 = p->x/SCALE + px; | ||
446 | t2 = p->y/SCALE + py; | ||
447 | |||
448 | rb->lcd_drawline(oldX, oldY, t1, t2); | ||
449 | |||
450 | if(bDrawAll) | ||
451 | { | ||
452 | rb->lcd_drawline(oldX - LCD_WIDTH, oldY, t1 - LCD_WIDTH, t2); | ||
453 | rb->lcd_drawline(oldX + LCD_WIDTH, oldY, t1 + LCD_WIDTH, t2); | ||
454 | rb->lcd_drawline(oldX - LCD_WIDTH, oldY + LCD_HEIGHT, | ||
455 | t1 - LCD_WIDTH, t2 + LCD_HEIGHT); | ||
456 | rb->lcd_drawline(oldX + LCD_WIDTH, oldY + LCD_HEIGHT, | ||
457 | t1 + LCD_WIDTH, t2 + LCD_HEIGHT); | ||
458 | |||
459 | rb->lcd_drawline(oldX, oldY - LCD_HEIGHT, t1, t2 - LCD_HEIGHT); | ||
460 | rb->lcd_drawline(oldX, oldY + LCD_HEIGHT, t1, t2 + LCD_HEIGHT); | ||
461 | rb->lcd_drawline(oldX - LCD_WIDTH, oldY - LCD_HEIGHT, | ||
462 | t1 - LCD_WIDTH, t2 - LCD_HEIGHT); | ||
463 | rb->lcd_drawline(oldX + LCD_WIDTH, oldY - LCD_HEIGHT, | ||
464 | t1 + LCD_WIDTH, t2 - LCD_HEIGHT); | ||
465 | } | ||
466 | oldX = t1; | ||
467 | oldY = t2; | ||
468 | p++; | ||
469 | } | ||
470 | } | ||
471 | |||
472 | void animate_and_draw_explosion(struct Point* point, int num_points, | ||
473 | int xoffset, int yoffset) | ||
474 | { | ||
475 | int n; | ||
476 | for(n = num_points; --n;) | ||
477 | { | ||
478 | if(game_state != PAUSE_MODE) | ||
479 | { | ||
480 | point->x += point->dx; | ||
481 | point->y += point->dy; | ||
482 | } | ||
483 | rb->lcd_fillrect( point->x/SCALE + xoffset, point->y/SCALE + yoffset, | ||
484 | POINT_SIZE, POINT_SIZE); | ||
485 | point++; | ||
486 | } | ||
487 | } | ||
488 | |||
489 | /*stop movement of ship, 'cos that's what happens when you go into hyperspace.*/ | ||
490 | void hyperspace(void) | ||
491 | { | ||
492 | ship.position.dx = ship.position.dy = 0; | ||
493 | ship.position.x = (rb->rand()%SCALED_WIDTH); | ||
494 | ship.position.y = (rb->rand()%SCALED_HEIGHT); | ||
495 | } | ||
496 | |||
497 | void initialise_enemy(void) | ||
498 | { | ||
499 | struct Point* point; | ||
500 | int n; | ||
501 | |||
502 | enemy_missile.survived = 0; | ||
503 | enemy_on_screen = true; | ||
504 | enemy.explode_countdown = 0; | ||
505 | |||
506 | point = enemy.vertices; | ||
507 | for(n = 0; n < NUM_ENEMY_VERTICES+NUM_ENEMY_VERTICES; n+=2) | ||
508 | { | ||
509 | point->x = enemy_vertices[n]; | ||
510 | point->y = enemy_vertices[n+1]; | ||
511 | point->x *= SCALE; | ||
512 | point->y *= SCALE; | ||
513 | point++; | ||
514 | } | ||
515 | |||
516 | if(ship.position.x >= SCALED_WIDTH/2) | ||
517 | { | ||
518 | enemy.position.dx = ENEMY_SPEED; | ||
519 | enemy.position.x = 0; | ||
520 | } | ||
521 | else | ||
522 | { | ||
523 | enemy.position.dx = -ENEMY_SPEED; | ||
524 | enemy.position.x = SCALED_WIDTH; | ||
525 | } | ||
526 | |||
527 | if(ship.position.y >= SCALED_HEIGHT/2) | ||
528 | { | ||
529 | enemy.position.dy = ENEMY_SPEED; | ||
530 | enemy.position.y = 0; | ||
531 | } | ||
532 | else | ||
533 | { | ||
534 | enemy.position.dy = -ENEMY_SPEED; | ||
535 | enemy.position.y = SCALED_HEIGHT; | ||
536 | } | ||
537 | |||
538 | enemy.position.dx *= SCALE/10; | ||
539 | enemy.position.dy *= SCALE/10; | ||
540 | } | ||
541 | |||
542 | void draw_and_move_enemy(void) | ||
543 | { | ||
544 | int enemy_x, enemy_y; | ||
545 | struct Point *point; | ||
546 | |||
547 | if(enemy_on_screen) | ||
548 | { | ||
549 | enemy_x = enemy.position.x/SCALE; | ||
550 | enemy_y = enemy.position.y/SCALE; | ||
551 | if(!enemy.explode_countdown) | ||
552 | { | ||
553 | point = enemy.vertices; | ||
554 | draw_polygon(enemy.vertices, enemy_x, enemy_y, NUM_ENEMY_VERTICES); | ||
555 | rb->lcd_drawline(enemy.vertices[0].x/SCALE + enemy_x, | ||
556 | enemy.vertices[0].y/SCALE + enemy_y, | ||
557 | enemy.vertices[3].x/SCALE + enemy_x, | ||
558 | enemy.vertices[3].y/SCALE + enemy_y); | ||
559 | |||
560 | if(game_state != PAUSE_MODE) | ||
561 | { | ||
562 | enemy.position.x += enemy.position.dx; | ||
563 | enemy.position.y += enemy.position.dy; | ||
564 | } | ||
565 | |||
566 | if(enemy.position.x > SCALED_WIDTH || enemy.position.x < 0) | ||
567 | enemy_on_screen = false; | ||
568 | |||
569 | if(enemy.position.y > SCALED_HEIGHT) | ||
570 | enemy.position.y = 0; | ||
571 | else if(enemy.position.y < 0) | ||
572 | enemy.position.y = SCALED_HEIGHT; | ||
573 | |||
574 | if( (rb->rand()%1000) < 10) | ||
575 | enemy.position.dy = -enemy.position.dy; | ||
576 | } | ||
577 | else | ||
578 | { | ||
579 | |||
580 | animate_and_draw_explosion(enemy.vertices, NUM_ENEMY_VERTICES, | ||
581 | enemy_x, enemy.position.y/SCALE); | ||
582 | if(game_state != PAUSE_MODE) | ||
583 | { | ||
584 | enemy.explode_countdown--; | ||
585 | if(!enemy.explode_countdown) | ||
586 | enemy_on_screen = false; | ||
587 | } | ||
588 | } | ||
589 | } | ||
590 | else | ||
591 | { | ||
592 | if( (rb->rand()%1000) < 2 ) | ||
593 | initialise_enemy(); | ||
594 | } | ||
595 | |||
596 | if(!enemy_missile.survived && game_state != GAME_OVER) | ||
597 | { | ||
598 | /*if no missile and the enemy is here and not exploding..then shoot baby!*/ | ||
599 | if( !enemy.explode_countdown && enemy_on_screen && | ||
600 | !ship.waiting_for_space && (rb->rand()%10) > 5 ) | ||
601 | { | ||
602 | enemy_missile.position.x = enemy.position.x; | ||
603 | enemy_missile.position.y = enemy.position.y; | ||
604 | |||
605 | /*lame, needs to be sorted - it's trying to shoot at the ship*/ | ||
606 | if(ABS(enemy.position.y - ship.position.y) <= 5*SCALE) | ||
607 | { | ||
608 | enemy_missile.position.dy = 0; | ||
609 | } | ||
610 | else | ||
611 | { | ||
612 | if( enemy.position.y < ship.position.y) | ||
613 | enemy_missile.position.dy = 1; | ||
614 | else | ||
615 | enemy_missile.position.dy = -1; | ||
616 | } | ||
617 | |||
618 | if(ABS(enemy.position.x - ship.position.x) <= 5*SCALE) | ||
619 | enemy_missile.position.dx = 0; | ||
620 | else | ||
621 | { | ||
622 | if( enemy.position.x < ship.position.x) | ||
623 | enemy_missile.position.dx = 1; | ||
624 | else | ||
625 | enemy_missile.position.dx = -1; | ||
626 | } | ||
627 | |||
628 | if(enemy_missile.position.dx == 0 && | ||
629 | enemy_missile.position.dy == 0) | ||
630 | enemy_missile.position.dx = enemy_missile.position.dy = -1; | ||
631 | |||
632 | enemy_missile.position.dx *= SCALE; | ||
633 | enemy_missile.position.dy *= SCALE; | ||
634 | enemy_missile.survived = ENEMY_MISSILE_SURVIVAL_LENGTH; | ||
635 | |||
636 | } | ||
637 | } | ||
638 | else | ||
639 | { | ||
640 | rb->lcd_fillrect( enemy_missile.position.x/SCALE, | ||
641 | enemy_missile.position.y/SCALE, | ||
642 | POINT_SIZE, POINT_SIZE); | ||
643 | if(game_state != PAUSE_MODE) | ||
644 | { | ||
645 | move_point(&enemy_missile.position); | ||
646 | enemy_missile.survived--; | ||
647 | } | ||
648 | } | ||
649 | } | ||
650 | |||
651 | /****************** | ||
652 | * Lame method of collision | ||
653 | * detection. It's checking for collision | ||
654 | * between point and a big rectangle around the asteroid... | ||
655 | *******************/ | ||
656 | bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point) | ||
657 | { | ||
658 | if( !is_point_within_rectangle(&asteroid->position, point, | ||
659 | asteroid->radius+4*SCALE) ) | ||
660 | return false; | ||
661 | |||
662 | if(point_in_poly(asteroid->vertices, NUM_ASTEROID_VERTICES, | ||
663 | point->x - asteroid->position.x, | ||
664 | point->y - asteroid->position.y)) | ||
665 | { | ||
666 | switch(asteroid->type) | ||
667 | { | ||
668 | case(SMALL): | ||
669 | asteroid->explode_countdown = EXPLOSION_LENGTH; | ||
670 | initialise_explosion(asteroid->vertices, NUM_ASTEROID_VERTICES); | ||
671 | break; | ||
672 | |||
673 | case(LARGE): | ||
674 | create_asteroid(MEDIUM, asteroid->position.x, | ||
675 | asteroid->position.y); | ||
676 | create_asteroid(MEDIUM, asteroid->position.x, | ||
677 | asteroid->position.y); | ||
678 | break; | ||
679 | |||
680 | case(MEDIUM): | ||
681 | create_asteroid(SMALL, asteroid->position.x, asteroid->position.y); | ||
682 | create_asteroid(SMALL, asteroid->position.x, asteroid->position.y); | ||
683 | break; | ||
684 | } | ||
685 | |||
686 | current_score++; | ||
687 | asteroid_count--; | ||
688 | asteroid->exists = false; | ||
689 | return true; | ||
690 | } | ||
691 | else | ||
692 | return false; | ||
693 | } | ||
694 | |||
695 | bool is_point_within_enemy(struct Point* point) | ||
696 | { | ||
697 | if( is_point_within_rectangle(&enemy.position, point, 5*SCALE) ) | ||
698 | { | ||
699 | current_score += 5; | ||
700 | /*enemy_missile.survived = 0;*/ | ||
701 | enemy.explode_countdown = EXPLOSION_LENGTH; | ||
702 | initialise_explosion(enemy.vertices, NUM_ENEMY_VERTICES); | ||
703 | return true; | ||
704 | } | ||
705 | else | ||
706 | return false; | ||
707 | } | ||
708 | |||
709 | bool is_ship_within_asteroid(struct Asteroid* asteroid) | ||
710 | { | ||
711 | bool hit = false; | ||
712 | struct Point p; | ||
713 | |||
714 | p.x = ship.position.x + ship.vertices[0].x; | ||
715 | p.y = ship.position.y + ship.vertices[0].y; | ||
716 | hit |= is_point_within_asteroid(asteroid, &p); | ||
717 | |||
718 | if(!hit) | ||
719 | { | ||
720 | p.x = ship.position.x + ship.vertices[1].x; | ||
721 | p.y = ship.position.y + ship.vertices[1].y; | ||
722 | hit |= is_point_within_asteroid(asteroid, &p); | ||
723 | if(!hit) | ||
724 | { | ||
725 | p.x = ship.position.x + ship.vertices[3].x; | ||
726 | p.y = ship.position.y + ship.vertices[3].y; | ||
727 | hit |= is_point_within_asteroid(asteroid, &p); | ||
728 | } | ||
729 | } | ||
730 | |||
731 | return hit; | ||
732 | } | ||
733 | |||
734 | void initialise_explosion(struct Point* point, int num_points) | ||
735 | { | ||
736 | int n; | ||
737 | |||
738 | point->x += point->dx; | ||
739 | point->y += point->dy; | ||
740 | for(n = num_points; --n;) | ||
741 | { | ||
742 | point->dx = point->x; | ||
743 | point->dy = point->y; | ||
744 | point++; | ||
745 | } | ||
746 | } | ||
747 | |||
748 | /* Check for collsions between the missiles and the asteroids and the ship */ | ||
749 | void check_collisions(void) | ||
750 | { | ||
751 | int m, n; | ||
752 | bool asteroids_onscreen = false; | ||
753 | struct Missile* missile; | ||
754 | struct Asteroid* asteroid; | ||
755 | bool ship_cant_be_placed = false; | ||
756 | |||
757 | asteroid = asteroids_array; | ||
758 | m = MAX_NUM_ASTEROIDS; | ||
759 | while(--m) | ||
760 | { | ||
761 | /*if the asteroids exists then test missile collision:*/ | ||
762 | if(asteroid->exists) | ||
763 | { | ||
764 | missile = missiles_array; | ||
765 | n = MAX_NUM_MISSILES; | ||
766 | while(--n) | ||
767 | { | ||
768 | /*if the missiles exists:*/ | ||
769 | if(missile->survived > 0) | ||
770 | { | ||
771 | /*has the missile hit the asteroid?*/ | ||
772 | if(is_point_within_asteroid(asteroid, &missile->position) | ||
773 | || is_point_within_asteroid(asteroid, | ||
774 | &missile->oldpoint)) | ||
775 | { | ||
776 | missile->survived = 0; | ||
777 | break; | ||
778 | } | ||
779 | } | ||
780 | missile++; | ||
781 | } | ||
782 | } | ||
783 | |||
784 | /*If it exists now, check ship collision:*/ | ||
785 | if(asteroid->exists) | ||
786 | { | ||
787 | /*now check collision with ship:*/ | ||
788 | if(!ship.waiting_for_space && !ship.explode_countdown) | ||
789 | { | ||
790 | if(is_ship_within_asteroid(asteroid)) | ||
791 | { | ||
792 | /*blow up ship*/ | ||
793 | ship.explode_countdown = EXPLOSION_LENGTH; | ||
794 | initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); | ||
795 | } | ||
796 | } | ||
797 | } | ||
798 | |||
799 | /*has the enemy missile blown something up?*/ | ||
800 | if(asteroid->exists && enemy_missile.survived) | ||
801 | { | ||
802 | if(is_point_within_asteroid(asteroid, &enemy_missile.position)) | ||
803 | { | ||
804 | /*take that score back then:*/ | ||
805 | if(current_score > 0) current_score--; | ||
806 | enemy_missile.survived = 0; | ||
807 | } | ||
808 | } | ||
809 | |||
810 | /*if it still exists, check if ship is waiting for space:*/ | ||
811 | if(asteroid->exists && ship.waiting_for_space) | ||
812 | ship_cant_be_placed |= | ||
813 | is_point_within_rectangle(&ship.position, | ||
814 | &asteroid->position, | ||
815 | space_check_size); | ||
816 | |||
817 | /*is an asteroid still exploding?*/ | ||
818 | if(asteroid->explode_countdown) | ||
819 | asteroids_onscreen = true; | ||
820 | |||
821 | asteroid++; | ||
822 | } | ||
823 | |||
824 | /*now check collision between ship and enemy*/ | ||
825 | if(enemy_on_screen && !ship.waiting_for_space && | ||
826 | !ship.explode_countdown && !enemy.explode_countdown) | ||
827 | { | ||
828 | /*has the enemy collided with the ship?*/ | ||
829 | if(is_point_within_enemy(&ship.position)) | ||
830 | { | ||
831 | ship.explode_countdown = EXPLOSION_LENGTH; | ||
832 | initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); | ||
833 | } | ||
834 | |||
835 | /*Now see if the enemy has been shot at by the ships missiles:*/ | ||
836 | missile = missiles_array; | ||
837 | n = MAX_NUM_MISSILES; | ||
838 | while(--n) | ||
839 | { | ||
840 | if(missile->survived > 0 && | ||
841 | is_point_within_enemy(&missile->position)) | ||
842 | { | ||
843 | missile->survived = 0; | ||
844 | break; | ||
845 | } | ||
846 | } | ||
847 | } | ||
848 | |||
849 | /*test collision with enemy missile and ship:*/ | ||
850 | if(!ship_cant_be_placed && enemy_missile.survived > 0 && | ||
851 | point_in_poly(ship.vertices, NUM_SHIP_VERTICES, | ||
852 | enemy_missile.position.x - ship.position.x, | ||
853 | enemy_missile.position.y - ship.position.y)) | ||
854 | { | ||
855 | ship.explode_countdown = EXPLOSION_LENGTH; | ||
856 | initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); | ||
857 | enemy_missile.survived = 0; | ||
858 | enemy_missile.position.x = enemy_missile.position.y = 0; | ||
859 | } | ||
860 | |||
861 | if(!ship_cant_be_placed) | ||
862 | ship.waiting_for_space = false; | ||
863 | |||
864 | /*if all asteroids cleared then start again:*/ | ||
865 | if(asteroid_count == 0 && !enemy_on_screen && !asteroids_onscreen) | ||
866 | { | ||
867 | current_level++; | ||
868 | game_state = SHOW_LEVEL; | ||
869 | show_level_timeout = SHOW_LEVEL_TIME; | ||
870 | } | ||
871 | } | ||
872 | |||
873 | /************************************************* | ||
874 | ** Creates a new asteroid of the given 4type (size) | ||
875 | ** and at the given location. | ||
876 | *************************************************/ | ||
877 | void create_asteroid(enum asteroid_type type, int x, int y) | ||
878 | { | ||
879 | struct Asteroid* asteroid; | ||
880 | int n; | ||
881 | |||
882 | asteroid = asteroids_array; | ||
883 | n = MAX_NUM_ASTEROIDS; | ||
884 | while(--n) | ||
885 | { | ||
886 | if(!asteroid->exists && !asteroid->explode_countdown) | ||
887 | { | ||
888 | initialise_asteroid(asteroid, type); | ||
889 | asteroid->position.x = x; | ||
890 | asteroid->position.y = y; | ||
891 | break; | ||
892 | } | ||
893 | asteroid++; | ||
894 | } | ||
895 | } | ||
896 | |||
897 | /* Initialise a missile */ | ||
898 | void initialise_missile(struct Missile* missile) | ||
899 | { | ||
900 | missile->position.x = ship.position.x; | ||
901 | missile->position.y = ship.position.y; | ||
902 | missile->position.dx = (ship.vertices[0].x - ship.vertices[2].x)/2; | ||
903 | missile->position.dy = (ship.vertices[0].y - ship.vertices[2].y)/2; | ||
904 | missile->survived = MISSILE_SURVIVAL_LENGTH; | ||
905 | missile->oldpoint.x = missile->position.x; | ||
906 | missile->oldpoint.y = missile->position.y; | ||
907 | } | ||
908 | |||
909 | /* Draw and Move all the missiles */ | ||
910 | void draw_and_move_missiles(void) | ||
911 | { | ||
912 | int n; | ||
913 | int p1x, p1y; | ||
914 | int p2x, p2y; | ||
915 | |||
916 | struct Missile* missile; | ||
917 | missile = missiles_array; | ||
918 | n = MAX_NUM_MISSILES; | ||
919 | while(--n) | ||
920 | { | ||
921 | if(missile->survived) | ||
922 | { | ||
923 | if(missile->position.dx > 0) | ||
924 | { | ||
925 | if(missile->position.x >= missile->oldpoint.x) | ||
926 | { | ||
927 | p1x = missile->oldpoint.x; | ||
928 | p2x = missile->position.x; | ||
929 | } | ||
930 | else | ||
931 | { | ||
932 | p1x = 0; | ||
933 | p2x = missile->position.x; | ||
934 | } | ||
935 | } | ||
936 | else | ||
937 | { | ||
938 | if(missile->oldpoint.x >= missile->position.x) | ||
939 | { | ||
940 | p1x = missile->oldpoint.x; | ||
941 | p2x = missile->position.x; | ||
942 | } | ||
943 | else | ||
944 | { | ||
945 | p1x = missile->oldpoint.x; | ||
946 | p2x = LCD_WIDTH; | ||
947 | } | ||
948 | } | ||
949 | |||
950 | if(missile->position.dy > 0) | ||
951 | { | ||
952 | if(missile->position.y >= missile->oldpoint.y) | ||
953 | { | ||
954 | p1y = missile->oldpoint.y; | ||
955 | p2y = missile->position.y; | ||
956 | } | ||
957 | else | ||
958 | { | ||
959 | p1y = 0; | ||
960 | p2y = missile->position.y; | ||
961 | } | ||
962 | } | ||
963 | else | ||
964 | { | ||
965 | if(missile->oldpoint.y >= missile->position.y) | ||
966 | { | ||
967 | p1y = missile->oldpoint.y; | ||
968 | p2y = missile->position.y; | ||
969 | } | ||
970 | else | ||
971 | { | ||
972 | p1y = missile->oldpoint.y; | ||
973 | p2y = LCD_HEIGHT; | ||
974 | } | ||
975 | } | ||
976 | |||
977 | rb->lcd_drawline( p1x/SCALE, p1y/SCALE, p2x/SCALE, p2y/SCALE); | ||
978 | |||
979 | if(game_state != PAUSE_MODE) | ||
980 | { | ||
981 | missile->oldpoint.x = missile->position.x; | ||
982 | missile->oldpoint.y = missile->position.y; | ||
983 | move_point(&missile->position); | ||
984 | missile->survived--; | ||
985 | } | ||
986 | } | ||
987 | missile++; | ||
988 | } | ||
989 | } | ||
990 | |||
991 | void draw_lives(void) | ||
992 | { | ||
993 | int n; | ||
994 | int px = (LCD_WIDTH - num_lives*4 - 1); | ||
995 | int py = (LCD_HEIGHT-4); | ||
996 | |||
997 | n = num_lives; | ||
998 | while(--n) | ||
999 | { | ||
1000 | draw_polygon(lives_points, px, py, NUM_SHIP_VERTICES); | ||
1001 | px += 6; | ||
1002 | } | ||
1003 | } | ||
1004 | |||
1005 | /*Fire the next missile*/ | ||
1006 | void fire_missile(void) | ||
1007 | { | ||
1008 | int n; | ||
1009 | struct Missile* missile; | ||
1010 | |||
1011 | if(!ship.explode_countdown && !ship.waiting_for_space) | ||
1012 | { | ||
1013 | missile = missiles_array; | ||
1014 | n = MAX_NUM_MISSILES; | ||
1015 | while(--n) | ||
1016 | { | ||
1017 | if(!missile->survived) | ||
1018 | { | ||
1019 | initialise_missile(missile); | ||
1020 | break; | ||
1021 | } | ||
1022 | missile++; | ||
1023 | } | ||
1024 | } | ||
1025 | } | ||
1026 | |||
1027 | /* Initialise the passed Asteroid */ | ||
1028 | void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type type) | ||
1029 | { | ||
1030 | int n; | ||
1031 | bool b,b2; | ||
1032 | struct Point* point; | ||
1033 | asteroid->exists = true; | ||
1034 | asteroid->type = type; | ||
1035 | asteroid->explode_countdown = 0; | ||
1036 | |||
1037 | /*Set the radius of the asteroid:*/ | ||
1038 | asteroid->radius = (int)type; | ||
1039 | |||
1040 | /*shall we move Clockwise and Fast*/ | ||
1041 | if((rb->rand()%100)>75) | ||
1042 | { | ||
1043 | asteroid->speed_cos = FAST_ROT_CW_COS; | ||
1044 | asteroid->speed_sin = FAST_ROT_CW_SIN; | ||
1045 | } | ||
1046 | else if((rb->rand()%100)>75) | ||
1047 | { | ||
1048 | asteroid->speed_cos = FAST_ROT_ACW_COS; | ||
1049 | asteroid->speed_sin = FAST_ROT_ACW_SIN; | ||
1050 | } | ||
1051 | else if((rb->rand()%100)>75) | ||
1052 | { | ||
1053 | asteroid->speed_cos = SLOW_ROT_ACW_COS; | ||
1054 | asteroid->speed_sin = SLOW_ROT_ACW_SIN; | ||
1055 | } | ||
1056 | else | ||
1057 | { | ||
1058 | asteroid->speed_cos = SLOW_ROT_CW_COS; | ||
1059 | asteroid->speed_sin = SLOW_ROT_CW_SIN; | ||
1060 | } | ||
1061 | |||
1062 | b = (rb->rand()%100)>66; | ||
1063 | b2 = (rb->rand()%100)>66; | ||
1064 | point = asteroid->vertices; | ||
1065 | for(n = 0; n < NUM_ASTEROID_VERTICES*2; n+=2) | ||
1066 | { | ||
1067 | if(b) | ||
1068 | { | ||
1069 | point->x = asteroid_one[n]*asteroid->radius/2; | ||
1070 | point->y = asteroid_one[n+1]*asteroid->radius/2; | ||
1071 | } | ||
1072 | else if( b2 ) | ||
1073 | { | ||
1074 | point->x = asteroid_two[n]*asteroid->radius/2; | ||
1075 | point->y = asteroid_two[n+1]*asteroid->radius/2; | ||
1076 | } | ||
1077 | else | ||
1078 | { | ||
1079 | point->x = asteroid_three[n]*asteroid->radius/2; | ||
1080 | point->y = asteroid_three[n+1]*asteroid->radius/2; | ||
1081 | } | ||
1082 | point->x *= SCALE; | ||
1083 | point->y *= SCALE; | ||
1084 | point++; | ||
1085 | } | ||
1086 | |||
1087 | asteroid->radius *= SCALE/2; | ||
1088 | |||
1089 | if(asteroid->type == LARGE) | ||
1090 | asteroid->radius *= 7; | ||
1091 | else if(asteroid->type == MEDIUM) | ||
1092 | asteroid->radius *= 4; | ||
1093 | else if(asteroid->type == SMALL) | ||
1094 | asteroid->radius /= 2; | ||
1095 | |||
1096 | b = true; | ||
1097 | while(b) | ||
1098 | { | ||
1099 | /*Set the position randomly:*/ | ||
1100 | asteroid->position.x = (rb->rand()%SCALED_WIDTH); | ||
1101 | asteroid->position.y = (rb->rand()%SCALED_HEIGHT); | ||
1102 | |||
1103 | asteroid->position.dx = 0; | ||
1104 | while(asteroid->position.dx == 0) | ||
1105 | asteroid->position.dx = (rb->rand()%10)-5; | ||
1106 | |||
1107 | asteroid->position.dy = 0; | ||
1108 | while(asteroid->position.dy == 0) | ||
1109 | asteroid->position.dy = (rb->rand()%10)-5; | ||
1110 | |||
1111 | asteroid->position.dx *= SCALE/10; | ||
1112 | asteroid->position.dy *= SCALE/10; | ||
1113 | |||
1114 | b = is_point_within_rectangle(&ship.position, &asteroid->position, | ||
1115 | space_check_size); | ||
1116 | } | ||
1117 | |||
1118 | /*Now rotate the asteroid a bit, so they all look a bit different*/ | ||
1119 | for(n=(rb->rand()%30) + 2;--n;) | ||
1120 | rotate_asteroid(asteroid); | ||
1121 | |||
1122 | /*great, we've created an asteroid, don't forget to increment the total:*/ | ||
1123 | asteroid_count++; | ||
1124 | } | ||
1125 | |||
1126 | /*Initialise the ship*/ | ||
1127 | void initialise_ship(void) | ||
1128 | { | ||
1129 | struct Point* point; | ||
1130 | struct Point* lives_point; | ||
1131 | int n; | ||
1132 | |||
1133 | ship.position.x = CENTER_LCD_X; | ||
1134 | ship.position.y = CENTER_LCD_Y; | ||
1135 | ship.position.x *= SCALE; | ||
1136 | ship.position.y *= SCALE; | ||
1137 | ship.position.dx = ship.position.dy = 0; | ||
1138 | |||
1139 | point = ship.vertices; | ||
1140 | lives_point = lives_points; | ||
1141 | for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2) | ||
1142 | { | ||
1143 | point->x = ship_vertices[n]; | ||
1144 | point->y = ship_vertices[n+1]; | ||
1145 | point->x *= SCALE; | ||
1146 | point->y *= SCALE; | ||
1147 | point++; | ||
1148 | lives_point++; | ||
1149 | } | ||
1150 | |||
1151 | ship.position.dx = 0; | ||
1152 | ship.position.dy = 0; | ||
1153 | ship.explode_countdown = 0; | ||
1154 | |||
1155 | /*hack-o-rama-city-arizona, take it out to see what happens:*/ | ||
1156 | for(n=17;--n;) | ||
1157 | rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN); | ||
1158 | |||
1159 | /*grab a copy of the ships points for the lives display:*/ | ||
1160 | point = ship.vertices; | ||
1161 | lives_point = lives_points; | ||
1162 | for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2) | ||
1163 | { | ||
1164 | lives_point->x = point->x; | ||
1165 | lives_point->y = point->y; | ||
1166 | lives_point++; | ||
1167 | point++; | ||
1168 | } | ||
1169 | } | ||
1170 | |||
1171 | void rotate_asteroid(struct Asteroid* asteroid) | ||
1172 | { | ||
1173 | struct Point* point; | ||
1174 | int n; | ||
1175 | long xtemp; | ||
1176 | |||
1177 | point = asteroid->vertices; | ||
1178 | for(n = NUM_ASTEROID_VERTICES+1; --n;) | ||
1179 | { | ||
1180 | xtemp = point->x; | ||
1181 | point->x = xtemp*asteroid->speed_cos/SIN_COS_SCALE - | ||
1182 | point->y*asteroid->speed_sin/SIN_COS_SCALE; | ||
1183 | point->y = point->y*asteroid->speed_cos/SIN_COS_SCALE + | ||
1184 | xtemp*asteroid->speed_sin/SIN_COS_SCALE; | ||
1185 | point++; | ||
1186 | } | ||
1187 | } | ||
1188 | |||
1189 | /************************************************* | ||
1190 | ** Draws the ship, moves the ship and creates a new | ||
1191 | ** one if it's finished exploding. | ||
1192 | **************************************************/ | ||
1193 | void draw_and_move_ship(void) | ||
1194 | { | ||
1195 | int nxoffset = ship.position.x/SCALE; | ||
1196 | int nyoffset = ship.position.y/SCALE; | ||
1197 | if(!ship.explode_countdown) | ||
1198 | { | ||
1199 | if(!ship.waiting_for_space) | ||
1200 | draw_polygon(ship.vertices, nxoffset, nyoffset, NUM_SHIP_VERTICES); | ||
1201 | } | ||
1202 | else | ||
1203 | { | ||
1204 | animate_and_draw_explosion(ship.vertices, NUM_SHIP_VERTICES, | ||
1205 | ship.position.x/SCALE, | ||
1206 | ship.position.y/SCALE); | ||
1207 | if(game_state != PAUSE_MODE) | ||
1208 | { | ||
1209 | ship.explode_countdown--; | ||
1210 | if(!ship.explode_countdown) | ||
1211 | { | ||
1212 | num_lives--; | ||
1213 | if(!num_lives) | ||
1214 | { | ||
1215 | show_game_over = SHOW_GAME_OVER_TIME; | ||
1216 | game_state = GAME_OVER; | ||
1217 | } | ||
1218 | else | ||
1219 | { | ||
1220 | initialise_ship(); | ||
1221 | ship.waiting_for_space = true; | ||
1222 | } | ||
1223 | } | ||
1224 | } | ||
1225 | } | ||
1226 | |||
1227 | if(game_state != PAUSE_MODE && game_state != GAME_OVER) | ||
1228 | move_point(&ship.position); | ||
1229 | } | ||
1230 | |||
1231 | void thrust_ship(void) | ||
1232 | { | ||
1233 | if(!ship.waiting_for_space) | ||
1234 | { | ||
1235 | ship.position.dx += ( ship.vertices[0].x - ship.vertices[2].x )/10; | ||
1236 | ship.position.dy += ( ship.vertices[0].y - ship.vertices[2].y )/10; | ||
1237 | /*if dx and dy are below a certain threshold, then set 'em to 0*/ | ||
1238 | } | ||
1239 | } | ||
1240 | |||
1241 | /************************************************** | ||
1242 | ** Rotate the ship using the passed sin & cos values | ||
1243 | ***************************************************/ | ||
1244 | void rotate_ship(int c, int s) | ||
1245 | { | ||
1246 | struct Point* point; | ||
1247 | int n; | ||
1248 | double xtemp; | ||
1249 | |||
1250 | if(!ship.waiting_for_space && !ship.explode_countdown) | ||
1251 | { | ||
1252 | point = ship.vertices; | ||
1253 | for(n=NUM_SHIP_VERTICES+1;--n;) | ||
1254 | { | ||
1255 | xtemp = point->x; | ||
1256 | point->x = xtemp*c/SIN_COS_SCALE - point->y*s/SIN_COS_SCALE; | ||
1257 | point->y = point->y*c/SIN_COS_SCALE + xtemp*s/SIN_COS_SCALE; | ||
1258 | point++; | ||
1259 | } | ||
1260 | } | ||
1261 | } | ||
1262 | |||
1263 | void drawstars() | ||
1264 | { | ||
1265 | struct Point* p; | ||
1266 | int n = NUM_STARS; | ||
1267 | |||
1268 | p = stars; | ||
1269 | while(--n) | ||
1270 | { | ||
1271 | rb->lcd_drawpixel(p->x , p->y); | ||
1272 | p++; | ||
1273 | } | ||
1274 | } | ||
1275 | |||
1276 | /************************************************* | ||
1277 | ** Draw And Move all Asteroids | ||
1278 | *************************************************/ | ||
1279 | void draw_and_move_asteroids(void) | ||
1280 | { | ||
1281 | int n; | ||
1282 | struct Asteroid* asteroid; | ||
1283 | |||
1284 | asteroid = asteroids_array; | ||
1285 | n = MAX_NUM_ASTEROIDS; | ||
1286 | while(--n) | ||
1287 | { | ||
1288 | if(game_state != PAUSE_MODE) | ||
1289 | { | ||
1290 | if(asteroid->exists) | ||
1291 | { | ||
1292 | move_point(&asteroid->position); | ||
1293 | rotate_asteroid(asteroid); | ||
1294 | draw_polygon(asteroid->vertices, asteroid->position.x/SCALE, | ||
1295 | asteroid->position.y/SCALE, | ||
1296 | NUM_ASTEROID_VERTICES); | ||
1297 | } | ||
1298 | else if(asteroid->explode_countdown) | ||
1299 | { | ||
1300 | animate_and_draw_explosion(asteroid->vertices, | ||
1301 | NUM_ASTEROID_VERTICES, | ||
1302 | asteroid->position.x/SCALE, | ||
1303 | asteroid->position.y/SCALE); | ||
1304 | if(game_state != PAUSE_MODE) | ||
1305 | asteroid->explode_countdown--; | ||
1306 | } | ||
1307 | } | ||
1308 | else | ||
1309 | { | ||
1310 | if(asteroid->exists) | ||
1311 | draw_polygon(asteroid->vertices, | ||
1312 | asteroid->position.x/SCALE, | ||
1313 | asteroid->position.y/SCALE, | ||
1314 | NUM_ASTEROID_VERTICES); | ||
1315 | } | ||
1316 | asteroid++; | ||
1317 | } | ||
1318 | } | ||
1319 | |||
1320 | void create_stars(void) | ||
1321 | { | ||
1322 | struct Point* p; | ||
1323 | int n; | ||
1324 | |||
1325 | p = stars; | ||
1326 | n = NUM_STARS; | ||
1327 | while(--n) | ||
1328 | { | ||
1329 | p->x = (rb->rand()%LCD_WIDTH); | ||
1330 | p->y = (rb->rand()%LCD_HEIGHT); | ||
1331 | p++; | ||
1332 | } | ||
1333 | } | ||
1334 | |||
1335 | /************************************************* | ||
1336 | ** Creates start_num number of new asteroids of | ||
1337 | ** full size. | ||
1338 | **************************************************/ | ||
1339 | void initialise_game(int start_num) | ||
1340 | { | ||
1341 | int n; | ||
1342 | asteroid_count = next_missile_count = next_thrust_count = 0; | ||
1343 | struct Asteroid* asteroid; | ||
1344 | struct Missile* missile; | ||
1345 | |||
1346 | /*no enemy*/ | ||
1347 | enemy_on_screen = 0; | ||
1348 | enemy_missile.survived = 0; | ||
1349 | |||
1350 | /*clear asteroids*/ | ||
1351 | asteroid = asteroids_array; | ||
1352 | n = MAX_NUM_ASTEROIDS; | ||
1353 | while(--n) | ||
1354 | { | ||
1355 | asteroid->exists = false; | ||
1356 | asteroid++; | ||
1357 | } | ||
1358 | |||
1359 | /*make some LARGE asteroids*/ | ||
1360 | for(n = 0; n < start_num; n++) | ||
1361 | initialise_asteroid(&asteroids_array[n], LARGE); | ||
1362 | |||
1363 | /*ensure all missiles are out of action: */ | ||
1364 | missile = missiles_array; | ||
1365 | n = MAX_NUM_MISSILES; | ||
1366 | while(--n) | ||
1367 | { | ||
1368 | missile->survived=0; | ||
1369 | missile++; | ||
1370 | } | ||
1371 | } | ||
1372 | |||
1373 | void start_attract_mode(void) | ||
1374 | { | ||
1375 | current_level = 5; | ||
1376 | num_lives = START_LIVES; | ||
1377 | current_score = 0; | ||
1378 | attract_flip_timeout = ATTRACT_FLIP_TIME; | ||
1379 | game_state = ATTRACT_MODE; | ||
1380 | if(asteroid_count < 3) | ||
1381 | initialise_game(current_level); | ||
1382 | } | ||
1383 | |||
1384 | enum plugin_status start_game(void) | ||
1385 | { | ||
1386 | char s[20]; | ||
1387 | char level[10]; | ||
1388 | int button; | ||
1389 | int end; | ||
1390 | int CYCLETIME = 30; | ||
1391 | |||
1392 | /*create stars once, and once only:*/ | ||
1393 | create_stars(); | ||
1394 | |||
1395 | while(true) | ||
1396 | { | ||
1397 | /*game starts with at level 1 | ||
1398 | with 1 asteroid.*/ | ||
1399 | start_attract_mode(); | ||
1400 | |||
1401 | /*Main loop*/ | ||
1402 | while(true) | ||
1403 | { | ||
1404 | end = *rb->current_tick + (CYCLETIME * HZ) / 1000; | ||
1405 | rb->lcd_clear_display(); | ||
1406 | switch(game_state) | ||
1407 | { | ||
1408 | case(ATTRACT_MODE): | ||
1409 | if(attract_flip_timeout < ATTRACT_FLIP_TIME/2) | ||
1410 | { | ||
1411 | rb->lcd_putsxy(CENTER_LCD_X - 39, | ||
1412 | CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, | ||
1413 | "Fire to Start"); | ||
1414 | if(!attract_flip_timeout) | ||
1415 | attract_flip_timeout = ATTRACT_FLIP_TIME; | ||
1416 | } | ||
1417 | else | ||
1418 | { | ||
1419 | rb->snprintf(s, sizeof(s), "Hi Score %d ", high_score); | ||
1420 | rb->lcd_putsxy(CENTER_LCD_X - 30, | ||
1421 | CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, s); | ||
1422 | } | ||
1423 | attract_flip_timeout--; | ||
1424 | break; | ||
1425 | |||
1426 | case(GAME_OVER): | ||
1427 | rb->lcd_putsxy(CENTER_LCD_X - 25, | ||
1428 | CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "Game Over"); | ||
1429 | rb->snprintf(s, sizeof(s), "score %d ", current_score); | ||
1430 | rb->lcd_putsxy(1,LCD_HEIGHT-8, s); | ||
1431 | show_game_over--; | ||
1432 | if(!show_game_over) | ||
1433 | start_attract_mode(); | ||
1434 | break; | ||
1435 | |||
1436 | case(PAUSE_MODE): | ||
1437 | rb->snprintf(s, sizeof(s), "score %d ", current_score); | ||
1438 | rb->lcd_putsxy(1,LCD_HEIGHT-8, s); | ||
1439 | rb->lcd_putsxy(CENTER_LCD_X - 15, | ||
1440 | CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "pause"); | ||
1441 | draw_and_move_missiles(); | ||
1442 | draw_lives(); | ||
1443 | draw_and_move_ship(); | ||
1444 | break; | ||
1445 | |||
1446 | case(PLAY_MODE): | ||
1447 | rb->snprintf(s, sizeof(s), "score %d ", current_score); | ||
1448 | rb->lcd_putsxy(1,LCD_HEIGHT-8, s); | ||
1449 | draw_and_move_missiles(); | ||
1450 | draw_lives(); | ||
1451 | check_collisions(); | ||
1452 | draw_and_move_ship(); | ||
1453 | break; | ||
1454 | |||
1455 | case(SHOW_LEVEL): | ||
1456 | show_level_timeout--; | ||
1457 | rb->snprintf(s, sizeof(s), "score %d ", current_score); | ||
1458 | rb->lcd_putsxy(1,LCD_HEIGHT-8, s); | ||
1459 | rb->snprintf(level, sizeof(level), "stage %d ", current_level); | ||
1460 | rb->lcd_putsxy(CENTER_LCD_X - 20, | ||
1461 | CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, level); | ||
1462 | draw_and_move_ship(); | ||
1463 | draw_lives(); | ||
1464 | if(!show_level_timeout) | ||
1465 | { | ||
1466 | initialise_game(current_level); | ||
1467 | game_state = PLAY_MODE; | ||
1468 | draw_lives(); | ||
1469 | } | ||
1470 | break; | ||
1471 | } | ||
1472 | drawstars(); | ||
1473 | draw_and_move_asteroids(); | ||
1474 | draw_and_move_enemy(); | ||
1475 | |||
1476 | rb->lcd_update(); | ||
1477 | button = rb->button_get(false); | ||
1478 | switch(button) | ||
1479 | { | ||
1480 | case(AST_PAUSE): | ||
1481 | if(game_state == PLAY_MODE) | ||
1482 | game_state = PAUSE_MODE; | ||
1483 | else if(game_state == PAUSE_MODE) | ||
1484 | game_state = PLAY_MODE; | ||
1485 | break; | ||
1486 | |||
1487 | case(AST_QUIT): | ||
1488 | if(game_state == ATTRACT_MODE) | ||
1489 | return PLUGIN_OK; | ||
1490 | else if(game_state == GAME_OVER) | ||
1491 | { | ||
1492 | start_attract_mode(); | ||
1493 | } | ||
1494 | else | ||
1495 | { | ||
1496 | show_game_over = SHOW_GAME_OVER_TIME; | ||
1497 | game_state = GAME_OVER; | ||
1498 | } | ||
1499 | break; | ||
1500 | |||
1501 | case (AST_LEFT_REP): | ||
1502 | case (AST_LEFT): | ||
1503 | if(game_state == PLAY_MODE || game_state == SHOW_LEVEL) | ||
1504 | rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN); | ||
1505 | break; | ||
1506 | |||
1507 | case (AST_RIGHT_REP): | ||
1508 | case (AST_RIGHT): | ||
1509 | if(game_state == PLAY_MODE || game_state == SHOW_LEVEL) | ||
1510 | rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN); | ||
1511 | break; | ||
1512 | |||
1513 | case (AST_THRUST_REP): | ||
1514 | case (AST_THRUST): | ||
1515 | if((game_state == PLAY_MODE || game_state == SHOW_LEVEL) && !next_thrust_count) | ||
1516 | { | ||
1517 | thrust_ship(); | ||
1518 | next_thrust_count = 5; | ||
1519 | } | ||
1520 | break; | ||
1521 | |||
1522 | case (AST_HYPERSPACE): | ||
1523 | if(game_state == PLAY_MODE) | ||
1524 | hyperspace(); | ||
1525 | /*maybe shield if it gets too hard */ | ||
1526 | break; | ||
1527 | |||
1528 | case (AST_FIRE_REP): | ||
1529 | case (AST_FIRE): | ||
1530 | if(game_state == ATTRACT_MODE) | ||
1531 | { | ||
1532 | current_level = START_LEVEL; | ||
1533 | initialise_ship(); | ||
1534 | initialise_game(current_level); | ||
1535 | show_level_timeout = SHOW_LEVEL_TIME; | ||
1536 | game_state = PLAY_MODE; | ||
1537 | } | ||
1538 | else if(game_state == PLAY_MODE) | ||
1539 | { | ||
1540 | if(!next_missile_count) | ||
1541 | { | ||
1542 | fire_missile(); | ||
1543 | next_missile_count = 10; | ||
1544 | } | ||
1545 | } | ||
1546 | else if(game_state == PAUSE_MODE) | ||
1547 | { | ||
1548 | game_state = PLAY_MODE; | ||
1549 | } | ||
1550 | break; | ||
1551 | |||
1552 | default: | ||
1553 | if (rb->default_event_handler(button)==SYS_USB_CONNECTED) | ||
1554 | return PLUGIN_USB_CONNECTED; | ||
1555 | break; | ||
1556 | } | ||
1557 | |||
1558 | if(!num_lives) | ||
1559 | { | ||
1560 | if(high_score < current_score) | ||
1561 | high_score = current_score; | ||
1562 | if(!show_game_over) | ||
1563 | break; | ||
1564 | } | ||
1565 | |||
1566 | if(next_missile_count) | ||
1567 | next_missile_count--; | ||
1568 | |||
1569 | if(next_thrust_count) | ||
1570 | next_thrust_count--; | ||
1571 | |||
1572 | if (end > *rb->current_tick) | ||
1573 | rb->sleep(end-*rb->current_tick); | ||
1574 | else | ||
1575 | rb->yield(); | ||
1576 | } | ||
1577 | |||
1578 | } | ||
1579 | } | ||
1580 | |||
1581 | enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | ||
1582 | { | ||
1583 | enum plugin_status retval; | ||
1584 | |||
1585 | (void)(parameter); | ||
1586 | rb = api; | ||
1587 | |||
1588 | game_state = ATTRACT_MODE; | ||
1589 | |||
1590 | /* universal font */ | ||
1591 | rb->lcd_setfont(FONT_SYSFIXED); | ||
1592 | rb->backlight_set_timeout(1); | ||
1593 | iohiscore(); | ||
1594 | retval = start_game(); | ||
1595 | iohiscore(); | ||
1596 | rb->lcd_setfont(FONT_UI); | ||
1597 | /* restore normal backlight setting*/ | ||
1598 | rb->backlight_set_timeout(rb->global_settings->backlight_timeout); | ||
1599 | |||
1600 | return retval; | ||
1601 | } | ||