Robert Hak's adjustments of Eric Linenberg's original Sokoban game, patched

by yours truly to work.

Put the levels.txt file (http://rockbox.haxx.se/levels.txt) in your
.rockbox/sokoban/ directory and play Sokoban like before, only using a
fraction of the memory!

Another upside of this fix, is the ability to design your own levels.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3740 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Daniel Stenberg 2003-06-10 22:31:02 +00:00
parent cd82560f2c
commit 0eaf4103f2
2 changed files with 188 additions and 1757 deletions

View file

@ -9,7 +9,7 @@
*
* Copyright (C) 2002 Eric Linenberg
* February 2003: Robert Hak performs a cleanup/rewrite/feature addition.
* Eric smiles. Bjorn cris. Linus say 'huh?'.
* Eric smiles. Bjorn cries. Linus say 'huh?'.
*
* 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.
@ -24,6 +24,8 @@
#ifdef USE_GAMES
#include <sprintf.h>
#include "ctype.h"
#include "sokoban.h"
#include "lcd.h"
#include "button.h"
@ -33,9 +35,6 @@
#include "font.h"
#include "file.h"
#include "debug.h"
#include "sokoban_levels.h"
#ifdef SIMULATOR
#include <stdio.h>
#endif
@ -45,20 +44,25 @@
#define SOKOBAN_TITLE "Sokoban"
#define SOKOBAN_TITLE_FONT 2
#define LEVELS_FILE "/sokoban.levels"
#define NUM_LEVELS sizeof(levels)/320
#define LEVELS_FILE "/.rockbox/sokoban/levels.txt"
#define ROWS 16
#define COLS 20
#define MAX_UNDOS 5
#define SOKOBAN_LEVEL_SIZE (ROWS*COLS)
static void init_undo(void);
static void undo(void);
static void add_undo(int button);
static int get_level(char *level, int level_size);
static int get_level_count(void);
static int load_level(void);
static void draw_level(void);
static void init_boards(void);
static void load_level(short level);
static void draw_level(short level);
static void update_screen(void);
static bool sokoban_loop(void);
@ -101,6 +105,9 @@ static struct BoardInfo {
char board[ROWS][COLS];
struct LevelInfo level;
struct Location player;
int max_level; /* How many levels do we have? */
int level_offset; /* Where in the level file is this level */
int loaded_level; /* Which level is in memory */
} current_info;
@ -239,34 +246,181 @@ static void init_boards(void)
current_info.player.row = 0;
current_info.player.col = 0;
current_info.player.spot = ' ';
current_info.max_level = 0;
current_info.level_offset = 0;
current_info.loaded_level = 0;
init_undo();
}
static void load_level(short level_to_load)
static int get_level_count(void)
{
short a = 0, b = 0, c = 0;
int i = 0;
int fd = 0;
int nread = 0;
char buffer[ROWS * COLS * 2];
if ((fd = open(LEVELS_FILE, O_RDONLY)) < 0) {
splash(0, 0, true, "Unable to open %s", LEVELS_FILE);
return -1;
}
do {
if ((nread = read(fd, buffer, sizeof(buffer))) < 0) {
splash(0, 0, true, "Reading %s failed.", LEVELS_FILE);
close(fd);
return -1;
}
for (i = 0; i < (nread - 1); i++) {
if (buffer[i] == '\n' && buffer[i+1] == '\n') {
while (isspace(buffer[i]))
i++;
current_info.max_level++;
}
}
if (buffer[i] == '\n' && buffer[i-1] != '\n')
lseek(fd, -1, SEEK_CUR);
} while (nread == sizeof(buffer));
close(fd);
return 0;
}
static int get_level(char *level, int level_size)
{
int fd = 0, i = 0;
int nread = 0;
int count = 0;
int offset = 0;
int level_ct = 0;
unsigned char buffer[SOKOBAN_LEVEL_SIZE * 2];
bool level_found = false;
int prevnewl=2; /* previous newlines in a row */
/* Lets not reparse the full file if we can avoid it */
if (current_info.loaded_level > current_info.level.level)
offset = 0;
/* open file */
if ((fd = open(LEVELS_FILE, O_RDONLY)) < 0)
return -1;
/* go where we left off */
offset = current_info.level_offset;
if(offset)
if (lseek(fd, offset, SEEK_SET) < 0) {
close(fd);
return -1;
}
while (!level_found) {
nread = read(fd, buffer, sizeof(buffer));
if (nread < SOKOBAN_LEVEL_SIZE) {
close(fd);
return -1;
}
/* we search for the first character that isn't a newline */
for (i = 0; i < nread; i++) {
/* skip and count all newlines */
while((buffer[i] == '\n') && (i < nread)) {
prevnewl++;
i++;
}
/* end of buffer? */
if(i == nread)
break;
/* start of new level? */
if((prevnewl>1) && (buffer[i] != '\n')) {
prevnewl=0; /* none now */
level_ct++;
if (level_ct == current_info.level.level) {
level_found = true;
offset += i;
break;
}
}
/* skip all non-newlines */
while((buffer[i] != '\n') && (i < nread))
i++;
}
if(!level_found)
offset += nread;
}
if (!level_found)
return -1;
/* now seek back to the exact start position */
lseek(fd, offset, SEEK_SET);
/* read a full buffer chunk from here */
nread = read(fd, buffer, sizeof(buffer)-1);
if (nread < 0)
return -1;
buffer[nread] = 0;
close(fd);
/* If we read less then a level, error */
if (nread < level_size)
return -1;
/* Load our new level */
for(i=0, count=0; (count < nread) && (i<level_size);) {
if (buffer[count] != '\n' && buffer[count] != '\r')
level[i++] = buffer[count];
count++;
}
level[i] = 0;
current_info.loaded_level = current_info.level.level;
return 0;
}
/* return non-zero on error */
static int load_level(void)
{
short c = 0;
short r = 0;
short i = 0;
char level[ROWS*COLS+1];
int x = 0;
current_info.player.spot=' ';
current_info.level.boxes_to_go = 0;
current_info.level.moves = 0;
for (b = 0; b < ROWS; b++) {
for (c = 0; c < COLS; c++) {
current_info.board[b][c] = levels[level_to_load][a];
a++;
if (get_level(level, sizeof(level)) != 0)
return -1;
if (current_info.board[b][c] == '@') {
current_info.player.row = b;
i = 0;
for (r = 0; r < ROWS; r++) {
x++;
for (c = 0; c < COLS; c++, i++) {
current_info.board[r][c] = level[i];
if (current_info.board[r][c] == '.')
current_info.level.boxes_to_go++;
else if (current_info.board[r][c] == '@') {
current_info.player.row = r;
current_info.player.col = c;
}
if (current_info.board[b][c] == '.')
current_info.level.boxes_to_go++;
}
}
return;
return 0;
}
static void update_screen(void)
@ -326,7 +480,7 @@ static void update_screen(void)
}
snprintf(s, sizeof(s), "%d", current_info.level.level+1);
snprintf(s, sizeof(s), "%d", current_info.level.level);
lcd_putsxy(86, 22, s);
snprintf(s, sizeof(s), "%d", current_info.level.moves);
lcd_putsxy(86, 54, s);
@ -340,9 +494,9 @@ static void update_screen(void)
lcd_update();
}
static void draw_level(short level)
static void draw_level(void)
{
load_level(level);
load_level();
lcd_clear_display();
update_screen();
}
@ -354,9 +508,9 @@ static bool sokoban_loop(void)
int i = 0, button = 0;
short r = 0, c = 0;
current_info.level.level = 0;
current_info.level.level = 1;
load_level(current_info.level.level);
load_level();
update_screen();
while (1) {
@ -396,10 +550,10 @@ static bool sokoban_loop(void)
case BUTTON_F1 | BUTTON_REPEAT:
/* previous level */
init_undo();
if (current_info.level.level)
if (current_info.level.level > 1)
current_info.level.level--;
draw_level(current_info.level.level);
draw_level();
moved = false;
break;
@ -407,7 +561,7 @@ static bool sokoban_loop(void)
case BUTTON_F2 | BUTTON_REPEAT:
/* same level */
init_undo();
draw_level(current_info.level.level);
draw_level();
moved = false;
break;
@ -697,7 +851,7 @@ static bool sokoban_loop(void)
lcd_clear_display();
if (current_info.level.level == NUM_LEVELS) {
if (current_info.level.level == current_info.max_level) {
lcd_putsxy(10, 20, str(LANG_SOKOBAN_WIN));
for (i = 0; i < 30000 ; i++) {
@ -711,7 +865,7 @@ static bool sokoban_loop(void)
return false;
}
load_level(current_info.level.level);
load_level();
update_screen();
}
@ -762,6 +916,10 @@ bool sokoban(void)
lcd_clear_display();
init_boards();
if (get_level_count() != 0)
return false;
result = sokoban_loop();
lcd_setfont(FONT_UI);
@ -770,7 +928,3 @@ bool sokoban(void)
}
#endif

File diff suppressed because it is too large Load diff