summaryrefslogtreecommitdiff
path: root/apps/recorder/sokoban.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/recorder/sokoban.c')
-rw-r--r--apps/recorder/sokoban.c222
1 files changed, 188 insertions, 34 deletions
diff --git a/apps/recorder/sokoban.c b/apps/recorder/sokoban.c
index c39320fd3a..faf868044c 100644
--- a/apps/recorder/sokoban.c
+++ b/apps/recorder/sokoban.c
@@ -9,7 +9,7 @@
9 * 9 *
10 * Copyright (C) 2002 Eric Linenberg 10 * Copyright (C) 2002 Eric Linenberg
11 * February 2003: Robert Hak performs a cleanup/rewrite/feature addition. 11 * February 2003: Robert Hak performs a cleanup/rewrite/feature addition.
12 * Eric smiles. Bjorn cris. Linus say 'huh?'. 12 * Eric smiles. Bjorn cries. Linus say 'huh?'.
13 * 13 *
14 * All files in this archive are subject to the GNU General Public License. 14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement. 15 * See the file COPYING in the source tree root for full license agreement.
@@ -24,6 +24,8 @@
24 24
25#ifdef USE_GAMES 25#ifdef USE_GAMES
26 26
27#include <sprintf.h>
28#include "ctype.h"
27#include "sokoban.h" 29#include "sokoban.h"
28#include "lcd.h" 30#include "lcd.h"
29#include "button.h" 31#include "button.h"
@@ -33,9 +35,6 @@
33#include "font.h" 35#include "font.h"
34#include "file.h" 36#include "file.h"
35 37
36#include "debug.h"
37#include "sokoban_levels.h"
38
39#ifdef SIMULATOR 38#ifdef SIMULATOR
40#include <stdio.h> 39#include <stdio.h>
41#endif 40#endif
@@ -45,20 +44,25 @@
45 44
46#define SOKOBAN_TITLE "Sokoban" 45#define SOKOBAN_TITLE "Sokoban"
47#define SOKOBAN_TITLE_FONT 2 46#define SOKOBAN_TITLE_FONT 2
48#define LEVELS_FILE "/sokoban.levels" 47
49#define NUM_LEVELS sizeof(levels)/320 48#define LEVELS_FILE "/.rockbox/sokoban/levels.txt"
50 49
51#define ROWS 16 50#define ROWS 16
52#define COLS 20 51#define COLS 20
53#define MAX_UNDOS 5 52#define MAX_UNDOS 5
54 53
54#define SOKOBAN_LEVEL_SIZE (ROWS*COLS)
55
55static void init_undo(void); 56static void init_undo(void);
56static void undo(void); 57static void undo(void);
57static void add_undo(int button); 58static void add_undo(int button);
58 59
60static int get_level(char *level, int level_size);
61static int get_level_count(void);
62static int load_level(void);
63static void draw_level(void);
64
59static void init_boards(void); 65static void init_boards(void);
60static void load_level(short level);
61static void draw_level(short level);
62static void update_screen(void); 66static void update_screen(void);
63static bool sokoban_loop(void); 67static bool sokoban_loop(void);
64 68
@@ -101,6 +105,9 @@ static struct BoardInfo {
101 char board[ROWS][COLS]; 105 char board[ROWS][COLS];
102 struct LevelInfo level; 106 struct LevelInfo level;
103 struct Location player; 107 struct Location player;
108 int max_level; /* How many levels do we have? */
109 int level_offset; /* Where in the level file is this level */
110 int loaded_level; /* Which level is in memory */
104} current_info; 111} current_info;
105 112
106 113
@@ -239,34 +246,181 @@ static void init_boards(void)
239 current_info.player.row = 0; 246 current_info.player.row = 0;
240 current_info.player.col = 0; 247 current_info.player.col = 0;
241 current_info.player.spot = ' '; 248 current_info.player.spot = ' ';
249 current_info.max_level = 0;
250 current_info.level_offset = 0;
251 current_info.loaded_level = 0;
242 252
243 init_undo(); 253 init_undo();
244} 254}
245 255
246static void load_level(short level_to_load) 256static int get_level_count(void)
257{
258 int i = 0;
259 int fd = 0;
260 int nread = 0;
261 char buffer[ROWS * COLS * 2];
262
263 if ((fd = open(LEVELS_FILE, O_RDONLY)) < 0) {
264 splash(0, 0, true, "Unable to open %s", LEVELS_FILE);
265 return -1;
266 }
267
268 do {
269 if ((nread = read(fd, buffer, sizeof(buffer))) < 0) {
270 splash(0, 0, true, "Reading %s failed.", LEVELS_FILE);
271 close(fd);
272 return -1;
273 }
274
275 for (i = 0; i < (nread - 1); i++) {
276 if (buffer[i] == '\n' && buffer[i+1] == '\n') {
277
278 while (isspace(buffer[i]))
279 i++;
280
281 current_info.max_level++;
282 }
283 }
284
285 if (buffer[i] == '\n' && buffer[i-1] != '\n')
286 lseek(fd, -1, SEEK_CUR);
287
288 } while (nread == sizeof(buffer));
289
290 close(fd);
291
292 return 0;
293}
294
295static int get_level(char *level, int level_size)
247{ 296{
248 short a = 0, b = 0, c = 0; 297 int fd = 0, i = 0;
298 int nread = 0;
299 int count = 0;
300 int offset = 0;
301 int level_ct = 0;
302 unsigned char buffer[SOKOBAN_LEVEL_SIZE * 2];
303 bool level_found = false;
304 int prevnewl=2; /* previous newlines in a row */
305
306 /* Lets not reparse the full file if we can avoid it */
307 if (current_info.loaded_level > current_info.level.level)
308 offset = 0;
309
310 /* open file */
311 if ((fd = open(LEVELS_FILE, O_RDONLY)) < 0)
312 return -1;
313
314 /* go where we left off */
315 offset = current_info.level_offset;
316 if(offset)
317 if (lseek(fd, offset, SEEK_SET) < 0) {
318 close(fd);
319 return -1;
320 }
321
322 while (!level_found) {
323 nread = read(fd, buffer, sizeof(buffer));
324 if (nread < SOKOBAN_LEVEL_SIZE) {
325 close(fd);
326 return -1;
327 }
328
329 /* we search for the first character that isn't a newline */
330 for (i = 0; i < nread; i++) {
331 /* skip and count all newlines */
332 while((buffer[i] == '\n') && (i < nread)) {
333 prevnewl++;
334 i++;
335 }
336
337 /* end of buffer? */
338 if(i == nread)
339 break;
340
341 /* start of new level? */
342 if((prevnewl>1) && (buffer[i] != '\n')) {
343 prevnewl=0; /* none now */
344 level_ct++;
345
346 if (level_ct == current_info.level.level) {
347 level_found = true;
348 offset += i;
349 break;
350 }
351 }
352
353 /* skip all non-newlines */
354 while((buffer[i] != '\n') && (i < nread))
355 i++;
356 }
357 if(!level_found)
358 offset += nread;
359 }
360
361 if (!level_found)
362 return -1;
363
364 /* now seek back to the exact start position */
365 lseek(fd, offset, SEEK_SET);
366
367 /* read a full buffer chunk from here */
368 nread = read(fd, buffer, sizeof(buffer)-1);
369 if (nread < 0)
370 return -1;
371 buffer[nread] = 0;
372
373 close(fd);
374
375 /* If we read less then a level, error */
376 if (nread < level_size)
377 return -1;
378
379 /* Load our new level */
380 for(i=0, count=0; (count < nread) && (i<level_size);) {
381 if (buffer[count] != '\n' && buffer[count] != '\r')
382 level[i++] = buffer[count];
383 count++;
384 }
385 level[i] = 0;
386
387 current_info.loaded_level = current_info.level.level;
388 return 0;
389}
390
391/* return non-zero on error */
392static int load_level(void)
393{
394 short c = 0;
395 short r = 0;
396 short i = 0;
397 char level[ROWS*COLS+1];
398 int x = 0;
249 399
250 current_info.player.spot=' '; 400 current_info.player.spot=' ';
251 current_info.level.boxes_to_go = 0; 401 current_info.level.boxes_to_go = 0;
252 current_info.level.moves = 0; 402 current_info.level.moves = 0;
253 403
254 for (b = 0; b < ROWS; b++) { 404 if (get_level(level, sizeof(level)) != 0)
255 for (c = 0; c < COLS; c++) { 405 return -1;
256 current_info.board[b][c] = levels[level_to_load][a]; 406
257 a++; 407 i = 0;
408 for (r = 0; r < ROWS; r++) {
409 x++;
410 for (c = 0; c < COLS; c++, i++) {
411 current_info.board[r][c] = level[i];
412
413 if (current_info.board[r][c] == '.')
414 current_info.level.boxes_to_go++;
258 415
259 if (current_info.board[b][c] == '@') { 416 else if (current_info.board[r][c] == '@') {
260 current_info.player.row = b; 417 current_info.player.row = r;
261 current_info.player.col = c; 418 current_info.player.col = c;
262 } 419 }
263
264 if (current_info.board[b][c] == '.')
265 current_info.level.boxes_to_go++;
266 } 420 }
267 } 421 }
268 422
269 return; 423 return 0;
270} 424}
271 425
272static void update_screen(void) 426static void update_screen(void)
@@ -326,7 +480,7 @@ static void update_screen(void)
326 } 480 }
327 481
328 482
329 snprintf(s, sizeof(s), "%d", current_info.level.level+1); 483 snprintf(s, sizeof(s), "%d", current_info.level.level);
330 lcd_putsxy(86, 22, s); 484 lcd_putsxy(86, 22, s);
331 snprintf(s, sizeof(s), "%d", current_info.level.moves); 485 snprintf(s, sizeof(s), "%d", current_info.level.moves);
332 lcd_putsxy(86, 54, s); 486 lcd_putsxy(86, 54, s);
@@ -340,9 +494,9 @@ static void update_screen(void)
340 lcd_update(); 494 lcd_update();
341} 495}
342 496
343static void draw_level(short level) 497static void draw_level(void)
344{ 498{
345 load_level(level); 499 load_level();
346 lcd_clear_display(); 500 lcd_clear_display();
347 update_screen(); 501 update_screen();
348} 502}
@@ -354,9 +508,9 @@ static bool sokoban_loop(void)
354 int i = 0, button = 0; 508 int i = 0, button = 0;
355 short r = 0, c = 0; 509 short r = 0, c = 0;
356 510
357 current_info.level.level = 0; 511 current_info.level.level = 1;
358 512
359 load_level(current_info.level.level); 513 load_level();
360 update_screen(); 514 update_screen();
361 515
362 while (1) { 516 while (1) {
@@ -396,10 +550,10 @@ static bool sokoban_loop(void)
396 case BUTTON_F1 | BUTTON_REPEAT: 550 case BUTTON_F1 | BUTTON_REPEAT:
397 /* previous level */ 551 /* previous level */
398 init_undo(); 552 init_undo();
399 if (current_info.level.level) 553 if (current_info.level.level > 1)
400 current_info.level.level--; 554 current_info.level.level--;
401 555
402 draw_level(current_info.level.level); 556 draw_level();
403 moved = false; 557 moved = false;
404 break; 558 break;
405 559
@@ -407,7 +561,7 @@ static bool sokoban_loop(void)
407 case BUTTON_F2 | BUTTON_REPEAT: 561 case BUTTON_F2 | BUTTON_REPEAT:
408 /* same level */ 562 /* same level */
409 init_undo(); 563 init_undo();
410 draw_level(current_info.level.level); 564 draw_level();
411 moved = false; 565 moved = false;
412 break; 566 break;
413 567
@@ -697,7 +851,7 @@ static bool sokoban_loop(void)
697 851
698 lcd_clear_display(); 852 lcd_clear_display();
699 853
700 if (current_info.level.level == NUM_LEVELS) { 854 if (current_info.level.level == current_info.max_level) {
701 lcd_putsxy(10, 20, str(LANG_SOKOBAN_WIN)); 855 lcd_putsxy(10, 20, str(LANG_SOKOBAN_WIN));
702 856
703 for (i = 0; i < 30000 ; i++) { 857 for (i = 0; i < 30000 ; i++) {
@@ -711,7 +865,7 @@ static bool sokoban_loop(void)
711 return false; 865 return false;
712 } 866 }
713 867
714 load_level(current_info.level.level); 868 load_level();
715 update_screen(); 869 update_screen();
716 } 870 }
717 871
@@ -762,6 +916,10 @@ bool sokoban(void)
762 lcd_clear_display(); 916 lcd_clear_display();
763 917
764 init_boards(); 918 init_boards();
919
920 if (get_level_count() != 0)
921 return false;
922
765 result = sokoban_loop(); 923 result = sokoban_loop();
766 924
767 lcd_setfont(FONT_UI); 925 lcd_setfont(FONT_UI);
@@ -770,7 +928,3 @@ bool sokoban(void)
770} 928}
771 929
772#endif 930#endif
773
774
775
776