/*************************************************************************** * __________ __ ___. * 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 "config.h" #include "options.h" #ifdef USE_GAMES #include #include #include "star.h" #include "lcd.h" #include "button.h" #include "kernel.h" #include "menu.h" #ifdef SIMULATOR #include #endif #include /* file which contains the levels */ #define STAR_LEVELS_FILE "/star_levels.txt" /* title of the game */ #define STAR_TITLE "Star" /* font used to display title */ #define STAR_TITLE_FONT 2 /* 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 /* this arrays contains all the levels */ static unsigned char levels[STAR_LEVEL_COUNT][144]; /* 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}; /* if the levels has already been loaded into memory */ static bool levels_loaded = false; /** * Display the text centered at position y */ static void star_center_putsy(int y, char *string) { int width, height; lcd_getstringsize(string, &width, &height); lcd_putsxy((LCD_WIDTH - width) / 2, y, string); } /** * Do a pretty transition from one level to another. */ static void star_transition_update() { 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++; } lcd_update_rect(center_x - x, center_y - y, x * 2, y * 2); sleep(STAR_SLEEP); } lcd_update(); } /** * Load all levels from file into memory. */ static int star_load_all_levels(void) { unsigned char buf[4096]; int y,x,l; int fd; int nbyte; unsigned char *ptr_buf; unsigned char *ptr_level; levels_loaded = true; fd = open(STAR_LEVELS_FILE, O_RDONLY); if (fd == -1) { lcd_putsxy(0, 0, "Levels file"); lcd_putsxy(0, 12, STAR_LEVELS_FILE); lcd_putsxy(0, 24, "not found !"); lcd_update(); sleep(HZ * 5); return 0; } nbyte = read(fd, buf, 4096); ptr_buf = buf; for (l = 0 ; l < STAR_LEVEL_COUNT ; l++) { ptr_level = levels[l]; for (y = 0 ; y < STAR_HEIGHT ; y++) { for (x = 0 ; x < STAR_WIDTH ; x++) { *(ptr_level++) = *(ptr_buf++); } ptr_buf++; } ptr_buf++; } close(fd); return 1; } /** * Convert a 2 decimal integer into a string. */ static void int_to_str2(int nb, char *str) { str[0] = nb / 10 + '0'; str[1] = nb % 10 + '0'; str[2] = '\0'; } /** * Load a level into board array. */ static void star_load_level(int current_level) { int x, y; char str_tmp[3]; char *ptr = levels[current_level]; control = STAR_CONTROL_BALL; star_count = 0; lcd_clear_display(); for (y = 0 ; y < STAR_HEIGHT ; y++) { for (x = 0 ; x < STAR_WIDTH ; x++) { board[y][x] = *ptr; switch (*ptr) { case STAR_VOID: break; case STAR_WALL: 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: 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; 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; 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++; } } lcd_putsxy(0,56, "L:"); int_to_str2(current_level, str_tmp); lcd_putsxy(15,56, str_tmp); lcd_bitmap(star_bmp, 45, 57, STAR_TILE_SIZE, STAR_TILE_SIZE, true); lcd_putsxy(50,56, ":"); int_to_str2(star_count, str_tmp); lcd_putsxy(60,56, str_tmp); lcd_putsxy(90,56, "C:"); lcd_bitmap (ball_bmp, 105, 57, STAR_TILE_SIZE, STAR_TILE_SIZE, true); star_transition_update(); } /** * Run the game. */ static void star_run_game(void) { int current_level = 0; int move_x = 0; int move_y = 0; int i; char str_tmp[3]; star_load_level(current_level); while (1) { move_x = 0; move_y = 0; switch (button_get(true)) { case BUTTON_OFF: return; 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) { lcd_bitmap (block_bmp, 105, 57, STAR_TILE_SIZE, STAR_TILE_SIZE, true); control = STAR_CONTROL_BLOCK; } else { lcd_bitmap (ball_bmp, 105, 57, STAR_TILE_SIZE, STAR_TILE_SIZE, true); control = STAR_CONTROL_BALL; } lcd_update_rect (105, 57, STAR_TILE_SIZE, STAR_TILE_SIZE); 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++) { 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); 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); 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--; int_to_str2(star_count, str_tmp); lcd_putsxy(60,56, str_tmp); lcd_update_rect (60, 56, 30, 8); } } 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++) { 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); 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); 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) { lcd_clear_display(); star_center_putsy(20, "Congratulation !"); lcd_update(); sleep(HZ * 3); return; } star_load_level(current_level); } } } /** * Display keys informations. */ static void star_display_keys(void) { int key; lcd_clear_display(); star_center_putsy(1, "KEYS"); lcd_putsxy(5, 22, "[ON] Toggle Ctl."); lcd_putsxy(5, 30, "[OFF] Exit"); lcd_putsxy(5, 38, "[F1] Prev. level"); lcd_putsxy(5, 46, "[F2] Reset level"); lcd_putsxy(5, 54, "[F3] Next level"); lcd_update(); while ((key = button_get(true)) != BUTTON_PLAY && key != BUTTON_ON); } /** * Display informations about the game. */ static void star_display_info(void) { int key; lcd_clear_display(); star_center_putsy(1, "INFO"); lcd_putsxy(5, 22, "Take all \"o\" "); lcd_putsxy(5, 30, "to go to the"); lcd_putsxy(5, 38, "next level."); lcd_putsxy(5, 46, "You can toggle"); lcd_putsxy(5, 54, "control with the"); lcd_update(); while ((key = button_get(true)) != BUTTON_PLAY && key != BUTTON_ON); lcd_clear_display(); star_center_putsy(1, "INFO"); lcd_putsxy(5, 22, "block to use it"); lcd_putsxy(5, 30, "as a mobile wall."); lcd_putsxy(5, 38, "The block cannot"); lcd_putsxy(5, 46, "take \"o\"."); lcd_update(); while ((key = button_get(true)) != BUTTON_PLAY && key != BUTTON_ON); } /** * Display the choice menu. */ static void star_menu(void) { int move_y; int menu_y = 0; int i; bool refresh = true; char anim_state = 0; while (true) { move_y = 0; if (refresh) { lcd_clear_display(); star_center_putsy(1, STAR_TITLE); lcd_putsxy(15, 30, "Start"); lcd_putsxy(15, 38, "Information"); lcd_putsxy(15, 46, "Keys"); lcd_putsxy(15, 54, "Exit"); lcd_update(); refresh = false; } lcd_bitmap(arrow_bmp[anim_arrow[(anim_state & 0x38) >> 3]], 2, 30 + menu_y * 8, 7, 8, true); lcd_update_rect (2, 30 + menu_y * 8 + move_y * i, 8, 8); sleep(STAR_SLEEP); anim_state++; switch (button_get(false)) { case BUTTON_OFF: return; 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: refresh = true; switch (menu_y) { case 0: star_run_game(); break; case 1: star_display_info(); break; case 2: star_display_keys(); break; case 3: return; } break; default: continue; } for (i = 0 ; i < 8 ; i++) { lcd_clearrect (2, 30, 7, 4 * 8); lcd_bitmap(arrow_bmp[anim_arrow[(anim_state & 0x38) >> 3]], 2, 30 + menu_y * 8 + move_y * i, 7, 8, false); lcd_update_rect(2, 30, 8, 4 * 8); anim_state++; sleep(STAR_SLEEP); } menu_y += move_y; } } /** * Main entry point from the menu to start the game control. */ bool star(void) { // if levels are already loaded, no need to reload them. if (!levels_loaded) { lcd_clear_display(); star_center_putsy(20, "Loading levels..."); lcd_update(); if (!star_load_all_levels()) return false; } // display choice menu. star_menu(); return true; } #endif /* USE_GAMES */