1
0
Fork 0
forked from len0rd/rockbox

2048: service pack 1 :)

- fixed some bugs
- added 1-bit LCD support

Change-Id: I7bb458d79d799dcd6b11d9d538773404f9a7f97c
Reviewed-on: http://gerrit.rockbox.org/917
Reviewed-by: Michael Giacomelli <giac2000@hotmail.com>
This commit is contained in:
Franklin Wei 2014-08-19 15:20:19 -04:00 committed by Michael Giacomelli
parent a9713d89e7
commit 7ac0056beb

View file

@ -83,10 +83,10 @@
#define SCORE_Y (max_numeral_height) #define SCORE_Y (max_numeral_height)
#define BEST_SCORE_X 0 #define BEST_SCORE_X 0
#define BEST_SCORE_Y (2*max_numeral_height) #define BEST_SCORE_Y (2*max_numeral_height)
#endif #endif /* LCD_WIDTH<LCD_HEIGHT */
#define BACKGROUND_X (BASE_X-MIN_SPACE) #define BACKGROUND_X (int)(BASE_X-MIN_SPACE)
#define BACKGROUND_Y (BASE_Y-MIN_SPACE) #define BACKGROUND_Y (int)(BASE_Y-MIN_SPACE)
/* key mappings */ /* key mappings */
@ -121,6 +121,9 @@ static struct game_ctx_t *ctx=&ctx_data;
static bool merged_grid[GRID_SIZE][GRID_SIZE]; static bool merged_grid[GRID_SIZE][GRID_SIZE];
static int old_grid[GRID_SIZE][GRID_SIZE]; static int old_grid[GRID_SIZE][GRID_SIZE];
static int max_numeral_height=-1; static int max_numeral_height=-1;
#if LCD_DEPTH <= 1
static int max_numeral_width;
#endif
static bool loaded=false; static bool loaded=false;
/* first init_game will set this, when it is exceeded, it will be updated in the slide functions */ /* first init_game will set this, when it is exceeded, it will be updated in the slide functions */
@ -180,7 +183,8 @@ static bool do_help(void)
static inline void slide_internal(int startx, int starty, static inline void slide_internal(int startx, int starty,
int stopx, int stopy, int stopx, int stopy,
int dx, int dy, int dx, int dy,
int lookx, int looky) int lookx, int looky,
bool update_best)
{ {
int best_score_before=best_score; int best_score_before=best_score;
for(int y=starty;y!=stopy;y+=dy) for(int y=starty;y!=stopy;y+=dy)
@ -202,7 +206,7 @@ static inline void slide_internal(int startx, int starty,
} }
} }
} }
if(ctx->score>best_score_before) if(ctx->score>best_score_before && update_best)
best_score=ctx->score; best_score=ctx->score;
} }
@ -215,12 +219,13 @@ static inline void slide_internal(int startx, int starty,
3 ^ ^ ^ ^ 3 ^ ^ ^ ^
0 1 2 3 0 1 2 3
*/ */
static void up(void) static void up(bool update_best)
{ {
slide_internal(0, 1, /* start values */ slide_internal(0, 1, /* start values */
GRID_SIZE, GRID_SIZE, /* stop values */ GRID_SIZE, GRID_SIZE, /* stop values */
1, 1, /* delta values */ 1, 1, /* delta values */
0, -1); /* lookahead values */ 0, -1, /* lookahead values */
update_best);
} }
/* Down /* Down
0 v v v v 0 v v v v
@ -229,12 +234,13 @@ static void up(void)
3 3
0 1 2 3 0 1 2 3
*/ */
static void down(void) static void down(bool update_best)
{ {
slide_internal(0, GRID_SIZE-2, slide_internal(0, GRID_SIZE-2,
GRID_SIZE, -1, GRID_SIZE, -1,
1, -1, 1, -1,
0, 1); 0, 1,
update_best);
} }
/* Left /* Left
0 < < < 0 < < <
@ -243,12 +249,13 @@ static void down(void)
3 < < < 3 < < <
0 1 2 3 0 1 2 3
*/ */
static void left(void) static void left(bool update_best)
{ {
slide_internal(1, 0, slide_internal(1, 0,
GRID_SIZE, GRID_SIZE, GRID_SIZE, GRID_SIZE,
1, 1, 1, 1,
-1, 0); -1, 0,
update_best);
} }
/* Right /* Right
0 > > > 0 > > >
@ -257,12 +264,13 @@ static void left(void)
3 > > > 3 > > >
0 1 2 3 0 1 2 3
*/ */
static void right(void) static void right(bool update_best)
{ {
slide_internal(GRID_SIZE-2, 0, /* start */ slide_internal(GRID_SIZE-2, 0, /* start */
-1, GRID_SIZE, /* stop */ -1, GRID_SIZE, /* stop */
-1, 1, /* delta */ -1, 1, /* delta */
1, 0); /* lookahead */ 1, 0, /* lookahead */
update_best);
} }
/* slightly modified version of base 2 log, returns 1 when given zero, and log2(n)+1 for anything else */ /* slightly modified version of base 2 log, returns 1 when given zero, and log2(n)+1 for anything else */
@ -279,6 +287,7 @@ static inline int ilog2(int n)
} }
return log+1; return log+1;
} }
#if LCD_DEPTH > 1
static void draw(void) static void draw(void)
{ {
#ifdef HAVE_LCD_COLOR #ifdef HAVE_LCD_COLOR
@ -318,13 +327,22 @@ static void draw(void)
int w, h; int w, h;
rb->lcd_setfont(FONT_UI); rb->lcd_setfont(FONT_UI);
rb->font_getstringsize(buf, &w, &h, FONT_UI); rb->font_getstringsize(buf, &w, &h, FONT_UI);
bool draw_title=true;
if(w+TITLE_X>=BACKGROUND_X && h+TITLE_Y>=BACKGROUND_Y) if(w+TITLE_X>=BACKGROUND_X && h+TITLE_Y>=BACKGROUND_Y)
{ {
/* if it goes into the grid, use the system font, which should be smaller */ /* if it goes into the grid, use the system font, which should be smaller */
rb->lcd_setfont(FONT_SYSFIXED); rb->lcd_setfont(FONT_SYSFIXED);
rb->font_getstringsize(buf, &w, &h, FONT_SYSFIXED);
if(w+TITLE_X>=BACKGROUND_X && h+TITLE_Y>=BACKGROUND_Y)
{
/* title can't fit, don't draw it */
draw_title=false;
h=0;
} }
}
if(draw_title)
rb->lcd_putsxy(TITLE_X, TITLE_Y, buf); rb->lcd_putsxy(TITLE_X, TITLE_Y, buf);
int score_y=TITLE_Y+h+VERT_SPACING;
/* draw the score */ /* draw the score */
rb->snprintf(buf, 31, "Score: %d", ctx->score); rb->snprintf(buf, 31, "Score: %d", ctx->score);
#ifdef HAVE_LCD_COLOR #ifdef HAVE_LCD_COLOR
@ -366,13 +384,18 @@ static void draw(void)
/* as a last resort, don't use Score: and use the system font */ /* as a last resort, don't use Score: and use the system font */
rb->snprintf(buf, 31, "%d", ctx->score); rb->snprintf(buf, 31, "%d", ctx->score);
rb->font_getstringsize(buf, &w, &h, FONT_SYSFIXED);
rb->lcd_setfont(FONT_SYSFIXED); rb->lcd_setfont(FONT_SYSFIXED);
if(w+SCORE_X<BACKGROUND_X)
goto draw_lbl;
else
goto skip_draw_score;
} }
draw_lbl: draw_lbl:
rb->lcd_putsxy(SCORE_X, SCORE_Y, buf); rb->lcd_putsxy(SCORE_X, score_y, buf);
score_y+=h+VERT_SPACING;
/* draw the best score */ /* draw the best score */
skip_draw_score:
rb->snprintf(buf, 31, "Best: %d", best_score); rb->snprintf(buf, 31, "Best: %d", best_score);
#ifdef HAVE_LCD_COLOR #ifdef HAVE_LCD_COLOR
rb->lcd_set_foreground(LCD_WHITE); rb->lcd_set_foreground(LCD_WHITE);
@ -413,16 +436,70 @@ draw_lbl:
/* as a last resort, don't use Score: and use the system font */ /* as a last resort, don't use Score: and use the system font */
rb->snprintf(buf, 31, "%d", best_score); rb->snprintf(buf, 31, "%d", best_score);
rb->font_getstringsize(buf, &w, &h, FONT_SYSFIXED);
rb->lcd_setfont(FONT_SYSFIXED); rb->lcd_setfont(FONT_SYSFIXED);
if(w+BEST_SCORE_X<BACKGROUND_X)
goto draw_best;
else
goto skip_draw_best;
} }
draw_best: draw_best:
rb->lcd_putsxy(BEST_SCORE_X, BEST_SCORE_Y, buf); rb->lcd_putsxy(BEST_SCORE_X, score_y, buf);
skip_draw_best:
rb->lcd_update(); rb->lcd_update();
/* revert the font back */ /* revert the font back */
rb->lcd_setfont(WHAT_FONT); rb->lcd_setfont(WHAT_FONT);
} }
#else /* LCD_DEPTH > 1 */
/* 1-bit display :( */
/* bitmaps are unreadable with these screens, so just resort to text */
static void draw(void)
{
rb->lcd_clear_display();
/* Draw the grid */
/* find the biggest tile */
int biggest_tile=-1;
for(int x=0;x<GRID_SIZE;++x)
{
for(int y=0;y<GRID_SIZE;++y)
if(ctx->grid[x][y]>biggest_tile)
biggest_tile=ctx->grid[x][y];
}
char str[32];
rb->snprintf(str, 31,"%d", biggest_tile);
int biggest_tile_width=rb->strlen(str)*rb->font_get_width(rb->font_get(WHAT_FONT), '0')+MIN_SPACE;
for(int y=0;y<GRID_SIZE;++y)
{
for(int x=0;x<GRID_SIZE;++x)
{
if(ctx->grid[x][y])
{
if(ctx->grid[x][y]>biggest_tile)
biggest_tile=ctx->grid[x][y];
rb->snprintf(str,31,"%d", ctx->grid[x][y]);
rb->lcd_putsxy(biggest_tile_width*x,y*max_numeral_height+max_numeral_height,str);
}
}
}
/* Now draw the score, and the game title */
rb->snprintf(str, 31, "Score: %d", ctx->score);
int str_width, str_height;
rb->font_getstringsize(str, &str_width, &str_height, WHAT_FONT);
int score_leftmost=LCD_WIDTH-str_width-1;
/* Check if there is enough space to display "Score: ", otherwise, only display the score */
if(score_leftmost>=0)
rb->lcd_putsxy(score_leftmost,0,str);
else
rb->lcd_putsxy(score_leftmost,0,str+rb->strlen("Score: "));
/* Reuse the same string for the title */
rb->snprintf(str, 31, "%d", WINNING_TILE);
rb->font_getstringsize(str, &str_width, &str_height, WHAT_FONT);
if(str_width<score_leftmost)
rb->lcd_putsxy(0,0,str);
rb->lcd_update();
}
#endif /* LCD_DEPTH > 1 */
/* place a 2 or 4 in a random empty space */ /* place a 2 or 4 in a random empty space */
static void place_random(void) static void place_random(void)
{ {
@ -455,74 +532,66 @@ static void restore_old_grid(void)
/* checks for a win or loss */ /* checks for a win or loss */
static bool check_gameover(void) static bool check_gameover(void)
{ {
int numempty=0; /* first, check for a loss */
int oldscore=ctx->score;
bool have_legal_move=false;
memset(&merged_grid,0,SPACES*sizeof(bool));
up(false);
if(memcmp(&old_grid, &ctx->grid, sizeof(int)*SPACES))
{
restore_old_grid();
ctx->score=oldscore;
have_legal_move=true;
}
restore_old_grid();
memset(&merged_grid,0,SPACES*sizeof(bool));
down(false);
if(memcmp(&old_grid, &ctx->grid, sizeof(int)*SPACES))
{
restore_old_grid();
ctx->score=oldscore;
have_legal_move=true;
}
restore_old_grid();
memset(&merged_grid,0,SPACES*sizeof(bool));
left(false);
if(memcmp(&old_grid, &ctx->grid, sizeof(int)*SPACES))
{
restore_old_grid();
ctx->score=oldscore;
have_legal_move=true;
}
restore_old_grid();
memset(&merged_grid,0,SPACES*sizeof(bool));
right(false);
if(memcmp(&old_grid, &ctx->grid, sizeof(int)*SPACES))
{
restore_old_grid();
ctx->score=oldscore;
have_legal_move=true;
}
ctx->score=oldscore;
if(!have_legal_move)
{
/* no more legal moves */
draw(); /* Shame the player :) */
rb->splash(HZ*2, "Game Over!");
return true;
}
for(int y=0;y<GRID_SIZE;++y) for(int y=0;y<GRID_SIZE;++y)
{ {
for(int x=0;x<GRID_SIZE;++x) for(int x=0;x<GRID_SIZE;++x)
{ {
if(ctx->grid[x][y]==0)
++numempty;
if(ctx->grid[x][y]==WINNING_TILE && !ctx->already_won) if(ctx->grid[x][y]==WINNING_TILE && !ctx->already_won)
{ {
/* Let the user see the tile in its full glory... */ /* Let the user see the tile in its full glory... */
draw(); draw();
ctx->already_won=true; ctx->already_won=true;
rb->splash(HZ*2,"You win!"); rb->splash(HZ*2,"You win!");
const struct text_message prompt={(const char*[]){"Keep going?"}, 1}; /* don't let the user quit here :) */
enum yesno_res keepgoing=rb->gui_syncyesno_run(&prompt, NULL, NULL);
if(keepgoing==YESNO_NO)
return true;
else
return false;
} }
} }
} }
if(!numempty)
{
/* No empty spaces, check for valid moves */
/* Then, get the current score */
int oldscore=ctx->score;
memset(&merged_grid,0,SPACES*sizeof(bool));
up();
if(memcmp(&old_grid, &ctx->grid, sizeof(int)*SPACES))
{
restore_old_grid();
ctx->score=oldscore;
return false;
}
restore_old_grid();
memset(&merged_grid,0,SPACES*sizeof(bool));
down();
if(memcmp(&old_grid, &ctx->grid, sizeof(int)*SPACES))
{
restore_old_grid();
ctx->score=oldscore;
return false;
}
restore_old_grid();
memset(&merged_grid,0,SPACES*sizeof(bool));
left();
if(memcmp(&old_grid, &ctx->grid, sizeof(int)*SPACES))
{
restore_old_grid();
ctx->score=oldscore;
return false;
}
restore_old_grid();
memset(&merged_grid,0,SPACES*sizeof(bool));
right();
if(memcmp(&old_grid, &ctx->grid, sizeof(int)*SPACES))
{
restore_old_grid();
ctx->score=oldscore;
return false;
}
/* no more legal moves */
ctx->score=oldscore;
draw(); /* Shame the player :) */
rb->splash(HZ*2, "Game Over!");
return true;
}
return false; return false;
} }
@ -540,6 +609,8 @@ static void load_hs(void)
static void init_game(bool newgame) static void init_game(bool newgame)
{ {
best_score=highscores[0].score; best_score=highscores[0].score;
if(loaded && ctx->score > best_score)
best_score=ctx->score;
if(newgame) if(newgame)
{ {
/* initialize the game context */ /* initialize the game context */
@ -558,6 +629,9 @@ static void init_game(bool newgame)
/* Now get the height of the font */ /* Now get the height of the font */
rb->font_getstringsize("0123456789", NULL, &max_numeral_height,WHAT_FONT); rb->font_getstringsize("0123456789", NULL, &max_numeral_height,WHAT_FONT);
max_numeral_height+=VERT_SPACING; max_numeral_height+=VERT_SPACING;
#if LCD_DEPTH <= 1
max_numeral_width=rb->font_get_width(rb->font_get(WHAT_FONT), '0');
#endif
backlight_ignore_timeout(); backlight_ignore_timeout();
rb->lcd_clear_display(); rb->lcd_clear_display();
draw(); draw();
@ -735,7 +809,7 @@ static enum plugin_status do_game(bool newgame)
for(int i=0;i<GRID_SIZE-1;++i) for(int i=0;i<GRID_SIZE-1;++i)
{ {
memcpy(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES); memcpy(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES);
up(); up(true);
if(memcmp(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES)) if(memcmp(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES))
{ {
rb->sleep(ANIM_SLEEPTIME); rb->sleep(ANIM_SLEEPTIME);
@ -748,7 +822,7 @@ static enum plugin_status do_game(bool newgame)
for(int i=0;i<GRID_SIZE-1;++i) for(int i=0;i<GRID_SIZE-1;++i)
{ {
memcpy(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES); memcpy(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES);
down(); down(true);
if(memcmp(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES)) if(memcmp(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES))
{ {
rb->sleep(ANIM_SLEEPTIME); rb->sleep(ANIM_SLEEPTIME);
@ -761,7 +835,7 @@ static enum plugin_status do_game(bool newgame)
for(int i=0;i<GRID_SIZE-1;++i) for(int i=0;i<GRID_SIZE-1;++i)
{ {
memcpy(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES); memcpy(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES);
left(); left(true);
if(memcmp(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES)) if(memcmp(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES))
{ {
rb->sleep(ANIM_SLEEPTIME); rb->sleep(ANIM_SLEEPTIME);
@ -774,7 +848,7 @@ static enum plugin_status do_game(bool newgame)
for(int i=0;i<GRID_SIZE-1;++i) for(int i=0;i<GRID_SIZE-1;++i)
{ {
memcpy(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES); memcpy(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES);
right(); right(true);
if(memcmp(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES)) if(memcmp(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES))
{ {
rb->sleep(ANIM_SLEEPTIME); rb->sleep(ANIM_SLEEPTIME);