From f91d06de7bf724e8e0aa580c18efa3eb345f88f9 Mon Sep 17 00:00:00 2001 From: Antoine Cellerier Date: Thu, 28 Jun 2007 20:45:00 +0000 Subject: [PATCH] Apply FS #6702: More Sokoban Improvements. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13731 a1c6a512-1295-4272-9138-f99709370657 --- apps/FILES | 2 +- apps/plugins/bitmaps/native/SOURCES | 8 +- apps/plugins/sokoban.c | 1391 ++++++++----- apps/plugins/sokoban.levels | 1816 ----------------- apps/plugins/sokobanlevels.sok | 1277 ++++++++++++ apps/plugins/viewers.config | 1 + manual/plugins/images/ss-sokoban-112x64x1.png | Bin 337 -> 353 bytes .../plugins/images/ss-sokoban-128x128x16.png | Bin 1135 -> 665 bytes .../plugins/images/ss-sokoban-138x110x2.png | Bin 481 -> 455 bytes .../plugins/images/ss-sokoban-160x128x16.png | Bin 1269 -> 699 bytes .../plugins/images/ss-sokoban-160x128x2.png | Bin 514 -> 615 bytes .../plugins/images/ss-sokoban-176x132x16.png | Bin 1323 -> 709 bytes .../plugins/images/ss-sokoban-176x220x16.png | Bin 1366 -> 875 bytes .../plugins/images/ss-sokoban-220x176x16.png | Bin 1645 -> 888 bytes .../plugins/images/ss-sokoban-240x320x16.png | Bin 2035 -> 972 bytes .../plugins/images/ss-sokoban-320x240x16.png | Bin 2255 -> 1205 bytes manual/plugins/sokoban.tex | 93 +- tools/buildzip.pl | 2 +- 18 files changed, 2245 insertions(+), 2345 deletions(-) delete mode 100644 apps/plugins/sokoban.levels create mode 100644 apps/plugins/sokobanlevels.sok diff --git a/apps/FILES b/apps/FILES index 85d70cbe74..06b7b38b9a 100644 --- a/apps/FILES +++ b/apps/FILES @@ -42,7 +42,7 @@ plugins/*.pl plugins/Makefile plugins/plugin.lds plugins/snake2.levels -plugins/sokoban.levels +plugins/sokobanlevels.sok plugins/viewers.config plugins/SOURCES plugins/SUBDIRS diff --git a/apps/plugins/bitmaps/native/SOURCES b/apps/plugins/bitmaps/native/SOURCES index 90a635ef01..00a6e3ab30 100644 --- a/apps/plugins/bitmaps/native/SOURCES +++ b/apps/plugins/bitmaps/native/SOURCES @@ -331,11 +331,13 @@ sokoban_tiles.14x14.bmp #elif (LCD_HEIGHT >= 144) && (LCD_WIDTH >= 212) || \ (LCD_HEIGHT >= 169) && (LCD_WIDTH >= 180-4) sokoban_tiles.9x9.bmp -#else -/* LCD_HEIGHT >= 96~121 && LCD_WIDTH >= 152~120 */ +#elif (LCD_HEIGHT >= 96 && LCD_WIDTH >= 152) || \ + (LCD_HEIGHT >= 121 && LCD_WIDTH >= 120) sokoban_tiles.6x6.bmp #endif -#elif LCD_DEPTH >= 2 +#elif LCD_DEPTH >= 2 && \ + ((LCD_HEIGHT >= 96 && LCD_WIDTH >= 152) || \ + (LCD_HEIGHT >= 121 && LCD_WIDTH >= 120)) sokoban_tiles.6x6x2.bmp #endif diff --git a/apps/plugins/sokoban.c b/apps/plugins/sokoban.c index 40a2f549ad..976f552dbd 100644 --- a/apps/plugins/sokoban.c +++ b/apps/plugins/sokoban.c @@ -10,6 +10,7 @@ * Copyright (C) 2002 Eric Linenberg * February 2003: Robert Hak performs a cleanup/rewrite/feature addition. * Eric smiles. Bjorn cries. Linus say 'huh?'. + * March 2007: Sean Morrisey performs a major rewrite/feature addition. * * 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. @@ -19,95 +20,126 @@ * ****************************************************************************/ #include "plugin.h" +#include "lib/playback_control.h" #ifdef HAVE_LCD_BITMAP PLUGIN_HEADER -#if LCD_DEPTH >= 2 +#if LCD_DEPTH >= 2 && ((LCD_HEIGHT >= 96 && LCD_WIDTH >= 152) || \ + (LCD_HEIGHT >= 121 && LCD_WIDTH >= 120)) extern const fb_data sokoban_tiles[]; #endif -#define SOKOBAN_TITLE "Sokoban" +#define SOKOBAN_TITLE "Sokoban" -#define LEVELS_FILE PLUGIN_DIR "/sokoban.levels" +#define SOKOBAN_LEVELS_FILE PLUGIN_DIR "/sokobanlevels.sok" +#define SOKOBAN_SAVE_FILE PLUGIN_DIR "/sokobansave.sok" -#define ROWS 16 -#define COLS 20 -#define SOKOBAN_LEVEL_SIZE (ROWS*COLS) -#define MAX_BUFFERED_BOARDS 500 -/* Use either all but 12k of the plugin buffer for board data - or just enough for MAX_BUFFERED_BOARDS, which ever is less */ -#if (PLUGIN_BUFFER_SIZE - 0x3000)/SOKOBAN_LEVEL_SIZE < MAX_BUFFERED_BOARDS -#define NUM_BUFFERED_BOARDS (PLUGIN_BUFFER_SIZE - 0x3000)/SOKOBAN_LEVEL_SIZE +/* Magnify is the number of pixels for each block. + * Set dynamically so all targets can support levels + * that fill their entire screen, less the stat box. + * 16 rows & 20 cols minimum */ +#if (LCD_HEIGHT >= 224) && (LCD_WIDTH >= 320) +#define MAGNIFY 14 +#define ROWS (LCD_HEIGHT/MAGNIFY) +#define COLS ((LCD_WIDTH-40)/MAGNIFY) +#elif (LCD_HEIGHT >= 249) && (LCD_WIDTH >= 280) +#define MAGNIFY 14 +#define ROWS ((LCD_HEIGHT-25)/MAGNIFY) +#define COLS (LCD_WIDTH/MAGNIFY) +#elif (LCD_HEIGHT >= 144) && (LCD_WIDTH >= 220) +#define MAGNIFY 9 +#define ROWS (LCD_HEIGHT/MAGNIFY) +#define COLS ((LCD_WIDTH-40)/MAGNIFY) +#elif (LCD_HEIGHT >= 169) && (LCD_WIDTH+4 >= 180) /* plus 4 for sansa */ +#define MAGNIFY 9 +#define ROWS ((LCD_HEIGHT-25)/MAGNIFY) +#define COLS ((LCD_WIDTH+4)/MAGNIFY) +#elif (LCD_HEIGHT >= 96) && (LCD_WIDTH >= 160) +#define MAGNIFY 6 +#define ROWS (LCD_HEIGHT/MAGNIFY) +#define COLS ((LCD_WIDTH-40)/MAGNIFY) +#elif (LCD_HEIGHT >= 121) && (LCD_WIDTH >= 120) +#define MAGNIFY 6 +#define ROWS ((LCD_HEIGHT-25)/MAGNIFY) +#define COLS (LCD_WIDTH/MAGNIFY) #else -#define NUM_BUFFERED_BOARDS MAX_BUFFERED_BOARDS +#define MAGNIFY 4 +#define ROWS 16 +#define COLS 20 #endif -/* Use 4k plus remaining plugin buffer (-8k for prog) for undo, up to 32k */ -#if PLUGIN_BUFFER_SIZE - NUM_BUFFERED_BOARDS*SOKOBAN_LEVEL_SIZE - 0x2000 > \ - 0x7FFF -#define MAX_UNDOS 0x7FFF + +/* Use either all but 16k of the plugin buffer for level data + * or 128k, which ever is less */ +#if PLUGIN_BUFFER_SIZE - 0x4000 < 0x20000 +#define MAX_LEVEL_DATA (PLUGIN_BUFFER_SIZE - 0x4000) #else -#define MAX_UNDOS PLUGIN_BUFFER_SIZE - \ - NUM_BUFFERED_BOARDS*SOKOBAN_LEVEL_SIZE - 0x2000 +#define MAX_LEVEL_DATA 0x20000 +#endif + +/* Number of levels for which to allocate buffer indexes */ +#define MAX_LEVELS MAX_LEVEL_DATA/70 + +/* Use 4k plus remaining plugin buffer (-12k for prog) for undo, up to 64k */ +#if PLUGIN_BUFFER_SIZE - MAX_LEVEL_DATA - 0x3000 > 0x10000 +#define MAX_UNDOS 0x10000 +#else +#define MAX_UNDOS (PLUGIN_BUFFER_SIZE - MAX_LEVEL_DATA - 0x3000) #endif /* Move/push definitions for undo */ -enum { - SOKOBAN_PUSH_LEFT, - SOKOBAN_PUSH_RIGHT, - SOKOBAN_PUSH_UP, - SOKOBAN_PUSH_DOWN, - SOKOBAN_MOVE_LEFT, - SOKOBAN_MOVE_RIGHT, - SOKOBAN_MOVE_UP, - SOKOBAN_MOVE_DOWN -}; -#define SOKOBAN_MOVE_DIFF (SOKOBAN_MOVE_LEFT-SOKOBAN_PUSH_LEFT) -#define SOKOBAN_MOVE_MIN SOKOBAN_MOVE_LEFT +#define SOKOBAN_PUSH_LEFT 'L' +#define SOKOBAN_PUSH_RIGHT 'R' +#define SOKOBAN_PUSH_UP 'U' +#define SOKOBAN_PUSH_DOWN 'D' +#define SOKOBAN_MOVE_LEFT 'l' +#define SOKOBAN_MOVE_RIGHT 'r' +#define SOKOBAN_MOVE_UP 'u' +#define SOKOBAN_MOVE_DOWN 'd' + +#define SOKOBAN_MOVE_DIFF (SOKOBAN_MOVE_LEFT-SOKOBAN_PUSH_LEFT) +#define SOKOBAN_MOVE_MIN SOKOBAN_MOVE_DOWN /* variable button definitions */ -#if CONFIG_KEYPAD == RECORDER_PAD +#if (CONFIG_KEYPAD == RECORDER_PAD) || \ + (CONFIG_KEYPAD == ARCHOS_AV300_PAD) #define SOKOBAN_UP BUTTON_UP #define SOKOBAN_DOWN BUTTON_DOWN -#define SOKOBAN_QUIT BUTTON_OFF +#define SOKOBAN_MENU BUTTON_OFF #define SOKOBAN_UNDO BUTTON_ON #define SOKOBAN_REDO BUTTON_PLAY -#define SOKOBAN_LEVEL_UP BUTTON_F3 #define SOKOBAN_LEVEL_DOWN BUTTON_F1 #define SOKOBAN_LEVEL_REPEAT BUTTON_F2 - -#elif CONFIG_KEYPAD == ARCHOS_AV300_PAD -#define SOKOBAN_UP BUTTON_UP -#define SOKOBAN_DOWN BUTTON_DOWN -#define SOKOBAN_QUIT BUTTON_OFF -#define SOKOBAN_UNDO BUTTON_ON -#define SOKOBAN_REDO BUTTON_PLAY #define SOKOBAN_LEVEL_UP BUTTON_F3 -#define SOKOBAN_LEVEL_DOWN BUTTON_F1 -#define SOKOBAN_LEVEL_REPEAT BUTTON_F2 +#define BUTTON_SAVE BUTTON_ON +#define BUTTON_SAVE_NAME "ON" #elif CONFIG_KEYPAD == ONDIO_PAD #define SOKOBAN_UP BUTTON_UP #define SOKOBAN_DOWN BUTTON_DOWN -#define SOKOBAN_QUIT BUTTON_OFF +#define SOKOBAN_MENU BUTTON_OFF #define SOKOBAN_UNDO_PRE BUTTON_MENU #define SOKOBAN_UNDO (BUTTON_MENU | BUTTON_REL) #define SOKOBAN_REDO (BUTTON_MENU | BUTTON_DOWN) -#define SOKOBAN_LEVEL_UP (BUTTON_MENU | BUTTON_RIGHT) #define SOKOBAN_LEVEL_DOWN (BUTTON_MENU | BUTTON_LEFT) #define SOKOBAN_LEVEL_REPEAT (BUTTON_MENU | BUTTON_UP) +#define SOKOBAN_LEVEL_UP (BUTTON_MENU | BUTTON_RIGHT) +#define BUTTON_SAVE BUTTON_MENU +#define BUTTON_SAVE_NAME "MENU" #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ (CONFIG_KEYPAD == IRIVER_H300_PAD) #define SOKOBAN_UP BUTTON_UP #define SOKOBAN_DOWN BUTTON_DOWN -#define SOKOBAN_QUIT BUTTON_OFF +#define SOKOBAN_MENU BUTTON_OFF #define SOKOBAN_UNDO BUTTON_REC #define SOKOBAN_REDO BUTTON_MODE -#define SOKOBAN_LEVEL_UP (BUTTON_ON | BUTTON_UP) #define SOKOBAN_LEVEL_DOWN (BUTTON_ON | BUTTON_DOWN) #define SOKOBAN_LEVEL_REPEAT BUTTON_ON +#define SOKOBAN_LEVEL_UP (BUTTON_ON | BUTTON_UP) +#define BUTTON_SAVE BUTTON_MODE +#define BUTTON_SAVE_NAME "MODE" #define SOKOBAN_RC_QUIT BUTTON_RC_STOP @@ -115,65 +147,70 @@ enum { (CONFIG_KEYPAD == IPOD_3G_PAD) #define SOKOBAN_UP BUTTON_MENU #define SOKOBAN_DOWN BUTTON_PLAY -#define SOKOBAN_QUIT (BUTTON_SELECT | BUTTON_MENU) +#define SOKOBAN_MENU (BUTTON_SELECT | BUTTON_MENU) #define SOKOBAN_UNDO_PRE BUTTON_SELECT #define SOKOBAN_UNDO (BUTTON_SELECT | BUTTON_REL) #define SOKOBAN_REDO (BUTTON_SELECT | BUTTON_PLAY) -#define SOKOBAN_LEVEL_UP (BUTTON_SELECT | BUTTON_RIGHT) #define SOKOBAN_LEVEL_DOWN (BUTTON_SELECT | BUTTON_LEFT) +#define SOKOBAN_LEVEL_UP (BUTTON_SELECT | BUTTON_RIGHT) +#define BUTTON_SAVE BUTTON_SELECT +#define BUTTON_SAVE_NAME "SELECT" -/* fixme: if/when simultaneous button presses work for X5, - add redo & level repeat */ -#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) +/* FIXME: if/when simultaneous button presses work for X5, + * add redo & level repeat */ +#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD #define SOKOBAN_UP BUTTON_UP #define SOKOBAN_DOWN BUTTON_DOWN -#define SOKOBAN_QUIT BUTTON_POWER +#define SOKOBAN_MENU BUTTON_POWER #define SOKOBAN_UNDO_PRE BUTTON_SELECT #define SOKOBAN_UNDO (BUTTON_SELECT | BUTTON_REL) -#define SOKOBAN_LEVEL_UP BUTTON_PLAY #define SOKOBAN_LEVEL_DOWN BUTTON_REC +#define SOKOBAN_LEVEL_UP BUTTON_PLAY +#define BUTTON_SAVE BUTTON_SELECT +#define BUTTON_SAVE_NAME "SELECT" -#elif (CONFIG_KEYPAD == GIGABEAT_PAD) -#define SOKOBAN_UP BUTTON_UP -#define SOKOBAN_DOWN BUTTON_DOWN -#define SOKOBAN_QUIT BUTTON_POWER -#define SOKOBAN_UNDO BUTTON_SELECT -#define SOKOBAN_REDO BUTTON_A -#define SOKOBAN_LEVEL_UP BUTTON_VOL_UP -#define SOKOBAN_LEVEL_DOWN BUTTON_VOL_DOWN -#define SOKOBAN_LEVEL_REPEAT BUTTON_MENU - -#elif (CONFIG_KEYPAD == SANSA_E200_PAD) -#define SOKOBAN_UP BUTTON_UP -#define SOKOBAN_DOWN BUTTON_DOWN -#define SOKOBAN_QUIT BUTTON_POWER -#define SOKOBAN_UNDO_PRE BUTTON_SELECT -#define SOKOBAN_UNDO (BUTTON_SELECT | BUTTON_REL) -#define SOKOBAN_REDO BUTTON_REC -#define SOKOBAN_LEVEL_UP (BUTTON_SELECT | BUTTON_UP) -#define SOKOBAN_LEVEL_DOWN (BUTTON_SELECT | BUTTON_DOWN) -#define SOKOBAN_LEVEL_REPEAT (BUTTON_SELECT | BUTTON_RIGHT) - -#elif (CONFIG_KEYPAD == IRIVER_H10_PAD) +#elif CONFIG_KEYPAD == IRIVER_H10_PAD #define SOKOBAN_UP BUTTON_SCROLL_UP #define SOKOBAN_DOWN BUTTON_SCROLL_DOWN -#define SOKOBAN_QUIT BUTTON_POWER +#define SOKOBAN_MENU BUTTON_POWER #define SOKOBAN_UNDO_PRE BUTTON_REW #define SOKOBAN_UNDO (BUTTON_REW | BUTTON_REL) #define SOKOBAN_REDO BUTTON_FF -#define SOKOBAN_LEVEL_UP (BUTTON_PLAY | BUTTON_SCROLL_UP) #define SOKOBAN_LEVEL_DOWN (BUTTON_PLAY | BUTTON_SCROLL_DOWN) #define SOKOBAN_LEVEL_REPEAT (BUTTON_PLAY | BUTTON_RIGHT) +#define SOKOBAN_LEVEL_UP (BUTTON_PLAY | BUTTON_SCROLL_UP) +#define BUTTON_SAVE BUTTON_PLAY +#define BUTTON_SAVE_NAME "PLAY" + +#elif CONFIG_KEYPAD == GIGABEAT_PAD +#define SOKOBAN_UP BUTTON_UP +#define SOKOBAN_DOWN BUTTON_DOWN +#define SOKOBAN_MENU BUTTON_POWER +#define SOKOBAN_UNDO BUTTON_SELECT +#define SOKOBAN_REDO BUTTON_A +#define SOKOBAN_LEVEL_DOWN BUTTON_VOL_DOWN +#define SOKOBAN_LEVEL_REPEAT BUTTON_MENU +#define SOKOBAN_LEVEL_UP BUTTON_VOL_UP +#define BUTTON_SAVE BUTTON_SELECT +#define BUTTON_SAVE_NAME "SELECT" + +#elif CONFIG_KEYPAD == SANSA_E200_PAD +#define SOKOBAN_UP BUTTON_UP +#define SOKOBAN_DOWN BUTTON_DOWN +#define SOKOBAN_MENU BUTTON_POWER +#define SOKOBAN_UNDO_PRE BUTTON_SELECT +#define SOKOBAN_UNDO (BUTTON_SELECT | BUTTON_REL) +#define SOKOBAN_REDO BUTTON_REC +#define SOKOBAN_LEVEL_DOWN (BUTTON_SELECT | BUTTON_DOWN) +#define SOKOBAN_LEVEL_REPEAT (BUTTON_SELECT | BUTTON_RIGHT) +#define SOKOBAN_LEVEL_UP (BUTTON_SELECT | BUTTON_UP) +#define BUTTON_SAVE BUTTON_SELECT +#define BUTTON_SAVE_NAME "SELECT" #endif -#ifdef HAVE_LCD_COLOR -/* Background color. Default Rockbox light blue. */ -#define BG_COLOR LCD_RGBPACK(181, 199, 231) +#define SOKOBAN_FONT FONT_SYSFIXED -#elif LCD_DEPTH >= 2 -#define MEDIUM_GRAY LCD_BRIGHTNESS(127) -#endif /* The Location, Undo and LevelInfo structs are OO-flavored. * (oooh!-flavored as Schnueff puts it.) It makes more you have to know, @@ -181,10 +218,12 @@ enum { /* Level data & stats */ struct LevelInfo { - short level; - short moves; - short pushes; - short boxes_to_go; + short index; /* Level index (level number - 1) */ + int moves; /* Moves & pushes for the stats */ + int pushes; + short boxes_to_go; /* Number of unplaced boxes remaining in level */ + short height; /* Height & width for centering level display */ + short width; }; struct Location { @@ -192,39 +231,42 @@ struct Location { short col; }; -struct Board { - char spaces[ROWS][COLS]; -}; - /* Our full undo history */ static struct UndoInfo { - short count; /* How many undos are left */ - short current; /* Which history is the current undo */ - short max; /* Which history is the max redoable */ + int count; /* How many undos have been done */ + int current; /* Which history is the current undo */ + int max; /* Which history is the max redoable */ char history[MAX_UNDOS]; } undo_info; /* Our playing board */ static struct BoardInfo { - char board[ROWS][COLS]; - struct LevelInfo level; - struct Location player; - int max_level; /* How many levels do we have? */ - int loaded_level; /* Which level is in memory */ + char board[ROWS][COLS]; /* The current board data */ + struct LevelInfo level; /* Level data & stats */ + struct Location player; /* Where the player is */ + int max_level; /* The number of levels we have */ } current_info; static struct BufferedBoards { - struct Board levels[NUM_BUFFERED_BOARDS]; - int low; + char filename[MAX_PATH]; /* Filename of the levelset we're using */ + char data[MAX_LEVEL_DATA]; /* Buffered level data */ + int index[MAX_LEVELS + 1]; /* Where each buffered board begins & ends */ + int start; /* Index of first buffered board */ + int end; /* Index of last buffered board */ + short prebuffered_boards; /* Number of boards before current to store */ } buffered_boards; + static struct plugin_api* rb; +static char buf[ROWS*(COLS + 1)]; /* Enough for a whole board or a filename */ + + static void init_undo(void) { undo_info.count = 0; - undo_info.current = -1; - undo_info.max = -1; + undo_info.current = 0; + undo_info.max = 0; } static void get_delta(char direction, short *d_r, short *d_c) @@ -261,9 +303,17 @@ static void undo(void) bool undo_push = false; /* If no more undos or we've wrapped all the way around, quit */ - if (undo_info.count == 0 || undo_info.current-1 == undo_info.max) + if (undo_info.count == 0 || undo_info.current - 1 == undo_info.max) return; + /* Move to previous undo in the list */ + if (undo_info.current == 0 && undo_info.count > 1) + undo_info.current = MAX_UNDOS - 1; + else + undo_info.current--; + + undo_info.count--; + undo = undo_info.history[undo_info.current]; if (undo < SOKOBAN_MOVE_MIN) @@ -281,17 +331,17 @@ static void undo(void) /* Update board info */ if (undo_push) { - /* Moving box from goal to blank */ - if (*space_next == '%' && *space_cur == '@') + /* Moving box from goal to floor */ + if (*space_next == '*' && *space_cur == '@') current_info.level.boxes_to_go++; - /* Moving box from blank to goal */ + /* Moving box from floor to goal */ else if (*space_next == '$' && *space_cur == '+') current_info.level.boxes_to_go--; /* Move box off of next space... */ - *space_next = (*space_next == '%' ? '.' : ' '); + *space_next = (*space_next == '*' ? '.' : ' '); /* ...and on to current space */ - *space_cur = (*space_cur == '+' ? '%' : '$'); + *space_cur = (*space_cur == '+' ? '*' : '$'); current_info.level.pushes--; } else @@ -306,27 +356,19 @@ static void undo(void) current_info.level.moves--; - /* Move to previous undo in the list */ - if (undo_info.current == 0 && undo_info.count > 1) - undo_info.current = MAX_UNDOS - 1; - else - undo_info.current--; - - undo_info.count--; - return; } static void add_undo(char undo) { + undo_info.history[undo_info.current] = undo; + /* Wrap around if MAX_UNDOS exceeded */ if (undo_info.current < (MAX_UNDOS - 1)) undo_info.current++; else undo_info.current = 0; - undo_info.history[undo_info.current] = undo; - if (undo_info.count < MAX_UNDOS) undo_info.count++; } @@ -353,34 +395,37 @@ static bool move(char direction, bool redo) space_next = ¤t_info.board[r + d_r][c + d_c]; space_beyond = ¤t_info.board[r + 2*d_r][c + 2*d_c]; - if (*space_next == '$' || *space_next == '%') { + if (*space_next == '$' || *space_next == '*') { /* Change direction from move to push for undo */ if (direction >= SOKOBAN_MOVE_MIN) direction -= SOKOBAN_MOVE_DIFF; push = true; } + else if (direction < SOKOBAN_MOVE_MIN) + /* Change back to move if redo/solution playback push is invalid */ + direction += SOKOBAN_MOVE_DIFF; /* Update board info */ if (push) { - /* Moving box from goal to blank */ - if (*space_next == '%' && *space_beyond == ' ') + /* Moving box from goal to floor */ + if (*space_next == '*' && *space_beyond == ' ') current_info.level.boxes_to_go++; - /* Moving box from blank to goal */ + /* Moving box from floor to goal */ else if (*space_next == '$' && *space_beyond == '.') current_info.level.boxes_to_go--; - /* Check for illegal move */ + /* Check for invalid move */ else if (*space_beyond != '.' && *space_beyond != ' ') return false; /* Move player onto next space */ - *space_next = (*space_next == '%' ? '+' : '@'); + *space_next = (*space_next == '*' ? '+' : '@'); /* Move box onto space beyond next */ - *space_beyond = (*space_beyond == '.' ? '%' : '$'); + *space_beyond = (*space_beyond == '.' ? '*' : '$'); current_info.level.pushes++; } else { - /* Check for illegal move */ - if (*space_next == '#' || *space_next == 'X') + /* Check for invalid move */ + if (*space_next != '.' && *space_next != ' ') return false; /* Move player onto next space */ @@ -396,19 +441,19 @@ static bool move(char direction, bool redo) current_info.level.moves++; /* Update undo_info.max to current on every normal move, - except if it's the same as a redo. */ - /* normal move */ + * except if it's the same as a redo. */ + /* normal move and either */ if (!redo && - /* moves have been undone */ + /* moves have been undone... */ ((undo_info.max != undo_info.current && - /* and the current move is NOT the same as the one in history */ - undo_info.history[undo_info.current+1] != direction) || + /* ...and the current move is NOT the same as the one in history */ + undo_info.history[undo_info.current] != direction) || /* or moves have not been undone */ undo_info.max == undo_info.current)) { add_undo(direction); undo_info.max = undo_info.current; } else /* redo move or move was same as redo */ - add_undo(direction); /* (just to update current) */ + add_undo(direction); /* add_undo to update current */ return true; } @@ -420,291 +465,371 @@ static bool redo(void) if (undo_info.current == undo_info.max) return false; - return move(undo_info.history[(undo_info.current+1 < MAX_UNDOS ? - undo_info.current+1 : 0)], true); + return move(undo_info.history[(undo_info.current < MAX_UNDOS ? + undo_info.current : 0)], true); } #endif static void init_boards(void) { - current_info.level.level = 0; - current_info.level.moves = 0; - current_info.level.pushes = 0; - current_info.level.boxes_to_go = 0; + rb->strncpy(buffered_boards.filename, SOKOBAN_LEVELS_FILE, MAX_PATH); + + current_info.level.index = 0; current_info.player.row = 0; current_info.player.col = 0; current_info.max_level = 0; - current_info.loaded_level = 0; - buffered_boards.low = 0; + buffered_boards.start = 0; + buffered_boards.end = 0; + buffered_boards.prebuffered_boards = 0; init_undo(); } -static int read_levels(int initialize_count) +static bool read_levels(bool initialize) { int fd = 0; - int len; - int lastlen = 0; - int row = 0; + short len; + short lastlen = 0; + short row = 0; int level_count = 0; - char buffer[COLS + 3]; /* COLS plus CR/LF and \0 */ - int endpoint = current_info.level.level-1; - if (endpoint < buffered_boards.low) - endpoint = current_info.level.level - NUM_BUFFERED_BOARDS; + int i = 0; + int level_len = 0; + bool index_set = false; - if (endpoint < 0) endpoint = 0; + /* Get the index of the first level to buffer */ + if (current_info.level.index > buffered_boards.prebuffered_boards && + !initialize) + buffered_boards.start = current_info.level.index - + buffered_boards.prebuffered_boards; + else + buffered_boards.start = 0; - buffered_boards.low = endpoint; - endpoint += NUM_BUFFERED_BOARDS; - - if ((fd = rb->open(LEVELS_FILE, O_RDONLY)) < 0) { - rb->splash(HZ*2, "Unable to open %s", LEVELS_FILE); - return -1; + if ((fd = rb->open(buffered_boards.filename, O_RDONLY)) < 0) { + rb->splash(HZ*2, "Unable to open %s", buffered_boards.filename); + return false; } do { - len = rb->read_line(fd, buffer, sizeof(buffer)); - if (len >= 3) { - /* This finds lines that are more than 1 or 2 characters - * shorter than they should be. Due to the possibility of - * a mixed unix and dos CR/LF file format, I'm not going to - * do a precise check */ - if (len < COLS) { - rb->splash(HZ*2, "Error in levels file: short line"); - return -1; - } - if (level_count >= buffered_boards.low && level_count < endpoint) { - int index = level_count - buffered_boards.low; - rb->memcpy( - buffered_boards.levels[index].spaces[row], buffer, COLS); - } - row++; - } else if (len) { - if (lastlen < 3) { - /* Two short lines in a row means new level */ - level_count++; - if (level_count >= endpoint && !initialize_count) break; - if (level_count && row != ROWS) { - rb->splash(HZ*2, "Error in levels file: short board"); - return -1; + len = rb->read_line(fd, buf, sizeof(buf)); + + /* Correct len when trailing \r's or \n's are counted */ + if (len > 2 && buf[len - 2] == '\0') + len -= 2; + else if (len > 1 && buf[len - 1] == '\0') + len--; + + /* Skip short lines & lines with non-level data */ + if (len >= 3 && ((buf[0] >= '1' && buf[0] <= '9') || buf[0] == '#' || + buf[0] == ' ' || buf[0] == '-' || buf[0] == '_')) { + if (level_count >= buffered_boards.start) { + /* Set the index of this level */ + if (!index_set && + level_count - buffered_boards.start < MAX_LEVELS) { + buffered_boards.index[level_count - buffered_boards.start] + = i; + index_set = true; + } + /* Copy buffer to board data */ + if (i + level_len + len < MAX_LEVEL_DATA) { + rb->memcpy(&buffered_boards.data[i + level_len], buf, len); + buffered_boards.data[i + level_len + len] = '\n'; } - row = 0; } - } - } while ((lastlen=len)); + level_len += len + 1; + row++; + + /* If newline & level is tall enough or is RLE */ + } else if (buf[0] == '\0' && (row > 2 || lastlen > 22)) { + level_count++; + if (level_count >= buffered_boards.start) { + i += level_len; + if (i < MAX_LEVEL_DATA) + buffered_boards.end = level_count; + else if (!initialize) + break; + } + row = 0; + level_len = 0; + index_set = false; + + } else if (len > 22) + len = 1; + + } while ((lastlen = len)); + + /* Set the index of the end of the last level */ + if (level_count - buffered_boards.start < MAX_LEVELS) + buffered_boards.index[level_count - buffered_boards.start] = i; + + if (initialize) { + current_info.max_level = level_count; + buffered_boards.prebuffered_boards = buffered_boards.end/2; + } rb->close(fd); - if (initialize_count) { - /* Plus one because there aren't trailing short lines in the file */ - current_info.max_level = level_count + 1; - } - return 0; + + return true; } -/* return non-zero on error */ static void load_level(void) { - int c = 0; - int r = 0; - int index = current_info.level.level - buffered_boards.low - 1; - struct Board *level; + int c, r; + int i, n; + int level_size; + int index = current_info.level.index - buffered_boards.start; + char *level; - if (index < 0 || index >= NUM_BUFFERED_BOARDS) { + /* Get the buffered board index of the current level */ + if (current_info.level.index < buffered_boards.start || + current_info.level.index >= buffered_boards.end) { read_levels(false); - index = index < 0 ? NUM_BUFFERED_BOARDS-1 : 0; + if (current_info.level.index > buffered_boards.prebuffered_boards) + index = buffered_boards.prebuffered_boards; + else + index = current_info.level.index; } - level = &buffered_boards.levels[index]; + level = &buffered_boards.data[buffered_boards.index[index]]; - current_info.level.boxes_to_go = 0; + /* Reset level info */ current_info.level.moves = 0; current_info.level.pushes = 0; - current_info.loaded_level = current_info.level.level; + current_info.level.boxes_to_go = 0; + current_info.level.width = 0; - for (r = 0; r < ROWS; r++) { - for (c = 0; c < COLS; c++) { - current_info.board[r][c] = level->spaces[r][c]; + /* Clear board */ + for (r = 0; r < ROWS; r++) + for (c = 0; c < COLS; c++) + current_info.board[r][c] = 'X'; - if (current_info.board[r][c] == '.' || - current_info.board[r][c] == '+') - current_info.level.boxes_to_go++; + level_size = buffered_boards.index[index + 1] - + buffered_boards.index[index]; - if (current_info.board[r][c] == '@' || - current_info.board[r][c] == '+') { - current_info.player.row = r; - current_info.player.col = c; + for (r = 0, c = 0, n = 1, i = 0; i < level_size; i++) { + if (level[i] == '\n' || level[i] == '|') { + if (c > 3) { + /* Update max width of level & go to next row */ + if (c > current_info.level.width) + current_info.level.width = c; + c = 0; + r++; + if (r >= ROWS) + break; + } + } else if (c < COLS) { + /* Read RLE character's length into n */ + if (level[i] >= '0' && level[i] <= '9') { + n = level[i++] - '0'; + if (level[i] >= '0' && level[i] <= '9') + n = n*10 + level[i++] - '0'; + } + + /* Cleanup & replace */ + if (level[i] == '%') + level[i] = '*'; + else if (level[i] == '-' || level[i] == '_') + level[i] = ' '; + + if (n > 1) { + if (c + n >= COLS) + n = COLS - c; + + if (level[i] == '.') + current_info.level.boxes_to_go += n; + + /* Put RLE character n times */ + while (n--) + current_info.board[r][c++] = level[i]; + n = 1; + + } else { + if (level[i] == '.' || level[i] == '+') + current_info.level.boxes_to_go++; + + if (level[i] == '@' ||level[i] == '+') { + current_info.player.row = r; + current_info.player.col = c; + } + + current_info.board[r][c++] = level[i]; } } } + + current_info.level.height = r; + +#if LCD_DEPTH > 2 + /* Fill in blank space outside level on color targets */ + for (r = 0; r < ROWS; r++) + for (c = 0; current_info.board[r][c] == ' ' && c < COLS; c++) + current_info.board[r][c] = 'X'; + + for (c = 0; c < COLS; c++) { + for (r = 0; (current_info.board[r][c] == ' ' || + current_info.board[r][c] == 'X') && r < ROWS; r++) + current_info.board[r][c] = 'X'; + for (r = ROWS - 1; (current_info.board[r][c] == ' ' || + current_info.board[r][c] == 'X') && r >= 0; r--) + current_info.board[r][c] = 'X'; + } +#endif } static void update_screen(void) { - int b = 0, c = 0; - int rows = 0, cols = 0; - char s[25]; + int c, r; + int rows, cols; -/* magnify is the number of pixels for each block */ -#if (LCD_HEIGHT >= 224) && (LCD_WIDTH >= 312) || \ - (LCD_HEIGHT >= 249) && (LCD_WIDTH >= 280) /* ipod 5g */ -#define MAGNIFY 14 -#elif (LCD_HEIGHT >= 144) && (LCD_WIDTH >= 212) || \ - (LCD_HEIGHT >= 169) && (LCD_WIDTH >= 180-4) /* h3x0, ipod color/photo */ -#define MAGNIFY 9 -#elif (LCD_HEIGHT >= 96) && (LCD_WIDTH >= 152) || \ - (LCD_HEIGHT >= 121) && (LCD_WIDTH >= 120) /* h1x0, ipod nano/mini */ -#define MAGNIFY 6 -#else /* other */ -#define MAGNIFY 4 -#endif - -#if LCD_DEPTH < 2 +#if LCD_DEPTH < 2 || ((LCD_HEIGHT < 96 || LCD_WIDTH < 152) && \ + (LCD_HEIGHT < 121 || LCD_WIDTH < 120)) int i, j; int max = MAGNIFY - 1; - int middle = max / 2; - int ldelta = (middle + 1) / 2; + int middle = max/2; + int ldelta = (middle + 1)/2; +#endif + +#if LCD_WIDTH - (COLS*MAGNIFY) < 32 +#define STAT_HEIGHT 25 +#define STAT_X (LCD_WIDTH - 120)/2 +#define STAT_Y (LCD_HEIGHT - STAT_HEIGHT) +#define BOARD_WIDTH LCD_WIDTH +#define BOARD_HEIGHT (LCD_HEIGHT - STAT_HEIGHT) + rb->lcd_putsxy(STAT_X + 4, STAT_Y + 4, "Level"); + rb->snprintf(buf, sizeof(buf), "%d", current_info.level.index + 1); + rb->lcd_putsxy(STAT_X + 7, STAT_Y + 14, buf); + rb->lcd_putsxy(STAT_X + 41, STAT_Y + 4, "Moves"); + rb->snprintf(buf, sizeof(buf), "%d", current_info.level.moves); + rb->lcd_putsxy(STAT_X + 44, STAT_Y + 14, buf); + rb->lcd_putsxy(STAT_X + 79, STAT_Y + 4, "Pushes"); + rb->snprintf(buf, sizeof(buf), "%d", current_info.level.pushes); + rb->lcd_putsxy(STAT_X + 82, STAT_Y + 14, buf); + + rb->lcd_drawrect(STAT_X, STAT_Y, 38, STAT_HEIGHT); + rb->lcd_drawrect(STAT_X + 37, STAT_Y, 39, STAT_HEIGHT); + rb->lcd_drawrect(STAT_X + 75, STAT_Y, 45, STAT_HEIGHT); +#else +#if LCD_WIDTH - (COLS*MAGNIFY) > 40 +#define STAT_X (LCD_WIDTH - 40) +#else +#define STAT_X COLS*MAGNIFY +#endif +#if LCD_HEIGHT >= 70 +#define STAT_Y (LCD_HEIGHT - 70)/2 +#else +#define STAT_Y (LCD_HEIGHT - 47)/2 +#endif +#define STAT_WIDTH (LCD_WIDTH - STAT_X) +#define BOARD_WIDTH (LCD_WIDTH - STAT_WIDTH) +#define BOARD_HEIGHT LCD_HEIGHT + rb->lcd_putsxy(STAT_X + 1, STAT_Y + 3, "Level"); + rb->snprintf(buf, sizeof(buf), "%d", current_info.level.index + 1); + rb->lcd_putsxy(STAT_X + 4, STAT_Y + 13, buf); + rb->lcd_putsxy(STAT_X + 1, STAT_Y + 26, "Moves"); + rb->snprintf(buf, sizeof(buf), "%d", current_info.level.moves); + rb->lcd_putsxy(STAT_X + 4, STAT_Y + 36, buf); + + rb->lcd_drawrect(STAT_X, STAT_Y + 0, STAT_WIDTH, 24); + rb->lcd_drawrect(STAT_X, STAT_Y + 23, STAT_WIDTH, 24); + +#if LCD_HEIGHT >= 70 + rb->lcd_putsxy(STAT_X + 1, STAT_Y + 49, "Pushes"); + rb->snprintf(buf, sizeof(buf), "%d", current_info.level.pushes); + rb->lcd_putsxy(STAT_X + 4, STAT_Y + 59, buf); + + rb->lcd_drawrect(STAT_X, STAT_Y + 46, STAT_WIDTH, 24); +#endif + #endif /* load the board to the screen */ - for (rows=0; rows < ROWS; rows++) { + for (rows = 0; rows < ROWS; rows++) { for (cols = 0; cols < COLS; cols++) { - c = cols * MAGNIFY; - b = rows * MAGNIFY; + c = cols*MAGNIFY + + (BOARD_WIDTH - current_info.level.width*MAGNIFY)/2; + r = rows*MAGNIFY + + (BOARD_HEIGHT - current_info.level.height*MAGNIFY)/2; switch(current_info.board[rows][cols]) { - case 'X': /* black space */ - break; + case 'X': /* blank space outside of level */ + break; - case '#': /* this is a wall */ -#if LCD_DEPTH >= 2 - rb->lcd_bitmap_part(sokoban_tiles, 0, 1*MAGNIFY, MAGNIFY, - c, b, MAGNIFY, MAGNIFY); +#if LCD_DEPTH >= 2 && ((LCD_HEIGHT >= 96 && LCD_WIDTH >= 152) || \ + (LCD_HEIGHT >= 121 && LCD_WIDTH >= 120)) + case ' ': /* floor */ + rb->lcd_bitmap_part(sokoban_tiles, 0, 0*MAGNIFY, MAGNIFY, + c, r, MAGNIFY, MAGNIFY); + break; + + case '#': /* wall */ + rb->lcd_bitmap_part(sokoban_tiles, 0, 1*MAGNIFY, MAGNIFY, + c, r, MAGNIFY, MAGNIFY); + break; + + case '$': /* box */ + rb->lcd_bitmap_part(sokoban_tiles, 0, 2*MAGNIFY, MAGNIFY, + c, r, MAGNIFY, MAGNIFY); + break; + + case '*': /* box on goal */ + rb->lcd_bitmap_part(sokoban_tiles, 0, 3*MAGNIFY, MAGNIFY, + c, r, MAGNIFY, MAGNIFY); + break; + + case '.': /* goal */ + rb->lcd_bitmap_part(sokoban_tiles, 0, 4*MAGNIFY, MAGNIFY, + c, r, MAGNIFY, MAGNIFY); + break; + + case '@': /* player */ + rb->lcd_bitmap_part(sokoban_tiles, 0, 5*MAGNIFY, MAGNIFY, + c, r, MAGNIFY, MAGNIFY); + break; + + case '+': /* player on goal */ + rb->lcd_bitmap_part(sokoban_tiles, 0, 6*MAGNIFY, MAGNIFY, + c, r, MAGNIFY, MAGNIFY); + break; #else - for (i = c; i < c + MAGNIFY; i++) - for (j = b; j < b + MAGNIFY; j++) - if ((i ^ j) & 1) - rb->lcd_drawpixel(i, j); -#endif - break; + case '#': /* wall */ + for (i = c; i < c + MAGNIFY; i++) + for (j = r; j < r + MAGNIFY; j++) + if ((i ^ j) & 1) + rb->lcd_drawpixel(i, j); + break; - case '$': /* this is a box */ -#if LCD_DEPTH >= 2 - rb->lcd_bitmap_part(sokoban_tiles, 0, 2*MAGNIFY, MAGNIFY, - c, b, MAGNIFY, MAGNIFY); -#else - /* Free boxes are not filled in */ - rb->lcd_drawrect(c, b, MAGNIFY, MAGNIFY); -#endif - break; + case '$': /* box */ + rb->lcd_drawrect(c, r, MAGNIFY, MAGNIFY); + break; - case '*': - case '%': /* this is a box on a goal */ + case '*': /* box on goal */ + rb->lcd_drawrect(c, r, MAGNIFY, MAGNIFY); + rb->lcd_drawrect(c + MAGNIFY/2 - 1, r + MAGNIFY/2 - 1, + MAGNIFY/2, MAGNIFY/2); + break; -#if LCD_DEPTH >= 2 - rb->lcd_bitmap_part(sokoban_tiles, 0, 3*MAGNIFY, MAGNIFY, - c, b, MAGNIFY, MAGNIFY ); -#else - rb->lcd_drawrect(c, b, MAGNIFY, MAGNIFY); - rb->lcd_drawrect(c+(MAGNIFY/2)-1, b+(MAGNIFY/2)-1, MAGNIFY/2, - MAGNIFY/2); -#endif - break; + case '.': /* goal */ + rb->lcd_drawrect(c + MAGNIFY/2 - 1, r + MAGNIFY/2 - 1, + MAGNIFY/2, MAGNIFY/2); + break; - case '.': /* this is a goal */ -#if LCD_DEPTH >= 2 - rb->lcd_bitmap_part(sokoban_tiles, 0, 4*MAGNIFY, MAGNIFY, - c, b, MAGNIFY, MAGNIFY); -#else - rb->lcd_drawrect(c+(MAGNIFY/2)-1, b+(MAGNIFY/2)-1, MAGNIFY/2, - MAGNIFY/2); -#endif - break; - - case '@': /* this is you */ -#if LCD_DEPTH >= 2 - rb->lcd_bitmap_part(sokoban_tiles, 0, 5*MAGNIFY, MAGNIFY, - c, b, MAGNIFY, MAGNIFY); -#else - rb->lcd_drawline(c, b+middle, c+max, b+middle); - rb->lcd_drawline(c+middle, b, c+middle, b+max-ldelta); - rb->lcd_drawline(c+max-middle, b, - c+max-middle, b+max-ldelta); - rb->lcd_drawline(c+middle, b+max-ldelta, - c+middle-ldelta, b+max); - rb->lcd_drawline(c+max-middle, b+max-ldelta, - c+max-middle+ldelta, b+max); -#endif - break; - - case '+': /* this is you on drugs, erm, on a goal */ -#if LCD_DEPTH >= 2 - rb->lcd_bitmap_part(sokoban_tiles, 0, 6*MAGNIFY, MAGNIFY, - c, b, MAGNIFY, MAGNIFY ); -#else - rb->lcd_drawline(c, b+middle, c+max, b+middle); - rb->lcd_drawline(c+middle, b, c+middle, b+max-ldelta); - rb->lcd_drawline(c+max-middle, b, c+max-middle, b+max-ldelta); - rb->lcd_drawline(c+middle, b+max-ldelta, c+middle-ldelta, - b+max); - rb->lcd_drawline(c+max-middle, b+max-ldelta, - c+max-middle+ldelta, b+max); - rb->lcd_drawline(c+middle-1, b+middle+1, c+max-middle+1, - b+middle+1); -#endif - break; - -#if LCD_DEPTH >= 2 - default: - rb->lcd_bitmap_part(sokoban_tiles, 0, 0*MAGNIFY, MAGNIFY, - c, b, MAGNIFY, MAGNIFY ); + case '@': /* player */ + case '+': /* player on goal */ + rb->lcd_drawline(c, r + middle, c + max, r + middle); + rb->lcd_drawline(c + middle, r, c + middle, + r + max - ldelta); + rb->lcd_drawline(c + max - middle, r, c + max - middle, + r + max - ldelta); + rb->lcd_drawline(c + middle, r + max - ldelta, + c + middle - ldelta, r + max); + rb->lcd_drawline(c + max - middle, r + max - ldelta, + c + max - middle + ldelta, r + max); + break; #endif } } } -#if LCD_WIDTH-(COLS*MAGNIFY) < 32 -#define STAT_SIZE 25 -#define STAT_POS LCD_HEIGHT-STAT_SIZE -#define STAT_CENTER (LCD_WIDTH-120)/2 - - rb->lcd_putsxy(4+STAT_CENTER, STAT_POS+4, "Level"); - rb->snprintf(s, sizeof(s), "%d", current_info.level.level); - rb->lcd_putsxy(7+STAT_CENTER, STAT_POS+14, s); - rb->lcd_putsxy(41+STAT_CENTER, STAT_POS+4, "Moves"); - rb->snprintf(s, sizeof(s), "%d", current_info.level.moves); - rb->lcd_putsxy(44+STAT_CENTER, STAT_POS+14, s); - rb->lcd_putsxy(79+STAT_CENTER, STAT_POS+4, "Pushes"); - rb->snprintf(s, sizeof(s), "%d", current_info.level.pushes); - rb->lcd_putsxy(82+STAT_CENTER, STAT_POS+14, s); - - rb->lcd_drawrect(STAT_CENTER, STAT_POS, 38, STAT_SIZE); - rb->lcd_drawrect(37+STAT_CENTER, STAT_POS, 39, STAT_SIZE); - rb->lcd_drawrect(75+STAT_CENTER, STAT_POS, 45, STAT_SIZE); - -#else -#define STAT_POS COLS*MAGNIFY -#define STAT_SIZE LCD_WIDTH-STAT_POS - - rb->lcd_putsxy(STAT_POS+1, 3, "Level"); - rb->snprintf(s, sizeof(s), "%d", current_info.level.level); - rb->lcd_putsxy(STAT_POS+4, 13, s); - rb->lcd_putsxy(STAT_POS+1, 26, "Moves"); - rb->snprintf(s, sizeof(s), "%d", current_info.level.moves); - rb->lcd_putsxy(STAT_POS+4, 36, s); - - rb->lcd_drawrect(STAT_POS, 0, STAT_SIZE, 24); - rb->lcd_drawrect(STAT_POS, 23, STAT_SIZE, 24); - -#if LCD_HEIGHT >= 70 - rb->lcd_putsxy(STAT_POS+1, 49, "Pushes"); - rb->snprintf(s, sizeof(s), "%d", current_info.level.pushes); - rb->lcd_putsxy(STAT_POS+4, 59, s); - - rb->lcd_drawrect(STAT_POS, 46, STAT_SIZE, 24); -#endif -#endif - /* print out the screen */ rb->lcd_update(); } @@ -716,21 +841,320 @@ static void draw_level(void) update_screen(); } +static bool save(char *filename, bool solution) +{ + int fd; + + rb->splash(0, "Saving..."); + + if (filename[0] == '\0' || + (fd = rb->open(filename, O_WRONLY|O_CREAT|O_TRUNC)) < 0) { + rb->splash(HZ*2, "Unable to open %s", filename); + return false; + } + + /* Sokoban: S/P for solution/progress : level number : current undo */ + rb->snprintf(buf, sizeof(buf), "Sokoban:%c:%d:%d\n", (solution ? 'S' : 'P'), + current_info.level.index + 1, undo_info.current); + rb->write(fd, buf, rb->strlen(buf)); + + /* Filename of levelset */ + rb->write(fd, buffered_boards.filename, + rb->strlen(buffered_boards.filename)); + rb->write(fd, "\n", 1); + + /* Full undo history */ + rb->write(fd, undo_info.history, undo_info.max); + + rb->close(fd); + + return true; +} + +static bool load(char *filename, bool silent) +{ + int fd; + int i = 0, n; + int len; + bool play_solution; + int button; + int step_delay = HZ/4; + + if (filename[0] == '\0' || (fd = rb->open(filename, O_RDONLY)) < 0) { + if (!silent) + rb->splash(HZ*2, "Unable to open %s", filename); + return false; + } + + /* Read header, level number, & current undo */ + rb->read_line(fd, buf, sizeof(buf)); + + /* If we're opening a level file, not a solution/progress file */ + if (rb->strncmp(buf, "Sokoban", 7) != 0) { + rb->close(fd); + + rb->strncpy(buffered_boards.filename, filename, MAX_PATH); + if (!read_levels(true)) + return false; + + current_info.level.index = 0; + load_level(); + + /* If there aren't any boxes to go or the player position wasn't set, + * the file probably wasn't a Sokoban level file */ + if (current_info.level.boxes_to_go == 0 || + current_info.player.row == 0 || current_info.player.col == 0) { + if (!silent) + rb->splash(HZ*2, "File is not a Sokoban level file"); + return false; + } + + } else { + + /* Read filename of levelset */ + rb->read_line(fd, buffered_boards.filename, + sizeof(buffered_boards.filename)); + + /* Read full undo history */ + len = rb->read_line(fd, undo_info.history, MAX_UNDOS); + + /* Correct len when trailing \r's or \n's are counted */ + if (len > 2 && undo_info.history[len - 2] == '\0') + len -= 2; + else if (len > 1 && undo_info.history[len - 1] == '\0') + len--; + + rb->close(fd); + + /* Check to see if we're going to play a solution or resume progress */ + play_solution = (buf[8] == 'S'); + + /* Get level number */ + for (n = 0, i = 10; buf[i] >= '0' && buf[i] <= '9' && i < 15; i++) + n = n*10 + buf[i] - '0'; + current_info.level.index = n - 1; + + /* Get current undo index */ + for (n = 0, i++; buf[i] >= '0' && buf[i] <= '9' && i < 21; i++) + n = n*10 + buf[i] - '0'; + if (n > len) + n = len; + + if (current_info.level.index < 0) { + if (!silent) + rb->splash(HZ*2, "Error loading level"); + return false; + } + if (!read_levels(true)) + return false; + if (current_info.level.index >= current_info.max_level) { + if (!silent) + rb->splash(HZ*2, "Error loading level"); + return false; + } + + load_level(); + + if (play_solution) { + rb->lcd_clear_display(); + update_screen(); + rb->sleep(2*step_delay); + + /* Replay solution until the end or quit button is pressed */ + for (i = 0; i < len; i++) { + if (!move(undo_info.history[i], true)) { + n = i; + break; + } + + rb->lcd_clear_display(); + update_screen(); + rb->sleep(step_delay); + + /* Ignore keypresses except for quit & changing speed */ + while ((button = rb->button_get(false)) != BUTTON_NONE) { + switch (button) { + case SOKOBAN_MENU: + /* Pretend the level is complete so we'll quit */ + current_info.level.boxes_to_go = 0; + return true; + + case SOKOBAN_UP: + if (step_delay > HZ/12) + step_delay = 5*step_delay/6; + break; + + case SOKOBAN_DOWN: + if (step_delay < 3*HZ/4) + step_delay = 6*step_delay/5; + } + } + } + + /* If level complete, wait for keypress before quitting */ + if (current_info.level.boxes_to_go == 0) + rb->button_get(true); + + } else { + /* Advance to current undo */ + for (i = 0; i < n; i++) { + if (!move(undo_info.history[i], true)) { + n = i; + break; + } + } + + rb->button_clear_queue(); + rb->lcd_clear_display(); + } + + undo_info.max = len; + undo_info.current = n; + } + + return true; +} + +static int sokoban_menu(void) +{ + int button; + int selection = 0; + int i; + bool menu_quit; + int start_selected = 0; + + MENUITEM_STRINGLIST(menu, "Sokoban Menu", NULL, + "Resume", "Audio Playback", "Keys", + "Load Default Level Set", "Quit Without Saving", + "Save Progress & Quit"); + + do { + menu_quit = true; + selection = rb->do_menu(&menu, &start_selected); + + switch (selection) { + case 0: /* Resume */ + break; + + case 1: /* Audio playback control */ + playback_control(rb); + menu_quit = false; + break; + + case 2: /* Keys */ + FOR_NB_SCREENS(i) + rb->screens[i]->clear_display(); + rb->lcd_setfont(SOKOBAN_FONT); + +#if (CONFIG_KEYPAD == RECORDER_PAD) || \ + (CONFIG_KEYPAD == ARCHOS_AV300_PAD) + rb->lcd_putsxy(3, 6, "[OFF] Menu"); + rb->lcd_putsxy(3, 16, "[ON] Undo"); + rb->lcd_putsxy(3, 26, "[PLAY] Redo"); + rb->lcd_putsxy(3, 36, "[F1] Down a Level"); + rb->lcd_putsxy(3, 46, "[F2] Restart Level"); + rb->lcd_putsxy(3, 56, "[F3] Up a Level"); +#elif CONFIG_KEYPAD == ONDIO_PAD + rb->lcd_putsxy(3, 6, "[OFF] Menu"); + rb->lcd_putsxy(3, 16, "[MODE] Undo"); + rb->lcd_putsxy(3, 26, "[MODE+DOWN] Redo"); + rb->lcd_putsxy(3, 36, "[MODE+LEFT] Previous Level"); + rb->lcd_putsxy(3, 46, "[MODE+UP] Restart Level"); + rb->lcd_putsxy(3, 56, "[MODE+RIGHT] Up Level"); +#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ + (CONFIG_KEYPAD == IRIVER_H300_PAD) + rb->lcd_putsxy(3, 6, "[STOP] Menu"); + rb->lcd_putsxy(3, 16, "[REC] Undo"); + rb->lcd_putsxy(3, 26, "[MODE] Redo"); + rb->lcd_putsxy(3, 36, "[PLAY+DOWN] Previous Level"); + rb->lcd_putsxy(3, 46, "[PLAY] Restart Level"); + rb->lcd_putsxy(3, 56, "[PLAY+UP] Next Level"); +#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ + (CONFIG_KEYPAD == IPOD_3G_PAD) + rb->lcd_putsxy(3, 6, "[SELECT+MENU] Menu"); + rb->lcd_putsxy(3, 16, "[SELECT] Undo"); + rb->lcd_putsxy(3, 26, "[SELECT+PLAY] Redo"); + rb->lcd_putsxy(3, 36, "[SELECT+LEFT] Previous Level"); + rb->lcd_putsxy(3, 46, "[SELECT+RIGHT] Next Level"); +#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD + rb->lcd_putsxy(3, 6, "[POWER] Menu"); + rb->lcd_putsxy(3, 16, "[SELECT] Undo"); + rb->lcd_putsxy(3, 26, "[REC] Previous Level"); + rb->lcd_putsxy(3, 36, "[PLAY] Next Level"); +#elif CONFIG_KEYPAD == IRIVER_H10_PAD + rb->lcd_putsxy(3, 6, "[POWER] Menu"); + rb->lcd_putsxy(3, 16, "[REW] Undo"); + rb->lcd_putsxy(3, 26, "[FF] Redo"); + rb->lcd_putsxy(3, 36, "[PLAY+DOWN] Previous Level"); + rb->lcd_putsxy(3, 46, "[PLAY+RIGHT] Restart Level"); + rb->lcd_putsxy(3, 56, "[PLAY+UP] Next Level"); +#elif CONFIG_KEYPAD == GIGABEAT_PAD + rb->lcd_putsxy(3, 6, "[POWER] Menu"); + rb->lcd_putsxy(3, 16, "[SELECT] Undo"); + rb->lcd_putsxy(3, 26, "[A] Redo"); + rb->lcd_putsxy(3, 36, "[VOL-] Previous Level"); + rb->lcd_putsxy(3, 46, "[MENU] Restart Level"); + rb->lcd_putsxy(3, 56, "[VOL+] Next Level"); +#elif CONFIG_KEYPAD == SANSA_E200_PAD + rb->lcd_putsxy(3, 6, "[POWER] Menu"); + rb->lcd_putsxy(3, 16, "[SELECT] Undo"); + rb->lcd_putsxy(3, 26, "[REC] Redo"); + rb->lcd_putsxy(3, 36, "[SELECT+DOWN] Previous Level"); + rb->lcd_putsxy(3, 46, "[SELECT+RIGHT] Restart Level"); + rb->lcd_putsxy(3, 56, "[SELECT+UP] Next Level"); +#endif + + FOR_NB_SCREENS(i) + rb->screens[i]->update(); + + /* Display until keypress */ + do { + rb->sleep(HZ/20); + button = rb->button_get(false); + } while (!button || button & BUTTON_REL || + button & BUTTON_REPEAT); + + menu_quit = false; + break; + + case 3: /* Load default levelset */ + init_boards(); + if (!read_levels(true)) + return 4; + load_level(); + break; + + case 4: /* Quit */ + break; + + case 5: /* Save & quit */ + save(SOKOBAN_SAVE_FILE, false); + rb->reload_directory(); + } + + } while (!menu_quit); + + /* Restore font */ + rb->lcd_setfont(SOKOBAN_FONT); + + FOR_NB_SCREENS(i) { + rb->screens[i]->clear_display(); + rb->screens[i]->update(); + } + + return selection; +} + static bool sokoban_loop(void) { - bool moved = true; + bool moved; int i = 0, button = 0, lastbutton = 0; short r = 0, c = 0; int w, h; - char s[25]; + char *loc; - current_info.level.level = 1; - - load_level(); - update_screen(); - - while (1) { - moved = true; + while (true) { + moved = false; r = current_info.player.row; c = current_info.player.col; @@ -742,24 +1166,25 @@ static bool sokoban_loop(void) #ifdef SOKOBAN_RC_QUIT case SOKOBAN_RC_QUIT: #endif - case SOKOBAN_QUIT: - /* get out of here */ -#ifdef HAVE_LCD_COLOR /* reset background color */ - rb->lcd_set_background(rb->global_settings->bg_color); -#endif - return PLUGIN_OK; + case SOKOBAN_MENU: + switch (sokoban_menu()) { + case 4: /* Quit */ + case 5: /* Save & quit */ + return PLUGIN_OK; + } + update_screen(); + break; case SOKOBAN_UNDO: #ifdef SOKOBAN_UNDO_PRE if (lastbutton != SOKOBAN_UNDO_PRE) break; -#else /* repeat can't work here for Ondio et al */ +#else /* repeat can't work here for Ondio, iPod, et al */ case SOKOBAN_UNDO | BUTTON_REPEAT: #endif undo(); rb->lcd_clear_display(); update_screen(); - moved = false; break; #ifdef SOKOBAN_REDO @@ -775,22 +1200,20 @@ static bool sokoban_loop(void) case SOKOBAN_LEVEL_UP | BUTTON_REPEAT: /* next level */ init_undo(); - if (current_info.level.level < current_info.max_level) - current_info.level.level++; + if (current_info.level.index + 1 < current_info.max_level) + current_info.level.index++; draw_level(); - moved = false; break; case SOKOBAN_LEVEL_DOWN: case SOKOBAN_LEVEL_DOWN | BUTTON_REPEAT: /* previous level */ init_undo(); - if (current_info.level.level > 1) - current_info.level.level--; + if (current_info.level.index > 0) + current_info.level.index--; draw_level(); - moved = false; break; #ifdef SOKOBAN_LEVEL_REPEAT @@ -799,7 +1222,6 @@ static bool sokoban_loop(void) /* same level */ init_undo(); draw_level(); - moved = false; break; #endif @@ -826,13 +1248,10 @@ static bool sokoban_loop(void) default: if (rb->default_event_handler(button) == SYS_USB_CONNECTED) return PLUGIN_USB_CONNECTED; - - moved = false; break; } - if (button != BUTTON_NONE) - lastbutton = button; + lastbutton = button; if (moved) { rb->lcd_clear_display(); @@ -844,58 +1263,102 @@ static bool sokoban_loop(void) if (moved) { rb->lcd_clear_display(); - /* Center level completed message */ - rb->snprintf(s, sizeof(s), "Level %d Complete!", - current_info.level.level); - rb->lcd_getstringsize(s, &w, &h); - rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - 16 , s); - rb->snprintf(s, sizeof(s), "%4d Moves ", - current_info.level.moves); - rb->lcd_getstringsize(s, &w, &h); - rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + 0 , s); - rb->snprintf(s, sizeof(s), "%4d Pushes", - current_info.level.pushes); - rb->lcd_getstringsize(s, &w, &h); - rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + 8 , s); - rb->lcd_update(); - rb->button_get(false); - rb->sleep(HZ/2); - for (i = 0; i < 30; i++) { + /* Show level complete message & stats */ + rb->snprintf(buf, sizeof(buf), "Level %d Complete!", + current_info.level.index + 1); + rb->lcd_getstringsize(buf, &w, &h); + rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h*3, buf); + + rb->snprintf(buf, sizeof(buf), "%4d Moves ", + current_info.level.moves); + rb->lcd_getstringsize(buf, &w, &h); + rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h, buf); + + rb->snprintf(buf, sizeof(buf), "%4d Pushes", + current_info.level.pushes); + rb->lcd_getstringsize(buf, &w, &h); + rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2, buf); + + if (undo_info.count < MAX_UNDOS) { + rb->snprintf(buf, sizeof(buf), "%s: Save solution", + BUTTON_SAVE_NAME); + rb->lcd_getstringsize(buf, &w, &h); + rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + h*2, buf); + } + + rb->lcd_update(); + rb->sleep(HZ/4); + rb->button_clear_queue(); + + /* Display for 4 seconds or until new keypress */ + for (i = 0; i < 75; i++) { rb->sleep(HZ/20); button = rb->button_get(false); - if (button && ((button & BUTTON_REL) != BUTTON_REL)) + if (button && !(button & BUTTON_REL) && + !(button & BUTTON_REPEAT)) break; } + + if (button == BUTTON_SAVE) { + if (undo_info.count < MAX_UNDOS) { + /* Default filename to current levelset plus + * level number and .sok extension */ + loc = rb->strrchr(buffered_boards.filename, '.'); + if (loc != NULL) + *loc = '\0'; + rb->snprintf(buf, sizeof(buf), "%s.%d.sok", + buffered_boards.filename, + current_info.level.index + 1); + if (loc != NULL) + *loc = '.'; + + if (!rb->kbd_input(buf, MAX_PATH)) + save(buf, true); + } else + rb->splash(HZ*2, "Solution too long to save"); + + rb->lcd_setfont(SOKOBAN_FONT); /* Restore font */ + } } - current_info.level.level++; + FOR_NB_SCREENS(i) { + rb->screens[i]->clear_display(); + rb->screens[i]->update(); + } + + current_info.level.index++; /* clear undo stats */ init_undo(); - rb->lcd_clear_display(); - - if (current_info.level.level > current_info.max_level) { - /* Center "You WIN!!" on all screen sizes */ - rb->snprintf(s, sizeof(s), "You WIN!!"); - rb->lcd_getstringsize(s, &w, &h); - rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h/2, s); + if (current_info.level.index >= current_info.max_level) { + /* Show levelset complete message */ + rb->snprintf(buf, sizeof(buf), "You WIN!!"); + rb->lcd_getstringsize(buf, &w, &h); + rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h/2, buf); rb->lcd_set_drawmode(DRMODE_COMPLEMENT); - /* Display for 10 seconds or until keypress */ - for (i = 0; i < 200; i++) { + /* Display for 4 seconds or until keypress */ + for (i = 0; i < 80; i++) { rb->lcd_fillrect(0, 0, LCD_WIDTH, LCD_HEIGHT); rb->lcd_update(); - rb->sleep(HZ/20); + rb->sleep(HZ/10); button = rb->button_get(false); - if (button && ((button & BUTTON_REL) != BUTTON_REL)) + if (button && !(button & BUTTON_REL)) break; } rb->lcd_set_drawmode(DRMODE_SOLID); - return PLUGIN_OK; + /* Reset to first level & show quit menu */ + current_info.level.index = 0; + + switch (sokoban_menu()) { + case 4: /* Quit */ + case 5: /* Save & quit */ + return PLUGIN_OK; + } } load_level(); @@ -911,99 +1374,41 @@ static bool sokoban_loop(void) enum plugin_status plugin_start(struct plugin_api* api, void* parameter) { int w, h; - int i; - int button = 0; (void)(parameter); rb = api; - rb->lcd_setfont(FONT_SYSFIXED); - -#ifdef HAVE_LCD_COLOR - rb->lcd_set_background(BG_COLOR); -#endif + rb->lcd_setfont(SOKOBAN_FONT); rb->lcd_clear_display(); rb->lcd_getstringsize(SOKOBAN_TITLE, &w, &h); rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h/2, SOKOBAN_TITLE); rb->lcd_update(); - rb->sleep(HZ); - - rb->lcd_clear_display(); - -#if (CONFIG_KEYPAD == RECORDER_PAD) || \ - (CONFIG_KEYPAD == ARCHOS_AV300_PAD) - rb->lcd_putsxy(3, 6, "[OFF] Quit"); - rb->lcd_putsxy(3, 16, "[ON] Undo"); - rb->lcd_putsxy(3, 26, "[PLAY] Redo"); - rb->lcd_putsxy(3, 36, "[F1] Down a Level"); - rb->lcd_putsxy(3, 46, "[F2] Restart Level"); - rb->lcd_putsxy(3, 56, "[F3] Up a Level"); -#elif CONFIG_KEYPAD == ONDIO_PAD - rb->lcd_putsxy(3, 6, "[OFF] Quit"); - rb->lcd_putsxy(3, 16, "[MODE] Undo"); - rb->lcd_putsxy(3, 26, "[MODE+DOWN] Redo"); - rb->lcd_putsxy(3, 36, "[MODE+LEFT] Down a Level"); - rb->lcd_putsxy(3, 46, "[MODE+UP] Restart Level"); - rb->lcd_putsxy(3, 56, "[MODE+RIGHT] Up Level"); -#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ - (CONFIG_KEYPAD == IRIVER_H300_PAD) - rb->lcd_putsxy(3, 6, "[STOP] Quit"); - rb->lcd_putsxy(3, 16, "[REC] Undo"); - rb->lcd_putsxy(3, 26, "[MODE] Redo"); - rb->lcd_putsxy(3, 36, "[PLAY+DOWN] Down a Level"); - rb->lcd_putsxy(3, 46, "[PLAY] Restart Level"); - rb->lcd_putsxy(3, 56, "[PLAY+UP] Up a Level"); -#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ - (CONFIG_KEYPAD == IPOD_3G_PAD) - rb->lcd_putsxy(3, 6, "[SELECT+MENU] Quit"); - rb->lcd_putsxy(3, 16, "[SELECT] Undo"); - rb->lcd_putsxy(3, 26, "[SELECT+PLAY] Redo"); - rb->lcd_putsxy(3, 36, "[SELECT+LEFT] Down a Level"); - rb->lcd_putsxy(3, 46, "[SELECT+RIGHT] Up a Level"); -#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD - rb->lcd_putsxy(3, 6, "[POWER] Quit"); - rb->lcd_putsxy(3, 16, "[SELECT] Undo"); - rb->lcd_putsxy(3, 26, "[REC] Down a Level"); - rb->lcd_putsxy(3, 36, "[PLAY] Up Level"); -#elif CONFIG_KEYPAD == GIGABEAT_PAD - rb->lcd_putsxy(3, 6, "[POWER] Quit"); - rb->lcd_putsxy(3, 16, "[SELECT] Undo"); - rb->lcd_putsxy(3, 26, "[A] Redo"); - rb->lcd_putsxy(3, 36, "[VOL-] Down a Level"); - rb->lcd_putsxy(3, 46, "[MENU] Restart Level"); - rb->lcd_putsxy(3, 56, "[VOL+] Up Level"); -#elif CONFIG_KEYPAD == SANSA_E200_PAD - rb->lcd_putsxy(3, 6, "[POWER] Quit"); - rb->lcd_putsxy(3, 16, "[SELECT] Undo"); - rb->lcd_putsxy(3, 26, "[REC] Redo"); - rb->lcd_putsxy(3, 36, "[SELECT+DOWN] Down a Level"); - rb->lcd_putsxy(3, 46, "[SELECT+RIGHT] Restart Level"); - rb->lcd_putsxy(3, 56, "[SELECT+UP] Up Level"); -#elif CONFIG_KEYPAD == IRIVER_H10_PAD - rb->lcd_putsxy(3, 6, "[POWER] Quit"); - rb->lcd_putsxy(3, 16, "[REW] Undo"); - rb->lcd_putsxy(3, 26, "[FF] Redo"); - rb->lcd_putsxy(3, 36, "[PLAY+DOWN] Down a Level"); - rb->lcd_putsxy(3, 46, "[PLAY+RIGHT] Restart Level"); - rb->lcd_putsxy(3, 56, "[PLAY+UP] Up Level"); -#endif - - rb->lcd_update(); - rb->button_get(false); - /* Display for 3 seconds or until keypress */ - for (i = 0; i < 60; i++) { - rb->sleep(HZ/20); - button = rb->button_get(false); - if (button && ((button & BUTTON_REL) != BUTTON_REL)) - break; - } - rb->lcd_clear_display(); + rb->sleep(HZ); /* Show title for 1 second */ init_boards(); - if (read_levels(1) != 0) - return PLUGIN_OK; + if (parameter == NULL) { + /* Attempt to resume saved progress, otherwise start at beginning */ + if (!load(SOKOBAN_SAVE_FILE, true)) { + init_boards(); + if (!read_levels(true)) + return PLUGIN_OK; + load_level(); + } + + } else { + /* The plugin is being used to open a file */ + if (load((char*) parameter, false)) { + /* If we loaded & played a solution, quit */ + if (current_info.level.boxes_to_go == 0) + return PLUGIN_OK; + } else + return PLUGIN_OK; + } + + rb->lcd_clear_display(); + update_screen(); return sokoban_loop(); } diff --git a/apps/plugins/sokoban.levels b/apps/plugins/sokoban.levels deleted file mode 100644 index 4d73a5ed9d..0000000000 --- a/apps/plugins/sokoban.levels +++ /dev/null @@ -1,1816 +0,0 @@ -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXX###XXXXXXXXX -XXXXXXXX#.#XXXXXXXXX -XXXXXXXX# ####XXXXXX -XXXXXX###$ $.#XXXXXX -XXXXXX#. $@###XXXXXX -XXXXXX####$#XXXXXXXX -XXXXXXXXX#.#XXXXXXXX -XXXXXXXXX###XXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXX#####XXXXXXXXXX -XXXXX# #XXXXXXXXXX -XXXXX#@$$#X###XXXXXX -XXXXX# $ #X#.#XXXXXX -XXXXX### ###.#XXXXXX -XXXXXX## .#XXXXXX -XXXXXX# # #XXXXXX -XXXXXX# ####XXXXXX -XXXXXX#####XXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX#######XXXXXXX -XXXXXX# ###XXXXX -XXXXX##$### #XXXXX -XXXXX# @ $ $ #XXXXX -XXXXX# ..# $ ##XXXXX -XXXXX##..# #XXXXXX -XXXXXX########XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXX#####XXXXXX -XXXXXX#### .#XXXXXX -XXXXXX# $ %#XXXXXX -XXXXXX# $$ $.#XXXXXX -XXXXXX##@##..#XXXXXX -XXXXXXX#######XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXX####XXXXXXXXX -XXXXXXX#@ ###XXXXXXX -XXXXXXX# $ #XXXXXXX -XXXXXX### # ##XXXXXX -XXXXXX#.# # #XXXXXX -XXXXXX#.$ # #XXXXXX -XXXXXX#. $ #XXXXXX -XXXXXX########XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXX#######XXXXX -XXXXXXX## # @#XXXXX -XXXXXXX# # #XXXXX -XXXXXXX#$ $ $ #XXXXX -XXXXXXX# $## #XXXXX -XXXXX### $ # ##XXXXX -XXXXX#..... #XXXXXX -XXXXX#########XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXX######XXXXXX -XXXXXX### #XXXXXX -XXXXX##. $## ##XXXXX -XXXXX#..$ $ @#XXXXX -XXXXX#.. $ $ ##XXXXX -XXXXX###### #XXXXXX -XXXXXXXXXX####XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXX######XXXXXX -XXXXXXXX# #XXXXXX -XXXXXX###$$$ #XXXXXX -XXXXXX#@ $.. #XXXXXX -XXXXXX# $...##XXXXXX -XXXXXX#### #XXXXXXX -XXXXXXXXX####XXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXX####XXXXXXXX -XXXXXXXX#..#XXXXXXXX -XXXXXXX## .##XXXXXXX -XXXXXXX# $.#XXXXXXX -XXXXXX## $ ##XXXXXX -XXXXXX# #$$ #XXXXXX -XXXXXX# @ #XXXXXX -XXXXXX########XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXX#####XXXXXXX -XXXXXX### @#XXXXXXX -XXXXXX# $. ##XXXXXX -XXXXXX# .$. #XXXXXX -XXXXXX### %$ #XXXXXX -XXXXXXXX# ##XXXXXX -XXXXXXXX#####XXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX########XXXXXX -XXXXXX# # #XXXXXX -XXXXXX# $..$ #XXXXXX -XXXXXX#@$.% ##XXXXXX -XXXXXX# $..$ #XXXXXX -XXXXXX# # #XXXXXX -XXXXXX########XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXX######XXXXXXX -XXXXXXX# ###XXXXX -XXXXXXX# $ #XXXXX -XXXXX### $ ## #XXXXX -XXXXX#... $ #XXXXX -XXXXX#...$#$ ##XXXXX -XXXXX#### # $ #XXXXX -XXXXXXXX# @ #XXXXX -XXXXXXXX#######XXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX######XXXXXXXX -XXXXXX# #XXXXXXXX -XXXXXX# $$$##XXXXXXX -XXXXXX# #..###XXXXX -XXXXXX## ..$ #XXXXX -XXXXXXX# @ #XXXXX -XXXXXXX########XXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXX########XXXXX -XXXXXXX# #. #XXXXX -XXXXXX## $...#XXXXX -XXXXXX# $ #%.#XXXXX -XXXXX## ##$# ##XXXXX -XXXXX# $ $ #XXXXX -XXXXX# # #XXXXX -XXXXX#######@ #XXXXX -XXXXXXXXXXX####XXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX#######XXXXXXX -XXXXXX#.... #XXXXXXX -XXXXX###...$###XXXXX -XXXXX# $#$ $ #XXXXX -XXXXX# $$ #$ #XXXXX -XXXXX# # #XXXXX -XXXXX#### @ ###XXXXX -XXXXXXXX#####XXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX########XXXXXX -XXXXXX#.. #XXXXXX -XXXXXX#..$ $@#XXXXXX -XXXXXX#$#$$$##XXXXXX -XXXXXX#..$ $ #XXXXXX -XXXXXX#.. #XXXXXX -XXXXXX########XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXX########XXXXXXX -XXXXX# #XXXXXXX -XXXXX# #$$ #XXXXXXX -XXXXX# ...# #XXXXXXX -XXXXX##...$ ##XXXXXX -XXXXXX# ## $ #XXXXXX -XXXXXX#$ $ #XXXXXX -XXXXXX# # @#XXXXXX -XXXXXX########XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXX#####XXXXXXXX -XXXXX### ####XXXXX -XXXXX# $ $ #XXXXX -XXXXX# $ $ @#XXXXX -XXXXX###$$#####XXXXX -XXXXXXX# ..#XXXXXXX -XXXXXXX#....#XXXXXXX -XXXXXXX######XXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXX#########XXXXXX -XXXXX# % #XXXXXX -XXXXX# $.$. @#XXXXXX -XXXXX# .$.$. #XXXXXX -XXXXX# $.$.$ #XXXXXX -XXXXX# % #XXXXXX -XXXXX#########XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX#########XXXXX -XXXXX## #XXXXX -XXXXX# #$#$ #XXXXX -XXXXX# $$ .$.#XXXXX -XXXXX# @###...#XXXXX -XXXXX####X#####XXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXX######XXXXXXX -XXXXXXX#. ..#XXXXXXX -XXXXXXX#. $.#XXXXXXX -XXXXXX### $##XXXXXX -XXXXXX# $ $ #XXXXXX -XXXXXX# #$## #XXXXXX -XXXXXX# @ #XXXXXX -XXXXXX########XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX#####XXXXXXXXX -XXXXXX# ####XXXXXX -XXXXX## #$ #XXXXXX -XXXXX# $ $$ #XXXXXX -XXXXX# #$#.%.#XXXXXX -XXXXX# @...#XXXXXX -XXXXX#########XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXX#####XXXXXX -XXXXXX#### ##XXXXX -XXXXXX# $ $ #XXXXX -XXXXXX#@#.%.# #XXXXX -XXXXXX# #.%.# #XXXXX -XXXXXX# $ $ #XXXXX -XXXXXX## ####XXXXX -XXXXXXX#####XXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXX#####XXXXXXX -XXXXX####. ##XXXXXX -XXXXX# $.$. #XXXXXX -XXXXX#@$# #$ #XXXXXX -XXXXX# $. . #XXXXXX -XXXXX####$#$ #XXXXXX -XXXXXXX#. . #XXXXXX -XXXXXXX#######XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXX########XXXX -XXXXX#### . #XXXX -XXXXX# $ $ $. #XXXX -XXXXX# .####.##XXXX -XXXXX# $.$ $ @#XXXXX -XXXXX# . ##XXXXX -XXXXX#########XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXX#######XXXXXXXX -XXXXX# #####XXXX -XXXXX# $ .%. $ #XXXX -XXXXX#@$.% %.$ #XXXX -XXXXX# $ .%. $ #XXXX -XXXXX###### #XXXX -XXXXXXXXXX######XXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXX######XXXXXXXXX -XXXXX# #XXXXXXXXX -XXXXX# $ ####XXXXXX -XXXXX# $%..% #XXXXXX -XXXXX# %..%$ #XXXXXX -XXXXX#### $ #XXXXXX -XXXXXXXX# @ #XXXXXX -XXXXXXXX######XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXX######XXXXX -XXXXXX####. @#XXXXX -XXXXXX# $$$ #XXXXX -XXXXXX#.##.##.#XXXXX -XXXXXX# $ #XXXXX -XXXXXX# $.# ##XXXXX -XXXXXX#### #XXXXXX -XXXXXXXXX#####XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX#########XXXXX -XXXXXX#. $. @#XXXXX -XXXXXX# .$.$ #XXXXX -XXXXXX##$.$ $##XXXXX -XXXXXX# .$.$ #XXXXX -XXXXXX#. $. #XXXXX -XXXXXX#########XXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXX#######XXXXXX -XXXXXXX# @ #XXXXXX -XXXXXXX##$ $ #XXXXXX -XXXXXXX# $$##XXXXXX -XXXXXXX#....#XXXXXXX -XXXXXXX######XXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX####XXXXXXXXXX -XXXXXX# #####XXXXXX -XXXXX##$ ## #XXXXXX -XXXXX# $@$ #XXXXXX -XXXXX# ##$ #XXXXXX -XXXXX###.## ###XXXXX -XXXXXX#...$ $ #XXXXX -XXXXXX##.. #XXXXX -XXXXXXX########XXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX########XXXXXX -XXXXXX# #.. ##XXXXX -XXXXXX# $. $% #XXXXX -XXXXXX# $@$ #XXXXX -XXXXXX# %$ .$ #XXXXX -XXXXXX## ..# #XXXXX -XXXXXXX########XXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX#######XXXXXXX -XXXXX## % ##XXXXXX -XXXXX# . . . #XXXXXX -XXXXX# $ % #XXXXXX -XXXXX#%$$%$$%#XXXXXX -XXXXX# % $ #XXXXXX -XXXXX# . .@. #XXXXXX -XXXXX## % ##XXXXXX -XXXXXX#######XXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXX#########XXXXXX -XXXXX# .$ @#XXXXXX -XXXXX# $ % $ #XXXXXX -XXXXX#%...%.%#XXXXXX -XXXXX# $$% #XXXXXX -XXXXX# . $ #XXXXXX -XXXXX#########XXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXX######XXXXX -XXXXX#####. #XXXXX -XXXXX# #..## #XXXXX -XXXXX# $.. #XXXXX -XXXXX# # .# ##XXXXX -XXXX### ##$# #XXXXX -XXXX# $ $$ #XXXXX -XXXX# #$# # #XXXXX -XXXX#@ #######XXXXX -XXXX#####XXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXX######XXXXXXX -XXXXXXX# ...#XXXXXXX -XXXX####....#XXXXXXX -XXXX# ###$ ###XXXXX -XXXX# $ $ $$ #XXXXX -XXXX#@ $ $ #XXXXX -XXXX# #### #XXXXX -XXXX####XX#####XXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX#########XXXXX -XXXXXX# ## #XXXXX -XXXXXX# $ #XXXXX -XXXXXX#$ ### $#XXXXX -XXXXXX# #...# #XXXXX -XXXXX## #...# ##XXXX -XXXXX# $ $ $ #XXXX -XXXXX# # @ #XXXX -XXXXX###########XXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXX#######XXXXX -XXXXXX### #XXXXX -XXXXX## # # #XXXXX -XXXXX# #.$$$ #XXXXX -XXXXX# #.%# ###XXXXX -XXXXX# ..# #XXXXXXX -XXXXX###..$ ##XXXXXX -XXXXXXX#.# $ #XXXXXX -XXXXXX## # #@#XXXXXX -XXXXXX# $ $ #XXXXXX -XXXXXX# ###XXXXXX -XXXXXX######XXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX##########XXXX -XXXXX## #XXXX -XXXXX#@ $$$ $ #XXXX -XXXXX## $ $ $ #XXXX -XXXXXX## #### ##XXXX -XXXXXXX# $ ##XXXX -XXXXX### ##$ $ #XXXX -XXXXX# # #XXXX -XXXXX# ######XXXX -XXXXX# ##XXXXXXXX -XXXXX#.....#XXXXXXXX -XXXXX#.....#XXXXXXXX -XXXXX#######XXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXX########XXXXXXX -XXXXX# #XXXXXXX -XXXXX# @ $# #XXXXXXX -XXXXX## # #XXXXXXX -XXXXX# $#.# #XXXXXXX -XXXXX# .%.$#XXXXXXX -XXXXX## #.# #XXXXXXX -XXXXXX# #. ##XXXXXX -XXXXX## $.# #XXXXXX -XXXXX# # $ #XXXXXX -XXXXX# $ ###XXXXXX -XXXXX# ####XXXXXXXX -XXXXX####XXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXX####XXXXX -XXXXXXXXXXX#@ #XXXXX -XXXXXXX##### #XXXXX -XXXX#### #XXXXX -XXXX# .### ##XXXXX -XXXX# # # ##XXXXX -XXXX# # $ $#. #XXXXX -XXXX# # % # #XXXXX -XXXX# .#$ $ # #XXXXX -XXXX## # # #XXXXX -XXXXX# ###. #XXXXX -XXXXX# ####XXXXX -XXXXX#######XXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXX#####XXXXXXXX -XXXXXXX# ##XXXXXXX -XXXXXXX# $ #XXXXXXX -XXXXXXX# $ @#XXXXXXX -XXXXXXX###. #XXXXXXX -XXXXXXXXX#.##XXXXXXX -XXXXXXXXX#. #XXXXXXX -XXXXXXX###. #XXXXXXX -XXXXXXX# $ #XXXXXXX -XXXXXXX# $ #XXXXXXX -XXXXXXX## ##XXXXXXX -XXXXXXXX####XXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX####XXXXXXXXXX -XXXXXX# #####XXXXXX -XXXXXX# # #XXXXXX -XXXXXX# . # #XXXXXX -XXXXXX##$# .#XXXXXX -XXXXXXX# #$# #XXXXXX -XXXXXX##. . #XXXXXX -XXXXXX# ## #XXXXXX -XXXXXX# # %#XXXXXX -XXXXXX# $ $ #XXXXXX -XXXXXX# $#% @#XXXXXX -XXXXXX# #.###XXXXXX -XXXXXX######XXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXX###XXXXXXXXX -XXXXXXXX#.######XXXX -XXXXXX###.$ # #XXXX -XXXXXX#... #$ #XXXX -XXXXXX#.## $ #XXXX -XXXXX##.$ $## ##XXXX -XXXXX#.$ # ## #XXXXX -XXXXX#.#$ #XXXXX -XXXXX#.$ #$ $#XXXXX -XXXXX#. $## @ #XXXXX -XXXXX#.$ $ #XXXXX -XXXXX#. #######XXXXX -XXXXX####XXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXX####XXXXXXX -XXXXXXX### ##XXXXXX -XXXXXX## ##XXXXX -XXXXXX# # ..#XXXXX -XXXXX## $#%#$.#XXXXX -XXXXX# $ # $.#XXXXX -XXXXX# $ @ $.#XXXXX -XXXXX# $ # $.#XXXXX -XXXXX##$$#%#$.#XXXXX -XXXXXX#. # ..#XXXXX -XXXXXX##. ##XXXXX -XXXXXXX### ##XXXXXX -XXXXXXXXX####XXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX#########XXXXX -XXXXXX# #XXXXX -XXXXXX# # ### #XXXXX -XXXXXX# $$ # #XXXXX -XXXXXX#@$ # #XXXXX -XXXXXX## ## # #XXXXX -XXXXXX# $ $ #XXXXX -XXXXXX# $## # #XXXXX -XXXXXX# #$# #XXXXX -XXXXXX#...# #XXXXX -XXXXXX#.#.#$###XXXXX -XXXXXX#... #XXXXXXX -XXXXXX#######XXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXX########XXXXXXX -XXXXX# .#XXXXXXX -XXXXX# #$#..##XXXXXX -XXXXX# $...#XXXXXX -XXXXX## ##.$.#XXXXXX -XXXXXX# ## ##XXXXXX -XXXXXX#$## #XXXXXXX -XXXXX## #$#XXXXXXX -XXXXX# # #XXXXXXX -XXXXX# $ ####XXXXX -XXXXX# $ $ @#XXXXX -XXXXX# ### #XXXXX -XXXXX####X#####XXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX####XXXXXXXXXX -XXXXXX# ####XXXXXXX -XXXXXX# $ #XXXXXXX -XXXXXX# #.# #XXXXXXX -XXXXXX# # # #XXXXXXX -XXXXXX#.$.$.#XXXXXXX -XXXXXX# # # #XXXXXXX -XXXXXX# #.# #XXXXXXX -XXXXXX# $$ #XXXXXXX -XXXXXX## @ #XXXXXXX -XXXXXXX# ###XXXXXXX -XXXXXXX####XXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXX######X####XXXXX -XXXX# ### #XXXXX -XXXX# $$ ## #XXXXX -XXXX# # $ #XXXXX -XXXX## ## $# #XXXXX -XXXXX# #... ##XXXXX -XXXXX# ...#$##XXXXX -XXXXX# #...# #XXXXX -XXXX## # ###@ #XXXXX -XXXX# $ $ $ #XXXXX -XXXX# #$#### #XXXXX -XXXX# #XX####XXXXX -XXXX#####XXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXX##########XXXXX -XXXXX#..$ $ %.#XXXXX -XXXXX#.% $ $..#XXXXX -XXXXX##.$ $ %##XXXXX -XXXXXX#% $ $.#XXXXXX -XXXXXX#.$ $ .#XXXXXX -XXXXXX#. $ $.#XXXXXX -XXXXXX#.$@$ %#XXXXXX -XXXXX##% $ $.##XXXXX -XXXXX#..$ $ %.#XXXXX -XXXXX#.% $ $..#XXXXX -XXXXX##########XXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXX#####XXXXXXXXXXX -XXXX# #XXXXXXXXXXX -XXXX#$ #XXXXXXXXXXX -XX### $##XXXXXXXXXX -XX# $ $ #XXXXXXXXXX -### # ## #XXX######X -# # ## ##### ..#X -# $ $ ..#X -##### ### #@## ..#X -XXXX# #########X -XXXX#######XXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXX############XXXXX -XXX#.. # ###XXX -XXX#.. # $ $ #XXX -XXX#.. #$#### #XXX -XXX#.. @ ## #XXX -XXX#.. # $ ##XXX -XXX###### ##$ $ #XXX -XXXXX# $ $ $ $ #XXX -XXXXX# # #XXX -XXXXX############XXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXX########XXX -XXXXXXXXX# @#XXX -XXXXXXXXX# $#$ ##XXX -XXXXXXXXX# $ $#XXXX -XXXXXXXXX##$ $ #XXXX -X######### $ # ###XX -X#.... ## $ $ #XX -X##... $ $ #XX -X#.... ##########XX -X########XXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXX######## -XXXXXXXXXXXX# ....# -X############ ....# -X# # $ $ ....# -X# $$$#$ $ # ....# -X# $ $ # ....# -X# $$ #$ $ $######## -X# $ # #XXXXXXX -X## #########XXXXXXX -X# # ##XXXXXXX -X# $ ##XXXXXXX -X# $$#$$ @#XXXXXXX -X# # ##XXXXXXX -X###########XXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXX#####XXXXXX -XXXXXXXXX# #####XX -XXXXXXXXX# #$## #XX -XXXXXXXXX# $ #XX -X######### ### #XX -X#.... ## $ $###XX -X#.... $ $$ ##XXX -X#.... ##$ $ @#XXX -X######### $ ##XXX -XXXXXXXXX# $ $ #XXX -XXXXXXXXX### ## #XXX -XXXXXXXXXXX# #XXX -XXXXXXXXXXX######XXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXX######XX###XXXXX -XXXX#.. #X##@##XXXX -XXXX#.. ### #XXXX -XXXX#.. $$ #XXXX -XXXX#.. # # $ #XXXX -XXXX#..### # $ #XXXX -XXXX#### $ #$ #XXXX -XXXXXXX# $# $ #XXXX -XXXXXXX# $ $ #XXXX -XXXXXXX# ## #XXXX -XXXXXXX#########XXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXX#####XXXX -XXXXX####### ##XXX -XXXX## # @## $$ #XXX -XXXX# $ #XXX -XXXX# $ ### #XXX -XXXX### #####$###XXX -XXXX# $ ### ..#XXXX -XXXX# $ $ $ ...#XXXX -XXXX# ###...#XXXX -XXXX# $$ #X#...#XXXX -XXXX# ###X#####XXXX -XXXX####XXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXX####XXXXXXXXXXXX -XXXX# ###########XX -XXXX# $ $ $ #XX -XXXX# $# $ # $ #XX -XXXX# $ $ # #XX -XX### $# # #### #XX -XX#@#$ $ $ ## #XX -XX# $ #$# # #XX -XX# $ $ $ $ #XX -XX##### #########XX -XXXX# #XXXXXXXX -XXXX#......#XXXXXXXX -XXXX#......#XXXXXXXX -XXXX#......#XXXXXXXX -XXXX########XXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXX#######XX -XXXXXXXXXXX# ...#XX -XXXXXXX##### ...#XX -XXXXXXX# . .#XX -XXXXXXX# ## ...#XX -XXXXXXX## ## ...#XX -XXXXXX### ########XX -XXXXXX# $$$ ##XXXXXX -XX##### $ $ #####XX -X## #$ $ # #XX -X#@ $ $ $ $ #XX -X###### $$ $ #####XX -XXXXXX# #XXXXXX -XXXXXX########XXXXXX -XXXXXXXXXXXXXXXXXXXX - - -X###XX#############X -##@#### # #X -# $$ $$ $ $ ...#X -# $$$# $ #...#X -# $ # $$ $$ #...#X -### # $ #...#X -# # $ $ $ #...#X -# ###### ###...#X -## # # $ $ #...#X -# ## # $$ $ $##..#X -# ..# # $ #.#X -# ..# # $$$ $$$ #.#X -##### # # #.#X -XXXX# ######### #.#X -XXXX# #.#X -XXXX###############X - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXX####XXXXX -XXXXXX####X# #XXXXX -XXXX### ###$ #XXXXX -XXX## @ $ #XXXXX -XX## $ $$## ##XXXXX -XX# #$## #XXXXX -XX# # $ $$ # ###XXXX -XX# $ # # $ ##### -X#### # $$ # # -X#### ## $ # -X#. ### ######## -X#.. ..#X####XXXXXXX -X#...#.#XXXXXXXXXXXX -X#.....#XXXXXXXXXXXX -X#######XXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XX################XX -XX# #XX -XX# # ###### #XX -XX# # $ $ $ $# #XX -XX# # $@$ ## ##X -XX# # #$ $ $###...#X -XX# # $ $ ##...#X -XX# ###$$$ $ ##...#X -XX# # ## ##...#X -XX##### ## ##...#X -XXXXXX##### ###X -XXXXXXXXXX# #XXX -XXXXXXXXXX#######XXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXX#########XXXXXXXX -XX## ## ######XXX -### # # ###X -# $ #$ # # ... #X -# # $#@$## # #.#. #X -# # #$ # . . #X -# $ $ # # #.#. #X -# ## ##$ $ . . #X -# $ # # #$#.#. #X -## $ $ $ $... #X -X#$ ###### ## #X -X# #XXXX##########X -X####XXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXX#######XXXXX -XX####### #XXXXX -XX# # $@$ #XXXXX -XX#$$ # #########X -XX# ###......## #X -XX# $......## # #X -XX# ###...... #X -X## #### ### #$##X -X# #$ # $ # #XX -X# $ $$$ # $## #XX -X# $ $ ###$$ # #XX -X##### $ # #XX -XXXXX### ### # #XX -XXXXXXX# # #XX -XXXXXXX######## #XX -XXXXXXXXXXXXXX####XX - - -XXXXX########XXXXXXX -XXXXX# # #XXXXXXX -XXXXX# $ #XXXXXXX -XXX### #$ ####XXXX -XXX# $ ##$ #XXXX -XXX# # @ $ # $#XXXX -XXX# # $ ####X -XXX## ####$## #X -XXX# $#.....# # #X -XXX# $..%%. $# ###X -XX## #.....# #XXX -XX# ### #######XXX -XX# $$ # #XXXXXXXX -XX# # #XXXXXXXX -XX###### #XXXXXXXX -XXXXXXX#####XXXXXXXX - - -XXX#####XXXXXXXXXXXX -XXX# ##XXXXXXXXXXX -XXX# #XX####XXXXX -XXX# $ #### #XXXXX -XXX# $$ $ $#XXXXX -XXX###@ #$ ##XXXX -XXXX# ## $ $ ##XXX -XXXX# $ ## ## .#XXX -XXXX# #$##$ #.#XXX -XXXX### $..##.#XXX -XXXXX# #.%...#XXX -XXXXX# $$ #.....#XXX -XXXXX# #########XXX -XXXXX# #XXXXXXXXXXX -XXXXX####XXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXX##########XXXXX -XXXXX#.. # #XXXXX -XXXXX#.. #XXXXX -XXXXX#.. # ####XXX -XXXX####### # ##XX -XXXX# #XX -XXXX# # ## # #XX -XX#### ## #### ##XX -XX# $ ##### # #XX -XX# # $ $ # $ #XX -XX# @$ $ # ##XX -XX#### ## #######XXX -XXXXX# #XXXXXXXXX -XXXXX######XXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXX###########XXXX -XXXXX# . # #XXXX -XXXXX# #. @ #XXXX -X##### ##..# ####XXX -## # ..### ###X -# $ #... $ # $ #X -# .. ## ## ## #X -####$##$# $ # # #X -XX## # #$ $$ # #X -XX# $ # # # $## #X -XX# #X -XX# ########### #X -XX####XXXXXXXXX####X -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXX######XXXXXXXXXXX -XXX# @####XXXXXXXX -X##### $ #XXXXXXXX -X# ## ####XXXXX -X# $ # ## #XXXXX -X# $ # ##### #XXXXX -X## $ $ # #XXXXX -X## $ $ ### # #XXXXX -X## # $ # # #XXXXX -X## # #$# # #XXXXX -X## ### # # ###### -X# $ #### # #....# -X# $ $ ..#.# -X####$ $# $ ....# -X# # ## ....# -X################### - - -XXXXX##########XXXXX -X##### ####XX -X# # $ #@ #XX -X# #######$#### ### -X# # ## # #$ ..# -X# # $ $ # # #.# -X# # $ # #$ ..# -X# # ### ## #.# -X# ### # # #$ ..# -X# # # $#### #.# -X# #$ $ $ #% ..# -X# $ # $ $ # #.# -X#### $### #% ..# -XXXX# $$ ###....# -XXXX# ##X###### -XXXX########XXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXX#########XXXXXXXX -XXX# #XXXXXXXX -XXX# ####XXXXX -XXX## #### # #XXXXX -XXX## #@## #XXXXX -XXX# $$$ $ $$#XXXXX -XXX# # ## $ #XXXXX -XXX# # ## $ ####XX -XXX#### $$$ $# #XX -XXXX# ## ....#XX -XXXX# # # #.. .#XX -XXXX# # # ##...#XX -XXXX##### $ #...#XX -XXXXXXXX## #####XX -XXXXXXXXX#####XXXXXX - - -X######XXXXX####XXXX -X# ####### ##### -X# $# # $ # # -X# $ $ $ # $ $ # -X##$ $ # @# $ # -X# $ ########### ## -X# # #.......# $#X -X# ## # ......# #X -X# # $........$ #X -X# # $ #.... ..# #X -X# $ $####$#### $#X -X# $ ### $ $ ## -X# $ $ $ $ # -X## ###### $ ##### # -X# # # -X################### - - -XXXXXXXXXXXXXXXXXXXX -XXXXX#######XXXXXXXX -XXXXX# # ####XXXXX -X##### $#$ # ##XXXX -X#.. # # # ####X -X#.. # $#$ # $# #X -X#. # #$ # #X -X#.. $# # $ #X -X#..@# #$ #$ # #X -X#.. # $# $# #X -X#.. # #$$#$ # ## -X#.. # $# # $#$ # -X#.. # # # # # -X##. #### ##### # -XX####XX####XXX##### -XXXXXXXXXXXXXXXXXXXX - - -X###############XXXX -X#.......... .####X -X#..........$$.# #X -X###########$ # ## -X# $ $ $ # -X## #### # $ # # -X# # ## # ## -X# $# # ## ### ## -X# $ #$### ### ## -X### $ # # ### ## -XX## $ ## # # ## -XX# $ # $ $ $ # -XX# $ $#$$$ # # -XX# # $ ##### -XX# @## # #XXXX -XX##############XXXX - - -X####XXXXXXXXXXXXXXX -X# ##############XX -X# # ..#......#XX -X# # # ##### ...#XX -X##$# ........#XX -X# ##$###### #### -X# $ # ######@ # -X##$ # $ ###### # -X# $ #$$$## # -X# # #$#$### -X# #### #$$$$$ #X -X# # $ # #X -X# # ## ## ### -X# ######$###### $ # -X# #XXXX# # -X##########XXXX##### - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXX#######XXXXXXXXXX -XXX# # #####XXXXXX -XX## # #...###XXXX -XX# $# #... #XXXX -XX# $ #$$ ... #XXXX -XX# $# #... .#XXXX -XX# # $########XXX -XX##$ $ $ #XXX -XX## # $$ # #XXX -XXX###### ##$$@#XXX -XXXXXXXX# ##XXX -XXXXXXXX########XXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -X#################XX -X#... # # ##X -##..... $## # #$ #X -#......# $ # #X -#......# # # # #X -######### $ $ $ #X -XX# #$##$ ##$##X -X## $ # $ #X -X# ## ### # ##$ #X -X# $ $$ $ $ #X -X# $ $##$ ######X -X####### @ ##XXXXXX -XXXXXXX######XXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXX#####XXXX -XXXXXXX##### #XXXX -XXXXXX## $ $ ####X -XX##### $ $ $ ##.#X -XX# $$ ##..#X -XX# ###### ###.. #X -XX## # # #... #X -XX# $ # #... #X -XX#@ #$ ## ####...#X -XX#### $ $$ ##..#X -XXXXX## $ $ $...#X -XXXXXX# $$ $ # .#X -XXXXXX# $ $ ####X -XXXXXX###### #XXXX -XXXXXXXXXXX#####XXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -X#####XXXXXXXXXXXXXX -X# ##XXXXXXXXXXXXX -X# $ #########XXXXX -X## # # ###### -X## # $#$#@ # # -X# # $ # $ # -X# ### ######### ## -X# ## ..%..... # ## -X## ## %.%..%.% # ## -X# $########## ##$ # -X# $ $ $ $ # -X# # # # # # -X################### -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXX###########X -XXXXXXXX# # #X -X#####XX# $ $ #X -X# ##### $## # ##X -X# $ ## # ## $ #X -X# $ @$$ # ##$$$ #X -X## ### # ## #X -X## # ### #####$#X -X## # $ #....#X -X# ### ## $ #....## -X# $ $ # #..$. # -X# ## $ # ##.... # -X##### ######...## -XXXXX#####XXXX#####X -XXXXXXXXXXXXXXXXXXXX - - -XXX####XXXXXXXXXXXXX -XXX# #########XXXXX -XX## ## # #XXXXX -XX# $# $@$ ####XX -XX#$ $ # $ $# ##X -X## $## #$ $ #X -X# # # # $$$ #X -X# $ $ $## ####X -X# $ $ #$# # #XXXX -X## ### ###$ #XXXX -XX# #.... #XXXX -XX####......####XXXX -XXXX#....####XXXXXXX -XXXX#...##XXXXXXXXXX -XXXX#...#XXXXXXXXXXX -XXXX#####XXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXX####XXXXXX -XXXXXX##### #XXXXXX -XXXXX## $#XXXXXX -XXXX## $ ## ###XXXX -XXXX#@$ $ # $ #XXXX -XXXX#### ## $#XXXX -XXXXX#....#$ $ #XXXX -XXXXX#....# $#XXXX -XXXXX#.... $$ ##XXX -XXXXX#... # $ #XXX -XXXXX######$ $ #XXX -XXXXXXXXXX# ###XXX -XXXXXXXXXX#$ ###XXXX -XXXXXXXXXX# #XXXXXX -XXXXXXXXXX####XXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXX############XXXX -XXXX## ## #XXXX -XXXX## $ $ #XXXX -XXXX#### ## $$ #XXXX -XXXX# $ # #XXXX -XXXX# $$$ # ####XXXX -XXXX# # # $ ##XXXX -XXXX# # # $ #XXXX -XXXX# $# $# #XXXX -XXXX# ..# ####XXXX -XXXX####.. $ #@#XXXX -XXXX#.....# $# #XXXX -XXXX##....# $ #XXXX -XXXX###..## #XXXX -XXXX############XXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXX#########XXXXXXX -XXXX#.... ##XXXXXX -XXXX#.#.# $ ##XXXXX -XXX##....# # @##XXXX -XXX# ....# # ##XXX -XXX# #$ ##$ #XXX -XXX## ### $ #XXX -XXXX#$ $ $ $# #XXX -XXXX# # $ $ ## #XXX -XXXX# ### ## #XXX -XXXX# ## ## ##XXX -XXXX# $ # $ #XXXX -XXXX###$ $ ###XXXX -XXXXXX# #####XXXXXX -XXXXXX####XXXXXXXXXX - - -############X######X -# # # ###....#X -# $$# @ .....#X -# # ### # ....#X -## ## ### # ....#X -X# $ $ # # ####X -X# $ $## # #X -#### # #### # ## #X -# # #$ ## # #X -# $ $ # ## # ##X -# # $ $ # # #XX -# $ ## ## # #####XX -# $$ $$ #XXXXXX -## ## ### $ #XXXXXX -X# #X# #XXXXXX -X######X######XXXXXX - - -XXXXXXXXXXXXX#####XX -X#####XX###### #XX -X# #### $ $ $ #XX -X# $ ## ## ## ##X -X# $ $ $ $ #X -X### $ ## ## ## -XXX# ##### #####$$ # -XX##$##### @## # -XX# $ ###$### $ ## -XX# $ # ### ###X -XX# $$ $ # $$ #XXX -XX# # ## #XXX -XX#######.. .####XXX -XXXXX#.........#XXXX -XXXXX#.........#XXXX -XXXXX###########XXXX - - -XXXXXXXXXXXXXXXXXXXX -###########XXXXXXXXX -#...... #########X -#...... # ## #X -#..### $ $ #X -#... $ $ # ### #X -#...#$##### # #X -### # #$ #$ #X -XX# $$ $ $ $## #X -XX# $ #$#$ ##$ #X -XX### ## # ## #X -XXX# $ $ ## ######X -XXX# $ $ #XXXXX -XXX## # # #XXXXX -XXXX#####@#####XXXXX -XXXXXXXX###XXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXX####XXXXXX -XXXX####### @#XXXXXX -XXXX# $ #XXXXXX -XXXX# $## $#XXXXXX -XXXX##$#...# #XXXXXX -XXXXX# $... #XXXXXX -XXXXX# #. .# ##XXXXX -XXXXX# # #$ #XXXXX -XXXXX#$ $ #XXXXX -XXXXX# #######XXXXX -XXXXX####XXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXX###### -XX#############....# -X## ## ##....# -X# $$## $ @##....# -X# $$ $# ....# -X# $ ## $$ # # ...# -X# $ ## $ # ....# -X## ##### ### ##.### -X## $ $ ## . # -X# $### # ##### ### -X# $ # #XX -X# $ #$ $ $### #XX -X# $$$# $ #X####XX -X# # $$ #XXXXXXX -X###### ###XXXXXXX -XXXXXX#####XXXXXXXXX - - -XXXXXX############XX -XXXXXX# ##X -XXXXXX# # #$$ $ #X -XXXXXX#$ #$# ## @#X -XXXXX## ## # $ # ##X -XXXXX# $ #$ # #XX -XXXXX# # $ # #XX -XXXXX## $ $ ## #XX -XXXXX# # ## $ #XX -XXXXX# ## $$# #XX -XX######$$ # #XX -XX#....# ########XX -XX#.#... ##XXXXXXXXX -XX#.... #XXXXXXXXX -XX#.... #XXXXXXXXX -XX#########XXXXXXXXX - - -XXXXXXXXXXX#####XXXX -XXXXXXXXXX## ##XXX -XXXXXXXXX## #XXX -XXXXXXXX## $$ #XXX -XXXXXXX## $$ $ #XXX -XXXXXXX# $ $ #XXX -####XXX# $$ #####X -# ######## ## #X -#. $$$@#X -#.# ####### ## ##X -#.# #######. #$ $##X -#........... # #X -############## $ #X -XXXXXXXXXXXXX## ##X -XXXXXXXXXXXXXX####XX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXX########XXXXXX -XXX#### ######X -XXX# ## $ $ @#X -XXX# ## ##$#$ $ $##X -X### ......# $$ ##X -X# ......# # #X -X# # ......#$ $ #X -X# # ...... $$# $ #X -X# $### ###$ $ ##X -X### $ $ $ $ #XX -XXX# $ $ $ $ #XX -XXX###### ######XX -XXXXXXXX#####XXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXX#######XXXXX -XXXX##### # ####XX -XXXX# # $ #XX -X#### #$$ ## ## #XX -## # # ## ###X -# ### $#$ $ $ #X -#... # ## # #X -#...# @ # ### ##X -#...# ### $ $ #X -########X## # #X -XXXXXXXXXX#########X -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -X#####XXXXXXXXXXXXXX -X# #XXXXXXXXXXXXXX -X# # #######XXXXXXXX -X# $@######XXXX -X# $ ##$ ### #XXXX -X# #### $ $ #XXXX -X# ##### # #$ ####X -## #### ##$ #X -# $# $ # ## ## #X -# # #...# #X -###### ### ... #X -XXXXX####X# #...# #X -XXXXXXXXXX# ### # #X -XXXXXXXXXX# #X -XXXXXXXXXX#########X -XXXXXXXXXXXXXXXXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXX#####X####XXXXXXX -XXX#...#X# ####XXXX -XXX#...### $ #XXXX -XXX#....## $ $###XX -XXX##....## $ #XX -XXX###... ## $ $ #XX -XXX# ## # $ #XX -XXX# ## # ### ####X -XXX# $ # #$ $ #X -XXX# $ @ $ $ #X -XXX# # $ $$ $ ###X -XXX# ###### ###XXX -XXX# ##XXXX####XXXXX -XXX###XXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXX##########XXXXXXX -XXX# ####XXXX -XXX# ###### # ##XXX -XXX# # $ $ $ $ #XXX -XXX# #$ #XXX -XXX###$ $$# ###XXX -XXXXX# ## # $##XXXX -XXXXX##$# $ @#XXXX -XXXXXX# $ $ ###XXXX -XXXXXX# # $ #XXXX -XXXXXX# ## # #XXXX -XXXXX## ##### #XXXX -XXXXX# #XXXX -XXXXX#.......###XXXX -XXXXX#.......#XXXXXX -XXXXX#########XXXXXX - - -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXX####XXXXXX -XX######### ##XXXXX -X## $ $ #####X -X# ## ## ##...#X -X# #$$ $ $$#$##...#X -X# # @ # ...#X -X# $# ###$$ ...#X -X# $ $$ $ ##....#X -X###$ #######X -XXX# #######XXXXXXX -XXX####XXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXX#########XXXXXX -XXXXX#%.%#%.%#XXXXXX -XXXXX#.%.%.%.#XXXXXX -XXXXX#%.%.%.%#XXXXXX -XXXXX#.%.%.%.#XXXXXX -XXXXX#%.%.%.%#XXXXXX -XXXXX### ###XXXXXX -XXXXXXX# #XXXXXXXX -XXX###### ######XXXX -XXX# #XXXX -XXX# $ $ $ $ $ #XXXX -XXX## $ $ $ $ ##XXXX -XXXX#$ $ $ $ $#XXXXX -XXXX# $@$ #XXXXX -XXXX# ##### #XXXXX -XXXX####XXX####XXXXX - - -XXXXXXXX####XXXXXXXX -XXXXXXXX# ##XXXXXXX -XXXXXXXX# ##XXXXXX -XXXXXXXX# $$ ##XXXXX -XXXXXX###$ $ ##XXXX -XXX#### $ #XXXX -X### # ##### #XXXX -X# # #....$ #XXXX -X# # $ ....# #XXXX -X# $ # #.%..# #XXXX -X### #### ### #XXXX -XXX#### @$ ##$##XXX -XXXXXX### $ #XXX -XXXXXXXX# ## #XXX -XXXXXXXX#########XXX -XXXXXXXXXXXXXXXXXXXX - - -XXXXXX############XX -XXXXX##.. #XX -XXXX##..% $ $ #XX -XXX##..%.# # #$ ##XX -XXX#..%.# # # $ #XX -####...# # # #XX -# ## # #XX -# @$ $ ### # # ##XX -# $ $ # # #XXX -###$$ # # # # #XXX -XX# $ # # #####X -XX# $# ##### #X -XX#$ #XXX# # #X -XX# ###XXX## #X -XX# #XXXXXX# ##X -XX####XXXXXX######XX - - -###################X -# ### # #X -# ##$ $ # $$ # $ #X -#.# . .$ # #..# #.#X -#.####.# # # ## # #X -# # # # # # #X -# $ # # ### # ## #X -# # # # #.$ # # #X -# $$.# # ## # ## #X -#$ # # # # ## # #X -# .# # ## # # ## #X -# # # # # ## #X -## ## # # # # $.#X -### ### $.# $.# $.#X -####### # # @#X -XXXXXX#############X diff --git a/apps/plugins/sokobanlevels.sok b/apps/plugins/sokobanlevels.sok new file mode 100644 index 0000000000..869dcfe76e --- /dev/null +++ b/apps/plugins/sokobanlevels.sok @@ -0,0 +1,1277 @@ + ### + #.# + # #### +###$ $.# +#. $@### +####$# + #.# + ### + +##### +# # +#@$$# ### +# $ # #.# +### ###.# + ## .# + # # # + # #### + ##### + + ####### + # ### +##$### # +# @ $ $ # +# ..# $ ## +##..# # + ######## + + ##### +#### .# +# $ *# +# $$ $.# +##@##..# + ####### + + #### + #@ ### + # $ # +### # ## +#.# # # +#.$ # # +#. $ # +######## + + ####### + ## # @# + # # # + #$ $ $ # + # $## # +### $ # ## +#..... # +######### + + ###### + ### # +##. $## ## +#..$ $ @# +#.. $ $ ## +###### # + #### + + ###### + # # +###$$$ # +#@ $.. # +# $...## +#### # + #### + + #### + #..# + ## .## + # $.# +## $ ## +# #$$ # +# @ # +######## + + ##### +### @# +# $. ## +# .$. # +### *$ # + # ## + ##### + +######## +# # # +# $..$ # +#@$.* ## +# $..$ # +# # # +######## + + ###### + # ### + # $ # +### $ ## # +#... $ # +#...$#$ ## +#### # $ # + # @ # + ####### + +###### +# # +# $$$## +# #..### +## ..$ # + # @ # + ######## + + ######## + # #. # + ## $...# + # $ #*.# +## ##$# ## +# $ $ # +# # # +#######@ # + #### + + ####### + #.... # +###...$### +# $#$ $ # +# $$ #$ # +# # # +#### @ ### + ##### + +######## +#.. # +#..$ $@# +#$#$$$## +#..$ $ # +#.. # +######## + +######## +# # +# #$$ # +# ...# # +##...$ ## + # ## $ # + #$ $ # + # # @# + ######## + + ##### +### #### +# $ $ # +# $ $ @# +###$$##### + # ..# + #....# + ###### + +######### +# * # +# $.$. @# +# .$.$. # +# $.$.$ # +# * # +######### + + ######### +## # +# #$#$ # +# $$ .$.# +# @###...# +#### ##### + + ###### + #. ..# + #. $.# +### $## +# $ $ # +# #$## # +# @ # +######## + + ##### + # #### +## #$ # +# $ $$ # +# #$#.*.# +# @...# +######### + + ##### +#### ## +# $ $ # +#@#.*.# # +# #.*.# # +# $ $ # +## #### + ##### + + ##### +####. ## +# $.$. # +#@$# #$ # +# $. . # +####$#$ # + #. . # + ####### + + ######## +#### . # +# $ $ $. # +# .####.## +# $.$ $ @# +# . ## +######### + +####### +# ##### +# $ .*. $ # +#@$.* *.$ # +# $ .*. $ # +###### # + ###### + +###### +# # +# $ #### +# $*..* # +# *..*$ # +#### $ # + # @ # + ###### + + ###### +####. @# +# $$$ # +#.##.##.# +# $ # +# $.# ## +#### # + ##### + +######### +#. $. @# +# .$.$ # +##$.$ $## +# .$.$ # +#. $. # +######### + +####### +# @ # +##$ $ # +# $$## +#....# +###### + + #### + # ##### +##$ ## # +# $@$ # +# ##$ # +###.## ### + #...$ $ # + ##.. # + ######## + +######## +# #.. ## +# $. $* # +# $@$ # +# *$ .$ # +## ..# # + ######## + + ####### +## * ## +# . . . # +# $ * # +#*$$*$$*# +# * $ # +# . .@. # +## * ## + ####### + +######### +# .$ @# +# $ * $ # +#*...*.*# +# $$* # +# . $ # +######### + + ###### + #####. # + # #..## # + # $.. # + # # .# ## +### ##$# # +# $ $$ # +# #$# # # +#@ ####### +##### + + ###### + # ...# +####....# +# ###$ ### +# $ $ $$ # +#@ $ $ # +# #### # +#### ##### + + ######### + # ## # + # $ # + #$ ### $# + # #...# # +## #...# ## +# $ $ $ # +# # @ # +########### + + ####### + ### # +## # # # +# #.$$$ # +# #.*# ### +# ..# # +###..$ ## + #.# $ # + ## # #@# + # $ $ # + # ### + ###### + + ########## +## # +#@ $$$ $ # +## $ $ $ # + ## #### ## + # $ ## +### ##$ $ # +# # # +# ###### +# ## +#.....# +#.....# +####### + +######## +# # +# @ $# # +## # # +# $#.# # +# .*.$# +## #.# # + # #. ## +## $.# # +# # $ # +# $ ### +# #### +#### + + #### + #@ # + ##### # +#### # +# .### ## +# # # ## +# # $ $#. # +# # * # # +# .#$ $ # # +## # # # + # ###. # + # #### + ####### + +##### +# ## +# $ # +# $ @# +###. # + #.## + #. # +###. # +# $ # +# $ # +## ## + #### + +#### +# ##### +# # # +# . # # +##$# .# + # #$# # +##. . # +# ## # +# # *# +# $ $ # +# $#* @# +# #.### +###### + + ### + #.###### + ###.$ # # + #... #$ # + #.## $ # +##.$ $## ## +#.$ # ## # +#.#$ # +#.$ #$ $# +#. $## @ # +#.$ $ # +#. ####### +#### + + #### + ### ## + ## ## + # # ..# +## $#*#$.# +# $ # $.# +# $ @ $.# +# $ # $.# +##$$#*#$.# + #. # ..# + ##. ## + ### ## + #### + +######### +# # +# # ### # +# $$ # # +#@$ # # +## ## # # +# $ $ # +# $## # # +# #$# # +#...# # +#.#.#$### +#... # +####### + +######## +# .# +# #$#..## +# $...# +## ##.$.# + # ## ## + #$## # +## #$# +# # # +# $ #### +# $ $ @# +# ### # +#### ##### + +#### +# #### +# $ # +# #.# # +# # # # +#.$.$.# +# # # # +# #.# # +# $$ # +## @ # + # ### + #### + +###### #### +# ### # +# $$ ## # +# # $ # +## ## $# # + # #... ## + # ...#$## + # #...# # +## # ###@ # +# $ $ $ # +# #$#### # +# # #### +##### + +########## +#..$ $ *.# +#.* $ $..# +##.$ $ *## + #* $ $.# + #.$ $ .# + #. $ $.# + #.$@$ *# +##* $ $.## +#..$ $ *.# +#.* $ $..# +########## + + ##### + # # + #$ # + ### $## + # $ $ # +### # ## # ###### +# # ## ##### ..# +# $ $ ..# +##### ### #@## ..# + # ######### + ####### + +############ +#.. # ### +#.. # $ $ # +#.. #$#### # +#.. @ ## # +#.. # # $ ## +###### ##$ $ # + # $ $ $ $ # + # # # + ############ + + ######## + # @# + # $#$ ## + # $ $# + ##$ $ # +######### $ # ### +#.... ## $ $ # +##... $ $ # +#.... ########## +######## + + ######## + # ....# +############ ....# +# # $ $ ....# +# $$$#$ $ # ....# +# $ $ # ....# +# $$ #$ $ $######## +# $ # # +## ######### +# # ## +# $ ## +# $$#$$ @# +# # ## +########### + + ##### + # ##### + # #$## # + # $ # +######### ### # +#.... ## $ $### +#.... $ $$ ## +#.... ##$ $ @# +######### $ ## + # $ $ # + ### ## # + # # + ###### + +###### ### +#.. # ##@## +#.. ### # +#.. $$ # +#.. # # $ # +#..### # $ # +#### $ #$ # + # $# $ # + # $ $ # + # ## # + ######### + + ##### + ####### ## +## # @## $$ # +# $ # +# $ ### # +### #####$### +# $ ### ..# +# $ $ $ ...# +# ###...# +# $$ # #...# +# ### ##### +#### + + #### + # ########### + # $ $ $ # + # $# $ # $ # + # $ $ # # +### $# # #### # +#@#$ $ $ ## # +# $ #$# # # +# $ $ $ $ # +##### ######### + # # + # # + #......# + #......# + #......# + ######## + + ####### + # ...# + ##### ...# + # . .# + # ## ...# + ## ## ...# + ### ######## + # $$$ ## + ##### $ $ ##### +## #$ $ # # +#@ $ $ $ $ # +###### $$ $ ##### + # # + ######## + + ### ############# +##@#### # # +# $$ $$ $ $ ...# +# $$$# $ #...# +# $ # $$ $$ #...# +### # $ #...# +# # $ $ $ #...# +# ###### ###...# +## # # $ $ #...# +# ## # $$ $ $##..# +# ..# # $ #.# +# ..# # $$$ $$$ #.# +##### # # #.# + # ######### #.# + # #.# + ############### + + #### + #### # # + ### @###$ # + ## $ # + ## $ $$## ## + # #$## # + # # $ $$ # ### + # $ # # $ ##### +#### # $$ # # +#### ## $ # +#. ### ######## +#.. ..# #### +#...#.# +#.....# +####### + +################ +# # +# # ###### # +# # $ $ $ $# # +# # $@$ ## ## +# # $ $ $###...# +# # $ $ ##...# +# ###$$$ $ ##...# +# # ## ##...# +##### ## ##...# + ##### ### + # # + ####### + + ######### + ## ## ###### +### # # ### +# $ #$ # # ... # +# # $#@$## # #.#. # +# # #$ # . . # +# $ $ # # #.#. # +# ## ##$ $ . . # +# $ # # #$#.#. # +## $ $ $ $... # + #$ ###### ## # + # # ########## + #### + + ####### + ####### # + # # $@$ # + #$$ # ######### + # ###......## # + # $......## # # + # ###...... # +## #### ### #$## +# #$ # $ # # +# $ $$$ # $## # +# $ $ ###$$ # # +##### $ # # + ### ### # # + # # # + ######## # + #### + + ######## + # # # + # $ # + ### #$ #### + # $ ##$ # + # # @ $ # $# + # # $ #### + ## ####$## # + # $#.....# # # + # $..**. $# ### +## #.....# # +# ### ####### +# $$ # # +# # # +###### # + ##### + +##### +# ## +# # #### +# $ #### # +# $$ $ $# +###@ #$ ## + # ## $ $ ## + # $ ## ## .# + # #$##$ #.# + ### $..##.# + # #.*...# + # $$ #.....# + # ######### + # # + #### + + ########## + #.. # # + #.. # + #.. # #### + ####### # ## + # # + # # ## # # +#### ## #### ## +# $ ##### # # +# # $ $ # $ # +# @$ $ # ## +#### ## ####### + # # + ###### + + ########### + # . # # + # #. @ # + ##### ##..# #### +## # ..### ### +# $ #... $ # $ # +# .. ## ## ## # +####$##$# $ # # # + ## # #$ $$ # # + # $ # # # $## # + # # + # ########### # + #### #### + + ###### + # @#### +##### $ # +# ## #### +# $ # ## # +# $ # ##### # +## $ $ # # +## $ $ ### # # +## # $ # # # +## # #$# # # +## ### # # ###### +# $ #### # #....# +# $ $ ..#.# +####$ $# $ ....# +# # ## ....# +################### + + ########## +##### #### +# # $ #@ # +# #######$#### ### +# # ## # #$ ..# +# # $ # # #.# +# # $ # #$ ..# +# # ### ## #.# +# ### # # #$ ..# +# # # #### #.# +# #$ $ $ #$ ..# +# $ # $ $ # #.# +#### $### #$ ..# + # $$ ###....# + # ## ###### + ######## + +######### +# # +# #### +## #### # # +## #@## # +# $$$ $ $$# +# # ## $ # +# # ## $ #### +#### $$$ $# # + # ## ....# + # # # #.. .# + # # # ##...# + ##### $ #...# + ## ##### + ##### + +###### #### +# ####### ##### +# $# # $ # # +# $ $ $ # $ $ # +##$ $ # @# $ # +# $ ########### ## +# # #.......# $# +# ## # ......# # +# # $........$ # +# # $ #.... ..# # +# $ $####$#### $# +# $ ### $ $ ## +# $ $ $ $ # +## ###### $ ##### # +# # # +################### + + ####### + # # #### +##### $#$ # ## +#.. # # # # +#.. # $#$ # $#### +#. # #$ # # +#.. $# # $ # +#..@# #$ #$ # # +#.. # $# $# # +#.. # #$$#$ # ## +#.. # $# # $#$ # +#.. # # # # # +##. #### ##### # + #### #### ##### + +############### +#.......... .#### +#..........$$.# # +###########$ # ## +# $ $ $ # +## #### # $ # # +# # ## # ## +# $# # ## ### ## +# $ #$### ### ## +### $ # # ### ## +### $ ## # # ## + # $ # $ $ $ # + # $ $#$$$ # # + # # $ ##### + # @## # # # + ############## + +#### +# ############## +# # ..#......# +# # # ##### ...# +##$# ........# +# ##$###### #### +# $ # ######@ # +##$ # $ ###### # +# $ #$$$## # +# # #$#$### +# #### #$$$$$ # +# # $ # # +# # ## ### +# ######$###### $ # +# # # # +########## ##### + + ####### + # # ##### +## # #...### +# $# #... # +# $ #$$ ... # +# $# #... .# +# # $######## +##$ $ $ # +## # $$ # # + ###### ##$$@# + # ## + ######## + + ################# + #... # # ## +##..... $## # #$ # +#......# $ # # +#......# # # # # +######### $ $ $ # + # #$##$ ##$## + ## $ # $ # + # ## ### # ##$ # + # $ $$ $ $ # + # $ $##$ ###### + ####### @ ## + ###### + + ##### + ##### # + ## $ $ #### +##### $ $ $ ##.# +# $$ ##..# +# ###### ###.. # +## # # #... # +# $ # #... # +#@ #$ ## ####...# +#### $ $$ ##..# + ## $ $ $...# + # $$ $ # .# + # $ $ #### + ###### # + ##### + +##### +# ## +# $ ######### +## # # ###### +## # $#$#@ # # +# # $ # $ # +# ### ######### ## +# ## ..*..... # ## +## ## *.*..*.* # ## +# $########## ##$ # +# $ $ $ $ # +# # # # # # +################### + + ########### + # # # +##### # $ $ # +# ##### $## # ## +# $ ## # ## $ # +# $ @$$ # ##$$$ # +## ### # ## # +## # ### #####$# +## # $ #....# +# ### ## $ #....## +# $ $ # #..$. # +# ## $ # ##.... # +##### ######...## + ##### ##### + + #### + # ######### + ## ## # # + # $# $@$ #### + #$ $ # $ $# ## +## $## #$ $ # +# # # # $$$ # +# $ $ $## #### +# $ $ #$# # # +## ### ###$ # + # #.... # + ####......#### + #....#### + #...## + #...# + ##### + + #### + ##### # + ## $# +## $ ## ### +#@$ $ # $ # +#### ## $# + #....#$ $ # + #....# $# + #.... $$ ## + #... # $ # + ######$ $ # + # ### + #$ ### + # # + #### + +############ +## ## # +## $ $ # +#### ## $$ # +# $ # # +# $$$ # #### +# # # $ ## +# # # $ # +# $# $# # +# ..# #### +####.. $ #@# +#.....# $# # +##....# $ # +###..## # +############ + + ######### + #.... ## + #.#.# $ ## +##....# # @## +# ....# # ## +# #$ ##$ # +## ### $ # + #$ $ $ $# # + # # $ $ ## # + # ### ## # + # ## ## ## + # $ # $ # + ###$ $ ### + # ##### + #### + +############ ###### +# # # ###....# +# $$# @ .....# +# # ### # ....# +## ## ### # ....# + # $ $ # # #### + # $ $## # # +#### # #### # ## # +# # #$ ## # # +# $ $ # ## # ## +# # $ $ # # # +# $ ## ## # ##### +# $$ $$ # +## ## ### $ # + # # # # + ###### ###### + + ##### +##### ###### # +# #### $ $ $ # +# $ ## ## ## ## +# $ $ $ $ # +### $ ## ## ## + # ##### #####$$ # + ##$##### @## # + # $ ###$### $ ## + # $ # ### ### + # $$ $ # $$ # + # # ## # + #######.. .#### + #.........# + #.........# + ########### + +########### +#...... ######### +#...... # ## # +#..### $ $ # +#... $ $ # ## # +#...#$##### # # +### # #$ #$ # + # $$ $ $ $## # + # $ #$#$ ##$ # + ### ## # ## # + # $ $ ## ###### + # $ $ # + ## # # # + #####@##### + ### + + #### +####### @# +# $ # +# $## $# +##$#...# # + # $... # + # #. .# ## + # # #$ # + #$ $ # + # ####### + #### + + ###### + #############....# +## ## ##....# +# $$## $ @##....# +# $$ $# ....# +# $ ## $$ # # ...# +# $ ## $ # ....# +## ##### ### ##.### +## $ $ ## . # +# $### # ##### ### +# $ # # +# $ #$ $ $### # +# $$$# $ # #### +# # $$ # +###### ### + ##### + + ############ + # ## + # # #$$ $ # + #$ #$# ## @# + ## ## # $ # ## + # $ #$ # # + # # $ # # + ## $ $ ## # + # # ## $ # + # ## $$# # +######$$ # # +#....# ######## +#.#... ## +#.... # +#.... # +######### + + ##### + ## ## + ## # + ## $$ # + ## $$ $ # + # $ $ # +#### # $$ ##### +# ######## ## # +#. $$$@# +#.# ####### ## ## +#.# #######. #$ $## +#........... # # +############## $ # + ## ## + #### + + ######## + #### ###### + # ## $ $ @# + # ## ##$#$ $ $## +### ......# $$ ## +# ......# # # +# # ......#$ $ # +# #$...... $$# $ # +# ### ###$ $ ## +### $ $ $ $ # + # $ $ $ $ # + ###### ###### + ##### + + ####### + ##### # #### + # # $ # + #### #$$ ## ## # +## # # ## ### +# ### $#$ $ $ # +#... # ## # # +#...# @ # ### ## +#...# ### $ $ # +######## ## # # + ######### + + ##### + # # + # # ####### + # $@###### + # $ ##$ ### # + # #### $ $ # + # ##### # #$ #### +## #### ##$ # +# $# $ # ## ## # +# # #...# # +###### ### ... # + #### # #...# # + # ### # # + # # + ######### + +##### #### +#...# # #### +#...### $ # +#....## $ $### +##....## $ # +###... ## $ $ # +# ## # $ # +# ## # ### #### +# $ # #$ $ # +# $ @ $ $ # +# # $ $$ $ ### +# ###### ### +# ## #### +### + +########## +# #### +# ###### # ## +# # $ $ $ $ # +# #$ # +###$ $$# ### + # ## # $## + ##$# $ @# + # $ $ ### + # # $ # + # ## # # + ## ##### # + # # + #.......### + #.......# + ######### + + #### + ######### ## +## $ $ ##### +# ## ## ##...# +# #$$ $ $$#$##...# +# # @ # ...# +# $# ###$$ ...# +# $ $$ $ ##....# +###$ ####### + # ####### + #### + + ######### + #*.*#*.*# + #.*.*.*.# + #*.*.*.*# + #.*.*.*.# + #*.*.*.*# + ### ### + # # +###### ###### +# # +# $ $ $ $ $ # +## $ $ $ $ ## + #$ $ $ $ $# + # $@$ # + # ##### # + #### #### + + #### + # ## + # ## + # $$ ## + ###$ $ ## + #### $ # +### # ##### # +# # #....$ # +# # $ ....# # +# $ # #.*..# # +### #### ### # + #### @$ ##$## + ### $ # + # ## # + ######### + + ############ + ##.. # # + ##..* $ $ # + ##..*.# # # $## + #..*.# # # $ # +####...# # # # +# ## # # +# @$ $ ### # ## +# $ $ # # # +###$$ # # # # # + # $ # # ##### + # $# ##### # + #$ # # # # + # ### ## # + # # # ## + #### ###### + +################### +# ### # # +# ##$ $ # $$ # $ # +#.# . .$ # #..# #.# +#.####.# # # ## # # +# # # # # # # +# $ # # ### # ## # +# # # # #.$ # # # +# $$.# # ## # ## # +#$ # # # # ## # # +# .# # ## # # ## # +# # # # # ## # +## ## # # # # $.# +### ### $.# $.# $.# +####### # # @# + ############# diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config index 95a7757e53..cf5ceccac5 100644 --- a/apps/plugins/viewers.config +++ b/apps/plugins/viewers.config @@ -16,6 +16,7 @@ m3u,viewers/iriverify,- mid,viewers/midiplay,7 rmi,viewers/midiplay,7 rsp,viewers/searchengine,8 +sok,rocks/sokoban,1 pgn,rocks/chessbox,1 ss,rocks/sudoku,1 wav,viewers/wav2wv,- diff --git a/manual/plugins/images/ss-sokoban-112x64x1.png b/manual/plugins/images/ss-sokoban-112x64x1.png index c0fa584d0c7481e2de1bceb1424073d11a71726e..c0bb499ded1f04b3c4e6e78133ae58ff83b7551f 100644 GIT binary patch delta 321 zcmV-H0lxmx0^tIXDSv+DegFUf|C>sF00009a7bBm000XU000XU0RWnu7ytkO2XskI zMF-ad8WaH!DPU}10002)NklxF$;n~6u|L|a5xv|hG@($5jeW(azay+i<9^X ziY&3cB?vBupj+A+qc7EvOLgy3-V1^@Z}9l>mpeUPO~Qa`V0F+{c9*VL9Ftw*Sfh7r_dLrH5W1g2E#?=21m-& z54E52ig@EMNR)!8J6Rv%Yj~buVF1DhP7(!ls(rsXrG{E>woOKK0)_Pd4k?~)aqC0 z+$}FxVF4i_Mi7!Fxx?opXW4xGNC**_8ZYR84(Nam=ztD*6u^_e&IN2&8@X?$zzf*k zOo11$YEWQ|X^Vo{nYJi=?0(y#z<{K97pbI+r^~FD;U4+*xW8B1!VW4;nOPMb~z~&1<@30 z6a=@&POOZAnJ?QFO#M2Ly~v6GG4;71dy)A6ZT(!YK=vZ>zge65T#&uUP2uYdA4nF6 z6W?E68*)L?A-gT+b3xJ}TN+da9Ef@a@h-%H$d(3O!GAc`D~NX?c4D?P(r3CSQYQIsj1eH6`ow*rX_+!@cH&NdpimCJlh3 nnA9mW`k*oj555xH>cSuYb$%PLHfwSK0000iC&hHx4djyBh$@W8veM1}5%L7h<9#Ls2Gyezv+^@Jm)NSF{nae*LGBX)9;~bl3mFVV7}}T)1TaW&F*q|OXeel1`~5I-;}T@?!$l=IuR1TR zi3oBCxueS1rl1lt;UGvc0}sdq2{rl9>1}bfKW{u*e$KxBeT~ZRv@jjhG{?h}AAU&r zam8)dirI{xZ&!8$8Nv!mSG%j~tmWtNoW1@`c}8Pd<1T?OcP>~kziK?XWxJf@-foM1 zeit5y%@WA~A5J2U71+J;V>uWtE3gWt?~?sH`4morTz6Z2R-V>!51e%`WL z{N);jm9rTYCH;0+O+0tUb1p;XRMyrj-6dfYuCy+A-gZp#!P%y5Up%)piG(`rj(Pg) z+_}H^t*n{KjryA}oBK!ftDTj$$Fo=Ad`b72qn>E34o#H17WeEM&x&=`&hp>4zyFhCzre9AkuaRr|60rW%QLzhZ;g)fot-?)mO6MQj{nGY$Ao*Zj+0HrEl6?#J=(wuP zPEjh_DiL|#HujCp4vmJ*3dMUY19DCkysNJlnE2=0^6zI9d)LjsU-s(Y@ht}LSZk|7jo22` z@S9Uu_x>!?SNddr|MrEXhI36dt7CympI@FI^yGleuU}@L=gi!?K)~sharn83*_uzj zHgA4y?Jv)}I`%BXJORgguzHE?DsDf>ZKb zb(R{jD@_w#O{hC#`#|BDyZH9#35AySdT)%amvZEqKl~Ncv)~=$TfMH;XE)!P>hW~> zq9}fkguuGXb@RTuMou*>dG|AuEr2`AegAiFbp?lCyW^uKaX7|RZH~9~;rQ}h4WDA87_6H>x=J9#Lue4TBQ=CEjWtfGp7Lv-ZYXo)67 uhJd7Tv|K`0LC*)t+SSfq>z};-!+iGh&7F7ZbWQ1qogETxHl7ArL+)1b{$JJiiczLhb zD56VmILODB_ujqZC6>agYpu{fpsuBtiPGtIwhVz%?-WUlUg~=o#kClt+h7Z$w1Z=X zeqt}Lt0cOiXup*8Z4@07#09BqZmBOV0CH&owfaDi$Shz+tjL`{Js3!Eu50n@HY-|@ zR|8~$7i`W@bbr`rF^xKE_9DM(9%#!?w&&JS(_zKB_+{f1l?p@0MOH9g(;3rBj{4)w zN(MO+!yRoUy&OgEI@3seX5`oU5J}arb~9^WSmz35R8k+Y(ACjBX|!~xH6oWLU21U} zE3?9nsX`VoN#@bJu%FSu#4R|%!`BXdgr43&BJ{fPcry1}lU5&W-jz2{cp+qPUDtpq|00000NkvXXu0mjfLDax4 delta 467 zcmV;^0WAK<1K|UZ7=Ho-0001mJY!=3000b7OjJd!*yeMPnK?*I000158Z6EL000Sa zNLh0L001Qb001QbBJg5R0004dNkl>D3(+$;5cp%z!NT<{DSF>u=Nn!+IS@c_Tyi((k@2 zwx}3CGY!5PdVivqHM?K)>^xVybacKnBU(eJLH9?y{T!KhX)x&i{4u;Rn7rOwy*!>V zqZk03quHAr-5&@cG|IBjz959aJiLa!A%qZ^MG@Ksgi!YiGLz?UuW6gr8~P7wj;JYt zzSBdP9-KWiAhXi;+gTz{sIR@SUN07b?^WH002ov JPDHLkV1mY?($4?@ diff --git a/manual/plugins/images/ss-sokoban-160x128x16.png b/manual/plugins/images/ss-sokoban-160x128x16.png index b267cf70b60628c7a59405f1d202dc52b753b4e9..53761aca5ba38262bf03e6c1371967c6f87fdfaf 100644 GIT binary patch delta 687 zcmV;g0#N<+3A+W57=Hu<0001fO@Al=001OVOjJbx002lxNcaE%fKUJkj0mu75Fn8F zczk%sgeb7Y;P}8``1}A}{`SfM000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iF4{ z7YjOvdj60A00JsWL_t(&-tCyNPQ)+_hO>HPy8Xl(z!N|==6^~&0XtKl0I8$bz5+Ab zy&U$X%>`&3hnk~DVzl!tbc%{Eyif5kkrLfth(H!@agnn>oNhWE;sE%nzCW0kiTR~)#b6>Wnn`$ zl~Hy%#+=cMcAG0~0+J{K76SXl6B}$5284E(g`@@=xr}0f6=0UsbsaHNTvo_q%-@>A zENU1ALUCM4>Is#~=z5XL3Wqn=MsY2vFF=@0UjpV;>wlhEA;q<%hTMcu3<`zCl(+1| zY-?%CvdcPP+JO@)#O;}q&gyBh?@`X>04jy#Lh|?Fcq=Nz???8E%L&LXAET7ZgbTVg z%u{}m*ANj^E@x97@9w2srcNDI3d?jB%8GIg%Tt*(5ENMr9_T!32W2c8rIHsttP@wEA)jWH}8RZ=%qSqB&J#?K9EImC%FP8O+ z#2Y2Hy$udaipBsCC{FH`>6SL`_c(_jpcYJ z?Ro$DiuykHBmGN1W_-~48aer{)4>M;1{NYbe5}pRaHe}|_un-iGah`-5}Bhtuhx*u zufOxCmdxwINck^3k=)-F2?GsV6|qJ>-)cE8P*QaIc7E^Vi=U*vJrbECH@|~tpK$4c z-vmbhjTB#h+ibZBW>;K4yeSkbaJUtq z9^tZT!5rIjZSKyWH&?5Cb-&iVOT>3u_c4xj>T$(;%AWj4e#I~A((-PL+d;9*msgq= zeR{3(wfz)ZY13KptgmOITwh&&KDA@Ybl2lDPgQO@uJS8LZq0c!tNGKW1ktzsRtF!2 zTnwJMZtmn?%GC#dA6z@*OpLw4yo{cN-D!5Bg;$b7E(%`IuxR-EG9kZfm&n`8>3pxl z->0)j$FlqmIg$AH)!#LHuX0XXpml3`{NDMpIi;Gja>PqtFS=WlS-$qv4A-z#r56K( zOCr`*Z{D!J*52}z^fQ@tYXo^^-`L$gai~M<##_bTGCXW~+~tY3d9xR9Xui9nJ+<6L z^v>pMv3mdi?vvlP&$YJi9A8=O=LM1*%Op+RDv#e&d70C6Y~3Q}th-M?-LqNKx>EMw z)a!kgi#9dOZnM8(zc+i2&!!Bo{c**oPA{6b=<9{I$I|NyY#B@TN97z;Ty1*KTK&P2 z7t_!D`7bkrZ(H`o%@N)*2j8hqIQ?^x<-ag-Z9z@7){dC7{cG!OXD+ujj+aWl$Q57S z_gs8~%KAlTE6SB}S5KJ#{+!E_KYxRrUVonPJa5J66~AB4+xab#y>oR&VOVyF&ENf8 zKa*68bd~&-o-Rqy-_?60v?O`{%|#oX^wf`DKI-Li%JbrnQ*T_QFNI&s&c3@%>(|}> zbis-CsjrL!d|zqp%G}!Kn%w&5X`X6Pf?VzY0FQ{;dH$lZK94xQz2uL#R5mZt&yTND z&lBS<{<8kshdmSCda~`!nE&p}2j5>@mCB3mmY!H3{`T_Rd1s5)PAIRvuGk#6CA_?9 z-Ny5Krg4-{1KP^?qh$G4<_i0WrmWbHFa1s@mWdY4VU-JHZ4ce{&T2y2RjHXJ^R)lu zvwu}-7U|t}U%;U0@PoR;b}0%G1>dFJ6t0(Eyp#XJQ%>;A-?oEK6mK{k=6W7;Lcz88 zd4jxAN5Z;mFPzz$T34G^O>pc|t39FIv@=S11`o^Y_}L33mmy_~1Vj!QQ05$-e{1-7 fuHG-{KN)XPRF*AX+4l!nb}@Lm`njxgN@xNAE<;eJ diff --git a/manual/plugins/images/ss-sokoban-160x128x2.png b/manual/plugins/images/ss-sokoban-160x128x2.png index 8cd23bdadb6c90fc4d09964157aedb6b8a8870e8..6f3833da7336ae90782aded01584a3779554826c 100644 GIT binary patch delta 582 zcmV-M0=fNy1m^^hEPnt10CbR=I!H~{sRzjb000SaNLh0L01FcU01FcV0GgZ_00007 zbV*G`2iF4{6Eh}*?Y8&;00HhvL_t(o!|j%_PQx$|h8-!c)C?q*lIQ6~N|{}$UV$|e zufm)G!IGsC8w~6Wyh?Wlrf^OuwH-UTmP!aIH)Z(r`+nblNq-odYO1NG`oATAY6OJ+ zLvSvz=qMn9i~?q1n2|szLI4UV^F)$B2ofM1z1m=dSs+fmM>Q%z0qd%)?@m+k4mjaz;(@q zt$3xtWF<`ySg3=lxu+Jq)LpA}p@WECT>t}Y%&;cJU5EWS##(s zu0sTuZ>D0B^gxU^g7M6lH6+5(V|%pKx#MIlJEjxQK`p!0OV4Sx7tGSO-tp2!~g&Q07*qoM6N<$f+Rl;$N&HU delta 480 zcmV<60U!S71cC&REPr#5nK?*I000158Z6EL000SaNLh0L001Qb001QbBJg5R0004; zNklm@CHn@qv>;6xKJNTWCqWpST1fC&`}FU0$6C>7PdQ9BAGSFBH}J}wG9t^NB5iU!rr z3{nT4z4na{Dh6Qv!iQn}t?Q$qL2?*`?gs@^Uyggihs0EU2Xgo-x12ns#xOtn4E2hFR@$C7!WSX+>5cpndj5C))T z+<}IH62jS@5+CqPI2B>Mp>LYbo;8d&!0X4^4TtdtxLVI1A&fV+o`+o+LhEiEiYMp3 zX`#Jmy>If{#(`1>D(3fYMQO%iE+d=YDF@z2BHV;p4_U)_z7ZFUgP2W?D{buYX2Ht^ zML~a zmdll_Y(;HjlM+NE0Vo(6I=uc+-{hCWWVC{V9qeESJJ`VvcCdpTeBI!1ZuJ1e|3BfC zgG(}k5qRnhCK61*yv|_YouA&|5CD<){)#68L+2W^+@I>wo{$&v@!hg|gAcp+^juIe zR)H762N@i$Lx1ric-I?DT4Rg`ib-ueMwKh76~7$6Y+ONLl`E=!Orj|9U&X8NMLrw zK1#iUut8trT#7fj#)znPMLxXehexSb(2WMwipzE(jJ=8)ms5kPAw-KhSCs8SRIK)K zIW@=_LVvWVd-KY6(NA$XHR$k!Xwh=}R|U?NOS&p>wt!WE6Y>uSHCPomPq_kW6w85g znR$VwrvxB^Re_Uv@ar3ZO0j%#nvp59qy(UGg?u^v0dvaAfd%?0Mwknd5`e}P^5wMA z#|p&_VAbW+@`IkX(bt02qp2PojKFB681TkwY%=BwJ0IT|*zDu~*?;C>2Rqoo4tB7E f9qeESn}NRp7I1ff9SmZV00000NkvXXu0mjflqx#V literal 1323 zcmeAS@N?(olHy`uVBq!ia0vp^8-Tclg9%9Pw=>%Wq&N#aB8!2vDi|w$ND5$JV7cq* z;uunK>+Ri*dAGwvj(vQ*hAGdC_K zFJp>hQgLQ}!OBx{MLEK`u|(n2huzbsWz5?1J?7beX{OGF!dAa3^!fSM7k_&9_?*Gs zvsE*H3sn6y`_5S7`e%Oi?603@-#N|@&%wgd*q|UFz{1qz;2^-k!NlmOFiGlT-P5$a za~{1@Z`8Qz^4*rxrS9v_dvo5s{k(5);UYyv2YuzuXRB_`dHwdf|J`&Q7Nz|U_SAnb z46lFX$ahJGr}4!4^OEz|1Xn%UuWrqM*7N?oi2skxrEkx7H84H$yQJ>wXZ}eJDn?)L z*k5xDN`={~z~SP@Cx28;;HHI7v*jMc(!a-7Gsb`Y^?mzJ{y!%l-4>GDA*~pezWVCT zS1a`m#LAVAe7jtBfV<~ttiqW!mM^!@-?n;l=-<~5b$9Yt+THP$JaPIl$HjRZudcgq z-}A%ryCeUj4Z9y23N+rHzWv~|&->38%U{Xa$?a0>cp*m8MET(1_0`7FF`?|=3eP1@ zlq?qSILEcf&-rgsVQ65g&+%9VomED8Z@;~;+sVIEygi(!F=<}=iuA5;+&)Jha|m7& z(LcLL`8ibKYGmJ=J|G=vu1ET%)$DOy=Jo?ro1>)KT)Lco+Y+iWdz_ zVzycPTyi*K+hM0a?eq@T0{K1lIr8nY6V92|)~WCwG0twh`|khemtQXKU$nRXJfBB( zVfkLwh^03zyJRA6XD+@c;vbvJvx2p3H~-h$*9-*u1bq4U-X!Z;D;%z~J5qAF_xL8` z3#PJPZlxE7Ze7k}&sRUKw$9F_x?~mBPp6b{CIk zJ`+^Z(@b9fe)swJe~;cfv+DGzGwa^RvFxv|oBrMU_3FqvbgHKY=G)tB zun%*rsr!HGjM)D_sm`ybPq|;c_V2^3_U{i@%hg&hIuqLF>hCQ3qiCgq-nX>;vu_UO z6h>Y=E#du4Yw>1(!53>3#HL?8475mWdg$}{KKjWs{)8U881-PI*5h{b`Df4ki+%Es zFHN<4>cy`nAqzG){doKL-kT+L-=F(Wqa6EITN~o^)es{hv9Z$1ex8mgq@c-l{!+WrJq& zy4MF|pDqY=P>A547sS}O;paN`@)cJ~CD*Xe_mEU(d3|uQrm_GdzqZb^RSlZWQ}1eu z8aRD03GrfOIaDE~wUB8U&ytX190xB4oD>n@_;OXk;vd$@?2>>GZN4fw2 diff --git a/manual/plugins/images/ss-sokoban-176x220x16.png b/manual/plugins/images/ss-sokoban-176x220x16.png index 157499dbecce90db3e83fb68909f2a508c3dea15..7251d244c57b8b0814534ae496df7b0ada6e7861 100644 GIT binary patch delta 864 zcmcb{^_p#hL_G^L0|SH7dNUs&r5@lD;tHfaJUo6dFf;@(aP)9&$PrMO@S~!p;zWza zh9eJt97y=^hU3Q{21DmZ3P7ct1s;*b3=G`DAk4@xYmNj^kiEpy*OmP`vy`}mez!;T zO9lp}>z*!-Ar-gYPTSZgY$(tcdtrwQS64>hy?TZ?g$*$(Q`(pgGJjz5X!rZhpuY4= zsD`cR`Uz8B7V)Tb=V1WRp={<)7l zbaU0X#5OCPdi>+1FSpFy&#U#z1pg%Oj@-1igeqs2C* zu$nuvTx(v~FBR_ZKYqAt?(upxPpOi za;U!czUv#5zI^xlc(&L7{w6p1=DCly%iq)0{@=92^~3qYd~@!;xchAO*T=65etoJx zuw)05#nvVfpq81{dmbJ9^0aa9@uLYF*LXaad;Srq;(%YFrA1W#6Nh6drDi|GHP6pj zGvmR>lUA{)%0daEaJPwx`xuYhU zGx)OWq#aFu#$Y1*;U;%N10$ORl&D8AfvgArn?nyuvAljV`>dJz6u0#ZIevDgB3G7o zJXrCpv3L0l7MXpoZ8lsw_Am687dw)IGMkPwt~spAqV_y`=WQPC$Tb1)XV|hi zdkWP)yL7O*_u8t`xRu#D0-hWE)`cf8)Y;&vp|DP4m=d}l(+yA$F&n&kruesvOkBb$LAN_f>dHd@3uWrwctLL7} z8Myp8XQEk%f#NbF#an6ZE0UdjQk}M(1D9+}S&v@2pu^bLHIpkBJeF zPM>=nF1fwD+$JGaQb4ScucyiLqExhMR*a=o9!zSK&(bi!{3q% zCzt=XO|E_0es=AYzF%c~U#@$mcQ8w#k)l<_?=8KYhM�&*r>%Ts4B1C9vxLr)%-c?|gmo@Z0*o>Ase$ zzItzv;#jm+b`g;AM&Kad#bYfQN$nE5cCego;rL(dbSKT}P3Xfp$p=55jlb1&J%4`A zuGc?uk3N=N!Pc~*`u?VzOI1IL_Evq>oO^e#U{%1ae-i_DEZCO-6#a3to!zG1_}+}a zDqG|wr@peA627h0)~3Gr>yMkIyib=KmKaLA+4^)Cc6{u)@ao_<1vTG}>GJO9R=?F( zcs)Y^qT#8^m(ySWhOeGoKW+Z8ugWC`>QyrY4)c|DBuezXi;ewP{QuW_wId5x{0@k_ zc}+HH&BHX|vJU6K^0&bUuW^379RE5|qV8{AX>GEB;;ex0u2p+~uABTYN22ZF?5hSm z>hJUJXvme$h`(jU%d+vh_ha+@XD{CQJ*^bz3&Y)qZp*X=UspR4_x9_hACFpIR72ux ziy=6^Yz-8fIDvt+!TC)ur=U*5XW!eE2>}aA22WQ%mvv4FO#r-gIlBM= diff --git a/manual/plugins/images/ss-sokoban-220x176x16.png b/manual/plugins/images/ss-sokoban-220x176x16.png index 554fcf77987e9ea4523e76c44c38b9abe9cb35d6..afef9c68068b6ddf9aedb76b64fecdda623e66c9 100644 GIT binary patch delta 877 zcmaFM^Mh@IL_G^L0|Ub}C)vqBNQL70(Y)*K0-AbW|YuPgg?W+`!bhWr~J z${84#o_M-AhE&{oJHxO~*ifV`_QDPquC8saJL?%^6by1yrnE5~WZc0Zl(CiF!7FoB z=&!XqoPw5}mgBOYedb*E;;+@;db*#MFS?k~UGw{YUHzZ*GuvJo9bjaaDZoyY7w(l= zxB6tE`Tf7I)857ZdlvTR;`D1J7PJ4I^vy^!To>+UUUX-|^PJ%NJJrRb@_I9Z`OSSjje$cb=+{MuBXKOxt=c@gD$>e3M6?cdK(90tCONZ9|%x1|f;BQ|S zdnWz$-F?~OpKn&}e_yh5_2IW)EW-2D-p;+|6Wp?RN9)NePuGRSCd+hN#s@!$ICJx( zK|R}!BxCI&@hgU@C7*c;Qq$_i#O|bzaP7E!R%^QTW37UiyT26sKd;uWI~Or`X3X8f@)NT&bL0Q4akyKccJAA|3Y#@W zJG&P|{9(D;@mQ#|XpSv!*2k1zdnfy(#sBe%ll6|Ynt6I+@$tgUcWND#KUVo%wyi(P zcxC=7X8!miJ2?BpldoFb|1Nj6_Rr#jJ3l|R$yeKYvvF5-@6305GSZ60cl}ztt9}vZ|3gJC->~@D-@Pnzv|?Z9Sh!_{k{FP+VaYX zmOoQIZqRzR=T+_3zPgh~a$RIr3P0X*RNr*+72ovwv`aG=?^^!YOiAzET#@V1>9c*( z?i;VQD6a`SbT9SMv=UKgqvY?wkD9Cu&&~L8WPSZR^*_B1ugxnpUcP$HFOj^t_pX26 zZsnK}!-?f#*kGh6RL12dlmR^p%Yop>hx1zz*MrN{s?0)wZkpUXO@geCy~Ev**- literal 1645 zcmdT_`#aNn9N$S)2(hg?cxnX%GwTSFHahE-#-#QAbA{c`?+^E~hO`}KL=m)Gb0c|OnQ{Yg9E<*uo2 zqz;3@G(GTGB7|Z{D_5_8tW+y!7J@aW@Bvf^5zD&mW7q*0Ol`9V*3CCwG&!&}8tws0 zee0nY%DtVP={vsp>K`loEYmg+n=f6y?6wADvQv+3URh~Zd55Uw3%FT*(Dt=-wB|Nl zP=U{(6`d0k@y=g61YghdGq`C3jYh)6qrL70jW(JuDE0*zpOct8+Pmx7G(n)?sCO%^ z=Lxzn#rQu2%e=}vyHU;(dYb}8?-R~lHD6a~C`UI3C(TFFUs8{WpK_wtR_6-Q6|r3f6aW2R%P)-@?I^%o_{1PcO`qLEop+S!tV0aze3w*@%8I?<_2xvN zhH)D86ApMzDoW9iTKqtcpG*BMETpkwkp`b#b!%~kG$HX#54-K0KKXkZi`CWWvJ{s~|tsapV0ay}HOwmE0EG*r}x0$U5n?e5{XYqeALs zPt(V2(Eu;Av#eIL@A!n7BQnk#)60(1elS&VFbXU;$>&~qU7CKDN>VE049U{fH z%f%#UV_v401F_tuM;fAS4Z;4LsR2{R-MsoT(&^bGXEU(mO?t`hjp2?|{&s#_v^E`0 z*gXR3**rIpDnSGj?9iOeJMG}FIEhlMzlY}#6rC1qnVG->r3a_T^12=bPWP*~ZGaa` zJLKH!Wy>e#kNWdZ&SM5i^cGw~%?@FyOVO<;3XVfi)+b=1teDa8Gk%To3wtXB=4hb6 zB;PHFb&dDDdZktBwG5;(vvVrM>QL;nM1F%E+d0K?Rs6V%pwHq%7wTJsY#_$IX)x~X z6+@N}j)$++$ML^$wlrHR>w0#$npM{=RL+iz#>Ygl`kwtN;X0K0d}c@-H-P74)J_rJ z(W%sH&s?$O&Y~2|%=X@mv&uHvcf$?*6o=7rAXb4c*=q|K^s0#_96Y`Y_wI zb>WJ+ry3!(Y&J$NqSPMpE?*GlXasN1asx^Fp)pcAe7*%PZ!sX33}FM@IHGwz;M?wud&+ICt~XZ7n}y>QOa$OJw75@#3ob9lcfp?xc|na z4a;Y_B?;nDtpudg0^ro?sqW!PSNGQ3xQgw|WY{qs#m&SMkEN|*L$W}&o-F7P_Gn5D zDs7)7v~A%Ru^U9%>D)mxR(;%=LMM9c(PZfLGKw?7iBW%q%VhU1A`(~9gr8e&N`ade z>rwe4J0j*OzP}Y8(UMn%W`ImPVzoUnaNnYBobS{lm_~cM55znAJSI>_OHc$bZC&+T6+rwOJOSb`Kn%PGxVwAR;o77-y zFGB9{0Enec)&E(y0m7{PTB$wYmAzCbuz=DLRA4EZM}(M>>4nJa0`PlBg3pY5H=O_Up{j42%p?KC%`J49pguE{-7;x8B~^n!M9_4yXT+l{PzOC2rRpWSjj*%e(Z%w(b?XcGMiW&m42%xZ<51 zyZ;$a%=(dd->0zQOxW#ML z^73MfR&BHWeZN5LUjNssTJeXE4+mX2e(dU@$|I}U72kwg-?K{Q4w~y;bK_m>%5B?Z z^Vga@$`hUY=HtT+@m;?xCT8xL%2#c9r#pi4cJjpQpazahURKDOV_x-qv;;ZR7s-V9;b}*wS&i&Y~TLYI_B(M z%{B8C4?miH`epWGlgrCF!#VG_pEznhU50P_jIssWT{nDrHfjID?e)U*)b1<_@y^#{ zzS|#sWZ!`!=F=ZOeEXunYwMS1LFOD!3Nqq9vM$Q|BFSa;b*0$(iqglq`}>cIckKFD zrm&-|-#a)q`s(*p+($03pAadiT$P=8l{IO>_U)n{CjUQ^wuqI7Oz`La!Fq;1BQame TRX%%x*^0r_)z4*}Q$iB}KWDII literal 2035 zcmeHI{ZrC+9B0d?&}t=1Nj#fYW_4MiF(f5YAy?|GOs!M%3A{o%Ow%Bx*{bE)*PKr& znh(u~Mrx@ckZ8K8K$@rt6GTeINK8vbO;q;vcDLL9gZ;3d-VdL9zwdpo&-?Xy-}&B$ zumQRa3V}d2cpdjR1=^1g$QMUVzFfo8;E#y>@zQ!!htY<(_&pKq4tU+W6~0z|BihJGTrN^pC;T>mlobdQPyP z-&5hC#>7cJGWmAmJ50~RDNa;i+il_WaPk75Uh9axa&Lqw@r7L6;^b%G4a1pxiaj>} zSKMq}b@9=Hyq4A1AAK3~FKssH=OVVNMXzigw9s`^%Wpr=_pf%M7*T12{e_t~b}xj4 zrjS<C9`OO}~kSzwFQ zU1@OMA!Ph{qMA5-(IU@m{h=J+U;Moi)Ll^9pYI2OVSb`#Yi5lPL@j99r= zuUi~j@YkPE+1-ZA1b#uEW1p`Io~ASpUOT77en7c~8!N-%XqkMV$wl$l2Nf)hajRZJ zkwskh011N|J6-;K#nF{JZ`J5P!K#(j#=*0_{k^_Nek|ErFY3+B91WbD644t;Mo&e4 zgB*W=Pk{zhN}C-TM1HRXV5W#_-%`7ApL{STz(?E}?ik*2(A~VK1zhfptlkC2)P-?4++5iEN!k^92py3 zUqW}XBlHPrc%a-A6VxNuhFoJr(*l?z+iNCpH zhS*e<(tWi$Zl8;K{JU{Q?d5KTH*LyZ14kEd6UI32CnhEs03tC2`96~GsVrqqdt15q zWLr|Zf63BEi6jY{L_t$!B8CR%CqUO!3mW*r6tQ?NydCUf#V(RCja~ zxhE!3WZUiVz(D)Om5-f@N_&caf}uU`(|Sozr#KKs@1L0};-Y2z$N!430r)|iwy||3Cmnbqp5!HfK zuhZ0MYF1qz%{cuW$hHHyAb>HmI{2p+XR*2yNiE6KIc+`Z2+s-=Rn#ZD&;pa?bds*5GgIk1c88!CX&cg#+Z$!6vS5kN{kz$e5NNPBpA{9s^c2w>po z;nhFp( zU;JG@e!h6@`q>{FjPl%$N<|;s)}1P{t}!TyBs^)!SpS@(E1FA=8w4-1cDva zqs%9F?3l^$!NrM->zs<%2E|3fk$P$izU#{c96KA~u*v^-u#4j|&n*pJ6AizeWbN4{ znU?Ta#KyECWChz!uBe~4US-eYJNw~o&-#OzoY&>pRYgVSdhVJ1GP@w?(C?rN9gJmp z$F}-99nx|5YQgm_@7UD@r$bX2UWXezOPkSnHd#}m)cDMSHcLLYr#~Ohdd_oy+C0xi zzxMpu`u4@dL)&Z2gB=cvBy4LslbXKeh}y1-xP;9Mnm#j0*YWnL_AsC0$?0(G5#o|t zAA4u-S)LpZNxp=V1=$60>$uADjhUshqV~Tr={j}w!I=Zcn7*C%JGK7cjFy%CD)-M? zm~4M@Cf?-f8I{jWv$YjUBdESBksnmQ#i;^f&E3ta!6 z_ImxupjWc&mHyXcr9~&BuTI?1WSj8VnnlFK**o{s-5z=8w%9+v|K4|TnasX|MI^`l z;ld_eg?Pv02-6?A`I#mg_V~M+L^h=S;IdLT_@Mu*^7oc9-nMFQ=KqVf-+t@jviV22 z%-cuL-3~6_di-EQer7~-uK4H8k`rgDSenTSz%`{k)C^vuSx^B-XNB$F`7uI`DnR;oh4X^oZPGzZQ zA0(_3i+V%LG-qr>ivs(PfwmpJJiuu zS+necg+@rTQl6UVMT7qHSL`Q$;K|N1Ul}~1yrwPl=kyhh*ESh%oqgrJ%9_Wq}R=U*xPK*V)pu+3XqI34-Rmgc=*7g_MF9yzKyGW zleoC#*u+?M3MF=QG)-!6Ocm8Bkl4}Fv~=Cn59vZb4g~dt?%nWB)`FAk$o$A|KDIHB~wDxK6uRdkKM+KSENmLNJU=Yia*;8lqTdx({2P4+j=tpm?BkIE}BM>?!TmBi#Z7Q$Z4H}|c7 zQ$r}9J+a^H0&L(r1Dx=w@ZTA_Qjb!X7Bz-!4 zv2Y`*qsO3hXQ_Z4>tQ+0Nkt2r7ihv^8JVc&%j%DPjHk%kJOL!l1;j{L9>)*&5jm=X)nu zG^VewtXd-%4{DY7^oEvRMibJP^(I9F6a#SX>lC{a1DA!dQ}0t|rOPeXD#Vdnlvu^t z>?`|hvzvDaqELyr`UR$RNuX_egDoNCM-8`E_-GdwPjc2*Lv~fS=*x^9Ce1t#`(NDs z7YAVVNDMFISm5{)mQA;q3h5Br?DVbDH%PSR;*PlWcq1ANeK8Ij<9}9{&_aFAtYn)Z z7mE{>r;&kqX%z&k4GUw96+Z0hvUCtFGv0ju)E!f~Ur*+P-|+U35J*Ruhf|jlW;e*L zo^X9SAMZ4tE4+QyQpC9*Z8_ts&_v8?>M2@j{MD_@U495OGnR5Ox^uRkrYR1cjjmr# zSe1qa)1nF`=JBH^5i+7+seoXb=3HVVbOh&e$Y(N(l7dpgUjccg|6;hS8o`&W8=B|~ zrLU98s$nSs{#-y}G{=XGf4-z^rK(PE14ztvDEHU3BY+Bk_$FW1=FV0}_+;^!kg}T~ zn*XA6B`w&$*$f3%d8CTFQhLW7rh5Y2E^Tfh?pG4qSRK3*KQDWI&r7;0N|$h~xyquX zK{#Jx>y7v}V++X@yH}>$xGUlmC*p9h@;i9C&Oa_iyDsMU{i$VLc;%U^N_o}t zH*rDbS5m4QIIkX)b!KH{vDF6#2U9im`AfO^$#o$B)qrk>{9oe}ootfJj)sA}K(~7_ zML`!4=aEkq@BSU+CfJx>S0KzW>g(7aY0W)HqZLa^Hzay~JT?6ys{{Y}y~=W^t9QzA zUmJd0y!L3f4(6$T9O~gSa7^Bgv{FEop~khNFW(jTbmI`Jo{0+HnZIe;AuGt?)i;m z_PVS%sbl7Na4Z?Ni*iwULg>^g*i(E-+uz<~d15JZ>7{kS7^rg!((2b1g^aa%4?Suw zFPM!WRG=mXk6kX!QHs2w=;`DX%xEzSIV0^Kqt%9~8kC~;#!z63nz$RJxlcECaFYfb z`eoYjjk1z;jmxyYgUo5)y42HHjO9&U^fj`d+tyJZg`a+;`F69yo~X^tFkAdChr%ncE;belE& zfPiitl2glDiDuZ6u(QEaq-6y(u;=62@aKZ)eZK>OSu72mrKG#;t#bS#XQfD|XreHE zP*Rc9(aw^C{k!V#M6N??P~F58aq8|;!{>Qf1?iIe+qmDsYxMJa1*c7fj=&M!!bkZ9 z>!wS-02C!*_8}-DVP?)oLY4Q^(Ze4Ooi9bwH!(gIHbHA|KoU8+FgdAg1_#3weAG6L zvR%8J<{!WF`x11F;bJUh$@{W(-Kj)*aNjxn*8J$Hg^ZrnK`v8X4bzOLi>1?@2a(`F zvDt3iD6#aWk+acm9F_{fSWTUbbh;M~MKc9B>8IE6l@1kmVD%!P4r6ZAh6MtT`9T#3Le zs4cwzWe$RlZN8V>y0S_p+~$>4b?Q!eq&{)E&2#?YH78k;E?JXpBt)U7Gq-X1r%ZBG z*1!cuGqFC3?S5`QmCVQch9wxSlpV2IEs7!Ej)j${!XsVLJO8&9{#RlAe{g!GT|=O- hrkU>dpCi=lKfU){&qNkh1HTfG_db$Gxf}JDe*+S84&49% diff --git a/manual/plugins/sokoban.tex b/manual/plugins/sokoban.tex index 755c4e8295..246eceda51 100644 --- a/manual/plugins/sokoban.tex +++ b/manual/plugins/sokoban.tex @@ -5,44 +5,75 @@ The object of the game is to push boxes into their correct position in a crowded warehouse with a minimal number of pushes and moves. The boxes can only be pushed, never pulled, and only one can be pushed at a time. +Sokoban may be used as a viewer for viewing saved solutions and playing +external level sets with the \fname{.sok} extension. Level sets should be in +the standard Sokoban text format or RLE (Run Length Encoded). For more +information about the level format, see +\url{http://sokobano.de/wiki/index.php?title=Level_format} + \begin{table} \begin{btnmap}{}{} -\opt{RECORDER_PAD,ONDIO_PAD,IRIVER_H100_PAD,IRIVER_H300_PAD,IAUDIO_X5_PAD,SANSA_E200_PAD} +\opt{RECORDER_PAD,ARCHOS_AV300_PAD,ONDIO_PAD,IRIVER_H100_PAD,IRIVER_H300_PAD,IAUDIO_X5_PAD,GIGABEAT_PAD,SANSA_E200_PAD} {\ButtonUp, \ButtonDown,} \opt{IPOD_4G_PAD,IPOD_3G_PAD}{\ButtonMenu, \ButtonPlay,} \opt{IRIVER_H10_PAD}{\ButtonScrollUp, \ButtonScrollDown,} \ButtonLeft, \ButtonRight & Move the ``sokoban'' up, down, left or right\\ -\opt{RECORDER_PAD}{\ButtonFOne} -\opt{ONDIO_PAD}{\ButtonMenu+\ButtonLeft} -\opt{IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonRec} -\opt{IPOD_4G_PAD,IPOD_3G_PAD,SANSA_E200_PAD}{\ButtonSelect+\ButtonLeft} -\opt{IAUDIO_X5_PAD}{\ButtonPlay+\ButtonDown} -\opt{IRIVER_H10_PAD}{\ButtonPlay+\ButtonScrollDown} - & Back to previous level \\ -\opt{RECORDER_PAD}{\ButtonFTwo} -\opt{ONDIO_PAD}{\ButtonMenu+\ButtonRight} -\opt{IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonSelect} -\opt{IPOD_4G_PAD,IPOD_3G_PAD}{\ButtonSelect+\ButtonPlay} -\opt{IAUDIO_X5_PAD,SANSA_E200_PAD}{\ButtonRec} -\opt{IRIVER_H10_PAD}{\ButtonFF} - & Restart level \\ -\opt{RECORDER_PAD}{\ButtonFThree} -\opt{ONDIO_PAD}{\ButtonMenu+\ButtonUp} -\opt{IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonMode} -\opt{IPOD_4G_PAD,IPOD_3G_PAD,SANSA_E200_PAD}{\ButtonSelect+\ButtonRight} -\opt{IAUDIO_X5_PAD}{\ButtonPlay+\ButtonUp} -\opt{IRIVER_H10_PAD}{\ButtonPlay+\ButtonScrollUp} - & Go to next level \\ -\opt{RECORDER_PAD,IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonOn} -\opt{ONDIO_PAD}{\ButtonMenu} -\opt{IPOD_4G_PAD,IPOD_3G_PAD,IAUDIO_X5_PAD}{\ButtonSelect} -\opt{IRIVER_H10_PAD}{\ButtonRew} -\opt{SANSA_E200_PAD}{\ButtonUp} - & Undo last movement \\ -\opt{RECORDER_PAD,ONDIO_PAD,IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonOff} +\opt{RECORDER_PAD,ARCHOS_AV300_PAD,ONDIO_PAD,IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonOff} \opt{IPOD_4G_PAD,IPOD_3G_PAD}{\ButtonSelect+\ButtonMenu} -\opt{IAUDIO_X5_PAD,IRIVER_H10_PAD,SANSA_E200_PAD}{\ButtonPower} - & Exit sokoban \\ +\opt{IAUDIO_X5_PAD,IRIVER_H10_PAD,GIGABEAT_PAD,SANSA_E200_PAD}{\ButtonPower} + & Menu \\ +\opt{RECORDER_PAD,ARCHOS_AV300_PAD}{\ButtonOn} +\opt{ONDIO_PAD}{\ButtonMenu} +\opt{IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonRec} +\opt{IPOD_4G_PAD,IPOD_3G_PAD,IAUDIO_X5_PAD,GIGABEAT_PAD,SANSA_E200_PAD}{\ButtonSelect} +\opt{IRIVER_H10_PAD}{\ButtonRew} + & Undo last movement \\ +\opt{RECORDER_PAD,ARCHOS_AV300_PAD}{\ButtonPlay} +\opt{ONDIO_PAD}{\ButtonMenu+\ButtonDown} +\opt{IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonMode} +\opt{IPOD_4G_PAD,IPOD_3G_PAD}{\ButtonSelect+\ButtonPlay} +\opt{IAUDIO_X5_PAD}{n/a} +\opt{IRIVER_H10_PAD}{\ButtonFF} +\opt{GIGABEAT_PAD}{\ButtonA} +\opt{SANSA_E200_PAD}{\ButtonRec} + & Redo previously undone move \\ +\opt{RECORDER_PAD,ARCHOS_AV300_PAD}{\ButtonFOne} +\opt{ONDIO_PAD}{\ButtonMenu+\ButtonLeft} +\opt{IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonOn+\ButtonDown} +\opt{IPOD_4G_PAD,IPOD_3G_PAD}{\ButtonSelect+\ButtonLeft} +\opt{IAUDIO_X5_PAD}{\ButtonRec} +\opt{IRIVER_H10_PAD}{\ButtonPlay+\ButtonScrollDown} +\opt{GIGABEAT_PAD}{\ButtonVolDown} +\opt{SANSA_E200_PAD}{\ButtonSelect+\ButtonDown} + & Back to previous level \\ +\opt{RECORDER_PAD,ARCHOS_AV300_PAD}{\ButtonFTwo} +\opt{ONDIO_PAD}{\ButtonMenu+\ButtonUp} +\opt{IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonOn} +\opt{IPOD_4G_PAD,IPOD_3G_PAD,IAUDIO_X5_PAD}{n/a} +\opt{IRIVER_H10_PAD}{\ButtonPlay+\ButtonRight} +\opt{GIGABEAT_PAD}{\ButtonMenu} +\opt{SANSA_E200_PAD}{\ButtonSelect+\ButtonRight} + & Restart level \\ +\opt{RECORDER_PAD,ARCHOS_AV300_PAD}{\ButtonFThree} +\opt{ONDIO_PAD}{\ButtonMenu+\ButtonRight} +\opt{IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonOn+\ButtonUp} +\opt{IPOD_4G_PAD,IPOD_3G_PAD}{\ButtonSelect+\ButtonRight} +\opt{IAUDIO_X5_PAD}{\ButtonPlay} +\opt{IRIVER_H10_PAD}{\ButtonPlay+\ButtonScrollUp} +\opt{GIGABEAT_PAD}{\ButtonVolUp} +\opt{SANSA_E200_PAD}{\ButtonSelect+\ButtonUp} + & Go to next level \\ +\opt{RECORDER_PAD,ARCHOS_AV300_PAD,ONDIO_PAD,IRIVER_H100_PAD,IRIVER_H300_PAD,IAUDIO_X5_PAD,GIGABEAT_PAD,SANSA_E200_PAD} + {\ButtonUp/\ButtonDown,} +\opt{IPOD_4G_PAD,IPOD_3G_PAD}{\ButtonMenu/\ButtonPlay,} +\opt{IRIVER_H10_PAD}{\ButtonScrollUp/\ButtonScrollDown,} + & Increase/decrease solution playback speed \end{btnmap} \end{table} + +Some places where can you can find level sets: +\begin{itemize} +\item \url{http://www.sourcecode.se/sokoban/levels.php} +\item \url{http://sokobano.de/en/levels.php} +\end{itemize} diff --git a/tools/buildzip.pl b/tools/buildzip.pl index 8c78b82170..404342b68e 100755 --- a/tools/buildzip.pl +++ b/tools/buildzip.pl @@ -329,7 +329,7 @@ STOP `cp $ROOT/apps/tagnavi.config .rockbox/`; if($bitmap) { - `cp $ROOT/apps/plugins/sokoban.levels .rockbox/rocks/`; # sokoban levels + `cp $ROOT/apps/plugins/sokobanlevels.sok .rockbox/rocks/`; # sokoban levels `cp $ROOT/apps/plugins/snake2.levels .rockbox/rocks/`; # snake2 levels }