rockbox/apps/plugins/spacerocks.c
Barry Wardell 41ee9e3304 FS#6539 - Thanks to Tom Ross
Add Jewels, Spacerocks, Wormlet, Rockboy and Sudoku for the e200. Also Includes manual changes for plugins.
Add X5 keymappings for wormlet to the manual.
Add help text for Jewels on the H10 and give a warning if help text is not defined.
Fix bug in spacerocks lives drawing on large screens (larger than Ondio).
Change spacerocks comments to C style.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12018 a1c6a512-1295-4272-9138-f99709370657
2007-01-15 20:40:48 +00:00

1964 lines
55 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2006 by Mat Holton
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#include "math.h"
#include "stdio.h"
PLUGIN_HEADER
/******************************* Globals ***********************************/
static struct plugin_api* rb; /* global api struct pointer */
/* variable button definitions */
#if CONFIG_KEYPAD == RECORDER_PAD
#define AST_PAUSE BUTTON_ON
#define AST_QUIT BUTTON_OFF
#define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
#define AST_THRUST BUTTON_UP
#define AST_HYPERSPACE BUTTON_DOWN
#define AST_LEFT BUTTON_LEFT
#define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
#define AST_RIGHT BUTTON_RIGHT
#define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
#define AST_FIRE BUTTON_PLAY
#define AST_FIRE_REP BUTTON_PLAY | BUTTON_REPEAT
#elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
#define AST_PAUSE BUTTON_ON
#define AST_QUIT BUTTON_OFF
#define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
#define AST_THRUST BUTTON_UP
#define AST_HYPERSPACE BUTTON_DOWN
#define AST_LEFT BUTTON_LEFT
#define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
#define AST_RIGHT BUTTON_RIGHT
#define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
#define AST_FIRE BUTTON_SELECT
#define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
#elif CONFIG_KEYPAD == ONDIO_PAD
#define AST_PAUSE (BUTTON_MENU | BUTTON_OFF)
#define AST_QUIT BUTTON_OFF
#define AST_THRUST BUTTON_UP
#define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
#define AST_HYPERSPACE BUTTON_DOWN
#define AST_LEFT BUTTON_LEFT
#define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
#define AST_RIGHT BUTTON_RIGHT
#define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
#define AST_FIRE BUTTON_MENU
#define AST_FIRE_REP BUTTON_MENU | BUTTON_REPEAT
#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
(CONFIG_KEYPAD == IRIVER_H300_PAD)
#define AST_PAUSE BUTTON_REC
#define AST_QUIT BUTTON_OFF
#define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
#define AST_THRUST BUTTON_UP
#define AST_HYPERSPACE BUTTON_DOWN
#define AST_LEFT BUTTON_LEFT
#define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
#define AST_RIGHT BUTTON_RIGHT
#define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
#define AST_FIRE BUTTON_SELECT
#define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
#define AST_RC_QUIT BUTTON_RC_STOP
#elif (CONFIG_KEYPAD == IAUDIO_X5_PAD)
#define AST_PAUSE BUTTON_PLAY
#define AST_QUIT BUTTON_POWER
#define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
#define AST_THRUST BUTTON_UP
#define AST_HYPERSPACE BUTTON_DOWN
#define AST_LEFT BUTTON_LEFT
#define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
#define AST_RIGHT BUTTON_RIGHT
#define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
#define AST_FIRE BUTTON_SELECT
#define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
#elif (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD)
#define AST_PAUSE (BUTTON_SELECT | BUTTON_PLAY)
#define AST_QUIT (BUTTON_SELECT | BUTTON_MENU)
#define AST_THRUST BUTTON_MENU
#define AST_THRUST_REP (BUTTON_MENU | BUTTON_REPEAT)
#define AST_HYPERSPACE BUTTON_PLAY
#define AST_LEFT BUTTON_SCROLL_BACK
#define AST_LEFT_REP (BUTTON_SCROLL_BACK | BUTTON_REPEAT)
#define AST_RIGHT BUTTON_SCROLL_FWD
#define AST_RIGHT_REP (BUTTON_SCROLL_FWD | BUTTON_REPEAT)
#define AST_FIRE BUTTON_SELECT
#define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT)
#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
#define AST_PAUSE BUTTON_POWER
#define AST_QUIT BUTTON_A
#define AST_THRUST_REP BUTTON_UP | BUTTON_REPEAT
#define AST_THRUST BUTTON_UP
#define AST_HYPERSPACE BUTTON_DOWN
#define AST_LEFT BUTTON_LEFT
#define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
#define AST_RIGHT BUTTON_RIGHT
#define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
#define AST_FIRE BUTTON_SELECT
#define AST_FIRE_REP BUTTON_SELECT | BUTTON_REPEAT
#elif (CONFIG_KEYPAD == SANSA_E200_PAD)
#define AST_PAUSE BUTTON_REC
#define AST_QUIT BUTTON_POWER
#define AST_THRUST_REP (BUTTON_UP | BUTTON_REPEAT)
#define AST_THRUST BUTTON_UP
#define AST_HYPERSPACE BUTTON_DOWN
#define AST_LEFT BUTTON_LEFT
#define AST_LEFT_REP (BUTTON_LEFT | BUTTON_REPEAT)
#define AST_RIGHT BUTTON_RIGHT
#define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
#define AST_FIRE BUTTON_SELECT
#define AST_FIRE_REP (BUTTON_SELECT | BUTTON_REPEAT)
#elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
#define AST_PAUSE BUTTON_PLAY
#define AST_QUIT BUTTON_POWER
#define AST_THRUST_REP BUTTON_SCROLL_UP | BUTTON_REPEAT
#define AST_THRUST BUTTON_SCROLL_UP
#define AST_HYPERSPACE BUTTON_SCROLL_DOWN
#define AST_LEFT BUTTON_LEFT
#define AST_LEFT_REP BUTTON_LEFT | BUTTON_REPEAT
#define AST_RIGHT BUTTON_RIGHT
#define AST_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
#define AST_FIRE BUTTON_REW
#define AST_FIRE_REP BUTTON_REW | BUTTON_REPEAT
#endif
#define ABS(x) ((x)>0?(x):-(x))
#if CONFIG_KEYPAD == RECORDER_PAD || CONFIG_KEYPAD == ONDIO_PAD
#define ENEMY_MISSILE_SURVIVAL_LENGTH 65
#define MISSILE_SURVIVAL_LENGTH 40
#define ASTEROID_SPEED 5
#define LARGE_LCD 0
#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
(CONFIG_KEYPAD == IRIVER_H300_PAD) || \
(CONFIG_KEYPAD == IAUDIO_X5_PAD) || \
(CONFIG_KEYPAD == IPOD_3G_PAD) || \
(CONFIG_KEYPAD == IPOD_4G_PAD) || \
(CONFIG_KEYPAD == GIGABEAT_PAD)|| \
(CONFIG_KEYPAD == ARCHOS_AV300_PAD)|| \
(CONFIG_KEYPAD == IRIVER_H10_PAD)|| \
(CONFIG_KEYPAD == SANSA_E200_PAD)
#define ENEMY_MISSILE_SURVIVAL_LENGTH 140
#define MISSILE_SURVIVAL_LENGTH 40
#define ASTEROID_SPEED 15
#define LARGE_LCD 1
#endif
#define EXTRA_LIFE 250
#define SCALE 5000
#define MISSILE_SCALE 5000
#define WRAP_GAP 12
#define EXPLOSION_LENGTH 20
#define SHOW_COL 0
#define HISCORE_FILE PLUGIN_DIR "/astrorocks.hs"
#define POINT_SIZE 2
#define MAX_NUM_ASTEROIDS 25
#define MAX_NUM_MISSILES 6
#define ENEMY_BIG_PROBABILITY_START 10
#define ENEMY_APPEAR_PROBABILITY_START 35
#define ENEMY_APPEAR_TIMING_START 1800
#define LITTLE_SHIP 2
#define BIG_SHIP 1
#define SHOW_GAME_OVER_TIME 100
#define SHOW_LEVEL_TIME 50
#define START_LIVES 3
#define START_LEVEL 1
#define NUM_ASTEROID_VERTICES 10
#define NUM_SHIP_VERTICES 4
#define NUM_ENEMY_VERTICES 6
#define MAX_LEVEL MAX_NUM_ASTEROIDS
#define ENEMY_SPEED 4
#define ENEMY_START_X 0
#define ENEMY_START_Y 0
#define SIZE_ENEMY_COLLISION 5*SCALE
#define ATTRACT_FLIP_TIME 100
#define NUM_STARS 50
#define NUM_TRAIL_POINTS 70
#define NUM_ROTATIONS 16
#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
#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
#ifdef HAVE_LCD_COLOR
#define COL_MISSILE LCD_RGBPACK(200,0,0)
#define COL_PLAYER LCD_RGBPACK(200,200,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
/* 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,
ATTRACT_MODE,
SHOW_LEVEL,
PLAY_MODE,
PAUSE_MODE
};
struct Point
{
int x;
int y;
int dx;
int dy;
};
struct TrailPoint
{
int alive;
struct Point position;
short r;
short g;
short b;
short dec;
};
/* Asteroid structure, contains an array of points */
struct Asteroid
{
enum asteroid_type type;
bool exists;
struct Point position;
struct Point vertices[NUM_ASTEROID_VERTICES];
int radius;
long speed_cos;
long speed_sin;
int explode_countdown;
};
struct Ship
{
struct Point vertices[NUM_SHIP_VERTICES];
struct Point position;
bool waiting_for_space;
int explode_countdown;
};
struct Enemy
{
struct Point vertices[NUM_ENEMY_VERTICES];
struct Point position;
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 attract_flip_timeout;
static int show_game_over;
static int current_level;
static int current_score;
static int high_score;
static int space_check_size = 30*SCALE;
static bool enemy_on_screen;
static char phscore[30];
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 trailPoints[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 s, int c);
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);
/*Hi-Score reading and writing to file - this needs moving to the hi-score plugin lib as
a 3rd function */
void iohiscore(void)
{
int fd;
int compare;
/* clear the buffer we're about to load the highscore data into */
rb->memset(phscore, 0, sizeof(phscore));
fd = rb->open(HISCORE_FILE,O_RDWR | O_CREAT);
/* highscore used to %d, is now %d\n
Deal with no file or bad file */
rb->read(fd,phscore, sizeof(phscore));
compare = rb->atoi(phscore);
if(high_score > compare){
rb->lseek(fd,0,SEEK_SET);
rb->fdprintf(fd, "%d\n", high_score);
}
else
high_score = compare;
rb->close(fd);
}
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;
pj += 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;
if(n == num_vertices - 1)
pj = _point;
else
pj++;
pi++;
}
return c;
}
void move_point(struct Point* point)
{
point->x += point->dx;
point->y += point->dy;
/*check bounds on the x-axis:*/
if(point->x >= SCALED_WIDTH)
point->x = 0;
else if(point->x <= 0)
point->x = SCALED_WIDTH;
/*Check bounds on the y-axis:*/
if(point->y >= SCALED_HEIGHT)
point->y = 0;
else if(point->y <= 0)
point->y = SCALED_HEIGHT;
}
void create_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()%5050)-2500;
tpoint->position.dy = (rb->rand()%5050)-2500;
}
void create_trail_blaze(int colour, struct Point* position)
{
int numtoadd;
struct TrailPoint* tpoint;
int n;
int xadd,yadd;
if(colour != SHIP_EXPLOSION_COLOUR)
{
numtoadd = NUM_TRAIL_POINTS/5;
xadd = position->x;
yadd = position->y;
}
else
{
numtoadd = NUM_TRAIL_POINTS/8;
xadd = ship.position.x;
yadd = ship.position.y;
}
/* give the point a random countdown timer, so they dissapears at different times */
tpoint = trailPoints;
n = NUM_TRAIL_POINTS;
while(--n)
{
if(tpoint->alive <= 0 && numtoadd)
{
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:
tpoint->r = 255;
tpoint->g = 255;
tpoint->b = 255;
create_explosion_trail(tpoint);
tpoint->alive = 510;
tpoint->dec = 2;
break;
case ASTEROID_EXPLOSION_COLOUR:
tpoint->r = ASTEROID_R;
tpoint->g = ASTEROID_G;
tpoint->b = ASTEROID_B;
create_explosion_trail(tpoint);
tpoint->alive = 510;
tpoint->dec = 2;
break;
case ENEMY_EXPLOSION_COLOUR:
tpoint->r = ENEMY_R;
tpoint->g = ENEMY_G;
tpoint->b = ENEMY_B;
create_explosion_trail(tpoint);
tpoint->alive = 510;
tpoint->dec = 2;
break;
case THRUST_COLOUR:
tpoint->r = THRUST_R;
tpoint->g = THRUST_G;
tpoint->b = THRUST_B;
create_trail(tpoint);
tpoint->alive = 175;
tpoint->dec = 4;
break;
}
/* add a proportional bit to the x and y based on dx and dy */
/* give the points a speed based on direction of travel - i.e. opposite */
tpoint->position.dx += position->dx;
tpoint->position.dy += position->dy;
}
tpoint++;
}
/* find a space in the array of trail_points that is NULL or DEAD or whatever.
and place this one here. */
}
void draw_trail_blaze(void)
{
struct TrailPoint* tpoint;
/* loop through, if alive then move and draw.
when drawn, countdown it's timer.
if zero kill it! */
tpoint = trailPoints;
int 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>0)tpoint->r-=tpoint->dec;
if(tpoint->g>0)tpoint->g-=tpoint->dec;
if(tpoint->b>0)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_drawline( aTLx/SCALE, aTLy/SCALE, aBRx/SCALE, aTLy/SCALE);
rb->lcd_drawline( aTLx/SCALE, aTLy/SCALE, aTLx/SCALE, aBRy/SCALE);
rb->lcd_drawline( aTLx/SCALE, aBRy/SCALE, aBRx/SCALE, aBRy/SCALE);
rb->lcd_drawline( aBRx/SCALE, aBRy/SCALE, aBRx/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;
p += num_vertices-1;
oldX = p->x/SCALE + px;
oldY = p->y/SCALE + py;
p = vertices;
for(n = num_vertices+1; --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;
for(n = num_points; --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_missile.survived = 0;
enemy_on_screen = true;
enemy.explode_countdown = 0;
enemy.last_time_appeared = *rb->current_tick;
point = enemy.vertices;
for(n = 0; n < NUM_ENEMY_VERTICES+NUM_ENEMY_VERTICES; 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;
struct Point *point;
SET_FG(COL_ENEMY);
if(enemy_on_screen)
{
enemy_x = enemy.position.x/SCALE;
enemy_y = enemy.position.y/SCALE;
if(!enemy.explode_countdown)
{
point = enemy.vertices;
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_on_screen = 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_on_screen = false;
}
}
}
else
{
if( (*rb->current_tick - enemy.last_time_appeared) > enemy.appear_timing)
if(rb->rand()%100 > enemy.appear_probability) initialise_enemy();
}
if(!enemy_missile.survived && game_state != GAME_OVER)
{
/*if no missile and the enemy is here and not exploding..then shoot baby!*/
if( !enemy.explode_countdown && enemy_on_screen &&
!ship.waiting_for_space && (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;
}
if(enemy_missile.position.dx == 0 &&
enemy_missile.position.dy == 0)
enemy_missile.position.dx = enemy_missile.position.dy = -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--;
}
}
}
/******************
* Lame method of collision
* detection. It's checking for collision
* between point and a big rectangle around the asteroid...
*******************/
bool is_point_within_asteroid(struct Asteroid* asteroid, struct Point* point)
{
if( !is_point_within_rectangle(&asteroid->position, point,
asteroid->radius+4*SCALE) )
return false;
if(point_in_poly(asteroid->vertices, NUM_ASTEROID_VERTICES,
point->x - asteroid->position.x,
point->y - asteroid->position.y))
{
switch(asteroid->type)
{
case(SMALL):
asteroid->explode_countdown = EXPLOSION_LENGTH;
create_trail_blaze(ASTEROID_EXPLOSION_COLOUR, &asteroid->position);
break;
case(LARGE):
create_asteroid(MEDIUM, asteroid->position.x,
asteroid->position.y);
create_asteroid(MEDIUM, asteroid->position.x,
asteroid->position.y);
break;
case(MEDIUM):
create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
create_asteroid(SMALL, asteroid->position.x, asteroid->position.y);
break;
}
current_score++;
if(current_score > extra_life)
{
num_lives++;
extra_life = current_score+EXTRA_LIFE;
}
asteroid_count--;
asteroid->exists = false;
return true;
}
else
return false;
}
bool is_point_within_enemy(struct Point* point)
{
if( is_point_within_rectangle(&enemy.position, point, 7*SCALE) )
{
current_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)
{
bool hit = false;
struct Point p;
p.x = ship.position.x + ship.vertices[0].x;
p.y = ship.position.y + ship.vertices[0].y;
hit |= is_point_within_asteroid(asteroid, &p);
if(!hit)
{
p.x = ship.position.x + ship.vertices[1].x;
p.y = ship.position.y + ship.vertices[1].y;
hit |= is_point_within_asteroid(asteroid, &p);
if(!hit)
{
p.x = ship.position.x + ship.vertices[3].x;
p.y = ship.position.y + ship.vertices[3].y;
hit |= is_point_within_asteroid(asteroid, &p);
}
}
return hit;
}
void initialise_explosion(struct Point* point, int num_points)
{
int n;
point->x += point->dx;
point->y += point->dy;
for(n = num_points; --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)
{
int m, n;
bool asteroids_onscreen = false;
struct Missile* missile;
struct Asteroid* asteroid;
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))
{
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))
{
/*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))
{
/*take that score back then:*/
if(current_score > 0) current_score--;
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_on_screen && !ship.waiting_for_space &&
!ship.explode_countdown && !enemy.explode_countdown)
{
/*has the enemy collided with the ship?*/
if(is_point_within_enemy(&ship.position))
{
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);
}
/*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))
{
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_on_screen && !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)
{
int n;
int p1x, p1y;
int p2x, p2y;
struct Missile* missile;
missile = missiles_array;
SET_FG(COL_MISSILE);
n = MAX_NUM_MISSILES;
while(--n)
{
if(missile->survived)
{
if(missile->position.dx > 0)
{
if(missile->position.x >= missile->oldpoint.x)
{
p1x = missile->oldpoint.x;
p2x = missile->position.x;
}
else
{
p1x = 0;
p2x = missile->position.x;
}
}
else
{
if(missile->oldpoint.x >= missile->position.x)
{
p1x = missile->oldpoint.x;
p2x = missile->position.x;
}
else
{
p1x = missile->oldpoint.x;
p2x = LCD_WIDTH;
}
}
if(missile->position.dy > 0)
{
if(missile->position.y >= missile->oldpoint.y)
{
p1y = missile->oldpoint.y;
p2y = missile->position.y;
}
else
{
p1y = 0;
p2y = missile->position.y;
}
}
else
{
if(missile->oldpoint.y >= missile->position.y)
{
p1y = missile->oldpoint.y;
p2y = missile->position.y;
}
else
{
p1y = missile->oldpoint.y;
p2y = LCD_HEIGHT;
}
}
rb->lcd_drawline( p1x/SCALE, p1y/SCALE, p2x/SCALE, p2y/SCALE);
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;
int px = (LCD_WIDTH - num_lives*4 - 1);
#if(LARGE_LCD)
int py = (LCD_HEIGHT-6);
#else
int py = (LCD_HEIGHT-4);
#endif
SET_FG(COL_PLAYER);
n = num_lives;
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)
{
int n;
struct Missile* missile;
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)
{
int n;
bool b,b2;
struct Point* point;
asteroid->exists = true;
asteroid->type = type;
asteroid->explode_countdown = 0;
/*Set the radius of the asteroid:*/
asteroid->radius = (int)type*SCALE;
/*shall we move Clockwise and Fast*/
if((rb->rand()%100)>75)
{
asteroid->speed_cos = FAST_ROT_CW_COS;
asteroid->speed_sin = FAST_ROT_CW_SIN;
}
else if((rb->rand()%100)>75)
{
asteroid->speed_cos = FAST_ROT_ACW_COS;
asteroid->speed_sin = FAST_ROT_ACW_SIN;
}
else if((rb->rand()%100)>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;
}
b = (rb->rand()%100)>66;
b2 = (rb->rand()%100)>66;
point = asteroid->vertices;
for(n = 0; n < NUM_ASTEROID_VERTICES*2; n+=2)
{
if(b)
{
point->x = asteroid_one[n];
point->y = asteroid_one[n+1];
}
else if( b2 )
{
point->x = asteroid_two[n];
point->y = asteroid_two[n+1];
}
else
{
point->x = asteroid_three[n];
point->y = asteroid_three[n+1];
}
point->x *= asteroid->radius/6;
point->y *= asteroid->radius/6;
point++;
}
asteroid->radius += 6*SCALE;
if(asteroid->type == SMALL)
asteroid->radius /= 3;/*2*/
else if(asteroid->type == LARGE)
asteroid->radius += 3*SCALE;/*2*/
b = true;
while(b)
{
/*Set the position randomly:*/
asteroid->position.x = (rb->rand()%SCALED_WIDTH);
asteroid->position.y = (rb->rand()%SCALED_HEIGHT);
asteroid->position.dx = 0;
while(asteroid->position.dx == 0)
asteroid->position.dx = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
asteroid->position.dy = 0;
while(asteroid->position.dy == 0)
asteroid->position.dy = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2;
asteroid->position.dx *= SCALE/10;
asteroid->position.dy *= SCALE/10;
b = is_point_within_rectangle(&ship.position, &asteroid->position,
space_check_size);
}
/*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;
ship.position.y = CENTER_LCD_Y;
ship.position.x *= SCALE;
ship.position.y *= SCALE;
ship.position.dx = ship.position.dy = 0;
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;
point++;
lives_point++;
}
ship.position.dx = 0;
ship.position.dy = 0;
ship.explode_countdown = 0;
/*hack-o-rama-city-arizona, take it out to see what happens:*/
for(n=30;--n;)
rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN);
/*grab a copy of the ships points for the lives display:*/
point = ship.vertices;
lives_point = lives_points;
for(n = 0; n < NUM_SHIP_VERTICES*2; n+=2)
{
lives_point->x = point->x;
lives_point->y = point->y;
lives_point++;
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)
{
int nxoffset = ship.position.x/SCALE;
int nyoffset = ship.position.y/SCALE;
SET_FG(COL_PLAYER);
if(!ship.explode_countdown)
{
if(!ship.waiting_for_space)
{
draw_polygon(ship.vertices, nxoffset, nyoffset, 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)
{
show_game_over = SHOW_GAME_OVER_TIME;
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;
double 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 = NUM_STARS;
p = stars;
SET_FG(COL_STARS);
while(--n)
{
rb->lcd_drawpixel(p->x , p->y);
p++;
}
}
/*************************************************
** Draw And Move all Asteroids
*************************************************/
void draw_and_move_asteroids(void)
{
int n;
struct Asteroid* asteroid;
asteroid = asteroids_array;
SET_FG(COL_ASTEROID);
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++;
}
/* give the point a random countdown timer, so they dissapears at different
times */
tpoint = trailPoints;
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)
{
int n;
asteroid_count = next_missile_count = next_thrust_count = 0;
struct Asteroid* asteroid;
struct Missile* missile;
extra_life = EXTRA_LIFE;
/*no enemy*/
enemy_on_screen = 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++;
}
}
void start_attract_mode(void)
{
enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START;
enemy.appear_timing = ENEMY_APPEAR_TIMING_START;
current_level = 5;
num_lives = START_LIVES;
current_score = 0;
attract_flip_timeout = ATTRACT_FLIP_TIME;
game_state = ATTRACT_MODE;
if(asteroid_count < 3)
initialise_game(current_level);
}
enum plugin_status start_game(void)
{
char s[20];
char level[10];
int button;
int end;
int CYCLETIME = 30;
/*create stars once, and once only:*/
create_stars();
SET_BG(LCD_BLACK);
while(true)
{
/*game starts with at level 1
with 1 asteroid.*/
start_attract_mode();
/*Main loop*/
while(true)
{
end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
rb->lcd_clear_display();
SET_FG(COL_TEXT);
switch(game_state)
{
case(ATTRACT_MODE):
if(attract_flip_timeout < ATTRACT_FLIP_TIME/2)
{
rb->lcd_putsxy(CENTER_LCD_X - 39,
CENTER_LCD_Y + CENTER_LCD_Y/2 - 4,
"Fire to Start");
if(!attract_flip_timeout)
attract_flip_timeout = ATTRACT_FLIP_TIME;
}
else
{
rb->snprintf(s, sizeof(s), "Hi Score %d ", high_score);
rb->lcd_putsxy(CENTER_LCD_X - 30,
CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, s);
}
attract_flip_timeout--;
break;
case(GAME_OVER):
rb->lcd_putsxy(CENTER_LCD_X - 25,
CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "Game Over");
rb->snprintf(s, sizeof(s), "score %d ", current_score);
rb->lcd_putsxy(1,LCD_HEIGHT-8, s);
show_game_over--;
if(!show_game_over)
start_attract_mode();
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):
show_level_timeout--;
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();
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();
button = rb->button_get(false);
#ifdef HAS_BUTTON_HOLD
if (rb->button_hold())
game_state = PAUSE_MODE;
#endif
switch(button)
{
case(AST_PAUSE):
if(game_state == PLAY_MODE)
game_state = PAUSE_MODE;
else if(game_state == PAUSE_MODE)
game_state = PLAY_MODE;
break;
#ifdef AST_RC_QUIT
case AST_RC_QUIT:
#endif
case(AST_QUIT):
if(game_state == ATTRACT_MODE)
return PLUGIN_OK;
else if(game_state == GAME_OVER)
{
start_attract_mode();
}
else
{
show_game_over = SHOW_GAME_OVER_TIME;
game_state = GAME_OVER;
}
break;
case (AST_LEFT_REP):
case (AST_LEFT):
if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN);
break;
case (AST_RIGHT_REP):
case (AST_RIGHT):
if(game_state == PLAY_MODE || game_state == SHOW_LEVEL)
rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN);
break;
case (AST_THRUST_REP):
case (AST_THRUST):
if((game_state == PLAY_MODE || game_state == SHOW_LEVEL) && !next_thrust_count)
{
thrust_ship();
next_thrust_count = 5;
}
break;
case (AST_HYPERSPACE):
if(game_state == PLAY_MODE)
hyperspace();
/*maybe shield if it gets too hard */
break;
case (AST_FIRE_REP):
case (AST_FIRE):
if(game_state == ATTRACT_MODE)
{
current_level = START_LEVEL;
initialise_ship();
initialise_game(current_level);
show_level_timeout = SHOW_LEVEL_TIME;
game_state = PLAY_MODE;
}
else 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(!num_lives)
{
if(high_score < current_score)
high_score = current_score;
if(!show_game_over)
break;
}
if(next_missile_count)
next_missile_count--;
if(next_thrust_count)
next_thrust_count--;
if (end > *rb->current_tick)
rb->sleep(end-*rb->current_tick);
else
rb->yield();
}
}
}
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
enum plugin_status retval;
(void)(parameter);
rb = api;
game_state = ATTRACT_MODE;
/* universal font */
#if LCD_DEPTH > 1
rb->lcd_set_backdrop(NULL);
#endif
rb->lcd_setfont(FONT_SYSFIXED);
rb->backlight_set_timeout(1);
iohiscore();
retval = start_game();
iohiscore();
rb->lcd_setfont(FONT_UI);
/* restore normal backlight setting*/
rb->backlight_set_timeout(rb->global_settings->backlight_timeout);
return retval;
}