/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2005 Adam Boot * * Color graphics from Frozen Bubble (http://www.frozen-bubble.org/) * * 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. * ****************************************************************************/ #include "plugin.h" #ifdef HAVE_LCD_BITMAP #include "xlcd.h" #include "pluginlib_actions.h" #include "fixedpoint.h" PLUGIN_HEADER /* files */ #define SCORE_FILE PLUGIN_GAMES_DIR "/bubbles.score" #define SAVE_FILE PLUGIN_GAMES_DIR "/bubbles.save" /* final game return status */ #define BB_NONE 5 #define BB_WIN 4 #define BB_END 3 #define BB_USB 2 #define BB_QUIT 1 #define BB_LOSE 0 /* play board dimension */ #define BB_HEIGHT 12 #define BB_WIDTH 8 #define BB_LEVEL_HEIGHT 10 /* various amounts */ #define NUM_SCORES 10 #define NUM_LEVELS 100 #define NUM_QUEUE 2 #define NUM_BUBBLES 8 #define MIN_ANGLE -76 #define MAX_ANGLE 76 #define NUM_COMPRESS 9 #define MAX_SHOTTIME 1000 /* keyboard layouts */ #if CONFIG_KEYPAD != SANSA_E200_PAD /* sansa uses the wheel instead of left/right */ #define BUBBLES_LEFT PLA_LEFT #define BUBBLES_LEFT_REP PLA_LEFT_REPEAT #define BUBBLES_RIGHT PLA_RIGHT #define BUBBLES_RIGHT_REP PLA_RIGHT_REPEAT #define ANGLE_STEP 4 #define ANGLE_STEP_REP 4 #else #define BUBBLES_LEFT PLA_UP #define BUBBLES_LEFT_REP PLA_UP_REPEAT #define BUBBLES_RIGHT PLA_DOWN #define BUBBLES_RIGHT_REP PLA_DOWN_REPEAT #define ANGLE_STEP 2 #define ANGLE_STEP_REP 4 #endif #define BUBBLES_QUIT PLA_QUIT #define BUBBLES_START PLA_START #define BUBBLES_SELECT PLA_FIRE #define BUBBLES_RESUME PLA_MENU #if CONFIG_KEYPAD != ONDIO_PAD #define BUBBLES_LVLINC PLA_UP #define BUBBLES_LVLINC_REP PLA_UP_REPEAT #define BUBBLES_LVLDEC PLA_DOWN #define BUBBLES_LVLDEC_REP PLA_DOWN_REPEAT #else /* ondio keys */ #define BUBBLES_LVLINC PLA_RIGHT #define BUBBLES_LVLINC_REP PLA_RIGHT_REPEAT #define BUBBLES_LVLDEC PLA_LEFT #define BUBBLES_LVLDEC_REP PLA_LEFT_REPEAT #endif /* external bitmaps */ #ifdef HAVE_LCD_COLOR #include "bubbles_background.h" #endif #include "bubbles_bubble.h" #include "bubbles_emblem.h" #define BUBBLE_WIDTH BMPWIDTH_bubbles_bubble #define BUBBLE_HEIGHT BMPHEIGHT_bubbles_bubble #define EMBLEM_WIDTH BMPWIDTH_bubbles_emblem #define EMBLEM_HEIGHT (BMPHEIGHT_bubbles_emblem/8) /* bubbles will consume height of ROW_HEIGHT*(BB_HEIGHT-1)+BUBBLE_HEIGHT*3/2 */ /* 22x22 bubbles (iPod Video) */ #if (LCD_HEIGHT == 240) && (LCD_WIDTH == 320) #define XOFS 72 #define ROW_HEIGHT 18 #define ROW_INDENT 11 #define MAX_FPS 40 /* 22x22 bubbles (Gigabeat) */ #elif (LCD_HEIGHT == 320) && (LCD_WIDTH == 240) #define XOFS 64 #define ROW_HEIGHT 18 #define ROW_INDENT 11 #define MAX_FPS 30 /* 16x16 bubbles (H300, iPod Color) */ #elif (LCD_HEIGHT == 176) && (LCD_WIDTH == 220) #define XOFS 46 #define ROW_HEIGHT 14 #define ROW_INDENT 8 #define MAX_FPS 30 /* 16x16 bubbles (Sansa E200) */ #elif (LCD_HEIGHT == 220) && (LCD_WIDTH == 176) #define XOFS 48 #define ROW_HEIGHT 14 #define ROW_INDENT 8 #define MAX_FPS 30 /* 12x12 bubbles (iPod Nano) */ #elif (LCD_HEIGHT == 132) && (LCD_WIDTH == 176) #define XOFS 40 #define ROW_HEIGHT 10 #define ROW_INDENT 6 #define MAX_FPS 40 /* 12x12 bubbles (H100, H10, iAudio X5, iPod 3G, iPod 4G grayscale) */ #elif (LCD_HEIGHT == 128) && ((LCD_WIDTH == 160) || (LCD_WIDTH == 128)) #define XOFS 33 #define ROW_HEIGHT 10 #define ROW_INDENT 6 #define MAX_FPS 30 /* 10x10 bubbles (iPod Mini) */ #elif (LCD_HEIGHT == 110) && (LCD_WIDTH == 138) #define XOFS 33 #define ROW_HEIGHT 8 #define ROW_INDENT 5 #define MAX_FPS 30 /* 9x9 bubbles (iAudio M3) */ #elif (LCD_HEIGHT == 96) && (LCD_WIDTH == 128) #define XOFS 45 #define ROW_HEIGHT 7 #define ROW_INDENT 4 #define MAX_FPS 30 /* 8x8 bubbles (Sansa C200) */ #elif (LCD_HEIGHT == 80) && (LCD_WIDTH == 132) #define XOFS 45 #define ROW_HEIGHT 6 #define ROW_INDENT 4 #define MAX_FPS 30 /* 8x7 bubbles (Archos recorder, Ondio) */ #elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 112) #define XOFS 33 #define ROW_HEIGHT 5 #define ROW_INDENT 4 #define MAX_FPS 20 #else #error BUBBLES: Unsupported LCD type #endif #define TEXT_LINES (LCD_HEIGHT/8) /* shot position */ #define SHOTX XOFS+ROW_INDENT+BUBBLE_WIDTH*3 #define SHOTY ROW_HEIGHT*(BB_HEIGHT-1)+BUBBLE_HEIGHT/2 /* collision distance squared */ #define MIN_DISTANCE ((BUBBLE_WIDTH*8)/10)*((BUBBLE_HEIGHT*8)/10) /* global rockbox api */ static const struct plugin_api* rb; /* levels */ char level[NUM_LEVELS][BB_LEVEL_HEIGHT][BB_WIDTH] = { {{ 6, 6, 4, 4, 2, 2, 3, 3}, { 6, 6, 4, 4, 2, 2, 3, -1}, { 2, 2, 3, 3, 6, 6, 4, 4}, { 2, 3, 3, 6, 6, 4, 4, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 7, 7, 7, 7, 7, 7, -1}, {-1, 1, 1, 1, 1, 1, -1, -1}, {-1, -1, 2, 2, 2, 2, -1, -1}, {-1, -1, -1, 2, -1, -1, -1, -1}, {-1, -1, -1, 2, 2, -1, -1, -1}, {-1, -1, -1, 5, -1, -1, -1, -1}, {-1, -1, -1, 5, 5, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, 7, -1, -1, 7, -1, -1}, {-1, -1, 7, 1, 7, -1, -1, -1}, {-1, -1, -1, 1, 2, -1, -1, -1}, {-1, -1, 1, 2, 1, -1, -1, -1}, {-1, -1, -1, 2, 5, -1, -1, -1}, {-1, -1, 3, 5, 3, -1, -1, -1}, {-1, -1, -1, 5, 3, -1, -1, -1}, {-1, -1, -1, 3, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 0, 0, -1, -1, -1}, {-1, -1, 5, 0, 1, -1, -1, -1}, {-1, -1, 3, 5, 1, 6, -1, -1}, {-1, 4, 3, -1, 6, 7, -1, -1}, {-1, 7, 4, -1, -1, 7, 4, -1}, { 6, 7, -1, -1, -1, 4, 3, -1}, { 1, 6, -1, -1, -1, -1, 3, 5}, { 1, -1, -1, -1, -1, -1, 5, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, 0, 0, 0, 0, -1, -1}, {-1, 0, 1, 1, 1, 0, -1, -1}, {-1, 0, 1, 0, 0, 1, 0, -1}, {-1, 0, 1, 1, 1, 0, -1, -1}, {-1, -1, 0, 0, 0, 0, -1, -1}, {-1, -1, 7, -1, 7, -1, -1, -1}, {-1, -1, 7, 7, 7, 7, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 4, 4, 4, 6, 6, 6, -1}, { 4, -1, -1, -1, -1, -1, 6, -1}, {-1, 4, -1, -1, -1, -1, 6, -1}, { 4, 2, 3, 1, 2, 3, 6, -1}, {-1, 3, 1, 2, 3, 1, 2, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 4, 4, 4, 6, 6, 6, -1}, { 4, -1, -1, -1, -1, -1, 6, -1}, {-1, 4, -1, -1, -1, -1, 6, -1}, { 4, 2, 3, 1, 2, 3, 6, -1}, {-1, 3, 1, 2, 3, 1, 2, -1}, {-1, 2, 3, 1, 2, 3, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 0, 0, -1, -1, 2, 2, -1}, {-1, 5, -1, -1, -1, 3, -1, -1}, {-1, 0, -1, -1, -1, 6, -1, -1}, {-1, 3, -1, -1, -1, 0, -1, -1}, {-1, 4, -1, -1, -1, 5, -1, -1}, {-1, 2, -1, -1, -1, 3, -1, -1}, {-1, 2, -1, -1, -1, 1, -1, -1}, {-1, 3, -1, -1, -1, 4, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 3, -1, -1, -1, -1, -1, -1, 3}, { 6, 3, 2, 4, 6, 3, 2, -1}, { 4, -1, -1, -1, -1, -1, -1, 4}, { 2, 4, 6, 3, 2, 4, 6, -1}, {-1, -1, -1, 6, -1, -1, -1, -1}, {-1, -1, -1, 3, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 2, -1, 1, -1, 1, -1, 2}, { 1, 2, -1, 2, 1, -1, 1, -1}, { 1, -1, 1, -1, 2, -1, 2, -1}, { 2, 1, -1, 1, 2, -1, 2, -1}, {-1, 2, -1, 2, -1, 2, -1, 2}, { 1, 2, -1, 2, 1, -1, 1, -1}, { 1, -1, 1, -1, 2, -1, 1, -1}, { 2, 2, -1, 1, 1, -1, 2, -1}, {-1, 2, -1, 1, -1, 1, -1, 1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 7, 7, -1, -1, 5, 5, -1}, { 1, -1, -1, -1, -1, -1, 4, -1}, { 2, 1, -1, -1, -1, -1, 4, 3}, { 2, -1, -1, -1, -1, -1, 3, -1}, { 1, 2, -1, -1, -1, -1, 3, 4}, { 1, -1, -1, -1, -1, -1, 4, -1}, { 7, 1, -1, -1, -1, -1, 4, 5}, { 7, 7, -1, -1, -1, 5, 5, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 7, 7, -1, -1, -1, -1, 5, 5}, { 1, 5, -1, -1, -1, 7, 4, -1}, { 2, 1, -1, -1, -1, -1, 4, 3}, { 2, -1, -1, -1, -1, -1, 3, -1}, { 1, 5, -1, -1, -1, -1, 7, 4}, { 1, -1, -1, -1, -1, -1, 4, -1}, { 7, 1, -1, -1, -1, -1, 4, 5}, { 7, 5, -1, -1, -1, 7, 5, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 0, 0, -1, -1, -1}, {-1, -1, 5, 0, 1, -1, -1, -1}, {-1, -1, 3, 5, 1, 6, -1, -1}, {-1, 4, 3, 2, 6, 2, -1, -1}, {-1, 7, 4, 7, 2, 2, 4, -1}, { 6, 7, 7, 3, 3, 4, 3, -1}, { 1, 6, 1, 1, 1, 3, 3, 5}, { 1, 1, -1, -1, -1, -1, 5, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, 0, -1, -1, 0, -1, -1}, {-1, 3, 3, -1, 3, 3, -1, -1}, {-1, 0, 2, 0, 0, 2, 0, -1}, {-1, 3, 3, -1, 3, 3, -1, -1}, {-1, -1, 0, -1, -1, 0, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 1, 1, -1, -1, -1}, {-1, -1, 2, 2, 2, -1, -1, -1}, {-1, -1, 3, 3, 3, 3, -1, -1}, {-1, 4, 4, 4, 4, 4, -1, -1}, {-1, 5, 5, 5, 5, 5, 5, -1}, {-1, -1, -1, 6, -1, -1, -1, -1}, {-1, -1, -1, 7, 7, -1, -1, -1}, {-1, -1, -1, 0, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 2, 5, -1, -1, -1}, {-1, 4, 3, -1, -1, -1, -1, -1}, { 6, 7, -1, 5, 2, -1, -1, -1}, {-1, -1, -1, -1, 3, 4, -1, -1}, {-1, -1, -1, 2, 5, -1, 7, 6}, {-1, 4, 3, -1, -1, -1, -1, -1}, { 6, 7, -1, 5, 2, -1, -1, -1}, {-1, -1, -1, -1, 3, 4, -1, -1}, {-1, -1, -1, -1, -1, -1, 7, 6}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 5, 5, -1, -1, -1}, {-1, -1, -1, 3, -1, -1, -1, -1}, {-1, -1, -1, 1, -1, -1, -1, -1}, {-1, -1, -1, 7, -1, -1, -1, -1}, {-1, -1, -1, 2, -1, -1, -1, -1}, {-1, -1, -1, 4, -1, -1, -1, -1}, {-1, -1, -1, 5, -1, -1, -1, -1}, {-1, -1, -1, 3, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 0, 1, -1, -1, -1}, {-1, -1, 0, 2, 7, 7, -1, -1}, {-1, -1, -1, 0, 1, 7, -1, -1}, {-1, 0, 0, 0, 0, -1, -1, -1}, {-1, 0, 0, 0, 1, 1, -1, -1}, { 0, 0, 0, 1, 1, 1, -1, -1}, {-1, 0, 0, 1, 1, 1, -1, -1}, {-1, 0, 0, 0, 7, 7, -1, -1}, {-1, -1, 7, 7, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 1, -1, -1, -1, -1, -1, -1}, { 1, -1, -1, -1, -1, -1, -1, -1}, {-1, 2, 3, 4, 7, 6, 5, -1}, {-1, -1, -1, -1, -1, -1, 1, -1}, {-1, -1, -1, -1, -1, -1, 1, -1}, {-1, 2, 3, 4, 7, 6, -1, -1}, {-1, 1, -1, -1, -1, -1, -1, -1}, { 1, -1, -1, -1, -1, -1, -1, -1}, {-1, 2, 3, 4, 7, 6, 5, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 6, -1, -1, -1, -1, -1, -1}, { 5, -1, -1, -1, -1, -1, -1, -1}, { 2, 3, 4, 7, 6, 5, 2, 3}, {-1, -1, -1, -1, -1, -1, 4, -1}, {-1, -1, -1, -1, -1, -1, 7, -1}, {-1, 4, 3, 2, 5, 6, -1, -1}, {-1, 7, -1, -1, -1, -1, -1, -1}, { 6, -1, -1, -1, -1, -1, -1, -1}, { 5, 2, 3, 4, 7, 6, 5, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 3, 2, 1, 0, 0, 1, 2, 3}, { 3, 2, 1, 0, 1, 2, 3, -1}, { 4, 3, 2, 1, 1, 2, 3, 4}, { 4, 3, 2, 1, 2, 3, 4, -1}, { 5, 4, 3, 2, 2, 3, 4, 5}, { 5, 4, 3, 2, 3, 4, 5, -1}, { 6, 5, 4, 3, 3, 4, 5, 6}, { 6, 5, 4, 3, 4, 5, 6, -1}, { 7, 6, 5, 4, 4, 5, 6, 7}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 5, 5, -1, -1, -1}, {-1, -1, -1, 3, -1, -1, -1, -1}, {-1, -1, -1, 2, 4, -1, -1, -1}, {-1, -1, -1, 6, -1, -1, -1, -1}, {-1, -1, -1, 2, 4, -1, -1, -1}, {-1, 2, -1, 5, -1, 4, -1, -1}, { 1, 0, 1, 0, 1, 0, 1, 0}, { 3, -1, 3, -1, 2, -1, 6, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, 1, -1, -1, -1}, { 7, 4, 3, 5, -1, -1, -1, -1}, { 6, -1, -1, 1, -1, -1, -1, -1}, {-1, -1, -1, 5, 3, 4, 7, -1}, { 6, -1, -1, -1, 1, -1, -1, 6}, { 7, 4, 3, 5, -1, -1, -1, -1}, {-1, -1, -1, 1, -1, -1, -1, 6}, {-1, -1, -1, 5, 3, 4, 7, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, 7, 3, 6, -1}, {-1, -1, 3, 7, 3, 6, 3, -1}, {-1, -1, 5, 7, 3, 6, 3, -1}, {-1, 6, 7, 3, 6, 7, -1, -1}, {-1, 7, 7, 3, 6, 1, -1, -1}, { 3, 7, 3, 6, 3, -1, -1, -1}, { 5, 6, 2, 7, 1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 5, -1, -1, -1, -1, -1, -1, 5}, { 5, -1, 6, 6, 6, -1, 5, -1}, {-1, 5, 4, -1, -1, 4, 5, -1}, {-1, 3, -1, -1, -1, 3, -1, -1}, {-1, 6, 0, -1, -1, 0, 6, -1}, {-1, 3, -1, -1, -1, 3, -1, -1}, {-1, -1, 4, -1, -1, 4, -1, -1}, {-1, -1, 6, 6, 6, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 7, 0, -1, -1, 0, 7, -1}, { 7, -1, 0, -1, 0, -1, 7, -1}, { 7, 1, -1, 0, 0, -1, 1, 7}, { 7, 1, 2, 0, 2, 1, 7, -1}, { 7, 6, 3, 2, 2, 3, 6, 7}, { 7, -1, 3, 2, 3, -1, 7, -1}, {-1, 7, 7, 3, 3, 7, 7, -1}, {-1, -1, -1, 3, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 3, -1, 1, -1, 7, -1, 6}, { 5, -1, 7, -1, 7, -1, 6, -1}, { 6, -1, 0, -1, 5, -1, 3, -1}, {-1, 2, -1, 1, -1, 5, -1, -1}, {-1, 4, -1, 3, -1, 4, -1, -1}, { 2, -1, 3, -1, 2, -1, -1, -1}, {-1, -1, 4, -1, 6, -1, -1, -1}, {-1, -1, -1, 5, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, 1, -1, -1, -1}, {-1, -1, -1, -1, 3, -1, -1, -1}, { 6, 1, 3, 1, 2, 1, 4, 1}, {-1, -1, -1, -1, 6, -1, -1, -1}, {-1, -1, -1, 4, 1, -1, -1, -1}, {-1, -1, 1, -1, 3, -1, -1, -1}, {-1, -1, -1, 2, 1, -1, -1, -1}, {-1, -1, -1, -1, 4, -1, -1, -1}, {-1, -1, -1, 6, 1, -1, -1, -1}, {-1, -1, -1, 6, -1, -1, -1, -1}}, {{-1, -1, -1, 5, 4, -1, -1, -1}, {-1, -1, 4, 1, 0, -1, -1, -1}, {-1, -1, -1, 2, 3, -1, -1, -1}, {-1, 1, 4, -1, 2, 2, -1, -1}, {-1, 3, 1, 2, 5, 1, 4, -1}, {-1, 4, 2, -1, 0, 4, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, 1, -1, -1, -1}, {-1, -1, -1, 1, -1, -1, -1, -1}, {-1, 2, -1, -1, 1, -1, 5, -1}, { 5, -1, -1, 1, -1, -1, 0, -1}, {-1, 6, -1, -1, 1, -1, 4, -1}, {-1, 0, -1, 1, -1, 5, -1, -1}, {-1, -1, 5, 5, 0, 1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 6, 3, -1, -1, -1}, {-1, -1, 3, 2, 6, -1, -1, -1}, {-1, -1, 2, 6, 3, 2, -1, -1}, {-1, 6, 3, 2, 6, 3, -1, -1}, {-1, 3, 2, 6, 3, 2, 6, -1}, { 2, 6, 3, 2, 6, 3, 2, -1}, { 6, 3, 2, 6, 3, 2, 6, 3}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 6, 6, 6, 6, 6, 6, 6, 6}, { 4, -1, -1, -1, -1, -1, -1, -1}, {-1, 3, 2, 5, 7, 6, 4, 3}, {-1, 5, -1, -1, -1, -1, -1, -1}, {-1, -1, 7, 6, 4, 3, 2, 5}, {-1, -1, 4, -1, -1, -1, -1, -1}, {-1, -1, -1, 3, 2, 5, 7, 6}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 1, -1, 7, -1, -1, 6, -1, 2}, { 6, -1, 1, -1, 6, 1, 3, -1}, {-1, 4, -1, 7, 2, -1, 7, -1}, { 2, 7, -1, -1, -1, 4, -1, -1}, { 6, -1, 3, 5, 0, 2, -1, 7}, { 1, -1, -1, -1, -1, -1, 1, -1}, {-1, 1, 4, 5, 7, 5, 1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 6, 6, 6, -1, -1, 6, 6, 6}, {-1, -1, 6, -1, 6, -1, -1, -1}, {-1, -1, 2, 3, 3, 2, -1, -1}, {-1, 3, -1, 5, -1, 3, -1, -1}, {-1, -1, 5, 3, 3, 5, -1, -1}, {-1, -1, 6, 1, 6, -1, -1, -1}, {-1, 4, 2, -1, -1, 2, 4, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 5, 5, -1, -1, -1}, {-1, -1, 5, -1, -1, -1, -1, -1}, {-1, 3, 4, 6, 6, -1, -1, 5}, { 3, 3, 4, 6, 5, -1, 5, -1}, { 3, 2, 3, 6, 6, 5, 5, -1}, { 3, 3, 4, 6, 5, -1, 5, -1}, {-1, 3, 4, 6, 6, -1, -1, 5}, {-1, -1, 5, -1, -1, -1, -1, -1}, {-1, -1, -1, 5, 5, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 1, -1, -1, -1, -1, -1, -1, 1}, { 1, -1, 2, 2, 2, -1, 1, -1}, {-1, 1, 2, 3, 3, 2, 1, -1}, { 6, 2, 3, -1, 3, 2, 6, -1}, { 6, 2, 3, -1, -1, 3, 2, 6}, { 6, 2, 3, -1, 3, 2, 6, -1}, { 3, 3, 3, 7, 7, 3, 3, 3}, { 0, 5, 0, 2, 0, 5, 0, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, 7, 7, 7, -1, -1, -1}, {-1, 7, 2, 2, 7, -1, -1, -1}, {-1, 7, 5, 5, 5, 7, -1, -1}, { 7, 7, 7, 7, 7, 7, -1, -1}, {-1, -1, 6, -1, 6, -1, -1, -1}, {-1, 6, -1, -1, 6, -1, -1, -1}, {-1, 6, 4, 4, -1, 6, 4, 4}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 3, 3, -1, 3, 3, 3, -1}, { 3, 7, 5, 4, 6, 5, 3, -1}, { 1, 3, 3, 3, -1, 3, 3, 1}, { 2, 1, 2, 1, 2, 1, 2, -1}, { 1, 3, 3, -1, 3, 3, 3, 1}, { 3, 5, 6, 4, 5, 7, 3, -1}, { 2, 3, 3, 3, -1, 3, 3, 2}, { 1, 1, 2, 2, 2, 1, 1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 6, 5, -1, -1, -1, -1, -1}, { 3, 1, 3, -1, -1, -1, -1, -1}, {-1, 5, 6, -1, -1, -1, -1, -1}, {-1, -1, 5, 3, -1, -1, -1, -1}, {-1, -1, 6, 1, 6, -1, -1, -1}, {-1, -1, 3, 5, -1, -1, -1, -1}, {-1, -1, -1, -1, 3, 6, -1, -1}, {-1, -1, -1, 5, 6, 5, -1, -1}, {-1, -1, -1, -1, 6, 3, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 6, 3, 7, 4, 5, 1, 6, 3}, { 5, 1, 6, 3, 7, 4, 5, -1}, { 6, 3, 7, 4, 5, 1, 6, 3}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, -1, 4, 4}, {-1, -1, 7, 7, 7, 4, 4, -1}, {-1, -1, -1, -1, -1, -1, 4, 4}, {-1, 1, -1, -1, -1, 7, -1, -1}, {-1, 1, 1, -1, -1, 7, -1, -1}, { 3, 3, 3, -1, 7, -1, -1, -1}, { 3, -1, 2, 3, 3, 3, -1, 3}, {-1, 2, -1, 3, -1, 3, 3, -1}, {-1, 2, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, 4, -1, -1, -1, -1, -1}, {-1, 7, 4, -1, -1, -1, -1, -1}, {-1, -1, 7, 4, -1, -1, -1, -1}, {-1, 4, 7, 4, -1, -1, -1, -1}, { 1, 1, 1, 1, 1, 1, 1, -1}, { 1, 2, 1, 2, 1, 1, -1, -1}, { 2, 2, 2, 2, 2, 2, 2, 2}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 0, -1, -1, -1, -1, -1, -1, 6}, { 6, 1, 4, 3, 7, 5, 0, -1}, { 0, -1, -1, -1, -1, -1, -1, 6}, { 6, 1, 4, 3, 7, 5, 0, -1}, { 0, -1, -1, -1, -1, -1, -1, 6}, { 6, 1, 4, 3, 7, 5, 0, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 3, 3, 4, 6, 6, 4, 3, 3}, { 0, 3, 4, 6, 4, 3, 1, -1}, { 5, 1, 3, 4, 4, 3, 0, 1}, { 0, 1, 3, 4, 3, 1, 0, -1}, { 2, 1, 6, 3, 3, 0, 0, 1}, { 0, 3, 4, 3, 6, 1, 5, -1}, { 6, 1, 2, 6, 4, 0, 0, 2}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 6, 6, -1, -1, -1, -1, 4, 4}, { 4, 0, -1, -1, -1, 3, 6, -1}, { 0, 6, -1, -1, -1, -1, 4, 2}, { 7, -1, -1, -1, -1, -1, 7, -1}, { 4, 4, -1, -1, -1, -1, 5, 6}, { 6, 4, 7, 7, 5, 6, 4, -1}, {-1, 7, 6, 4, 6, 4, 7, -1}, {-1, 0, -1, 7, -1, 7, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 5, -1, -1, -1, -1, 4, -1}, {-1, 5, -1, -1, -1, 4, -1, -1}, {-1, -1, 5, 6, 6, 4, -1, -1}, {-1, -1, 2, -1, 2, -1, -1, -1}, { 0, 0, 6, -1, -1, 6, 1, 1}, {-1, -1, 2, -1, 2, -1, -1, -1}, {-1, -1, 7, 6, 6, 3, -1, -1}, {-1, 7, -1, -1, -1, 3, -1, -1}, {-1, 7, -1, -1, -1, -1, 3, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 6, -1, -1, -1, -1, 2, -1}, { 1, 7, 1, 1, 1, 3, 1, -1}, {-1, -1, 4, 1, 1, 4, -1, -1}, {-1, 1, 3, 1, 7, 1, -1, -1}, {-1, -1, -1, 2, 6, -1, -1, -1}, {-1, -1, 1, 5, 1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 7, 7, 7, 7, 7, 7, 7, 7}, { 7, -1, -1, -1, -1, -1, 7, -1}, { 7, -1, -1, 2, 0, 5, 2, 2}, { 7, -1, -1, -1, 0, 3, 6, -1}, { 7, -1, -1, -1, -1, -1, 4, 0}, { 5, 5, -1, -1, -1, -1, -1, -1}, { 4, 3, 6, 2, -1, -1, -1, -1}, { 0, 2, 0, 4, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, 1, -1, -1, 1, -1, -1}, {-1, 4, -1, -1, 5, -1, -1, -1}, {-1, 7, -1, -1, 1, 1, 1, -1}, { 6, -1, -1, -1, -1, 7, -1, -1}, { 1, 1, 1, 1, -1, 4, -1, -1}, {-1, -1, 5, -1, -1, -1, -1, -1}, {-1, -1, 0, -1, -1, -1, -1, -1}, {-1, 3, -1, -1, -1, -1, -1, -1}, {-1, 1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 7, 7, -1, -1, 7, 7, -1}, { 6, -1, 4, -1, 4, -1, 6, -1}, { 5, -1, -1, 3, 3, -1, -1, 5}, { 6, -1, -1, -1, -1, -1, 6, -1}, {-1, 7, -1, -1, -1, -1, 7, -1}, {-1, 4, -1, -1, -1, 4, -1, -1}, {-1, -1, 3, -1, -1, 3, -1, -1}, {-1, -1, 2, -1, 2, -1, -1, -1}, {-1, -1, -1, 5, 5, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 0, 0, -1, -1, 0, 0, -1}, { 7, 4, 6, 6, 6, 4, 3, -1}, { 5, 6, 6, 6, 2, 6, 6, 3}, { 7, 4, 6, 6, 6, 4, 3, -1}, {-1, 0, 0, -1, -1, 0, 0, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, -1, 7, 7, 7}, {-1, -1, -1, -1, 2, 7, 7, -1}, {-1, 0, 7, 7, 7, -1, 7, 7}, { 6, 7, 7, 7, -1, -1, -1, -1}, { 6, -1, -1, -1, 7, 7, 7, 7}, { 6, -1, -1, -1, -1, -1, -1, -1}, { 4, 2, 2, 2, 4, -1, 3, -1}, { 4, 4, 4, 4, 3, 3, 3, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 4, -1, -1, 7, -1, 6, -1, 7}, { 7, 6, 7, -1, -1, 7, 4, -1}, {-1, -1, 7, -1, -1, 7, -1, -1}, {-1, 0, 0, 0, 0, 0, 3, -1}, {-1, -1, 0, 2, 2, 0, 6, 4}, {-1, -1, 0, 0, 0, 1, 3, -1}, {-1, -1, -1, 0, 0, -1, 3, 4}, {-1, -1, -1, 6, -1, 5, 6, -1}, {-1, -1, -1, -1, -1, -1, 1, 0}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 5, -1, -1, -1, -1, 5, -1}, { 0, -1, -1, 0, -1, -1, 0, -1}, { 0, 0, 0, 2, 2, 0, 0, 0}, { 0, -1, -1, 0, -1, -1, 0, -1}, {-1, 7, -1, 3, -1, -1, 7, -1}, {-1, -1, 3, 6, -1, -1, -1, -1}, {-1, -1, -1, 6, -1, -1, -1, -1}, {-1, 3, 6, -1, -1, -1, -1, -1}, {-1, 3, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 6, 5, -1, -1, -1}, {-1, -1, 2, 6, 3, -1, -1, -1}, {-1, -1, 5, 4, 7, 1, -1, -1}, {-1, 6, 2, 2, 3, 4, -1, -1}, {-1, -1, 3, 7, 3, 6, -1, -1}, {-1, -1, 1, 3, 2, -1, -1, -1}, {-1, -1, -1, 4, 5, -1, -1, -1}, {-1, -1, -1, 4, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 7, 7, -1, 2, 2, -1, 6, 6}, { 6, -1, -1, 6, -1, -1, 3, -1}, { 2, -1, -1, 1, -1, -1, 2, -1}, { 5, -1, -1, 3, -1, -1, 2, -1}, { 1, -1, -1, 2, -1, -1, 1, -1}, { 5, -1, -1, 2, -1, -1, 2, -1}, { 6, -1, -1, 1, -1, -1, 7, -1}, { 5, -1, -1, 5, -1, -1, 4, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 6, 6, -1, -1, -1}, {-1, 0, 4, 4, 4, 0, -1, -1}, {-1, -1, -1, 6, 6, -1, -1, -1}, {-1, -1, 2, 7, 2, -1, -1, -1}, {-1, -1, -1, 6, 6, -1, -1, -1}, {-1, 0, 5, 5, 5, 0, -1, -1}, {-1, -1, -1, 3, 3, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, 4, 1, 3, -1, -1, -1}, {-1, 1, -1, -1, 1, -1, -1, -1}, {-1, -1, 4, 1, 3, 4, 1, -1}, {-1, 1, 3, 4, -1, -1, 4, -1}, {-1, 3, -1, -1, 3, 4, 1, -1}, {-1, 1, 3, 4, 1, 3, -1, -1}, {-1, -1, 4, 1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 6, 4, -1, 3, 2, 5, -1}, { 0, -1, -1, -1, -1, -1, 1, -1}, {-1, 2, 3, 5, -1, 4, 6, -1}, { 0, -1, -1, -1, -1, -1, 1, -1}, {-1, 4, 6, -1, 2, 5, 3, -1}, { 0, -1, -1, -1, -1, -1, 1, -1}, {-1, 5, 2, 3, -1, 4, 6, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 6, 6, -1, -1, -1}, {-1, -1, 7, 6, 4, -1, -1, -1}, {-1, 2, 1, 7, 4, 1, 3, -1}, { 2, 1, 1, 1, 1, 1, 3, -1}, {-1, 2, 2, 2, 3, 3, 3, -1}, {-1, -1, -1, 5, -1, -1, -1, -1}, {-1, -1, -1, 2, 3, -1, -1, -1}, {-1, -1, -1, 5, -1, -1, -1, -1}, {-1, -1, 2, 2, 3, 3, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 4, -1, 5, -1, -1, 3, -1, 6}, { 2, -1, 3, -1, 2, -1, 4, -1}, { 4, -1, -1, 1, 0, -1, -1, 6}, { 6, -1, 2, 3, 5, -1, 4, -1}, { 4, -1, -1, 0, 1, -1, -1, 6}, { 2, -1, 5, -1, 3, -1, 4, -1}, { 4, -1, 3, -1, -1, 2, -1, 6}, { 6, -1, -1, -1, -1, -1, 4, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 2, 6, 0, 5, 5, 1, 3, 4}, { 1, -1, -1, 2, -1, -1, 0, -1}, { 4, -1, -1, 3, 6, -1, -1, 2}, {-1, -1, -1, 0, -1, -1, -1, -1}, {-1, -1, -1, 1, 4, -1, -1, -1}, {-1, -1, -1, 2, -1, -1, -1, -1}, {-1, -1, -1, 6, 3, -1, -1, -1}, {-1, -1, -1, 5, -1, -1, -1, -1}, {-1, -1, -1, 4, 1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, -1, 5, 1, 1, 3}, { 0, 5, 1, 0, 5, 3, 3, -1}, { 5, 1, 0, 5, 1, 0, 5, 1}, { 0, 5, 1, 0, 5, 1, 6, -1}, {-1, -1, -1, -1, 1, 6, 5, 1}, {-1, -1, -1, -1, 5, 1, 6, -1}, {-1, -1, -1, -1, 1, 0, 5, 1}, {-1, -1, -1, -1, 5, 1, 0, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 0, 7, 3, -1, -1, 2, 2}, {-1, 0, 7, 3, -1, -1, 2, -1}, {-1, 0, 7, 3, -1, -1, 2, 2}, {-1, 0, 7, 3, -1, 3, 1, -1}, {-1, 0, 7, 3, -1, 6, 4, 5}, {-1, 0, 7, 3, -1, 7, 0, -1}, {-1, 0, 7, 3, -1, 2, 3, 4}, {-1, 0, 7, 3, -1, 5, 6, -1}, {-1, -1, -1, -1, -1, 7, 0, 1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 7, 7, 7, 7, -1}, { 3, 4, 5, -1, -1, -1, 7, -1}, { 2, -1, -1, -1, -1, -1, -1, 3}, { 7, -1, -1, -1, -1, -1, 4, -1}, { 7, -1, -1, -1, 3, 4, 5, 6}, { 7, -1, -1, 2, 0, 1, 2, -1}, { 6, -1, -1, -1, 3, 4, 5, 6}, { 0, 1, -1, -1, -1, -1, -1, -1}, { 2, 3, 4, -1, -1, -1, -1, -1}, { 5, 6, 0, -1, -1, -1, -1, -1}}, {{-1, 7, -1, -1, -1, -1, 2, -1}, { 1, 1, -1, -1, -1, 3, 3, -1}, {-1, 2, -1, -1, -1, -1, 4, -1}, { 3, 3, -1, -1, -1, 5, 5, -1}, {-1, 4, -1, -1, -1, -1, 6, -1}, { 5, 5, -1, -1, -1, 1, 1, -1}, {-1, 6, -1, -1, -1, -1, 7, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 4, -1, -1, -1, -1, 4, -1}, { 2, -1, -1, 1, -1, -1, 2, -1}, { 5, -1, -1, 0, 0, -1, -1, 5}, { 5, -1, -1, 1, -1, -1, 6, -1}, {-1, 4, 2, 7, 7, 5, 4, -1}, {-1, -1, -1, 6, -1, -1, -1, -1}, {-1, -1, -1, 3, 3, -1, -1, -1}, {-1, -1, -1, 7, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 1, -1, -1, 2, 3, 4, -1}, { 2, -1, -1, 3, 0, 4, -1, -1}, { 4, -1, -1, 2, 3, 1, -1, -1}, { 3, -1, 4, 3, 0, -1, -1, -1}, { 4, -1, -1, 2, 5, 1, -1, -1}, { 3, -1, 4, 5, 0, 4, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 2, -1, -1, 1, 1, -1, -1, 2}, { 2, -1, 3, 3, 3, -1, 2, -1}, {-1, 2, -1, 4, 4, -1, 2, -1}, {-1, 7, 7, 0, 7, 7, -1, -1}, {-1, -1, -1, 4, 4, -1, -1, -1}, {-1, -1, 5, 7, 5, -1, -1, -1}, { 6, 3, 2, 6, 4, 2, 3, 6}, { 5, -1, -1, -1, -1, -1, 1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 4, 2, 3, 5, 7, 1, 3, 6}, { 1, -1, -1, 1, -1, -1, 1, -1}, { 3, 0, 1, 3, 2, 4, 3, 5}, { 4, -1, -1, 4, -1, -1, 4, -1}, {-1, 5, -1, -1, 5, -1, -1, 5}, { 0, 3, 2, 0, 4, 5, 0, -1}, {-1, 6, -1, -1, 6, -1, -1, 6}, { 7, -1, -1, 7, -1, -1, 7, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 5, 4, -1, 1, 1, -1, -1}, { 5, -1, 4, 1, -1, 1, -1, -1}, { 0, -1, -1, -1, -1, -1, 0, -1}, { 0, 6, 4, -1, -1, 4, 2, -1}, {-1, 4, 3, 5, 2, 6, 3, 6}, {-1, 2, 6, -1, -1, 5, 4, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 6, 6, -1, -1, -1}, {-1, -1, 5, 5, 4, -1, -1, -1}, {-1, -1, 1, 6, 6, 4, -1, -1}, {-1, 1, 7, 2, 5, 3, -1, -1}, {-1, 2, 7, 2, 1, 5, 3, -1}, { 2, 1, 3, 1, 4, 2, 7, -1}, {-1, 3, 1, 3, 4, 2, 7, -1}, {-1, 3, 5, 5, 6, 6, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, 7, 3, -1, -1, -1, -1}, {-1, 1, 7, 6, -1, -1, -1, -1}, {-1, 3, 7, 5, 1, 5, -1, -1}, { 7, 7, 0, 2, 4, 0, 4, -1}, { 7, 1, 4, 6, 5, 6, 5, 7}, { 1, 7, 7, 1, 7, 7, 1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, 1, -1, -1, 1, -1, -1}, {-1, 5, 6, 1, 5, 6, -1, -1}, {-1, 1, 1, 2, 2, 1, 1, -1}, { 4, 7, 1, 0, 1, 7, 4, -1}, {-1, 3, 7, 5, 7, 5, 3, -1}, {-1, 1, 1, 1, 1, 1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 4, -1, -1, -1, 5, -1, -1, 4}, { 6, 6, 7, 6, -1, 4, 5, -1}, { 4, 2, 7, 5, 2, 2, 6, 4}, {-1, -1, 4, 1, -1, 5, 2, -1}, {-1, 5, 2, 7, 7, -1, 7, 4}, { 4, 6, 5, 4, -1, 4, 2, -1}, {-1, -1, -1, 4, -1, 4, 1, -1}, { 0, 0, 0, 5, -1, -1, -1, -1}, {-1, -1, -1, -1, 0, 0, 0, 0}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 1, -1, -1, -1, 0, 0, -1, -1}, { 2, -1, -1, 0, 1, 0, -1, -1}, { 3, -1, -1, 0, 2, 2, 0, -1}, { 4, -1, 0, 1, 1, 1, 0, -1}, { 5, -1, -1, 0, 4, 4, 0, -1}, { 6, -1, -1, 4, 4, 4, -1, -1}, { 7, -1, -1, -1, 4, 4, -1, -1}, {-1, -1, -1, 0, 1, 0, -1, -1}, {-1, -1, -1, 0, 1, 1, 0, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, 3, -1, -1, 1, 7, -1}, {-1, 7, 4, -1, -1, 4, 3, -1}, { 1, -1, -1, 0, 2, 0, -1, -1}, { 5, 4, -1, 3, -1, -1, -1, -1}, { 4, -1, 3, 6, 1, 1, 6, -1}, {-1, 1, -1, -1, 4, -1, 1, -1}, {-1, 7, 5, -1, -1, -1, 3, -1}, {-1, -1, 3, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 1, -1, -1, -1, 1, -1, -1, -1}, { 2, -1, -1, -1, 2, -1, -1, -1}, {-1, 3, -1, -1, 3, 3, -1, -1}, {-1, 4, -1, 4, -1, 4, -1, -1}, {-1, 5, -1, -1, 5, 5, -1, -1}, { 6, -1, -1, 7, 1, 7, -1, -1}, { 7, -1, -1, -1, 6, 6, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 2, -1, -1, 6, -1, 2, 5, 1}, { 5, -1, 4, -1, 4, -1, 4, -1}, { 6, -1, -1, 3, -1, -1, -1, 3}, { 4, 2, 0, -1, -1, -1, 5, -1}, {-1, -1, -1, 6, -1, 3, 6, -1}, {-1, -1, 5, -1, 5, -1, -1, -1}, {-1, -1, -1, 3, -1, 4, 2, 5}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 6, -1, -1, -1, 4, -1, -1, 3}, { 0, 3, -1, -1, 6, -1, 0, -1}, {-1, -1, 7, -1, 1, -1, 3, -1}, { 7, -1, 4, 7, -1, 2, -1, -1}, { 5, 2, 3, 2, 1, 6, -1, 3}, {-1, -1, 0, 4, 3, 5, 4, -1}, {-1, 7, 6, -1, -1, 0, -1, -1}, { 4, 3, -1, -1, -1, 4, 2, -1}, { 0, -1, -1, -1, -1, -1, 6, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 6, 1, 2, 5, 1, 6, 3, 0}, {-1, -1, -1, -1, -1, -1, 4, -1}, { 0, 5, 2, 7, 1, 6, 2, -1}, { 3, -1, -1, -1, -1, -1, -1, -1}, { 6, 7, 6, 4, 0, 5, 2, 6}, {-1, -1, -1, -1, -1, -1, 1, -1}, { 6, 1, 4, 0, 6, 2, 3, -1}, { 0, -1, -1, -1, -1, -1, -1, -1}, {-1, 0, 4, 5, 3, 7, 6, 0}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 0, 1, -1, -1, -1}, {-1, -1, 0, 7, 0, -1, -1, -1}, {-1, -1, 1, 2, 2, 0, -1, -1}, {-1, 0, 7, 0, 7, 0, -1, -1}, {-1, 6, -1, 7, 7, -1, 6, -1}, { 4, 1, 6, 6, 6, 4, 1, -1}, {-1, 5, -1, 7, 7, -1, 5, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 5, 6, -1, -1, -1}, {-1, -1, 3, 3, 3, -1, -1, -1}, {-1, -1, 7, 5, 3, 7, -1, -1}, {-1, 3, -1, 6, -1, 3, -1, -1}, { 2, -1, -1, 3, 7, -1, -1, 1}, { 2, 2, -1, 3, -1, 1, 1, -1}, {-1, 0, 2, 5, 6, 1, 0, -1}, {-1, -1, -1, 3, -1, -1, -1, -1}, {-1, -1, -1, 3, 7, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 6, -1, -1, -1, -1, 2, -1}, {-1, 2, 6, 0, 6, 0, -1, -1}, {-1, 0, -1, -1, -1, -1, -1, -1}, { 6, -1, -1, -1, -1, -1, -1, -1}, {-1, 3, 3, 2, 0, 6, 0, 0}, {-1, 6, -1, -1, -1, -1, 0, -1}, {-1, -1, -1, 6, 0, 2, 6, -1}, {-1, 2, 0, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 0, 7, -1, -1, -1, -1, -1, -1}, { 1, 5, -1, -1, -1, -1, -1, -1}, { 7, 2, 5, -1, -1, -1, -1, -1}, { 6, 3, 4, -1, -1, -1, -1, -1}, { 5, 5, 4, 4, -1, -1, -1, -1}, { 3, 3, 5, 3, -1, -1, -1, -1}, { 1, 2, 2, 5, 3, -1, -1, -1}, { 1, 0, 0, 7, 6, -1, -1, -1}, { 3, 3, 5, 5, 7, 6, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, 2, 6, 6, 2, -1, -1}, {-1, 2, 1, 1, 0, 2, -1, -1}, {-1, 2, 3, 2, 2, 0, 2, -1}, { 2, 3, 2, 5, 2, 7, 2, -1}, { 2, 4, 2, 5, 2, 7, 2, 0}, { 2, 4, 2, 6, 6, 2, 0, -1}, {-1, 2, 5, 2, 2, 2, 7, 2}, {-1, 2, 5, 6, 6, 7, 2, -1}, {-1, -1, 2, 2, 2, 2, 2, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, 0, -1, -1, 0, -1, -1}, { 1, 0, 0, 1, 0, 0, 1, -1}, { 1, 7, 7, 5, 5, 7, 7, 1}, { 3, 2, -1, 2, -1, 2, 3, -1}, { 3, 7, -1, 6, 6, -1, 7, 3}, { 7, -1, -1, 6, -1, -1, 7, -1}, { 4, 4, 5, -1, -1, 5, 4, 4}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 6, 3, -1, -1, 3, 6, -1}, { 6, -1, 2, -1, 2, -1, 6, -1}, { 2, -1, 0, 1, 1, 0, -1, 2}, { 5, 0, -1, 7, -1, 0, 5, -1}, {-1, 5, -1, 6, 6, -1, 5, -1}, { 7, 1, 4, -1, 4, 1, 7, -1}, { 7, -1, 4, -1, -1, 4, -1, 7}, { 2, 0, -1, -1, -1, 0, 2, -1}, {-1, 2, -1, -1, -1, -1, 2, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 6, 1, -1, -1, -1, -1, 4, 0}, { 2, 7, 5, 5, 5, 7, 3, -1}, { 6, 1, -1, -1, -1, -1, 4, 0}, { 2, 5, 7, 7, 7, 5, 3, -1}, { 6, 1, -1, -1, -1, -1, 4, 0}, { 2, 0, 6, 6, 6, 0, 3, -1}, { 6, 1, -1, -1, -1, -1, 4, 0}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 5, -1, -1, 1, 1, -1, -1, 5}, { 5, -1, 4, -1, 4, -1, 5, -1}, {-1, 2, 4, -1, -1, 4, 2, -1}, { 7, 2, -1, -1, -1, 2, 7, -1}, { 0, -1, 0, 4, 4, 0, -1, 0}, { 7, 2, -1, -1, -1, 2, 7, -1}, {-1, 2, 3, -1, -1, 3, 2, -1}, { 5, -1, 3, -1, 3, -1, 5, -1}, { 5, -1, -1, 6, 6, -1, -1, 5}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 2, 2, -1, -1, -1, -1, 5, 5}, { 5, -1, -1, -1, -1, -1, 2, -1}, { 5, -1, -1, -1, -1, -1, -1, 2}, { 1, -1, 1, 5, 1, -1, 3, -1}, { 5, 2, 5, 3, 1, 2, 5, 2}, { 2, 0, 5, -1, 2, 0, 5, -1}, {-1, 3, 7, -1, -1, 3, 7, -1}, {-1, -1, 2, 0, 5, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 0, 6, 5, 2, 3, 4, 1, 7}, {-1, -1, -1, -1, 1, -1, -1, -1}, {-1, -1, -1, 1, 1, -1, -1, -1}, {-1, -1, 1, -1, -1, -1, -1, -1}, { 7, 1, 4, 3, 2, 5, 6, 0}, {-1, -1, -1, -1, 1, -1, -1, -1}, {-1, -1, -1, 1, 1, -1, -1, -1}, {-1, -1, 1, -1, -1, -1, -1, -1}, { 0, 6, 5, 2, 3, 4, 1, 7}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, 1, -1, -1, 1, -1, -1}, {-1, 2, 4, -1, 2, 4, -1, -1}, {-1, 2, 3, 6, 5, 3, 2, -1}, {-1, 6, 5, -1, 6, 5, -1, -1}, {-1, -1, -1, 7, 7, -1, -1, -1}, {-1, -1, -1, 7, -1, -1, -1, -1}, { 1, -1, -1, 7, 7, -1, -1, 3}, { 2, -1, -1, 7, -1, -1, 2, -1}, {-1, 3, 4, 5, 6, 4, 1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 1, -1, -1, 2, 2, -1, -1, 2}, { 1, 3, 7, 3, 7, 4, 2, -1}, {-1, 1, 6, -1, -1, 6, 2, -1}, { 6, -1, 7, 3, 7, -1, 6, -1}, {-1, 4, 2, -1, -1, 1, 3, -1}, {-1, -1, 2, 6, 1, -1, -1, -1}, {-1, 4, 3, 3, 4, 4, 3, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, -1, -1, 5, 6, -1, -1, -1}, {-1, -1, -1, 3, -1, -1, -1, -1}, {-1, -1, -1, 1, 2, -1, -1, -1}, {-1, -1, -1, 4, -1, -1, -1, -1}, {-1, -1, -1, 5, 7, -1, -1, -1}, {-1, -1, -1, 2, -1, -1, -1, -1}, { 6, 5, 4, 3, 2, 1, 7, 5}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{-1, 0, -1, 1, -1, 2, -1, -1}, {-1, 4, -1, 5, -1, 6, -1, -1}, {-1, 7, -1, 0, -1, 2, -1, -1}, {-1, 6, -1, 3, -1, 6, -1, -1}, {-1, 1, -1, 1, -1, 2, -1, -1}, {-1, 3, -1, 5, -1, 0, -1, -1}, {-1, 2, -1, 4, -1, 6, -1, -1}, {-1, 3, -1, 6, -1, 7, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 1, 1, 2, 2, 3, 3, 4, 4}, { 5, 5, 6, 7, 6, 5, 5, -1}, { 6, 4, 3, 3, 2, 2, 1, 6}, { 4, 6, 5, 7, 6, 3, 1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 7, 4, -1, 1, 2, -1, 4, 7}, { 5, 5, -1, 2, -1, 4, 4, -1}, {-1, 5, -1, 7, 7, -1, 4, -1}, { 1, 0, 6, 7, 6, 0, 2, -1}, {-1, 2, -1, 5, 3, -1, 1, -1}, { 1, 1, -1, -1, -1, 2, 2, -1}, { 6, 1, 4, -1, -1, 4, 2, 6}, { 5, 3, -1, -1, -1, 3, 5, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 1, 5, 1, 0, 0, 1, 5, 1}, { 1, 2, 5, -1, 5, 2, 1, -1}, { 3, 6, 1, 2, 2, 1, 6, 3}, { 4, 3, 4, -1, 4, 3, 4, -1}, { 3, 4, 6, 5, 5, 6, 4, 3}, { 0, 2, 3, -1, 3, 2, 0, -1}, { 2, 3, 1, 5, 5, 1, 3, 2}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}}, {{ 3, 0, 2, 7, 5, 7, 6, 5}, { 6, -1, 1, -1, 2, -1, 1, -1}, {-1, 6, 4, 0, 3, 4, 5, -1}, {-1, 5, -1, 1, -1, 4, -1, -1}, {-1, 7, 3, 5, 6, 5, 3, -1}, { 1, -1, 2, -1, 4, -1, 2, -1}, { 6, 4, 4, 6, 6, 5, 5, 1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1}} }; /* the tile struct * type is the bubble number 0-7 * fallx is the x axis movement for the falling bubble * fallvel is the initial upward velocity for the falling bubble * ingroup denotes a bubble that is part of a group to be removed * anchored denotes a bubble that is anchored to the ceiling */ struct tile { int type; int fallx; int fallvel; bool ingroup; bool anchored; bool delete; }; /* the highscore struct * level is the highscore level * score is the highscore score */ struct highscore { unsigned int level; unsigned int score; }; /* the game context struct * score is the current score * level is the current level * highlevel is the highest level beaten * highscores is the list of high scores * angle is the current cannon direction * shots is the number of shots fired since last compression * compress is the height of the compressor * onboardcnt is the number of unique bubbles on the playing board * onboard is the unique bubbles on the playing board * nextinq is the pointer to the next bubble in the firing queue * queue is the circular buffer of bubbles to be fired * elapsedlvl is level elapsed time in 1/100s of seconds * elapsedshot is the shot elapsed time in 1/100s of seconds * startedshot is when the current shot began * resume denotes whether to resume the currently loaded game * dirty denotes whether the high scores are out of sync with the saved file * playboard is the game playing board */ struct game_context { unsigned int score; unsigned int level; unsigned int highlevel; struct highscore highscores[NUM_SCORES]; int angle; int shots; int compress; int onboardcnt; int onboard[NUM_BUBBLES]; int nextinq; int queue[NUM_QUEUE]; long elapsedlvl; long elapsedshot; long startedshot; bool resume; bool dirty; struct tile playboard[BB_HEIGHT][BB_WIDTH]; }; static void bubbles_init(struct game_context* bb); static bool bubbles_nextlevel(struct game_context* bb); static void bubbles_getonboard(struct game_context* bb); static void bubbles_drawboard(struct game_context* bb); static int bubbles_fire(struct game_context* bb); static bool bubbles_collision(struct game_context* bb, int y, int x, int nearrow, int nearcol); static bool bubbles_ingroup(struct game_context* bb, int row, int col); static int bubbles_searchgroup(struct game_context* bb, int row, int col); static int bubbles_remove(struct game_context* bb); static void bubbles_anchored(struct game_context* bb, int row, int col); static int bubbles_fall(struct game_context* bb); static int bubbles_checklevel(struct game_context* bb); static int bubbles_recordscore(struct game_context* bb); static void bubbles_savescores(struct game_context* bb); static bool bubbles_loadgame(struct game_context* bb); static void bubbles_savegame(struct game_context* bb); static void bubbles_setcolors(void); static void bubbles_callback(void* param); static int bubbles_handlebuttons(struct game_context* bb, bool animblock, int timeout); static int bubbles(struct game_context* bb); /***************************************************************************** * bubbles_init() initializes bubbles data structures. ******************************************************************************/ static void bubbles_init(struct game_context* bb) { /* seed the rand generator */ rb->srand(*rb->current_tick); /* check for resumed game */ if(bb->resume) { bb->resume = false; return; } bb->score = 0; bubbles_nextlevel(bb); } /***************************************************************************** * bubbles_nextlevel() sets up the game for the next level, returns false if * there are no more levels. ******************************************************************************/ static bool bubbles_nextlevel(struct game_context* bb) { int i, j, pos; bb->level++; /* check if there are no more levels */ if(bb->level > NUM_LEVELS) return false; /* set up the play board */ rb->memset(bb->playboard, 0, sizeof(bb->playboard)); for(i=0; ilevel-1][i][j]; if(pos >=0 && pos < NUM_BUBBLES) { bb->playboard[i][j].type = pos; } else { bb->playboard[i][j].type = -1; } } } for(i=BB_LEVEL_HEIGHT; iplayboard[i][j].type = -1; } } /* fill first bubbles in shot queue */ bubbles_getonboard(bb); for(i=0; iqueue[i] = bb->onboard[rb->rand()%bb->onboardcnt]; } bb->angle = 0; bb->shots = 0; bb->compress = 0; bb->nextinq = 0; bb->elapsedlvl = 0; bb->elapsedshot = 0; return true; } /***************************************************************************** * bubbles_getonboard() determines which bubble types are on the play board. ******************************************************************************/ static void bubbles_getonboard(struct game_context* bb) { int i, j, k; bool found; bb->onboardcnt = 0; rb->memset(bb->onboard, -1, sizeof(bb->onboard)); for(i=0; iplayboard[i][j].type >= 0) { found = false; for(k=0; konboardcnt; k++) { if(bb->playboard[i][j].type == bb->onboard[k]) { found = true; break; } } if(!found) { bb->onboard[bb->onboardcnt] = bb->playboard[i][j].type; bb->onboardcnt++; } if(bb->onboardcnt == NUM_BUBBLES) return; } } } } /***************************************************************************** * bubbles_drawboard() draws the game board to the buffer but does not update * the lcd. ******************************************************************************/ static void bubbles_drawboard(struct game_context* bb) { int i, j; int w, h; int colmax, indent; int tipx, tipy; bool evenline = false; char *level = "Level"; char *score = "Score"; char *next = "Next"; char *hurry = "HURRY!"; char str[11]; /* clear screen */ rb->lcd_clear_display(); /* draw background */ #ifdef HAVE_LCD_COLOR rb->lcd_bitmap(bubbles_background, 0, 0, LCD_WIDTH, LCD_HEIGHT); #endif /* display play board */ for(i=0; iplayboard[i][j].type >= 0 && !bb->playboard[i][j].delete) { rb->lcd_bitmap_part(bubbles_emblem, 0, EMBLEM_HEIGHT*bb->playboard[i][j].type, EMBLEM_WIDTH, XOFS+indent+BUBBLE_WIDTH*j+(BUBBLE_WIDTH-EMBLEM_WIDTH)/2, ROW_HEIGHT*i+(BUBBLE_HEIGHT-EMBLEM_HEIGHT)/2+bb->compress*ROW_HEIGHT, EMBLEM_WIDTH, EMBLEM_HEIGHT); rb->lcd_set_drawmode(DRMODE_FG); rb->lcd_mono_bitmap((const unsigned char *)bubbles_bubble, XOFS+indent+BUBBLE_WIDTH*j, ROW_HEIGHT*i+bb->compress*ROW_HEIGHT, BUBBLE_WIDTH, BUBBLE_HEIGHT); rb->lcd_set_drawmode(DRMODE_SOLID); } } } /* display bubble to be shot */ rb->lcd_bitmap_part(bubbles_emblem, 0, EMBLEM_HEIGHT*bb->queue[bb->nextinq], EMBLEM_WIDTH, SHOTX+(BUBBLE_WIDTH-EMBLEM_WIDTH)/2, SHOTY+(BUBBLE_HEIGHT-EMBLEM_HEIGHT)/2, EMBLEM_WIDTH, EMBLEM_HEIGHT); rb->lcd_set_drawmode(DRMODE_FG); rb->lcd_mono_bitmap((const unsigned char *)bubbles_bubble, SHOTX, SHOTY, BUBBLE_WIDTH, BUBBLE_HEIGHT); rb->lcd_set_drawmode(DRMODE_SOLID); /* display next bubble to be shot */ rb->lcd_bitmap_part(bubbles_emblem, 0, EMBLEM_HEIGHT*bb->queue[(bb->nextinq+1)%NUM_QUEUE], EMBLEM_WIDTH, XOFS/2-BUBBLE_WIDTH/2+(BUBBLE_WIDTH-EMBLEM_WIDTH)/2, SHOTY+(BUBBLE_HEIGHT-EMBLEM_HEIGHT)/2, EMBLEM_WIDTH, EMBLEM_HEIGHT); rb->lcd_set_drawmode(DRMODE_FG); rb->lcd_mono_bitmap((const unsigned char *)bubbles_bubble, XOFS/2-BUBBLE_WIDTH/2, SHOTY, BUBBLE_WIDTH, BUBBLE_HEIGHT); rb->lcd_set_drawmode(DRMODE_SOLID); /* draw bounding lines */ #ifndef HAVE_LCD_COLOR rb->lcd_vline(XOFS-1, 0, LCD_HEIGHT); rb->lcd_vline(XOFS+BUBBLE_WIDTH*BB_WIDTH, 0, LCD_HEIGHT); #endif rb->lcd_hline(XOFS, XOFS+BUBBLE_WIDTH*BB_WIDTH-1, bb->compress*ROW_HEIGHT-1); rb->lcd_hline(XOFS, XOFS+BUBBLE_WIDTH*BB_WIDTH-1, ROW_HEIGHT*(BB_HEIGHT-2)+BUBBLE_HEIGHT); /* draw arrow */ tipx = SHOTX+BUBBLE_WIDTH/2+(((sin_int(bb->angle)>>4)*BUBBLE_WIDTH*3/2)>>10); tipy = SHOTY+BUBBLE_HEIGHT/2-(((cos_int(bb->angle)>>4)*BUBBLE_HEIGHT*3/2)>>10); rb->lcd_drawline(SHOTX+BUBBLE_WIDTH/2+(((sin_int(bb->angle)>>4)*BUBBLE_WIDTH/2)>>10), SHOTY+BUBBLE_HEIGHT/2-(((cos_int(bb->angle)>>4)*BUBBLE_HEIGHT/2)>>10), tipx, tipy); xlcd_filltriangle(tipx, tipy, tipx+(((sin_int(bb->angle-135)>>4)*BUBBLE_WIDTH/3)>>10), tipy-(((cos_int(bb->angle-135)>>4)*BUBBLE_HEIGHT/3)>>10), tipx+(((sin_int(bb->angle+135)>>4)*BUBBLE_WIDTH/3)>>10), tipy-(((cos_int(bb->angle+135)>>4)*BUBBLE_HEIGHT/3)>>10)); /* draw text */ rb->lcd_getstringsize(level, &w, &h); rb->lcd_putsxy(XOFS/2-w/2, 2, level); rb->snprintf(str, 4, "%d", bb->level); rb->lcd_getstringsize(str, &w, &h); rb->lcd_putsxy(XOFS/2-w/2, 11, str); rb->lcd_getstringsize(score, &w, &h); rb->lcd_putsxy(XOFS/2-w/2, 29, score); rb->snprintf(str, 10, "%d", bb->score); rb->lcd_getstringsize(str, &w, &h); rb->lcd_putsxy(XOFS/2-w/2, 38, str); rb->lcd_getstringsize(next, &w, &h); rb->lcd_putsxy(XOFS/2-w/2, SHOTY-9, next); if(bb->elapsedshot >= (MAX_SHOTTIME*7)/10) { rb->lcd_getstringsize(hurry, &w, &h); rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-h/2, hurry); } } /***************************************************************************** * bubbles_fire() fires the current bubble, reloads the cannon, attaches * bubble to playboard, removes appropriate bubbles, and advances the * the compressor. ******************************************************************************/ static int bubbles_fire(struct game_context* bb) { int bubblecur; long shotxinc, shotyinc; long shotxofs, shotyofs; int shotxdirec = 1; long tempxofs, tempyofs; int nearrow, nearcol; int lastrow = BB_HEIGHT-1; int lastcol = (BB_WIDTH-1)/2; int buttonres; long lasttick, currenttick; /* get current bubble */ bubblecur = bb->queue[bb->nextinq]; shotxinc = ((sin_int(bb->angle)>>4)*BUBBLE_WIDTH)/3; shotyinc = ((-1*(cos_int(bb->angle)>>4))*BUBBLE_HEIGHT)/3; shotxofs = shotyofs = 0; /* advance the queue */ bb->queue[bb->nextinq] = bb->onboard[rb->rand()%bb->onboardcnt]; bb->nextinq = (bb->nextinq+1)%NUM_QUEUE; bubbles_drawboard(bb); rb->lcd_update_rect(0, 0, XOFS, LCD_HEIGHT); /* move the bubble across the play board */ lasttick = *rb->current_tick; while(true) { /* move the bubble one step */ shotyofs += shotyinc; shotxofs += shotxinc*shotxdirec; /* check for bounce off sides */ if(SHOTX+(shotxofs>>10) < XOFS) { shotxofs += 2*((XOFS<<10)-(((SHOTX)<<10)+shotxofs)); shotxdirec *= -1; } else if(SHOTX+(shotxofs>>10) > XOFS+(BB_WIDTH-1)*BUBBLE_WIDTH) { shotxofs -= 2*((((SHOTX)<<10)+shotxofs)- ((XOFS<<10)+(((BB_WIDTH-1)*BUBBLE_WIDTH)<<10))); shotxdirec *= -1; } tempxofs = shotxofs>>10; tempyofs = shotyofs>>10; /* display shot */ bubbles_drawboard(bb); rb->lcd_bitmap_part(bubbles_emblem, 0, EMBLEM_HEIGHT*bubblecur, EMBLEM_WIDTH, SHOTX+tempxofs+(BUBBLE_WIDTH-EMBLEM_WIDTH)/2, SHOTY+tempyofs+(BUBBLE_HEIGHT-EMBLEM_HEIGHT)/2, EMBLEM_WIDTH, EMBLEM_HEIGHT); rb->lcd_set_drawmode(DRMODE_FG); rb->lcd_mono_bitmap((const unsigned char *)bubbles_bubble, SHOTX+tempxofs, SHOTY+tempyofs, BUBBLE_WIDTH, BUBBLE_HEIGHT); rb->lcd_set_drawmode(DRMODE_SOLID); rb->lcd_update_rect(XOFS, 0, BB_WIDTH*BUBBLE_WIDTH, LCD_HEIGHT); /* find nearest position */ nearrow = ((SHOTY+tempyofs)- (bb->compress*ROW_HEIGHT)+ (ROW_HEIGHT/2))/ROW_HEIGHT; if(nearrow >= BB_HEIGHT) nearrow = BB_HEIGHT-1; if(nearrow%2) { /* odd row */ nearcol = ((SHOTX+tempxofs)- (XOFS+ROW_INDENT)+ (BUBBLE_WIDTH/2))/BUBBLE_WIDTH; if(nearcol >= BB_WIDTH-1) nearcol = BB_WIDTH-2; } else { /* even row */ nearcol = ((SHOTX+tempxofs)-XOFS+(BUBBLE_WIDTH/2))/BUBBLE_WIDTH; if(nearcol >= BB_WIDTH) nearcol = BB_WIDTH-1; } if(nearcol < 0) nearcol = 0; /* if nearest position is occupied attach to last position */ if(bb->playboard[nearrow][nearcol].type >= 0) { bb->playboard[lastrow][lastcol].type = bubblecur; break; } /* save last position */ lastrow = nearrow; lastcol = nearcol; /* if collision with neighbor then attach shot */ if(bubbles_collision(bb, SHOTY+tempyofs, SHOTX+tempxofs, nearrow, nearcol)) { bb->playboard[nearrow][nearcol].type = bubblecur; break; } /* if at top then attach shot to the ceiling */ if(nearrow == 0 && SHOTY+tempyofs <= bb->compress*ROW_HEIGHT) { bb->playboard[nearrow][nearcol].type = bubblecur; break; } /* handle button events */ buttonres = bubbles_handlebuttons(bb, true, 0); if(buttonres != BB_NONE) return buttonres; /* framerate limiting */ currenttick = *rb->current_tick; if(currenttick-lasttick < HZ/MAX_FPS) { rb->sleep((HZ/MAX_FPS)-(currenttick-lasttick)); } else { rb->yield(); } lasttick = currenttick; } bubbles_drawboard(bb); rb->lcd_update(); /* clear appropriate bubbles from playing board */ if(bubbles_ingroup(bb, lastrow, lastcol)) { buttonres = bubbles_remove(bb); if(buttonres != BB_NONE) return buttonres; } /* update shots and compress amount */ bb->shots++; if(bb->shots >= NUM_COMPRESS) { bb->shots = 0; bb->compress++; } return BB_NONE; } /***************************************************************************** * bubbles_collision() determines if a fired bubble has collided with another * bubble. ******************************************************************************/ static bool bubbles_collision(struct game_context* bb, int y, int x, int nearrow, int nearcol) { int nx, ny; int adj = nearrow%2; /* check neighbors */ if(nearcol-1 >= 0) { if(bb->playboard[nearrow][nearcol-1].type >= 0) { nx = XOFS+(nearrow%2 ? ROW_INDENT : 0)+BUBBLE_WIDTH*(nearcol-1); ny = ROW_HEIGHT*nearrow+bb->compress*ROW_HEIGHT; if((x-nx)*(x-nx)+(y-ny)*(y-ny) < MIN_DISTANCE) return true; } } if(nearcol-1+adj >= 0) { if(nearrow-1 >= 0) { if(bb->playboard[nearrow-1][nearcol-1+adj].type >= 0) { nx = XOFS+((nearrow-1)%2 ? ROW_INDENT : 0)+ BUBBLE_WIDTH*(nearcol-1+adj); ny = ROW_HEIGHT*(nearrow-1)+bb->compress*ROW_HEIGHT; if((x-nx)*(x-nx)+(y-ny)*(y-ny) < MIN_DISTANCE) return true; } } if(nearrow+1 < BB_HEIGHT) { if(bb->playboard[nearrow+1][nearcol-1+adj].type >= 0) { nx = XOFS+((nearrow+1)%2 ? ROW_INDENT : 0)+ BUBBLE_WIDTH*(nearcol-1+adj); ny = ROW_HEIGHT*(nearrow+1)+bb->compress*ROW_HEIGHT; if((x-nx)*(x-nx)+(y-ny)*(y-ny) < MIN_DISTANCE) return true; } } } if(nearcol+adj >= 0) { if(nearrow-1 >= 0) { if(bb->playboard[nearrow-1][nearcol+adj].type >= 0) { nx = XOFS+((nearrow-1)%2 ? ROW_INDENT : 0)+ BUBBLE_WIDTH*(nearcol+adj); ny = ROW_HEIGHT*(nearrow-1)+bb->compress*ROW_HEIGHT; if((x-nx)*(x-nx)+(y-ny)*(y-ny) < MIN_DISTANCE) return true; } } if(nearrow+1 < BB_HEIGHT) { if(bb->playboard[nearrow+1][nearcol+adj].type >= 0) { nx = XOFS+((nearrow+1)%2 ? ROW_INDENT : 0)+ BUBBLE_WIDTH*(nearcol+adj); ny = ROW_HEIGHT*(nearrow+1)+bb->compress*ROW_HEIGHT; if((x-nx)*(x-nx)+(y-ny)*(y-ny) < MIN_DISTANCE) return true; } } } if(nearcol+1 < BB_WIDTH-adj) { if(bb->playboard[nearrow][nearcol+1].type >= 0) { nx = XOFS+(nearrow%2 ? ROW_INDENT : 0)+BUBBLE_WIDTH*(nearcol+1); ny = ROW_HEIGHT*nearrow+bb->compress*ROW_HEIGHT; if((x-nx)*(x-nx)+(y-ny)*(y-ny) < MIN_DISTANCE) return true; } } return false; } /***************************************************************************** * bubbles_ingroup() marks all bubbles that form the current group. ******************************************************************************/ static bool bubbles_ingroup(struct game_context* bb, int row, int col) { int i, j; int count; count = bubbles_searchgroup(bb, row, col); /* unmark group if too small */ if(count < 3) { for(i=0; iplayboard[i][j].ingroup = false; } } return false; } return true; } /***************************************************************************** * bubbles_searchgroup() return the size of the group of bubbles of the same * type that the current bubble belongs to. ******************************************************************************/ static int bubbles_searchgroup(struct game_context* bb, int row, int col) { int i, adj; int myrow, mycol, mytype; int count = 0; struct coord { int row; int col; } search[(2*BB_WIDTH-1)*(BB_HEIGHT/2)]; /* search initial bubble */ bb->playboard[row][col].ingroup = true; search[count].row = row; search[count].col = col; count++; /* breadth-first search neighbors */ for(i=0; iplayboard[myrow][mycol].type; adj = myrow%2; if(mycol-1 >= 0) { if(bb->playboard[myrow][mycol-1].type == mytype && !bb->playboard[myrow][mycol-1].ingroup) { bb->playboard[myrow][mycol-1].ingroup = true; search[count].row = myrow; search[count].col = mycol-1; count++; } } if(mycol-1+adj >= 0) { if(myrow-1 >= 0) { if(bb->playboard[myrow-1][mycol-1+adj].type == mytype && !bb->playboard[myrow-1][mycol-1+adj].ingroup) { bb->playboard[myrow-1][mycol-1+adj].ingroup = true; search[count].row = myrow-1; search[count].col = mycol-1+adj; count++; } } if(myrow+1 < BB_HEIGHT) { if(bb->playboard[myrow+1][mycol-1+adj].type == mytype && !bb->playboard[myrow+1][mycol-1+adj].ingroup) { bb->playboard[myrow+1][mycol-1+adj].ingroup = true; search[count].row = myrow+1; search[count].col = mycol-1+adj; count++; } } } if(mycol+adj >= 0) { if(myrow-1 >= 0) { if(bb->playboard[myrow-1][mycol+adj].type == mytype && !bb->playboard[myrow-1][mycol+adj].ingroup) { bb->playboard[myrow-1][mycol+adj].ingroup = true; search[count].row = myrow-1; search[count].col = mycol+adj; count++; } } if(myrow+1 < BB_HEIGHT) { if(bb->playboard[myrow+1][mycol+adj].type == mytype && !bb->playboard[myrow+1][mycol+adj].ingroup) { bb->playboard[myrow+1][mycol+adj].ingroup = true; search[count].row = myrow+1; search[count].col = mycol+adj; count++; } } } if(mycol+1 < BB_WIDTH-adj) { if(bb->playboard[myrow][mycol+1].type == mytype && !bb->playboard[myrow][mycol+1].ingroup) { bb->playboard[myrow][mycol+1].ingroup = true; search[count].row = myrow; search[count].col = mycol+1; count++; } } } return count; } /***************************************************************************** * bubbles_remove() removes all bubbles in the current group and all * unanchored bubbles from the play board. ******************************************************************************/ static int bubbles_remove(struct game_context* bb) { int i, j; int buttonres; /* determine all anchored bubbles */ for(j=0; jplayboard[0][j].type >= 0 && !bb->playboard[0][j].ingroup) { bubbles_anchored(bb, 0, j); } } /* mark bubbles to be deleted */ for(i=0; iplayboard[i][j].type >= 0 && (!bb->playboard[i][j].anchored || bb->playboard[i][j].ingroup)) { bb->playboard[i][j].delete = true; } } } /* animate falling bubbles */ buttonres = bubbles_fall(bb); if(buttonres != BB_NONE) return buttonres; /* remove bubbles */ for(i=0; iplayboard[i][j].delete) { bb->playboard[i][j].ingroup = false; bb->playboard[i][j].type = -1; bb->playboard[i][j].delete = false; } else { bb->playboard[i][j].anchored = false; } } } bubbles_getonboard(bb); return BB_NONE; } /***************************************************************************** * bubbles_anchored() marks all bubbles that are anchored in some way to the * current bubble. ******************************************************************************/ static void bubbles_anchored(struct game_context* bb, int row, int col) { int i, adj; int myrow, mycol, mytype; int count = 0; struct coord { int row; int col; } search[(2*BB_WIDTH-1)*(BB_HEIGHT/2)]; /* search initial bubble */ bb->playboard[row][col].anchored = true; search[count].row = row; search[count].col = col; count++; /* breadth-first search neighbors */ for(i=0; iplayboard[myrow][mycol].type; adj = myrow%2; if(mycol-1 >= 0) { if(bb->playboard[myrow][mycol-1].type >= 0 && !bb->playboard[myrow][mycol-1].ingroup && !bb->playboard[myrow][mycol-1].anchored) { bb->playboard[myrow][mycol-1].anchored = true; search[count].row = myrow; search[count].col = mycol-1; count++; } } if(mycol-1+adj >= 0) { if(myrow-1 >= 0) { if(bb->playboard[myrow-1][mycol-1+adj].type >= 0 && !bb->playboard[myrow-1][mycol-1+adj].ingroup && !bb->playboard[myrow-1][mycol-1+adj].anchored) { bb->playboard[myrow-1][mycol-1+adj].anchored = true; search[count].row = myrow-1; search[count].col = mycol-1+adj; count++; } } if(myrow+1 < BB_HEIGHT) { if(bb->playboard[myrow+1][mycol-1+adj].type >= 0 && !bb->playboard[myrow+1][mycol-1+adj].ingroup && !bb->playboard[myrow+1][mycol-1+adj].anchored) { bb->playboard[myrow+1][mycol-1+adj].anchored = true; search[count].row = myrow+1; search[count].col = mycol-1+adj; count++; } } } if(mycol+adj >= 0) { if(myrow-1 >= 0) { if(bb->playboard[myrow-1][mycol+adj].type >= 0 && !bb->playboard[myrow-1][mycol+adj].ingroup && !bb->playboard[myrow-1][mycol+adj].anchored) { bb->playboard[myrow-1][mycol+adj].anchored = true; search[count].row = myrow-1; search[count].col = mycol+adj; count++; } } if(myrow+1 < BB_HEIGHT) { if(bb->playboard[myrow+1][mycol+adj].type >= 0 && !bb->playboard[myrow+1][mycol+adj].ingroup && !bb->playboard[myrow+1][mycol+adj].anchored) { bb->playboard[myrow+1][mycol+adj].anchored = true; search[count].row = myrow+1; search[count].col = mycol+adj; count++; } } } if(mycol+1 < BB_WIDTH-adj) { if(bb->playboard[myrow][mycol+1].type >= 0 && !bb->playboard[myrow][mycol+1].ingroup && !bb->playboard[myrow][mycol+1].anchored) { bb->playboard[myrow][mycol+1].anchored = true; search[count].row = myrow; search[count].col = mycol+1; count++; } } } } /***************************************************************************** * bubbles_fall() makes removed bubbles fall from the screen. ******************************************************************************/ static int bubbles_fall(struct game_context* bb) { int i, j; int count; int indent; int xofs, yofs; int buttonres; bool onscreen; long lasttick, currenttick; /* give all falling bubbles an x axis movement */ for(i=0; iplayboard[i][j].delete) { bb->playboard[i][j].fallx = rb->rand()%25 - 12; bb->playboard[i][j].fallvel = rb->rand()%5 + 6; } } } /* draw bubbles falling off the screen * follows y=x^2-8x scaled to bubble size */ lasttick = *rb->current_tick; for(count=1; ;count++) { onscreen = false; bubbles_drawboard(bb); for(i=0; iplayboard[i][j].delete) { indent = (i%2 ? ROW_INDENT : 0); xofs = ((bb->playboard[i][j].fallx*count)*BUBBLE_WIDTH)/48; yofs = ((count*count - bb->playboard[i][j].fallvel*count)* BUBBLE_HEIGHT)/20; /* draw bubble if it is still on the screen */ if(ROW_HEIGHT*i+bb->compress*ROW_HEIGHT+yofs <= LCD_HEIGHT) { onscreen = true; rb->lcd_bitmap_part(bubbles_emblem, 0, EMBLEM_HEIGHT*bb->playboard[i][j].type, EMBLEM_WIDTH, XOFS+indent+BUBBLE_WIDTH*j+ (BUBBLE_WIDTH-EMBLEM_WIDTH)/2+xofs, ROW_HEIGHT*i+(BUBBLE_HEIGHT-EMBLEM_HEIGHT)/2+ bb->compress*ROW_HEIGHT+yofs, EMBLEM_WIDTH, EMBLEM_HEIGHT); rb->lcd_set_drawmode(DRMODE_FG); rb->lcd_mono_bitmap( (const unsigned char *)bubbles_bubble, XOFS+indent+BUBBLE_WIDTH*j+xofs, ROW_HEIGHT*i+bb->compress*ROW_HEIGHT+yofs, BUBBLE_WIDTH, BUBBLE_HEIGHT); rb->lcd_set_drawmode(DRMODE_SOLID); } } } } rb->lcd_update(); /* break out if all bubbles are off the screen */ if(!onscreen) break; /* handle button events */ buttonres = bubbles_handlebuttons(bb, true, 0); if(buttonres != BB_NONE) return buttonres; /* framerate limiting */ currenttick = *rb->current_tick; if(currenttick-lasttick < HZ/MAX_FPS) { rb->sleep((HZ/MAX_FPS)-(currenttick-lasttick)); } else { rb->yield(); } lasttick = currenttick; } return BB_NONE; } /***************************************************************************** * bubbles_checklevel() checks the state of the playboard for a win or loss. ******************************************************************************/ static int bubbles_checklevel(struct game_context* bb) { int i, j; int points; char str[13]; bubbles_drawboard(bb); rb->lcd_update(); /* check for bubbles below cut off point */ for(i=0; i<=bb->compress; i++) { for(j=0; jplayboard[BB_HEIGHT-1-i][j].type >= 0) return BB_LOSE; } } /* check for bubbles above cut off point */ for(i=0; icompress; i++) { for(j=0; jplayboard[i][j].type >= 0) return BB_NONE; } } /* level complete, record score */ points = 100 - bb->elapsedlvl/100; if(points > 0) { bb->score += points; } else { points = 0; } rb->snprintf(str, 12, "%d points", points); rb->splash(HZ, str); /* advance to the next level */ if(!bubbles_nextlevel(bb)) { return BB_WIN; } bubbles_drawboard(bb); rb->lcd_update(); rb->snprintf(str, 12, "Level %d", bb->level); rb->splash(HZ, str); bubbles_drawboard(bb); rb->lcd_update(); return BB_NONE; } /***************************************************************************** * bubbles_recordscore() inserts a high score into the high scores list and * returns the high score position. ******************************************************************************/ static int bubbles_recordscore(struct game_context* bb) { int i; int position = 0; unsigned int currentscore, currentlevel; unsigned int tempscore, templevel; if(bb->score > 0) { currentlevel = bb->level-1; currentscore = bb->score; for(i=0; i= bb->highscores[i].score) { if(!position) { position = i+1; bb->dirty = true; } templevel = bb->highscores[i].level; tempscore = bb->highscores[i].score; bb->highscores[i].level = currentlevel; bb->highscores[i].score = currentscore; currentlevel = templevel; currentscore = tempscore; } } } return position; } /***************************************************************************** * bubbles_loadscores() loads the high scores saved file. ******************************************************************************/ static void bubbles_loadscores(struct game_context* bb) { int fd; bb->dirty = false; /* clear high scores */ bb->highlevel = 0; rb->memset(bb->highscores, 0, sizeof(bb->highscores)); /* open scores file */ fd = rb->open(SCORE_FILE, O_RDONLY); if(fd < 0) return; /* read in high scores */ rb->read(fd, &bb->highlevel, sizeof(bb->highlevel)); if(rb->read(fd, bb->highscores, sizeof(bb->highscores)) <= 0) { /* scores are bad, reset */ rb->memset(bb->highscores, 0, sizeof(bb->highscores)); } if( bb->highlevel >= NUM_LEVELS ) bb->highlevel = NUM_LEVELS - 1; rb->close(fd); } /***************************************************************************** * bubbles_savescores() saves the high scores saved file. ******************************************************************************/ static void bubbles_savescores(struct game_context* bb) { int fd; /* write out the high scores to the save file */ fd = rb->open(SCORE_FILE, O_WRONLY|O_CREAT); rb->write(fd, &bb->highlevel, sizeof(bb->highlevel)); rb->write(fd, bb->highscores, sizeof(bb->highscores)); rb->close(fd); bb->dirty = false; } /***************************************************************************** * bubbles_loadgame() loads the saved game and returns load success. ******************************************************************************/ static bool bubbles_loadgame(struct game_context* bb) { int fd; bool loaded = false; /* open game file */ fd = rb->open(SAVE_FILE, O_RDONLY); if(fd < 0) return loaded; /* read in saved game */ while(true) { if(rb->read(fd, &bb->score, sizeof(bb->score)) <= 0) break; if(rb->read(fd, &bb->level, sizeof(bb->level)) <= 0) break; if(rb->read(fd, &bb->angle, sizeof(bb->angle)) <= 0) break; if(rb->read(fd, &bb->shots, sizeof(bb->shots)) <= 0) break; if(rb->read(fd, &bb->compress, sizeof(bb->compress)) <= 0) break; if(rb->read(fd, &bb->onboardcnt, sizeof(bb->onboardcnt)) <= 0) break; if(rb->read(fd, bb->onboard, sizeof(bb->onboard)) <= 0) break; if(rb->read(fd, &bb->nextinq, sizeof(bb->nextinq)) <= 0) break; if(rb->read(fd, bb->queue, sizeof(bb->queue)) <= 0) break; if(rb->read(fd, &bb->elapsedlvl, sizeof(bb->elapsedlvl)) <= 0) break; if(rb->read(fd, bb->playboard, sizeof(bb->playboard)) <= 0) break; bb->resume = true; loaded = true; break; } rb->close(fd); /* delete saved file */ rb->remove(SAVE_FILE); return loaded; } /***************************************************************************** * bubbles_savegame() saves the current game state. ******************************************************************************/ static void bubbles_savegame(struct game_context* bb) { int fd; /* write out the game state to the save file */ fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT); rb->write(fd, &bb->score, sizeof(bb->score)); rb->write(fd, &bb->level, sizeof(bb->level)); rb->write(fd, &bb->angle, sizeof(bb->angle)); rb->write(fd, &bb->shots, sizeof(bb->shots)); rb->write(fd, &bb->compress, sizeof(bb->compress)); rb->write(fd, &bb->onboardcnt, sizeof(bb->onboardcnt)); rb->write(fd, bb->onboard, sizeof(bb->onboard)); rb->write(fd, &bb->nextinq, sizeof(bb->nextinq)); rb->write(fd, bb->queue, sizeof(bb->queue)); rb->write(fd, &bb->elapsedlvl, sizeof(bb->elapsedlvl)); rb->write(fd, bb->playboard, sizeof(bb->playboard)); rb->close(fd); bb->resume = true; } /***************************************************************************** * bubbles_setcolors() set the foreground and background colors. ******************************************************************************/ static inline void bubbles_setcolors(void) { #ifdef HAVE_LCD_COLOR rb->lcd_set_background(LCD_RGBPACK(181,181,222)); rb->lcd_set_foreground(LCD_BLACK); #endif } /***************************************************************************** * bubbles_callback() is the default event handler callback which is called * on usb connect and shutdown. ******************************************************************************/ static void bubbles_callback(void* param) { struct game_context* bb = (struct game_context*) param; if(bb->dirty) { rb->splash(HZ/2, "Saving high scores..."); bubbles_savescores(bb); } } /***************************************************************************** * bubbles_handlebuttons() handles button events during a game. ******************************************************************************/ static int bubbles_handlebuttons(struct game_context* bb, bool animblock, int timeout) { int button; int buttonres; long start; const struct button_mapping *plugin_contexts[] #if CONFIG_KEYPAD != SANSA_E200_PAD = {generic_left_right_fire,generic_actions}; #else = {generic_directions,generic_actions}; #endif if (timeout < 0) timeout = 0; button = pluginlib_getaction(rb,timeout,plugin_contexts,2); #if defined(HAS_BUTTON_HOLD) && !defined(HAVE_REMOTE_LCD_AS_MAIN) /* FIXME: Should probably check remote hold here */ if (rb->button_hold()) button = BUBBLES_START; #endif switch(button){ case BUBBLES_LEFT_REP: if(bb->angle > MIN_ANGLE) bb->angle -= ANGLE_STEP_REP; case BUBBLES_LEFT: /* change angle to the left */ if(bb->angle > MIN_ANGLE) bb->angle -= ANGLE_STEP; break; case BUBBLES_RIGHT_REP: if(bb->angle < MAX_ANGLE) bb->angle += ANGLE_STEP_REP; case BUBBLES_RIGHT: /* change angle to the right */ if(bb->angle < MAX_ANGLE) bb->angle += ANGLE_STEP; break; case BUBBLES_SELECT: /* fire the shot */ if(!animblock) { bb->elapsedlvl += bb->elapsedshot; bb->elapsedshot = 0; buttonres = bubbles_fire(bb); if(buttonres != BB_NONE) return buttonres; buttonres = bubbles_checklevel(bb); if(buttonres != BB_NONE) return buttonres; bb->startedshot = *rb->current_tick; } break; case BUBBLES_START: /* pause the game */ start = *rb->current_tick; rb->splash(0, "Paused"); while(pluginlib_getaction(rb,TIMEOUT_BLOCK,plugin_contexts,2) != (BUBBLES_START)); bb->startedshot += *rb->current_tick-start; bubbles_drawboard(bb); rb->lcd_update(); break; case BUBBLES_RESUME: /* save and end the game */ if(!animblock) { rb->splash(HZ/2, "Saving game..."); bubbles_savegame(bb); return BB_END; } break; case BUBBLES_QUIT: /* end the game */ return BB_END; case ACTION_UNKNOWN: case ACTION_NONE: /* no button pressed */ break; default: if(rb->default_event_handler_ex(button, bubbles_callback, (void*) bb) == SYS_USB_CONNECTED) return BB_USB; break; } return BB_NONE; } /***************************************************************************** * bubbles() is the main game subroutine, it returns the final game status. ******************************************************************************/ static int bubbles(struct game_context* bb) { int i; int w, h; int button; int buttonres; unsigned int startlevel = 0; char *title = "Bubbles"; bool startgame = false; bool showscores = false; long timeout; const struct button_mapping *plugin_contexts[] = {generic_actions,generic_directions}; bubbles_setcolors(); /* don't resume by default */ bb->resume = false; /******************** * menu * ********************/ while(!startgame){ char str[30]; rb->lcd_clear_display(); if(!showscores) { /* welcome screen to display key bindings */ rb->lcd_getstringsize(title, &w, &h); rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, title); #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) rb->lcd_puts(0, 2, "ON to start/pause"); rb->lcd_puts(0, 3, "MODE to save/resume"); rb->lcd_puts(0, 4, "OFF to exit"); rb->lcd_puts(0, 5, "SELECT to fire"); rb->lcd_puts(0, 6, " and show high scores"); rb->lcd_puts(0, 7, "LEFT/RIGHT to aim"); rb->lcd_puts(0, 8, "UP/DOWN to change level"); #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) rb->lcd_puts(0, 2, "PLAY to start/pause"); rb->lcd_puts(0, 3, "MENU to save/resume"); rb->lcd_puts(0, 4, "MENU+SELECT to exit"); rb->lcd_puts(0, 5, "SELECT to fire"); rb->lcd_puts(0, 6, " and show high scores"); rb->lcd_puts(0, 7, "SCROLL to aim"); rb->lcd_puts(0, 8, " and to change level"); #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD rb->lcd_puts(0, 2, "PLAY to start/pause"); rb->lcd_puts(0, 3, "REC to save/resume"); rb->lcd_puts(0, 4, "POWER to exit"); rb->lcd_puts(0, 5, "SELECT to fire"); rb->lcd_puts(0, 6, " and show high scores"); rb->lcd_puts(0, 7, "LEFT/RIGHT to aim"); rb->lcd_puts(0, 8, "UP/DOWN to change level"); #elif CONFIG_KEYPAD == GIGABEAT_PAD rb->lcd_puts(0, 2, "A to start/pause"); rb->lcd_puts(0, 3, "MENU to save/resume"); rb->lcd_puts(0, 4, "POWER to exit"); rb->lcd_puts(0, 5, "SELECT to fire"); rb->lcd_puts(0, 6, " and show high scores"); rb->lcd_puts(0, 7, "LEFT/RIGHT to aim"); rb->lcd_puts(0, 8, "UP/DOWN to change level"); #elif CONFIG_KEYPAD == RECORDER_PAD rb->lcd_puts_scroll(0, 2, "ON to start/pause, " "F1 to save/resume, " "OFF to exit, " "PLAY to fire and show high scores, " "LEFT/RIGHT to aim, " "UP/DOWN to change level."); #elif CONFIG_KEYPAD == ONDIO_PAD rb->lcd_puts_scroll(0, 2, "MODE to start/pause, " "DOWN to save/resume, " "OFF to exit, " "UP to fire and show high scores, " "LEFT/RIGHT to aim and to change level."); #elif CONFIG_KEYPAD == IRIVER_H10_PAD rb->lcd_puts(0, 2, "PLAY to start/pause"); rb->lcd_puts(0, 3, "FF to save/resume"); rb->lcd_puts(0, 4, "POWER to exit"); rb->lcd_puts(0, 5, "REW/UP to fire"); rb->lcd_puts(0, 6, " and show high scores"); rb->lcd_puts(0, 7, "LEFT/RIGHT to aim"); rb->lcd_puts(0, 8, "UP/DOWN to change level"); #elif CONFIG_KEYPAD == SANSA_E200_PAD rb->lcd_puts(0, 2, "PLAY to start/pause"); rb->lcd_puts(0, 3, "SUBMENU to save/resume"); rb->lcd_puts(0, 4, "POWER to exit"); rb->lcd_puts(0, 5, "SELECT to fire"); rb->lcd_puts(0, 6, " and show high scores"); rb->lcd_puts(0, 7, "SCROLL to aim"); rb->lcd_puts(0, 8, " and change level"); #elif CONFIG_KEYPAD == SANSA_C200_PAD rb->lcd_puts(0, 2, "PLAY to start/pause"); rb->lcd_puts(0, 3, "SUBMENU to save/resume"); rb->lcd_puts(0, 4, "POWER to exit"); rb->lcd_puts_scroll(0, 5, "SELECT to fire and show high scores, " "LEFT/RIGHT to aim and change level"); #elif CONFIG_KEYPAD == IAUDIO_M3_PAD rb->lcd_puts(0, 2, "PLAY to start/pause"); rb->lcd_puts(0, 3, "MENU to save/resume"); rb->lcd_puts(0, 4, "REC to exit"); rb->lcd_puts(0, 5, "MODE to fire"); rb->lcd_puts(0, 6, " and show high scores"); rb->lcd_puts(0, 7, "REW/FF to aim"); rb->lcd_puts(0, 8, "VOL UP/DN to chg. lvl"); #endif #if LCD_WIDTH >= 138 rb->snprintf(str, 28, "Start on level %d of %d", startlevel+1, bb->highlevel+1); #else rb->snprintf(str, 28, "Start on lvl %d/%d", startlevel+1, bb->highlevel+1); #endif rb->lcd_puts(0, MIN(TEXT_LINES-3,10), str); rb->lcd_puts(0, MIN(TEXT_LINES-2,12), "High Score:"); rb->snprintf(str, 30, "%d, Lvl %d", bb->highscores[0].score, bb->highscores[0].level); rb->lcd_puts(2, MIN(TEXT_LINES-1,13), str); } else { /* show high scores */ rb->snprintf(str, 12, "High Scores"); rb->lcd_getstringsize(str, &w, &h); rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, str); for(i=0; isnprintf(str, 30, "#%02d: %d, Lvl %d", i+1, bb->highscores[i].score, bb->highscores[i].level); rb->lcd_puts(0, i+2, str); } } rb->lcd_update(); /* handle menu button presses */ button = pluginlib_getaction(rb,TIMEOUT_BLOCK,plugin_contexts,2); switch(button){ case BUBBLES_START: /* start playing */ bb->level = startlevel; startgame = true; break; case BUBBLES_QUIT: /* quit program */ if(showscores) { showscores = false; break; } return BB_QUIT; case BUBBLES_RESUME: /* resume game */ if(!bubbles_loadgame(bb)) { rb->splash(HZ*2, "Nothing to resume"); } else { startgame = true; } break; case BUBBLES_SELECT: /* toggle high scores */ showscores = !showscores; break; case BUBBLES_LVLINC: /* increase starting level */ case BUBBLES_LVLINC_REP: if(startlevel >= bb->highlevel) { startlevel = 0; } else { startlevel++; } break; case BUBBLES_LVLDEC: /* decrease starting level */ case BUBBLES_LVLDEC_REP: if(startlevel <= 0) { startlevel = bb->highlevel; } else { startlevel--; } break; default: if(rb->default_event_handler_ex(button, bubbles_callback, (void*) bb) == SYS_USB_CONNECTED) return BB_USB; break; } } /******************** * init * ********************/ bubbles_init(bb); bubbles_drawboard(bb); rb->lcd_update(); /********************** * play * **********************/ bb->startedshot = *rb->current_tick; while(true) { /* refresh the board */ bubbles_drawboard(bb); rb->lcd_update(); /* manange idle framerate */ bb->elapsedshot = *rb->current_tick-bb->startedshot; if(MAX_SHOTTIME-bb->elapsedshot < HZ/2) { timeout = MAX_SHOTTIME-bb->elapsedshot; } else { timeout = HZ/2; } /* handle button events */ buttonres = bubbles_handlebuttons(bb, false, timeout); if(buttonres != BB_NONE) return buttonres; /* handle timing */ bb->elapsedshot = *rb->current_tick-bb->startedshot; if(bb->elapsedshot > MAX_SHOTTIME) { bb->elapsedlvl += bb->elapsedshot; bb->elapsedshot = 0; buttonres = bubbles_fire(bb); if(buttonres != BB_NONE) return buttonres; buttonres = bubbles_checklevel(bb); if(buttonres != BB_NONE) return buttonres; bb->startedshot = *rb->current_tick; } } } /***************************************************************************** * plugin entry point. ******************************************************************************/ enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter) { struct game_context bb; bool exit = false; int position; /* plugin init */ (void)parameter; rb = api; /* end of plugin init */ /* more init */ xlcd_init(rb); /* load files */ rb->splash(0, "Loading..."); bubbles_loadscores(&bb); rb->lcd_clear_display(); /* start app */ #if LCD_DEPTH > 1 rb->lcd_set_backdrop(NULL); #endif rb->lcd_setfont(FONT_SYSFIXED); while(!exit) { switch(bubbles(&bb)){ char str[19]; case BB_WIN: rb->splash(HZ*2, "You Win!"); /* record high level */ if( NUM_LEVELS-1 > bb.highlevel) { bb.highlevel = NUM_LEVELS-1; bb.dirty = true; } /* record high score */ if((position = bubbles_recordscore(&bb))) { rb->snprintf(str, 19, "New high score #%d!", position); rb->splash(HZ*2, str); } break; case BB_LOSE: rb->splash(HZ*2, "Game Over"); /* fall through to BB_END */ case BB_END: if(!bb.resume) { /* record high level */ if(bb.level-1 > bb.highlevel) { bb.highlevel = bb.level-1; bb.dirty = true; } /* record high score */ if((position = bubbles_recordscore(&bb))) { rb->snprintf(str, 19, "New high score #%d!", position); rb->splash(HZ*2, str); } } break; case BB_USB: rb->lcd_setfont(FONT_UI); return PLUGIN_USB_CONNECTED; case BB_QUIT: if(bb.dirty) { rb->splash(HZ/2, "Saving high scores..."); bubbles_savescores(&bb); } exit = true; break; default: break; } } rb->lcd_setfont(FONT_UI); return PLUGIN_OK; } #endif