1
0
Fork 0
forked from len0rd/rockbox

Adapted Wormlet to all other models with bitmap LCDs - fullscreen on all of them - with colors where possible. Untested on all models except Recorder and iPod 5G; might be a bit buggy.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9020 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Zakk Roberts 2006-03-13 03:13:05 +00:00
parent 7a10c08af4
commit c091a77381
2 changed files with 266 additions and 149 deletions

View file

@ -32,6 +32,8 @@ plasma.c
bejeweled.c bejeweled.c
bounce.c bounce.c
wormlet.c
#if (LCD_WIDTH != 138) && (LCD_WIDTH != 128) #if (LCD_WIDTH != 138) && (LCD_WIDTH != 128)
/* These need adjusting for the Mini's and iRiver if'p screen */ /* These need adjusting for the Mini's and iRiver if'p screen */
brickmania.c brickmania.c
@ -59,9 +61,6 @@ sudoku.c
video.c video.c
#endif #endif
vu_meter.c vu_meter.c
#if CONFIG_KEYPAD == RECORDER_PAD /* Recorder models only for now */
wormlet.c
#endif
#ifdef CONFIG_RTC #ifdef CONFIG_RTC
clock.c clock.c

View file

@ -18,8 +18,6 @@
****************************************************************************/ ****************************************************************************/
#include "plugin.h" #include "plugin.h"
#if defined(HAVE_LCD_BITMAP) && (CONFIG_KEYPAD == RECORDER_PAD)
PLUGIN_HEADER PLUGIN_HEADER
/* size of the field the worm lives in */ /* size of the field the worm lives in */
@ -28,31 +26,118 @@ PLUGIN_HEADER
#define FIELD_RECT_WIDTH (LCD_WIDTH - 45) #define FIELD_RECT_WIDTH (LCD_WIDTH - 45)
#define FIELD_RECT_HEIGHT (LCD_HEIGHT - 2) #define FIELD_RECT_HEIGHT (LCD_HEIGHT - 2)
/* size of the ring of the worm /* size of the ring of the worm
choos a value that is a power of 2 to help choos a value that is a power of 2 to help
the compiler optimize modul operations*/ the compiler optimize modul operations*/
#define MAX_WORM_SEGMENTS 64 #define MAX_WORM_SEGMENTS 64
/* when the game starts */ /* when the game starts */
#define INITIAL_WORM_LENGTH 10 #define INITIAL_WORM_LENGTH 10
/* num of pixel the worm grows per eaten food */ /* num of pixel the worm grows per eaten food */
#define WORM_PER_FOOD 7 #define WORM_PER_FOOD 7
/* num of worms creeping in the FIELD */ /* num of worms creeping in the FIELD */
#define MAX_WORMS 3 #define MAX_WORMS 3
/* minimal distance between a worm and an argh /* minimal distance between a worm and an argh
when a new argh is made */ when a new argh is made */
#define MIN_ARGH_DIST 5 #define MIN_ARGH_DIST 5
#if (CONFIG_KEYPAD == RECORDER_PAD)
#define BTN_DIR_UP BUTTON_UP
#define BTN_DIR_DOWN BUTTON_DOWN
#define BTN_DIR_LEFT BUTTON_LEFT
#define BTN_DIR_RIGHT BUTTON_RIGHT
#define BTN_PLAYER2_DIR1 BUTTON_F2
#define BTN_PLAYER2_DIR2 BUTTON_F3
#define BTN_RC_UP BUTTON_RC_VOL_UP
#define BTN_RC_DOWN BUTTON_RC_VOL_DOWN
#define BTN_STARTPAUSE BUTTON_PLAY
#define BTN_QUIT BUTTON_OFF
#define BTN_STOPRESET BUTTON_ON
#define BTN_TOGGLE_KEYS BUTTON_F1
#define REMOTE
#define MULTIPLAYER
#define PLAYERS_TEXT "UP/DN"
#define WORMS_TEXT "L/R"
#define KEY_CONTROL_TEXT "F1"
#elif (CONFIG_KEYPAD == ONDIO_PAD)
#define BTN_DIR_UP BUTTON_UP
#define BTN_DIR_DOWN BUTTON_DOWN
#define BTN_DIR_LEFT BUTTON_LEFT
#define BTN_DIR_RIGHT BUTTON_RIGHT
#define BTN_STARTPAUSE (BUTTON_MODE|BUTTON_REL)
#define BTN_QUIT (BUTTON_ONOFF|BUTTON_REL)
#define BTN_STOPRESET (BUTTON_ONOFF|BUTTON_MODE)
#define PLAYERS_TEXT "UP/DN"
#define WORMS_TEXT "L/R"
#elif (CONFIG_KEYPAD == IPOD_4G_PAD)
#define BTN_DIR_UP BUTTON_MENU
#define BTN_DIR_DOWN BUTTON_PLAY
#define BTN_DIR_LEFT BUTTON_LEFT
#define BTN_DIR_RIGHT BUTTON_RIGHT
#define BTN_STARTPAUSE (BUTTON_SELECT|BUTTON_REL)
#define BTN_QUIT (BUTTON_SELECT|BUTTON_MENU)
#define BTN_STOPRESET (BUTTON_SELECT|BUTTON_PLAY)
#define PLAYERS_TEXT "Menu/Play"
#define WORMS_TEXT "Left/Right"
#elif (CONFIG_KEYPAD == IRIVER_H300_PAD) ||
(CONFIG_KEYPAD == IRIVER_H100_PAD)
#define BTN_DIR_UP BUTTON_UP
#define BTN_DIR_DOWN BUTTON_DOWN
#define BTN_DIR_LEFT BUTTON_LEFT
#define BTN_DIR_RIGHT BUTTON_RIGHT
#define BTN_STARTPAUSE (BUTTON_SELECT|BUTTON_REL)
#define BTN_QUIT BUTTON_OFF
#define BTN_STOPRESET BUTTON_ON
#define PLAYERS_TEXT "Up/Down"
#define WORMS_TEXT "Left/Right"
#endif
#if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
#define FOOD_SIZE 3
#define ARGH_SIZE 4
#define SPEED 14
#elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
#define FOOD_SIZE 4
#define ARGH_SIZE 5
#define SPEED 8
#elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
#define COLOR_LCD
#define FOOD_SIZE 4
#define ARGH_SIZE 5
#define SPEED 6
#elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
#define COLOR_LCD
#define FOOD_SIZE 5
#define ARGH_SIZE 6
#define SPEED 4
#elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
#define COLOR_LCD
#define FOOD_SIZE 7
#define ARGH_SIZE 8
#define SPEED 4
#endif
/** /**
* All the properties that a worm has. * All the properties that a worm has.
*/ */
static struct worm { static struct worm {
/* The worm is stored in a ring of xy coordinates */ /* The worm is stored in a ring of xy coordinates */
char x[MAX_WORM_SEGMENTS]; int x[MAX_WORM_SEGMENTS];
char y[MAX_WORM_SEGMENTS]; int y[MAX_WORM_SEGMENTS];
int head; /* index of the head within the buffer */ int head; /* index of the head within the buffer */
int tail; /* index of the tail within the buffer */ int tail; /* index of the tail within the buffer */
@ -65,8 +150,8 @@ static struct worm {
/* this method is used to fetch the direction the user /* this method is used to fetch the direction the user
has selected. It can be one of the values has selected. It can be one of the values
human_player1, human_player2, remote_player, virtual_player. human_player1, human_player2, remote_player, virtual_player.
All these values are fuctions, that can change the direction All these values are fuctions, that can change the direction
of the worm */ of the worm */
void (*fetch_worm_direction)(struct worm *w); void (*fetch_worm_direction)(struct worm *w);
} worms[MAX_WORMS]; } worms[MAX_WORMS];
@ -74,22 +159,20 @@ static struct worm {
/* stores the highscore - besides it was scored by a virtual player */ /* stores the highscore - besides it was scored by a virtual player */
static int highscore; static int highscore;
#define MAX_FOOD 5 /* maximal number of food items */ #define MAX_FOOD 5 /* maximal number of food items */
#define FOOD_SIZE 3 /* the width and height of a food */
/* The arrays store the food coordinates */ /* The arrays store the food coordinates */
static char foodx[MAX_FOOD]; static char foodx[MAX_FOOD];
static char foody[MAX_FOOD]; static char foody[MAX_FOOD];
#define MAX_ARGH 100 /* maximal number of argh items */ #define MAX_ARGH 100 /* maximal number of argh items */
#define ARGH_SIZE 4 /* the width and height of a argh */
#define ARGHS_PER_FOOD 2 /* number of arghs produced per eaten food */ #define ARGHS_PER_FOOD 2 /* number of arghs produced per eaten food */
/* The arrays store the argh coordinates */ /* The arrays store the argh coordinates */
static char arghx[MAX_ARGH]; static char arghx[MAX_ARGH];
static char arghy[MAX_ARGH]; static char arghy[MAX_ARGH];
/* the number of arghs that are currently in use */ /* the number of arghs that are currently in use */
static int argh_count; static int argh_count;
#ifdef DEBUG_WORMLET #ifdef DEBUG_WORMLET
@ -97,9 +180,6 @@ static int argh_count;
static char debugout[15]; static char debugout[15];
#endif #endif
/* the number of ticks each game cycle should take */
#define SPEED 14
/* the number of active worms (dead or alive) */ /* the number of active worms (dead or alive) */
static int worm_count = MAX_WORMS; static int worm_count = MAX_WORMS;
@ -124,9 +204,9 @@ static bool use_remote = false;
#define SOUTH 3 #define SOUTH 3
/* direction of human player 1 */ /* direction of human player 1 */
static int player1_dir = EAST; static int player1_dir = EAST;
/* direction of human player 2 */ /* direction of human player 2 */
static int player2_dir = EAST; static int player2_dir = EAST;
/* direction of human player 3 */ /* direction of human player 3 */
static int player3_dir = EAST; static int player3_dir = EAST;
@ -146,7 +226,7 @@ static void set_debug_out(char *str){
/** /**
* Returns the direction id in which the worm * Returns the direction id in which the worm
* currently is creeping. * currently is creeping.
* @param struct worm *w The worm that is to be investigated. * @param struct worm *w The worm that is to be investigated.
* w Must not be null. * w Must not be null.
* @return int A value 0 <= value < 4 * @return int A value 0 <= value < 4
* Note the predefined constants NORTH, SOUTH, EAST, WEST * Note the predefined constants NORTH, SOUTH, EAST, WEST
@ -175,7 +255,7 @@ static int get_worm_dir(struct worm *w) {
* to right by 90 degree. * to right by 90 degree.
* @param struct worm *w The worm that is to be altered. w Must not be null. * @param struct worm *w The worm that is to be altered. w Must not be null.
* @param int dir The new direction in which the worm is to creep. * @param int dir The new direction in which the worm is to creep.
* dir must be 0 <= dir < 4. Use predefined constants * dir must be 0 <= dir < 4. Use predefined constants
* NORTH, SOUTH, EAST, WEST * NORTH, SOUTH, EAST, WEST
*/ */
static void set_worm_dir(struct worm *w, int dir) { static void set_worm_dir(struct worm *w, int dir) {
@ -255,7 +335,7 @@ static int get_score(struct worm *w) {
/** /**
* Determines wether the line specified by startx, starty, endx, endy intersects * Determines wether the line specified by startx, starty, endx, endy intersects
* the rectangle specified by x, y, width, height. Note that the line must be exactly * the rectangle specified by x, y, width, height. Note that the line must be exactly
* horizontal or vertical (startx == endx or starty == endy). * horizontal or vertical (startx == endx or starty == endy).
* @param int startx The x coordinate of the start point of the line. * @param int startx The x coordinate of the start point of the line.
* @param int starty The y coordinate of the start point of the line. * @param int starty The y coordinate of the start point of the line.
* @param int endx The x coordinate of the end point of the line. * @param int endx The x coordinate of the end point of the line.
@ -305,7 +385,7 @@ static bool line_in_rect(int startx, int starty, int endx, int endy, int x, int
return retval; return retval;
} }
/** /**
* Tests wether the specified worm intersects with the rect. * Tests wether the specified worm intersects with the rect.
* @param struct worm *w The worm to be investigated * @param struct worm *w The worm to be investigated
* @param int x The x coordinate of the top left corner of the rect * @param int x The x coordinate of the top left corner of the rect
@ -433,7 +513,7 @@ static bool worm_food_collision(struct worm *w, int foodIndex)
{ {
bool retVal = false; bool retVal = false;
retVal = worm_in_rect(w, foodx[foodIndex], foody[foodIndex], retVal = worm_in_rect(w, foodx[foodIndex], foody[foodIndex],
FOOD_SIZE - 1, FOOD_SIZE - 1); FOOD_SIZE - 1, FOOD_SIZE - 1);
return retVal; return retVal;
@ -443,7 +523,7 @@ static bool worm_food_collision(struct worm *w, int foodIndex)
* Returns true if the worm hits the argh within the next moves (unless * Returns true if the worm hits the argh within the next moves (unless
* the worm changes it's direction). * the worm changes it's direction).
* @param struct worm *w - The worm to investigate * @param struct worm *w - The worm to investigate
* @param int argh_idx - The index of the argh * @param int argh_idx - The index of the argh
* @param int moves - The number of moves that are considered. * @param int moves - The number of moves that are considered.
* @return Returns false if the specified argh is not hit within the next * @return Returns false if the specified argh is not hit within the next
* moves. * moves.
@ -457,7 +537,7 @@ static bool worm_argh_collision_in_moves(struct worm *w, int argh_idx, int moves
x2 = w->x[w->head] + moves * w->dirx; x2 = w->x[w->head] + moves * w->dirx;
y2 = w->y[w->head] + moves * w->diry; y2 = w->y[w->head] + moves * w->diry;
retVal = line_in_rect(x1, y1, x2, y2, arghx[argh_idx], arghy[argh_idx], retVal = line_in_rect(x1, y1, x2, y2, arghx[argh_idx], arghy[argh_idx],
ARGH_SIZE, ARGH_SIZE); ARGH_SIZE, ARGH_SIZE);
return retVal; return retVal;
} }
@ -472,7 +552,7 @@ static bool worm_argh_collision(struct worm *w, int arghIndex)
{ {
bool retVal = false; bool retVal = false;
retVal = worm_in_rect(w, arghx[arghIndex], arghy[arghIndex], retVal = worm_in_rect(w, arghx[arghIndex], arghy[arghIndex],
ARGH_SIZE - 1, ARGH_SIZE - 1); ARGH_SIZE - 1, ARGH_SIZE - 1);
return retVal; return retVal;
@ -481,7 +561,7 @@ static bool worm_argh_collision(struct worm *w, int arghIndex)
/** /**
* Find new coordinates for the food stored in foodx[index], foody[index] * Find new coordinates for the food stored in foodx[index], foody[index]
* that don't collide with any other food or argh * that don't collide with any other food or argh
* @param int index * @param int index
* Ensure that 0 <= index < MAX_FOOD. * Ensure that 0 <= index < MAX_FOOD.
*/ */
static int make_food(int index) { static int make_food(int index) {
@ -504,12 +584,12 @@ static int make_food(int index) {
If one or more corners of the new food hit any existing If one or more corners of the new food hit any existing
argh or food a collision is detected. argh or food a collision is detected.
*/ */
collisionDetected = collisionDetected =
food_collision(x , y ) >= 0 || food_collision(x , y ) >= 0 ||
food_collision(x , y + FOOD_SIZE - 1) >= 0 || food_collision(x , y + FOOD_SIZE - 1) >= 0 ||
food_collision(x + FOOD_SIZE - 1, y ) >= 0 || food_collision(x + FOOD_SIZE - 1, y ) >= 0 ||
food_collision(x + FOOD_SIZE - 1, y + FOOD_SIZE - 1) >= 0 || food_collision(x + FOOD_SIZE - 1, y + FOOD_SIZE - 1) >= 0 ||
argh_collision(x , y ) >= 0 || argh_collision(x , y ) >= 0 ||
argh_collision(x , y + FOOD_SIZE - 1) >= 0 || argh_collision(x , y + FOOD_SIZE - 1) >= 0 ||
argh_collision(x + FOOD_SIZE - 1, y ) >= 0 || argh_collision(x + FOOD_SIZE - 1, y ) >= 0 ||
argh_collision(x + FOOD_SIZE - 1, y + FOOD_SIZE - 1) >= 0; argh_collision(x + FOOD_SIZE - 1, y + FOOD_SIZE - 1) >= 0;
@ -531,7 +611,7 @@ static int make_food(int index) {
/** /**
* Clears a food from the lcd buffer. * Clears a food from the lcd buffer.
* @param int index The index of the food arrays under which * @param int index The index of the food arrays under which
* the coordinates of the desired food can be found. Ensure * the coordinates of the desired food can be found. Ensure
* that the value is 0 <= index <= MAX_FOOD. * that the value is 0 <= index <= MAX_FOOD.
*/ */
static void clear_food(int index) static void clear_food(int index)
@ -547,13 +627,16 @@ static void clear_food(int index)
/** /**
* Draws a food in the lcd buffer. * Draws a food in the lcd buffer.
* @param int index The index of the food arrays under which * @param int index The index of the food arrays under which
* the coordinates of the desired food can be found. Ensure * the coordinates of the desired food can be found. Ensure
* that the value is 0 <= index <= MAX_FOOD. * that the value is 0 <= index <= MAX_FOOD.
*/ */
static void draw_food(int index) static void draw_food(int index)
{ {
/* draw the food object */ /* draw the food object */
rb->lcd_fillrect(foodx[index] + FIELD_RECT_X, #ifdef COLOR_LCD
rb->lcd_set_foreground(LCD_RGBPACK(0, 150, 0));
#endif
rb->lcd_fillrect(foodx[index] + FIELD_RECT_X,
foody[index] + FIELD_RECT_Y, foody[index] + FIELD_RECT_Y,
FOOD_SIZE, FOOD_SIZE); FOOD_SIZE, FOOD_SIZE);
rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
@ -561,18 +644,21 @@ static void draw_food(int index)
foody[index] + FIELD_RECT_Y + 1, foody[index] + FIELD_RECT_Y + 1,
FOOD_SIZE - 2, FOOD_SIZE - 2); FOOD_SIZE - 2, FOOD_SIZE - 2);
rb->lcd_set_drawmode(DRMODE_SOLID); rb->lcd_set_drawmode(DRMODE_SOLID);
#ifdef COLOR_LCD
rb->lcd_set_foreground(LCD_RGBPACK(0, 0, 0));
#endif
} }
/** /**
* Find new coordinates for the argh stored in arghx[index], arghy[index] * Find new coordinates for the argh stored in arghx[index], arghy[index]
* that don't collide with any other food or argh. * that don't collide with any other food or argh.
* @param int index * @param int index
* Ensure that 0 <= index < argh_count < MAX_ARGH. * Ensure that 0 <= index < argh_count < MAX_ARGH.
*/ */
static int make_argh(int index) static int make_argh(int index)
{ {
int x = -1; int x = -1;
int y = -1; int y = -1;
bool collisionDetected = false; bool collisionDetected = false;
int tries = 0; int tries = 0;
int i; int i;
@ -589,12 +675,12 @@ static int make_argh(int index)
If one or more corners of the new argh hit any existing If one or more corners of the new argh hit any existing
argh or food an intersection is detected. argh or food an intersection is detected.
*/ */
collisionDetected = collisionDetected =
food_collision(x , y ) >= 0 || food_collision(x , y ) >= 0 ||
food_collision(x , y + ARGH_SIZE - 1) >= 0 || food_collision(x , y + ARGH_SIZE - 1) >= 0 ||
food_collision(x + ARGH_SIZE - 1, y ) >= 0 || food_collision(x + ARGH_SIZE - 1, y ) >= 0 ||
food_collision(x + ARGH_SIZE - 1, y + ARGH_SIZE - 1) >= 0 || food_collision(x + ARGH_SIZE - 1, y + ARGH_SIZE - 1) >= 0 ||
argh_collision(x , y ) >= 0 || argh_collision(x , y ) >= 0 ||
argh_collision(x , y + ARGH_SIZE - 1) >= 0 || argh_collision(x , y + ARGH_SIZE - 1) >= 0 ||
argh_collision(x + ARGH_SIZE - 1, y ) >= 0 || argh_collision(x + ARGH_SIZE - 1, y ) >= 0 ||
argh_collision(x + ARGH_SIZE - 1, y + ARGH_SIZE - 1) >= 0; argh_collision(x + ARGH_SIZE - 1, y + ARGH_SIZE - 1) >= 0;
@ -606,7 +692,7 @@ static int make_argh(int index)
/* now test wether we accidently hit the worm with argh ;) */ /* now test wether we accidently hit the worm with argh ;) */
for (i = 0; i < worm_count && !collisionDetected; i++) { for (i = 0; i < worm_count && !collisionDetected; i++) {
collisionDetected |= worm_argh_collision(&worms[i], index); collisionDetected |= worm_argh_collision(&worms[i], index);
collisionDetected |= worm_argh_collision_in_moves(&worms[i], index, collisionDetected |= worm_argh_collision_in_moves(&worms[i], index,
MIN_ARGH_DIST); MIN_ARGH_DIST);
} }
} }
@ -617,15 +703,21 @@ static int make_argh(int index)
/** /**
* Draws an argh in the lcd buffer. * Draws an argh in the lcd buffer.
* @param int index The index of the argh arrays under which * @param int index The index of the argh arrays under which
* the coordinates of the desired argh can be found. Ensure * the coordinates of the desired argh can be found. Ensure
* that the value is 0 <= index < argh_count <= MAX_ARGH. * that the value is 0 <= index < argh_count <= MAX_ARGH.
*/ */
static void draw_argh(int index) static void draw_argh(int index)
{ {
/* draw the new argh */ /* draw the new argh */
rb->lcd_fillrect(arghx[index] + FIELD_RECT_X, #ifdef COLOR_LCD
arghy[index] + FIELD_RECT_Y, rb->lcd_set_foreground(LCD_RGBPACK(175, 0, 0));
#endif
rb->lcd_fillrect(arghx[index] + FIELD_RECT_X,
arghy[index] + FIELD_RECT_Y,
ARGH_SIZE, ARGH_SIZE); ARGH_SIZE, ARGH_SIZE);
#ifdef COLOR_LCD
rb->lcd_set_foreground(LCD_RGBPACK(0, 0, 0));
#endif
} }
static void virtual_player(struct worm *w); static void virtual_player(struct worm *w);
@ -659,40 +751,40 @@ static void init_worm(struct worm *w, int x, int y){
w->fetch_worm_direction = virtual_player; w->fetch_worm_direction = virtual_player;
} }
/** /**
* Writes the direction that was stored for * Writes the direction that was stored for
* human player 1 into the specified worm. This function * human player 1 into the specified worm. This function
* may be used to be stored in worm.fetch_worm_direction. * may be used to be stored in worm.fetch_worm_direction.
* The value of * The value of
* the direction is read from player1_dir. * the direction is read from player1_dir.
* @param struct worm *w - The worm of which the direction * @param struct worm *w - The worm of which the direction
* is altered. * is altered.
*/ */
static void human_player1(struct worm *w) { static void human_player1(struct worm *w) {
set_worm_dir(w, player1_dir); set_worm_dir(w, player1_dir);
} }
/** /**
* Writes the direction that was stored for * Writes the direction that was stored for
* human player 2 into the specified worm. This function * human player 2 into the specified worm. This function
* may be used to be stored in worm.fetch_worm_direction. * may be used to be stored in worm.fetch_worm_direction.
* The value of * The value of
* the direction is read from player2_dir. * the direction is read from player2_dir.
* @param struct worm *w - The worm of which the direction * @param struct worm *w - The worm of which the direction
* is altered. * is altered.
*/ */
static void human_player2(struct worm *w) { static void human_player2(struct worm *w) {
set_worm_dir(w, player2_dir); set_worm_dir(w, player2_dir);
} }
/** /**
* Writes the direction that was stored for * Writes the direction that was stored for
* human player using a remote control * human player using a remote control
* into the specified worm. This function * into the specified worm. This function
* may be used to be stored in worm.fetch_worm_direction. * may be used to be stored in worm.fetch_worm_direction.
* The value of * The value of
* the direction is read from player3_dir. * the direction is read from player3_dir.
* @param struct worm *w - The worm of which the direction * @param struct worm *w - The worm of which the direction
* is altered. * is altered.
*/ */
static void remote_player(struct worm *w) { static void remote_player(struct worm *w) {
@ -735,7 +827,7 @@ static void init_wormlet(void)
worms[2].fetch_worm_direction = human_player2; worms[2].fetch_worm_direction = human_player2;
} }
/* Needed when the game is restarted using BUTTON_ON */ /* Needed when the game is restarted using BTN_STOPRESET */
rb->lcd_clear_display(); rb->lcd_clear_display();
/* make and display some food and argh */ /* make and display some food and argh */
@ -758,9 +850,9 @@ static void init_wormlet(void)
} }
/** /**
* Move the worm one step further if it is alive. * Move the worm one step further if it is alive.
* The direction in which the worm moves is taken from dirx and diry. * The direction in which the worm moves is taken from dirx and diry.
* move_worm decreases growing if > 0. While the worm is growing the tail * move_worm decreases growing if > 0. While the worm is growing the tail
* is left untouched. * is left untouched.
* @param struct worm *w The worm to move. w must not be NULL. * @param struct worm *w The worm to move. w must not be NULL.
@ -787,7 +879,7 @@ static void move_worm(struct worm *w)
} }
/* olddir == dir? /* olddir == dir?
a change of direction means a new segment a change of direction means a new segment
has been opened */ has been opened */
if (olddirx != w->dirx || if (olddirx != w->dirx ||
olddiry != w->diry) { olddiry != w->diry) {
@ -804,15 +896,15 @@ static void move_worm(struct worm *w)
/* update the worms grow state */ /* update the worms grow state */
w->growing--; w->growing--;
} }
/* if the worm isn't growing the tail has to be dragged */ /* if the worm isn't growing the tail has to be dragged */
else { else {
/* index of the end of the tail segment */ /* index of the end of the tail segment */
int tail_segment_end = (w->tail + 1) % MAX_WORM_SEGMENTS; int tail_segment_end = (w->tail + 1) % MAX_WORM_SEGMENTS;
/* drag the end of the tail */ /* drag the end of the tail */
/* only one coordinate has to be altered. Here it is /* only one coordinate has to be altered. Here it is
determined which one */ determined which one */
int dir = 0; /* specifies wether the coord has to be in- or decreased */ int dir = 0; /* specifies wether the coord has to be in- or decreased */
if (w->x[w->tail] == w->x[tail_segment_end]) { if (w->x[w->tail] == w->x[tail_segment_end]) {
dir = (w->y[w->tail] - w->y[tail_segment_end] < 0) ? 1 : -1; dir = (w->y[w->tail] - w->y[tail_segment_end] < 0) ? 1 : -1;
@ -827,7 +919,7 @@ static void move_worm(struct worm *w)
must be freed */ must be freed */
if (w->x[w->tail] == w->x[tail_segment_end] && if (w->x[w->tail] == w->x[tail_segment_end] &&
w->y[w->tail] == w->y[tail_segment_end]){ w->y[w->tail] == w->y[tail_segment_end]){
/* drop the last tail point */ /* drop the last tail point */
w->tail = tail_segment_end; w->tail = tail_segment_end;
} }
@ -836,12 +928,15 @@ static void move_worm(struct worm *w)
} }
/** /**
* Draws the head and clears the tail of the worm in * Draws the head and clears the tail of the worm in
* the display buffer. lcd_update() is NOT called thus * the display buffer. lcd_update() is NOT called thus
* the caller has to take care that the buffer is displayed. * the caller has to take care that the buffer is displayed.
*/ */
static void draw_worm(struct worm *w) static void draw_worm(struct worm *w)
{ {
#ifdef COLOR_LCD
rb->lcd_set_foreground(LCD_RGBPACK(80, 40, 0));
#endif
/* draw the new head */ /* draw the new head */
int x = w->x[w->head]; int x = w->x[w->head];
int y = w->y[w->head]; int y = w->y[w->head];
@ -858,16 +953,19 @@ static void draw_worm(struct worm *w)
rb->lcd_drawpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y); rb->lcd_drawpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y);
} }
rb->lcd_set_drawmode(DRMODE_SOLID); rb->lcd_set_drawmode(DRMODE_SOLID);
#ifdef COLOR_LCD
rb->lcd_set_foreground(LCD_RGBPACK(0, 0, 0));
#endif
} }
/** /**
* Checks wether the coordinate is part of the worm. Returns * Checks wether the coordinate is part of the worm. Returns
* true if any part of the worm was hit - including the head. * true if any part of the worm was hit - including the head.
* @param x int The x coordinate * @param x int The x coordinate
* @param y int The y coordinate * @param y int The y coordinate
* @return int The index of the worm arrays that contain x, y. * @return int The index of the worm arrays that contain x, y.
* Returns -1 if the coordinates are not part of the worm. * Returns -1 if the coordinates are not part of the worm.
*/ */
static int specific_worm_collision(struct worm *w, int x, int y) static int specific_worm_collision(struct worm *w, int x, int y)
{ {
int retVal = -1; int retVal = -1;
@ -891,7 +989,7 @@ static int specific_worm_collision(struct worm *w, int x, int y)
if (samey) { if (samey) {
min = w->x[linestart]; min = w->x[linestart];
max = w->x[lineend]; max = w->x[lineend];
test = x; test = x;
} else { } else {
min = w->y[linestart]; min = w->y[linestart];
max = w->y[lineend]; max = w->y[lineend];
@ -911,7 +1009,7 @@ static int specific_worm_collision(struct worm *w, int x, int y)
} }
/** /**
* Increases the length of the specified worm by marking * Increases the length of the specified worm by marking
* that it may grow by len pixels. Note that the worm has * that it may grow by len pixels. Note that the worm has
* to move to make the growing happen. * to move to make the growing happen.
* @param worm *w The worm that is to be altered. * @param worm *w The worm that is to be altered.
@ -926,8 +1024,8 @@ static void add_growing(struct worm *w, int len) {
* Determins the worm that is at the coordinates x, y. The parameter * Determins the worm that is at the coordinates x, y. The parameter
* w is a switch parameter that changes the functionality of worm_collision. * w is a switch parameter that changes the functionality of worm_collision.
* If w is specified and x,y hits the head of w NULL is returned. * If w is specified and x,y hits the head of w NULL is returned.
* This is a useful way to determine wether the head of w hits * This is a useful way to determine wether the head of w hits
* any worm but including itself but excluding its own head. * any worm but including itself but excluding its own head.
* (It hits always its own head ;)) * (It hits always its own head ;))
* If w is set to NULL worm_collision returns any worm including all heads * If w is set to NULL worm_collision returns any worm including all heads
* that is at position of x,y. * that is at position of x,y.
@ -954,9 +1052,9 @@ static struct worm* worm_collision(struct worm *w, int x, int y){
/** /**
* Returns true if the head of the worm just has * Returns true if the head of the worm just has
* crossed the field boundaries. * crossed the field boundaries.
* @return bool true if the worm just has wrapped. * @return bool true if the worm just has wrapped.
*/ */
static bool field_collision(struct worm *w) static bool field_collision(struct worm *w)
{ {
bool retVal = false; bool retVal = false;
@ -972,11 +1070,11 @@ static bool field_collision(struct worm *w)
/** /**
* Returns true if the specified coordinates are within the * Returns true if the specified coordinates are within the
* field specified by the FIELD_RECT_XXX constants. * field specified by the FIELD_RECT_XXX constants.
* @param int x The x coordinate of the point that is investigated * @param int x The x coordinate of the point that is investigated
* @param int y The y coordinate of the point that is investigated * @param int y The y coordinate of the point that is investigated
* @return bool Returns false if x,y specifies a point outside the * @return bool Returns false if x,y specifies a point outside the
* field of worms. * field of worms.
*/ */
static bool is_in_field_rect(int x, int y) { static bool is_in_field_rect(int x, int y) {
@ -1017,7 +1115,7 @@ static int check_collision(struct worm *w)
/** /**
* Returns the index of the food that is closest to the point * Returns the index of the food that is closest to the point
* specified by x, y. This index may be used in the foodx and * specified by x, y. This index may be used in the foodx and
* foody arrays. * foody arrays.
* @param int x The x coordinate of the point * @param int x The x coordinate of the point
* @param int y The y coordinate of the point * @param int y The y coordinate of the point
@ -1045,10 +1143,10 @@ static int get_nearest_food(int x, int y){
return nearestfood; return nearestfood;
} }
/** /**
* Returns wether the specified position is next to the worm * Returns wether the specified position is next to the worm
* and in the direction the worm looks. Use this method to * and in the direction the worm looks. Use this method to
* test wether this position would be hit with the next move of * test wether this position would be hit with the next move of
* the worm unless the worm changes its direction. * the worm unless the worm changes its direction.
* @param struct worm *w - The worm to be investigated * @param struct worm *w - The worm to be investigated
* @param int x - The x coordinate of the position to test. * @param int x - The x coordinate of the position to test.
@ -1083,21 +1181,21 @@ static bool will_worm_collide(struct worm *w) {
if (!retVal) { if (!retVal) {
retVal = (argh_collision(x, y) != -1); retVal = (argh_collision(x, y) != -1);
} }
if (!retVal) { if (!retVal) {
retVal = (worm_collision(w, x, y) != NULL); retVal = (worm_collision(w, x, y) != NULL);
} }
return retVal; return retVal;
} }
/** /**
* This function * This function
* may be used to be stored in worm.fetch_worm_direction for * may be used to be stored in worm.fetch_worm_direction for
* worms that are not controlled by humans but by artificial stupidity. * worms that are not controlled by humans but by artificial stupidity.
* A direction is searched that doesn't lead to collision but to the nearest * A direction is searched that doesn't lead to collision but to the nearest
* food - but not very intelligent. The direction is written to the specified * food - but not very intelligent. The direction is written to the specified
* worm. * worm.
* @param struct worm *w - The worm of which the direction * @param struct worm *w - The worm of which the direction
* is altered. * is altered.
*/ */
static void virtual_player(struct worm *w) { static void virtual_player(struct worm *w) {
@ -1171,7 +1269,7 @@ static void score_board(void)
rb->lcd_set_drawmode(DRMODE_SOLID); rb->lcd_set_drawmode(DRMODE_SOLID);
for (i = 0; i < worm_count; i++) { for (i = 0; i < worm_count; i++) {
int score = get_score(&worms[i]); int score = get_score(&worms[i]);
/* high score */ /* high score */
if (worms[i].fetch_worm_direction != virtual_player){ if (worms[i].fetch_worm_direction != virtual_player){
if (highscore < score) { if (highscore < score) {
@ -1184,7 +1282,7 @@ static void score_board(void)
/* worm state */ /* worm state */
switch (check_collision(&worms[i])) { switch (check_collision(&worms[i])) {
case COLLISION_NONE: case COLLISION_NONE:
if (worms[i].growing > 0) if (worms[i].growing > 0)
buf2 = "Growing"; buf2 = "Growing";
else { else {
@ -1195,19 +1293,19 @@ static void score_board(void)
} }
break; break;
case COLLISION_WORM: case COLLISION_WORM:
buf2 = "Wormed"; buf2 = "Wormed";
break; break;
case COLLISION_FOOD: case COLLISION_FOOD:
buf2 = "Growing"; buf2 = "Growing";
break; break;
case COLLISION_ARGH: case COLLISION_ARGH:
buf2 = "Argh"; buf2 = "Argh";
break; break;
case COLLISION_FIELD: case COLLISION_FIELD:
buf2 = "Crashed"; buf2 = "Crashed";
break; break;
} }
@ -1248,11 +1346,11 @@ static bool process_collisions(struct worm *w)
index = food_collision(w->x[w->head], w->y[w->head]); index = food_collision(w->x[w->head], w->y[w->head]);
if (index != -1){ if (index != -1){
int i; int i;
clear_food(index); clear_food(index);
make_food(index); make_food(index);
draw_food(index); draw_food(index);
for (i = 0; i < ARGHS_PER_FOOD; i++) { for (i = 0; i < ARGHS_PER_FOOD; i++) {
argh_count++; argh_count++;
if (argh_count > MAX_ARGH) if (argh_count > MAX_ARGH)
@ -1287,7 +1385,7 @@ static bool process_collisions(struct worm *w)
* @return bool Returns true if the game ended * @return bool Returns true if the game ended
* with a dead worm. Returns false if the user * with a dead worm. Returns false if the user
* aborted the game manually. * aborted the game manually.
*/ */
static bool run(void) static bool run(void)
{ {
int button = 0; int button = 0;
@ -1306,24 +1404,24 @@ static bool run(void)
cycle_start = *rb->current_tick; cycle_start = *rb->current_tick;
/* change the direction of the worm */ /* change the direction of the worm */
while (button != BUTTON_OFF && ! wormDead) while (button != BTN_QUIT && ! wormDead)
{ {
int i; int i;
long cycle_duration ; long cycle_duration ;
switch (button) { switch (button) {
case BUTTON_UP: case BTN_DIR_UP:
if (players == 1 && !use_remote) { if (players == 1 && !use_remote) {
player1_dir = NORTH; player1_dir = NORTH;
} }
break; break;
case BUTTON_DOWN: case BTN_DIR_DOWN:
if (players == 1 && !use_remote) { if (players == 1 && !use_remote) {
player1_dir = SOUTH; player1_dir = SOUTH;
} }
break; break;
case BUTTON_LEFT: case BTN_DIR_LEFT:
if (players != 1 || use_remote) { if (players != 1 || use_remote) {
player1_dir = (player1_dir + 3) % 4; player1_dir = (player1_dir + 3) % 4;
} else { } else {
@ -1331,7 +1429,7 @@ static bool run(void)
} }
break; break;
case BUTTON_RIGHT: case BTN_DIR_RIGHT:
if (players != 1 || use_remote) { if (players != 1 || use_remote) {
player1_dir = (player1_dir + 1) % 4; player1_dir = (player1_dir + 1) % 4;
} else { } else {
@ -1339,28 +1437,32 @@ static bool run(void)
} }
break; break;
case BUTTON_F2: #ifdef MULTIPLAYER
case BTN_PLAYER2_DIR1:
player2_dir = (player2_dir + 3) % 4; player2_dir = (player2_dir + 3) % 4;
break; break;
case BUTTON_F3: case BTN_PLAYER2_DIR2:
player2_dir = (player2_dir + 1) % 4; player2_dir = (player2_dir + 1) % 4;
break; break;
#endif
case BUTTON_RC_VOL_UP: #ifdef REMOTE
case BTN_RC_UP:
player3_dir = (player3_dir + 1) % 4; player3_dir = (player3_dir + 1) % 4;
break; break;
case BUTTON_RC_VOL_DOWN: case BTN_RC_DOWN:
player3_dir = (player3_dir + 3) % 4; player3_dir = (player3_dir + 3) % 4;
break; break;
#endif
case BUTTON_PLAY: case BTN_STARTPAUSE:
do { do {
button = rb->button_get(true); button = rb->button_get(true);
} while (button != BUTTON_PLAY && } while (button != BTN_STARTPAUSE &&
button != BUTTON_OFF && button != BTN_QUIT &&
button != BUTTON_ON); button != BTN_STOPRESET);
break; break;
} }
@ -1377,7 +1479,7 @@ static bool run(void)
} }
score_board(); score_board();
rb->lcd_update(); rb->lcd_update();
if (button == BUTTON_ON) { if (button == BTN_STOPRESET) {
wormDead = true; wormDead = true;
} }
@ -1478,7 +1580,6 @@ static void test_worm_food_collision(void) {
} }
static bool expensive_worm_in_rect(struct worm *w, int rx, int ry, int rw, int rh){ static bool expensive_worm_in_rect(struct worm *w, int rx, int ry, int rw, int rh){
int x, y; int x, y;
bool retVal = false; bool retVal = false;
@ -1876,10 +1977,10 @@ static void test_worm_argh_collision_in_moves(void) {
rb->snprintf(buf, sizeof buf, "in 5 moves hits: %d", hit_count); rb->snprintf(buf, sizeof buf, "in 5 moves hits: %d", hit_count);
rb->lcd_putsxy(0, LCD_HEIGHT - 8, buf); rb->lcd_putsxy(0, LCD_HEIGHT - 8, buf);
rb->lcd_update(); rb->lcd_update();
} }
if (hit_count != ARGH_SIZE + 5) { if (hit_count != ARGH_SIZE + 5) {
rb->button_get(true); rb->button_get(true);
} }
} }
#endif /* DEBUG_WORMLET */ #endif /* DEBUG_WORMLET */
@ -1892,12 +1993,16 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{ {
bool worm_dead = false; bool worm_dead = false;
int button; int button;
(void)(parameter); (void)(parameter);
rb = api; rb = api;
rb->lcd_setfont(FONT_SYSFIXED); rb->lcd_setfont(FONT_SYSFIXED);
#ifdef COLOR_LCD
rb->lcd_set_background(LCD_RGBPACK(200, 210, 230));
#endif
#ifdef DEBUG_WORMLET #ifdef DEBUG_WORMLET
testline_in_rect(); testline_in_rect();
test_worm_argh_collision_in_moves(); test_worm_argh_collision_in_moves();
@ -1905,47 +2010,65 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
test_worm_food_collision(); test_worm_food_collision();
test_worm_argh_collision(); test_worm_argh_collision();
test_specific_worm_collision(); test_specific_worm_collision();
#endif #endif
/* Setup screen */ /* Setup screen */
do { do {
char buf[20]; char buf[40];
char* ptr; char* ptr;
rb->lcd_clear_display(); rb->lcd_clear_display();
/* first line players */ /* first line players */
rb->snprintf(buf, sizeof buf, "%d Players UP/DN", players); #ifdef MULTIPLAYER
rb->snprintf(buf, sizeof buf, "%d Players (%s)", players, PLAYERS_TEXT);
#else
rb->snprintf(buf, sizeof buf, "1 Player");
#endif
rb->lcd_puts(0, 0, buf); rb->lcd_puts(0, 0, buf);
/* second line worms */ /* second line worms */
rb->snprintf(buf, sizeof buf, "%d Worms L/R", worm_count); rb->snprintf(buf, sizeof buf, "%d Worms (%s)", worm_count, WORMS_TEXT);
rb->lcd_puts(0, 1, buf); rb->lcd_puts(0, 1, buf);
#if defined MULTIPLAYER && defined REMOTE
/* third line control */ /* third line control */
if (players > 1) { if (players > 1) {
if (use_remote) { if (use_remote) {
ptr = "Remote Control F1"; rb->snprintf(buf, sizeof(buf), "Remote Control (%s)", KEY_CONTROL_TEXT);
ptr = buf;
} else { } else {
ptr = "No Rem. Control F1"; rb->snprintf(buf, sizeof(buf), "No Rem. Control (%s)", KEY_CONTROL_TEXT);
ptr = buf;
} }
} else { } else {
if (players > 0) { if (players > 0) {
if (use_remote) { if (use_remote) {
ptr = "2 Key Control F1"; rb->snprintf(buf, sizeof(buf), "2 Key Control (%s)", KEY_CONTROL_TEXT);
ptr = buf;
} else { } else {
ptr = "4 Key Control F1"; rb->snprintf(buf, sizeof(buf), "4 Key Control (%s)", KEY_CONTROL_TEXT);
ptr = buf;
} }
} else { } else {
ptr = "Out Of Control"; ptr = "Out Of Control";
} }
} }
rb->lcd_puts(0, 2, ptr); rb->lcd_puts(0, 2, ptr);
#endif
rb->lcd_update(); rb->lcd_update();
/* user selection */ /* user selection */
button = rb->button_get(true); button = rb->button_get(true);
switch (button) { switch (button) {
case BUTTON_UP: #ifdef MULTIPLAYER
case BTN_TOGGLE_KEYS:
use_remote = !use_remote;
if (players > 2) {
use_remote = true;
}
break;
case BTN_DIR_UP:
if (players < 3) { if (players < 3) {
players ++; players ++;
if (players > worm_count) { if (players > worm_count) {
@ -1956,12 +2079,14 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
} }
} }
break; break;
case BUTTON_DOWN:
case BTN_DIR_DOWN:
if (players > 0) { if (players > 0) {
players --; players --;
} }
break; break;
case BUTTON_LEFT: #endif
case BTN_DIR_LEFT:
if (worm_count > 1) { if (worm_count > 1) {
worm_count--; worm_count--;
if (worm_count < players) { if (worm_count < players) {
@ -1969,56 +2094,49 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
} }
} }
break; break;
case BUTTON_RIGHT:
case BTN_DIR_RIGHT:
if (worm_count < MAX_WORMS) { if (worm_count < MAX_WORMS) {
worm_count ++; worm_count ++;
} }
break; break;
case BUTTON_F1:
use_remote = !use_remote;
if (players > 2) {
use_remote = true;
}
break;
default: default:
if (rb->default_event_handler(button) == SYS_USB_CONNECTED) if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
return PLUGIN_USB_CONNECTED; return PLUGIN_USB_CONNECTED;
break; break;
} }
} while (button != BUTTON_PLAY && } while (button != BTN_STARTPAUSE &&
button != BUTTON_OFF && button != BUTTON_ON); button != BTN_QUIT && button != BTN_STOPRESET);
rb->lcd_clear_display(); rb->lcd_clear_display();
/* end of setup */ /* end of setup */
do { do {
/* button state will be overridden if /* button state will be overridden if
the game quits with the death of the worm. the game quits with the death of the worm.
Initializing button to BUTTON_OFF ensures Initializing button to BTN_QUIT ensures
that the user can hit BUTTON_OFF during the that the user can hit BTN_QUIT during the
game to return to the menu. game to return to the menu.
*/ */
button = BUTTON_OFF; button = BTN_QUIT;
/* start the game */ /* start the game */
worm_dead = run(); worm_dead = run();
/* if worm isn't dead the game was quit /* if worm isn't dead the game was quit
via BUTTON_OFF -> no need to wait for buttons. */ via BTN_QUIT -> no need to wait for buttons. */
if (worm_dead) { if (worm_dead) {
do { do {
button = rb->button_get(true); button = rb->button_get(true);
} }
/* BUTTON_ON -> start new game */ /* BTN_STOPRESET -> start new game */
/* BUTTON_OFF -> back to game menu */ /* BTN_QUIT -> back to game menu */
while (button != BUTTON_OFF && button != BUTTON_ON); while (button != BTN_QUIT && button != BTN_STOPRESET);
} }
} }
while (button != BUTTON_OFF); while (button != BTN_QUIT);
return PLUGIN_OK; return PLUGIN_OK;
} }
#endif