rockbox/apps/plugins/bubbles.c
Thomas Martitz 20e9d56ba5 S#10387 - Rework pluginlib actions
It changes pluginlib actions to contain only a single and simple context (and
other one for remote directional buttons),
consisting of 7(9) buttons: up/down/left/right, select OR short select and long
select, exit and cancel (plus 2 for scrollwheel targets).
This ensures contexts don't clash with other contexts and simplifies them, at
the expense of reduced versatility. However, the versatility made it largely unusable
due to the great number of targets.
This should allow for using pluginlib actions safely for the most simple plugins (e.g. almost all demos).

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26202 a1c6a512-1295-4272-9138-f99709370657
2010-05-20 17:41:28 +00:00

2572 lines
89 KiB
C

/***************************************************************************
* __________ __ ___.
* 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 "lib/xlcd.h"
#include "lib/pluginlib_actions.h"
#include "lib/fixedpoint.h"
#include "lib/playback_control.h"
#include "lib/highscore.h"
PLUGIN_HEADER
/* files */
#define SCORE_FILE PLUGIN_GAMES_DIR "/bubbles.score"
#define SAVE_FILE PLUGIN_GAMES_DIR "/bubbles.save"
#define DATA_FILE PLUGIN_GAMES_DIR "/bubbles.data"
/* final game return status */
enum {
BB_LOSE,
BB_QUIT_WITHOUT_SAVING,
BB_QUIT,
BB_USB,
BB_END,
BB_WIN,
BB_NONE,
};
/* play board dimension */
#define BB_HEIGHT 12
#define BB_WIDTH 8
#define BB_LEVEL_HEIGHT 10
/* various amounts */
#define NUM_SCORES 5
#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 */
#ifdef HAVE_SCROLLWHEEL
/* sansas use the wheel instead of left/right if available */
#define BUBBLES_LEFT PLA_SCROLL_BACK
#define BUBBLES_LEFT_REP PLA_SCROLL_BACK_REPEAT
#define BUBBLES_RIGHT PLA_SCROLL_FWD
#define BUBBLES_RIGHT_REP PLA_SCROLL_FWD_REPEAT
#else
#define BUBBLES_LEFT PLA_LEFT
#define BUBBLES_LEFT_REP PLA_LEFT_REPEAT
#define BUBBLES_RIGHT PLA_RIGHT
#define BUBBLES_RIGHT_REP PLA_RIGHT_REPEAT
#endif
#define ANGLE_STEP 2
#define ANGLE_STEP_REP 4
#define BUBBLES_QUIT1 PLA_EXIT
#define BUBBLES_QUIT2 PLA_CANCEL
/* these are better off shooting with up */
#if (CONFIG_KEYPAD == SAMSUNG_YH_PAD) \
|| (CONFIG_KEYPAD == ONDIO_PAD) \
|| (CONFIG_KEYPAD == IRIVER_H10_PAD)
#define SHOOT_WITH_UP
#endif
#ifdef SHOOT_WITH_UP
#define BUBBLES_FIRE PLA_UP
#define BUBBLES_FIRE_REPEAT PLA_UP_REPEAT
#define BUBBLES_PAUSE PLA_SELECT
#else
#define BUBBLES_FIRE PLA_SELECT
#define BUBBLES_FIRE_REPEAT PLA_SELECT_REPEAT
#define BUBBLES_PAUSE PLA_UP
#endif
/* external bitmaps */
#ifdef HAVE_LCD_COLOR
#include "pluginbitmaps/bubbles_background.h"
#endif
#include "pluginbitmaps/bubbles_bubble.h"
#include "pluginbitmaps/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 */
/* 44x44 bubbles (m:robe 500) */
#if (LCD_WIDTH == 640) && (LCD_HEIGHT == 480)
#define XOFS 144
#define MAX_FPS 40
#elif (LCD_WIDTH == 480) && (LCD_HEIGHT == 640)
#define XOFS 128
#define MAX_FPS 40
/* 22x22 bubbles (iPod Video) */
#elif (LCD_HEIGHT == 240) && (LCD_WIDTH == 320)
#define XOFS 72
#define MAX_FPS 40
/* 22x22 bubbles (Gigabeat, Onda VX747) */
#elif ((LCD_HEIGHT == 320) || (LCD_HEIGHT == 400)) && (LCD_WIDTH == 240)
#define XOFS 64
#define MAX_FPS 30
/* 16x16 bubbles (H300, iPod Color, HDD6330) */
#elif (LCD_HEIGHT == 176) && (LCD_WIDTH == 220)
#define XOFS 46
#define MAX_FPS 30
/* 16x16 bubbles (Sansa E200) */
#elif (LCD_HEIGHT == 220) && (LCD_WIDTH == 176)
#define XOFS 24
#define MAX_FPS 30
#define YOFS 45
/* custom text positioning */
#define LEVEL_TXT_X 24
#define LEVEL_TXT_WIDTH 31
#define LEVEL_TXT_Y 5
#define SCORE_TXT_X 58
#define SCORE_TXT_WIDTH 31
#define SCORE_TXT_Y 5
#define NEXT_BB_X 112
#define NEXT_BB_WIDTH 31
#define NEXT_BB_Y 3
/* 12x12 bubbles (iPod Nano) */
#elif (LCD_HEIGHT == 132) && (LCD_WIDTH == 176)
#define XOFS 40
#define MAX_FPS 40
/* 12x12 bubbles (H100, H10, iAudio X5, HDD1630, iPod 3G, iPod 4G grayscale) */
#elif (LCD_HEIGHT == 128) && ((LCD_WIDTH == 160) || (LCD_WIDTH == 128))
#define XOFS 33
#define MAX_FPS 30
/* 12x12 bubbles (GoGear SA9200) */
#elif (LCD_HEIGHT == 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 MAX_FPS 30
/* 9x9 bubbles (iAudio M3) */
#elif (LCD_HEIGHT == 96) && (LCD_WIDTH == 128)
#define XOFS 45
#define MAX_FPS 30
/* 8x8 bubbles (Sansa C200) */
#elif ((LCD_HEIGHT == 80) && (LCD_WIDTH == 132))
#define XOFS 45
#define ROW_HEIGHT 6
#define MAX_FPS 30
/* 7x7 bubbles (Sansa Clip/m200) */
#elif (LCD_HEIGHT == 64 && LCD_WIDTH == 128)
#define XOFS 33
#define ROW_HEIGHT 5
#define MAX_FPS 30
/* 8x7 bubbles (Archos recorder, Ondio) */
#elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 112)
#define XOFS 33
#define ROW_HEIGHT 5
#define MAX_FPS 20
#else
#error BUBBLES: Unsupported LCD type
#endif
#if !defined(ROW_HEIGHT)
#define ROW_HEIGHT (BUBBLE_WIDTH-(BUBBLE_WIDTH-EMBLEM_WIDTH)/2)
#endif
#define ROW_INDENT (BUBBLE_WIDTH/2)
#define TEXT_LINES (LCD_HEIGHT/8)
#ifndef YOFS
#define YOFS 0
#endif
/* shot position */
#define SHOTX XOFS+ROW_INDENT+BUBBLE_WIDTH*3
#define SHOTY (YOFS+ROW_HEIGHT*(BB_HEIGHT-1)+BUBBLE_HEIGHT/2)
/* collision distance squared */
#define MIN_DISTANCE ((BUBBLE_WIDTH*8)/10)*((BUBBLE_HEIGHT*8)/10)
/* 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 game context struct
* score is the current score
* level is the current level
* 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
* playboard is the game playing board
*/
struct game_context {
unsigned int score;
unsigned int level;
int angle;
int shots;
int compress;
int onboardcnt;
int onboard[NUM_BUBBLES];
int nextinq;
int queue[NUM_QUEUE];
long elapsedlvl;
long elapsedshot;
long startedshot;
struct tile playboard[BB_HEIGHT][BB_WIDTH];
};
static struct highscore highscores[NUM_SCORES];
/* used to denote available resume info */
static bool resume = false;
static bool resume_file = false;
static unsigned int highlevel = 0; /* the highest level beaten */
static unsigned int last_highlevel = 0;
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 void bubbles_recordscore(struct game_context* bb);
static bool bubbles_loadgame(struct game_context* bb);
static void bubbles_savegame(struct game_context* bb);
static inline 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) {
bubbles_setcolors();
/* seed the rand generator */
rb->srand(*rb->current_tick);
/* check for resumed game */
if (resume)
{
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;
/* save highest level */
if (bb->level-1 > highlevel)
highlevel = bb->level-1;
/* set up the play board */
rb->memset(bb->playboard, 0, sizeof(bb->playboard));
for(i=0; i<BB_LEVEL_HEIGHT; i++) {
for(j=0; j<BB_WIDTH; j++) {
pos = (int)level[bb->level-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; i<BB_HEIGHT; i++) {
for(j=0; j<BB_WIDTH; j++) {
bb->playboard[i][j].type = -1;
}
}
/* fill first bubbles in shot queue */
bubbles_getonboard(bb);
for(i=0; i<NUM_QUEUE; i++) {
bb->queue[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; i<BB_HEIGHT; i++) {
for(j=0; j<BB_WIDTH; j++) {
if(bb->playboard[i][j].type >= 0) {
found = false;
for(k=0; k<bb->onboardcnt; 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 w1, w2, 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();
int font = rb->screens[SCREEN_MAIN]->getfont();
h = rb->font_get(font)->height + 1;
/* draw background */
#ifdef HAVE_LCD_COLOR
rb->lcd_bitmap(bubbles_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
#endif
/* display play board */
for(i=0; i<BB_HEIGHT; i++) {
colmax = BB_WIDTH;
if(evenline) {
colmax--;
indent = ROW_INDENT;
} else {
indent = 0;
}
evenline = !evenline;
for(j=0; j<colmax; j++) {
if(bb->playboard[i][j].type >= 0 && !bb->playboard[i][j].delete) {
rb->lcd_bitmap_part(bubbles_emblem,
0, EMBLEM_HEIGHT*bb->playboard[i][j].type,
STRIDE( SCREEN_MAIN,
BMPWIDTH_bubbles_emblem, BMPHEIGHT_bubbles_emblem),
XOFS+indent+BUBBLE_WIDTH*j+(BUBBLE_WIDTH-EMBLEM_WIDTH)/2,
YOFS+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,
YOFS+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],
STRIDE( SCREEN_MAIN,
BMPWIDTH_bubbles_emblem, BMPHEIGHT_bubbles_emblem),
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 */
#ifndef NEXT_BB_X
rb->lcd_bitmap_part(bubbles_emblem,
0, EMBLEM_HEIGHT*bb->queue[(bb->nextinq+1)%NUM_QUEUE],
STRIDE( SCREEN_MAIN,
BMPWIDTH_bubbles_emblem, BMPHEIGHT_bubbles_emblem),
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);
#else
rb->lcd_bitmap_part(bubbles_emblem,
0, EMBLEM_HEIGHT*bb->queue[(bb->nextinq+1)%NUM_QUEUE],
STRIDE( SCREEN_MAIN,
BMPWIDTH_bubbles_emblem, BMPHEIGHT_bubbles_emblem),
NEXT_BB_X + NEXT_BB_WIDTH/2-BUBBLE_WIDTH/2+(BUBBLE_WIDTH-EMBLEM_WIDTH)/2,
NEXT_BB_Y + (BUBBLE_HEIGHT-EMBLEM_HEIGHT)/2 + h,
EMBLEM_WIDTH, EMBLEM_HEIGHT);
rb->lcd_set_drawmode(DRMODE_FG);
rb->lcd_mono_bitmap((const unsigned char *)bubbles_bubble,
NEXT_BB_X + NEXT_BB_WIDTH/2-BUBBLE_WIDTH/2, NEXT_BB_Y + h,
BUBBLE_WIDTH, BUBBLE_HEIGHT);
rb->lcd_set_drawmode(DRMODE_SOLID);
#endif
/* 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, YOFS+bb->compress*ROW_HEIGHT-1);
rb->lcd_hline(XOFS, XOFS+BUBBLE_WIDTH*BB_WIDTH-1,
YOFS+ROW_HEIGHT*(BB_HEIGHT-2)+BUBBLE_HEIGHT);
/* draw arrow */
tipx = SHOTX+BUBBLE_WIDTH/2+(((fp14_sin(bb->angle)>>4)*BUBBLE_WIDTH*3/2)>>10);
tipy = SHOTY+BUBBLE_HEIGHT/2-(((fp14_cos(bb->angle)>>4)*BUBBLE_HEIGHT*3/2)>>10);
rb->lcd_drawline(SHOTX+BUBBLE_WIDTH/2+(((fp14_sin(bb->angle)>>4)*BUBBLE_WIDTH/2)>>10),
SHOTY+BUBBLE_HEIGHT/2-(((fp14_cos(bb->angle)>>4)*BUBBLE_HEIGHT/2)>>10),
tipx, tipy);
xlcd_filltriangle(tipx, tipy,
tipx+(((fp14_sin(bb->angle-135)>>4)*BUBBLE_WIDTH/3)>>10),
tipy-(((fp14_cos(bb->angle-135)>>4)*BUBBLE_HEIGHT/3)>>10),
tipx+(((fp14_sin(bb->angle+135)>>4)*BUBBLE_WIDTH/3)>>10),
tipy-(((fp14_cos(bb->angle+135)>>4)*BUBBLE_HEIGHT/3)>>10));
/* draw text */
rb->snprintf(str, 4, "%d", bb->level);
rb->lcd_getstringsize(level, &w1, NULL);
rb->lcd_getstringsize(str, &w2, NULL);
#ifndef LEVEL_TXT_X
rb->lcd_putsxy(XOFS/2-w1/2, 2, level);
rb->lcd_putsxy(XOFS/2-w2/2, 2+h, str);
#else
rb->lcd_putsxy(LEVEL_TXT_X+(LEVEL_TXT_WIDTH/2-w1/2), LEVEL_TXT_Y, level);
rb->lcd_putsxy(LEVEL_TXT_X+(LEVEL_TXT_WIDTH/2-w2/2), LEVEL_TXT_Y+h, str);
#endif
rb->snprintf(str, 10, "%d", bb->score);
rb->lcd_getstringsize(score, &w1,NULL);
rb->lcd_getstringsize(str, &w2, NULL);
#ifndef SCORE_TXT_X
rb->lcd_putsxy(XOFS/2-w1/2, 29, score);
rb->lcd_putsxy(XOFS/2-w2/2, 29+h, str);
#else
rb->lcd_putsxy(SCORE_TXT_X+(SCORE_TXT_WIDTH/2-w1/2), SCORE_TXT_Y, score);
rb->lcd_putsxy(SCORE_TXT_X+(SCORE_TXT_WIDTH/2-w2/2), SCORE_TXT_Y+h, str);
#endif
rb->lcd_getstringsize(next, &w1, NULL);
#ifndef NEXT_BB_X
rb->lcd_putsxy(XOFS/2-w1/2, SHOTY-h, next);
#else
rb->lcd_putsxy(NEXT_BB_X+(NEXT_BB_WIDTH/2-w1/2), NEXT_BB_Y, next);
#endif
if(bb->elapsedshot >= (MAX_SHOTTIME*7)/10) {
rb->lcd_getstringsize(hurry, &w1, &h);
rb->lcd_putsxy(LCD_WIDTH/2-w1/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 = ((fp14_sin(bb->angle)>>4)*BUBBLE_WIDTH)/3;
shotyinc = ((-1*(fp14_cos(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,
STRIDE( SCREEN_MAIN,
BMPWIDTH_bubbles_emblem,
BMPHEIGHT_bubbles_emblem),
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)-
(YOFS+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, YOFS+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 <= YOFS+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 = YOFS+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 = YOFS+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 = YOFS+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 = YOFS+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 = YOFS+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 = YOFS+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; i<BB_HEIGHT; i++) {
for(j=0; j<BB_WIDTH; j++) {
bb->playboard[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; i<count; i++) {
myrow = search[i].row;
mycol = search[i].col;
mytype = bb->playboard[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; j<BB_WIDTH; j++) {
if(bb->playboard[0][j].type >= 0 && !bb->playboard[0][j].ingroup) {
bubbles_anchored(bb, 0, j);
}
}
/* mark bubbles to be deleted */
for(i=0; i<BB_HEIGHT; i++) {
for(j=0; j<BB_WIDTH; j++) {
if(bb->playboard[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; i<BB_HEIGHT; i++) {
for(j=0; j<BB_WIDTH; j++) {
if(bb->playboard[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; i<count; i++) {
myrow = search[i].row;
mycol = search[i].col;
mytype = bb->playboard[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; i<BB_HEIGHT; i++) {
for(j=0; j<BB_WIDTH; j++) {
if(bb->playboard[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; i<BB_HEIGHT; i++) {
for(j=0; j<BB_WIDTH; j++) {
if(bb->playboard[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(YOFS+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,
STRIDE( SCREEN_MAIN,
BMPWIDTH_bubbles_emblem,
BMPHEIGHT_bubbles_emblem),
XOFS+indent+BUBBLE_WIDTH*j+
(BUBBLE_WIDTH-EMBLEM_WIDTH)/2+xofs,
YOFS+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,
YOFS+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; j<BB_WIDTH; j++) {
if(bb->playboard[BB_HEIGHT-1-i][j].type >= 0) return BB_LOSE;
}
}
/* check for bubbles above cut off point */
for(i=0; i<BB_HEIGHT-1-bb->compress; i++) {
for(j=0; j<BB_WIDTH; j++) {
if(bb->playboard[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 void bubbles_recordscore(struct game_context* bb) {
int position;
position = highscore_update(bb->score, bb->level-1, "",
highscores, NUM_SCORES);
if (position != -1)
{
if (position == 0)
rb->splash(HZ*2, "New High Score");
highscore_show(position, highscores, NUM_SCORES, true);
}
}
/*****************************************************************************
* bubbles_loaddata() loads highest level beaten.
******************************************************************************/
static void bubbles_loaddata(void) {
int fd;
last_highlevel = highlevel = 0;
/* open data file */
fd = rb->open(DATA_FILE, O_RDONLY);
if (fd < 0) return;
/* read in saved game */
if (rb->read(fd, &highlevel, sizeof(highlevel)) < (long)sizeof(highlevel))
{
highlevel = 0;
}
if (highlevel >= NUM_LEVELS)
highlevel = NUM_LEVELS-1;
last_highlevel = highlevel;
rb->close(fd);
}
/*****************************************************************************
* bubbles_savedata() saves the current game state.
******************************************************************************/
static void bubbles_savedata(void) {
int fd;
if (last_highlevel >= highlevel) /* no need to save */
return;
fd = rb->open(DATA_FILE, O_WRONLY|O_CREAT, 0666);
if (fd < 0) return;
rb->write(fd, &highlevel, sizeof(highlevel));
rb->close(fd);
}
/*****************************************************************************
* bubbles_loadgame() loads the saved game and returns load success.
******************************************************************************/
static bool bubbles_loadgame(struct game_context* bb) {
int fd;
bool ret = true;
/* open game file */
fd = rb->open(SAVE_FILE, O_RDONLY);
if(fd < 0) return false;
/* read in saved game */
if(rb->read(fd, bb, sizeof(struct game_context))
< (long)sizeof(struct game_context))
{
ret = false;
}
rb->close(fd);
return ret;
}
/*****************************************************************************
* bubbles_savegame() saves the current game state.
******************************************************************************/
static void bubbles_savegame(struct game_context* bb) {
int fd;
if (!resume) /* nothing to save */
return;
/* write out the game state to the save file */
fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT, 0666);
if (fd < 0)
{
rb->splash(HZ/2, "Failed to save game");
return;
}
if (rb->write(fd, bb, sizeof(struct game_context)) <= 0)
{
rb->splash(HZ/2, "Failed to save game");
}
rb->close(fd);
}
/*****************************************************************************
* 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) {
(void) param;
highscore_save(SCORE_FILE, highscores, NUM_SCORES);
}
/*****************************************************************************
* 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[]
= { pla_main_ctx,
#ifdef HAVE_REMOTE_LCD
pla_remote_ctx,
#endif
};
if (timeout < 0)
timeout = 0;
button = pluginlib_getaction(timeout,plugin_contexts,ARRAYLEN(plugin_contexts));
#if defined(HAS_BUTTON_HOLD) && !defined(HAVE_REMOTE_LCD_AS_MAIN)
/* FIXME: Should probably check remote hold here */
if (rb->button_hold())
button = BUBBLES_PAUSE;
#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_FIRE: /* fire the shot */
case BUBBLES_FIRE_REPEAT:
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_PAUSE: /* pause the game */
start = *rb->current_tick;
rb->splash(0, "Paused");
while(pluginlib_getaction(TIMEOUT_BLOCK,plugin_contexts,
ARRAYLEN(plugin_contexts))
!= BUBBLES_PAUSE);
bb->startedshot += *rb->current_tick-start;
bubbles_drawboard(bb);
rb->lcd_update();
break;
case BUBBLES_QUIT1:
case BUBBLES_QUIT2: /* end the game */
if(!animblock) {
resume = true;
return BB_END;
}
break;
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;
}
static int bubbles_menu_cb(int action, const struct menu_item_ex *this_item)
{
int i = ((intptr_t)this_item);
if(action == ACTION_REQUEST_MENUITEM
&& !resume && (i==0))
return ACTION_EXIT_MENUITEM;
return action;
}
/*****************************************************************************
* bubbles_menu() is the initial menu at the start of the game.
******************************************************************************/
static int bubbles_menu(struct game_context* bb) {
static unsigned int startlevel = 0;
int selected = 0;
bool startgame = false;
MENUITEM_STRINGLIST(menu,"Bubbles Menu",bubbles_menu_cb,
"Resume Game", "Start New Game",
"Level", "High Scores", "Playback Control",
"Quit without Saving", "Quit");
while(!startgame){
switch (rb->do_menu(&menu, &selected, NULL, false))
{
case 0: /* resume game */
startgame = true;
if(resume_file)
rb->remove(SAVE_FILE);
resume_file = false;
break;
case 1: /* new game */
bb->level = startlevel;
startgame = true;
resume = false;
resume_file = false;
break;
case 2: /* choose level */
startlevel++;
rb->set_int("Choose start level", "", UNIT_INT, &startlevel,
NULL, 1, 1, highlevel+1, NULL);
startlevel--;
break;
case 3: /* High scores */
highscore_show(-1, highscores, NUM_SCORES, true);
break;
case 4: /* Playback Control */
playback_control(NULL);
break;
case 5: /* quit but don't save */
return BB_QUIT_WITHOUT_SAVING;
case 6: /* save and quit */
return BB_QUIT;
case MENU_ATTACHED_USB:
bubbles_callback(bb);
return BB_USB;
}
}
return 0;
}
/*****************************************************************************
* bubbles() is the main game subroutine, it returns the final game status.
******************************************************************************/
static int bubbles(struct game_context* bb) {
int buttonres;
long timeout;
/********************
* menu *
********************/
buttonres = bubbles_menu(bb);
if(buttonres != 0)
return buttonres;
/********************
* 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 void* parameter) {
static struct game_context bb;
bool exit = false;
enum plugin_status ret = PLUGIN_OK;
(void)parameter;
/* load files */
resume = bubbles_loadgame(&bb);
resume_file = resume;
bubbles_loaddata();
highscore_load(SCORE_FILE, highscores, NUM_SCORES);
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)){
case BB_WIN:
rb->splash(HZ*2, "You Win!");
/* record high level */
highlevel = NUM_LEVELS-1;
/* record high score */
bubbles_recordscore(&bb);
break;
case BB_LOSE:
resume = false;
rb->splash(HZ*2, "Game Over");
/* record high score */
bubbles_recordscore(&bb);
/* fall through to BB_END */
case BB_END:
break;
case BB_USB:
ret = PLUGIN_USB_CONNECTED;
exit = true;
break;
case BB_QUIT:
rb->splash(HZ/3, "Saving game data ...");
bubbles_savegame(&bb);
bubbles_savedata();
highscore_save(SCORE_FILE, highscores, NUM_SCORES);
/* fall through */
case BB_QUIT_WITHOUT_SAVING:
exit = true;
break;
default:
break;
}
}
rb->lcd_setfont(FONT_UI);
return ret;
}
#endif