fix wrong score recording.
[kugel-rb.git] / apps / plugins / spacerocks.c
blob39de40cdd22a4cded3cf1fde51ae50c2ae3870dc
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 by Mat Holton
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "plugin.h"
23 #include "lib/helper.h"
25 PLUGIN_HEADER
27 /******************************* Globals ***********************************/
28 /* variable button definitions */
29 #if CONFIG_KEYPAD == RECORDER_PAD
30 #define AST_PAUSE BUTTON_ON
31 #define AST_QUIT BUTTON_OFF
32 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
33 #define AST_THRUST BUTTON_UP
34 #define AST_HYPERSPACE BUTTON_DOWN
35 #define AST_LEFT BUTTON_LEFT
36 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
37 #define AST_RIGHT BUTTON_RIGHT
38 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
39 #define AST_FIRE BUTTON_PLAY
40 #define AST_FIRE_REP BUTTON_PLAY | BUTTON_REPEAT
42 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
43 #define AST_PAUSE BUTTON_ON
44 #define AST_QUIT BUTTON_OFF
45 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
46 #define AST_THRUST BUTTON_UP
47 #define AST_HYPERSPACE BUTTON_DOWN
48 #define AST_LEFT BUTTON_LEFT
49 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
50 #define AST_RIGHT BUTTON_RIGHT
51 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
52 #define AST_FIRE BUTTON_SELECT
53 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
55 #elif CONFIG_KEYPAD == ONDIO_PAD
56 #define AST_PAUSE (BUTTON_MENU | BUTTON_OFF)
57 #define AST_QUIT BUTTON_OFF
58 #define AST_THRUST BUTTON_UP
59 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
60 #define AST_HYPERSPACE BUTTON_DOWN
61 #define AST_LEFT BUTTON_LEFT
62 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
63 #define AST_RIGHT BUTTON_RIGHT
64 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
65 #define AST_FIRE BUTTON_MENU
66 #define AST_FIRE_REP BUTTON_MENU | BUTTON_REPEAT
68 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
69 (CONFIG_KEYPAD == IRIVER_H300_PAD)
70 #define AST_PAUSE BUTTON_REC
71 #define AST_QUIT BUTTON_OFF
72 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
73 #define AST_THRUST BUTTON_UP
74 #define AST_HYPERSPACE BUTTON_DOWN
75 #define AST_LEFT BUTTON_LEFT
76 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
77 #define AST_RIGHT BUTTON_RIGHT
78 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
79 #define AST_FIRE BUTTON_SELECT
80 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
82 #define AST_RC_QUIT BUTTON_RC_STOP
84 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
85 #define AST_PAUSE BUTTON_PLAY
86 #define AST_QUIT BUTTON_POWER
87 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
88 #define AST_THRUST BUTTON_UP
89 #define AST_HYPERSPACE BUTTON_DOWN
90 #define AST_LEFT BUTTON_LEFT
91 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
92 #define AST_RIGHT BUTTON_RIGHT
93 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
94 #define AST_FIRE BUTTON_SELECT
95 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
97 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
98 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
99 #define AST_PAUSE (BUTTON_SELECT | BUTTON_PLAY)
100 #define AST_QUIT (BUTTON_SELECT | BUTTON_MENU)
101 #define AST_THRUST BUTTON_MENU
102 #define AST_THRUST_REP (BUTTON_MENU | BUTTON_REPEAT)
103 #define AST_HYPERSPACE BUTTON_PLAY
104 #define AST_LEFT BUTTON_SCROLL_BACK
105 #define AST_LEFT_REP (BUTTON_SCROLL_BACK | BUTTON_REPEAT)
106 #define AST_RIGHT BUTTON_SCROLL_FWD
107 #define AST_RIGHT_REP (BUTTON_SCROLL_FWD | BUTTON_REPEAT)
108 #define AST_FIRE BUTTON_SELECT
109 #define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT)
111 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
112 #define AST_PAUSE BUTTON_A
113 #define AST_QUIT BUTTON_POWER
114 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
115 #define AST_THRUST BUTTON_UP
116 #define AST_HYPERSPACE BUTTON_DOWN
117 #define AST_LEFT BUTTON_LEFT
118 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
119 #define AST_RIGHT BUTTON_RIGHT
120 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
121 #define AST_FIRE BUTTON_SELECT
122 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
124 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
125 #define AST_PAUSE BUTTON_REC
126 #define AST_QUIT BUTTON_POWER
127 #define AST_THRUST_REP (BUTTON_UP | BUTTON_REPEAT)
128 #define AST_THRUST BUTTON_UP
129 #define AST_HYPERSPACE BUTTON_DOWN
130 #define AST_LEFT BUTTON_SCROLL_BACK
131 #define AST_LEFT_REP (BUTTON_SCROLL_BACK | BUTTON_REPEAT)
132 #define AST_RIGHT BUTTON_SCROLL_FWD
133 #define AST_RIGHT_REP (BUTTON_SCROLL_FWD | BUTTON_REPEAT)
134 #define AST_FIRE BUTTON_SELECT
135 #define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT)
137 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
138 #define AST_PAUSE (BUTTON_SELECT | BUTTON_UP)
139 #define AST_QUIT (BUTTON_HOME|BUTTON_REPEAT)
140 #define AST_THRUST_REP (BUTTON_UP | BUTTON_REPEAT)
141 #define AST_THRUST BUTTON_UP
142 #define AST_HYPERSPACE BUTTON_DOWN
143 #define AST_LEFT BUTTON_SCROLL_BACK
144 #define AST_LEFT_REP (BUTTON_SCROLL_BACK | BUTTON_REPEAT)
145 #define AST_RIGHT BUTTON_SCROLL_FWD
146 #define AST_RIGHT_REP (BUTTON_SCROLL_FWD | BUTTON_REPEAT)
147 #define AST_FIRE BUTTON_SELECT
148 #define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT)
150 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
151 #define AST_PAUSE BUTTON_REC
152 #define AST_QUIT BUTTON_POWER
153 #define AST_THRUST_REP (BUTTON_UP | BUTTON_REPEAT)
154 #define AST_THRUST BUTTON_UP
155 #define AST_HYPERSPACE BUTTON_DOWN
156 #define AST_LEFT BUTTON_LEFT
157 #define AST_LEFT_REP (BUTTON_LEFT | BUTTON_REPEAT)
158 #define AST_RIGHT BUTTON_RIGHT
159 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
160 #define AST_FIRE BUTTON_SELECT
161 #define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT)
163 #elif (CONFIG_KEYPAD == SANSA_CLIP_PAD)
164 #define AST_PAUSE BUTTON_HOME
165 #define AST_QUIT BUTTON_POWER
166 #define AST_THRUST_REP (BUTTON_UP | BUTTON_REPEAT)
167 #define AST_THRUST BUTTON_UP
168 #define AST_HYPERSPACE BUTTON_DOWN
169 #define AST_LEFT BUTTON_LEFT
170 #define AST_LEFT_REP (BUTTON_LEFT | BUTTON_REPEAT)
171 #define AST_RIGHT BUTTON_RIGHT
172 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
173 #define AST_FIRE BUTTON_SELECT
174 #define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT)
176 #elif (CONFIG_KEYPAD == SANSA_M200_PAD)
177 #define AST_PAUSE (BUTTON_SELECT | BUTTON_UP)
178 #define AST_QUIT BUTTON_POWER
179 #define AST_THRUST_REP (BUTTON_UP | BUTTON_REPEAT)
180 #define AST_THRUST BUTTON_UP
181 #define AST_HYPERSPACE BUTTON_DOWN
182 #define AST_LEFT BUTTON_LEFT
183 #define AST_LEFT_REP (BUTTON_LEFT | BUTTON_REPEAT)
184 #define AST_RIGHT BUTTON_RIGHT
185 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
186 #define AST_FIRE (BUTTON_SELECT | BUTTON_REL)
187 #define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT)
189 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
190 #define AST_PAUSE BUTTON_PLAY
191 #define AST_QUIT BUTTON_POWER
192 #define AST_THRUST_REP BUTTON_SCROLL_UP | BUTTON_REPEAT
193 #define AST_THRUST BUTTON_SCROLL_UP
194 #define AST_HYPERSPACE BUTTON_SCROLL_DOWN
195 #define AST_LEFT BUTTON_LEFT
196 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
197 #define AST_RIGHT BUTTON_RIGHT
198 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
199 #define AST_FIRE BUTTON_REW
200 #define AST_FIRE_REP BUTTON_REW | BUTTON_REPEAT
202 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
203 #define AST_PAUSE BUTTON_PLAY
204 #define AST_QUIT BUTTON_BACK
205 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
206 #define AST_THRUST BUTTON_UP
207 #define AST_HYPERSPACE BUTTON_DOWN
208 #define AST_LEFT BUTTON_LEFT
209 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
210 #define AST_RIGHT BUTTON_RIGHT
211 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
212 #define AST_FIRE BUTTON_SELECT
213 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
215 #elif (CONFIG_KEYPAD == MROBE100_PAD)
216 #define AST_PAUSE BUTTON_DISPLAY
217 #define AST_QUIT BUTTON_POWER
218 #define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
219 #define AST_THRUST BUTTON_UP
220 #define AST_HYPERSPACE BUTTON_DOWN
221 #define AST_LEFT BUTTON_LEFT
222 #define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
223 #define AST_RIGHT BUTTON_RIGHT
224 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
225 #define AST_FIRE BUTTON_SELECT
226 #define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
228 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
229 #define AST_PAUSE BUTTON_RC_PLAY
230 #define AST_QUIT BUTTON_RC_REC
231 #define AST_THRUST_REP BUTTON_RC_VOL_UP | BUTTON_REPEAT
232 #define AST_THRUST BUTTON_RC_VOL_UP
233 #define AST_HYPERSPACE BUTTON_RC_VOL_DOWN
234 #define AST_LEFT BUTTON_RC_REW
235 #define AST_LEFT_REP (BUTTON_RC_REW | BUTTON_REPEAT)
236 #define AST_RIGHT BUTTON_RC_FF
237 #define AST_RIGHT_REP (BUTTON_RC_FF | BUTTON_REPEAT)
238 #define AST_FIRE BUTTON_RC_MODE
239 #define AST_FIRE_REP (BUTTON_RC_MODE | BUTTON_REPEAT)
241 #elif (CONFIG_KEYPAD == COWOND2_PAD)
242 #define AST_QUIT BUTTON_POWER
244 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
245 #define AST_PAUSE BUTTON_PLAY
246 #define AST_QUIT BUTTON_BACK
247 #define AST_THRUST_REP (BUTTON_UP | BUTTON_REPEAT)
248 #define AST_THRUST BUTTON_UP
249 #define AST_HYPERSPACE BUTTON_DOWN
250 #define AST_LEFT BUTTON_LEFT
251 #define AST_LEFT_REP (BUTTON_LEFT | BUTTON_REPEAT)
252 #define AST_RIGHT BUTTON_RIGHT
253 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
254 #define AST_FIRE BUTTON_SELECT
255 #define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT)
257 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
258 #define AST_PAUSE BUTTON_VIEW
259 #define AST_QUIT BUTTON_POWER
260 #define AST_THRUST_REP (BUTTON_UP | BUTTON_REPEAT)
261 #define AST_THRUST BUTTON_UP
262 #define AST_HYPERSPACE BUTTON_DOWN
263 #define AST_LEFT BUTTON_LEFT
264 #define AST_LEFT_REP (BUTTON_LEFT | BUTTON_REPEAT)
265 #define AST_RIGHT BUTTON_RIGHT
266 #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
267 #define AST_FIRE BUTTON_PLAYLIST
268 #define AST_FIRE_REP (BUTTON_PLAYLIST | BUTTON_REPEAT)
270 #elif (CONFIG_KEYPAD == ONDAVX747_PAD) || CONFIG_KEYPAD == MROBE500_PAD
271 #define AST_QUIT BUTTON_POWER
273 #else
274 #error No keymap defined!
275 #endif
277 #ifdef HAVE_TOUCHSCREEN
278 #ifndef AST_PAUSE
279 #define AST_PAUSE BUTTON_CENTER
280 #endif
281 #ifndef AST_QUIT
282 #define AST_QUIT BUTTON_TOPLEFT
283 #endif
284 #ifndef AST_THRUST_REP
285 #define AST_THRUST_REP (BUTTON_TOPMIDDLE | BUTTON_REPEAT)
286 #endif
287 #ifndef AST_THRUST
288 #define AST_THRUST BUTTON_TOPMIDDLE
289 #endif
290 #ifndef AST_HYPERSPACE
291 #define AST_HYPERSPACE BUTTON_TOPRIGHT
292 #endif
293 #ifndef AST_LEFT
294 #define AST_LEFT BUTTON_MIDLEFT
295 #endif
296 #ifndef AST_LEFT_REP
297 #define AST_LEFT_REP (BUTTON_MIDLEFT | BUTTON_REPEAT)
298 #endif
299 #ifndef AST_RIGHT
300 #define AST_RIGHT BUTTON_MIDRIGHT
301 #endif
302 #ifndef AST_RIGHT_REP
303 #define AST_RIGHT_REP (BUTTON_MIDRIGHT | BUTTON_REPEAT)
304 #endif
305 #ifndef AST_FIRE
306 #define AST_FIRE BUTTON_BOTTOMMIDDLE
307 #endif
308 #ifndef AST_FIRE_REP
310 #ifdef BUTTON_MENU
311 #define AST_FIRE_REP (BUTTON_BOTTOMMIDDLE | BUTTON_MENU)
312 #else
313 #define AST_FIRE_REP BUTTON_BOTTOMMIDDLE | BUTTON_REPEAT
314 #endif
316 #endif
317 #endif
319 #define ABS(x) ((x)>0?(x):-(x))
321 #define RES MAX(LCD_WIDTH, LCD_HEIGHT)
322 #define LARGE_LCD RES >= 200
323 #define ENEMY_MISSILE_SURVIVAL_LENGTH RES/2
324 #define ASTEROID_SPEED RES/20
325 #define MISSILE_SURVIVAL_LENGTH 40
327 #define EXTRA_LIFE 250
328 #define SPAWN_TIME 30
329 #define BLINK_TIME 10
330 #define SCALE 5000
331 #define MISSILE_SCALE 5000
332 #define WRAP_GAP 12
333 #define EXPLOSION_LENGTH 20
334 #define SHOW_COL 0
335 #define HISCORE_FILE PLUGIN_GAMES_DIR "/astrorocks.hs"
336 #define POINT_SIZE 2
337 #define MAX_NUM_ASTEROIDS 25
338 #define MAX_NUM_MISSILES 6
339 #define ENEMY_BIG_PROBABILITY_START 10
340 #define ENEMY_APPEAR_PROBABILITY_START 35
341 #define ENEMY_APPEAR_TIMING_START 1800
342 #define LITTLE_SHIP 2
343 #define BIG_SHIP 1
344 #define SHOW_GAME_OVER_TIME 100
345 #define SHOW_LEVEL_TIME 50
346 #define START_LIVES 3
347 #define START_LEVEL 1
348 #define NUM_ASTEROID_VERTICES 10
349 #define NUM_SHIP_VERTICES 4
350 #define NUM_ENEMY_VERTICES 6
351 #define MAX_LEVEL MAX_NUM_ASTEROIDS
352 #define ENEMY_SPEED 4
353 #define ENEMY_START_X 0
354 #define ENEMY_START_Y 0
355 #define SIZE_ENEMY_COLLISION 5*SCALE
356 #define ATTRACT_FLIP_TIME 100
357 #define NUM_STARS 50
358 #define NUM_TRAIL_POINTS 70
359 #define NUM_ROTATIONS 16
361 #define SIN_COS_SCALE 10000
363 #define FAST_ROT_CW_SIN 873
364 #define FAST_ROT_CW_COS 9963
365 #define FAST_ROT_ACW_SIN -873
366 #define FAST_ROT_ACW_COS 9963
368 #define MEDIUM_ROT_CW_SIN 350
369 #define MEDIUM_ROT_CW_COS 9994
370 #define MEDIUM_ROT_ACW_SIN -350
371 #define MEDIUM_ROT_ACW_COS 9994
373 #define SLOW_ROT_CW_SIN 350
374 #define SLOW_ROT_CW_COS 9994
375 #define SLOW_ROT_ACW_SIN - 350
376 #define SLOW_ROT_ACW_COS 9994
378 #ifdef HAVE_LCD_COLOR
379 #define SHIP_ROT_CW_SIN 2419
380 #define SHIP_ROT_CW_COS 9702
381 #define SHIP_ROT_ACW_SIN -2419
382 #define SHIP_ROT_ACW_COS 9702
383 #else
384 #define SHIP_ROT_CW_SIN 3827
385 #define SHIP_ROT_CW_COS 9239
386 #define SHIP_ROT_ACW_SIN -3827
387 #define SHIP_ROT_ACW_COS 9239
388 #endif
391 #define SCALED_WIDTH (LCD_WIDTH*SCALE)
392 #define SCALED_HEIGHT (LCD_HEIGHT*SCALE)
393 #define CENTER_LCD_X (LCD_WIDTH/2)
394 #define CENTER_LCD_Y (LCD_HEIGHT/2)
396 #define SHIP_EXPLOSION_COLOUR 1
397 #define ASTEROID_EXPLOSION_COLOUR 2
398 #define ENEMY_EXPLOSION_COLOUR 3
399 #define THRUST_COLOUR 4
401 #define ASTEROID_R 230
402 #define ASTEROID_G 200
403 #define ASTEROID_B 100
404 #define SHIP_R 255
405 #define SHIP_G 255
406 #define SHIP_B 255
407 #define ENEMY_R 50
408 #define ENEMY_G 220
409 #define ENEMY_B 50
410 #define THRUST_R 200
411 #define THRUST_G 200
412 #define THRUST_B 0
414 #ifdef HAVE_LCD_COLOR
415 #define COL_MISSILE LCD_RGBPACK(200,0,0)
416 #define COL_PLAYER LCD_RGBPACK(200,200,200)
417 #define COL_INVULN LCD_RGBPACK(100,100,200)
418 #define COL_STARS LCD_WHITE
419 #define COL_ASTEROID LCD_RGBPACK(ASTEROID_R,ASTEROID_G,ASTEROID_B)
420 #define COL_TEXT LCD_RGBPACK(200,200,255)
421 #define COL_ENEMY LCD_RGBPACK(ENEMY_R,ENEMY_G,ENEMY_B)
422 #define SET_FG rb->lcd_set_foreground
423 #define SET_BG rb->lcd_set_background
424 #else
425 #define SET_FG(x)
426 #define SET_BG(x)
427 #endif
429 /* The array of points that make up an asteroid */
430 static const short asteroid_one[NUM_ASTEROID_VERTICES*2] =
432 -2, -12,
433 4, -8,
434 8, -14,
435 16, -5,
436 14, 0,
437 20, 2,
438 12, 14,
439 -4, 14,
440 -10, 6,
441 -10, -8
444 /* The array of points that make up an asteroid */
445 static const short asteroid_two[NUM_ASTEROID_VERTICES*2] =
447 -2, -12,
448 4, -16,
449 6, -14,
450 16, -8,
451 14, 0,
452 20, 2,
453 12, 14,
454 -4, 14,
455 -10, 6,
456 -10, -8
459 /* The array of points that make up an asteroid */
460 static const short asteroid_three[NUM_ASTEROID_VERTICES*2] =
462 -2, -12,
463 4, -16,
464 6, -14,
465 2, -8,
466 14, 0,
467 20, 2,
468 12, 14,
469 -4, 14,
470 -16, 6,
471 -10, -8
474 /* The array od points the make up the ship */
475 static const short ship_vertices[NUM_SHIP_VERTICES*2] =
477 #if(LARGE_LCD)
478 0,-6,
479 4, 6,
480 0, 2,
481 -4, 6
482 #else
483 0,-4,
484 3, 4,
485 0, 1,
486 -3, 4
487 #endif
490 /* The array of points the make up the bad spaceship */
491 static const short enemy_vertices[NUM_ENEMY_VERTICES*2] =
493 #if(LARGE_LCD)
494 -8, 0,
495 -4, 4,
496 4, 4,
497 8, 0,
498 4, -4,
499 -4, -4
500 #else
501 -5, 0,
502 -2, 2,
503 2, 2,
504 5, 0,
505 2, -2,
506 -2, -2
507 #endif
511 enum asteroid_type
513 #if(LARGE_LCD)
514 SMALL = 2,
515 MEDIUM = 4,
516 LARGE = 6,
517 #else
518 SMALL = 1,
519 MEDIUM = 2,
520 LARGE = 3,
521 #endif
525 enum game_state
527 GAME_OVER,
528 ATTRACT_MODE,
529 SHOW_LEVEL,
530 PLAY_MODE,
531 PAUSE_MODE
534 struct Point
536 int x;
537 int y;
538 int dx;
539 int dy;
542 struct TrailPoint
544 int alive;
545 struct Point position;
546 short r;
547 short g;
548 short b;
549 short dec;
552 /* Asteroid structure, contains an array of points */
553 struct Asteroid
555 enum asteroid_type type;
556 bool exists;
557 struct Point position;
558 struct Point vertices[NUM_ASTEROID_VERTICES];
559 int radius;
560 long speed_cos;
561 long speed_sin;
562 int explode_countdown;
565 struct Ship
567 struct Point vertices[NUM_SHIP_VERTICES];
568 struct Point position;
569 bool waiting_for_space;
570 bool invulnerable;
571 int spawn_time;
572 int explode_countdown;
575 struct Enemy
577 struct Point vertices[NUM_ENEMY_VERTICES];
578 struct Point position;
579 int explode_countdown;
580 long last_time_appeared;
581 short size_probability;
582 short appear_probability;
583 short appear_timing;
586 struct Missile
588 struct Point position;
589 struct Point oldpoint;
590 int survived;
593 static enum game_state game_state;
594 static int asteroid_count;
595 static int next_missile_count;
596 static int next_thrust_count;
597 static int num_lives;
598 static int extra_life;
599 static int show_level_timeout;
600 static int attract_flip_timeout;
601 static int show_game_over;
602 static int current_level;
603 static int current_score;
604 static int high_score;
605 static int space_check_size = 30*SCALE;
607 static bool enemy_on_screen;
608 static char phscore[30];
609 static struct Ship ship;
610 static struct Point stars[NUM_STARS];
611 static struct Asteroid asteroids_array[MAX_NUM_ASTEROIDS];
612 static struct Missile missiles_array[MAX_NUM_MISSILES];
613 static struct Missile enemy_missile;
614 static struct Enemy enemy;
615 static struct Point lives_points[NUM_SHIP_VERTICES];
616 static struct TrailPoint trailPoints[NUM_TRAIL_POINTS];
618 void draw_and_move_asteroids(void);
619 void initialise_game(int nStartNum);
621 bool is_asteroid_near_ship(struct Asteroid* asteroid);
622 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point);
624 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type eType);
625 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices);
626 void rotate_asteroid(struct Asteroid* asteroid);
627 void create_asteroid(enum asteroid_type type, int x, int y);
628 void create_stars(void);
630 void initialise_ship(void);
631 void draw_and_move_ship(void);
632 void rotate_ship(int s, int c);
633 void thrust_ship(void);
635 void initialise_missile(struct Missile* missile);
636 void draw_and_move_missiles(void);
637 void fire_missile(void);
639 void animate_and_draw_explosion(struct Point* point, int num_points, int xoffset, int yoffset);
640 void initialise_explosion(struct Point* point, int num_points);
642 void move_point(struct Point* point);
643 void hyperspace(void);
644 void check_collisions(void);
645 void initialise_enemy(void);
646 void draw_and_move_enemy(void);
647 void draw_lives(void);
648 void drawstars(void);
649 bool is_ship_within_asteroid(struct Asteroid* asteroid);
653 /*Hi-Score reading and writing to file - this needs moving to the hi-score plugin lib as
654 a 3rd function */
655 void iohiscore(void)
657 int fd;
658 int compare;
660 /* clear the buffer we're about to load the highscore data into */
661 rb->memset(phscore, 0, sizeof(phscore));
663 fd = rb->open(HISCORE_FILE,O_RDWR | O_CREAT);
664 if(fd < 0)
666 rb->splash(HZ, "Highscore file read error");
667 return;
670 /* highscore used to %d, is now %d\n
671 Deal with no file or bad file */
672 rb->read(fd,phscore, sizeof(phscore));
674 compare = rb->atoi(phscore);
676 if(high_score > compare)
678 rb->lseek(fd,0,SEEK_SET);
679 rb->fdprintf(fd, "%d\n", high_score);
681 else
682 high_score = compare;
684 rb->close(fd);
687 bool point_in_poly(struct Point* _point, int num_vertices, int x, int y)
689 struct Point* pi;
690 struct Point* pj;
691 int n;
692 bool c = false;
694 pi = _point;
695 pj = _point;
696 pj += num_vertices-1;
698 n = num_vertices;
699 while(n--)
701 if((((pi->y <= y) && (y < pj->y)) || ((pj->y <= y) && (y < pi->y))) &&
702 (x < (pj->x - pi->x) * (y - pi->y) / (pj->y - pi->y) + pi->x))
703 c = !c;
705 if(n == num_vertices - 1)
706 pj = _point;
707 else
708 pj++;
710 pi++;
713 return c;
716 void move_point(struct Point* point)
718 point->x += point->dx;
719 point->y += point->dy;
721 /*check bounds on the x-axis:*/
722 if(point->x >= SCALED_WIDTH)
723 point->x = 0;
724 else if(point->x <= 0)
725 point->x = SCALED_WIDTH;
727 /*Check bounds on the y-axis:*/
728 if(point->y >= SCALED_HEIGHT)
729 point->y = 0;
730 else if(point->y <= 0)
731 point->y = SCALED_HEIGHT;
734 void create_trail(struct TrailPoint* tpoint)
736 tpoint->position.dx = -( ship.vertices[0].x - ship.vertices[2].x )/10;
737 tpoint->position.dy = -( ship.vertices[0].y - ship.vertices[2].y )/10;
740 void create_explosion_trail(struct TrailPoint* tpoint)
742 tpoint->position.dx = (rb->rand()%5050)-2500;
743 tpoint->position.dy = (rb->rand()%5050)-2500;
746 void create_trail_blaze(int colour, struct Point* position)
748 int numtoadd;
749 struct TrailPoint* tpoint;
750 int n;
751 int xadd,yadd;
752 if(colour != SHIP_EXPLOSION_COLOUR)
754 numtoadd = NUM_TRAIL_POINTS/5;
755 xadd = position->x;
756 yadd = position->y;
758 else
760 numtoadd = NUM_TRAIL_POINTS/8;
761 xadd = ship.position.x;
762 yadd = ship.position.y;
765 /* give the point a random countdown timer, so they dissapears at different times */
766 tpoint = trailPoints;
767 n = NUM_TRAIL_POINTS;
768 while(--n)
770 if(tpoint->alive <= 0 && numtoadd)
772 numtoadd--;
773 /* take a random x point anywhere between bottom two points of ship. */
774 /* ship.position.x; */
775 tpoint->position.x = (ship.vertices[2].x + (rb->rand()%18000)-9000) + position->x;
776 tpoint->position.y = (ship.vertices[2].y + (rb->rand()%18000)-9000) + position->y;
778 switch(colour)
780 case SHIP_EXPLOSION_COLOUR:
781 tpoint->r = 255;
782 tpoint->g = 255;
783 tpoint->b = 255;
784 create_explosion_trail(tpoint);
785 tpoint->alive = 510;
786 tpoint->dec = 2;
787 break;
788 case ASTEROID_EXPLOSION_COLOUR:
789 tpoint->r = ASTEROID_R;
790 tpoint->g = ASTEROID_G;
791 tpoint->b = ASTEROID_B;
792 create_explosion_trail(tpoint);
793 tpoint->alive = 510;
794 tpoint->dec = 2;
795 break;
796 case ENEMY_EXPLOSION_COLOUR:
797 tpoint->r = ENEMY_R;
798 tpoint->g = ENEMY_G;
799 tpoint->b = ENEMY_B;
800 create_explosion_trail(tpoint);
801 tpoint->alive = 510;
802 tpoint->dec = 2;
803 break;
804 case THRUST_COLOUR:
805 tpoint->r = THRUST_R;
806 tpoint->g = THRUST_G;
807 tpoint->b = THRUST_B;
808 create_trail(tpoint);
809 tpoint->alive = 175;
810 tpoint->dec = 4;
811 break;
813 /* add a proportional bit to the x and y based on dx and dy */
815 /* give the points a speed based on direction of travel - i.e. opposite */
816 tpoint->position.dx += position->dx;
817 tpoint->position.dy += position->dy;
821 tpoint++;
823 /* find a space in the array of trail_points that is NULL or DEAD or whatever.
824 and place this one here. */
828 void draw_trail_blaze(void)
830 struct TrailPoint* tpoint;
831 /* loop through, if alive then move and draw.
832 when drawn, countdown it's timer.
833 if zero kill it! */
834 tpoint = trailPoints;
835 int n = NUM_TRAIL_POINTS;
837 while(--n)
839 if(tpoint->alive)
841 if(game_state != PAUSE_MODE)
843 tpoint->alive-=10;
844 move_point(&(tpoint->position));
846 #ifdef HAVE_LCD_COLOR
847 /* intensity = tpoint->alive/2; */
848 if(tpoint->r>0)tpoint->r-=tpoint->dec;
849 if(tpoint->g>0)tpoint->g-=tpoint->dec;
850 if(tpoint->b>0)tpoint->b-=tpoint->dec;
851 SET_FG(LCD_RGBPACK(tpoint->r, tpoint->g, tpoint->b));
852 #endif
853 rb->lcd_drawpixel(tpoint->position.x/SCALE , tpoint->position.y/SCALE);
855 tpoint++;
859 /*Check if point is within a rectangle*/
860 bool is_point_within_rectangle(struct Point* rect, struct Point* p, int size)
862 #if SHOW_COL
863 int aTLx = rect->x - size;
864 int aTLy = rect->y - size;
865 int aBRx = rect->x + size;
866 int aBRy = rect->y + size;
867 rb->lcd_hline( aTLx/SCALE, aBRx/SCALE, aTLy/SCALE);
868 rb->lcd_vline( aTLx/SCALE, aTLy/SCALE, aBRy/SCALE);
869 rb->lcd_hline( aTLx/SCALE, aBRx/SCALE, aBRy/SCALE);
870 rb->lcd_vline( aBRx/SCALE, aBRy/SCALE, aTLy/SCALE);
871 return (p->x > aTLx && p->x < aBRx && p->y > aTLy && p->y < aBRy);
872 #else
873 return (p->x > rect->x - size && p->x < rect->x + size &&
874 p->y > rect->y - size && p->y < rect->y + size);
875 #endif
878 /* Draw polygon */
879 void draw_polygon(struct Point* vertices, int px, int py, int num_vertices)
881 int n, t1, t2, oldX, oldY;
882 struct Point *p;
883 bool bDrawAll = px < WRAP_GAP || LCD_WIDTH - px < WRAP_GAP ||
884 py < WRAP_GAP || LCD_HEIGHT - py < WRAP_GAP;
886 p = vertices;
887 p += num_vertices-1;
888 oldX = p->x/SCALE + px;
889 oldY = p->y/SCALE + py;
890 p = vertices;
891 for(n = num_vertices+1; --n;)
893 t1 = p->x/SCALE + px;
894 t2 = p->y/SCALE + py;
896 rb->lcd_drawline(oldX, oldY, t1, t2);
898 if(bDrawAll)
900 rb->lcd_drawline(oldX - LCD_WIDTH, oldY, t1 - LCD_WIDTH, t2);
901 rb->lcd_drawline(oldX + LCD_WIDTH, oldY, t1 + LCD_WIDTH, t2);
902 rb->lcd_drawline(oldX - LCD_WIDTH, oldY + LCD_HEIGHT,
903 t1 - LCD_WIDTH, t2 + LCD_HEIGHT);
904 rb->lcd_drawline(oldX + LCD_WIDTH, oldY + LCD_HEIGHT,
905 t1 + LCD_WIDTH, t2 + LCD_HEIGHT);
907 rb->lcd_drawline(oldX, oldY - LCD_HEIGHT, t1, t2 - LCD_HEIGHT);
908 rb->lcd_drawline(oldX, oldY + LCD_HEIGHT, t1, t2 + LCD_HEIGHT);
909 rb->lcd_drawline(oldX - LCD_WIDTH, oldY - LCD_HEIGHT,
910 t1 - LCD_WIDTH, t2 - LCD_HEIGHT);
911 rb->lcd_drawline(oldX + LCD_WIDTH, oldY - LCD_HEIGHT,
912 t1 + LCD_WIDTH, t2 - LCD_HEIGHT);
914 oldX = t1;
915 oldY = t2;
916 p++;
920 void animate_and_draw_explosion(struct Point* point, int num_points,
921 int xoffset, int yoffset)
923 int n;
924 for(n = num_points; --n;)
926 if(game_state != PAUSE_MODE)
928 point->x += point->dx;
929 point->y += point->dy;
931 rb->lcd_fillrect( point->x/SCALE + xoffset, point->y/SCALE + yoffset,
932 POINT_SIZE, POINT_SIZE);
933 point++;
937 /*stop movement of ship, 'cos that's what happens when you go into hyperspace.*/
938 void hyperspace(void)
940 ship.position.dx = ship.position.dy = 0;
941 ship.position.x = (rb->rand()%SCALED_WIDTH);
942 ship.position.y = (rb->rand()%SCALED_HEIGHT);
945 void initialise_enemy(void)
947 struct Point* point;
948 int n;
949 int size;
951 if(rb->rand()%100 > enemy.size_probability)
953 size = BIG_SHIP;
954 enemy.size_probability++;
955 if(enemy.size_probability < 90)
957 enemy.size_probability = ENEMY_BIG_PROBABILITY_START;
960 else
962 size = LITTLE_SHIP;
965 enemy_missile.survived = 0;
966 enemy_on_screen = true;
967 enemy.explode_countdown = 0;
968 enemy.last_time_appeared = *rb->current_tick;
969 point = enemy.vertices;
970 for(n = 0; n < NUM_ENEMY_VERTICES+NUM_ENEMY_VERTICES; n+=2)
972 point->x = enemy_vertices[n];
973 point->y = enemy_vertices[n+1];
974 point->x *= SCALE/size;
975 point->y *= SCALE/size;
976 point++;
979 if(ship.position.x >= SCALED_WIDTH/2)
981 enemy.position.dx = ENEMY_SPEED;
982 enemy.position.x = 0;
984 else
986 enemy.position.dx = -ENEMY_SPEED;
987 enemy.position.x = SCALED_WIDTH;
990 if(ship.position.y >= SCALED_HEIGHT/2)
992 enemy.position.dy = ENEMY_SPEED;
993 enemy.position.y = 0;
995 else
997 enemy.position.dy = -ENEMY_SPEED;
998 enemy.position.y = SCALED_HEIGHT;
1001 enemy.position.dx *= SCALE/10;
1002 enemy.position.dy *= SCALE/10;
1005 void draw_and_move_enemy(void)
1007 int enemy_x, enemy_y;
1008 struct Point *point;
1010 SET_FG(COL_ENEMY);
1012 if(enemy_on_screen)
1014 enemy_x = enemy.position.x/SCALE;
1015 enemy_y = enemy.position.y/SCALE;
1016 if(!enemy.explode_countdown)
1018 point = enemy.vertices;
1019 draw_polygon(enemy.vertices, enemy_x, enemy_y, NUM_ENEMY_VERTICES);
1020 rb->lcd_drawline(enemy.vertices[0].x/SCALE + enemy_x,
1021 enemy.vertices[0].y/SCALE + enemy_y,
1022 enemy.vertices[3].x/SCALE + enemy_x,
1023 enemy.vertices[3].y/SCALE + enemy_y);
1025 if(game_state != PAUSE_MODE)
1027 enemy.position.x += enemy.position.dx;
1028 enemy.position.y += enemy.position.dy;
1031 if(enemy.position.x > SCALED_WIDTH || enemy.position.x < 0)
1032 enemy_on_screen = false;
1034 if(enemy.position.y > SCALED_HEIGHT)
1035 enemy.position.y = 0;
1036 else if(enemy.position.y < 0)
1037 enemy.position.y = SCALED_HEIGHT;
1039 if( (rb->rand()%1000) < 10)
1040 enemy.position.dy = -enemy.position.dy;
1042 else
1045 /* animate_and_draw_explosion(enemy.vertices, NUM_ENEMY_VERTICES,
1046 enemy_x, enemy.position.y/SCALE); */
1047 if(game_state != PAUSE_MODE)
1049 enemy.explode_countdown--;
1050 if(!enemy.explode_countdown)
1051 enemy_on_screen = false;
1055 else
1057 if( (*rb->current_tick - enemy.last_time_appeared) > enemy.appear_timing)
1058 if(rb->rand()%100 > enemy.appear_probability) initialise_enemy();
1061 if(!enemy_missile.survived && game_state != GAME_OVER)
1063 /*if no missile and the enemy is here and not exploding..then shoot baby!*/
1064 if( !enemy.explode_countdown && enemy_on_screen &&
1065 !ship.waiting_for_space && (rb->rand()%10) > 5 )
1067 enemy_missile.position.x = enemy.position.x;
1068 enemy_missile.position.y = enemy.position.y;
1070 /*lame, needs to be sorted - it's trying to shoot at the ship*/
1071 if(ABS(enemy.position.y - ship.position.y) <= 5*SCALE)
1073 enemy_missile.position.dy = 0;
1075 else
1077 if( enemy.position.y < ship.position.y)
1078 enemy_missile.position.dy = 1;
1079 else
1080 enemy_missile.position.dy = -1;
1083 if(ABS(enemy.position.x - ship.position.x) <= 5*SCALE)
1084 enemy_missile.position.dx = 0;
1085 else
1087 if( enemy.position.x < ship.position.x)
1088 enemy_missile.position.dx = 1;
1089 else
1090 enemy_missile.position.dx = -1;
1093 if(enemy_missile.position.dx == 0 &&
1094 enemy_missile.position.dy == 0)
1095 enemy_missile.position.dx = enemy_missile.position.dy = -1;
1097 enemy_missile.position.dx *= SCALE;
1098 enemy_missile.position.dy *= SCALE;
1099 enemy_missile.survived = ENEMY_MISSILE_SURVIVAL_LENGTH;
1103 else
1105 rb->lcd_fillrect( enemy_missile.position.x/SCALE,
1106 enemy_missile.position.y/SCALE,
1107 POINT_SIZE, POINT_SIZE);
1108 if(game_state != PAUSE_MODE)
1110 move_point(&enemy_missile.position);
1111 enemy_missile.survived--;
1116 /******************
1117 * Lame method of collision
1118 * detection. It's checking for collision
1119 * between point and a big rectangle around the asteroid...
1120 *******************/
1121 bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point)
1123 if( !is_point_within_rectangle(&asteroid->position, point,
1124 asteroid->radius+4*SCALE) )
1125 return false;
1127 if(point_in_poly(asteroid->vertices, NUM_ASTEROID_VERTICES,
1128 point->x - asteroid->position.x,
1129 point->y - asteroid->position.y))
1131 switch(asteroid->type)
1133 case(SMALL):
1134 asteroid->explode_countdown = EXPLOSION_LENGTH;
1135 create_trail_blaze(ASTEROID_EXPLOSION_COLOUR, &asteroid->position);
1136 break;
1138 case(LARGE):
1139 create_asteroid(MEDIUM, asteroid->position.x,
1140 asteroid->position.y);
1141 create_asteroid(MEDIUM, asteroid->position.x,
1142 asteroid->position.y);
1143 break;
1145 case(MEDIUM):
1146 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1147 create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
1148 break;
1151 current_score++;
1152 if(current_score > extra_life)
1154 num_lives++;
1155 extra_life = current_score+EXTRA_LIFE;
1157 asteroid_count--;
1158 asteroid->exists = false;
1159 return true;
1161 else
1162 return false;
1165 bool is_point_within_enemy(struct Point* point)
1167 if( is_point_within_rectangle(&enemy.position, point, 7*SCALE) )
1169 current_score += 5;
1170 /*enemy_missile.survived = 0;*/
1171 enemy.explode_countdown = EXPLOSION_LENGTH;
1172 /* initialise_explosion(enemy.vertices, NUM_ENEMY_VERTICES); */
1173 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1174 return true;
1176 else
1177 return false;
1180 bool is_ship_within_asteroid(struct Asteroid* asteroid)
1182 bool hit = false;
1183 struct Point p;
1185 p.x = ship.position.x + ship.vertices[0].x;
1186 p.y = ship.position.y + ship.vertices[0].y;
1187 hit |= is_point_within_asteroid(asteroid, &p);
1189 if(!hit)
1191 p.x = ship.position.x + ship.vertices[1].x;
1192 p.y = ship.position.y + ship.vertices[1].y;
1193 hit |= is_point_within_asteroid(asteroid, &p);
1194 if(!hit)
1196 p.x = ship.position.x + ship.vertices[3].x;
1197 p.y = ship.position.y + ship.vertices[3].y;
1198 hit |= is_point_within_asteroid(asteroid, &p);
1202 return hit;
1205 void initialise_explosion(struct Point* point, int num_points)
1207 int n;
1209 point->x += point->dx;
1210 point->y += point->dy;
1211 for(n = num_points; --n;)
1213 point->dx = point->x;
1214 point->dy = point->y;
1215 point++;
1220 /* Check for collsions between the missiles and the asteroids and the ship */
1221 void check_collisions(void)
1223 int m, n;
1224 bool asteroids_onscreen = false;
1225 struct Missile* missile;
1226 struct Asteroid* asteroid;
1227 bool ship_cant_be_placed = false;
1229 asteroid = asteroids_array;
1230 m = MAX_NUM_ASTEROIDS;
1231 while(--m)
1233 /*if the asteroids exists then test missile collision:*/
1234 if(asteroid->exists)
1236 missile = missiles_array;
1237 n = MAX_NUM_MISSILES;
1238 while(--n)
1240 /*if the missiles exists:*/
1241 if(missile->survived > 0)
1243 /*has the missile hit the asteroid?*/
1244 if(is_point_within_asteroid(asteroid, &missile->position)
1245 || is_point_within_asteroid(asteroid,
1246 &missile->oldpoint))
1248 missile->survived = 0;
1249 break;
1252 missile++;
1255 /*now check collision with ship:*/
1256 if(asteroid->exists && !ship.waiting_for_space && !ship.explode_countdown)
1258 if(is_ship_within_asteroid(asteroid))
1260 if (!ship.invulnerable)
1262 /*if not invulnerable, blow up ship*/
1263 ship.explode_countdown = EXPLOSION_LENGTH;
1264 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1265 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1269 /*has the enemy missile blown something up?*/
1270 if(asteroid->exists && enemy_missile.survived)
1272 if(is_point_within_asteroid(asteroid, &enemy_missile.position))
1274 /*take that score back then:*/
1275 if(current_score > 0) current_score--;
1276 enemy_missile.survived = 0;
1279 /*if it still exists, check if ship is waiting for space:*/
1280 if(asteroid->exists && ship.waiting_for_space)
1281 ship_cant_be_placed |=
1282 is_point_within_rectangle(&ship.position,
1283 &asteroid->position,
1284 space_check_size);
1288 /*is an asteroid still exploding?*/
1289 if(asteroid->explode_countdown)
1290 asteroids_onscreen = true;
1292 asteroid++;
1295 /*now check collision between ship and enemy*/
1296 if(enemy_on_screen && !ship.waiting_for_space &&
1297 !ship.explode_countdown && !enemy.explode_countdown)
1299 /*has the enemy collided with the ship?*/
1300 if(is_point_within_enemy(&ship.position))
1302 if (!ship.invulnerable)
1304 ship.explode_countdown = EXPLOSION_LENGTH;
1305 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1306 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1308 create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position);
1311 /*Now see if the enemy has been shot at by the ships missiles:*/
1312 missile = missiles_array;
1313 n = MAX_NUM_MISSILES;
1314 while(--n)
1316 if(missile->survived > 0 &&
1317 is_point_within_enemy(&missile->position))
1319 missile->survived = 0;
1320 break;
1322 missile++;
1326 /*test collision with enemy missile and ship:*/
1327 if(!ship_cant_be_placed && enemy_missile.survived > 0 &&
1328 point_in_poly(ship.vertices, NUM_SHIP_VERTICES,
1329 enemy_missile.position.x - ship.position.x,
1330 enemy_missile.position.y - ship.position.y))
1332 if (!ship.invulnerable)
1334 ship.explode_countdown = EXPLOSION_LENGTH;
1335 /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */
1336 create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position);
1338 enemy_missile.survived = 0;
1339 enemy_missile.position.x = enemy_missile.position.y = 0;
1342 if(!ship_cant_be_placed)
1343 ship.waiting_for_space = false;
1345 /*if all asteroids cleared then start again:*/
1346 if(asteroid_count == 0 && !enemy_on_screen && !asteroids_onscreen)
1348 current_level++;
1349 game_state = SHOW_LEVEL;
1350 enemy.appear_probability += 5;
1351 enemy.appear_timing -= 200;
1352 if( enemy.appear_probability > 100)
1353 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1354 show_level_timeout = SHOW_LEVEL_TIME;
1358 /*************************************************
1359 ** Creates a new asteroid of the given 4type (size)
1360 ** and at the given location.
1361 *************************************************/
1362 void create_asteroid(enum asteroid_type type, int x, int y)
1364 struct Asteroid* asteroid;
1365 int n;
1367 asteroid = asteroids_array;
1368 n = MAX_NUM_ASTEROIDS;
1369 while(--n)
1371 if(!asteroid->exists && !asteroid->explode_countdown)
1373 initialise_asteroid(asteroid, type);
1374 asteroid->position.x = x;
1375 asteroid->position.y = y;
1376 break;
1378 asteroid++;
1382 /* Initialise a missile */
1383 void initialise_missile(struct Missile* missile)
1385 missile->position.x = ship.position.x + ship.vertices[0].x;
1386 missile->position.y = ship.position.y + ship.vertices[0].y;
1387 missile->position.dx = (ship.vertices[0].x - ship.vertices[2].x)/2;
1388 missile->position.dy = (ship.vertices[0].y - ship.vertices[2].y)/2;
1389 missile->survived = MISSILE_SURVIVAL_LENGTH;
1390 missile->oldpoint.x = missile->position.x;
1391 missile->oldpoint.y = missile->position.y;
1394 /* Draw and Move all the missiles */
1395 void draw_and_move_missiles(void)
1397 int n;
1398 int p1x, p1y;
1399 int p2x, p2y;
1401 struct Missile* missile;
1402 missile = missiles_array;
1404 SET_FG(COL_MISSILE);
1406 n = MAX_NUM_MISSILES;
1407 while(--n)
1409 if(missile->survived)
1411 if(missile->position.dx > 0)
1413 if(missile->position.x >= missile->oldpoint.x)
1415 p1x = missile->oldpoint.x;
1416 p2x = missile->position.x;
1418 else
1420 p1x = 0;
1421 p2x = missile->position.x;
1424 else
1426 if(missile->oldpoint.x >= missile->position.x)
1428 p1x = missile->oldpoint.x;
1429 p2x = missile->position.x;
1431 else
1433 p1x = missile->oldpoint.x;
1434 p2x = LCD_WIDTH;
1438 if(missile->position.dy > 0)
1440 if(missile->position.y >= missile->oldpoint.y)
1442 p1y = missile->oldpoint.y;
1443 p2y = missile->position.y;
1445 else
1447 p1y = 0;
1448 p2y = missile->position.y;
1451 else
1453 if(missile->oldpoint.y >= missile->position.y)
1455 p1y = missile->oldpoint.y;
1456 p2y = missile->position.y;
1458 else
1460 p1y = missile->oldpoint.y;
1461 p2y = LCD_HEIGHT;
1465 rb->lcd_drawline( p1x/SCALE, p1y/SCALE, p2x/SCALE, p2y/SCALE);
1467 if(game_state != PAUSE_MODE)
1469 missile->oldpoint.x = missile->position.x;
1470 missile->oldpoint.y = missile->position.y;
1471 move_point(&missile->position);
1472 missile->survived--;
1475 missile++;
1479 void draw_lives(void)
1481 int n;
1482 int px = (LCD_WIDTH - num_lives*4 - 1);
1483 #if(LARGE_LCD)
1484 int py = (LCD_HEIGHT-6);
1485 #else
1486 int py = (LCD_HEIGHT-4);
1487 #endif
1489 SET_FG(COL_PLAYER);
1491 n = num_lives;
1492 while(--n)
1494 draw_polygon(lives_points, px, py, NUM_SHIP_VERTICES);
1495 #if(LARGE_LCD)
1496 px += 8;
1497 #else
1498 px += 6;
1499 #endif
1503 /*Fire the next missile*/
1504 void fire_missile(void)
1506 int n;
1507 struct Missile* missile;
1509 if(!ship.explode_countdown && !ship.waiting_for_space)
1511 missile = missiles_array;
1512 n = MAX_NUM_MISSILES;
1513 while(--n)
1515 if(!missile->survived)
1517 initialise_missile(missile);
1518 break;
1520 missile++;
1525 /* Initialise the passed Asteroid */
1526 void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type type)
1528 int n;
1529 bool b,b2;
1530 struct Point* point;
1531 asteroid->exists = true;
1532 asteroid->type = type;
1533 asteroid->explode_countdown = 0;
1535 /*Set the radius of the asteroid:*/
1536 asteroid->radius = (int)type*SCALE;
1538 /*shall we move Clockwise and Fast*/
1539 if((rb->rand()%100)>75)
1541 asteroid->speed_cos = FAST_ROT_CW_COS;
1542 asteroid->speed_sin = FAST_ROT_CW_SIN;
1544 else if((rb->rand()%100)>75)
1546 asteroid->speed_cos = FAST_ROT_ACW_COS;
1547 asteroid->speed_sin = FAST_ROT_ACW_SIN;
1549 else if((rb->rand()%100)>75)
1551 asteroid->speed_cos = SLOW_ROT_ACW_COS;
1552 asteroid->speed_sin = SLOW_ROT_ACW_SIN;
1554 else
1556 asteroid->speed_cos = SLOW_ROT_CW_COS;
1557 asteroid->speed_sin = SLOW_ROT_CW_SIN;
1560 b = (rb->rand()%100)>66;
1561 b2 = (rb->rand()%100)>66;
1562 point = asteroid->vertices;
1563 for(n = 0; n < NUM_ASTEROID_VERTICES*2; n+=2)
1565 if(b)
1567 point->x = asteroid_one[n];
1568 point->y = asteroid_one[n+1];
1570 else if( b2 )
1572 point->x = asteroid_two[n];
1573 point->y = asteroid_two[n+1];
1575 else
1577 point->x = asteroid_three[n];
1578 point->y = asteroid_three[n+1];
1581 point->x *= asteroid->radius/6;
1582 point->y *= asteroid->radius/6;
1583 point++;
1587 asteroid->radius += 6*SCALE;
1588 if(asteroid->type == SMALL)
1589 asteroid->radius /= 3;/*2*/
1590 else if(asteroid->type == LARGE)
1591 asteroid->radius += 3*SCALE;/*2*/
1592 b = true;
1593 while(b)
1595 /*Set the position randomly:*/
1596 asteroid->position.x = (rb->rand()%SCALED_WIDTH);
1597 asteroid->position.y = (rb->rand()%SCALED_HEIGHT);
1599 asteroid->position.dx = 0;
1600 while(asteroid->position.dx == 0)
1601 asteroid->position.dx = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1603 asteroid->position.dy = 0;
1604 while(asteroid->position.dy == 0)
1605 asteroid->position.dy = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
1607 asteroid->position.dx *= SCALE/10;
1608 asteroid->position.dy *= SCALE/10;
1610 b = is_point_within_rectangle(&ship.position, &asteroid->position,
1611 space_check_size);
1614 /*Now rotate the asteroid a bit, so they all look a bit different*/
1615 for(n=(rb->rand()%30) + 2;--n;)
1616 rotate_asteroid(asteroid);
1618 /*great, we've created an asteroid, don't forget to increment the total:*/
1619 asteroid_count++;
1622 /*Initialise the ship*/
1623 void initialise_ship(void)
1625 struct Point* point;
1626 struct Point* lives_point;
1627 int n;
1629 ship.position.x = CENTER_LCD_X;
1630 ship.position.y = CENTER_LCD_Y;
1631 ship.position.x *= SCALE;
1632 ship.position.y *= SCALE;
1633 ship.position.dx = ship.position.dy = 0;
1634 ship.spawn_time = SPAWN_TIME;
1635 ship.invulnerable = 1;
1637 point = ship.vertices;
1638 lives_point = lives_points;
1639 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1641 point->x = ship_vertices[n];
1642 point->y = ship_vertices[n+1];
1643 point->x *= SCALE;
1644 point->y *= SCALE;
1645 point++;
1646 lives_point++;
1649 ship.position.dx = 0;
1650 ship.position.dy = 0;
1651 ship.explode_countdown = 0;
1653 /*grab a copy of the ships points for the lives display:*/
1654 point = ship.vertices;
1655 lives_point = lives_points;
1656 for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
1658 lives_point->x = point->x;
1659 lives_point->y = point->y;
1660 lives_point++;
1661 point++;
1665 void rotate_asteroid(struct Asteroid* asteroid)
1667 struct Point* point;
1668 int n;
1669 long xtemp;
1671 point = asteroid->vertices;
1672 for(n = NUM_ASTEROID_VERTICES+1; --n;)
1674 xtemp = point->x;
1675 point->x = xtemp*asteroid->speed_cos/SIN_COS_SCALE -
1676 point->y*asteroid->speed_sin/SIN_COS_SCALE;
1677 point->y = point->y*asteroid->speed_cos/SIN_COS_SCALE +
1678 xtemp*asteroid->speed_sin/SIN_COS_SCALE;
1679 point++;
1683 /*************************************************
1684 ** Draws the ship, moves the ship and creates a new
1685 ** one if it's finished exploding.
1686 **************************************************/
1687 void draw_and_move_ship(void)
1689 int nxoffset = ship.position.x/SCALE;
1690 int nyoffset = ship.position.y/SCALE;
1691 if (ship.invulnerable && (ship.spawn_time > BLINK_TIME || ship.spawn_time % 2 == 0))
1693 SET_FG(COL_INVULN);
1695 else
1697 SET_FG(COL_PLAYER);
1699 if(!ship.explode_countdown)
1701 /* make sure ship is invulnerable until spawn time over */
1702 if (ship.spawn_time)
1704 ship.spawn_time--;
1705 if (ship.spawn_time <= 0)
1707 ship.invulnerable = 0;
1710 if(!ship.waiting_for_space)
1712 draw_polygon(ship.vertices, nxoffset, nyoffset, NUM_SHIP_VERTICES);
1713 if(game_state != PAUSE_MODE && game_state != GAME_OVER)
1715 move_point(&ship.position);
1719 else
1721 /* animate_and_draw_explosion(ship.vertices, NUM_SHIP_VERTICES,
1722 ship.position.x/SCALE,
1723 ship.position.y/SCALE); */
1724 if(game_state != PAUSE_MODE)
1726 ship.explode_countdown--;
1727 if(!ship.explode_countdown)
1729 num_lives--;
1730 if(!num_lives)
1732 show_game_over = SHOW_GAME_OVER_TIME;
1733 game_state = GAME_OVER;
1735 else
1737 initialise_ship();
1738 ship.waiting_for_space = true;
1745 void thrust_ship(void)
1747 if(!ship.waiting_for_space)
1749 ship.position.dx += ( ship.vertices[0].x - ship.vertices[2].x )/20;
1750 ship.position.dy += ( ship.vertices[0].y - ship.vertices[2].y )/20;
1751 /*if dx and dy are below a certain threshold, then set 'em to 0
1752 but to do this we need to ascertain if the spacehip as moved on screen
1753 for more than a certain amount. */
1755 create_trail_blaze(THRUST_COLOUR, &ship.position);
1759 /**************************************************
1760 ** Rotate the ship using the passed sin & cos values
1761 ***************************************************/
1762 void rotate_ship(int c, int s)
1764 struct Point* point;
1765 int n;
1766 double xtemp;
1768 if(!ship.waiting_for_space && !ship.explode_countdown)
1770 point = ship.vertices;
1771 for(n=NUM_SHIP_VERTICES+1;--n;)
1773 xtemp = point->x;
1774 point->x = xtemp*c/SIN_COS_SCALE - point->y*s/SIN_COS_SCALE;
1775 point->y = point->y*c/SIN_COS_SCALE + xtemp*s/SIN_COS_SCALE;
1776 point++;
1781 void drawstars()
1783 struct Point* p;
1784 int n = NUM_STARS;
1786 p = stars;
1787 SET_FG(COL_STARS);
1789 while(--n)
1791 rb->lcd_drawpixel(p->x , p->y);
1792 p++;
1796 /*************************************************
1797 ** Draw And Move all Asteroids
1798 *************************************************/
1799 void draw_and_move_asteroids(void)
1801 int n;
1802 struct Asteroid* asteroid;
1804 asteroid = asteroids_array;
1805 SET_FG(COL_ASTEROID);
1807 n = MAX_NUM_ASTEROIDS;
1808 while(--n)
1810 if(game_state != PAUSE_MODE)
1812 if(asteroid->exists)
1814 move_point(&asteroid->position);
1815 rotate_asteroid(asteroid);
1816 draw_polygon(asteroid->vertices, asteroid->position.x/SCALE,
1817 asteroid->position.y/SCALE,
1818 NUM_ASTEROID_VERTICES);
1820 else if(asteroid->explode_countdown)
1822 /* animate_and_draw_explosion(asteroid->vertices,
1823 NUM_ASTEROID_VERTICES,
1824 asteroid->position.x/SCALE,
1825 asteroid->position.y/SCALE); */
1826 asteroid->explode_countdown--;
1829 else
1831 if(asteroid->exists)
1832 draw_polygon(asteroid->vertices,
1833 asteroid->position.x/SCALE,
1834 asteroid->position.y/SCALE,
1835 NUM_ASTEROID_VERTICES);
1837 asteroid++;
1841 void create_stars(void)
1843 struct TrailPoint* tpoint;
1844 struct Point* p;
1845 int n;
1847 p = stars;
1848 n = NUM_STARS;
1849 while(--n)
1851 p->x = (rb->rand()%LCD_WIDTH);
1852 p->y = (rb->rand()%LCD_HEIGHT);
1853 p++;
1857 /* give the point a random countdown timer, so they dissapears at different
1858 times */
1859 tpoint = trailPoints;
1860 n = NUM_TRAIL_POINTS;
1861 while(--n)
1863 tpoint->alive = 0;
1864 tpoint++;
1868 /*************************************************
1869 ** Creates start_num number of new asteroids of
1870 ** full size.
1871 **************************************************/
1872 void initialise_game(int start_num)
1874 int n;
1875 asteroid_count = next_missile_count = next_thrust_count = 0;
1876 struct Asteroid* asteroid;
1877 struct Missile* missile;
1878 extra_life = EXTRA_LIFE;
1880 /*no enemy*/
1881 enemy_on_screen = 0;
1882 enemy_missile.survived = 0;
1884 /*clear asteroids*/
1885 asteroid = asteroids_array;
1886 n = MAX_NUM_ASTEROIDS;
1887 while(--n)
1889 asteroid->exists = false;
1890 asteroid++;
1893 /*make some LARGE asteroids*/
1894 for(n = 0; n < start_num; n++)
1895 initialise_asteroid(&asteroids_array[n], LARGE);
1897 /*ensure all missiles are out of action: */
1898 missile = missiles_array;
1899 n = MAX_NUM_MISSILES;
1900 while(--n)
1902 missile->survived=0;
1903 missile++;
1907 void start_attract_mode(void)
1909 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
1910 enemy.appear_timing = ENEMY_APPEAR_TIMING_START;
1911 current_level = 5;
1912 num_lives = START_LIVES;
1913 current_score = 0;
1914 attract_flip_timeout = ATTRACT_FLIP_TIME;
1915 game_state = ATTRACT_MODE;
1916 if(asteroid_count < 3)
1917 initialise_game(current_level);
1920 enum plugin_status start_game(void)
1922 char s[20];
1923 char level[10];
1924 int button;
1925 int end;
1926 int CYCLETIME = 30;
1928 /*create stars once, and once only:*/
1929 create_stars();
1931 SET_BG(LCD_BLACK);
1933 while(true)
1935 /*game starts with at level 1
1936 with 1 asteroid.*/
1937 start_attract_mode();
1939 /*Main loop*/
1940 while(true)
1942 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1943 rb->lcd_clear_display();
1944 SET_FG(COL_TEXT);
1945 switch(game_state)
1947 case(ATTRACT_MODE):
1948 if(attract_flip_timeout < ATTRACT_FLIP_TIME/2)
1950 rb->lcd_putsxy(CENTER_LCD_X - 39,
1951 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4,
1952 "Fire to Start");
1953 if(!attract_flip_timeout)
1954 attract_flip_timeout = ATTRACT_FLIP_TIME;
1956 else
1958 rb->snprintf(s, sizeof(s), "Hi Score %d ", high_score);
1959 rb->lcd_putsxy(CENTER_LCD_X - 30,
1960 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, s);
1962 attract_flip_timeout--;
1963 break;
1965 case(GAME_OVER):
1966 rb->lcd_putsxy(CENTER_LCD_X - 25,
1967 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "Game Over");
1968 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1969 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1970 show_game_over--;
1971 if(!show_game_over)
1972 start_attract_mode();
1973 break;
1975 case(PAUSE_MODE):
1976 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1977 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1978 rb->lcd_putsxy(CENTER_LCD_X - 15,
1979 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "pause");
1980 draw_and_move_missiles();
1981 draw_lives();
1982 draw_and_move_ship();
1983 break;
1985 case(PLAY_MODE):
1986 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1987 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1988 draw_and_move_missiles();
1989 draw_lives();
1990 check_collisions();
1991 draw_and_move_ship();
1992 break;
1994 case(SHOW_LEVEL):
1995 show_level_timeout--;
1996 rb->snprintf(s, sizeof(s), "score %d ", current_score);
1997 rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
1998 rb->snprintf(level, sizeof(level), "stage %d ", current_level);
1999 rb->lcd_putsxy(CENTER_LCD_X - 20,
2000 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, level);
2001 draw_and_move_ship();
2002 draw_lives();
2003 if(!show_level_timeout)
2005 initialise_game(current_level);
2006 game_state = PLAY_MODE;
2007 draw_lives();
2009 break;
2011 draw_trail_blaze();
2012 drawstars();
2013 draw_and_move_asteroids();
2014 draw_and_move_enemy();
2016 rb->lcd_update();
2017 button = rb->button_get(false);
2019 #ifdef HAS_BUTTON_HOLD
2020 if (rb->button_hold() && game_state == PLAY_MODE)
2021 game_state = PAUSE_MODE;
2022 #endif
2024 switch(button)
2026 case(AST_PAUSE):
2027 if(game_state == PLAY_MODE)
2028 game_state = PAUSE_MODE;
2029 else if(game_state == PAUSE_MODE)
2030 game_state = PLAY_MODE;
2031 break;
2033 #ifdef AST_RC_QUIT
2034 case AST_RC_QUIT:
2035 #endif
2036 case(AST_QUIT):
2037 if(game_state == ATTRACT_MODE)
2038 return PLUGIN_OK;
2039 else if(game_state == GAME_OVER)
2041 start_attract_mode();
2043 else
2045 show_game_over = SHOW_GAME_OVER_TIME;
2046 game_state = GAME_OVER;
2048 break;
2050 case (AST_LEFT_REP):
2051 case (AST_LEFT):
2052 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
2053 rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN);
2054 break;
2056 case (AST_RIGHT_REP):
2057 case (AST_RIGHT):
2058 if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
2059 rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN);
2060 break;
2062 case (AST_THRUST_REP):
2063 case (AST_THRUST):
2064 if((game_state == PLAY_MODE || game_state == SHOW_LEVEL) && !next_thrust_count)
2066 thrust_ship();
2067 next_thrust_count = 5;
2069 break;
2071 case (AST_HYPERSPACE):
2072 if(game_state == PLAY_MODE)
2073 hyperspace();
2074 /*maybe shield if it gets too hard */
2075 break;
2077 case (AST_FIRE_REP):
2078 case (AST_FIRE):
2079 if(game_state == ATTRACT_MODE)
2081 current_level = START_LEVEL;
2082 initialise_ship();
2083 initialise_game(current_level);
2084 show_level_timeout = SHOW_LEVEL_TIME;
2085 game_state = PLAY_MODE;
2087 else if(game_state == PLAY_MODE)
2089 if(!next_missile_count)
2091 fire_missile();
2092 next_missile_count = 10;
2095 else if(game_state == PAUSE_MODE)
2097 game_state = PLAY_MODE;
2099 break;
2101 default:
2102 if (rb->default_event_handler(button)==SYS_USB_CONNECTED)
2103 return PLUGIN_USB_CONNECTED;
2104 break;
2107 if(!num_lives)
2109 if(high_score < current_score)
2110 high_score = current_score;
2111 if(!show_game_over)
2112 break;
2115 if(next_missile_count)
2116 next_missile_count--;
2118 if(next_thrust_count)
2119 next_thrust_count--;
2121 if (end > *rb->current_tick)
2122 rb->sleep(end-*rb->current_tick);
2123 else
2124 rb->yield();
2130 enum plugin_status plugin_start(const void* parameter)
2132 enum plugin_status retval;
2133 (void)(parameter);
2135 game_state = ATTRACT_MODE;
2137 #if LCD_DEPTH > 1
2138 rb->lcd_set_backdrop(NULL);
2139 #endif
2140 /* universal font */
2141 rb->lcd_setfont(FONT_SYSFIXED);
2142 /* Turn off backlight timeout */
2143 backlight_force_on(); /* backlight control in lib/helper.c */
2144 iohiscore();
2145 retval = start_game();
2146 iohiscore();
2147 rb->lcd_setfont(FONT_UI);
2148 /* Turn on backlight timeout (revert to settings) */
2149 backlight_use_settings(); /* backlight control in lib/helper.c */
2150 return retval;