diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index 76859dfa94..83880f5809 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -59,7 +59,7 @@ sokoban.c star.c starfield.c #if (LCD_WIDTH != 240) && ((LCD_WIDTH != 128) || (LCD_HEIGHT != 64)) -tetrox.c +rockblox.c #endif #if CONFIG_LCD == LCD_SSD1815 video.c diff --git a/apps/plugins/bitmaps/mono/SOURCES b/apps/plugins/bitmaps/mono/SOURCES index be23b4f519..e6ccebb9ce 100644 --- a/apps/plugins/bitmaps/mono/SOURCES +++ b/apps/plugins/bitmaps/mono/SOURCES @@ -27,9 +27,9 @@ brickmania_powerups.112x64x1.bmp #endif -/* Tetrox */ +/* Rockblox */ #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64) -tetrox_background.112x64x1.bmp +rockblox_background.112x64x1.bmp #endif /* Solitaire */ diff --git a/apps/plugins/bitmaps/mono/tetrox_background.112x64x1.bmp b/apps/plugins/bitmaps/mono/rockblox_background.112x64x1.bmp similarity index 100% rename from apps/plugins/bitmaps/mono/tetrox_background.112x64x1.bmp rename to apps/plugins/bitmaps/mono/rockblox_background.112x64x1.bmp diff --git a/apps/plugins/bitmaps/native/SOURCES b/apps/plugins/bitmaps/native/SOURCES index 41b6d6f4f7..a06a287a8e 100644 --- a/apps/plugins/bitmaps/native/SOURCES +++ b/apps/plugins/bitmaps/native/SOURCES @@ -255,21 +255,21 @@ brickmania_break.176x132x16.bmp #endif -/* Tetrox */ +/* Rockblox */ #if (LCD_WIDTH == 320) && (LCD_HEIGHT == 240) && (LCD_DEPTH == 16) -tetrox_background.320x240x16.bmp +rockblox_background.320x240x16.bmp #elif (LCD_WIDTH >= 220) && (LCD_HEIGHT >= 176) && (LCD_DEPTH == 16) -tetrox_background.220x176x16.bmp +rockblox_background.220x176x16.bmp #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132) && (LCD_DEPTH == 16) -tetrox_background.176x132x16.bmp +rockblox_background.176x132x16.bmp #elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128) && (LCD_DEPTH >= 16) -tetrox_background.160x128x16.bmp +rockblox_background.160x128x16.bmp #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128) && (LCD_DEPTH == 16) -tetrox_background.128x128x16.bmp +rockblox_background.128x128x16.bmp #elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128) && (LCD_DEPTH == 2) -tetrox_background.160x128x2.bmp +rockblox_background.160x128x2.bmp #elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110) && (LCD_DEPTH == 2) -tetrox_background.138x110x2.bmp +rockblox_background.138x110x2.bmp #endif #ifdef HAVE_LCD_COLOR diff --git a/apps/plugins/bitmaps/native/tetrox_background.128x128x16.bmp b/apps/plugins/bitmaps/native/rockblox_background.128x128x16.bmp old mode 100755 new mode 100644 similarity index 100% rename from apps/plugins/bitmaps/native/tetrox_background.128x128x16.bmp rename to apps/plugins/bitmaps/native/rockblox_background.128x128x16.bmp diff --git a/apps/plugins/bitmaps/native/tetrox_background.138x110x2.bmp b/apps/plugins/bitmaps/native/rockblox_background.138x110x2.bmp similarity index 68% rename from apps/plugins/bitmaps/native/tetrox_background.138x110x2.bmp rename to apps/plugins/bitmaps/native/rockblox_background.138x110x2.bmp index c16c8030a5..23df4ed506 100644 Binary files a/apps/plugins/bitmaps/native/tetrox_background.138x110x2.bmp and b/apps/plugins/bitmaps/native/rockblox_background.138x110x2.bmp differ diff --git a/apps/plugins/bitmaps/native/tetrox_background.160x128x16.bmp b/apps/plugins/bitmaps/native/rockblox_background.160x128x16.bmp old mode 100755 new mode 100644 similarity index 100% rename from apps/plugins/bitmaps/native/tetrox_background.160x128x16.bmp rename to apps/plugins/bitmaps/native/rockblox_background.160x128x16.bmp diff --git a/apps/plugins/bitmaps/native/rockblox_background.160x128x2.bmp b/apps/plugins/bitmaps/native/rockblox_background.160x128x2.bmp new file mode 100644 index 0000000000..7f30c8c165 Binary files /dev/null and b/apps/plugins/bitmaps/native/rockblox_background.160x128x2.bmp differ diff --git a/apps/plugins/bitmaps/native/tetrox_background.176x132x16.bmp b/apps/plugins/bitmaps/native/rockblox_background.176x132x16.bmp old mode 100755 new mode 100644 similarity index 100% rename from apps/plugins/bitmaps/native/tetrox_background.176x132x16.bmp rename to apps/plugins/bitmaps/native/rockblox_background.176x132x16.bmp diff --git a/apps/plugins/bitmaps/native/tetrox_background.220x176x16.bmp b/apps/plugins/bitmaps/native/rockblox_background.220x176x16.bmp old mode 100755 new mode 100644 similarity index 100% rename from apps/plugins/bitmaps/native/tetrox_background.220x176x16.bmp rename to apps/plugins/bitmaps/native/rockblox_background.220x176x16.bmp diff --git a/apps/plugins/bitmaps/native/tetrox_background.320x240x16.bmp b/apps/plugins/bitmaps/native/rockblox_background.320x240x16.bmp old mode 100755 new mode 100644 similarity index 100% rename from apps/plugins/bitmaps/native/tetrox_background.320x240x16.bmp rename to apps/plugins/bitmaps/native/rockblox_background.320x240x16.bmp diff --git a/apps/plugins/bitmaps/native/tetrox_background.160x128x2.bmp b/apps/plugins/bitmaps/native/tetrox_background.160x128x2.bmp deleted file mode 100755 index dbc0a713e8..0000000000 Binary files a/apps/plugins/bitmaps/native/tetrox_background.160x128x2.bmp and /dev/null differ diff --git a/apps/plugins/rockblox.c b/apps/plugins/rockblox.c new file mode 100644 index 0000000000..1277b328c2 --- /dev/null +++ b/apps/plugins/rockblox.c @@ -0,0 +1,870 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 Eli Sherer + * + * Heavily modified for embedded use by Björn Stenberg (bjorn@haxx.se) + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "plugin.h" +#include "highscore.h" + +#ifdef HAVE_LCD_BITMAP + +PLUGIN_HEADER + +extern const fb_data rockblox_background[]; + +#if (CONFIG_KEYPAD == IPOD_3G_PAD) || \ + (CONFIG_KEYPAD == IPOD_4G_PAD) + +#define ROCKBLOX_OFF (BUTTON_MENU | BUTTON_SELECT) +#define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_BACK +#define ROCKBLOX_ROTATE_RIGHT2 (BUTTON_MENU | BUTTON_REL) +#define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_FWD +#define ROCKBLOX_LEFT BUTTON_LEFT +#define ROCKBLOX_RIGHT BUTTON_RIGHT +#define ROCKBLOX_DOWN BUTTON_PLAY +#define ROCKBLOX_RESTART (BUTTON_SELECT | BUTTON_PLAY) +#define ROCKBLOX_DROP (BUTTON_SELECT | BUTTON_REL) + +#define SCROLL_WHEEL + +#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ + (CONFIG_KEYPAD == IRIVER_H300_PAD) + +#define ROCKBLOX_OFF BUTTON_OFF +#define ROCKBLOX_ROTATE_RIGHT BUTTON_UP +#define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT +#define ROCKBLOX_DOWN BUTTON_DOWN +#define ROCKBLOX_LEFT BUTTON_LEFT +#define ROCKBLOX_RIGHT BUTTON_RIGHT +#define ROCKBLOX_DROP BUTTON_MODE +#define ROCKBLOX_RESTART BUTTON_ON + +#define ROCKBLOX_RC_OFF BUTTON_RC_STOP +#elif CONFIG_KEYPAD == RECORDER_PAD + +#define ROCKBLOX_OFF BUTTON_OFF +#define ROCKBLOX_ROTATE_RIGHT BUTTON_UP +#define ROCKBLOX_ROTATE_LEFT BUTTON_PLAY +#define ROCKBLOX_DOWN BUTTON_DOWN +#define ROCKBLOX_LEFT BUTTON_LEFT +#define ROCKBLOX_RIGHT BUTTON_RIGHT +#define ROCKBLOX_DROP BUTTON_ON +#define ROCKBLOX_RESTART BUTTON_F1 + +#elif CONFIG_KEYPAD == ONDIO_PAD + +#define ROCKBLOX_OFF BUTTON_OFF +#define ROCKBLOX_ROTATE_RIGHT BUTTON_UP +#define ROCKBLOX_ROTATE_LEFT (BUTTON_MENU|BUTTON_UP) +#define ROCKBLOX_DOWN BUTTON_DOWN +#define ROCKBLOX_LEFT BUTTON_LEFT +#define ROCKBLOX_RIGHT BUTTON_RIGHT +#define ROCKBLOX_DROP_PRE BUTTON_MENU +#define ROCKBLOX_DROP (BUTTON_MENU|BUTTON_REL) + +#elif CONFIG_KEYPAD == IAUDIO_X5_PAD + +#define ROCKBLOX_OFF BUTTON_POWER +#define ROCKBLOX_ROTATE_RIGHT BUTTON_UP +#define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT +#define ROCKBLOX_DOWN BUTTON_DOWN +#define ROCKBLOX_LEFT BUTTON_LEFT +#define ROCKBLOX_RIGHT BUTTON_RIGHT +#define ROCKBLOX_DROP BUTTON_REC +#define ROCKBLOX_RESTART BUTTON_PLAY + +#elif CONFIG_KEYPAD == IRIVER_H10_PAD + +#define ROCKBLOX_OFF BUTTON_POWER +#define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_UP +#define ROCKBLOX_ROTATE_LEFT BUTTON_REW +#define ROCKBLOX_DOWN BUTTON_SCROLL_DOWN +#define ROCKBLOX_LEFT BUTTON_LEFT +#define ROCKBLOX_RIGHT BUTTON_RIGHT +#define ROCKBLOX_DROP BUTTON_FF +#define ROCKBLOX_RESTART BUTTON_PLAY + +#endif + +#define BLOCKS_NUM 7 +#define EMPTY_BLOCK 7 + +#define BOARD_WIDTH 10 +#define BOARD_HEIGHT 20 + +#if (LCD_WIDTH == 320) && (LCD_HEIGHT == 240) + +#define BLOCK_WIDTH 12 +#define BLOCK_HEIGHT 12 +#define BOARD_X 86 +#define BOARD_Y 0 +#define PREVIEW_X 12 +#define PREVIEW_Y 11 +#define LABEL_X 242 +#define SCORE_Y 25 +#define LEVEL_Y 70 +#define LINES_Y 105 + +#elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176) + +#define BLOCK_WIDTH 8 +#define BLOCK_HEIGHT 8 +#define BOARD_X 27 +#define BOARD_Y 5 +#define PREVIEW_X 158 +#define PREVIEW_Y 130 +#define LABEL_X 147 +#define SCORE_Y 20 +#define LEVEL_Y 65 +#define LINES_Y 100 + +#elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132) + +#define BLOCK_WIDTH 6 +#define BLOCK_HEIGHT 6 +#define BOARD_X 25 +#define BOARD_Y 1 +#define PREVIEW_X 126 +#define PREVIEW_Y 102 +#define LABEL_X 112 +#define SCORE_Y 17 +#define LEVEL_Y 49 +#define LINES_Y 81 + +#elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128) + +#define BLOCK_WIDTH 6 +#define BLOCK_HEIGHT 6 +#define BOARD_X 22 +#define BOARD_Y 3 +#define PREVIEW_X 114 +#define PREVIEW_Y 100 +#define LABEL_X 101 +#define SCORE_Y 17 +#define LEVEL_Y 49 +#define LINES_Y 82 + +#elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128) + +#define BLOCK_WIDTH 6 +#define BLOCK_HEIGHT 6 +#define BOARD_X 4 +#define BOARD_Y 3 +#define PREVIEW_X 84 +#define PREVIEW_Y 100 +#define LABEL_X 71 +#define SCORE_Y 17 +#define LEVEL_Y 49 +#define LINES_Y 82 + +#elif (LCD_WIDTH == 112) && (LCD_HEIGHT == 64) + +#define BLOCK_WIDTH 4 +#define BLOCK_HEIGHT 3 +#define BOARD_X 9 +#define BOARD_Y 3 +#define PREVIEW_X 59 +#define PREVIEW_Y 5 +#define LABEL_X 59 +#define SCORE_Y 32 +#define LEVEL_Y 13 +#define LEVEL_X 78 +#define LINES_Y 51 + +#elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110) + +#define BLOCK_WIDTH 5 +#define BLOCK_HEIGHT 5 +#define BOARD_X 14 +#define BOARD_Y 0 +#define PREVIEW_X 98 +#define PREVIEW_Y 88 +#define LABEL_X 80 +#define SCORE_Y 15 +#define LEVEL_Y 45 +#define LINES_Y 74 + +#endif + +/* Pictures */ +#ifdef HAVE_LCD_COLOR +#define SPLASH_SCREEN PLUGIN_DIR "/rockblox/splash.bmp" +#define PIC_SCREEN PLUGIN_DIR "/rockblox/screen.bmp" +#endif + +/* <> + + %% + %% - O has 1 orientation + + %% % + %% %% - Z has 2 orientations + % + + %% % + %% %% - S has 2 orientations + % + % + % + % %%%% - I has 2 orientations + % + + % %% + % % % %%% - L has 4 orientations + %% %%% % % + + % %%s + % % % %%% - J has 4 orientations + %% %%% % % + + % % %%% + %% % %% % - T has 4 orientations + % %%% % + */ + + +/* must have variable */ +static struct plugin_api *rb; + +static bool gameover = false; +/* c=current f=figure o=orientation n=next */ +static int lines, level, score, cx, cy, cf, co, nf; +static short board[BOARD_HEIGHT][BOARD_WIDTH]; /* 20 rows of 10 blocks */ + +#ifdef SCROLL_WHEEL +int wheel_events = 0, last_wheel_event = 0; +bool wheel_enabled = false; +#endif + +static const short scoring[4] = { /* scoring for each number of lines */ + 40 /* single */ , 100 /* double */ , 300 /* triple */ , 1200 /* rockblox */ +}; + +struct figure +{ +#if LCD_DEPTH >= 2 + unsigned short color[3]; /* color of figure (light,middle,shadow) */ +#endif + unsigned short max_or; /* max orientations */ + signed short shapeX[4], shapeY[4]; /* implementation of figures */ +} + +/* array of figures */ +figures[BLOCKS_NUM] = { + /* O */ + { +#if LCD_DEPTH >= 16 + {LCD_RGBPACK (153, 255, 255), LCD_RGBPACK(0, 255, 255), + LCD_RGBPACK(0,153,153)}, +#elif LCD_DEPTH == 2 + {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY}, +#endif + 1, + {-1, 0, -1, 0}, + {0, 0, 1, 1} + }, + /* I */ + { +#if LCD_DEPTH >= 16 + {LCD_RGBPACK (255, 153, 128), LCD_RGBPACK (255, 0, 0), + LCD_RGBPACK (153, 0, 0)}, +#elif LCD_DEPTH == 2 + {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY}, +#endif + 2, + {-2, -1, 0, 1}, + {0, 0, 0, 0} + }, + /* 'Z' */ + { +#if LCD_DEPTH >= 16 + {LCD_RGBPACK (153, 255, 153), LCD_RGBPACK (0, 255, 0), + LCD_RGBPACK (0, 153, 0)}, +#elif LCD_DEPTH == 2 + {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY}, +#endif + 2, + {0, 1, -1, 0}, + {0, 0, 1, 1} + }, + /* 'S' */ + { +#if LCD_DEPTH >= 16 + {LCD_RGBPACK (153, 153, 255), LCD_RGBPACK (0, 0, 255), + LCD_RGBPACK (0, 0, 153)}, +#elif LCD_DEPTH == 2 + {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY}, +#endif + 2, + {-1, 0, 0, 1}, + {0, 0, 1, 1} + }, + /* 'L' */ + { +#if LCD_DEPTH >= 16 + {LCD_RGBPACK (255, 255, 153), LCD_RGBPACK (255, 255, 0), + LCD_RGBPACK (153, 153, 0)}, +#elif LCD_DEPTH == 2 + {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY}, +#endif + 4, + {-1, 0, 1, 1}, + {0, 0, 0, 1} + }, + /* 'J' */ + { +#if LCD_DEPTH >= 16 + {LCD_RGBPACK (255, 153, 255), LCD_RGBPACK (255, 0, 255), + LCD_RGBPACK (153, 0, 153)}, +#elif LCD_DEPTH == 2 + {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY}, +#endif + 4, + {-1, 0, 1, -1}, + {0, 0, 0, 1} + }, + /* 'T' */ + { +#if LCD_DEPTH >= 16 + {LCD_RGBPACK (204, 204, 204), LCD_RGBPACK (153, 153, 153), + LCD_RGBPACK (85, 85, 85)}, +#elif LCD_DEPTH == 2 + {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY}, +#endif + 4, + {-1, 0, 1, 0}, + {0, 0, 0, 1} + } +}; + +/* get random number from (0) to (range-1) */ +static int t_rand (int range) +{ + return rb->rand () % range; +} + +/* init the board array to have no blocks */ +static void init_board (void) +{ + int i, j; + for (i = 0; i < BOARD_WIDTH; i++) + for (j = 0; j < BOARD_HEIGHT; j++) + board[j][i] = EMPTY_BLOCK; +} + +/* show the score, level and lines */ +static void show_details (void) +{ + char str[25]; /* for strings */ +#if LCD_DEPTH >= 2 + rb->lcd_set_foreground (LCD_BLACK); + rb->lcd_set_background (LCD_WHITE); +#endif + rb->snprintf (str, sizeof (str), "%d", score); + rb->lcd_putsxy (LABEL_X, SCORE_Y, str); + rb->snprintf (str, sizeof (str), "%d", level); +#ifdef LEVEL_X + rb->lcd_putsxy (LEVEL_X, LEVEL_Y, str); +#else + rb->lcd_putsxy (LABEL_X, LEVEL_Y, str); +#endif + rb->snprintf (str, sizeof (str), "%d", lines); + rb->lcd_putsxy (LABEL_X, LINES_Y, str); +} + +static void init_rockblox (void) +{ + level = 1; + lines = 0; + score = 0; + gameover = false; + nf = t_rand (BLOCKS_NUM); + init_board (); + rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT); + show_details (); +} + +static inline int level_speed(int level) +{ + return (5*HZ) / (level + 9); +} + +static int getRelativeX (int figure, int square, int orientation) +{ + switch (orientation) { + case 0: + return figures[figure].shapeX[square]; + case 1: + return figures[figure].shapeY[square]; + case 2: + return -figures[figure].shapeX[square]; + case 3: + return -figures[figure].shapeY[square]; + default: + return 0; + } +} + +static int getRelativeY (int figure, int square, int orientation) +{ + switch (orientation) { + case 0: + return figures[figure].shapeY[square]; + case 1: + return -figures[figure].shapeX[square]; + case 2: + return -figures[figure].shapeY[square]; + case 3: + return figures[figure].shapeX[square]; + default: + return 0; + } +} + +/* redraw the while board on the screen */ +static void refresh_board (void) +{ + int i, j, x, y, block; + +#if LCD_DEPTH >= 2 + rb->lcd_set_foreground (LCD_BLACK); +#elif LCD_DEPTH == 1 + rb->lcd_set_drawmode (DRMODE_SOLID | DRMODE_INVERSEVID); +#endif + + rb->lcd_fillrect (BOARD_X, 1, BOARD_WIDTH * BLOCK_WIDTH, BOARD_Y); + +#if LCD_DEPTH == 1 + rb->lcd_set_drawmode (DRMODE_SOLID); +#endif + + for (i = 0; i < BOARD_WIDTH; i++) + for (j = 0; j < BOARD_HEIGHT; j++) { + block = board[j][i]; + if (block == EMPTY_BLOCK) { +#if LCD_DEPTH >= 2 + rb->lcd_set_foreground (LCD_BLACK); +#elif LCD_DEPTH == 1 + rb->lcd_set_drawmode (DRMODE_SOLID | DRMODE_INVERSEVID); +#endif + + rb->lcd_fillrect (BOARD_X + i * BLOCK_WIDTH, + BOARD_Y + j * BLOCK_HEIGHT, BLOCK_WIDTH, + BLOCK_HEIGHT); + +#if LCD_DEPTH == 1 + rb->lcd_set_drawmode (DRMODE_SOLID); +#endif + } else { +#if LCD_DEPTH >= 2 + /* middle drawing */ + rb->lcd_set_foreground (figures[block].color[1]); +#endif + rb->lcd_fillrect (BOARD_X + i * BLOCK_WIDTH, + BOARD_Y + j * BLOCK_HEIGHT, + BLOCK_WIDTH, BLOCK_HEIGHT); +#if LCD_DEPTH >= 2 + /* light drawing */ + rb->lcd_set_foreground (figures[block].color[0]); +#endif + rb->lcd_vline (BOARD_X + i * BLOCK_WIDTH, + BOARD_Y + j * BLOCK_HEIGHT, + BOARD_Y + (j + 1) * BLOCK_HEIGHT - 2); + rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH, + BOARD_X + (i + 1) * BLOCK_WIDTH - 2, + BOARD_Y + j * BLOCK_HEIGHT); +#if LCD_DEPTH >= 2 + /* shadow drawing */ + rb->lcd_set_foreground (figures[block].color[2]); +#endif + rb->lcd_vline (BOARD_X + (i + 1) * BLOCK_WIDTH - 1, + BOARD_Y + j * BLOCK_HEIGHT + 1, + BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1); + rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH + 1, + BOARD_X + (i + 1) * BLOCK_WIDTH - 1, + BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1); + } + } + + for (i = 0; i < 4; i++) { + x = getRelativeX (cf, i, co) + cx; + y = getRelativeY (cf, i, co) + cy; +#if LCD_DEPTH >= 2 + rb->lcd_set_foreground (figures[cf].color[1]); /* middle drawing */ +#endif + rb->lcd_fillrect (BOARD_X + x * BLOCK_WIDTH, + BOARD_Y + y * BLOCK_HEIGHT, + BLOCK_WIDTH, BLOCK_HEIGHT); +#if LCD_DEPTH >= 2 + rb->lcd_set_foreground (figures[cf].color[0]); /* light drawing */ +#endif + rb->lcd_vline (BOARD_X + x * BLOCK_WIDTH, BOARD_Y + y * BLOCK_HEIGHT, + BOARD_Y + (y + 1) * BLOCK_HEIGHT - 2); + rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH, + BOARD_X + (x + 1) * BLOCK_WIDTH - 2, + BOARD_Y + y * BLOCK_HEIGHT); +#if LCD_DEPTH >= 2 + rb->lcd_set_foreground (figures[cf].color[2]); /* shadow drawing */ +#endif + rb->lcd_vline (BOARD_X + (x + 1) * BLOCK_WIDTH - 1, + BOARD_Y + y * BLOCK_HEIGHT + 1, + BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1); + rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH + 1, + BOARD_X + (x + 1) * BLOCK_WIDTH - 1, + BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1); + } + rb->lcd_update (); +} + +static bool canMoveTo (int x, int y, int newOrientation) +{ + int i, rx, ry; + for (i = 0; i < 4; i++) { + ry = getRelativeY (cf, i, newOrientation) + y; + rx = getRelativeX (cf, i, newOrientation) + x; + if ((rx < 0 || rx >= BOARD_WIDTH) || + (ry < 0 || ry >= BOARD_HEIGHT) || (board[ry][rx] != EMPTY_BLOCK)) + return false; + } + return true; +} + +/* draws the preview of next block in the preview window */ +static void draw_next_block (void) +{ + int i, rx, ry; + /* clear preview window first */ +#if LCD_DEPTH >= 2 + rb->lcd_set_foreground (LCD_BLACK); +#elif LCD_DEPTH == 1 + rb->lcd_set_drawmode (DRMODE_SOLID | DRMODE_INVERSEVID); +#endif + + /* 4x4 */ + rb->lcd_fillrect (PREVIEW_X, PREVIEW_Y, BLOCK_WIDTH * 4, BLOCK_HEIGHT * 4); + +#if LCD_DEPTH == 1 + rb->lcd_set_drawmode (DRMODE_SOLID); +#endif + + /* draw the lightgray rectangles */ +#if LCD_DEPTH >= 16 + rb->lcd_set_foreground (LCD_RGBPACK (40, 40, 40)); +#elif LCD_DEPTH == 2 + rb->lcd_set_foreground (LCD_DARKGRAY); +#endif + +#if LCD_DEPTH >= 2 + for (rx = 0; rx < 4; rx++) + for (ry = 0; ry < 4; ry++) + rb->lcd_drawrect (PREVIEW_X + rx * BLOCK_WIDTH, + PREVIEW_Y + ry * BLOCK_HEIGHT, BLOCK_WIDTH, + BLOCK_HEIGHT); +#endif + + /* draw the figure */ + for (i = 0; i < 4; i++) { + rx = getRelativeX (nf, i, 0) + 2; + ry = getRelativeY (nf, i, 0) + 2; +#if LCD_DEPTH >= 2 + rb->lcd_set_foreground (figures[nf].color[1]); /* middle drawing */ +#endif + rb->lcd_fillrect (PREVIEW_X + rx * BLOCK_WIDTH, + PREVIEW_Y + ry * BLOCK_HEIGHT, + BLOCK_WIDTH, BLOCK_HEIGHT); +#if LCD_DEPTH >= 2 + rb->lcd_set_foreground (figures[nf].color[0]); /* light drawing */ +#endif + rb->lcd_vline (PREVIEW_X + rx * BLOCK_WIDTH, + PREVIEW_Y + ry * BLOCK_HEIGHT, + PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 2); + rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH, + PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 2, + PREVIEW_Y + ry * BLOCK_HEIGHT); +#if LCD_DEPTH >= 2 + rb->lcd_set_foreground (figures[nf].color[2]); /* shadow drawing */ +#endif + rb->lcd_vline (PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1, + PREVIEW_Y + ry * BLOCK_HEIGHT + 1, + PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1); + rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH + 1, + PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1, + PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1); + } + +} + +/* move the block to a relative location */ +static void move_block (int x, int y, int o) +{ + if (canMoveTo (cx + x, cy + y, o)) { + cy += y; + cx += x; + co = o; + } +} + +/* try to add a new block to play with (return true if gameover) */ +static void new_block (void) +{ + cy = 1; + cx = 5; + cf = nf; + co = 0; /* start at the same orientation all time */ + nf = t_rand (BLOCKS_NUM); + gameover = !canMoveTo (cx, cy, co); + + draw_next_block (); +} + + +/* check for filled lines and do what necessary */ +static int check_lines (void) +{ + int i, j, y; + int rockblox = 0; + + for (j = 0; j < BOARD_HEIGHT; j++) { + for (i = 0; ((i < BOARD_WIDTH) && (board[j][i] != EMPTY_BLOCK)); i++); + if (i == BOARD_WIDTH) { /* woo hoo, we have a line */ + rockblox++; + for (y = j; y > 0; y--) + for (i = 0; i < BOARD_WIDTH; i++) + board[y][i] = board[y - 1][i]; /* fall line */ + } + } + + return rockblox; +} + +/* moves down the figure and returns true if gameover */ +static void move_down (void) +{ + int l, i, rx, ry; + + if (!canMoveTo (cx, cy + 1, co)) { + /* save figure to board */ + for (i = 0; i < 4; i++) { + rx = getRelativeX (cf, i, co) + cx; + ry = getRelativeY (cf, i, co) + cy; + board[ry][rx] = cf; + } + /* check if formed some lines */ + l = check_lines (); + if (l) { + /* the original scoring from "http://en.wikipedia.org/wiki/Rockblox" */ + score += scoring[l - 1] * level; + lines += l; + level = (int) lines / 10 + 1; + } + + /* show details */ + show_details (); + + /* generate a new figure */ + new_block (); + } else + move_block (0, 1, co); +} + +static int rockblox_loop (void) +{ + int button; + int lastbutton = BUTTON_NONE; + long next_down_tick = *rb->current_tick + level_speed(level); + + new_block (); + + while (1) { +#ifdef HAS_BUTTON_HOLD + if (rb->button_hold ()) { + /* Restore user's original backlight setting */ + rb->backlight_set_timeout (rb->global_settings->backlight_timeout); + + rb->splash(0, true, "Paused"); + while (rb->button_hold ()) + rb->sleep(HZ/10); + + /* Permanently enable the backlight (unless the user has + turned it off) */ + if (rb->global_settings->backlight_timeout > 0) + rb->backlight_set_timeout (1); + + /* get rid of the splash text */ + rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT); + show_details (); + draw_next_block (); + refresh_board (); + } +#endif + + button = rb->button_get_w_tmo (MAX(next_down_tick - *rb->current_tick, 1)); + switch (button) { +#ifdef ROCKBLOX_RC_OFF + case ROCKBLOX_RC_OFF: +#endif + case ROCKBLOX_OFF: + return PLUGIN_OK; + + case ROCKBLOX_ROTATE_RIGHT: + case ROCKBLOX_ROTATE_RIGHT | BUTTON_REPEAT: +#ifdef SCROLL_WHEEL + /* if the wheel is disabled, add an event to the stack. */ + if(wheel_enabled == false) + wheel_events++; + + /* if it's enabled, go ahead and rotate.. */ + if(wheel_enabled) +#endif + move_block (0, 0, (co + 1) % figures[cf].max_or); + break; + + case ROCKBLOX_ROTATE_LEFT: + case ROCKBLOX_ROTATE_LEFT | BUTTON_REPEAT: +#ifdef SCROLL_WHEEL + if(wheel_enabled == false) + wheel_events++; + + if(wheel_enabled) +#endif + move_block (0, 0, + (co + figures[cf].max_or - + 1) % figures[cf].max_or); + break; + +#ifdef ROCKBLOX_ROTATE_RIGHT2 + case ROCKBLOX_ROTATE_RIGHT2: + move_block (0, 0, (co + 1) % figures[cf].max_or); + break; +#endif + + case ROCKBLOX_DOWN: + case ROCKBLOX_DOWN | BUTTON_REPEAT: + move_block (0, 1, co); + break; + + case ROCKBLOX_RIGHT: + case ROCKBLOX_RIGHT | BUTTON_REPEAT: + move_block (1, 0, co); + break; + + case ROCKBLOX_LEFT: + case ROCKBLOX_LEFT | BUTTON_REPEAT: + move_block (-1, 0, co); + break; + + case ROCKBLOX_DROP: +#ifdef ROCKBLOX_DROP_PRE + if (lastbutton != ROCKBLOX_DROP_PRE) + break; +#endif + while (canMoveTo (cx, cy + 1, co)) + move_block (0, 1, co); + break; +#ifdef ROCKBLOX_RESTART + case ROCKBLOX_RESTART: + rb->splash (HZ * 1, true, "Restarting..."); + init_rockblox (); + new_block (); + break; +#endif + + default: + if (rb->default_event_handler (button) == SYS_USB_CONNECTED) + return PLUGIN_USB_CONNECTED; + break; + } + if (button != BUTTON_NONE) + lastbutton = button; + +#ifdef SCROLL_WHEEL + /* check if we should enable the scroll wheel, if events + * begin to stack up... */ + if(wheel_enabled == false) + { + /* stopped rotating the wheel, reset the count */ + if(wheel_events == last_wheel_event) + { + last_wheel_event = 0; + wheel_events = 0; + } + /* rotated the wheel a while constantly, enable it. */ + else if(wheel_events > 3) + { + wheel_enabled = true; + } + + /* this evens out the last event and the "current" event. + * if we get an event next time through button reading, it will + * remain ahead of last_event. if we don't, they'll end up equaling + * each other.. thus, the scroll count will be reset. */ + if(wheel_enabled == false && wheel_events > last_wheel_event) + last_wheel_event++; + } +#endif + + if (TIME_AFTER(*rb->current_tick, next_down_tick)) { + move_down (); + next_down_tick += level_speed(level); + if (TIME_AFTER(*rb->current_tick, next_down_tick)) + /* restart time "raster" when we had to wait longer than usual + * (pause, game restart etc) */ + next_down_tick = *rb->current_tick + level_speed(level); + } + + if (gameover) { +#if LCD_DEPTH >= 2 + rb->lcd_set_foreground (LCD_BLACK); +#endif + rb->splash (HZ * 2, true, "Game Over"); + init_rockblox (); + new_block (); + } + + refresh_board (); + } + + return PLUGIN_OK; +} + +enum plugin_status plugin_start (struct plugin_api *api, void *parameter) +{ + int ret; + + (void) parameter; + rb = api; + + rb->srand (*rb->current_tick); + + rb->lcd_setfont (FONT_SYSFIXED); + /* Permanently enable the backlight (unless the user has turned it off) */ + if (rb->global_settings->backlight_timeout > 0) + rb->backlight_set_timeout (1); + + init_rockblox (); + ret = rockblox_loop (); + + /* Lets use the default font */ + rb->lcd_setfont (FONT_UI); + /* Restore user's original backlight setting */ + rb->backlight_set_timeout (rb->global_settings->backlight_timeout); + + return ret; +} + +#endif