rockbox/apps/plugins/bubbles.c
Teruaki Kawashima f79b45d8bb bubbles: fix FS#11070
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25044 a1c6a512-1295-4272-9138-f99709370657
2010-03-06 12:29:17 +00:00

2557 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 */
#if (CONFIG_KEYPAD != SANSA_E200_PAD) && \
(CONFIG_KEYPAD != SANSA_FUZE_PAD)
/* sansas use the wheel instead of left/right if available */
#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_QUIT1 PLA_QUIT
#define BUBBLES_QUIT2 PLA_MENU
#define BUBBLES_PAUSE PLA_START
#define BUBBLES_FIRE PLA_FIRE
/* 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);
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);
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[]
#if (CONFIG_KEYPAD == SANSA_E200_PAD) || \
(CONFIG_KEYPAD == SANSA_FUZE_PAD)
= {generic_directions,generic_actions};
#else
= {generic_left_right_fire,generic_actions};
#endif
if (timeout < 0)
timeout = 0;
button = pluginlib_getaction(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_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 */
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,2)
!= 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