From b61553c2b18d37566b6561e413ef1b49de39c0a7 Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Sun, 29 Jun 2014 14:49:07 -0400 Subject: [PATCH] Added 2048 game Change-Id: I4012dca4f93ca0db386a454635534f648ba906e9 Reviewed-on: http://gerrit.rockbox.org/888 Reviewed-by: Michael Giacomelli Tested: Michael Giacomelli --- apps/plugins/2048.c | 916 ++++++++++++++++++ apps/plugins/CATEGORIES | 1 + apps/plugins/SOURCES | 2 + apps/plugins/bitmaps/native/SOURCES | 22 + .../native/_2048_background.103x103x24.bmp | Bin 0 -> 32258 bytes .../native/_2048_background.121x121x24.bmp | Bin 0 -> 44166 bytes .../native/_2048_background.168x168x24.bmp | Bin 0 -> 84794 bytes .../native/_2048_background.224x224x24.bmp | Bin 0 -> 150650 bytes .../native/_2048_background.56x56x24.bmp | Bin 0 -> 9530 bytes .../bitmaps/native/_2048_tiles.12x12x24.bmp | Bin 0 -> 7898 bytes .../bitmaps/native/_2048_tiles.22x22x24.bmp | Bin 0 -> 26258 bytes .../bitmaps/native/_2048_tiles.26x26x24.bmp | Bin 0 -> 36626 bytes .../bitmaps/native/_2048_tiles.36x36x24.bmp | Bin 0 -> 70106 bytes .../bitmaps/native/_2048_tiles.48x48x24.bmp | Bin 0 -> 124538 bytes docs/CREDITS | 1 + manual/plugins/2048.tex | 16 + manual/plugins/main.tex | 2 + 17 files changed, 960 insertions(+) create mode 100644 apps/plugins/2048.c create mode 100644 apps/plugins/bitmaps/native/_2048_background.103x103x24.bmp create mode 100644 apps/plugins/bitmaps/native/_2048_background.121x121x24.bmp create mode 100644 apps/plugins/bitmaps/native/_2048_background.168x168x24.bmp create mode 100644 apps/plugins/bitmaps/native/_2048_background.224x224x24.bmp create mode 100644 apps/plugins/bitmaps/native/_2048_background.56x56x24.bmp create mode 100644 apps/plugins/bitmaps/native/_2048_tiles.12x12x24.bmp create mode 100644 apps/plugins/bitmaps/native/_2048_tiles.22x22x24.bmp create mode 100644 apps/plugins/bitmaps/native/_2048_tiles.26x26x24.bmp create mode 100644 apps/plugins/bitmaps/native/_2048_tiles.36x36x24.bmp create mode 100644 apps/plugins/bitmaps/native/_2048_tiles.48x48x24.bmp create mode 100644 manual/plugins/2048.tex diff --git a/apps/plugins/2048.c b/apps/plugins/2048.c new file mode 100644 index 0000000000..9a74b0ff38 --- /dev/null +++ b/apps/plugins/2048.c @@ -0,0 +1,916 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2014 Franklin Wei + * + * Clone of 2048 by Gabriele Cirulli + * + * Thanks to [Saint], saratoga, and gevaerts for answering all my n00b + * questions :) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* TODO + * Sounds! + * Better animations! + */ + +/* includes */ + +#include + +#include "lib/display_text.h" + +#include "lib/helper.h" +#include "lib/highscore.h" +#include "lib/playback_control.h" +#include "lib/pluginlib_actions.h" +#include "lib/pluginlib_exit.h" + +#ifdef HAVE_LCD_BITMAP +#include "pluginbitmaps/_2048_background.h" +#include "pluginbitmaps/_2048_tiles.h" +#endif + +/* defines */ + +#define ANIM_SLEEPTIME (HZ/20) +#define GRID_SIZE 4 +#define HISCORES_FILE PLUGIN_GAMES_DATA_DIR "/2048.score" +#define NUM_SCORES 5 +#define NUM_STARTING_TILES 2 +#define RESUME_FILE PLUGIN_GAMES_DATA_DIR "/2048.save" +#define WHAT_FONT FONT_UI +#define SPACES (GRID_SIZE*GRID_SIZE) +#define MIN_SPACE (BMPHEIGHT__2048_tiles*0.134) /* space between tiles */ +#define MAX_UNDOS 64 +#define VERT_SPACING 4 +#define WINNING_TILE 2048 + +/* screen-specific configuration */ + +#if LCD_WIDTHrand()%(max-min+1)+min; +} + +/* prepares to exit */ +static void cleanup(void) +{ + backlight_use_settings(); +} + +/* returns 2 or 4 */ +static inline int rand_2_or_4(void) +{ + /* 1 in 10 chance of a four */ + if(rb->rand()%10==0) + return 4; + else + return 2; +} + +/* display the help text */ +static bool do_help(void) +{ +#ifdef HAVE_LCD_COLOR + rb->lcd_set_foreground(LCD_WHITE); + rb->lcd_set_background(LCD_BLACK); +#endif + rb->lcd_setfont(FONT_UI); + char* help_text[]= {"2048", "", "Aim", + "", "Join", "the", "numbers", "to", "get", "to", "the", "2048", "tile!", "", "", + "How", "to", "Play", "", + "", "Use", "the", "directional", "keys", "to", "move", "the", "tiles.", "When", + "two", "tiles", "with", "the", "same", "number", "touch,", "they", "merge", "into", "one!"}; + struct style_text style[]={ + {0, TEXT_CENTER|TEXT_UNDERLINE}, + {2, C_RED}, + {15, C_RED}, {16, C_RED}, {17,C_RED}, + LAST_STYLE_ITEM + }; + return display_text(ARRAYLEN(help_text), help_text, style,NULL,true); +} + +/*** the logic for sliding ***/ + +/* this is the helper function that does the actual tile moving */ + +static inline void slide_internal(int startx, int starty, + int stopx, int stopy, + int dx, int dy, + int lookx, int looky) +{ + int best_score_before=best_score; + for(int y=starty;y!=stopy;y+=dy) + { + for(int x=startx;x!=stopx;x+=dx) + { + if(ctx->grid[x+lookx][y+looky]==ctx->grid[x][y] && ctx->grid[x][y] && !merged_grid[x+lookx][y+looky] && !merged_grid[x][y]) /* Slide into */ + { + /* Each merged tile cannot be merged again */ + merged_grid[x+lookx][y+looky]=true; + ctx->grid[x+lookx][y+looky]=2*ctx->grid[x][y]; + ctx->score+=ctx->grid[x+lookx][y+looky]; + ctx->grid[x][y]=0; + } + else if(ctx->grid[x+lookx][y+looky]==0) /* Empty! */ + { + ctx->grid[x+lookx][y+looky]=ctx->grid[x][y]; + ctx->grid[x][y]=0; + } + } + } + if(ctx->score>best_score_before) + best_score=ctx->score; +} + +/* these functions move each tile 1 space in the direction specified via calls to slide_internal */ + +/* Up + 0 + 1 ^ ^ ^ ^ + 2 ^ ^ ^ ^ + 3 ^ ^ ^ ^ + 0 1 2 3 +*/ +static void up(void) +{ + slide_internal(0, 1, /* start values */ + GRID_SIZE, GRID_SIZE, /* stop values */ + 1, 1, /* delta values */ + 0, -1); /* lookahead values */ +} +/* Down + 0 v v v v + 1 v v v v + 2 v v v v + 3 + 0 1 2 3 +*/ +static void down(void) +{ + slide_internal(0, GRID_SIZE-2, + GRID_SIZE, -1, + 1, -1, + 0, 1); +} +/* Left + 0 < < < + 1 < < < + 2 < < < + 3 < < < + 0 1 2 3 +*/ +static void left(void) +{ + slide_internal(1, 0, + GRID_SIZE, GRID_SIZE, + 1, 1, + -1, 0); +} +/* Right + 0 > > > + 1 > > > + 2 > > > + 3 > > > + 0 1 2 3 +*/ +static void right(void) +{ + slide_internal(GRID_SIZE-2, 0, /* start */ + -1, GRID_SIZE, /* stop */ + -1, 1, /* delta */ + 1, 0); /* lookahead */ +} + +/* slightly modified version of base 2 log, returns 1 when given zero, and log2(n)+1 for anything else */ + +static inline int ilog2(int n) +{ + if(n==0) + return 1; + int log=0; + while(n>1) + { + n>>=1; + ++log; + } + return log+1; +} +static void draw(void) +{ +#ifdef HAVE_LCD_COLOR + rb->lcd_set_background(BACKGROUND); +#endif + rb->lcd_clear_display(); + + /* draw the background */ + + rb->lcd_bitmap(_2048_background, BACKGROUND_X, BACKGROUND_Y, BMPWIDTH__2048_background, BMPWIDTH__2048_background); + + /* + grey_gray_bitmap(_2048_background, BACKGROUND_X, BACKGROUND_Y, BMPWIDTH__2048_background, BMPHEIGHT__2048_background); + */ + + /* draw the grid */ + + for(int y=0;ylcd_bitmap_part(_2048_tiles, /* source */ + BMPWIDTH__2048_tiles-BMPHEIGHT__2048_tiles*ilog2(ctx->grid[x][y]), 0, /* source upper left corner */ + STRIDE(SCREEN_MAIN, BMPWIDTH__2048_tiles, BMPHEIGHT__2048_tiles), /* stride */ + (BMPHEIGHT__2048_tiles+MIN_SPACE)*x+BASE_X, (BMPHEIGHT__2048_tiles+MIN_SPACE)*y+BASE_Y, /* dest upper-left corner */ + BMPHEIGHT__2048_tiles, BMPHEIGHT__2048_tiles); /* size of the cut section */ + } + } + /* draw the title */ + char buf[32]; +#ifdef HAVE_LCD_COLOR + rb->lcd_set_foreground(TEXT_COLOR); +#endif + rb->snprintf(buf, 31, "%d", WINNING_TILE); + + /* check if the title will go into the grid */ + int w, h; + rb->lcd_setfont(FONT_UI); + rb->font_getstringsize(buf, &w, &h, FONT_UI); + 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 */ + rb->lcd_setfont(FONT_SYSFIXED); + } + rb->lcd_putsxy(TITLE_X, TITLE_Y, buf); + + /* draw the score */ + rb->snprintf(buf, 31, "Score: %d", ctx->score); +#ifdef HAVE_LCD_COLOR + rb->lcd_set_foreground(LCD_WHITE); + rb->lcd_set_background(BOARD_BACKGROUND); +#endif + rb->lcd_setfont(FONT_UI); + rb->font_getstringsize(buf, &w, &h, FONT_UI); + if(w+SCORE_X>=BACKGROUND_X && h+SCORE_Y>=BACKGROUND_Y) + { + /* score overflows */ + /* first see if it fits with Score: and FONT_SYSFIXED */ + rb->lcd_setfont(FONT_SYSFIXED); + rb->font_getstringsize(buf, &w, &h, FONT_SYSFIXED); + if(w+SCORE_X < BACKGROUND_X) + /* it fits, go and draw it */ + goto draw_lbl; + + /* now try with S: and FONT_UI */ + rb->snprintf(buf, 31, "S: %d", ctx->score); + rb->font_getstringsize(buf, &w, &h, FONT_UI); + rb->lcd_setfont(FONT_UI); + if(w+SCORE_Xsnprintf(buf, 31, "S: %d", ctx->score); + rb->font_getstringsize(buf, &w, &h, FONT_SYSFIXED); + rb->lcd_setfont(FONT_SYSFIXED); + if(w+SCORE_Xsnprintf(buf, 31, "%d", ctx->score); + rb->font_getstringsize(buf, &w, &h, FONT_UI); + rb->lcd_setfont(FONT_UI); + if(w+SCORE_Xsnprintf(buf, 31, "%d", ctx->score); + rb->lcd_setfont(FONT_SYSFIXED); + } +draw_lbl: + rb->lcd_putsxy(SCORE_X, SCORE_Y, buf); + + /* draw the best score */ + + rb->snprintf(buf, 31, "Best: %d", best_score); +#ifdef HAVE_LCD_COLOR + rb->lcd_set_foreground(LCD_WHITE); + rb->lcd_set_background(BOARD_BACKGROUND); +#endif + rb->lcd_setfont(FONT_UI); + rb->font_getstringsize(buf, &w, &h, FONT_UI); + if(w+BEST_SCORE_X>=BACKGROUND_X && h+BEST_SCORE_Y>=BACKGROUND_Y) + { + /* score overflows */ + /* first see if it fits with Score: and FONT_SYSFIXED */ + rb->lcd_setfont(FONT_SYSFIXED); + rb->font_getstringsize(buf, &w, &h, FONT_SYSFIXED); + if(w+BEST_SCORE_X < BACKGROUND_X) + /* it fits, go and draw it */ + goto draw_best; + + /* now try with S: and FONT_UI */ + rb->snprintf(buf, 31, "B: %d", best_score); + rb->font_getstringsize(buf, &w, &h, FONT_UI); + rb->lcd_setfont(FONT_UI); + if(w+BEST_SCORE_Xsnprintf(buf, 31, "B: %d", best_score); + rb->font_getstringsize(buf, &w, &h, FONT_SYSFIXED); + rb->lcd_setfont(FONT_SYSFIXED); + if(w+BEST_SCORE_Xsnprintf(buf, 31, "%d", best_score); + rb->font_getstringsize(buf, &w, &h, FONT_UI); + rb->lcd_setfont(FONT_UI); + if(w+BEST_SCORE_Xsnprintf(buf, 31, "%d", best_score); + rb->lcd_setfont(FONT_SYSFIXED); + } +draw_best: + rb->lcd_putsxy(BEST_SCORE_X, BEST_SCORE_Y, buf); + + rb->lcd_update(); + /* revert the font back */ + rb->lcd_setfont(WHAT_FONT); +} + +/* place a 2 or 4 in a random empty space */ +static void place_random(void) +{ + int xpos[SPACES],ypos[SPACES]; + int back=0; + /* get the indexes of empty spaces */ + for(int y=0;ygrid[x][y]) + { + xpos[back]=x; + ypos[back]=y; + ++back; + } + } + if(!back) + /* no empty spaces */ + return; + int idx=rand_range(0,back-1); + ctx->grid[xpos[idx]][ypos[idx]]=rand_2_or_4(); +} + +/* copies old_grid to ctx->grid */ +static void restore_old_grid(void) +{ + memcpy(&ctx->grid, &old_grid, sizeof(int)*SPACES); +} + +/* checks for a win or loss */ +static bool check_gameover(void) +{ + int numempty=0; + for(int y=0;ygrid[x][y]==0) + ++numempty; + if(ctx->grid[x][y]==WINNING_TILE && !ctx->already_won) + { + /* Let the user see the tile in its full glory... */ + draw(); + ctx->already_won=true; + rb->splash(HZ*2,"You win!"); + const struct text_message prompt={(const char*[]){"Keep going?"}, 1}; + 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; +} + +/* loads highscores from disk */ +/* creates an empty structure if the file does not exist */ +static void load_hs(void) +{ + if(rb->file_exists(HISCORES_FILE)) + highscore_load(HISCORES_FILE, highscores, NUM_SCORES); + else + memset(highscores, 0, sizeof(struct highscore)*NUM_SCORES); +} + +/* initialize the data structures */ +static void init_game(bool newgame) +{ + best_score=highscores[0].score; + if(newgame) + { + /* initialize the game context */ + memset(ctx->grid, 0, sizeof(int)*SPACES); + for(int i=0;iscore=0; + ctx->already_won=false; + } + /* using the menu resets the font */ + /* set it again here */ + rb->lcd_setfont(WHAT_FONT); + /* Now calculate font sizes */ + /* Now get the height of the font */ + rb->font_getstringsize("0123456789", NULL, &max_numeral_height,WHAT_FONT); + max_numeral_height+=VERT_SPACING; + backlight_ignore_timeout(); + rb->lcd_clear_display(); + draw(); +} + +/* save the current game state */ +static void save_game(void) +{ + rb->splash(0, "Saving..."); + int fd=rb->open(RESUME_FILE,O_WRONLY|O_CREAT, 0666); + if(fd<0) + { + return; + } + ctx->cksum=0; + for(int x=0;xcksum+=ctx->grid[x][y]; + ctx->cksum^=ctx->score; + rb->write(fd, ctx,sizeof(struct game_ctx_t)); + rb->close(fd); + rb->lcd_update(); +} + +/* loads a saved game, returns true on success */ +static bool load_game(void) +{ + int success=0; + int fd=rb->open(RESUME_FILE, O_RDONLY); + if(fd<0) + { + rb->remove(RESUME_FILE); + return false; + } + int numread=rb->read(fd, ctx, sizeof(struct game_ctx_t)); + int calc=0; + for(int x=0;xgrid[x][y]; + calc^=ctx->score; + if(numread==sizeof(struct game_ctx_t) && calc==ctx->cksum) + ++success; + rb->close(fd); + rb->remove(RESUME_FILE); + return (success==1); +} + +/* update the highscores with ctx->score */ +static void hs_check_update(bool noshow) +{ + /* first, find the biggest tile to show as the level */ + int biggest=0; + for(int x=0;xgrid[x][y]>biggest) + biggest=ctx->grid[x][y]; + } + } + int hs_idx=highscore_update(ctx->score,biggest, "", highscores,NUM_SCORES); + if(!noshow) + { + /* show the scores if there is a new high score */ + if(hs_idx>=0) + { + rb->splashf(HZ*2,"New High Score: %d", ctx->score); + rb->lcd_clear_display(); + highscore_show(hs_idx,highscores,NUM_SCORES,true); + } + } + highscore_save(HISCORES_FILE,highscores,NUM_SCORES); +} + +/* asks the user if they wish to quit */ +static bool confirm_quit(void) +{ + const struct text_message prompt={(const char*[]){"Are you sure?", "This will clear your current game."}, 2}; + enum yesno_res response=rb->gui_syncyesno_run(&prompt, NULL, NULL); + if(response==YESNO_NO) + return false; + else + return true; +} + +/* show the pause menu */ +static int do_2048_pause_menu(void) +{ + int sel=0; + MENUITEM_STRINGLIST(menu,"2048 Menu", NULL, + "Resume Game", + "Start New Game", + "High Scores", + "Playback Control", + "Help", + "Quit without Saving", + "Quit"); + bool quit=false; + while(!quit) + { + switch(rb->do_menu(&menu, &sel, NULL, false)) + { + case 0: + draw(); + return 0; + case 1: + { + if(!confirm_quit()) + break; + else + { + hs_check_update(false); + return 1; + } + } + case 2: + highscore_show(-1,highscores, NUM_SCORES, true); + break; + case 3: + playback_control(NULL); + break; + case 4: + do_help(); + break; + case 5: /* quit w/o saving */ + { + if(!confirm_quit()) + break; + else + { + return 2; + } + } + case 6: + return 3; + } + } + return 0; +} + +static void exit_handler(void) +{ + cleanup(); + if(abnormal_exit) + save_game(); + return; +} +static bool check_hs; +/* main game loop */ +static enum plugin_status do_game(bool newgame) +{ + init_game(newgame); + rb_atexit(&exit_handler); + int made_move=0; + while(1) + { +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(false); /* Save battery when idling */ +#endif + /* Wait for a button press */ + int button=pluginlib_getaction(-1, plugin_contexts, ARRAYLEN(plugin_contexts)); + made_move=0; + memset(&merged_grid,0,SPACES*sizeof(bool)); + memcpy(&old_grid, &ctx->grid, sizeof(int)*SPACES); + int grid_before_anim_step[GRID_SIZE][GRID_SIZE]; +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(true); /* doing work now... */ +#endif + switch(button) + { + case KEY_UP: + for(int i=0;igrid, sizeof(int)*SPACES); + up(); + if(memcmp(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES)) + { + rb->sleep(ANIM_SLEEPTIME); + draw(); + } + } + made_move=1; + break; + case KEY_DOWN: + for(int i=0;igrid, sizeof(int)*SPACES); + down(); + if(memcmp(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES)) + { + rb->sleep(ANIM_SLEEPTIME); + draw(); + } + } + made_move=1; + break; + case KEY_LEFT: + for(int i=0;igrid, sizeof(int)*SPACES); + left(); + if(memcmp(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES)) + { + rb->sleep(ANIM_SLEEPTIME); + draw(); + } + } + made_move=1; + break; + case KEY_RIGHT: + for(int i=0;igrid, sizeof(int)*SPACES); + right(); + if(memcmp(grid_before_anim_step, ctx->grid, sizeof(int)*SPACES)) + { + rb->sleep(ANIM_SLEEPTIME); + draw(); + } + } + made_move=1; + break; + case KEY_EXIT: + switch(do_2048_pause_menu()) + { + case 0: /* resume */ + break; + case 1: /* new game */ + init_game(true); + made_move=1; + continue; + break; + case 2: /* quit without saving */ + check_hs=true; + rb->remove(RESUME_FILE); + return PLUGIN_ERROR; + case 3: /* save and quit */ + check_hs=false; + save_game(); + return PLUGIN_ERROR; + } + break; + default: + { + exit_on_usb(button); /* handles poweroff and USB events */ + break; + } + } + if(made_move) + { + /* Check if we actually moved, then add random */ + if(memcmp(&old_grid, ctx->grid, sizeof(int)*SPACES)) + { + place_random(); + } + memcpy(&old_grid, ctx->grid, sizeof(int)*SPACES); + if(check_gameover()) + return PLUGIN_OK; + draw(); + } +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(false); /* back to idle */ +#endif + rb->yield(); + } +} + +/* decide if this_item should be shown in the main menu */ +/* used to hide resume option when there is no save */ +static int mainmenu_cb(int action, const struct menu_item_ex *this_item) +{ + int idx=((intptr_t)this_item); + if(action==ACTION_REQUEST_MENUITEM && !loaded && (idx==0 || idx==5)) + return ACTION_EXIT_MENUITEM; + return action; +} + +/* show the main menu */ +static enum plugin_status do_2048_menu(void) +{ + int sel=0; + loaded=load_game(); + MENUITEM_STRINGLIST(menu,"2048 Menu", mainmenu_cb, "Resume Game", "Start New Game","High Scores","Playback Control", "Help", "Quit without Saving", "Quit"); + bool quit=false; + while(!quit) + { + int item; + switch(item=rb->do_menu(&menu,&sel,NULL,false)) + { + case 0: /* Start new game or resume a game */ + case 1: + { + if(item==1 && loaded) + { + if(!confirm_quit()) + break; + } + enum plugin_status ret=do_game(item==1); + switch(ret) + { + case PLUGIN_OK: + { + loaded=false; + rb->remove(RESUME_FILE); + hs_check_update(false); + break; + } + case PLUGIN_USB_CONNECTED: + save_game(); + /* Don't bother showing the high scores... */ + return ret; + case PLUGIN_ERROR: /* exit without menu */ + if(check_hs) + hs_check_update(false); + return PLUGIN_OK; + default: + break; + } + break; + } + case 2: + highscore_show(-1,highscores, NUM_SCORES, true); + break; + case 3: + playback_control(NULL); + break; + case 4: + do_help(); + break; + case 5: + if(confirm_quit()) + return PLUGIN_OK; + case 6: + if(loaded) + save_game(); + return PLUGIN_OK; + default: + break; + } + } + return PLUGIN_OK; +} +enum plugin_status plugin_start(const void* param) +{ + (void)param; + rb->srand(*rb->current_tick); + load_hs(); + rb->lcd_setfont(WHAT_FONT); + + /* now start the game menu */ + enum plugin_status ret=do_2048_menu(); + highscore_save(HISCORES_FILE,highscores,NUM_SCORES); + cleanup(); + abnormal_exit=false; + return ret; +} diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index 8a849aafc2..626dca0d32 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES @@ -1,3 +1,4 @@ +2048,games alpine_cdc,apps alarmclock,apps autostart,apps diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index c56cd5eb46..9b7436ac20 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -213,6 +213,8 @@ nim.c #if LCD_DEPTH > 1 /* non-mono bitmap targets */ +/* 2048 runs on 1-bit LCDs, but it is unplayable */ +2048.c matrix.c #if (LCD_WIDTH > 138) diff --git a/apps/plugins/bitmaps/native/SOURCES b/apps/plugins/bitmaps/native/SOURCES index 4b7f0e2670..d608062335 100644 --- a/apps/plugins/bitmaps/native/SOURCES +++ b/apps/plugins/bitmaps/native/SOURCES @@ -1,5 +1,27 @@ #ifdef HAVE_LCD_BITMAP +/* 2048 */ + +#define MIN(x,y) ((x=240 +_2048_tiles.48x48x24.bmp +_2048_background.224x224x24.bmp +#elif MIN(LCD_WIDTH, LCD_HEIGHT)>=176 +_2048_tiles.36x36x24.bmp +_2048_background.168x168x24.bmp +#elif MIN(LCD_WIDTH, LCD_HEIGHT)>=132 || MIN(LCD_WIDTH, LCD_HEIGHT)>=128 +_2048_tiles.26x26x24.bmp +_2048_background.121x121x24.bmp +#elif MIN(LCD_WIDTH, LCD_HEIGHT)>=110 +_2048_tiles.22x22x24.bmp +_2048_background.103x103x24.bmp +#else +/* default to smallest bitmaps */ +_2048_tiles.12x12x24.bmp +_2048_background.56x56x24.bmp +#endif +#undef MIN + /* Brickmania */ #ifdef HAVE_LCD_COLOR #if LCD_WIDTH >= 112 diff --git a/apps/plugins/bitmaps/native/_2048_background.103x103x24.bmp b/apps/plugins/bitmaps/native/_2048_background.103x103x24.bmp new file mode 100644 index 0000000000000000000000000000000000000000..153126bc996538c4a845c583411165157a15eea0 GIT binary patch literal 32258 zcmeI*Ax;Bf7)8;61)y0^4GP01FgP3uXchqpSQ79A0U9g|;tK_Xp>y?VI_;#HXHITv z|IP9K)$;win9sAhPJgbw&s<1K3JBUxqe@pqm%RB`(3~H|2+8m{(1ZGeE;-v z_vrnPz$lH?+sEe^&JD3u0wXqVN?V0C50BWmtzCJ31h};fxN&O&ZKXGEO`xsx#;pmo zmEO2Dfws~cw5W?xXe+&OYXWVhH*QU!t@OsN3AB~oxHW;c(i^uX&{lfm z)&$y0Z`_(dTj`Bk6KE^Faccr?r8jO(psn=AtqHW1-ncb^w$dB7CeT)TV*-ZKXGEO`xsx#;pmomEO2Dfws~cwUu=l|^ss5Lp$ literal 0 HcmV?d00001 diff --git a/apps/plugins/bitmaps/native/_2048_background.121x121x24.bmp b/apps/plugins/bitmaps/native/_2048_background.121x121x24.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1e6e3270d06e19769e19efa3314358a5beacc27d GIT binary patch literal 44166 zcmeIzF-`(u7zEH?Yh%rMXsl>F2c4B3z*AUw06l>v)KKnq+z^<8%1p8p<`L0}`e`y@ z9_!8f*El`i=Fi*t`Feidjn(P<5A)AAk7Iny&&y-|^!#$kfBkxY^^3d1^!fecW9bI= z$7wA6Km7ePpzGUhTGzV%k8dGf*Iw6N*Lh17iUt_M5QY@PagqiY!VrdJ4nolYLm0x4 zVmMCH07DqUkjz0S8ej-R7*Y(!Ng7}XLl}}d2t@-7VF*Kt;W$YH3}FaEG6$h(fFTTF zNHH8IX@DUNVMyj66b&$hAq**o<0K6*gdq&c9E73)hA@O7#c-UY0fsPyA(?|vG{6vs zFr*lclQh5(hA<>^5Q+vE!VrcO!*P-Z7{U;SWDY{n07DqUkYYGa(f~sk!jQ~CC>mf0 zLl{yF$4MGs2tyc>IS54q3}FaEis3j(0}NpZLox@UXn-LMVMs9?Cux8o3}Hy-AQTNS zgdq$mhT|j+FoYot$sB~D0fsPyA;oZ#Pa1I=fvycTv5uk`}In4~I%a*>7AID~!5E@t!fwyS@gM_&u;XB)58;c_?rL?9N` zqiJJN=I7g=T-h~~Kx((2?j;Z)K!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ x009C72oNAZfB*pkJqW~Wm7i}tY-Edp2&8t$qIxv#u_y;}B**AMAT_;ywl7<32^|0c literal 0 HcmV?d00001 diff --git a/apps/plugins/bitmaps/native/_2048_background.224x224x24.bmp b/apps/plugins/bitmaps/native/_2048_background.224x224x24.bmp new file mode 100644 index 0000000000000000000000000000000000000000..531d5ed5412a01f512fa18c09b43a1e797a26884 GIT binary patch literal 150650 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 literal 0 HcmV?d00001 diff --git a/docs/CREDITS b/docs/CREDITS index 0329738b1b..9d6e984964 100644 --- a/docs/CREDITS +++ b/docs/CREDITS @@ -637,6 +637,7 @@ Dmitry Gamza Sebastian Leonhardt Avi Eisenberg Richard Burke +Franklin Wei The libmad team The wavpack team diff --git a/manual/plugins/2048.tex b/manual/plugins/2048.tex new file mode 100644 index 0000000000..863eebb961 --- /dev/null +++ b/manual/plugins/2048.tex @@ -0,0 +1,16 @@ +\subsection{2048} +%\screenshot{plugins/images/ss-2048}{2048}{fig:2048} + +2048 is a simple, addictive puzzle game played by moving tiles in around on a 4x4 grid. Tiles slide as far as possible in the direction chosen by the player each turn until they are stopped by either another tile or the edge of the grid. If two tiles of the same number collide while moving, they merge into a tile with the total value of the two tiles that collided. The resulting tile cannot merge with another the same move. After each move, a tile with the value of 2 or 4 is created in an empty spot on the grid. + +The game is won when a tile with a value of 2048 is created, and the player loses when there are no more possible moves. + +\begin{btnmap} + \PluginUp, \PluginDown, \PluginLeft, \PluginRight + \opt{HAVEREMOTEKEYMAP}{& \PluginRCUp, \PluginRCDown, \PluginRCLeft, \PluginRCRight} + & Slide tiles\\ + + \PluginCancel + \opt{HAVEREMOTEKEYMAP}{& \PluginRCCancel} + & Go to menu\\ +\end{btnmap} diff --git a/manual/plugins/main.tex b/manual/plugins/main.tex index 856af129e7..7369d35c03 100644 --- a/manual/plugins/main.tex +++ b/manual/plugins/main.tex @@ -23,6 +23,8 @@ text files% \opt{archosrecorder,archosfmrecorder,iriverh100,iaudiom5,lcd_color} {and Rockboy in \reference{ref:Rockboy}}.} +\opt{lcd_bitmap}{\input{plugins/2048.tex}} + \opt{lcd_bitmap}{\input{plugins/blackjack.tex}} \opt{lcd_bitmap}{\input{plugins/brickmania.tex}}