From 020ab8f01ee369a1955d891e500edfbf22219b49 Mon Sep 17 00:00:00 2001 From: Björn Stenberg Date: Sun, 29 Jun 2003 21:10:27 +0000 Subject: Frederic Dang Ngoc's 'Star' game. Very nice graphic effects. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3777 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/star.c | 786 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 786 insertions(+) create mode 100644 apps/plugins/star.c diff --git a/apps/plugins/star.c b/apps/plugins/star.c new file mode 100644 index 0000000000..961c17f143 --- /dev/null +++ b/apps/plugins/star.c @@ -0,0 +1,786 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 Frederic Dang Ngoc + * + * 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" +#ifdef HAVE_LCD_BITMAP + +/* file which contains the levels */ +#define STAR_LEVELS_FILE "/.rockbox/star/levels.txt" + +/* title of the game */ +#define STAR_TITLE "Star" + +/* font used to display title */ +#define STAR_TITLE_FONT 2 + +/* size of a level in file */ +#define STAR_LEVEL_SIZE ((STAR_WIDTH + 1) * STAR_HEIGHT + 1) + +/* size of the game board */ +#define STAR_WIDTH 16 +#define STAR_HEIGHT 9 + +/* left and top margin */ +#define STAR_OFFSET_X 8 +#define STAR_OFFSET_Y 0 + +/* number of level */ +#define STAR_LEVEL_COUNT 20 + +/* size of a tile */ +#define STAR_TILE_SIZE 6 + +/* values of object in the board */ +#define STAR_VOID '.' +#define STAR_WALL '*' +#define STAR_STAR 'o' +#define STAR_BALL 'X' +#define STAR_BLOCK 'x' + +/* sleep time between two frames */ +#define STAR_SLEEP 1 + +/* value of ball and block control */ +#define STAR_CONTROL_BALL 0 +#define STAR_CONTROL_BLOCK 1 + +/* position of the ball */ +static int ball_x, ball_y; + +/* position of the block */ +static int block_x, block_y; + +/* number of stars to get to finish the level */ +static int star_count; + +/* the object we control : ball or block */ +static int control; + +/* the current board */ +static char board[STAR_HEIGHT][STAR_WIDTH]; + +/* bitmap of the wall */ +static unsigned char wall_bmp[STAR_TILE_SIZE] + = {0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55}; + +/* bitmap of the star */ +static unsigned char star_bmp[STAR_TILE_SIZE] + = {0x00, 0x0c, 0x12, 0x12, 0x0c, 0x00}; + +/* bitmap of the ball */ +static unsigned char ball_bmp[STAR_TILE_SIZE] + = {0x00, 0x0c, 0x1e, 0x1a, 0x0c, 0x00}; + +/* bitmap of the block */ +static unsigned char block_bmp[STAR_TILE_SIZE] + = {0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x00}; + +/* bitmap of the arrow animation */ +static unsigned char arrow_bmp[4][7] = + { + {0x7f, 0x7f, 0x3e, 0x3e, 0x1c, 0x1c, 0x08}, + {0x3e, 0x3e, 0x1c, 0x1c, 0x08, 0x08, 0x08}, + {0x1c, 0x1c, 0x1c, 0x1c, 0x08, 0x08, 0x08}, + {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08} + }; + +/* sequence of the bitmap arrow to follow to do one turn */ +static unsigned char anim_arrow[8] = {0, 1, 2, 3, 2, 1, 0}; + +/* current_level */ +static int current_level = 0; + +/* char font size */ +static int char_width = -1; +static int char_height = -1; + +static struct plugin_api* rb; + +/* this arrays contains a group of levels loaded into memory */ +static unsigned char* levels = +"****************\n" +"*X**........o*x*\n" +"*..........o.***\n" +"*.......**o....*\n" +"*...**.o......**\n" +"**.o..o.....o..*\n" +"*.o......o**.o.*\n" +"*.....**o.....o*\n" +"****************\n" +"\n" +".*..*.*.*...*.**\n" +"*...o.........X*\n" +"...*o..*o...o...\n" +"*.*.o.....o..*.*\n" +"......*...o...*.\n" +"*....*x*..o....*\n" +"...*..*.*...*oo*\n" +"*.............*.\n" +".*..*........*..\n" +"\n" +"****************\n" +"*...........o*x*\n" +"*...**......**X*\n" +"*...*o.........*\n" +"*.o.....o**...o*\n" +"*.*o..o..o*..o**\n" +"*.**o.*o..o.o***\n" +"*o....**o......*\n" +"****************\n" +"\n" +"****************\n" +"*............*x*\n" +"*.....*........*\n" +"**o*o.o*o*o*o*o*\n" +"*.*.*o.o*.*.*.**\n" +"**o*o*o.o*o*o*o*\n" +"*.....*........*\n" +"*...*.......*X.*\n" +"****************\n" +"\n" +".**************.\n" +"*X..*...*..*...*\n" +"*..*o.*.o..o.*.*\n" +"**......*..*...*\n" +"*o.*o*........**\n" +"**.....*.o.*...*\n" +"*o*..*.*.*...*x*\n" +"*...*....o*..*o*\n" +".**************.\n" +"\n" +"....************\n" +"...*...o...*o.o*\n" +"..*....o....*.**\n" +".*.....o.......*\n" +"*X.....o.......*\n" +"**.....o..*...**\n" +"*......o....*..*\n" +"*x.*...o..**o..*\n" +"****************\n" +"\n" +"****************\n" +"*..............*\n" +".**.***..*o.**o*\n" +".*o..*o.*.*.*.*.\n" +"..*..*..***.**..\n" +".**..*..*o*.*o**\n" +"*..............*\n" +"*..X*o....x..*o*\n" +"****************\n" +"\n" +"***************.\n" +"*..o**.........*\n" +"*..*o..**.o....*\n" +"*..o**.*.*o....*\n" +"**.....**..*o*.*\n" +"**.*.......o*o.*\n" +"*oxo*...o..*X*.*\n" +"**.............*\n" +".***************\n" +"\n" +"..*.***********.\n" +".*o*o......*..X*\n" +"*o.o*....o....*.\n" +".*.*..o**..o*..*\n" +"*..*o.*oxo....o*\n" +"*.....o**.....*.\n" +"*o*o.........*..\n" +"*...........*...\n" +".***********....\n" +"\n" +"....***********.\n" +"*****.o........*\n" +"*...x.***o.o*.o*\n" +"*.o...*o.*o...*.\n" +"*.....*..o..*.o*\n" +"*o*o..*.o*..*X*.\n" +".*o...***..***..\n" +"*.........*.*.*.\n" +".*********..*..*\n" +"\n" +"****************\n" +"*......*......X*\n" +"*..*oo.....oo.**\n" +"**...o...**...o*\n" +"*o....*o*oo..***\n" +"**.**....**....*\n" +"*o..o*.o....x.o*\n" +"**o***....*...**\n" +"***************.\n" +"\n" +"**.....**..****.\n" +"*X*****o.***.o**\n" +"*....oo.....o..*\n" +"*.**..**o..*o*.*\n" +"*.*.o.*.*o.**..*\n" +"*.**..**...*x*.*\n" +"*.....o........*\n" +"*........o.....*\n" +"****************\n" +"\n" +".**************.\n" +"*.X*........o.**\n" +"*.*...*o...o**.*\n" +"*.......o....*.*\n" +"*.o..........*o*\n" +"*.*......o.....*\n" +"**......o.o..*o*\n" +"*x..*....o.*.*.*\n" +".**************.\n" +"\n" +"****************\n" +"*o*o........o*o*\n" +"*.o*X......**..*\n" +"*.x........o...*\n" +"*........o*....*\n" +"*......o.......*\n" +"*.o*........*..*\n" +"*o*o........o*o*\n" +"****************\n" +"\n" +".******.********\n" +"*.....o*.....o.*\n" +"*.*.o.*..*...o.*\n" +"*..X*...*oo.*o.*\n" +".*.*...*.o..x*.*\n" +"*o.......*..*o.*\n" +".*......o.....*.\n" +"*o............o*\n" +"****************\n" +"\n" +"****************\n" +"**.x*o.o......o*\n" +"*o.Xo*o.......**\n" +"**.***........**\n" +"**.....o*o*....*\n" +"*oo.......o*o..*\n" +"**.o....****o..*\n" +"**o*..*........*\n" +"****************\n" +"\n" +"****************\n" +"*.o*........*X.*\n" +"*.*..o*oo*o..*.*\n" +"*....*o**o*.o..*\n" +"*.o*.......o*..*\n" +"*..o*o....o*...*\n" +"*.*..*.**o*..*.*\n" +"*....o.*o...x..*\n" +"****************\n" +"\n" +"****************\n" +"*.o....o..x*...*\n" +"*..*o*o...*o...*\n" +"*...*o*....*o..*\n" +"*...o..*...o*o.*\n" +"*.*o*...*.o*...*\n" +"*.o*o.*.o.*....*\n" +"*o*X..*.....*..*\n" +"****************\n" +"\n" +"****************\n" +"*o...**.....**o*\n" +"*.*..*......*o.*\n" +"*.o*...o**..o..*\n" +"*.*....*o......*\n" +"*....*...o*....*\n" +"*.**.o*.**o..*x*\n" +"*.o*.*o.....**X*\n" +"****************\n" +"\n" +"****************\n" +"*...o*o........*\n" +"**o..o*.**o...**\n" +"*.*.*.o...*..*.*\n" +"*.x.*..**..*.Xo*\n" +"*.*..*...o.*.*.*\n" +"**...o**.*o..o**\n" +"*........o*o...*\n" +"****************"; + +/** + * Display text. + */ +static void star_display_text(char *str, bool waitkey) +{ + int chars_by_line; + int lines_by_screen; + int chars_for_line; + int current_line = 0; + int first_char_index = 0; + char *ptr_char; + char *ptr_line; + int i; + char line[255]; + int key; + + rb->lcd_clear_display(); + + chars_by_line = LCD_WIDTH / char_width; + lines_by_screen = LCD_HEIGHT / char_height; + + do + { + ptr_char = str + first_char_index; + chars_for_line = 0; + i = 0; + ptr_line = line; + while (i < chars_by_line) + { + switch (*ptr_char) + { + case '\t': + case ' ': + *(ptr_line++) = ' '; + case '\n': + case '\0': + chars_for_line = i; + break; + + default: + *(ptr_line++) = *ptr_char; + } + if (*ptr_char == '\n' || *ptr_char == '\0') + break; + ptr_char++; + i++; + } + + if (chars_for_line == 0) + chars_for_line = i; + + line[chars_for_line] = '\0'; + + // test if we have cutted a word. If it is the case we don't have to + // skip the space + if (i == chars_by_line && chars_for_line == chars_by_line) + first_char_index += chars_for_line; + else + first_char_index += chars_for_line + 1; + + // print the line on the screen + rb->lcd_putsxy(0, current_line * char_height, line); + + // if the number of line showed on the screen is equals to the + // maximum number of line we can show, we wait for a key pressed to + // clear and show the remaining text. + current_line++; + if (current_line == lines_by_screen || *ptr_char == '\0') + { + current_line = 0; + rb->lcd_update(); + if (waitkey) + while ((key = rb->button_get(true)) != BUTTON_PLAY + && key != BUTTON_ON + && key != BUTTON_DOWN); + rb->lcd_clear_display(); + } + } while (*ptr_char != '\0'); +} + +/** + * Do a pretty transition from one level to another. + */ +static void star_transition_update(void) +{ + int center_x = LCD_WIDTH / 2; + int lcd_demi_width = LCD_WIDTH / 2; + int center_y = LCD_HEIGHT / 2; + int x; + int y = 0; + int var_y = 0; + + for (x = 0 ; x < lcd_demi_width ; x++) + { + var_y += LCD_HEIGHT; + if (var_y > LCD_WIDTH) + { + var_y -= LCD_WIDTH; + y++; + } + rb->lcd_update_rect(center_x - x, center_y - y, + x * 2, y * 2); + rb->sleep(STAR_SLEEP); + } + rb->lcd_update(); +} + +/** + * Display information board of the current level. + */ +static void star_display_board_info(void) +{ + int label_offset_y = label_offset_y = LCD_HEIGHT - char_height; + char str_info[32]; + + rb->snprintf(str_info, sizeof(str_info), "L:%02d S:%02d C:", + current_level, star_count); + rb->lcd_putsxy(0, label_offset_y, str_info); + + if (control == STAR_CONTROL_BALL) + rb->lcd_bitmap (ball_bmp, 103, label_offset_y + 1, STAR_TILE_SIZE, + STAR_TILE_SIZE, true); + else + rb->lcd_bitmap (block_bmp, 103, label_offset_y + 1, STAR_TILE_SIZE, + STAR_TILE_SIZE, true); + + rb->lcd_update_rect(0, label_offset_y, LCD_WIDTH, char_height); +} + + +/** + * Load a level into board array. + */ +static int star_load_level(int current_level) +{ + int x, y; + char *ptr_tab; + + ptr_tab = levels + current_level * STAR_LEVEL_SIZE; + control = STAR_CONTROL_BALL; + star_count = 0; + + rb->lcd_clear_display(); + + for (y = 0 ; y < STAR_HEIGHT ; y++) + { + for (x = 0 ; x < STAR_WIDTH ; x++) + { + board[y][x] = *ptr_tab; + switch (*ptr_tab) + { + case STAR_VOID: + break; + + case STAR_WALL: + rb->lcd_bitmap (wall_bmp, + STAR_OFFSET_X + x * STAR_TILE_SIZE, + STAR_OFFSET_Y + y * STAR_TILE_SIZE, + STAR_TILE_SIZE, STAR_TILE_SIZE, false); + break; + + case STAR_STAR: + rb->lcd_bitmap (star_bmp, + STAR_OFFSET_X + x * STAR_TILE_SIZE, + STAR_OFFSET_Y + y * STAR_TILE_SIZE, + STAR_TILE_SIZE, STAR_TILE_SIZE, false); + star_count++; + break; + + case STAR_BALL: + ball_x = x; + ball_y = y; + rb->lcd_bitmap (ball_bmp, + STAR_OFFSET_X + x * STAR_TILE_SIZE, + STAR_OFFSET_Y + y * STAR_TILE_SIZE, + STAR_TILE_SIZE, STAR_TILE_SIZE, false); + break; + + + case STAR_BLOCK: + block_x = x; + block_y = y; + rb->lcd_bitmap (block_bmp, + STAR_OFFSET_X + x * STAR_TILE_SIZE, + STAR_OFFSET_Y + y * STAR_TILE_SIZE, + STAR_TILE_SIZE, STAR_TILE_SIZE, false); + break; + } + ptr_tab++; + } + ptr_tab++; + } + star_display_board_info(); + star_transition_update(); + return 1; +} + +/** + * Run the game. + */ +static int star_run_game(void) +{ + int move_x = 0; + int move_y = 0; + int i; + + int label_offset_y; + + label_offset_y = LCD_HEIGHT - char_height; + + if (!star_load_level(current_level)) + return 0; + + while (true) + { + move_x = 0; + move_y = 0; + + switch (rb->button_get(true)) + { + case BUTTON_OFF: + return PLUGIN_OK; + + case BUTTON_LEFT: + move_x = -1; + break; + + case BUTTON_RIGHT: + move_x = 1; + break; + + case BUTTON_UP: + move_y = -1; + break; + + case BUTTON_DOWN: + move_y = 1; + break; + + case BUTTON_F1: + if (current_level > 0) + { + current_level--; + star_load_level(current_level); + } + continue; + + case BUTTON_F2: + star_load_level(current_level); + continue; + + case BUTTON_F3: + if (current_level < STAR_LEVEL_COUNT - 1) + { + current_level++; + star_load_level(current_level); + } + continue; + + case BUTTON_PLAY: + case BUTTON_ON: + if (control == STAR_CONTROL_BALL) + control = STAR_CONTROL_BLOCK; + else + control = STAR_CONTROL_BALL; + star_display_board_info(); + continue; + + default: + continue; + } + + if (control == STAR_CONTROL_BALL) + { + board[ball_y][ball_x] = STAR_VOID; + while ((board[ball_y + move_y][ball_x + move_x] == STAR_VOID + || board[ball_y + move_y][ball_x + move_x] == STAR_STAR)) + + { + for (i = 0 ; i < 7 ; i++) + { + rb->lcd_bitmap( + ball_bmp, + STAR_OFFSET_X + ball_x * STAR_TILE_SIZE + move_x * i, + STAR_OFFSET_Y + ball_y * STAR_TILE_SIZE + move_y * i, + STAR_TILE_SIZE, STAR_TILE_SIZE, true); + + rb->lcd_update_rect( + STAR_OFFSET_X + ball_x * STAR_TILE_SIZE + move_x * i, + STAR_OFFSET_Y + ball_y * STAR_TILE_SIZE + move_y * i, + STAR_TILE_SIZE, STAR_TILE_SIZE); + rb->sleep(STAR_SLEEP); + } + ball_x += move_x; + ball_y += move_y; + + if (board[ball_y][ball_x] == STAR_STAR) + { + board[ball_y][ball_x] = STAR_VOID; + star_count--; + + star_display_board_info(); + } + } + board[ball_y][ball_x] = STAR_BALL; + } + else + { + board[block_y][block_x] = STAR_VOID; + while (board[block_y + move_y][block_x + move_x] == STAR_VOID) + { + for (i = 0 ; i < 7 ; i++) + { + rb->lcd_bitmap( + block_bmp, + STAR_OFFSET_X + block_x * STAR_TILE_SIZE + move_x * i, + STAR_OFFSET_Y + block_y * STAR_TILE_SIZE + move_y * i, + STAR_TILE_SIZE, STAR_TILE_SIZE, true); + + rb->lcd_update_rect( + STAR_OFFSET_X + block_x * STAR_TILE_SIZE + move_x * i, + STAR_OFFSET_Y + block_y * STAR_TILE_SIZE + move_y * i, + STAR_TILE_SIZE, STAR_TILE_SIZE); + + rb->sleep(STAR_SLEEP); + } + block_x += move_x; + block_y += move_y; + } + board[block_y][block_x] = STAR_BLOCK; + } + + if (star_count == 0) + { + current_level++; + if (current_level == STAR_LEVEL_COUNT) + { + rb->lcd_clear_display(); + star_display_text("Congratulation !", true); + rb->lcd_update(); + return 1; + } + star_load_level(current_level); + } + } +} + +/** + * Display the choice menu. + */ +static int star_menu(void) +{ + int move_y; + int menu_y = 0; + int i = 0; + bool refresh = true; + char anim_state = 0; + unsigned char *menu[4] = {"Start", "Information", "Keys", "Exit"}; + int menu_count = sizeof(menu) / sizeof(unsigned char *); + int menu_offset_y; + + menu_offset_y = LCD_HEIGHT - char_height * menu_count; + + while (true) + { + if (refresh) + { + rb->lcd_clear_display(); + rb->lcd_putsxy((LCD_WIDTH - char_width * + rb->strlen(STAR_TITLE)) / 2, + 0, STAR_TITLE); + for (i = 0 ; i < menu_count ; i++) + { + rb->lcd_putsxy(15, menu_offset_y + char_height * i, menu[i]); + } + + rb->lcd_update(); + refresh = false; + } + + move_y = 0; + rb->lcd_bitmap(arrow_bmp[anim_arrow[(anim_state & 0x38) >> 3]], + 2, menu_offset_y + menu_y * char_height, 7, 8, true); + rb->lcd_update_rect (2, menu_offset_y + menu_y * 8, 8, 8); + rb->sleep(STAR_SLEEP); + anim_state++; + + switch (rb->button_get(false)) + { + case BUTTON_OFF: + return PLUGIN_OK; + case BUTTON_UP: + if (menu_y > 0) + move_y = -1; + break; + case BUTTON_DOWN: + if (menu_y < 3) + move_y = 1; + break; + + case BUTTON_ON: + case BUTTON_PLAY: + case BUTTON_RIGHT: + refresh = true; + switch (menu_y) + { + case 0: + if (!star_run_game()) + return PLUGIN_OK; + break; + case 1: + star_display_text( + "INFO\n\n" + "Take all \"o\" to go to the next level. " + "You can toggle control with the block to " + "use it as a mobile wall. The block cannot " + "take \"o\".", true); + break; + case 2: + star_display_text("KEYS\n\n" + "[ON] Toggle Ctl.\n" + "[OFF] Exit\n" + "[F1] Prev. level\n" + "[F2] Reset level\n" + "[F3] Next level", true); + break; + case 3: + return PLUGIN_OK; + } + break; + + case SYS_USB_CONNECTED: + rb->usb_screen(); + return PLUGIN_USB_CONNECTED; + + default: + continue; + } + + for (i = 0 ; i < char_height ; i++) + { + rb->lcd_clearrect (2, 30, 7, 4 * 8); + rb->lcd_bitmap(arrow_bmp[anim_arrow[(anim_state & 0x38) >> 3]], + 2, menu_offset_y + menu_y * 8 + move_y * i, 7, 8, + false); + rb->lcd_update_rect(2, 30, 8, 4 * 8); + anim_state++; + rb->sleep(STAR_SLEEP); + } + menu_y += move_y; + } +} + +/** + * Main entry point + */ +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) +{ + TEST_PLUGIN_API(api); + (void)parameter; + rb = api; + + /* get the size of char */ + if (char_width == -1) + rb->lcd_getstringsize("a", &char_width, &char_height); + + /* display choice menu */ + return star_menu(); +} + +#endif -- cgit v1.2.3