2006-03-12 09:35:53 +00:00
/***************************************************************************
* __________ __ ___ .
* Open \ ______ \ ____ ____ | | _ \ _ | __ _______ ___
* Source | _ // _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( < _ > ) \ ___ | < | \ _ \ ( < _ > > < <
* Firmware | ____ | _ / \ ____ / \ ___ > __ | _ \ | ___ / \ ____ / __ / \ _ \
* \ / \ / \ / \ / \ /
* $ Id $
*
* Copyright ( C ) 2006 Eli Sherer
2007-06-03 17:34:23 +00:00
* 2007 Antoine Cellerier
2006-03-12 09:35:53 +00:00
*
* 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"
PLUGIN_HEADER
# if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
# define QUIT BUTTON_OFF
# define LEFT BUTTON_LEFT
# define RIGHT BUTTON_RIGHT
# define PAUSE BUTTON_MODE
# define UP BUTTON_UP
# define DOWN BUTTON_DOWN
# define SELECT BUTTON_SELECT
2006-06-30 16:43:47 +00:00
# define RC_QUIT BUTTON_RC_STOP
2007-01-14 13:48:09 +00:00
# elif (CONFIG_KEYPAD == ARCHOS_AV300_PAD)
# define QUIT BUTTON_OFF
# define LEFT BUTTON_LEFT
# define RIGHT BUTTON_RIGHT
# define PAUSE BUTTON_ON
# define UP BUTTON_UP
# define DOWN BUTTON_DOWN
# define SELECT BUTTON_SELECT
2006-03-12 09:35:53 +00:00
# elif (CONFIG_KEYPAD == IPOD_3G_PAD) || \
( CONFIG_KEYPAD = = IPOD_4G_PAD )
# define QUIT (BUTTON_SELECT | BUTTON_MENU)
# define LEFT BUTTON_LEFT
# define RIGHT BUTTON_RIGHT
# define PAUSE BUTTON_SELECT
# define SELECT BUTTON_SELECT
2006-05-23 03:33:02 +00:00
# define MENU_UP BUTTON_SCROLL_FWD
# define MENU_DOWN BUTTON_SCROLL_BACK
2006-03-12 09:35:53 +00:00
# define UP BUTTON_MENU
# define DOWN BUTTON_PLAY
2007-03-16 23:02:39 +00:00
# elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
2006-03-12 09:35:53 +00:00
# define QUIT BUTTON_POWER
# define LEFT BUTTON_LEFT
# define RIGHT BUTTON_RIGHT
# define SELECT BUTTON_SELECT
# define UP BUTTON_UP
# define DOWN BUTTON_DOWN
# define PAUSE BUTTON_PLAY
# elif (CONFIG_KEYPAD == GIGABEAT_PAD)
2007-05-19 23:38:09 +00:00
# define QUIT BUTTON_POWER
2006-03-12 09:35:53 +00:00
# define LEFT BUTTON_LEFT
# define RIGHT BUTTON_RIGHT
# define SELECT BUTTON_SELECT
# define UP BUTTON_UP
# define DOWN BUTTON_DOWN
2007-05-19 23:38:09 +00:00
# define PAUSE BUTTON_A
2006-03-12 09:35:53 +00:00
2006-10-26 13:38:09 +00:00
# elif (CONFIG_KEYPAD == SANSA_E200_PAD)
# define QUIT BUTTON_POWER
# define LEFT BUTTON_LEFT
# define RIGHT BUTTON_RIGHT
# define SELECT BUTTON_SELECT
# define UP BUTTON_UP
# define DOWN BUTTON_DOWN
# define PAUSE BUTTON_REC
2006-08-03 20:17:25 +00:00
# elif CONFIG_KEYPAD == IRIVER_H10_PAD
# define QUIT BUTTON_POWER
# define LEFT BUTTON_LEFT
# define RIGHT BUTTON_RIGHT
# define SELECT BUTTON_REW
# define UP BUTTON_SCROLL_UP
# define DOWN BUTTON_SCROLL_DOWN
# define PAUSE BUTTON_PLAY
2006-03-12 09:35:53 +00:00
# else
# error Unsupported keypad
# endif
# define MOVE_NO 0 /* player movement */
# define MOVE_UP 1 /* 1 */
# define MOVE_DN 2 /* 3 0 4 */
# define MOVE_LT 3 /* 2 */
# define MOVE_RT 4
2007-06-03 17:34:23 +00:00
/* ball movement (12 ways) */
/* UUL UR */
/* UL UR */
/* ULL . URR */
/* DLL DRR */
/* DL DR */
/* DDL DDR */
# define DIR_UU (1<<7)
# define DIR_U (1<<6)
# define DIR_RR (1<<5)
# define DIR_R (1<<4)
# define DIR_DD (1<<3)
# define DIR_D (1<<2)
# define DIR_LL (1<<1)
# define DIR_L (1<<0)
# define MOVE_UUR ( DIR_UU | DIR_R )
# define MOVE_UR ( DIR_U | DIR_R )
# define MOVE_URR ( DIR_U | DIR_RR )
# define MOVE_DRR ( DIR_D | DIR_RR )
# define MOVE_DR ( DIR_D | DIR_R )
# define MOVE_DDR ( DIR_DD | DIR_R )
# define MOVE_DDL ( DIR_DD | DIR_L )
# define MOVE_DL ( DIR_D | DIR_L )
# define MOVE_DLL ( DIR_D | DIR_LL )
# define MOVE_ULL ( DIR_U | DIR_LL )
# define MOVE_UL ( DIR_U | DIR_L )
# define MOVE_UUL ( DIR_UU | DIR_L )
2006-03-12 09:35:53 +00:00
# define CUBE_SIZE 8 /* 8x22=176 */
# define STARTING_QIXES 2
# define MAX_LEVEL 10
# define MAX_QIXES MAX_LEVEL+STARTING_QIXES
# define BOARD_W ((int)LCD_WIDTH / CUBE_SIZE)
# define BOARD_H ((int)LCD_HEIGHT / CUBE_SIZE)
# define BOARD_X (LCD_WIDTH-BOARD_W*CUBE_SIZE) / 2
# define BOARD_Y (LCD_HEIGHT-BOARD_H*CUBE_SIZE) / 2
# ifdef HAVE_LCD_COLOR
2006-05-23 03:57:35 +00:00
# define CLR_RED LCD_RGBPACK(255,0,0) /* used to imply danger */
# define CLR_LTBLUE LCD_RGBPACK(125, 145, 180) /* used for frame and filling */
# define PLR_COL LCD_WHITE /* color used for the player */
2006-03-12 09:35:53 +00:00
# else
2006-05-23 03:57:35 +00:00
# define CLR_RED LCD_DARKGRAY /* used to imply danger */
# define CLR_LTBLUE LCD_LIGHTGRAY /* used for frame and filling */
# define PLR_COL LCD_BLACK /* color used for the player */
2006-03-12 09:35:53 +00:00
# endif
# define EMPTIED LCD_BLACK /* empty spot */
2006-05-23 03:57:35 +00:00
# define FILLED CLR_LTBLUE /* filled spot */
2006-03-12 09:35:53 +00:00
# define TRAIL CLR_RED /* the red trail of the player */
# define QIX LCD_WHITE
# define UNCHECKED 0
# define CHECKED 1
# define PIC_QIX 0
# define PIC_PLAYER 1
2007-03-25 17:52:56 +00:00
# define MENU_START 0
# define MENU_QUIT 1
2006-03-12 09:35:53 +00:00
/* The time (in ms) for one iteration through the game loop - decrease this
to speed up the game - note that current_tick is ( currently ) only accurate
to 10 ms .
*/
# define CYCLETIME 50
static struct plugin_api * rb ;
static bool quit = false ;
2007-06-03 17:34:23 +00:00
static unsigned int board [ BOARD_H ] [ BOARD_W ] ,
2006-03-12 09:35:53 +00:00
testboard [ BOARD_H ] [ BOARD_W ] , boardcopy [ BOARD_H ] [ BOARD_W ] ;
/*
2007-06-03 17:34:23 +00:00
00011000 0x18 - 11100111 0xe7
00111100 0x3c - 11100111 0xe7
01111110 0x7e - 11000011 0xc3
11111111 0xff - 00000000 0x00
11111111 0xff - 00000000 0x00
01111110 0x7e - 11000011 0xc3
00111100 0x3c - 11100111 0xe7
00011000 0x18 - 11100111 0xe7
2006-03-12 09:35:53 +00:00
*/
const unsigned char pics [ 2 ] [ 8 ] = {
2007-06-03 17:34:23 +00:00
{ 0x18 , 0x3c , 0x7e , 0xff , 0xff , 0x7e , 0x3c , 0x18 } , /* Alien (QIX) */
{ 0xe7 , 0xe7 , 0xc3 , 0x00 , 0x00 , 0xc3 , 0xe7 , 0xe7 } /* Player (XONIX) */
2006-03-12 09:35:53 +00:00
} ;
static struct qix
{
2007-06-03 17:34:23 +00:00
int velocity ; /* velocity */
int x , y ; /* position on screen */
int angle ; /* angle */
2006-03-12 09:35:53 +00:00
} qixes [ MAX_QIXES ] ; /* black_qix */
static struct splayer
{
2007-06-03 17:34:23 +00:00
int i , j ; /* position on board */
int move , score , level , lives ;
2006-03-12 09:35:53 +00:00
bool drawing ;
bool gameover ;
} player ;
2007-06-03 17:34:23 +00:00
static int percentage_cache ;
2006-03-12 09:35:53 +00:00
/*************************** STACK STUFF **********************/
/* the stack */
# define STACK_SIZE BOARD_W*BOARD_H
static struct pos
{
int x , y ; /* position on board */
} stack [ STACK_SIZE ] ;
static int stackPointer ;
2006-03-17 13:38:45 +00:00
# define div(a,b) (((a) / (b)))
2007-06-03 17:34:23 +00:00
# if CUBE_SIZE == 8
# define pos(a) ((a)>>3)
# else
# define pos(a) div((a),CUBE_SIZE)
# endif
2006-03-12 09:35:53 +00:00
2007-06-03 17:34:23 +00:00
static inline bool pop ( struct pos * p )
2006-03-12 09:35:53 +00:00
{
if ( stackPointer > 0 ) {
p - > x = stack [ stackPointer ] . x ;
p - > y = stack [ stackPointer ] . y ;
stackPointer - - ;
return true ;
} else
return false ; /* SE */
}
2007-06-03 17:34:23 +00:00
static inline bool push ( struct pos * p )
2006-03-12 09:35:53 +00:00
{
if ( stackPointer < STACK_SIZE - 1 ) {
stackPointer + + ;
stack [ stackPointer ] . x = p - > x ;
stack [ stackPointer ] . y = p - > y ;
return true ;
} else
return false ; /* SOF */
}
2007-06-03 17:34:23 +00:00
static inline void emptyStack ( void )
2006-03-12 09:35:53 +00:00
{
stackPointer = 0 ;
}
/*********************** END OF STACK STUFF *********************/
/* calculate the new x coordinate of the ball according to angle and speed */
2007-06-03 17:34:23 +00:00
static inline int get_newx ( int x , int len , int deg )
2006-03-12 09:35:53 +00:00
{
2007-06-03 17:34:23 +00:00
if ( deg & DIR_R )
return x + len ;
else if ( deg & DIR_L )
return x - len ;
else if ( deg & DIR_RR )
return x + len * 2 ;
else /* (def & DIR_LL) */
return x - len * 2 ;
2006-03-12 09:35:53 +00:00
}
/* calculate the new y coordinate of the ball according to angle and speed */
2007-06-03 17:34:23 +00:00
static inline int get_newy ( int y , int len , int deg )
2006-03-12 09:35:53 +00:00
{
2007-06-03 17:34:23 +00:00
if ( deg & DIR_D )
return y + len ;
else if ( deg & DIR_U )
return y - len ;
else if ( deg & DIR_DD )
return y + len * 2 ;
else /* (deg & DIR_UU) */
return y - len * 2 ;
2006-03-12 09:35:53 +00:00
}
/* make random function get it's value from the device ticker */
static inline void randomize ( void )
{
rb - > srand ( * rb - > current_tick ) ;
}
/* get a random number between 0 and range-1 */
static int t_rand ( int range )
{
return rb - > rand ( ) % range ;
}
/* initializes the test help board */
static void init_testboard ( void )
{
2007-06-03 17:34:23 +00:00
int j ; /* testboard */
2006-03-12 09:35:53 +00:00
for ( j = 0 ; j < BOARD_H ; j + + )
2007-06-03 17:34:23 +00:00
/* UNCHEKED == (int)0 */
rb - > memset ( testboard [ j ] , 0 , BOARD_W * sizeof ( int ) ) ;
2006-03-12 09:35:53 +00:00
}
/* initializes the game board on with the player,qix's and black qix */
static void init_board ( void )
{
int i , j ;
for ( j = 0 ; j < BOARD_H ; j + + )
for ( i = 0 ; i < BOARD_W ; i + + ) { /* make a nice cyan frame */
2006-09-17 15:07:11 +00:00
if ( ( i = = 0 ) | | ( j < = 1 ) | | ( i = = BOARD_W - 1 )
| | ( j > = BOARD_H - 2 ) )
2006-03-12 09:35:53 +00:00
board [ j ] [ i ] = FILLED ;
else
board [ j ] [ i ] = EMPTIED ;
}
/* (level+2) is the number of qixes */
for ( j = 0 ; j < player . level + STARTING_QIXES ; j + + ) {
qixes [ j ] . velocity = t_rand ( 2 ) + 1 ; /* 1 or 2 pix-per-sec */
/* not on frame */
qixes [ j ] . x =
BOARD_X + t_rand ( ( ( BOARD_W - 4 ) * CUBE_SIZE ) - 2 * CUBE_SIZE ) +
2 * CUBE_SIZE ;
qixes [ j ] . y =
BOARD_Y + t_rand ( ( ( BOARD_H - 6 ) * CUBE_SIZE ) - 2 * CUBE_SIZE ) +
3 * CUBE_SIZE ;
2007-06-03 17:34:23 +00:00
switch ( t_rand ( 12 ) ) {
# define ANGLE_CASE(a,b) \
case a : \
qixes [ j ] . angle = MOVE_ # # b ; \
break ;
ANGLE_CASE ( 0 , UR ) ;
ANGLE_CASE ( 1 , URR ) ;
ANGLE_CASE ( 2 , DRR ) ;
ANGLE_CASE ( 3 , DR ) ;
ANGLE_CASE ( 4 , DDR ) ;
ANGLE_CASE ( 5 , DDL ) ;
ANGLE_CASE ( 6 , DL ) ;
ANGLE_CASE ( 7 , DLL ) ;
ANGLE_CASE ( 8 , ULL ) ;
ANGLE_CASE ( 9 , UL ) ;
ANGLE_CASE ( 10 , UUL ) ;
ANGLE_CASE ( 11 , UUR ) ;
# undef ANGLE_CASE
}
2006-03-12 09:35:53 +00:00
}
/*black_qix.velocity=1;
black_qix . x = BOARD_X + ( BOARD_W * CUBE_SIZE ) / 2 - CUBE_SIZE / 2 ;
black_qix . y = BOARD_Y + ( BOARD_H * CUBE_SIZE ) - CUBE_SIZE - CUBE_SIZE / 2 ;
black_qix . angle = MOVE_UR ; */
player . move = MOVE_NO ;
player . drawing = false ;
player . i = BOARD_W / 2 ;
player . j = 1 ;
2007-06-03 17:34:23 +00:00
percentage_cache = 0 ;
2006-03-12 09:35:53 +00:00
}
/* calculates the percentage of the screen filling */
static int percentage ( void )
{
int i , j , filled = 0 ;
for ( j = 2 ; j < BOARD_H - 2 ; j + + )
for ( i = 1 ; i < BOARD_W - 1 ; i + + )
if ( board [ j ] [ i ] = = FILLED )
filled + + ;
2007-06-03 21:09:32 +00:00
return ( filled * 100 ) / ( ( BOARD_W - 2 ) * ( BOARD_H - 4 ) ) ;
2006-03-12 09:35:53 +00:00
}
/* draw the board on with all the game figures */
static void refresh_board ( void )
{
int i , j ;
char str [ 25 ] ;
rb - > lcd_set_background ( LCD_BLACK ) ;
for ( j = 0 ; j < BOARD_H ; j + + )
2006-09-17 15:07:11 +00:00
{
unsigned last_color = board [ j ] [ 0 ] ;
int last_i = 0 ;
for ( i = 1 ; i < BOARD_W ; i + + ) {
if ( last_color ! = board [ j ] [ i ] )
{
rb - > lcd_set_foreground ( last_color ) ;
rb - > lcd_fillrect ( BOARD_X + CUBE_SIZE * ( last_i ) ,
BOARD_Y + CUBE_SIZE * j ,
CUBE_SIZE * ( i - last_i ) , CUBE_SIZE ) ;
last_color = board [ j ] [ i ] ;
last_i = i ;
}
2006-03-12 09:35:53 +00:00
}
2006-09-17 15:07:11 +00:00
rb - > lcd_set_foreground ( last_color ) ;
rb - > lcd_fillrect ( BOARD_X + CUBE_SIZE * ( last_i ) ,
BOARD_Y + CUBE_SIZE * j ,
CUBE_SIZE * ( i - last_i ) , CUBE_SIZE ) ;
}
2007-06-03 21:09:32 +00:00
2006-03-12 09:35:53 +00:00
rb - > lcd_set_foreground ( LCD_BLACK ) ;
2006-05-23 03:57:35 +00:00
rb - > lcd_set_background ( CLR_LTBLUE ) ;
2006-03-12 09:35:53 +00:00
rb - > snprintf ( str , sizeof ( str ) , " Level %d " , player . level + 1 ) ;
rb - > lcd_putsxy ( BOARD_X , BOARD_Y , str ) ;
2007-06-03 17:34:23 +00:00
rb - > snprintf ( str , sizeof ( str ) , " %d%% " , percentage_cache ) ;
2006-03-12 09:35:53 +00:00
rb - > lcd_putsxy ( BOARD_X + CUBE_SIZE * BOARD_W - 24 , BOARD_Y , str ) ;
rb - > snprintf ( str , sizeof ( str ) , " Score: %d " , player . score ) ;
rb - > lcd_putsxy ( BOARD_X , BOARD_Y + CUBE_SIZE * BOARD_H - 8 , str ) ;
rb - > snprintf ( str , sizeof ( str ) , " %d Lives " , player . lives ) ;
rb - > lcd_putsxy ( BOARD_X + CUBE_SIZE * BOARD_W - 60 ,
BOARD_Y + CUBE_SIZE * BOARD_H - 8 , str ) ;
2006-03-22 17:47:31 +00:00
rb - > lcd_set_foreground ( PLR_COL ) ;
2006-03-12 09:35:53 +00:00
rb - > lcd_set_background ( board [ player . j ] [ player . i ] ) ;
rb - > lcd_mono_bitmap ( pics [ PIC_PLAYER ] , player . i * CUBE_SIZE + BOARD_X ,
player . j * CUBE_SIZE + BOARD_Y , CUBE_SIZE , CUBE_SIZE ) ;
2007-06-03 21:09:32 +00:00
2006-03-12 09:35:53 +00:00
rb - > lcd_set_background ( EMPTIED ) ;
2007-06-03 17:34:23 +00:00
rb - > lcd_set_drawmode ( DRMODE_FG ) ;
2006-03-22 17:47:31 +00:00
rb - > lcd_set_foreground ( LCD_WHITE ) ;
2006-03-12 09:35:53 +00:00
for ( j = 0 ; j < player . level + STARTING_QIXES ; j + + )
rb - > lcd_mono_bitmap ( pics [ PIC_QIX ] , qixes [ j ] . x + BOARD_X ,
qixes [ j ] . y + BOARD_Y , CUBE_SIZE , CUBE_SIZE ) ;
2007-06-03 17:34:23 +00:00
rb - > lcd_set_drawmode ( DRMODE_SOLID ) ;
2006-03-12 09:35:53 +00:00
rb - > lcd_set_foreground ( LCD_BLACK ) ;
rb - > lcd_update ( ) ;
}
static inline int infested_area ( int i , int j )
{
2007-06-03 17:34:23 +00:00
struct pos p ;
2006-03-12 09:35:53 +00:00
p . x = i ;
p . y = j ;
emptyStack ( ) ;
init_testboard ( ) ;
if ( ! push ( & p ) )
return - 1 ;
2006-03-17 13:38:45 +00:00
while ( pop ( & p ) ) {
2006-03-12 09:35:53 +00:00
testboard [ p . y ] [ p . x ] = CHECKED ;
2007-06-03 17:48:25 +00:00
if ( ( boardcopy [ p . y ] [ p . x ] = = QIX ) )
return 1 ;
2007-06-03 17:34:23 +00:00
{
struct pos p1 = { p . x + 1 , p . y } ;
if ( ( p1 . x < BOARD_W ) & & ( testboard [ p1 . y ] [ p1 . x ] = = UNCHECKED ) )
if ( board [ p1 . y ] [ p1 . x ] ! = FILLED )
if ( ! push ( & p1 ) )
return - 1 ;
}
{
struct pos p1 = { p . x - 1 , p . y } ;
if ( ( p1 . x > = 0 ) & & ( testboard [ p1 . y ] [ p1 . x ] = = UNCHECKED ) )
if ( board [ p1 . y ] [ p1 . x ] ! = FILLED )
if ( ! push ( & p1 ) )
return - 1 ;
}
{
struct pos p1 = { p . x , p . y + 1 } ;
if ( ( p1 . y < BOARD_H ) & & ( testboard [ p1 . y ] [ p1 . x ] = = UNCHECKED ) )
if ( board [ p1 . y ] [ p1 . x ] ! = FILLED )
if ( ! push ( & p1 ) )
return - 1 ;
}
{
struct pos p1 = { p . x , p . y - 1 } ;
if ( ( p1 . y > = 0 ) & & ( testboard [ p1 . y ] [ p1 . x ] = = UNCHECKED ) )
if ( board [ p1 . y ] [ p1 . x ] ! = FILLED )
if ( ! push ( & p1 ) )
return - 1 ;
}
2006-03-12 09:35:53 +00:00
}
2007-06-03 17:48:25 +00:00
return 0 ;
2006-03-12 09:35:53 +00:00
}
static inline int fill_area ( int i , int j )
{
2007-06-03 17:34:23 +00:00
struct pos p ;
2006-03-12 09:35:53 +00:00
p . x = i ;
p . y = j ;
emptyStack ( ) ;
init_testboard ( ) ;
if ( ! push ( & p ) )
return - 1 ;
while ( pop ( & p ) ) {
board [ p . y ] [ p . x ] = FILLED ;
testboard [ p . y ] [ p . x ] = CHECKED ;
2007-06-03 17:34:23 +00:00
{
struct pos p1 = { p . x + 1 , p . y } ;
if ( ( p1 . x < BOARD_W ) & & ( testboard [ p1 . y ] [ p1 . x ] = = UNCHECKED ) )
if ( board [ p1 . y ] [ p1 . x ] = = EMPTIED )
if ( ! push ( & p1 ) )
return - 1 ;
}
{
struct pos p1 = { p . x - 1 , p . y } ;
if ( ( p1 . x > = 0 ) & & ( testboard [ p1 . y ] [ p1 . x ] = = UNCHECKED ) )
if ( board [ p1 . y ] [ p1 . x ] = = EMPTIED )
if ( ! push ( & p1 ) )
return - 1 ;
}
{
struct pos p1 = { p . x , p . y + 1 } ;
if ( ( p1 . y < BOARD_H ) & & ( testboard [ p1 . y ] [ p1 . x ] = = UNCHECKED ) )
if ( board [ p1 . y ] [ p1 . x ] = = EMPTIED )
if ( ! push ( & p1 ) )
return - 1 ;
}
{
struct pos p1 = { p . x , p . y - 1 } ;
if ( ( p1 . y > = 0 ) & & ( testboard [ p1 . y ] [ p1 . x ] = = UNCHECKED ) )
if ( board [ p1 . y ] [ p1 . x ] = = EMPTIED )
if ( ! push ( & p1 ) )
return - 1 ;
}
2006-03-12 09:35:53 +00:00
}
return 1 ;
}
/* take care of stuff after xonix has landed on a filled spot */
2006-03-17 13:38:45 +00:00
static void complete_trail ( int fill )
2006-03-12 09:35:53 +00:00
{
int i , j , ret ;
2007-06-03 17:34:23 +00:00
for ( j = 0 ; j < BOARD_H ; j + + ) {
2006-03-17 13:38:45 +00:00
for ( i = 0 ; i < BOARD_W ; i + + ) {
if ( board [ j ] [ i ] = = TRAIL ) {
if ( fill )
board [ j ] [ i ] = FILLED ;
else
board [ j ] [ i ] = EMPTIED ;
}
2007-06-03 17:34:23 +00:00
/*boardcopy[j][i] = board[j][i];*/
2006-03-17 13:38:45 +00:00
}
2007-06-03 17:34:23 +00:00
rb - > memcpy ( boardcopy [ j ] , board [ j ] , BOARD_W * sizeof ( int ) ) ;
}
2006-03-17 13:38:45 +00:00
if ( fill ) {
for ( i = 0 ; i < player . level + STARTING_QIXES ; i + + ) /* add qixes to board */
2007-06-03 17:34:23 +00:00
boardcopy [ pos ( qixes [ i ] . y - BOARD_Y ) ]
[ pos ( qixes [ i ] . x - BOARD_X ) ] = QIX ;
2006-05-23 03:33:02 +00:00
2007-06-03 17:34:23 +00:00
init_testboard ( ) ;
2006-03-17 13:38:45 +00:00
for ( j = 1 ; j < BOARD_H - 1 ; j + + )
for ( i = 0 ; i < BOARD_W - 0 ; i + + )
2007-06-03 17:34:23 +00:00
if ( board [ j ] [ i ] ! = FILLED & & testboard [ j ] [ i ] ! = CHECKED /* testboard[i][j] == CHECKED means that this is part of an infested area tested on the previous run */ ) {
2006-03-17 13:38:45 +00:00
ret = infested_area ( i , j ) ;
2006-09-17 15:07:11 +00:00
if ( ret < 0 | | ( ret = = 0 & & fill_area ( i , j ) < 0 ) )
2006-03-12 09:35:53 +00:00
quit = true ;
}
2007-06-03 17:34:23 +00:00
percentage_cache = percentage ( ) ;
2006-03-17 13:38:45 +00:00
}
2006-05-23 03:57:35 +00:00
rb - > button_clear_queue ( ) ;
2006-03-12 09:35:53 +00:00
}
/* returns the color the real pixel(x,y) on the lcd is pointing at */
2007-06-03 17:34:23 +00:00
static inline unsigned int getpixel ( int x , int y )
2006-03-12 09:35:53 +00:00
{
2007-06-03 17:34:23 +00:00
const int a = pos ( x - BOARD_X ) , b = pos ( y - BOARD_Y ) ;
2006-03-12 09:35:53 +00:00
if ( ( a > 0 ) & & ( a < BOARD_W ) & & ( b > 0 ) & & ( b < BOARD_H ) ) /* if inside board */
return board [ b ] [ a ] ;
else
return FILLED ;
}
/* returns the color the ball on (newx,newy) is heading at *----*
checks the four edge points of the square if 1 st of all | |
are a trail ( cause it ' s a lose life situation ) and 2 nd | |
if it ' s filled so it needs to bounce . * ____ *
*/
2007-06-03 17:34:23 +00:00
static inline unsigned int next_hit ( int newx , int newy )
2006-03-12 09:35:53 +00:00
{
if ( ( getpixel ( newx , newy ) = = TRAIL )
| | ( getpixel ( newx , newy + CUBE_SIZE - 1 ) = = TRAIL )
| | ( getpixel ( newx + CUBE_SIZE - 1 , newy ) = = TRAIL )
| | ( getpixel ( newx + CUBE_SIZE - 1 , newy + CUBE_SIZE - 1 ) = = TRAIL ) )
return TRAIL ;
else if ( ( getpixel ( newx , newy ) = = FILLED )
| | ( getpixel ( newx , newy + CUBE_SIZE - 1 ) = = FILLED )
| | ( getpixel ( newx + CUBE_SIZE - 1 , newy ) = = FILLED )
| | ( getpixel ( newx + CUBE_SIZE - 1 , newy + CUBE_SIZE - 1 ) = =
FILLED ) )
return FILLED ;
else
return EMPTIED ;
}
2006-03-17 13:38:45 +00:00
static void die ( void )
{
player . lives - - ;
if ( player . lives = = 0 )
player . gameover = true ;
else {
refresh_board ( ) ;
2007-03-16 21:56:08 +00:00
rb - > splash ( HZ , " Crash! " ) ;
2006-03-17 13:38:45 +00:00
complete_trail ( false ) ;
player . move = MOVE_NO ;
player . drawing = false ;
player . i = BOARD_W / 2 ;
player . j = 1 ;
}
}
2007-06-03 17:34:23 +00:00
/* returns true if the (side) of the block -***-
starting from ( newx , newy ) has any filled pixels * *
- * * * -
*/
static inline bool line_check_lt ( int newx , int newy )
{
int i = 0 ;
for ( i = 3 ; i < CUBE_SIZE - 3 ; i + + ) {
if ( getpixel ( newx , newy + i ) ! = FILLED )
return false ;
}
return true ;
}
static inline bool line_check_rt ( int newx , int newy )
{
int i = 0 ;
for ( i = 3 ; i < CUBE_SIZE - 3 ; i + + ) {
if ( getpixel ( newx + CUBE_SIZE - 1 , newy + i ) ! = FILLED )
return false ;
}
return true ;
}
static inline bool line_check_up ( int newx , int newy )
{
int i = 0 ;
for ( i = 3 ; i < CUBE_SIZE - 3 ; i + + ) {
if ( getpixel ( newx + i , newy ) ! = FILLED )
return false ;
}
return true ;
}
static inline bool line_check_dn ( int newx , int newy )
{
int i = 0 ;
for ( i = 3 ; i < CUBE_SIZE - 3 ; i + + ) {
if ( getpixel ( newx + i , newy + CUBE_SIZE - 1 ) ! = FILLED )
return false ;
}
return true ;
}
static inline void move_qix ( struct qix * q )
2006-03-12 09:35:53 +00:00
{
2007-06-03 17:34:23 +00:00
int newx , newy ;
2006-03-12 09:35:53 +00:00
newx = get_newx ( q - > x , q - > velocity , q - > angle ) ;
newy = get_newy ( q - > y , q - > velocity , q - > angle ) ;
2007-06-03 17:48:25 +00:00
switch ( next_hit ( newx , newy ) )
{
case EMPTIED :
q - > x = newx ;
q - > y = newy ;
break ;
case FILLED :
{
const int a = q - > angle ;
q - > angle =
( ( a & ( DIR_UU | DIR_U ) )
? ( line_check_up ( newx , newy ) ? ( ( a & ( DIR_UU | DIR_U ) ) > > 4 )
: ( a & ( DIR_UU | DIR_U ) ) )
: 0 )
|
( ( a & ( DIR_RR | DIR_R ) )
? ( line_check_rt ( newx , newy ) ? ( ( a & ( DIR_RR | DIR_R ) ) > > 4 )
: ( a & ( DIR_RR | DIR_R ) ) )
: 0 )
|
( ( a & ( DIR_DD | DIR_D ) )
? ( line_check_dn ( newx , newy ) ? ( ( a & ( DIR_DD | DIR_D ) ) < < 4 )
: ( a & ( DIR_DD | DIR_D ) ) )
: 0 )
|
( ( a & ( DIR_LL | DIR_L ) )
? ( line_check_lt ( newx , newy ) ? ( ( a & ( DIR_LL | DIR_L ) ) < < 4 )
: ( a & ( DIR_LL | DIR_L ) ) )
: 0 ) ;
q - > x = get_newx ( q - > x , q - > velocity , q - > angle ) ;
q - > y = get_newy ( q - > y , q - > velocity , q - > angle ) ;
break ;
}
case TRAIL :
die ( ) ;
break ;
2006-03-12 09:35:53 +00:00
}
}
/* move the board forward timewise */
static inline void move_board ( void )
{
int j , newi , newj ;
for ( j = 0 ; j < player . level + STARTING_QIXES ; j + + )
move_qix ( & qixes [ j ] ) ;
/* move_qix(&black_qix,true); */
if ( player . move ) {
newi = player . i ;
newj = player . j ;
switch ( player . move ) {
case MOVE_UP :
if ( player . j > 1 )
newj - - ;
break ;
case MOVE_DN :
if ( player . j < BOARD_H - 2 )
newj + + ;
break ;
case MOVE_LT :
if ( player . i > 0 )
newi - - ;
break ;
case MOVE_RT :
if ( player . i < BOARD_W - 1 )
newi + + ;
break ;
default :
break ;
}
if ( ( player . drawing ) & & ( board [ newj ] [ newi ] = = EMPTIED ) ) /* continue drawing */
board [ newj ] [ newi ] = TRAIL ;
else if ( ( player . drawing ) & & ( board [ newj ] [ newi ] = = FILLED ) ) { /* finish drawing */
player . move = MOVE_NO ; /* stop moving */
player . drawing = false ;
2006-03-17 13:38:45 +00:00
complete_trail ( true ) ;
2006-03-12 09:35:53 +00:00
} else if ( ( board [ player . j ] [ player . i ] = = FILLED )
& & ( board [ newj ] [ newi ] = = EMPTIED ) ) {
/* start drawing */
player . drawing = true ;
board [ newj ] [ newi ] = TRAIL ;
2006-05-23 03:33:02 +00:00
/* if the block after next is empty and we're moving onto filled, stop */
} else if ( ( board [ newj ] [ newi ] = = FILLED )
& & ( board [ newj + newj - player . j ] [ newi + newi - player . i ] = = EMPTIED ) ) {
player . move = MOVE_NO ;
2006-03-12 09:35:53 +00:00
}
player . i = newi ;
player . j = newj ;
}
2007-06-03 17:48:25 +00:00
if ( percentage_cache > 75 ) { /* finished level */
2007-03-16 21:56:08 +00:00
rb - > splash ( HZ * 2 , " Level %d finished " , player . level + 1 ) ;
2007-06-03 17:48:25 +00:00
player . score + = percentage_cache ;
2006-03-12 09:35:53 +00:00
if ( player . level < MAX_LEVEL )
player . level + + ;
init_board ( ) ;
refresh_board ( ) ;
2007-03-16 21:56:08 +00:00
rb - > splash ( HZ * 2 , " Ready? " ) ;
2006-03-12 09:35:53 +00:00
}
}
/* the main menu */
static int game_menu ( void )
{
2007-03-25 14:31:56 +00:00
MENUITEM_STRINGLIST ( menu , " XOBOX Menu " , NULL , " Start New Game " , " Quit " ) ;
int selection = 0 ;
2007-03-25 14:42:14 +00:00
# ifdef HAVE_LCD_COLOR
2007-03-25 14:31:56 +00:00
rb - > lcd_set_foreground ( rb - > global_settings - > fg_color ) ;
rb - > lcd_set_background ( rb - > global_settings - > bg_color ) ;
2007-03-25 17:52:56 +00:00
# else
rb - > lcd_set_foreground ( LCD_BLACK ) ;
rb - > lcd_set_background ( LCD_WHITE ) ;
2007-03-25 14:42:14 +00:00
# endif
2007-03-25 14:31:56 +00:00
selection = rb - > do_menu ( & menu , NULL ) ;
if ( selection < 0 )
{
selection = MENU_QUIT ;
2006-03-12 09:35:53 +00:00
}
return selection ;
}
/* init game's variables */
static void init_game ( void )
{
player . level = 0 ;
player . score = 0 ;
player . lives = 3 ;
player . gameover = false ;
player . drawing = false ;
2006-05-23 03:33:02 +00:00
rb - > lcd_setfont ( FONT_SYSFIXED ) ;
2006-03-12 09:35:53 +00:00
init_board ( ) ;
refresh_board ( ) ;
2007-03-16 21:56:08 +00:00
rb - > splash ( HZ * 2 , " Ready? " ) ;
2006-03-12 09:35:53 +00:00
}
/* general keypad handler loop */
static int xobox_loop ( void )
{
int button = 0 , ret ;
bool pause = false ;
int end ;
while ( ! quit ) {
end = * rb - > current_tick + ( CYCLETIME * HZ ) / 1000 ;
2006-07-30 03:10:09 +00:00
# ifdef HAS_BUTTON_HOLD
if ( rb - > button_hold ( ) ) {
pause = true ;
2007-03-16 21:56:08 +00:00
rb - > splash ( HZ , " PAUSED " ) ;
2006-07-30 03:10:09 +00:00
}
# endif
2006-03-12 09:35:53 +00:00
button = rb - > button_get_w_tmo ( true ) ;
switch ( button ) {
case UP :
2006-05-23 03:57:35 +00:00
case UP | BUTTON_REPEAT :
2006-03-12 09:35:53 +00:00
player . move = MOVE_UP ;
break ;
case DOWN :
2006-05-23 03:57:35 +00:00
case DOWN | BUTTON_REPEAT :
2006-03-12 09:35:53 +00:00
player . move = MOVE_DN ;
break ;
case LEFT :
2006-05-23 03:57:35 +00:00
case LEFT | BUTTON_REPEAT :
2006-03-12 09:35:53 +00:00
player . move = MOVE_LT ;
break ;
case RIGHT :
2006-05-23 03:57:35 +00:00
case RIGHT | BUTTON_REPEAT :
2006-03-12 09:35:53 +00:00
player . move = MOVE_RT ;
break ;
case PAUSE :
pause = ! pause ;
if ( pause )
2007-03-16 21:56:08 +00:00
rb - > splash ( HZ , " Paused " ) ;
2006-03-12 09:35:53 +00:00
break ;
case QUIT :
2006-05-23 03:33:02 +00:00
ret = game_menu ( ) ;
if ( ret = = MENU_START )
init_game ( ) ;
else
2007-03-25 17:52:56 +00:00
{
2006-05-23 03:33:02 +00:00
quit = true ;
2007-03-25 17:52:56 +00:00
continue ;
}
2006-03-12 09:35:53 +00:00
break ;
default :
if ( rb - > default_event_handler ( button ) = = SYS_USB_CONNECTED )
return PLUGIN_USB_CONNECTED ;
break ;
}
if ( ! pause ) {
move_board ( ) ;
refresh_board ( ) ;
}
if ( player . gameover ) {
2007-03-16 21:56:08 +00:00
rb - > splash ( HZ , " Game Over! " ) ;
2006-03-12 09:35:53 +00:00
ret = game_menu ( ) ;
if ( ret = = MENU_START )
init_game ( ) ;
else
quit = true ;
}
if ( end > * rb - > current_tick )
rb - > sleep ( end - * rb - > current_tick ) ;
else
rb - > yield ( ) ;
} /* end while */
return PLUGIN_OK ; /* for no warnings on compiling */
}
/* plugin main procedure */
enum plugin_status plugin_start ( struct plugin_api * api , void * parameter )
{
2006-05-23 03:33:02 +00:00
int ret = PLUGIN_OK ;
2006-03-12 09:35:53 +00:00
( void ) parameter ;
rb = api ;
rb - > lcd_setfont ( FONT_SYSFIXED ) ;
2006-11-15 06:14:27 +00:00
rb - > lcd_set_backdrop ( NULL ) ;
2006-03-12 09:35:53 +00:00
/* Permanently enable the backlight (unless the user has turned it off) */
if ( rb - > global_settings - > backlight_timeout > 0 )
rb - > backlight_set_timeout ( 1 ) ;
2007-06-03 17:34:23 +00:00
2007-03-25 17:52:56 +00:00
quit = false ;
2006-03-12 09:35:53 +00:00
randomize ( ) ;
2006-03-16 08:20:57 +00:00
if ( game_menu ( ) = = MENU_START ) {
2006-03-12 09:35:53 +00:00
init_game ( ) ;
ret = xobox_loop ( ) ;
}
rb - > backlight_set_timeout ( rb - > global_settings - > backlight_timeout ) ;
rb - > lcd_setfont ( FONT_UI ) ;
2006-03-16 08:20:57 +00:00
return ret ;
2006-03-12 09:35:53 +00:00
}