/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2006 by Mat Holton * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "plugin.h" #include "lib/display_text.h" #include "lib/helper.h" #include "lib/highscore.h" #include "lib/playback_control.h" PLUGIN_HEADER /* variable button definitions */ #if CONFIG_KEYPAD == RECORDER_PAD #define AST_PAUSE BUTTON_ON #define AST_QUIT BUTTON_OFF #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_LEFT #define AST_RIGHT BUTTON_RIGHT #define AST_FIRE BUTTON_PLAY #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD #define AST_PAUSE BUTTON_ON #define AST_QUIT BUTTON_OFF #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_LEFT #define AST_RIGHT BUTTON_RIGHT #define AST_FIRE BUTTON_SELECT #elif CONFIG_KEYPAD == ONDIO_PAD #define AST_PAUSE (BUTTON_MENU | BUTTON_OFF) #define AST_QUIT BUTTON_OFF #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_LEFT #define AST_RIGHT BUTTON_RIGHT #define AST_FIRE BUTTON_MENU #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ (CONFIG_KEYPAD == IRIVER_H300_PAD) #define AST_PAUSE BUTTON_REC #define AST_QUIT BUTTON_OFF #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_LEFT #define AST_RIGHT BUTTON_RIGHT #define AST_FIRE BUTTON_SELECT #define AST_RC_QUIT BUTTON_RC_STOP #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) #define AST_PAUSE BUTTON_PLAY #define AST_QUIT BUTTON_POWER #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_LEFT #define AST_RIGHT BUTTON_RIGHT #define AST_FIRE BUTTON_SELECT #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) #define AST_PAUSE (BUTTON_SELECT | BUTTON_PLAY) #define AST_QUIT (BUTTON_SELECT | BUTTON_MENU) #define AST_THRUST BUTTON_MENU #define AST_HYPERSPACE BUTTON_PLAY #define AST_LEFT BUTTON_SCROLL_BACK #define AST_RIGHT BUTTON_SCROLL_FWD #define AST_FIRE BUTTON_SELECT #elif (CONFIG_KEYPAD == GIGABEAT_PAD) #define AST_PAUSE BUTTON_A #define AST_QUIT BUTTON_POWER #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_LEFT #define AST_RIGHT BUTTON_RIGHT #define AST_FIRE BUTTON_SELECT #elif (CONFIG_KEYPAD == SANSA_E200_PAD) #define AST_PAUSE BUTTON_REC #define AST_QUIT BUTTON_POWER #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_SCROLL_BACK #define AST_RIGHT BUTTON_SCROLL_FWD #define AST_FIRE BUTTON_SELECT #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD) #define AST_PAUSE (BUTTON_SELECT | BUTTON_UP) #define AST_QUIT (BUTTON_HOME|BUTTON_REPEAT) #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_SCROLL_BACK #define AST_RIGHT BUTTON_SCROLL_FWD #define AST_FIRE BUTTON_SELECT #elif (CONFIG_KEYPAD == SANSA_C200_PAD) #define AST_PAUSE BUTTON_REC #define AST_QUIT BUTTON_POWER #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_LEFT #define AST_RIGHT BUTTON_RIGHT #define AST_FIRE BUTTON_SELECT #elif (CONFIG_KEYPAD == SANSA_CLIP_PAD) #define AST_PAUSE BUTTON_HOME #define AST_QUIT BUTTON_POWER #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_LEFT #define AST_RIGHT BUTTON_RIGHT #define AST_FIRE BUTTON_SELECT #elif (CONFIG_KEYPAD == SANSA_M200_PAD) #define AST_PAUSE (BUTTON_SELECT | BUTTON_UP) #define AST_QUIT BUTTON_POWER #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_LEFT #define AST_RIGHT BUTTON_RIGHT #define AST_FIRE (BUTTON_SELECT | BUTTON_REL) #elif (CONFIG_KEYPAD == IRIVER_H10_PAD) #define AST_PAUSE BUTTON_PLAY #define AST_QUIT BUTTON_POWER #define AST_THRUST BUTTON_SCROLL_UP #define AST_HYPERSPACE BUTTON_SCROLL_DOWN #define AST_LEFT BUTTON_LEFT #define AST_RIGHT BUTTON_RIGHT #define AST_FIRE BUTTON_REW #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) #define AST_PAUSE BUTTON_PLAY #define AST_QUIT BUTTON_BACK #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_LEFT #define AST_RIGHT BUTTON_RIGHT #define AST_FIRE BUTTON_SELECT #elif (CONFIG_KEYPAD == MROBE100_PAD) #define AST_PAUSE BUTTON_DISPLAY #define AST_QUIT BUTTON_POWER #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_LEFT #define AST_RIGHT BUTTON_RIGHT #define AST_FIRE BUTTON_SELECT #elif CONFIG_KEYPAD == IAUDIO_M3_PAD #define AST_PAUSE BUTTON_RC_PLAY #define AST_QUIT BUTTON_RC_REC #define AST_THRUST BUTTON_RC_VOL_UP #define AST_HYPERSPACE BUTTON_RC_VOL_DOWN #define AST_LEFT BUTTON_RC_REW #define AST_RIGHT BUTTON_RC_FF #define AST_FIRE BUTTON_RC_MODE #elif (CONFIG_KEYPAD == COWOND2_PAD) #define AST_QUIT BUTTON_POWER #elif CONFIG_KEYPAD == CREATIVEZVM_PAD #define AST_PAUSE BUTTON_PLAY #define AST_QUIT BUTTON_BACK #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_LEFT #define AST_RIGHT BUTTON_RIGHT #define AST_FIRE BUTTON_SELECT #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD #define AST_PAUSE BUTTON_VIEW #define AST_QUIT BUTTON_POWER #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_LEFT #define AST_RIGHT BUTTON_RIGHT #define AST_FIRE BUTTON_PLAYLIST #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD #define AST_PAUSE BUTTON_RIGHT #define AST_QUIT BUTTON_POWER #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_PREV #define AST_RIGHT BUTTON_NEXT #define AST_FIRE BUTTON_LEFT #elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \ (CONFIG_KEYPAD == ONDAVX777_PAD) || \ CONFIG_KEYPAD == MROBE500_PAD #define AST_QUIT BUTTON_POWER #elif (CONFIG_KEYPAD == SAMSUNG_YH_PAD) #define AST_PAUSE BUTTON_FFWD #define AST_QUIT BUTTON_REC #define AST_THRUST_REP (BUTTON_UP | BUTTON_REW) #define AST_THRUST BUTTON_UP #define AST_HYPERSPACE BUTTON_DOWN #define AST_LEFT BUTTON_LEFT #define AST_LEFT_REP (BUTTON_LEFT | BUTTON_REW) #define AST_RIGHT BUTTON_RIGHT #define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REW) #define AST_FIRE BUTTON_PLAY #define AST_FIRE_REP (BUTTON_PLAY | BUTTON_REW) #else #error No keymap defined! #endif #ifdef HAVE_TOUCHSCREEN #ifndef AST_PAUSE #define AST_PAUSE BUTTON_CENTER #endif #ifndef AST_QUIT #define AST_QUIT BUTTON_TOPLEFT #endif #ifndef AST_THRUST_REP #define AST_THRUST_REP (BUTTON_TOPMIDDLE | BUTTON_REPEAT) #endif #ifndef AST_THRUST #define AST_THRUST BUTTON_TOPMIDDLE #endif #ifndef AST_HYPERSPACE #define AST_HYPERSPACE BUTTON_TOPRIGHT #endif #ifndef AST_LEFT #define AST_LEFT BUTTON_MIDLEFT #endif #ifndef AST_LEFT_REP #define AST_LEFT_REP (BUTTON_MIDLEFT | BUTTON_REPEAT) #endif #ifndef AST_RIGHT #define AST_RIGHT BUTTON_MIDRIGHT #endif #ifndef AST_RIGHT_REP #define AST_RIGHT_REP (BUTTON_MIDRIGHT | BUTTON_REPEAT) #endif #ifndef AST_FIRE #define AST_FIRE BUTTON_BOTTOMMIDDLE #endif #ifndef AST_FIRE_REP #ifdef BUTTON_MENU #define AST_FIRE_REP (BUTTON_BOTTOMMIDDLE | BUTTON_MENU) #else #define AST_FIRE_REP BUTTON_BOTTOMMIDDLE | BUTTON_REPEAT #endif #endif #endif #define RES MAX(LCD_WIDTH, LCD_HEIGHT) #define LARGE_LCD (RES >= 200) #define CYCLETIME 30 #define SHOW_COL 0 #define SCALE 5000 #define MISSILE_SCALE 5000 #define WRAP_GAP 12 #define POINT_SIZE 2 #define SHOW_GAME_OVER_TIME 100 #define SHOW_LEVEL_TIME 50 #define EXPLOSION_LENGTH 20 #define MAX_NUM_ASTEROIDS 25 #define MAX_NUM_MISSILES 6 #define MAX_LEVEL MAX_NUM_ASTEROIDS #define NUM_STARS 50 #define NUM_TRAIL_POINTS 70 #define NUM_ROTATIONS 16 #define NUM_ASTEROID_VERTICES 10 #define NUM_SHIP_VERTICES 4 #define NUM_ENEMY_VERTICES 6 #define SPAWN_TIME 30 #define BLINK_TIME 10 #define EXTRA_LIFE 250 #define START_LIVES 3 #define START_LEVEL 1 #define MISSILE_SURVIVAL_LENGTH 40 #define ASTEROID_SPEED (RES/20) #define SPACE_CHECK_SIZE 30*SCALE #define LITTLE_SHIP 2 #define BIG_SHIP 1 #define ENEMY_BIG_PROBABILITY_START 10 #define ENEMY_APPEAR_PROBABILITY_START 35 #define ENEMY_APPEAR_TIMING_START 1800 #define ENEMY_SPEED 4 #define ENEMY_MISSILE_SURVIVAL_LENGTH (RES/2) #define SIZE_ENEMY_COLLISION 5*SCALE #define SIN_COS_SCALE 10000 #define FAST_ROT_CW_SIN 873 #define FAST_ROT_CW_COS 9963 #define FAST_ROT_ACW_SIN -873 #define FAST_ROT_ACW_COS 9963 #define MEDIUM_ROT_CW_SIN 350 #define MEDIUM_ROT_CW_COS 9994 #define MEDIUM_ROT_ACW_SIN -350 #define MEDIUM_ROT_ACW_COS 9994 #define SLOW_ROT_CW_SIN 350 #define SLOW_ROT_CW_COS 9994 #define SLOW_ROT_ACW_SIN -350 #define SLOW_ROT_ACW_COS 9994 #ifdef HAVE_LCD_COLOR #define SHIP_ROT_CW_SIN 2419 #define SHIP_ROT_CW_COS 9702 #define SHIP_ROT_ACW_SIN -2419 #define SHIP_ROT_ACW_COS 9702 #else #define SHIP_ROT_CW_SIN 3827 #define SHIP_ROT_CW_COS 9239 #define SHIP_ROT_ACW_SIN -3827 #define SHIP_ROT_ACW_COS 9239 #endif #define SCALED_WIDTH (LCD_WIDTH*SCALE) #define SCALED_HEIGHT (LCD_HEIGHT*SCALE) #define CENTER_LCD_X (LCD_WIDTH/2) #define CENTER_LCD_Y (LCD_HEIGHT/2) #define SHIP_EXPLOSION_COLOUR 1 #define ASTEROID_EXPLOSION_COLOUR 2 #define ENEMY_EXPLOSION_COLOUR 3 #define THRUST_COLOUR 4 #ifdef HAVE_LCD_COLOR #define ASTEROID_R 230 #define ASTEROID_G 200 #define ASTEROID_B 100 #define SHIP_R 255 #define SHIP_G 255 #define SHIP_B 255 #define ENEMY_R 50 #define ENEMY_G 220 #define ENEMY_B 50 #define THRUST_R 200 #define THRUST_G 200 #define THRUST_B 0 #define COL_MISSILE LCD_RGBPACK(200,0,0) #define COL_PLAYER LCD_RGBPACK(200,200,200) #define COL_INVULN LCD_RGBPACK(100,100,200) #define COL_STARS LCD_WHITE #define COL_ASTEROID LCD_RGBPACK(ASTEROID_R,ASTEROID_G,ASTEROID_B) #define COL_TEXT LCD_RGBPACK(200,200,255) #define COL_ENEMY LCD_RGBPACK(ENEMY_R,ENEMY_G,ENEMY_B) #define SET_FG rb->lcd_set_foreground #define SET_BG rb->lcd_set_background #else #define SET_FG(x) #define SET_BG(x) #endif #define HIGH_SCORE PLUGIN_GAMES_DIR "/spacerocks.score" #define NUM_SCORES 5 struct highscore highscores[NUM_SCORES]; /* The array of points that make up an asteroid */ static const short asteroid_one[NUM_ASTEROID_VERTICES*2] = { -2, -12, 4, -8, 8, -14, 16, -5, 14, 0, 20, 2, 12, 14, -4, 14, -10, 6, -10, -8, }; /* The array of points that make up an asteroid */ static const short asteroid_two[NUM_ASTEROID_VERTICES*2] = { -2, -12, 4, -16, 6, -14, 16, -8, 14, 0, 20, 2, 12, 14, -4, 14, -10, 6, -10, -8, }; /* The array of points that make up an asteroid */ static const short asteroid_three[NUM_ASTEROID_VERTICES*2] = { -2, -12, 4, -16, 6, -14, 2, -8, 14, 0, 20, 2, 12, 14, -4, 14, -16, 6, -10, -8, }; /* The array od points the make up the ship */ static const short ship_vertices[NUM_SHIP_VERTICES*2] = { #if (LARGE_LCD) 0, -6, 4, 6, 0, 2, -4, 6, #else 0, -4, 3, 4, 0, 1, -3, 4, #endif }; /* The array of points the make up the bad spaceship */ static const short enemy_vertices[NUM_ENEMY_VERTICES*2] = { #if (LARGE_LCD) -8, 0, -4, 4, 4, 4, 8, 0, 4, -4, -4, -4, #else -5, 0, -2, 2, 2, 2, 5, 0, 2, -2, -2, -2, #endif }; enum asteroid_type { #if (LARGE_LCD) SMALL = 2, MEDIUM = 4, LARGE = 6, #else SMALL = 1, MEDIUM = 2, LARGE = 3, #endif }; enum game_state { GAME_OVER, SHOW_LEVEL, PLAY_MODE, PAUSE_MODE, }; struct Point { int x; int y; int dx; int dy; }; struct TrailPoint { int alive; struct Point position; #ifdef HAVE_LCD_COLOR short r; short g; short b; short dec; #endif }; /* Asteroid structure, contains an array of points */ struct Asteroid { struct Point position; struct Point vertices[NUM_ASTEROID_VERTICES]; bool exists; int explode_countdown; enum asteroid_type type; int radius; long speed_cos; long speed_sin; }; struct Ship { struct Point vertices[NUM_SHIP_VERTICES]; struct Point position; bool waiting_for_space; int explode_countdown; bool invulnerable; int spawn_time; }; struct Enemy { struct Point vertices[NUM_ENEMY_VERTICES]; struct Point position; bool exists; int explode_countdown; long last_time_appeared; short size_probability; short appear_probability; short appear_timing; }; struct Missile { struct Point position; struct Point oldpoint; int survived; }; static enum game_state game_state; static int asteroid_count; static int next_missile_count; static int next_thrust_count; static int num_lives; static int extra_life; static int show_level_timeout; static int current_level; static int current_score; static struct Ship ship; static struct Point stars[NUM_STARS]; static struct Asteroid asteroids_array[MAX_NUM_ASTEROIDS]; static struct Missile missiles_array[MAX_NUM_MISSILES]; static struct Missile enemy_missile; static struct Enemy enemy; static struct Point lives_points[NUM_SHIP_VERTICES]; static struct TrailPoint trail_points[NUM_TRAIL_POINTS]; void draw_and_move_asteroids(void); void initialise_game(int nStartNum); bool is_asteroid_near_ship(struct Asteroid* asteroid); bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point); void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type eType); void draw_polygon(struct Point* vertices, int px, int py, int num_vertices); void rotate_asteroid(struct Asteroid* asteroid); void create_asteroid(enum asteroid_type type, int x, int y); void create_stars(void); void initialise_ship(void); void draw_and_move_ship(void); void rotate_ship(int c, int s); void thrust_ship(void); void initialise_missile(struct Missile* missile); void draw_and_move_missiles(void); void fire_missile(void); void animate_and_draw_explosion(struct Point* point, int num_points, int xoffset, int yoffset); void initialise_explosion(struct Point* point, int num_points); void move_point(struct Point* point); void hyperspace(void); void check_collisions(void); void initialise_enemy(void); void draw_and_move_enemy(void); void draw_lives(void); void drawstars(void); bool is_ship_within_asteroid(struct Asteroid* asteroid); void init(void) { enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START; enemy.appear_timing = ENEMY_APPEAR_TIMING_START; enemy.size_probability = ENEMY_BIG_PROBABILITY_START; current_level = START_LEVEL; num_lives = START_LIVES; extra_life = EXTRA_LIFE; current_score = 0; initialise_ship(); initialise_game(current_level); show_level_timeout = SHOW_LEVEL_TIME; game_state = PLAY_MODE; } static bool spacerocks_help(void) { static char *help_text[] = { "Spacerocks", "", "Aim", "", "The", "goal", "of", "the", "game", "is", "to", "blow", "up", "the", "asteroids", "and", "avoid", "being", "hit", "by", "them.", "Also", "you'd", "better", "watch", "out", "for", "the", "UFOs!" }; static struct style_text formation[]={ { 0, TEXT_CENTER|TEXT_UNDERLINE }, { 2, C_RED }, { -1, 0 } }; int button; rb->lcd_setfont(FONT_UI); #ifdef HAVE_LCD_COLOR rb->lcd_set_background(LCD_BLACK); rb->lcd_set_foreground(LCD_WHITE); #endif if (display_text(ARRAYLEN(help_text), help_text, formation, NULL) ==PLUGIN_USB_CONNECTED) return true; do { button = rb->button_get(true); if (button == SYS_USB_CONNECTED) return true; } while( ( button == BUTTON_NONE ) || ( button & (BUTTON_REL|BUTTON_REPEAT) ) ); rb->lcd_setfont(FONT_SYSFIXED); return false; } static bool _ingame; static int spacerocks_menu_cb(int action, const struct menu_item_ex *this_item) { if(action == ACTION_REQUEST_MENUITEM && !_ingame && ((intptr_t)this_item)==0) return ACTION_EXIT_MENUITEM; return action; } static int spacerocks_menu(bool ingame) { int choice = 0; _ingame = ingame; MENUITEM_STRINGLIST(main_menu, "Spacerocks Menu", spacerocks_menu_cb, "Resume Game", "Start New Game", "Help", "High Scores", "Playback Control", "Quit"); rb->button_clear_queue(); while (1) { switch (rb->do_menu(&main_menu, &choice, NULL, false)) { case 0: return 0; case 1: init(); return 0; case 2: if(spacerocks_help()) return 1; break; case 3: highscore_show(NUM_SCORES, highscores, NUM_SCORES, true); break; case 4: playback_control(NULL); break; case 5: return 1; case MENU_ATTACHED_USB: return 1; default: break; } } } bool point_in_poly(struct Point* point, int num_vertices, int x, int y) { struct Point* pi; struct Point* pj; int n; bool c = false; pi = point; pj = point + num_vertices-1; n = num_vertices; while(n--) { if((((pi->y <= y) && (y < pj->y)) || ((pj->y <= y) && (y < pi->y))) && (x < (pj->x - pi->x) * (y - pi->y) / (pj->y - pi->y) + pi->x)) c = !c; pj = pi; pi++; } return c; } void move_point(struct Point* point) { point->x += point->dx; point->y += point->dy; /*check bounds on the x-axis:*/ point->x %= SCALED_WIDTH; if(point->x < 0) point->x += SCALED_WIDTH; /*Check bounds on the y-axis:*/ point->y %= SCALED_HEIGHT; if(point->y < 0) point->y += SCALED_HEIGHT; } void create_ship_trail(struct TrailPoint* tpoint) { tpoint->position.dx = -( ship.vertices[0].x - ship.vertices[2].x )/10; tpoint->position.dy = -( ship.vertices[0].y - ship.vertices[2].y )/10; } void create_explosion_trail(struct TrailPoint* tpoint) { tpoint->position.dx = (rb->rand()%5001)-2500; tpoint->position.dy = (rb->rand()%5001)-2500; } void create_trail_blaze(int colour, struct Point* position) { int numtoadd; struct TrailPoint* tpoint; int n; if(colour != SHIP_EXPLOSION_COLOUR) { numtoadd = NUM_TRAIL_POINTS/5; } else { numtoadd = NUM_TRAIL_POINTS/8; } /* give the point a random countdown timer, so they dissapears at different times */ tpoint = trail_points; n = NUM_TRAIL_POINTS; while(n-- && numtoadd) { /* find a space in the array of trail_points that is NULL or DEAD or whatever and place this one here. */ if(tpoint->alive <= 0) { numtoadd--; /* take a random x point anywhere between bottom two points of ship. */ /* ship.position.x; */ tpoint->position.x = (ship.vertices[2].x + (rb->rand()%18000)-9000) + position->x; tpoint->position.y = (ship.vertices[2].y + (rb->rand()%18000)-9000) + position->y; switch(colour) { case SHIP_EXPLOSION_COLOUR: create_explosion_trail(tpoint); tpoint->alive = 510; #ifdef HAVE_LCD_COLOR tpoint->r = SHIP_R; tpoint->g = SHIP_G; tpoint->b = SHIP_B; tpoint->dec = 2; #endif break; case ASTEROID_EXPLOSION_COLOUR: create_explosion_trail(tpoint); tpoint->alive = 510; #ifdef HAVE_LCD_COLOR tpoint->r = ASTEROID_R; tpoint->g = ASTEROID_G; tpoint->b = ASTEROID_B; tpoint->dec = 2; #endif break; case ENEMY_EXPLOSION_COLOUR: create_explosion_trail(tpoint); tpoint->alive = 510; #ifdef HAVE_LCD_COLOR tpoint->r = ENEMY_R; tpoint->g = ENEMY_G; tpoint->b = ENEMY_B; tpoint->dec = 2; #endif break; case THRUST_COLOUR: create_ship_trail(tpoint); tpoint->alive = 175; #ifdef HAVE_LCD_COLOR tpoint->r = THRUST_R; tpoint->g = THRUST_G; tpoint->b = THRUST_B; tpoint->dec = 4; #endif break; } /* give the points a speed based on direction of travel - i.e. opposite */ tpoint->position.dx += position->dx; tpoint->position.dy += position->dy; } tpoint++; } } void draw_trail_blaze(void) { struct TrailPoint* tpoint; int n; /* loop through, if alive then move and draw. when drawn, countdown it's timer. if zero kill it! */ tpoint = trail_points; n = NUM_TRAIL_POINTS; while(n--) { if(tpoint->alive) { if(game_state != PAUSE_MODE) { tpoint->alive -= 10; move_point(&(tpoint->position)); } #ifdef HAVE_LCD_COLOR /* intensity = tpoint->alive/2; */ if(tpoint->r >= tpoint->dec) tpoint->r -= tpoint->dec; if(tpoint->g >= tpoint->dec) tpoint->g -= tpoint->dec; if(tpoint->b >= tpoint->dec) tpoint->b -= tpoint->dec; SET_FG(LCD_RGBPACK(tpoint->r, tpoint->g, tpoint->b)); #endif rb->lcd_drawpixel(tpoint->position.x/SCALE, tpoint->position.y/SCALE); } tpoint++; } } /*Check if point is within a rectangle*/ bool is_point_within_rectangle(struct Point* rect, struct Point* p, int size) { #if SHOW_COL int aTLx = rect->x - size; int aTLy = rect->y - size; int aBRx = rect->x + size; int aBRy = rect->y + size; rb->lcd_hline( aTLx/SCALE, aBRx/SCALE, aTLy/SCALE); rb->lcd_vline( aTLx/SCALE, aTLy/SCALE, aBRy/SCALE); rb->lcd_hline( aTLx/SCALE, aBRx/SCALE, aBRy/SCALE); rb->lcd_vline( aBRx/SCALE, aBRy/SCALE, aTLy/SCALE); return (p->x > aTLx && p->x < aBRx && p->y > aTLy && p->y < aBRy); #else return (p->x > rect->x - size && p->x < rect->x + size && p->y > rect->y - size && p->y < rect->y + size); #endif } /* Draw polygon */ void draw_polygon(struct Point* vertices, int px, int py, int num_vertices) { int n, t1, t2, oldX, oldY; struct Point *p; bool bDrawAll = px < WRAP_GAP || LCD_WIDTH - px < WRAP_GAP || py < WRAP_GAP || LCD_HEIGHT - py < WRAP_GAP; p = vertices + num_vertices - 1; oldX = p->x/SCALE + px; oldY = p->y/SCALE + py; p = vertices; n = num_vertices; while(n--) { t1 = p->x/SCALE + px; t2 = p->y/SCALE + py; rb->lcd_drawline(oldX, oldY, t1, t2); if(bDrawAll) { rb->lcd_drawline(oldX - LCD_WIDTH, oldY, t1 - LCD_WIDTH, t2); rb->lcd_drawline(oldX + LCD_WIDTH, oldY, t1 + LCD_WIDTH, t2); rb->lcd_drawline(oldX - LCD_WIDTH, oldY + LCD_HEIGHT, t1 - LCD_WIDTH, t2 + LCD_HEIGHT); rb->lcd_drawline(oldX + LCD_WIDTH, oldY + LCD_HEIGHT, t1 + LCD_WIDTH, t2 + LCD_HEIGHT); rb->lcd_drawline(oldX, oldY - LCD_HEIGHT, t1, t2 - LCD_HEIGHT); rb->lcd_drawline(oldX, oldY + LCD_HEIGHT, t1, t2 + LCD_HEIGHT); rb->lcd_drawline(oldX - LCD_WIDTH, oldY - LCD_HEIGHT, t1 - LCD_WIDTH, t2 - LCD_HEIGHT); rb->lcd_drawline(oldX + LCD_WIDTH, oldY - LCD_HEIGHT, t1 + LCD_WIDTH, t2 - LCD_HEIGHT); } oldX = t1; oldY = t2; p++; } } void animate_and_draw_explosion(struct Point* point, int num_points, int xoffset, int yoffset) { int n = num_points; while(n--) { if(game_state != PAUSE_MODE) { point->x += point->dx; point->y += point->dy; } rb->lcd_fillrect( point->x/SCALE + xoffset, point->y/SCALE + yoffset, POINT_SIZE, POINT_SIZE ); point++; } } /*stop movement of ship, 'cos that's what happens when you go into hyperspace.*/ void hyperspace(void) { ship.position.dx = ship.position.dy = 0; ship.position.x = (rb->rand()%SCALED_WIDTH); ship.position.y = (rb->rand()%SCALED_HEIGHT); } void initialise_enemy(void) { struct Point* point; int n; int size; if(rb->rand()%100 > enemy.size_probability) { size = BIG_SHIP; enemy.size_probability++; if(enemy.size_probability > 90) { enemy.size_probability = ENEMY_BIG_PROBABILITY_START; } } else { size = LITTLE_SHIP; enemy.size_probability = ENEMY_BIG_PROBABILITY_START; } enemy_missile.survived = 0; enemy.exists = true; enemy.explode_countdown = 0; enemy.last_time_appeared = *rb->current_tick; point = enemy.vertices; for(n = 0; n < NUM_ENEMY_VERTICES*2; n += 2) { point->x = enemy_vertices[n]; point->y = enemy_vertices[n+1]; point->x *= SCALE/size; point->y *= SCALE/size; point++; } if(ship.position.x >= SCALED_WIDTH/2) { enemy.position.dx = ENEMY_SPEED; enemy.position.x = 0; } else { enemy.position.dx = -ENEMY_SPEED; enemy.position.x = SCALED_WIDTH; } if(ship.position.y >= SCALED_HEIGHT/2) { enemy.position.dy = ENEMY_SPEED; enemy.position.y = 0; } else { enemy.position.dy = -ENEMY_SPEED; enemy.position.y = SCALED_HEIGHT; } enemy.position.dx *= SCALE/10; enemy.position.dy *= SCALE/10; } void draw_and_move_enemy(void) { int enemy_x, enemy_y; SET_FG(COL_ENEMY); if(enemy.exists) { enemy_x = enemy.position.x/SCALE; enemy_y = enemy.position.y/SCALE; if(!enemy.explode_countdown) { draw_polygon(enemy.vertices, enemy_x, enemy_y, NUM_ENEMY_VERTICES); rb->lcd_drawline(enemy.vertices[0].x/SCALE + enemy_x, enemy.vertices[0].y/SCALE + enemy_y, enemy.vertices[3].x/SCALE + enemy_x, enemy.vertices[3].y/SCALE + enemy_y); if(game_state != PAUSE_MODE) { enemy.position.x += enemy.position.dx; enemy.position.y += enemy.position.dy; if(enemy.position.x > SCALED_WIDTH || enemy.position.x < 0) enemy.exists = false; if(enemy.position.y > SCALED_HEIGHT) enemy.position.y = 0; else if(enemy.position.y < 0) enemy.position.y = SCALED_HEIGHT; if((rb->rand()%1000) < 10) enemy.position.dy = -enemy.position.dy; } } else { /* animate_and_draw_explosion(enemy.vertices, NUM_ENEMY_VERTICES, enemy_x, enemy.position.y/SCALE); */ if(game_state != PAUSE_MODE) { enemy.explode_countdown--; if(!enemy.explode_countdown) enemy.exists = false; } } } else { if (TIME_AFTER(*rb->current_tick, enemy.last_time_appeared+enemy.appear_timing)) { if(rb->rand()%100 >= enemy.appear_probability) initialise_enemy(); } } if(!enemy_missile.survived) { /*if no missile and the enemy is here and not exploding..then shoot baby!*/ if( !enemy.explode_countdown && enemy.exists && !ship.waiting_for_space && game_state == PLAY_MODE && (rb->rand()%10) >= 5 ) { enemy_missile.position.x = enemy.position.x; enemy_missile.position.y = enemy.position.y; /*lame, needs to be sorted - it's trying to shoot at the ship*/ if(ABS(enemy.position.y - ship.position.y) <= 5*SCALE) enemy_missile.position.dy = 0; else if( enemy.position.y < ship.position.y) enemy_missile.position.dy = 1; else enemy_missile.position.dy = -1; if(ABS(enemy.position.x - ship.position.x) <= 5*SCALE) enemy_missile.position.dx = 0; else if( enemy.position.x < ship.position.x) enemy_missile.position.dx = 1; else enemy_missile.position.dx = -1; while(enemy_missile.position.dx == 0 && enemy_missile.position.dy == 0) { enemy_missile.position.dx = rb->rand()%2-1; enemy_missile.position.dy = rb->rand()%2-1; } enemy_missile.position.dx *= SCALE; enemy_missile.position.dy *= SCALE; enemy_missile.survived = ENEMY_MISSILE_SURVIVAL_LENGTH; } } else { rb->lcd_fillrect( enemy_missile.position.x/SCALE, enemy_missile.position.y/SCALE, POINT_SIZE, POINT_SIZE ); if(game_state != PAUSE_MODE) { move_point(&enemy_missile.position); enemy_missile.survived--; } } } void add_score(int val) { current_score += val; if(current_score >= extra_life) { num_lives++; extra_life += EXTRA_LIFE; } } bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point) { if(!is_point_within_rectangle(&asteroid->position, point, asteroid->radius)) return false; if(point_in_poly(asteroid->vertices, NUM_ASTEROID_VERTICES, point->x - asteroid->position.x, point->y - asteroid->position.y)) { struct Point p; p.dx = asteroid->position.dx; p.dy = asteroid->position.dy; p.x = asteroid->position.x; p.y = asteroid->position.y; asteroid_count--; asteroid->exists = false; switch(asteroid->type) { case SMALL: asteroid->explode_countdown = EXPLOSION_LENGTH; create_trail_blaze(ASTEROID_EXPLOSION_COLOUR, &p); break; case MEDIUM: create_asteroid(SMALL, p.x, p.y); create_asteroid(SMALL, p.x, p.y); break; case LARGE: create_asteroid(MEDIUM, p.x, p.y); create_asteroid(MEDIUM, p.x, p.y); break; } return true; } else return false; } bool is_point_within_enemy(struct Point* point) { if( is_point_within_rectangle(&enemy.position, point, 7*SCALE) ) { add_score(5); /* enemy_missile.survived = 0; */ enemy.explode_countdown = EXPLOSION_LENGTH; /* initialise_explosion(enemy.vertices, NUM_ENEMY_VERTICES); */ create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position); return true; } else return false; } bool is_ship_within_asteroid(struct Asteroid* asteroid) { struct Point p; p.x = ship.position.x + ship.vertices[0].x; p.y = ship.position.y + ship.vertices[0].y; if(is_point_within_asteroid(asteroid, &p)) return true; p.x = ship.position.x + ship.vertices[1].x; p.y = ship.position.y + ship.vertices[1].y; if(is_point_within_asteroid(asteroid, &p)) return true; p.x = ship.position.x + ship.vertices[3].x; p.y = ship.position.y + ship.vertices[3].y; if(is_point_within_asteroid(asteroid, &p)) return true; return false; } void initialise_explosion(struct Point* point, int num_points) { int n; point->x += point->dx; point->y += point->dy; n = num_points; while(n--) { point->dx = point->x; point->dy = point->y; point++; } } /* Check for collsions between the missiles and the asteroids and the ship */ void check_collisions(void) { struct Missile* missile; struct Asteroid* asteroid; int m, n; bool asteroids_onscreen = false; bool ship_cant_be_placed = false; asteroid = asteroids_array; m = MAX_NUM_ASTEROIDS; while(m--) { /*if the asteroids exists then test missile collision:*/ if (asteroid->exists) { missile = missiles_array; n = MAX_NUM_MISSILES; while(n--) { /*if the missiles exists:*/ if(missile->survived > 0) { /*has the missile hit the asteroid?*/ if(is_point_within_asteroid(asteroid, &missile->position) || is_point_within_asteroid(asteroid, &missile->oldpoint)) { add_score(1); missile->survived = 0; break; } } missile++; } /*now check collision with ship:*/ if (asteroid->exists && !ship.waiting_for_space && !ship.explode_countdown) { if (is_ship_within_asteroid(asteroid)) { add_score(1); if (!ship.invulnerable) { /*if not invulnerable, blow up ship*/ ship.explode_countdown = EXPLOSION_LENGTH; /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */ create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position); } } /*has the enemy missile blown something up?*/ if (asteroid->exists && enemy_missile.survived) { if(is_point_within_asteroid(asteroid, &enemy_missile.position)) { enemy_missile.survived = 0; } /*if it still exists, check if ship is waiting for space:*/ if (asteroid->exists && ship.waiting_for_space) { ship_cant_be_placed |= is_point_within_rectangle(&ship.position, &asteroid->position, SPACE_CHECK_SIZE); } } } } /*is an asteroid still exploding?*/ if (asteroid->explode_countdown) asteroids_onscreen = true; asteroid++; } /*now check collision between ship and enemy*/ if(enemy.exists && !enemy.explode_countdown && !ship.waiting_for_space && !ship.explode_countdown) { /*has the enemy collided with the ship?*/ if(is_point_within_enemy(&ship.position)) { if (!ship.invulnerable) { ship.explode_countdown = EXPLOSION_LENGTH; /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */ create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position); } create_trail_blaze(ENEMY_EXPLOSION_COLOUR, &enemy.position); } if (enemy.exists && !enemy.explode_countdown) { /*Now see if the enemy has been shot at by the ships missiles:*/ missile = missiles_array; n = MAX_NUM_MISSILES; while(n--) { if (missile->survived > 0 && is_point_within_enemy(&missile->position)) { missile->survived = 0; break; } missile++; } } } /*test collision with enemy missile and ship:*/ if (!ship_cant_be_placed && enemy_missile.survived > 0 && point_in_poly(ship.vertices, NUM_SHIP_VERTICES, enemy_missile.position.x - ship.position.x, enemy_missile.position.y - ship.position.y)) { if (!ship.invulnerable) { ship.explode_countdown = EXPLOSION_LENGTH; /* initialise_explosion(ship.vertices, NUM_SHIP_VERTICES); */ create_trail_blaze(SHIP_EXPLOSION_COLOUR, &ship.position); } enemy_missile.survived = 0; enemy_missile.position.x = enemy_missile.position.y = 0; } if(!ship_cant_be_placed) ship.waiting_for_space = false; /*if all asteroids cleared then start again:*/ if(asteroid_count == 0 && !enemy.exists && !asteroids_onscreen) { current_level++; game_state = SHOW_LEVEL; enemy.appear_probability += 5; enemy.appear_timing -= 200; if (enemy.appear_probability >= 100) enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START; show_level_timeout = SHOW_LEVEL_TIME; } } /************************************************* ** Creates a new asteroid of the given 4type (size) ** and at the given location. *************************************************/ void create_asteroid(enum asteroid_type type, int x, int y) { struct Asteroid* asteroid; int n; asteroid = asteroids_array; n = MAX_NUM_ASTEROIDS; while(n--) { if(!asteroid->exists && !asteroid->explode_countdown) { initialise_asteroid(asteroid, type); asteroid->position.x = x; asteroid->position.y = y; break; } asteroid++; } } /* Initialise a missile */ void initialise_missile(struct Missile* missile) { missile->position.x = ship.position.x + ship.vertices[0].x; missile->position.y = ship.position.y + ship.vertices[0].y; missile->position.dx = (ship.vertices[0].x - ship.vertices[2].x)/2; missile->position.dy = (ship.vertices[0].y - ship.vertices[2].y)/2; missile->survived = MISSILE_SURVIVAL_LENGTH; missile->oldpoint.x = missile->position.x; missile->oldpoint.y = missile->position.y; } /* Draw and Move all the missiles */ void draw_and_move_missiles(void) { struct Missile* missile; struct Point vertices[2]; int n; SET_FG(COL_MISSILE); missile = missiles_array; n = MAX_NUM_MISSILES; while(n--) { if(missile->survived) { vertices[0].x = 0; vertices[0].y = 0; vertices[1].x = -missile->position.dx; vertices[1].y = -missile->position.dy; draw_polygon(vertices, missile->position.x/SCALE, missile->position.y/SCALE, 2); if(game_state != PAUSE_MODE) { missile->oldpoint.x = missile->position.x; missile->oldpoint.y = missile->position.y; move_point(&missile->position); missile->survived--; } } missile++; } } void draw_lives(void) { int n; #if (LARGE_LCD) int px = (LCD_WIDTH-1 - 4); int py = (LCD_HEIGHT-1 - 6); #else int px = (LCD_WIDTH-1 - 3); int py = (LCD_HEIGHT-1 - 4); #endif SET_FG(COL_PLAYER); n = num_lives-1; while(n--) { draw_polygon(lives_points, px, py, NUM_SHIP_VERTICES); #if (LARGE_LCD) px -= 8; #else px -= 6; #endif } } /*Fire the next missile*/ void fire_missile(void) { struct Missile* missile; int n; if (!ship.explode_countdown && !ship.waiting_for_space) { missile = missiles_array; n = MAX_NUM_MISSILES; while(n--) { if(!missile->survived) { initialise_missile(missile); break; } missile++; } } } /* Initialise the passed Asteroid */ void initialise_asteroid(struct Asteroid* asteroid, enum asteroid_type type) { const short *asteroid_vertices; struct Point* point; int n; asteroid->exists = true; asteroid->type = type; asteroid->explode_countdown = 0; /*Set the radius of the asteroid:*/ asteroid->radius = (int)type*SCALE*3; /*shall we move Clockwise and Fast*/ n = rb->rand()%100; if(n < 25) { asteroid->speed_cos = FAST_ROT_CW_COS; asteroid->speed_sin = FAST_ROT_CW_SIN; } else if(n < 50) { asteroid->speed_cos = FAST_ROT_ACW_COS; asteroid->speed_sin = FAST_ROT_ACW_SIN; } else if(n < 75) { asteroid->speed_cos = SLOW_ROT_ACW_COS; asteroid->speed_sin = SLOW_ROT_ACW_SIN; } else { asteroid->speed_cos = SLOW_ROT_CW_COS; asteroid->speed_sin = SLOW_ROT_CW_SIN; } n = rb->rand()%99; if (n < 33) asteroid_vertices = asteroid_one; else if (n < 66) asteroid_vertices = asteroid_two; else asteroid_vertices = asteroid_three; point = asteroid->vertices; for(n = 0; n < NUM_ASTEROID_VERTICES*2; n += 2) { point->x = asteroid_vertices[n]; point->y = asteroid_vertices[n+1]; point->x *= asteroid->radius/20; point->y *= asteroid->radius/20; point++; } do { /*Set the position randomly:*/ asteroid->position.x = (rb->rand()%SCALED_WIDTH); asteroid->position.y = (rb->rand()%SCALED_HEIGHT); } while (is_point_within_rectangle(&ship.position, &asteroid->position, SPACE_CHECK_SIZE)); do { asteroid->position.dx = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2; } while (asteroid->position.dx == 0); do { asteroid->position.dy = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2; } while (asteroid->position.dy == 0); asteroid->position.dx *= SCALE/10; asteroid->position.dy *= SCALE/10; /*Now rotate the asteroid a bit, so they all look a bit different*/ for(n = (rb->rand()%30)+2; n--; ) rotate_asteroid(asteroid); /*great, we've created an asteroid, don't forget to increment the total:*/ asteroid_count++; } /*Initialise the ship*/ void initialise_ship(void) { struct Point* point; struct Point* lives_point; int n; ship.position.x = CENTER_LCD_X * SCALE; ship.position.y = CENTER_LCD_Y * SCALE; ship.position.dx = 0; ship.position.dy = 0; ship.explode_countdown = 0; ship.spawn_time = SPAWN_TIME; ship.invulnerable = 1; point = ship.vertices; lives_point = lives_points; for(n = 0; n < NUM_SHIP_VERTICES*2; n += 2) { point->x = ship_vertices[n]; point->y = ship_vertices[n+1]; point->x *= SCALE; point->y *= SCALE; /*grab a copy of the ships points for the lives display:*/ lives_point->x = point->x; lives_point->y = point->y; point++; lives_point++; } } void rotate_asteroid(struct Asteroid* asteroid) { struct Point* point; int n; long xtemp; point = asteroid->vertices; for(n = NUM_ASTEROID_VERTICES+1; --n;) { xtemp = point->x; point->x = xtemp*asteroid->speed_cos/SIN_COS_SCALE - point->y*asteroid->speed_sin/SIN_COS_SCALE; point->y = point->y*asteroid->speed_cos/SIN_COS_SCALE + xtemp*asteroid->speed_sin/SIN_COS_SCALE; point++; } } /************************************************* ** Draws the ship, moves the ship and creates a new ** one if it's finished exploding. **************************************************/ void draw_and_move_ship(void) { if (ship.invulnerable && (ship.spawn_time > BLINK_TIME || ship.spawn_time % 2 == 0)) { SET_FG(COL_INVULN); } else { SET_FG(COL_PLAYER); } if(!ship.explode_countdown) { /* make sure ship is invulnerable until spawn time over */ if (ship.spawn_time) { ship.spawn_time--; if (ship.spawn_time <= 0) { ship.invulnerable = 0; } } if(!ship.waiting_for_space) { draw_polygon(ship.vertices, ship.position.x/SCALE, ship.position.y/SCALE, NUM_SHIP_VERTICES); if(game_state != PAUSE_MODE && game_state != GAME_OVER) { move_point(&ship.position); } } } else { /* animate_and_draw_explosion(ship.vertices, NUM_SHIP_VERTICES, ship.position.x/SCALE, ship.position.y/SCALE); */ if(game_state != PAUSE_MODE) { ship.explode_countdown--; if(!ship.explode_countdown) { num_lives--; if(!num_lives) { game_state = GAME_OVER; } else { initialise_ship(); ship.waiting_for_space = true; } } } } } void thrust_ship(void) { if(!ship.waiting_for_space) { ship.position.dx += ( ship.vertices[0].x - ship.vertices[2].x )/20; ship.position.dy += ( ship.vertices[0].y - ship.vertices[2].y )/20; /*if dx and dy are below a certain threshold, then set 'em to 0 but to do this we need to ascertain if the spacehip as moved on screen for more than a certain amount. */ create_trail_blaze(THRUST_COLOUR, &ship.position); } } /************************************************** ** Rotate the ship using the passed sin & cos values ***************************************************/ void rotate_ship(int c, int s) { struct Point* point; int n; long xtemp; if(!ship.waiting_for_space && !ship.explode_countdown) { point = ship.vertices; for(n=NUM_SHIP_VERTICES+1;--n;) { xtemp = point->x; point->x = xtemp*c/SIN_COS_SCALE - point->y*s/SIN_COS_SCALE; point->y = point->y*c/SIN_COS_SCALE + xtemp*s/SIN_COS_SCALE; point++; } } } void drawstars() { struct Point* p; int n; SET_FG(COL_STARS); p = stars; n = NUM_STARS; while(n--) { rb->lcd_drawpixel(p->x , p->y); p++; } } /************************************************* ** Draw And Move all Asteroids *************************************************/ void draw_and_move_asteroids(void) { struct Asteroid* asteroid; int n; SET_FG(COL_ASTEROID); asteroid = asteroids_array; n = MAX_NUM_ASTEROIDS; while(n--) { if(game_state != PAUSE_MODE) { if(asteroid->exists) { move_point(&asteroid->position); rotate_asteroid(asteroid); draw_polygon(asteroid->vertices, asteroid->position.x/SCALE, asteroid->position.y/SCALE, NUM_ASTEROID_VERTICES); } else if(asteroid->explode_countdown) { /* animate_and_draw_explosion(asteroid->vertices, NUM_ASTEROID_VERTICES, asteroid->position.x/SCALE, asteroid->position.y/SCALE); */ asteroid->explode_countdown--; } } else { if(asteroid->exists) draw_polygon(asteroid->vertices, asteroid->position.x/SCALE, asteroid->position.y/SCALE, NUM_ASTEROID_VERTICES); } asteroid++; } } void create_stars(void) { struct TrailPoint* tpoint; struct Point* p; int n; p = stars; n = NUM_STARS; while(n--) { p->x = (rb->rand()%LCD_WIDTH); p->y = (rb->rand()%LCD_HEIGHT); p++; } tpoint = trail_points; n = NUM_TRAIL_POINTS; while(--n) { tpoint->alive = 0; tpoint++; } } /************************************************* ** Creates start_num number of new asteroids of ** full size. **************************************************/ void initialise_game(int start_num) { struct Asteroid* asteroid; struct Missile* missile; int n; asteroid_count = next_missile_count = next_thrust_count = 0; /*no enemy*/ enemy.exists = 0; enemy_missile.survived = 0; /*clear asteroids*/ asteroid = asteroids_array; n = MAX_NUM_ASTEROIDS; while(n--) { asteroid->exists = false; asteroid++; } /*make some LARGE asteroids*/ for(n = 0; n < start_num; n++) initialise_asteroid(&asteroids_array[n], LARGE); /*ensure all missiles are out of action: */ missile = missiles_array; n = MAX_NUM_MISSILES; while(--n) { missile->survived = 0; missile++; } } static int spacerocks_game_loop(void) { char s[20]; char level[10]; int button; int end; int position; /*create stars once, and once only:*/ create_stars(); if (spacerocks_menu(false)!=0) return 0; SET_BG(LCD_BLACK); while(true) { end = *rb->current_tick + (CYCLETIME * HZ) / 1000; rb->lcd_clear_display(); SET_FG(COL_TEXT); switch(game_state) { case GAME_OVER: rb->splash (HZ * 2, "Game Over"); rb->lcd_clear_display(); position = highscore_update(current_score, current_level, "", highscores, NUM_SCORES); if (position != -1) { if (position == 0) rb->splash(HZ*2, "New High Score"); highscore_show(position, highscores, NUM_SCORES, true); } if (spacerocks_menu(false)!=0) return 0; break; case PAUSE_MODE: rb->snprintf(s, sizeof(s), "score %d ", current_score); rb->lcd_putsxy(1,LCD_HEIGHT-8, s); rb->lcd_putsxy(CENTER_LCD_X - 15, CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "pause"); draw_and_move_missiles(); draw_lives(); draw_and_move_ship(); break; case PLAY_MODE: rb->snprintf(s, sizeof(s), "score %d ", current_score); rb->lcd_putsxy(1,LCD_HEIGHT-8, s); draw_and_move_missiles(); draw_lives(); check_collisions(); draw_and_move_ship(); break; case SHOW_LEVEL: rb->snprintf(s, sizeof(s), "score %d ", current_score); rb->lcd_putsxy(1,LCD_HEIGHT-8, s); rb->snprintf(level, sizeof(level), "stage %d ", current_level); rb->lcd_putsxy(CENTER_LCD_X - 20, CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, level); draw_and_move_ship(); draw_lives(); show_level_timeout--; if(!show_level_timeout) { initialise_game(current_level); game_state = PLAY_MODE; draw_lives(); } break; } draw_trail_blaze(); drawstars(); draw_and_move_asteroids(); draw_and_move_enemy(); rb->lcd_update(); #ifdef HAS_BUTTON_HOLD if (rb->button_hold() && game_state == PLAY_MODE) game_state = PAUSE_MODE; #endif button = rb->button_get(false); switch(button) { case(AST_QUIT): if (spacerocks_menu(true)!=0) return 0; break; #ifdef AST_PAUSE case(AST_PAUSE): if (game_state == PAUSE_MODE) game_state = PLAY_MODE; else if (game_state == PLAY_MODE) game_state = PAUSE_MODE; break; #endif case (AST_LEFT): case (AST_LEFT | BUTTON_REPEAT): if(game_state == PLAY_MODE || game_state == SHOW_LEVEL) rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN); break; case (AST_RIGHT): case (AST_RIGHT | BUTTON_REPEAT): if(game_state == PLAY_MODE || game_state == SHOW_LEVEL) rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN); break; case (AST_THRUST): case (AST_THRUST | BUTTON_REPEAT): if(game_state == PLAY_MODE || game_state == SHOW_LEVEL) { if (!next_thrust_count) { next_thrust_count = 5; thrust_ship(); } } break; case (AST_HYPERSPACE): if(game_state == PLAY_MODE) hyperspace(); /*maybe shield if it gets too hard */ break; case (AST_FIRE): case (AST_FIRE | BUTTON_REPEAT): if(game_state == PLAY_MODE) { if(!next_missile_count) { fire_missile(); next_missile_count = 10; } } else if(game_state == PAUSE_MODE) game_state = PLAY_MODE; break; default: if (rb->default_event_handler(button)==SYS_USB_CONNECTED) return PLUGIN_USB_CONNECTED; break; } if(next_missile_count) next_missile_count--; if(next_thrust_count) next_thrust_count--; if (TIME_BEFORE(*rb->current_tick, end)) rb->sleep(end-*rb->current_tick); else rb->yield(); } } enum plugin_status plugin_start(const void* parameter) { (void)parameter; #if LCD_DEPTH > 1 rb->lcd_set_backdrop(NULL); #endif /* universal font */ rb->lcd_setfont(FONT_SYSFIXED); /* Turn off backlight timeout */ backlight_force_on(); /* backlight control in lib/helper.c */ highscore_load(HIGH_SCORE, highscores, NUM_SCORES); spacerocks_game_loop(); rb->lcd_setfont(FONT_UI); highscore_save(HIGH_SCORE, highscores, NUM_SCORES); /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); /* backlight control in lib/helper.c */ return PLUGIN_OK; }