diff options
author | Björn Stenberg <bjorn@haxx.se> | 2003-06-29 16:33:04 +0000 |
---|---|---|
committer | Björn Stenberg <bjorn@haxx.se> | 2003-06-29 16:33:04 +0000 |
commit | ba371fb595affd68c823926b85718d1d613dc7d3 (patch) | |
tree | cfda303d0603d623cdb12f3928905d3ae02f1d87 /apps/recorder/sokoban.c | |
parent | 9bcbe3fd723d23a709873a0855f27b86bc5c96f1 (diff) | |
download | rockbox-ba371fb595affd68c823926b85718d1d613dc7d3.tar.gz rockbox-ba371fb595affd68c823926b85718d1d613dc7d3.zip |
Added plugin loader. Moved games, demos and the text viewer to loadable plugins. Copy your *.rock files to /.rockbox/rocks/
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3769 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/recorder/sokoban.c')
-rw-r--r-- | apps/recorder/sokoban.c | 891 |
1 files changed, 0 insertions, 891 deletions
diff --git a/apps/recorder/sokoban.c b/apps/recorder/sokoban.c deleted file mode 100644 index d28e32f430..0000000000 --- a/apps/recorder/sokoban.c +++ /dev/null | |||
@@ -1,891 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 Eric Linenberg | ||
11 | * February 2003: Robert Hak performs a cleanup/rewrite/feature addition. | ||
12 | * Eric smiles. Bjorn cries. Linus say 'huh?'. | ||
13 | * | ||
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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "config.h" | ||
23 | #include "options.h" | ||
24 | |||
25 | #ifdef USE_GAMES | ||
26 | |||
27 | #include <sprintf.h> | ||
28 | #include "ctype.h" | ||
29 | #include "sokoban.h" | ||
30 | #include "lcd.h" | ||
31 | #include "button.h" | ||
32 | #include "kernel.h" | ||
33 | #include "menu.h" | ||
34 | #include "screens.h" | ||
35 | #include "font.h" | ||
36 | #include "file.h" | ||
37 | #include "misc.h" | ||
38 | #include "debug.h" | ||
39 | |||
40 | #ifdef SIMULATOR | ||
41 | #include <stdio.h> | ||
42 | #endif | ||
43 | #include <string.h> | ||
44 | #include "lang.h" | ||
45 | #include "sprintf.h" | ||
46 | |||
47 | #define SOKOBAN_TITLE "Sokoban" | ||
48 | #define SOKOBAN_TITLE_FONT 2 | ||
49 | |||
50 | #define LEVELS_FILE "/.rockbox/sokoban/levels.txt" | ||
51 | |||
52 | #define ROWS 16 | ||
53 | #define COLS 20 | ||
54 | #define MAX_UNDOS 5 | ||
55 | |||
56 | #define SOKOBAN_LEVEL_SIZE (ROWS*COLS) | ||
57 | |||
58 | static void init_undo(void); | ||
59 | static void undo(void); | ||
60 | static void add_undo(int button); | ||
61 | |||
62 | static int get_level(char *level, int level_size); | ||
63 | static int get_level_count(void); | ||
64 | static int load_level(void); | ||
65 | static void draw_level(void); | ||
66 | |||
67 | static void init_boards(void); | ||
68 | static void update_screen(void); | ||
69 | static bool sokoban_loop(void); | ||
70 | |||
71 | /* The Location, Undo and LevelInfo structs are OO-flavored. | ||
72 | * (oooh!-flavored as Schnueff puts it.) It makes more you have to know, | ||
73 | * but the overall data layout becomes more manageable. */ | ||
74 | |||
75 | /* We use the same three values in 2 structs. Makeing them a struct | ||
76 | * hopefully ensures that if you change things in one, the other changes | ||
77 | * as well. */ | ||
78 | struct LevelInfo { | ||
79 | short level; | ||
80 | short moves; | ||
81 | short boxes_to_go; | ||
82 | }; | ||
83 | |||
84 | /* What a given location on the board looks like at a given time */ | ||
85 | struct Location { | ||
86 | char spot; | ||
87 | short row; | ||
88 | short col; | ||
89 | }; | ||
90 | |||
91 | /* A single level of undo. Each undo move can affect upto, | ||
92 | * but not more then, 3 spots on the board */ | ||
93 | struct Undo { | ||
94 | struct LevelInfo level; | ||
95 | struct Location location[3]; | ||
96 | }; | ||
97 | |||
98 | /* Our full undo history */ | ||
99 | static struct UndoInfo { | ||
100 | short count; /* How many undos are there in history */ | ||
101 | short current; /* Which history is the current undo */ | ||
102 | struct Undo history[MAX_UNDOS]; | ||
103 | } undo_info; | ||
104 | |||
105 | /* Our playing board */ | ||
106 | static struct BoardInfo { | ||
107 | char board[ROWS][COLS]; | ||
108 | struct LevelInfo level; | ||
109 | struct Location player; | ||
110 | int max_level; /* How many levels do we have? */ | ||
111 | int level_offset; /* Where in the level file is this level */ | ||
112 | int loaded_level; /* Which level is in memory */ | ||
113 | } current_info; | ||
114 | |||
115 | |||
116 | static void init_undo(void) | ||
117 | { | ||
118 | undo_info.count = 0; | ||
119 | undo_info.current = 0; | ||
120 | } | ||
121 | |||
122 | static void undo(void) | ||
123 | { | ||
124 | struct Undo *undo; | ||
125 | int i = 0; | ||
126 | short row, col; | ||
127 | |||
128 | if (undo_info.count == 0) | ||
129 | return; | ||
130 | |||
131 | /* Update board info */ | ||
132 | undo = &undo_info.history[undo_info.current]; | ||
133 | |||
134 | current_info.level = undo->level; | ||
135 | current_info.player = undo->location[0]; | ||
136 | |||
137 | row = undo->location[0].row; | ||
138 | col = undo->location[0].col; | ||
139 | current_info.board[row][col] = '@'; | ||
140 | |||
141 | /* Update the two other possible spots */ | ||
142 | for (i = 1; i < 3; i++) { | ||
143 | if (undo->location[i].spot != '\0') { | ||
144 | row = undo->location[i].row; | ||
145 | col = undo->location[i].col; | ||
146 | current_info.board[row][col] = undo->location[i].spot; | ||
147 | undo->location[i].spot = '\0'; | ||
148 | } | ||
149 | } | ||
150 | |||
151 | /* Remove this undo from the list */ | ||
152 | if (undo_info.current == 0) { | ||
153 | if (undo_info.count > 1) | ||
154 | undo_info.current = MAX_UNDOS - 1; | ||
155 | } else { | ||
156 | undo_info.current--; | ||
157 | } | ||
158 | |||
159 | undo_info.count--; | ||
160 | |||
161 | return; | ||
162 | } | ||
163 | |||
164 | static void add_undo(int button) | ||
165 | { | ||
166 | struct Undo *undo; | ||
167 | int row, col, i; | ||
168 | bool storable; | ||
169 | |||
170 | if ((button != BUTTON_LEFT) && (button != BUTTON_RIGHT) && | ||
171 | (button != BUTTON_UP) && (button != BUTTON_DOWN)) | ||
172 | return; | ||
173 | |||
174 | if (undo_info.count != 0) { | ||
175 | if (undo_info.current < (MAX_UNDOS - 1)) | ||
176 | undo_info.current++; | ||
177 | else | ||
178 | undo_info.current = 0; | ||
179 | } | ||
180 | |||
181 | /* Make what follows more readable */ | ||
182 | undo = &undo_info.history[undo_info.current]; | ||
183 | |||
184 | /* Store our level info */ | ||
185 | undo->level = current_info.level; | ||
186 | |||
187 | /* Store our player info */ | ||
188 | undo->location[0] = current_info.player; | ||
189 | |||
190 | /* Now we need to store upto 2 blocks that may be affected. | ||
191 | * If player.spot is NULL, then there is no info stored | ||
192 | * for that block */ | ||
193 | |||
194 | row = current_info.player.row; | ||
195 | col = current_info.player.col; | ||
196 | |||
197 | /* This must stay as _1_ because the first block (0) is the player */ | ||
198 | for (i = 1; i < 3; i++) { | ||
199 | storable = true; | ||
200 | |||
201 | switch (button) { | ||
202 | case BUTTON_LEFT: | ||
203 | col--; | ||
204 | if (col < 0) | ||
205 | storable = false; | ||
206 | break; | ||
207 | |||
208 | case BUTTON_RIGHT: | ||
209 | col++; | ||
210 | if (col >= COLS) | ||
211 | storable = false; | ||
212 | break; | ||
213 | |||
214 | case BUTTON_UP: | ||
215 | row--; | ||
216 | if (row < 0) | ||
217 | storable = false; | ||
218 | break; | ||
219 | |||
220 | case BUTTON_DOWN: | ||
221 | row++; | ||
222 | if (row >= ROWS) | ||
223 | storable = false; | ||
224 | break; | ||
225 | |||
226 | default: | ||
227 | return; | ||
228 | } | ||
229 | |||
230 | if (storable) { | ||
231 | undo->location[i].col = col; | ||
232 | undo->location[i].row = row; | ||
233 | undo->location[i].spot = current_info.board[row][col]; | ||
234 | } else { | ||
235 | undo->location[i].spot = '\0'; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | if (undo_info.count < MAX_UNDOS) | ||
240 | undo_info.count++; | ||
241 | } | ||
242 | |||
243 | static void init_boards(void) | ||
244 | { | ||
245 | current_info.level.level = 0; | ||
246 | current_info.level.moves = 0; | ||
247 | current_info.level.boxes_to_go = 0; | ||
248 | current_info.player.row = 0; | ||
249 | current_info.player.col = 0; | ||
250 | current_info.player.spot = ' '; | ||
251 | current_info.max_level = 0; | ||
252 | current_info.level_offset = 0; | ||
253 | current_info.loaded_level = 0; | ||
254 | |||
255 | init_undo(); | ||
256 | } | ||
257 | |||
258 | static int get_level_count(void) | ||
259 | { | ||
260 | int fd = 0; | ||
261 | int len, lastlen = 0; | ||
262 | char buffer[COLS + 3]; /* COLS plus CR/LF and \0 */ | ||
263 | |||
264 | if ((fd = open(LEVELS_FILE, O_RDONLY)) < 0) { | ||
265 | splash(0, 0, true, "Unable to open %s", LEVELS_FILE); | ||
266 | return -1; | ||
267 | } | ||
268 | |||
269 | while(1) { | ||
270 | len = read_line(fd, buffer, sizeof(buffer)); | ||
271 | if(len <= 0) | ||
272 | break; | ||
273 | |||
274 | /* Two short lines in a row means new level */ | ||
275 | if(len < 3 && lastlen < 3) | ||
276 | current_info.max_level++; | ||
277 | |||
278 | lastlen = len; | ||
279 | } | ||
280 | |||
281 | DEBUGF("%d levels loaded\n", current_info.max_level); | ||
282 | close(fd); | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int get_level(char *level, int level_size) | ||
287 | { | ||
288 | int fd = 0, i = 0; | ||
289 | int nread = 0; | ||
290 | int count = 0; | ||
291 | int len, lastlen = 0; | ||
292 | int level_ct = 1; | ||
293 | unsigned char buffer[SOKOBAN_LEVEL_SIZE * 2]; | ||
294 | bool level_found = false; | ||
295 | |||
296 | /* open file */ | ||
297 | if ((fd = open(LEVELS_FILE, O_RDONLY)) < 0) | ||
298 | return -1; | ||
299 | |||
300 | /* Lets not reparse the full file if we can avoid it */ | ||
301 | if (current_info.loaded_level < current_info.level.level) { | ||
302 | lseek(fd, current_info.level_offset, SEEK_SET); | ||
303 | level_ct = current_info.loaded_level; | ||
304 | } | ||
305 | |||
306 | if(current_info.level.level > 1) { | ||
307 | while(!level_found) { | ||
308 | len = read_line(fd, buffer, SOKOBAN_LEVEL_SIZE); | ||
309 | if(len <= 0) { | ||
310 | close(fd); | ||
311 | return -1; | ||
312 | } | ||
313 | |||
314 | /* Two short lines in a row means new level */ | ||
315 | if(len < 3 && lastlen < 3) { | ||
316 | level_ct++; | ||
317 | if(level_ct == current_info.level.level) | ||
318 | level_found = true; | ||
319 | } | ||
320 | lastlen = len; | ||
321 | } | ||
322 | } | ||
323 | |||
324 | /* Remember the current offset */ | ||
325 | current_info.level_offset = lseek(fd, 0, SEEK_CUR); | ||
326 | |||
327 | /* read a full buffer chunk from here */ | ||
328 | nread = read(fd, buffer, sizeof(buffer)-1); | ||
329 | if (nread < 0) | ||
330 | return -1; | ||
331 | buffer[nread] = 0; | ||
332 | |||
333 | close(fd); | ||
334 | |||
335 | /* If we read less then a level, error */ | ||
336 | if (nread < level_size) | ||
337 | return -1; | ||
338 | |||
339 | /* Load our new level */ | ||
340 | for(i=0, count=0; (count < nread) && (i<level_size);) { | ||
341 | if (buffer[count] != '\n' && buffer[count] != '\r') | ||
342 | level[i++] = buffer[count]; | ||
343 | count++; | ||
344 | } | ||
345 | level[i] = 0; | ||
346 | |||
347 | current_info.loaded_level = current_info.level.level; | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | /* return non-zero on error */ | ||
352 | static int load_level(void) | ||
353 | { | ||
354 | short c = 0; | ||
355 | short r = 0; | ||
356 | short i = 0; | ||
357 | char level[ROWS*COLS+1]; | ||
358 | int x = 0; | ||
359 | |||
360 | current_info.player.spot=' '; | ||
361 | current_info.level.boxes_to_go = 0; | ||
362 | current_info.level.moves = 0; | ||
363 | |||
364 | if (get_level(level, sizeof(level)) != 0) | ||
365 | return -1; | ||
366 | |||
367 | i = 0; | ||
368 | for (r = 0; r < ROWS; r++) { | ||
369 | x++; | ||
370 | for (c = 0; c < COLS; c++, i++) { | ||
371 | current_info.board[r][c] = level[i]; | ||
372 | |||
373 | if (current_info.board[r][c] == '.') | ||
374 | current_info.level.boxes_to_go++; | ||
375 | |||
376 | else if (current_info.board[r][c] == '@') { | ||
377 | current_info.player.row = r; | ||
378 | current_info.player.col = c; | ||
379 | } | ||
380 | } | ||
381 | } | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static void update_screen(void) | ||
387 | { | ||
388 | short b = 0, c = 0; | ||
389 | short rows = 0, cols = 0; | ||
390 | char s[25]; | ||
391 | |||
392 | short magnify = 4; | ||
393 | |||
394 | /* load the board to the screen */ | ||
395 | for (rows=0 ; rows < ROWS ; rows++) { | ||
396 | for (cols = 0 ; cols < COLS ; cols++) { | ||
397 | c = cols * magnify; | ||
398 | b = rows * magnify; | ||
399 | |||
400 | switch(current_info.board[rows][cols]) { | ||
401 | case 'X': /* black space */ | ||
402 | lcd_drawrect(c, b, magnify, magnify); | ||
403 | lcd_drawrect(c+1, b+1, 2, 2); | ||
404 | break; | ||
405 | |||
406 | case '#': /* this is a wall */ | ||
407 | lcd_drawpixel(c, b); | ||
408 | lcd_drawpixel(c+2, b); | ||
409 | lcd_drawpixel(c+1, b+1); | ||
410 | lcd_drawpixel(c+3, b+1); | ||
411 | lcd_drawpixel(c, b+2); | ||
412 | lcd_drawpixel(c+2, b+2); | ||
413 | lcd_drawpixel(c+1, b+3); | ||
414 | lcd_drawpixel(c+3, b+3); | ||
415 | break; | ||
416 | |||
417 | case '.': /* this is a home location */ | ||
418 | lcd_drawrect(c+1, b+1, 2, 2); | ||
419 | break; | ||
420 | |||
421 | case '$': /* this is a box */ | ||
422 | lcd_drawrect(c, b, magnify, magnify); | ||
423 | break; | ||
424 | |||
425 | case '@': /* this is you */ | ||
426 | lcd_drawline(c+1, b, c+2, b); | ||
427 | lcd_drawline(c, b+1, c+3, b+1); | ||
428 | lcd_drawline(c+1, b+2, c+2, b+2); | ||
429 | |||
430 | lcd_drawpixel(c, b+3); | ||
431 | lcd_drawpixel(c+3, b+3); | ||
432 | break; | ||
433 | |||
434 | case '%': /* this is a box on a home spot */ | ||
435 | lcd_drawrect(c, b, magnify, magnify); | ||
436 | lcd_drawrect(c+1, b+1, 2, 2); | ||
437 | break; | ||
438 | } | ||
439 | } | ||
440 | } | ||
441 | |||
442 | |||
443 | snprintf(s, sizeof(s), "%d", current_info.level.level); | ||
444 | lcd_putsxy(86, 22, s); | ||
445 | snprintf(s, sizeof(s), "%d", current_info.level.moves); | ||
446 | lcd_putsxy(86, 54, s); | ||
447 | |||
448 | lcd_drawrect(80,0,32,32); | ||
449 | lcd_drawrect(80,32,32,64); | ||
450 | lcd_putsxy(81, 10, str(LANG_SOKOBAN_LEVEL)); | ||
451 | lcd_putsxy(81, 42, str(LANG_SOKOBAN_MOVE)); | ||
452 | |||
453 | /* print out the screen */ | ||
454 | lcd_update(); | ||
455 | } | ||
456 | |||
457 | static void draw_level(void) | ||
458 | { | ||
459 | load_level(); | ||
460 | lcd_clear_display(); | ||
461 | update_screen(); | ||
462 | } | ||
463 | |||
464 | static bool sokoban_loop(void) | ||
465 | { | ||
466 | char new_spot; | ||
467 | bool moved = true; | ||
468 | int i = 0, button = 0; | ||
469 | short r = 0, c = 0; | ||
470 | |||
471 | current_info.level.level = 1; | ||
472 | |||
473 | load_level(); | ||
474 | update_screen(); | ||
475 | |||
476 | while (1) { | ||
477 | moved = true; | ||
478 | |||
479 | r = current_info.player.row; | ||
480 | c = current_info.player.col; | ||
481 | |||
482 | button = button_get(true); | ||
483 | |||
484 | add_undo(button); | ||
485 | |||
486 | switch(button) | ||
487 | { | ||
488 | case BUTTON_OFF: | ||
489 | /* get out of here */ | ||
490 | return false; | ||
491 | |||
492 | case BUTTON_ON: | ||
493 | case BUTTON_ON | BUTTON_REPEAT: | ||
494 | /* this is UNDO */ | ||
495 | undo(); | ||
496 | lcd_clear_display(); | ||
497 | update_screen(); | ||
498 | moved = false; | ||
499 | break; | ||
500 | |||
501 | case BUTTON_F3: | ||
502 | case BUTTON_F3 | BUTTON_REPEAT: | ||
503 | /* increase level */ | ||
504 | init_undo(); | ||
505 | current_info.level.boxes_to_go=0; | ||
506 | moved = true; | ||
507 | break; | ||
508 | |||
509 | case BUTTON_F1: | ||
510 | case BUTTON_F1 | BUTTON_REPEAT: | ||
511 | /* previous level */ | ||
512 | init_undo(); | ||
513 | if (current_info.level.level > 1) | ||
514 | current_info.level.level--; | ||
515 | |||
516 | draw_level(); | ||
517 | moved = false; | ||
518 | break; | ||
519 | |||
520 | case BUTTON_F2: | ||
521 | case BUTTON_F2 | BUTTON_REPEAT: | ||
522 | /* same level */ | ||
523 | init_undo(); | ||
524 | draw_level(); | ||
525 | moved = false; | ||
526 | break; | ||
527 | |||
528 | case BUTTON_LEFT: | ||
529 | switch(current_info.board[r][c-1]) | ||
530 | { | ||
531 | case ' ': /* if it is a blank spot */ | ||
532 | case '.': /* if it is a home spot */ | ||
533 | new_spot = current_info.board[r][c-1]; | ||
534 | current_info.board[r][c-1] = '@'; | ||
535 | current_info.board[r][c] = current_info.player.spot; | ||
536 | current_info.player.spot = new_spot; | ||
537 | break; | ||
538 | |||
539 | case '$': | ||
540 | switch(current_info.board[r][c-2]) | ||
541 | { | ||
542 | case ' ': /* going from blank to blank */ | ||
543 | current_info.board[r][c-2] = current_info.board[r][c-1]; | ||
544 | current_info.board[r][c-1] = current_info.board[r][c]; | ||
545 | current_info.board[r][c] = current_info.player.spot; | ||
546 | current_info.player.spot = ' '; | ||
547 | break; | ||
548 | |||
549 | case '.': /* going from a blank to home */ | ||
550 | current_info.board[r][c-2] = '%'; | ||
551 | current_info.board[r][c-1] = current_info.board[r][c]; | ||
552 | current_info.board[r][c] = current_info.player.spot; | ||
553 | current_info.player.spot = ' '; | ||
554 | current_info.level.boxes_to_go--; | ||
555 | break; | ||
556 | |||
557 | default: | ||
558 | moved = false; | ||
559 | break; | ||
560 | } | ||
561 | break; | ||
562 | |||
563 | case '%': | ||
564 | switch(current_info.board[r][c-2]) { | ||
565 | case ' ': /* we are going from a home to a blank */ | ||
566 | current_info.board[r][c-2] = '$'; | ||
567 | current_info.board[r][c-1] = current_info.board[r][c]; | ||
568 | current_info.board[r][c] = current_info.player.spot; | ||
569 | current_info.player.spot = '.'; | ||
570 | current_info.level.boxes_to_go++; | ||
571 | break; | ||
572 | |||
573 | case '.': /* if we are going from a home to home */ | ||
574 | current_info.board[r][c-2] = '%'; | ||
575 | current_info.board[r][c-1] = current_info.board[r][c]; | ||
576 | current_info.board[r][c] = current_info.player.spot; | ||
577 | current_info.player.spot = '.'; | ||
578 | break; | ||
579 | |||
580 | default: | ||
581 | moved = false; | ||
582 | break; | ||
583 | } | ||
584 | break; | ||
585 | |||
586 | default: | ||
587 | moved = false; | ||
588 | break; | ||
589 | } | ||
590 | |||
591 | if (moved) | ||
592 | current_info.player.col--; | ||
593 | break; | ||
594 | |||
595 | case BUTTON_RIGHT: /* if it is a blank spot */ | ||
596 | switch(current_info.board[r][c+1]) { | ||
597 | case ' ': | ||
598 | case '.': /* if it is a home spot */ | ||
599 | new_spot = current_info.board[r][c+1]; | ||
600 | current_info.board[r][c+1] = '@'; | ||
601 | current_info.board[r][c] = current_info.player.spot; | ||
602 | current_info.player.spot = new_spot; | ||
603 | break; | ||
604 | |||
605 | case '$': | ||
606 | switch(current_info.board[r][c+2]) { | ||
607 | case ' ': /* going from blank to blank */ | ||
608 | current_info.board[r][c+2] = current_info.board[r][c+1]; | ||
609 | current_info.board[r][c+1] = current_info.board[r][c]; | ||
610 | current_info.board[r][c] = current_info.player.spot; | ||
611 | current_info.player.spot = ' '; | ||
612 | break; | ||
613 | |||
614 | case '.': /* going from a blank to home */ | ||
615 | current_info.board[r][c+2] = '%'; | ||
616 | current_info.board[r][c+1] = current_info.board[r][c]; | ||
617 | current_info.board[r][c] = current_info.player.spot; | ||
618 | current_info.player.spot = ' '; | ||
619 | current_info.level.boxes_to_go--; | ||
620 | break; | ||
621 | |||
622 | default: | ||
623 | moved = false; | ||
624 | break; | ||
625 | } | ||
626 | break; | ||
627 | |||
628 | case '%': | ||
629 | switch(current_info.board[r][c+2]) { | ||
630 | case ' ': /* going from a home to a blank */ | ||
631 | current_info.board[r][c+2] = '$'; | ||
632 | current_info.board[r][c+1] = current_info.board[r][c]; | ||
633 | current_info.board[r][c] = current_info.player.spot; | ||
634 | current_info.player.spot = '.'; | ||
635 | current_info.level.boxes_to_go++; | ||
636 | break; | ||
637 | |||
638 | case '.': | ||
639 | current_info.board[r][c+2] = '%'; | ||
640 | current_info.board[r][c+1] = current_info.board[r][c]; | ||
641 | current_info.board[r][c] = current_info.player.spot; | ||
642 | current_info.player.spot = '.'; | ||
643 | break; | ||
644 | |||
645 | default: | ||
646 | moved = false; | ||
647 | break; | ||
648 | } | ||
649 | break; | ||
650 | |||
651 | default: | ||
652 | moved = false; | ||
653 | break; | ||
654 | } | ||
655 | |||
656 | if (moved) | ||
657 | current_info.player.col++; | ||
658 | break; | ||
659 | |||
660 | case BUTTON_UP: | ||
661 | switch(current_info.board[r-1][c]) { | ||
662 | case ' ': /* if it is a blank spot */ | ||
663 | case '.': /* if it is a home spot */ | ||
664 | new_spot = current_info.board[r-1][c]; | ||
665 | current_info.board[r-1][c] = '@'; | ||
666 | current_info.board[r][c] = current_info.player.spot; | ||
667 | current_info.player.spot = new_spot; | ||
668 | break; | ||
669 | |||
670 | case '$': | ||
671 | switch(current_info.board[r-2][c]) { | ||
672 | case ' ': /* going from blank to blank */ | ||
673 | current_info.board[r-2][c] = current_info.board[r-1][c]; | ||
674 | current_info.board[r-1][c] = current_info.board[r][c]; | ||
675 | current_info.board[r][c] = current_info.player.spot; | ||
676 | current_info.player.spot = ' '; | ||
677 | break; | ||
678 | |||
679 | case '.': /* going from a blank to home */ | ||
680 | current_info.board[r-2][c] = '%'; | ||
681 | current_info.board[r-1][c] = current_info.board[r][c]; | ||
682 | current_info.board[r][c] = current_info.player.spot; | ||
683 | current_info.player.spot = ' '; | ||
684 | current_info.level.boxes_to_go--; | ||
685 | break; | ||
686 | |||
687 | default: | ||
688 | moved = false; | ||
689 | break; | ||
690 | } | ||
691 | break; | ||
692 | |||
693 | case '%': | ||
694 | switch(current_info.board[r-2][c]) { | ||
695 | case ' ': /* we are going from a home to a blank */ | ||
696 | current_info.board[r-2][c] = '$'; | ||
697 | current_info.board[r-1][c] = current_info.board[r][c]; | ||
698 | current_info.board[r][c] = current_info.player.spot; | ||
699 | current_info.player.spot = '.'; | ||
700 | current_info.level.boxes_to_go++; | ||
701 | break; | ||
702 | |||
703 | case '.': /* if we are going from a home to home */ | ||
704 | current_info.board[r-2][c] = '%'; | ||
705 | current_info.board[r-1][c] = current_info.board[r][c]; | ||
706 | current_info.board[r][c] = current_info.player.spot; | ||
707 | current_info.player.spot = '.'; | ||
708 | break; | ||
709 | |||
710 | default: | ||
711 | moved = false; | ||
712 | break; | ||
713 | } | ||
714 | break; | ||
715 | |||
716 | default: | ||
717 | moved = false; | ||
718 | break; | ||
719 | } | ||
720 | |||
721 | if (moved) | ||
722 | current_info.player.row--; | ||
723 | break; | ||
724 | |||
725 | case BUTTON_DOWN: | ||
726 | switch(current_info.board[r+1][c]) { | ||
727 | case ' ': /* if it is a blank spot */ | ||
728 | case '.': /* if it is a home spot */ | ||
729 | new_spot = current_info.board[r+1][c]; | ||
730 | current_info.board[r+1][c] = '@'; | ||
731 | current_info.board[r][c] = current_info.player.spot; | ||
732 | current_info.player.spot = new_spot; | ||
733 | break; | ||
734 | |||
735 | case '$': | ||
736 | switch(current_info.board[r+2][c]) { | ||
737 | case ' ': /* going from blank to blank */ | ||
738 | current_info.board[r+2][c] = current_info.board[r+1][c]; | ||
739 | current_info.board[r+1][c] = current_info.board[r][c]; | ||
740 | current_info.board[r][c] = current_info.player.spot; | ||
741 | current_info.player.spot = ' '; | ||
742 | break; | ||
743 | |||
744 | case '.': /* going from a blank to home */ | ||
745 | current_info.board[r+2][c] = '%'; | ||
746 | current_info.board[r+1][c] = current_info.board[r][c]; | ||
747 | current_info.board[r][c] = current_info.player.spot; | ||
748 | current_info.player.spot = ' '; | ||
749 | current_info.level.boxes_to_go--; | ||
750 | break; | ||
751 | |||
752 | default: | ||
753 | moved = false; | ||
754 | break; | ||
755 | } | ||
756 | break; | ||
757 | |||
758 | case '%': | ||
759 | switch(current_info.board[r+2][c]) { | ||
760 | case ' ': /* going from a home to a blank */ | ||
761 | current_info.board[r+2][c] = '$'; | ||
762 | current_info.board[r+1][c] = current_info.board[r][c]; | ||
763 | current_info.board[r][c] = current_info.player.spot; | ||
764 | current_info.player.spot = '.'; | ||
765 | current_info.level.boxes_to_go++; | ||
766 | break; | ||
767 | |||
768 | case '.': /* going from a home to home */ | ||
769 | current_info.board[r+2][c] = '%'; | ||
770 | current_info.board[r+1][c] = current_info.board[r][c]; | ||
771 | current_info.board[r][c] = current_info.player.spot; | ||
772 | current_info.player.spot = '.'; | ||
773 | break; | ||
774 | |||
775 | default: | ||
776 | moved = false; | ||
777 | break; | ||
778 | } | ||
779 | break; | ||
780 | |||
781 | default: | ||
782 | moved = false; | ||
783 | break; | ||
784 | } | ||
785 | |||
786 | if (moved) | ||
787 | current_info.player.row++; | ||
788 | break; | ||
789 | |||
790 | case SYS_USB_CONNECTED: | ||
791 | usb_screen(); | ||
792 | return true; | ||
793 | |||
794 | default: | ||
795 | moved = false; | ||
796 | break; | ||
797 | } | ||
798 | |||
799 | if (moved) { | ||
800 | current_info.level.moves++; | ||
801 | lcd_clear_display(); | ||
802 | update_screen(); | ||
803 | } | ||
804 | |||
805 | /* We have completed this level */ | ||
806 | if (current_info.level.boxes_to_go == 0) { | ||
807 | current_info.level.level++; | ||
808 | |||
809 | /* clear undo stats */ | ||
810 | init_undo(); | ||
811 | |||
812 | lcd_clear_display(); | ||
813 | |||
814 | if (current_info.level.level > current_info.max_level) { | ||
815 | lcd_putsxy(10, 20, str(LANG_SOKOBAN_WIN)); | ||
816 | |||
817 | for (i = 0; i < 30000 ; i++) { | ||
818 | lcd_invertrect(0, 0, 111, 63); | ||
819 | lcd_update(); | ||
820 | |||
821 | button = button_get(false); | ||
822 | if (button && ((button & BUTTON_REL) != BUTTON_REL)) | ||
823 | break; | ||
824 | } | ||
825 | |||
826 | return false; | ||
827 | } | ||
828 | |||
829 | load_level(); | ||
830 | update_screen(); | ||
831 | } | ||
832 | |||
833 | } /* end while */ | ||
834 | |||
835 | return false; | ||
836 | } | ||
837 | |||
838 | |||
839 | bool sokoban(void) | ||
840 | { | ||
841 | bool result; | ||
842 | int w, h; | ||
843 | int len; | ||
844 | |||
845 | lcd_setfont(FONT_SYSFIXED); | ||
846 | |||
847 | lcd_getstringsize(SOKOBAN_TITLE, &w, &h); | ||
848 | |||
849 | /* Get horizontel centering for text */ | ||
850 | len = w; | ||
851 | if (len%2 != 0) | ||
852 | len =((len+1)/2)+(w/2); | ||
853 | else | ||
854 | len /= 2; | ||
855 | |||
856 | if (h%2 != 0) | ||
857 | h = (h/2)+1; | ||
858 | else | ||
859 | h /= 2; | ||
860 | |||
861 | lcd_clear_display(); | ||
862 | lcd_putsxy(LCD_WIDTH/2-len,(LCD_HEIGHT/2)-h, SOKOBAN_TITLE); | ||
863 | |||
864 | lcd_update(); | ||
865 | sleep(HZ*2); | ||
866 | |||
867 | lcd_clear_display(); | ||
868 | |||
869 | lcd_putsxy(3, 6, str(LANG_SOKOBAN_QUIT)); | ||
870 | lcd_putsxy(3, 16, str(LANG_SOKOBAN_ON)); | ||
871 | lcd_putsxy(3, 26, str(LANG_SOKOBAN_F1)); | ||
872 | lcd_putsxy(3, 36, str(LANG_SOKOBAN_F2)); | ||
873 | lcd_putsxy(3, 46, str(LANG_SOKOBAN_F3)); | ||
874 | |||
875 | lcd_update(); | ||
876 | sleep(HZ*2); | ||
877 | lcd_clear_display(); | ||
878 | |||
879 | init_boards(); | ||
880 | |||
881 | if (get_level_count() != 0) | ||
882 | return false; | ||
883 | |||
884 | result = sokoban_loop(); | ||
885 | |||
886 | lcd_setfont(FONT_UI); | ||
887 | |||
888 | return result; | ||
889 | } | ||
890 | |||
891 | #endif | ||