diff options
Diffstat (limited to 'apps/recorder/sokoban.c')
-rw-r--r-- | apps/recorder/sokoban.c | 222 |
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 | |||
55 | static void init_undo(void); | 56 | static void init_undo(void); |
56 | static void undo(void); | 57 | static void undo(void); |
57 | static void add_undo(int button); | 58 | static void add_undo(int button); |
58 | 59 | ||
60 | static int get_level(char *level, int level_size); | ||
61 | static int get_level_count(void); | ||
62 | static int load_level(void); | ||
63 | static void draw_level(void); | ||
64 | |||
59 | static void init_boards(void); | 65 | static void init_boards(void); |
60 | static void load_level(short level); | ||
61 | static void draw_level(short level); | ||
62 | static void update_screen(void); | 66 | static void update_screen(void); |
63 | static bool sokoban_loop(void); | 67 | static 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 | ||
246 | static void load_level(short level_to_load) | 256 | static 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 | |||
295 | static 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 */ | ||
392 | static 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 | ||
272 | static void update_screen(void) | 426 | static 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 | ||
343 | static void draw_level(short level) | 497 | static 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 | |||