A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

FS#8647: Amaze - 3D maze game plugin

- update to build against latest Git
- cleanup (whitespace, indentation)
- fixed old PLA handling
- update indentation/curly brace style
- improve load/save mechanism
- enable marking ground with "select" button
- add compass view
- improve display on 1-bit-targets (floor pattern)
- graphics update: add 3x3 and 5x5 tiles, rework 7x7 and 9x9 tiles,
load tiles dependant of screen size
- fix: on some targets (Fuze+) division by 0 could occur.
Fix by calculating the exact view depth on all targets.
- fix: duplicate error checks when saving prefs
- Fully translate it
- Add a simple manual entry (including screenshots for some platforms)

Change-Id: Ic84d98650c1152ab0ad268b51bd060f714ace288

authored by

Franklin Wei and committed by
Solomon Peachy
6efd7f8f 2dbf26f1

+1893
+224
apps/lang/english.lang
··· 16711 16711 *: "Default Browser" 16712 16712 </voice> 16713 16713 </phrase> 16714 + <phrase> 16715 + id: LANG_AMAZE_MENU 16716 + desc: Amaze game 16717 + user: core 16718 + <source> 16719 + *: "Amaze Main Menu" 16720 + </source> 16721 + <dest> 16722 + *: "Amaze Main Menu" 16723 + </dest> 16724 + <voice> 16725 + *: "Amaze Main Menu" 16726 + </voice> 16727 + </phrase> 16728 + <phrase> 16729 + id: LANG_SET_MAZE_SIZE 16730 + desc: Maze size in Amaze game 16731 + user: core 16732 + <source> 16733 + *: "Set Maze Size" 16734 + </source> 16735 + <dest> 16736 + *: "Set Maze Size" 16737 + </dest> 16738 + <voice> 16739 + *: "Set Maze Size" 16740 + </voice> 16741 + </phrase> 16742 + <phrase> 16743 + id: LANG_VIEW_MAP 16744 + desc: Map in Amaze game 16745 + user: core 16746 + <source> 16747 + *: "View Map" 16748 + </source> 16749 + <dest> 16750 + *: "View Map" 16751 + </dest> 16752 + <voice> 16753 + *: "View Map" 16754 + </voice> 16755 + </phrase> 16756 + <phrase> 16757 + id: LANG_SHOW_COMPASS 16758 + desc: Compass in Amaze game 16759 + user: core 16760 + <source> 16761 + *: "Show Compass" 16762 + </source> 16763 + <dest> 16764 + *: "Show Compass" 16765 + </dest> 16766 + <voice> 16767 + *: "Show Compass" 16768 + </voice> 16769 + </phrase> 16770 + <phrase> 16771 + id: LANG_SHOW_MAP 16772 + desc: Map in Amaze game 16773 + user: core 16774 + <source> 16775 + *: "Show Map" 16776 + </source> 16777 + <dest> 16778 + *: "Show Map" 16779 + </dest> 16780 + <voice> 16781 + *: "Show Map" 16782 + </voice> 16783 + </phrase> 16784 + <phrase> 16785 + id: LANG_REMEMBER_PATH 16786 + desc: Map in Amaze game 16787 + user: core 16788 + <source> 16789 + *: "Remember Path" 16790 + </source> 16791 + <dest> 16792 + *: "Remember Path" 16793 + </dest> 16794 + <voice> 16795 + *: "Remember Path" 16796 + </voice> 16797 + </phrase> 16798 + <phrase> 16799 + id: LANG_USE_LARGE_TILES 16800 + desc: Map in Amaze game 16801 + user: core 16802 + <source> 16803 + *: "Use Large Tiles" 16804 + </source> 16805 + <dest> 16806 + *: "Use Large Tiles" 16807 + </dest> 16808 + <voice> 16809 + *: "Use Large Tiles" 16810 + </voice> 16811 + </phrase> 16812 + <phrase> 16813 + id: LANG_SHOW_SOLUTION 16814 + desc: Map in Amaze game 16815 + user: core 16816 + <source> 16817 + *: "Show Solution" 16818 + </source> 16819 + <dest> 16820 + *: "Show Solution" 16821 + </dest> 16822 + <voice> 16823 + *: "Show Solution" 16824 + </voice> 16825 + </phrase> 16826 + <phrase> 16827 + id: LANG_QUIT_WITHOUT_SAVING 16828 + desc: 16829 + user: core 16830 + <source> 16831 + *: "Quit without saving" 16832 + </source> 16833 + <dest> 16834 + *: "Quit without saving" 16835 + </dest> 16836 + <voice> 16837 + *: "Quit without saving" 16838 + </voice> 16839 + </phrase> 16840 + <phrase> 16841 + id: LANG_GENERATING_MAZE 16842 + desc: Amaze game 16843 + user: core 16844 + <source> 16845 + *: "Generating maze..." 16846 + </source> 16847 + <dest> 16848 + *: "Generating maze..." 16849 + </dest> 16850 + <voice> 16851 + *: "Generating maze..." 16852 + </voice> 16853 + </phrase> 16854 + <phrase> 16855 + id: LANG_YOU_WIN 16856 + desc: Success in game 16857 + user: core 16858 + <source> 16859 + *: "You win!" 16860 + </source> 16861 + <dest> 16862 + *: "You win!" 16863 + </dest> 16864 + <voice> 16865 + *: "You win!" 16866 + </voice> 16867 + </phrase> 16868 + <phrase> 16869 + id: LANG_YOU_CHEATED 16870 + desc: Cheated in game 16871 + user: core 16872 + <source> 16873 + *: "You cheated!" 16874 + </source> 16875 + <dest> 16876 + *: "You cheated!" 16877 + </dest> 16878 + <voice> 16879 + *: "You cheated!" 16880 + </voice> 16881 + </phrase> 16882 + <phrase> 16883 + id: LANG_DIFFICULTY_EASY 16884 + desc: Game difficulty 16885 + user: core 16886 + <source> 16887 + *: "Easy" 16888 + </source> 16889 + <dest> 16890 + *: "Easy" 16891 + </dest> 16892 + <voice> 16893 + *: "Easy" 16894 + </voice> 16895 + </phrase> 16896 + <phrase> 16897 + id: LANG_DIFFICULTY_MEDIUM 16898 + desc: Game difficulty 16899 + user: core 16900 + <source> 16901 + *: "Medium" 16902 + </source> 16903 + <dest> 16904 + *: "Medium" 16905 + </dest> 16906 + <voice> 16907 + *: "Medium" 16908 + </voice> 16909 + </phrase> 16910 + <phrase> 16911 + id: LANG_DIFFICULTY_HARD 16912 + desc: Game difficulty 16913 + user: core 16914 + <source> 16915 + *: "Hard" 16916 + </source> 16917 + <dest> 16918 + *: "Hard" 16919 + </dest> 16920 + <voice> 16921 + *: "Hard" 16922 + </voice> 16923 + </phrase> 16924 + <phrase> 16925 + id: LANG_DIFFICULTY_EXPERT 16926 + desc: Game difficulty 16927 + user: core 16928 + <source> 16929 + *: "Expert" 16930 + </source> 16931 + <dest> 16932 + *: "Expert" 16933 + </dest> 16934 + <voice> 16935 + *: "Expert" 16936 + </voice> 16937 + </phrase>
+1
apps/plugins/CATEGORIES
··· 2 2 alpine_cdc,apps 3 3 alarmclock,apps 4 4 announce_status,demos 5 + amaze,games 5 6 autostart,apps 6 7 battery_bench,apps 7 8 bench_scaler,apps
+1
apps/plugins/SOURCES
··· 112 112 metronome.c 113 113 114 114 2048.c 115 + amaze.c 115 116 116 117 /* Lua needs at least 160 KB to work in */ 117 118 #if PLUGIN_BUFFER_SIZE >= 0x80000
+1620
apps/plugins/amaze.c
··· 1 + /*************************************************************************** 2 + * __________ __ ___. 3 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 + * \/ \/ \/ \/ \/ 8 + * $Id$ 9 + * 10 + * Copyright (C) 2014 Franklin Wei, (c) 2018 Sebastian Leonhardt 11 + * 12 + * Original work (C) 2000 David Leonard, public domain according to 13 + * http://www.adaptive-enterprises.com.au/~d/software/amaze/ 14 + * 15 + * Original Rockbox port by Jerry Chapman, 2007 16 + * 17 + * This program is free software; you can redistribute it and/or 18 + * modify it under the terms of the GNU General Public License 19 + * as published by the Free Software Foundation; either version 2 20 + * of the License, or (at your option) any later version. 21 + * 22 + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 23 + * KIND, either express or implied. 24 + * 25 + ***************************************************************************/ 26 + 27 + #include "plugin.h" 28 + #include "lib/pluginlib_actions.h" 29 + 30 + const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; 31 + 32 + static const struct opt_items noyes_text[] = { 33 + { STR(LANG_SET_BOOL_NO) }, 34 + { STR(LANG_SET_BOOL_YES) } 35 + }; 36 + 37 + static const struct opt_items mazesize_text[] = { 38 + { STR(LANG_DIFFICULTY_EASY) }, 39 + { STR(LANG_DIFFICULTY_MEDIUM) }, 40 + { STR(LANG_DIFFICULTY_HARD) }, 41 + { STR(LANG_DIFFICULTY_EXPERT) } 42 + }; 43 + 44 + bool show_map; 45 + bool remember_visited; 46 + bool use_large_tiles; 47 + int maze_size; 48 + 49 + #if LCD_DEPTH >= 16 50 + #define COLOR_GROUND LCD_RGBPACK(51,51,51) 51 + #define COLOR_SKY LCD_RGBPACK(51,51,102) 52 + #define COLOR_VISITED LCD_RGBPACK(102,77,51) 53 + #define COLOR_MARK LCD_RGBPACK(255,100,61) 54 + #define COLOR_GOAL LCD_RGBPACK(128,0,0) /* red */ 55 + #define COLOR_COMPASS LCD_RGBPACK(255,255,0) /* yellow */ 56 + #define COLOR_PARA LCD_RGBPACK(153,153,102) /* color side wall */ 57 + /* #define COLOR_PERP LCD_RGBPACK(102,51,0) */ 58 + #define COLOR_PERP LCD_RGBPACK(204,153,102) /* color wall perp */ 59 + #elif LCD_DEPTH == 2 60 + #define COLOR_GROUND LCD_BLACK 61 + #define COLOR_SKY LCD_WHITE 62 + #define COLOR_VISITED LCD_DARKGRAY 63 + #define COLOR_GOAL LCD_WHITE 64 + #define COLOR_COMPASS LCD_BLACK 65 + #define COLOR_MARK LCD_WHITE 66 + #define COLOR_PARA LCD_DARKGRAY /* color side wall */ 67 + #define COLOR_PERP LCD_LIGHTGRAY /* color wall perp */ 68 + #else /* mono */ 69 + #define COLOR_GROUND LCD_BLACK 70 + #define COLOR_SKY LCD_BLACK 71 + #define COLOR_VISITED LCD_BLACK 72 + #define COLOR_GOAL LCD_BLACK 73 + #define COLOR_COMPASS LCD_WHITE 74 + #define COLOR_PARA LCD_BLACK /* color side wall */ 75 + #define COLOR_PERP LCD_WHITE /* color wall perp */ 76 + #endif 77 + 78 + #define A_DOWN 'v' 79 + #define A_RIGHT '>' 80 + #define A_UP '^' 81 + #define A_LEFT '<' 82 + #define SPACE ' ' /* Space you can walk through */ 83 + #define BLOCK 'B' /* A block that you can't walk through */ 84 + #define OBSPACE '#' /* Obscured space */ 85 + #define VISITED '.' /* Visited space */ 86 + #define GOAL '%' /* Exit from the maze */ 87 + #define START '+' /* Starting point in the maze */ 88 + 89 + enum dir { DIR_DOWN=0, DIR_RIGHT=1, DIR_UP=2, DIR_LEFT=3 }; 90 + #define _TOD(d) (enum dir)((d) % 4) 91 + #define _TOI(d) (int)(d) 92 + #define LEFT_OF(d) _TOD(_TOI(d) + 1) 93 + #define REVERSE_OF(d) _TOD(_TOI(d) + 2) 94 + #define RIGHT_OF(d) _TOD(_TOI(d) + 3) 95 + 96 + static struct { int y, x; } dirtab[4] = 97 + { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } }; 98 + static char ptab[4] = { A_DOWN, A_RIGHT, A_UP, A_LEFT }; 99 + 100 + int px, py; /* Player position */ 101 + enum dir pdir; /* Player direction */ 102 + char punder; /* character under player, if any */ 103 + int sx, sy; /* Start position */ 104 + int gx, gy; /* Goal position */ 105 + int gdist; /* Distance from start to goal */ 106 + int won = 0; /* Reached goal */ 107 + int cheated = 0; /* Cheated somehow */ 108 + bool compass = false; /* show compass */ 109 + int button; /* Button data */ 110 + bool loaded=false; /* Loaded? */ 111 + 112 + #define FIELD_SIZE 80 113 + #define MAP_CONST 20 114 + 115 + static char map[FIELD_SIZE * FIELD_SIZE]; /* map storage */ 116 + static char umap[FIELD_SIZE * FIELD_SIZE]; 117 + 118 + /* visible depth */ 119 + #define MAX_DEPTH 20 120 + int depth; 121 + 122 + /* CX,CY = center of screen */ 123 + #define CX LCD_WIDTH / 2 124 + #define CY LCD_HEIGHT / 2 125 + 126 + int crd_x[MAX_DEPTH], crd_y[MAX_DEPTH]; /* screen vertices */ 127 + 128 + #if LCD_WIDTH >= 220 || LCD_HEIGHT >= 220 129 + #include "pluginbitmaps/amaze_tiles_9.h" 130 + #define amaze_tiles_large amaze_tiles_9 131 + #define TILESIZE_LARGE BMPWIDTH_amaze_tiles_9 132 + #include "pluginbitmaps/amaze_tiles_7.h" 133 + #define amaze_tiles_small amaze_tiles_7 134 + #define TILESIZE_SMALL BMPWIDTH_amaze_tiles_7 135 + #elif LCD_WIDTH >= 160 || LCD_HEIGHT >= 160 136 + #include "pluginbitmaps/amaze_tiles_7.h" 137 + #define amaze_tiles_large amaze_tiles_7 138 + #define TILESIZE_LARGE BMPWIDTH_amaze_tiles_7 139 + #include "pluginbitmaps/amaze_tiles_5.h" 140 + #define amaze_tiles_small amaze_tiles_5 141 + #define TILESIZE_SMALL BMPWIDTH_amaze_tiles_5 142 + #else 143 + #include "pluginbitmaps/amaze_tiles_5.h" 144 + #define amaze_tiles_large amaze_tiles_5 145 + #define TILESIZE_LARGE BMPWIDTH_amaze_tiles_5 146 + #include "pluginbitmaps/amaze_tiles_3.h" 147 + #define amaze_tiles_small amaze_tiles_3 148 + #define TILESIZE_SMALL BMPWIDTH_amaze_tiles_3 149 + #endif 150 + 151 + /* save file names */ 152 + #define UMAP_FILE PLUGIN_GAMES_DIR "/amaze_umap.sav" 153 + #define MAP_FILE PLUGIN_GAMES_DIR "/amaze_map.sav" 154 + #define PREF_FILE PLUGIN_GAMES_DIR "/amaze_prefs.sav" 155 + 156 + void clearscreen (void) 157 + { 158 + #if LCD_DEPTH > 1 159 + rb->lcd_set_background(LCD_BLACK); 160 + rb->lcd_set_foreground(LCD_WHITE); 161 + #endif 162 + rb->lcd_clear_display(); 163 + rb->lcd_update(); 164 + } 165 + 166 + void getmaxyx(int *y, int *x) 167 + { 168 + *y = (maze_size + 1) * MAP_CONST; 169 + *x = (maze_size + 1) * MAP_CONST; 170 + } 171 + 172 + void map_write (char *pane, int y, int x, char c) 173 + { 174 + int maxy, maxx; 175 + 176 + getmaxyx(&maxy, &maxx); 177 + 178 + if (x<0 || x>=maxx || y<0 || y>=maxy) return; 179 + 180 + pane[x * FIELD_SIZE + y] = c; 181 + 182 + } 183 + char map_read (char *pane, int y, int x) 184 + { 185 + int maxy, maxx; 186 + 187 + getmaxyx(&maxy, &maxx); 188 + 189 + if (x<0 || x>=maxx || y<0 || y>=maxy) { 190 + return SPACE; 191 + } 192 + 193 + return pane[x * FIELD_SIZE + y]; 194 + } 195 + 196 + /* redefine ncurses werase */ 197 + void werase (char *pane) 198 + { 199 + int y, x; 200 + int maxy, maxx; 201 + 202 + getmaxyx(&maxy, &maxx); 203 + 204 + for (y = 0; y < maxy; y++) 205 + for (x = 0; x < maxx; x++) 206 + map_write(pane, y, x, SPACE); 207 + } 208 + 209 + /* start of David Leonard's code */ 210 + 211 + /* Look at position (y,x) in the maze map */ 212 + char at(int y, int x) 213 + { 214 + int maxy, maxx; 215 + 216 + getmaxyx(&maxy, &maxx); 217 + 218 + if (y == py && x == px) 219 + return punder; 220 + 221 + if (y < 0 || y >= maxy || x < 0 || x >= maxx) 222 + return SPACE; 223 + else { 224 + return map_read(map, y, x); 225 + } 226 + } 227 + 228 + void copyumap(int y, int x, int fullvis) 229 + { 230 + char c; 231 + 232 + c = at(y, x); 233 + if (!fullvis && c == SPACE && map_read(umap, y, x) != SPACE) 234 + c = OBSPACE; 235 + map_write(umap, y, x, c); 236 + } 237 + 238 + struct path { 239 + int y, x; 240 + int ttl; /* Time until this path stops */ 241 + int spawns; /* Max number of forks this path can do */ 242 + int distance; /* Distance from start */ 243 + struct path *next; 244 + }; 245 + 246 + /* 247 + * A better maze-digging algorithm. 248 + * Simultaneously advance multiple digging paths through the map. 249 + * This is done by having a work queue of advancing paths. 250 + * Occasionally a path can fork; thus adding more to the work 251 + * queue and diversifying the maze. 252 + */ 253 + void eatmaze(int starty, int startx) 254 + { 255 + struct path { 256 + int y, x; 257 + int ttl; /* Time until this path stops */ 258 + int spawns; /* Max number of forks this path can do */ 259 + int distance; /* Distance from start */ 260 + struct path *next; 261 + }; 262 + struct path *path_free, *path_head, *path_tail; 263 + struct path *p, *s; 264 + /* static -- per <hcs> in #rockbox -- was having stack issues */ 265 + static struct path path_storage[2000]; 266 + int try; 267 + unsigned i; 268 + int y, x, dy, dx; 269 + int sdir; 270 + 271 + /* Set up the free list of path cells */ 272 + for (i = 2; i < sizeof path_storage / sizeof path_storage[0]; i++) 273 + path_storage[i].next = &path_storage[i-1]; 274 + path_storage[1].next = NULL; 275 + path_free = &path_storage[sizeof path_storage / sizeof path_storage[0] - 1]; 276 + 277 + /* Set up the initial path cell */ 278 + path_storage[0].y = starty; 279 + path_storage[0].x = startx; 280 + map_write(map, starty, startx, SPACE); 281 + 282 + /* Set up the initial goal. It will move later. */ 283 + gy = starty; 284 + gx = startx; 285 + gdist = 0; 286 + 287 + /* Initial properties of the root path */ 288 + path_storage[0].ttl = 50; 289 + path_storage[0].spawns = 20; 290 + path_storage[0].distance = 0; 291 + 292 + /* Put the initial path into the queue */ 293 + path_storage[0].next = NULL; 294 + path_head = path_tail = &path_storage[0]; 295 + 296 + while (path_head != NULL) { 297 + /* Dequeue */ 298 + p = path_head; 299 + path_head = p->next; 300 + if (path_head == NULL) 301 + path_tail = NULL; 302 + 303 + /* There's a large chance that some paths miss a turn */ 304 + if (rb->rand() % 100 < 60) 305 + goto requeue; 306 + 307 + /* First thing we do is advance the path. */ 308 + y = p->y; 309 + x = p->x; 310 + 311 + sdir = rb->rand() % 4; 312 + for (try = 0; try < 4; try ++) { 313 + dx = dirtab[(sdir + try) % 4].x; 314 + dy = dirtab[(sdir + try) % 4].y; 315 + 316 + /* Going back on ourselves? */ 317 + if (at(y + dy, x + dx) != BLOCK) 318 + continue; 319 + 320 + /* Connecting to another path? */ 321 + if (at(y + dy * 2, x + dx * 2) != BLOCK) 322 + continue; 323 + if (at(y + dy + dx, x + dx - dy) != BLOCK) 324 + continue; 325 + if (at(y + dy - dx, x + dx + dy) != BLOCK) 326 + continue; 327 + 328 + break; 329 + } 330 + if (try == 4 || p->ttl <= 0) { 331 + /* Failed: the path is placed on the free list. */ 332 + p->next = path_free; 333 + path_free = p; 334 + continue; 335 + } 336 + 337 + /* Dig the path a bit */ 338 + p->y = y + dy; 339 + p->x = x + dx; 340 + map_write(map, p->y, p->x, SPACE); 341 + p->ttl--; 342 + p->distance++; 343 + 344 + if (p->distance > gdist) { 345 + gx = p->x; 346 + gy = p->y; 347 + gdist = p->distance; 348 + } 349 + 350 + /* Decide if we should spawn */ 351 + if (/* rb->rand() % (p->ttl + 1) < p->spawns && */ path_free) { 352 + /* Take a new path element off the free list */ 353 + s = path_free; 354 + path_free = s->next; 355 + 356 + /* Insert it at the tail of the queue */ 357 + s->next = NULL; 358 + if (path_tail) path_tail->next = s; 359 + else path_head = s; 360 + path_tail = s; 361 + 362 + /* Newly spawned path s will inherit most properties from p */ 363 + s->y = p->y; 364 + s->x = p->x; 365 + s->ttl = p->ttl + rb->rand() % 10; 366 + s->spawns = p->spawns; 367 + s->distance = p->distance; 368 + 369 + /* p->spawns--; */ 370 + } 371 + 372 + requeue: 373 + /* Put p onto the tail of the queue */ 374 + p->next = NULL; 375 + if (path_tail) path_tail->next = p; 376 + else path_head = p; 377 + path_tail = p; 378 + } 379 + } 380 + 381 + /* Move the player to a new position/direction in the maze map */ 382 + void mappmove(int newpy, int newpx, enum dir newpdir) 383 + { 384 + map_write(map, py, px, punder); 385 + copyumap(py, px, 1); 386 + punder = at(newpy, newpx); 387 + py = newpy; 388 + px = newpx; 389 + pdir = newpdir; 390 + copyumap(py, px, 1); 391 + map_write(umap, py, px, ptab[_TOI(pdir)]); 392 + rb->lcd_update(); 393 + } 394 + 395 + void clearmap (char *amap) 396 + { 397 + int maxy, maxx; 398 + int y, x; 399 + 400 + getmaxyx(&maxy, &maxx); 401 + 402 + 403 + for (y = 0; y < maxy; y++) 404 + for (x = 0; x < maxx; x++) 405 + map_write(amap, y, x, BLOCK); 406 + } 407 + 408 + /* Reveal the solution to the user */ 409 + void showmap(void) 410 + { 411 + int maxy, maxx, y, x; 412 + char ch, och; 413 + 414 + getmaxyx(&maxy, &maxx); 415 + for (y = 0; y < maxy; y++) 416 + for (x = 0; x < maxx; x++) { 417 + ch = at(y, x); 418 + if (ch == SPACE) { 419 + och = map_read(umap, y, x); 420 + if (och == BLOCK || och == OBSPACE) 421 + ch = OBSPACE; 422 + } 423 + map_write(umap, y, x, ch); 424 + rb->yield(); 425 + } 426 + map_write(umap, py, px, ptab[_TOI(pdir)]); 427 + rb->lcd_update(); 428 + } 429 + 430 + /* 431 + * Create a new maze map 432 + * The algorithm here is quite inferior to that presented in the 433 + * magazine. I could only remember the gist of it: recursively dig a 434 + * trail that doesn't touch any other part of the maze, keeping track 435 + * of all possible points where the path could fork. Later on try those 436 + * possible branches; put limits on the segment lengths etc. 437 + */ 438 + void makemaze(void) 439 + { 440 + int maxy, maxx; 441 + int i; 442 + 443 + /* Get the window dimensions */ 444 + getmaxyx(&maxy, &maxx); 445 + 446 + clearmap(map); 447 + 448 + py = rb->rand() % (maxy - 2) + 1; /* maxy/2 */ 449 + px = rb->rand() % (maxx - 2) + 1; /* maxx/2 */ 450 + 451 + eatmaze(py, px); 452 + 453 + sx = px; /* starting position */ 454 + sy = py; 455 + 456 + /* Face in an interesting direction: */ 457 + pdir = DIR_UP; 458 + for (i = 0; 459 + i < 4 && at(py + dirtab[pdir].y, 460 + px + dirtab[pdir].x) == BLOCK; 461 + i++) 462 + pdir = LEFT_OF(pdir); 463 + 464 + map_write(map, py, px, START); 465 + map_write(map, gy, gx, GOAL); 466 + punder = START; 467 + mappmove(py, px, pdir); 468 + } 469 + 470 + /* new drawing routines */ 471 + 472 + void draw_arrow(int dir, int sx, int sy, int pass) 473 + { 474 + if (pass > 2) return; 475 + 476 + rb->lcd_fillrect(sx, sy, 1, 1); 477 + switch(dir) { 478 + case 0: /* down */ 479 + rb->lcd_fillrect(sx + 2*pass, sy, 1, 1); 480 + draw_arrow(dir, sx - 1, sy - 1, pass + 1); 481 + break; 482 + case 2: /* up */ 483 + rb->lcd_fillrect(sx + 2*pass, sy, 1, 1); 484 + draw_arrow(dir, sx - 1, sy + 1, pass + 1); 485 + break; 486 + case 1: /* left */ 487 + rb->lcd_fillrect(sx, sy + 2*pass, 1, 1); 488 + draw_arrow(dir, sx + 1, sy - 1, pass + 1); 489 + break; 490 + case 3: /* right */ 491 + rb->lcd_fillrect(sx, sy + 2*pass, 1, 1); 492 + draw_arrow(dir, sx - 1, sy - 1, pass +1); 493 + break; 494 + } 495 + } 496 + 497 + /* Provide a compass pointing 'north' or draw arrow mark on the floor */ 498 + void draw_pointer(int dir, bool is_compass) 499 + { 500 + int offset; 501 + 502 + if(is_compass) 503 + offset = -crd_y[1]*2/3; /* draw compass at the top */ 504 + else 505 + offset = crd_y[1]/2; /* draw mark on the floor */ 506 + 507 + #if LCD_DEPTH > 1 508 + if(is_compass) 509 + rb->lcd_set_foreground(COLOR_COMPASS); 510 + else 511 + rb->lcd_set_foreground(COLOR_MARK); 512 + #else 513 + rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); 514 + #endif 515 + switch(dir) { 516 + case 0: /* point down */ 517 + draw_arrow(dir, CX - 1, CY + offset + 6, 0); 518 + rb->lcd_fillrect(CX - 1, CY + offset + 1, 1, 3); 519 + break; 520 + case 2: /* point up */ 521 + draw_arrow(dir, CX - 1, CY + offset, 0); 522 + rb->lcd_fillrect(CX - 1, CY + offset + 3, 1, 3); 523 + break; 524 + case 1: /* point left */ 525 + draw_arrow(dir, CX - 6, CY + offset + 6, 0); 526 + rb->lcd_fillrect(CX - 3, CY + offset + 6, 3, 1); 527 + break; 528 + case 3: /* point right */ 529 + draw_arrow(dir, CX + 1, CY + offset + 6, 0); 530 + rb->lcd_fillrect(CX - 4, CY + offset + 6, 3, 1); 531 + break; 532 + } 533 + #if LCD_DEPTH == 1 534 + rb->lcd_set_drawmode(DRMODE_SOLID); 535 + #endif 536 + rb->lcd_update(); 537 + } 538 + 539 + void draw_end_wall(int bx, int by) 540 + { 541 + #if LCD_DEPTH > 1 542 + rb->lcd_set_foreground(COLOR_PERP); 543 + rb->lcd_fillrect(CX - bx/2, CY - by/2, bx + 1, by); 544 + #else 545 + rb->lcd_drawrect(CX - bx/2, CY - by/2, bx + 1, by); 546 + #endif 547 + } 548 + 549 + void draw_side(int fx, int bx, int by, int tan_n, int tan_d, bool isleft) 550 + { 551 + int signx; 552 + 553 + if(isleft) 554 + signx = -1; 555 + else 556 + signx = 1; 557 + 558 + #if LCD_DEPTH > 1 559 + for(int i = bx; i < fx + 1; i++) 560 + { 561 + /* add some stripes */ 562 + if(i % 3 == 0) 563 + rb->lcd_set_foreground(COLOR_PERP); 564 + else 565 + rb->lcd_set_foreground(COLOR_PARA); 566 + rb->lcd_vline(CX + signx * i/2, 567 + CY - tan_n * (i-bx)/2 / tan_d - by/2, 568 + CY + tan_n * (i-bx)/2 / tan_d + by/2); 569 + } 570 + #else 571 + rb->lcd_vline(CX + signx * bx/2, 572 + CY - by/2, 573 + CY + by/2); 574 + rb->lcd_vline(CX + signx * (fx + 1)/2, 575 + CY - tan_n * (fx - bx + 1)/2 / tan_d - by/2, 576 + CY + tan_n * (fx - bx + 1)/2 / tan_d + by/2); 577 + rb->lcd_drawline(CX + signx * bx/2, 578 + CY - by/2, 579 + CX + signx * (fx + 1)/2, 580 + CY - tan_n * (fx - bx + 1)/2 / tan_d - by/2); 581 + rb->lcd_drawline(CX + signx * bx/2, 582 + CY + by/2, 583 + CX + signx * (fx + 1)/2, 584 + CY + tan_n * (fx - bx + 1)/2 / tan_d + by/2); 585 + #endif 586 + } 587 + 588 + void draw_hall(int fx, int bx, int by, bool isleft) 589 + { 590 + #if LCD_DEPTH > 1 591 + rb->lcd_set_foreground(COLOR_PERP); 592 + 593 + if(isleft) 594 + rb->lcd_fillrect(CX - fx/2, CY - by/2, (fx - bx)/2 + 1, by); 595 + else 596 + rb->lcd_fillrect(CX + bx/2, CY - by/2, (fx - bx)/2 + 1, by); 597 + #else 598 + if(isleft) 599 + rb->lcd_drawrect(CX - fx/2, CY - by/2, (fx - bx)/2 + 1, by); 600 + else 601 + rb->lcd_drawrect(CX + bx/2, CY - by/2, (fx - bx)/2 + 1, by); 602 + #endif 603 + } 604 + 605 + void draw_side_tri(int fx, int fy, int bx, int tan_n, int tan_d, 606 + bool isvisited, bool isgoal) 607 + { 608 + int i; 609 + int signx, signy; 610 + 611 + signy = 1; 612 + 613 + while(signy >= -1) 614 + { 615 + #if LCD_DEPTH > 1 616 + if(signy == 1) 617 + if(isgoal) 618 + rb->lcd_set_foreground(COLOR_GOAL); 619 + else if(isvisited) 620 + rb->lcd_set_foreground(COLOR_VISITED); 621 + else 622 + rb->lcd_set_foreground(COLOR_GROUND); 623 + else 624 + rb->lcd_set_foreground(COLOR_SKY); 625 + #endif 626 + 627 + signx = 1; 628 + 629 + while(signx >= -1) 630 + { 631 + for(i = fx; i > bx; i--) { 632 + #if LCD_DEPTH == 1 /* if unvisited floor draw pattern, otherwise solid */ 633 + if (signy!=1 || isgoal || isvisited || (CX + signx * i/2) & 1) 634 + #endif 635 + rb->lcd_vline(CX + signx * i/2, 636 + CY + signy * fy/2, 637 + CY + signy * fy/2 638 + + signy * tan_n 639 + * (i - fx)/2 / tan_d); 640 + } 641 + signx-=2; 642 + } 643 + signy-=2; 644 + } 645 + } 646 + 647 + void draw_hall_crnr(int fx, int fy, int bx, int by, 648 + bool isleft, bool isvisited, bool isgoal) 649 + { 650 + #if LCD_DEPTH > 1 651 + rb->lcd_set_foreground(COLOR_SKY); 652 + #endif 653 + if(isleft) 654 + rb->lcd_fillrect(CX - fx/2, CY - fy/2, 655 + (fx - bx)/2 + 1, (fy - by)/2); 656 + else 657 + rb->lcd_fillrect(CX + bx/2, CY - fy/2, 658 + (fx - bx)/2 + 1, (fy - by)/2); 659 + 660 + #if LCD_DEPTH > 1 661 + if(isgoal) 662 + rb->lcd_set_foreground(COLOR_GOAL); 663 + else if(isvisited) 664 + rb->lcd_set_foreground(COLOR_VISITED); 665 + else 666 + rb->lcd_set_foreground(COLOR_GROUND); 667 + 668 + if(isleft) 669 + rb->lcd_fillrect(CX - fx/2, CY + by/2, 670 + (fx - bx)/2 + 1, (fy - by)/2); 671 + else 672 + rb->lcd_fillrect(CX + bx/2, CY + by/2, 673 + (fx - bx)/2 + 1, (fy - by)/2); 674 + #else /* LCD_DEPTH == 1 */ 675 + /* if unvisited floor draw pattern, otherwise solid */ 676 + if(isleft) 677 + for (int x = CX-fx/2; x <= CX-bx/2; x++) { 678 + if (isgoal || isvisited || x & 1) 679 + rb->lcd_vline(x, CY + by/2, CY + fy/2); 680 + } 681 + else 682 + for (int x = CX+bx/2; x <= CX+fx/2; x++) { 683 + if (isgoal || isvisited || x & 1) 684 + rb->lcd_vline(x, CY + by/2, CY + fy/2); 685 + } 686 + #endif 687 + } 688 + 689 + void draw_center_sq(int fy, int bx, int by, bool isvisited, bool isgoal, 690 + bool isfront, int chr) 691 + { 692 + chr = chr - '0'; /* get the integer value */ 693 + 694 + #if LCD_DEPTH > 1 695 + rb->lcd_set_foreground(COLOR_SKY); 696 + #endif 697 + rb->lcd_fillrect(CX - bx/2, CY - fy/2, bx, (fy - by)/2); 698 + 699 + #if LCD_DEPTH > 1 700 + if(isgoal) 701 + rb->lcd_set_foreground(COLOR_GOAL); 702 + else if(isvisited) 703 + rb->lcd_set_foreground(COLOR_VISITED); 704 + else 705 + rb->lcd_set_foreground(COLOR_GROUND); 706 + rb->lcd_fillrect(CX - bx/2, CY + by/2, bx, (fy - by)/2 + 1); 707 + #else 708 + /* if unvisited floor draw pattern, otherwise solid */ 709 + for (int x = CX-bx/2; x <= CX+bx/2; x++) { 710 + if (isgoal || isvisited || x & 1) 711 + rb->lcd_vline(x, CY + by/2, CY + fy/2 + 1); 712 + } 713 + #endif 714 + 715 + if(isvisited && chr >= 0 && chr <= 3) 716 + { 717 + #if LCD_DEPTH > 1 718 + rb->lcd_set_foreground(COLOR_MARK); 719 + #else 720 + rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); 721 + #endif 722 + if(isfront) 723 + { /* cell is marked in front, draw arrow */ 724 + if (chr == ((int)(pdir) + 3) % 4) 725 + draw_pointer(DIR_LEFT, false); 726 + else if (chr == ((int)(pdir) + 1) % 4) 727 + draw_pointer(DIR_RIGHT, false); 728 + else if (chr == ((int)(pdir) + 2) % 4) 729 + draw_pointer(DIR_DOWN, false); 730 + else /* same direction */ 731 + draw_pointer(DIR_UP, false); 732 + } 733 + else /* cell is marked but is in distance */ 734 + rb->lcd_fillrect(CX, CY + (fy + by)/4, 2, 2); 735 + #if LCD_DEPTH == 1 736 + rb->lcd_set_drawmode(DRMODE_SOLID); 737 + #endif 738 + } 739 + } 740 + 741 + bool is_visited(char cell) 742 + { 743 + if (cell - '0' >= 0 && cell - '0' <= 3) 744 + return true; 745 + else if (cell == VISITED) 746 + return true; 747 + else 748 + return false; 749 + } 750 + 751 + void graphic_view(void) 752 + { 753 + int dist; 754 + int x, y, dx, dy; 755 + int a, l, r; /* is block? ahead/left/right */ 756 + bool g, gl, gr; /* ground visted? under/left/right */ 757 + bool e, el, er; /* is goal? under/left/right */ 758 + int tan_n, tan_d; /* tangent numerator/denominator */ 759 + 760 + dx = dirtab[(int)pdir].x; 761 + dy = dirtab[(int)pdir].y; 762 + 763 + for (dist = 1; dist < depth; dist++) 764 + if (at(py + dy * dist, px + dx * dist) == BLOCK) 765 + break; 766 + 767 + if (!show_map) 768 + { 769 + clearmap(umap); 770 + copyumap(gy, gx, 1); 771 + } 772 + 773 + #if LCD_DEPTH == 1 774 + clearscreen(); 775 + #endif 776 + 777 + while (--dist >= 0) 778 + { 779 + x = px + dx * dist; 780 + y = py + dy * dist; 781 + 782 + /* ground */ 783 + g = is_visited(at(y, x)); 784 + gl = is_visited(at(y - dx, x + dy)); 785 + gr = is_visited(at(y + dx, x - dy)); 786 + /* goal/end */ 787 + e = at(y, x) == GOAL; 788 + el = at(y - dx, x + dy) == GOAL; 789 + er = at(y + dx, x - dy) == GOAL; 790 + /* ahead */ 791 + a = at(y + dy, x + dx) == BLOCK; 792 + /* to the left */ 793 + l = at(y - dx, x + dy) == BLOCK; 794 + /* to the right */ 795 + r = at(y + dx, x - dy) == BLOCK; 796 + 797 + tan_n = crd_y[dist] - crd_y[dist+1]; 798 + tan_d = crd_x[dist] - crd_x[dist+1]; 799 + 800 + if (a) 801 + draw_end_wall(crd_x[dist+1], crd_y[dist+1]); 802 + if (l) 803 + { 804 + draw_side(crd_x[dist], crd_x[dist+1], 805 + crd_y[dist+1], tan_n, tan_d, true); 806 + } 807 + else 808 + { 809 + draw_hall(crd_x[dist], crd_x[dist+1], 810 + crd_y[dist+1], true); 811 + draw_hall_crnr(crd_x[dist], crd_y[dist], crd_x[dist+1], 812 + crd_y[dist+1], true, gl, el); 813 + } 814 + if (r) 815 + { 816 + draw_side(crd_x[dist], crd_x[dist+1], 817 + crd_y[dist+1], tan_n, tan_d, false); 818 + } 819 + else 820 + { 821 + draw_hall(crd_x[dist], crd_x[dist+1], 822 + crd_y[dist+1], false); 823 + draw_hall_crnr(crd_x[dist], crd_y[dist], 824 + crd_x[dist+1], crd_y[dist+1], false, gr, er); 825 + } 826 + 827 + draw_center_sq(crd_y[dist], crd_x[dist+1], crd_y[dist+1], 828 + g, e, dist==0, (int)(at(y, x))); 829 + draw_side_tri(crd_x[dist], crd_y[dist], 830 + crd_x[dist+1], tan_n, tan_d, g, e); 831 + 832 + copyumap(y + dy, x + dx, 0); /* ahead */ 833 + copyumap(y, x, 1); /* here */ 834 + copyumap(y - dx, x + dy, 0); /* left */ 835 + copyumap(y + dx, x - dy, 0); /* right */ 836 + if (!l) 837 + copyumap(y - dx + dy, x + dy + dx, 0); /* lft ahead */ 838 + if (!r) 839 + copyumap(y + dx + dy, x - dy + dx, 0); /* rt ahead */ 840 + } 841 + if (compass) 842 + draw_pointer(pdir, true); 843 + } 844 + 845 + void win(void) 846 + { 847 + /* 848 + int i; 849 + char amazed[8] = "amazing!"; 850 + char newton; 851 + 852 + for (i=0; i <= 8; i++) 853 + { 854 + newton = amazed[i]; 855 + map_write(msg, 0, i + 31, newton); 856 + } 857 + */ 858 + won++; 859 + showmap(); 860 + show_map = 1; 861 + } 862 + 863 + 864 + /* Try to move the player in the direction given */ 865 + void trymove(enum dir dir) 866 + { 867 + int nx, ny; 868 + 869 + ny = py + dirtab[(int)dir].y; 870 + nx = px + dirtab[(int)dir].x; 871 + 872 + if (at(ny, nx) == BLOCK) 873 + { 874 + graphic_view(); 875 + return; 876 + } 877 + 878 + if (at(ny, nx) == GOAL) 879 + win(); 880 + 881 + mappmove(ny, nx, pdir); 882 + if (remember_visited && punder == SPACE) 883 + punder = VISITED; 884 + graphic_view(); 885 + } 886 + 887 + void walkleft(void) 888 + { 889 + int a, l; 890 + int dx, dy; 891 + int owon = won; 892 + 893 + while (1) 894 + { 895 + int input = pluginlib_getaction(TIMEOUT_NOBLOCK, plugin_contexts, 896 + ARRAYLEN(plugin_contexts)); 897 + if(input==PLA_CANCEL || input==PLA_EXIT) 898 + { 899 + return; 900 + } 901 + rb->lcd_update(); 902 + if (won != owon) 903 + { 904 + break; 905 + } 906 + 907 + dx = dirtab[(int)pdir].x; 908 + dy = dirtab[(int)pdir].y; 909 + 910 + /* ahead */ 911 + a = at(py + dy, px + dx) == BLOCK; 912 + /* to the left */ 913 + l = at(py - dx, px + dy) == BLOCK; 914 + 915 + if (!l) 916 + { 917 + mappmove(py, px, LEFT_OF(pdir)); 918 + graphic_view(); 919 + rb->sleep(2); 920 + trymove(pdir); 921 + continue; 922 + } 923 + if (a) 924 + { 925 + mappmove(py, px, RIGHT_OF(pdir)); 926 + graphic_view(); 927 + continue; 928 + } 929 + trymove(pdir); 930 + rb->yield(); 931 + } 932 + } 933 + 934 + void draw_tile(int index, int x, int y) 935 + { 936 + if (use_large_tiles == 1) 937 + rb->lcd_bitmap_part (amaze_tiles_large, 0, index * TILESIZE_LARGE, 938 + TILESIZE_LARGE, x * TILESIZE_LARGE, y * TILESIZE_LARGE, 939 + TILESIZE_LARGE, TILESIZE_LARGE); 940 + else 941 + rb->lcd_bitmap_part (amaze_tiles_small, 0, index * TILESIZE_SMALL, 942 + TILESIZE_SMALL, x * TILESIZE_SMALL, y * TILESIZE_SMALL, 943 + TILESIZE_SMALL, TILESIZE_SMALL); 944 + } 945 + 946 + void draw_tile_map(int xmin, int xmax, int ymin, int ymax) 947 + { 948 + int x,y; 949 + char map_unit; 950 + int tdex = 7; /* tile index */ 951 + 952 + enum tile_index 953 + { t_down=0, t_right=1, t_up=2, t_left=3, t_visited=4, 954 + t_obspace=5, t_goal=6, t_block=7, t_space=8, t_start=9 }; 955 + 956 + for(y = ymin; y <= ymax; y++) 957 + for(x = xmin; x <= xmax; x++) 958 + { 959 + 960 + map_unit = map_read(umap, y, x); 961 + 962 + switch (map_unit) 963 + { 964 + case VISITED: 965 + case '0': case '1': case '2': case '3': 966 + tdex = t_visited; 967 + break; 968 + case OBSPACE: 969 + tdex = t_obspace; 970 + break; 971 + case START: 972 + tdex = t_start; 973 + break; 974 + case GOAL: 975 + tdex = t_goal; 976 + break; 977 + case SPACE: 978 + tdex = t_space; 979 + break; 980 + case BLOCK: 981 + tdex = t_block; 982 + break; 983 + } 984 + draw_tile(tdex, x - xmin, y - ymin); 985 + } 986 + if(sx>=xmin && sx<=xmax && sy>=ymin && sy<=ymax) 987 + { 988 + x = sx; 989 + y = sy; 990 + draw_tile(t_start, x - xmin, y - ymin); 991 + } 992 + 993 + if(px>=xmin && px<=xmax && py>=ymin && py<=ymax) 994 + { 995 + x = px; 996 + y = py; 997 + draw_tile(pdir, x - xmin, y - ymin); 998 + } 999 + 1000 + rb->lcd_update(); 1001 + } 1002 + 1003 + void check_map_bounds(int *xmin, int *xmax, int *ymin, int *ymax) 1004 + { 1005 + int maxx, maxy; 1006 + 1007 + getmaxyx(&maxy, &maxx); 1008 + 1009 + /* bounds check x */ 1010 + if(*xmin < 0) 1011 + { 1012 + *xmax = *xmax - *xmin; 1013 + *xmin = 0; 1014 + } 1015 + if(*xmax >= maxx) 1016 + { 1017 + *xmin = *xmin - *xmax + maxx - 1; 1018 + *xmax = maxx - 1; 1019 + } 1020 + 1021 + /* bounds check y */ 1022 + if(*ymin < 0) 1023 + { 1024 + *ymax = *ymax - *ymin; 1025 + *ymin = 0; 1026 + } 1027 + if(*ymax >= maxy) 1028 + { 1029 + *ymin = *ymin - *ymax + maxy - 1; 1030 + *ymax = maxy - 1; 1031 + } 1032 + } 1033 + 1034 + void calc_map_size(int *xmin, int *xmax, int *ymin, int *ymax) 1035 + { 1036 + int tile_size; /* runtime option */ 1037 + int vx, vy; /* maxx, maxy of view */ 1038 + int midx, midy; /* midpoint x, y of view */ 1039 + int maxx, maxy; /* maxx, maxy of map */ 1040 + 1041 + getmaxyx(&maxy, &maxx); 1042 + 1043 + if (use_large_tiles == 1) 1044 + tile_size = TILESIZE_LARGE; 1045 + else 1046 + tile_size = TILESIZE_SMALL; 1047 + 1048 + vx = LCD_WIDTH / tile_size; 1049 + if (vx > maxx) 1050 + vx = maxx; 1051 + vy = LCD_HEIGHT / tile_size; 1052 + if (vy > maxy) 1053 + vy = maxy; 1054 + 1055 + midx = vx / 2; 1056 + midy = vy / 2; 1057 + 1058 + *xmin = px - midx; 1059 + if(vx % 2 == 0) 1060 + *xmax = px + midx - 1; 1061 + else 1062 + *xmax = px + midx; 1063 + 1064 + *ymin = py - midy; 1065 + if(vy % 2 == 0) 1066 + *ymax = py + midy - 1; 1067 + else 1068 + *ymax = py + midy; 1069 + 1070 + } 1071 + 1072 + 1073 + void draw_portion_map(void) 1074 + { 1075 + int xmin, xmax, ymin, ymax; /* coords of map corners */ 1076 + bool quit_map; 1077 + int input; 1078 + 1079 + clearscreen(); 1080 + 1081 + calc_map_size(&xmin, &xmax, &ymin, &ymax); 1082 + 1083 + quit_map = false; 1084 + 1085 + while (!quit_map) 1086 + { 1087 + check_map_bounds(&xmin, &xmax, &ymin, &ymax); 1088 + draw_tile_map(xmin, xmax, ymin, ymax); 1089 + 1090 + input = pluginlib_getaction(TIMEOUT_BLOCK, plugin_contexts, 1091 + ARRAYLEN(plugin_contexts)); 1092 + 1093 + switch(input) 1094 + { 1095 + case PLA_CANCEL: 1096 + case PLA_EXIT: 1097 + quit_map = true; 1098 + break; 1099 + case PLA_UP: 1100 + case PLA_UP_REPEAT: 1101 + ymin--; 1102 + ymax--; 1103 + break; 1104 + case PLA_DOWN: 1105 + case PLA_DOWN_REPEAT: 1106 + ymin++; 1107 + ymax++; 1108 + break; 1109 + case PLA_LEFT: 1110 + case PLA_LEFT_REPEAT: 1111 + xmin--; 1112 + xmax--; 1113 + break; 1114 + case PLA_RIGHT: 1115 + case PLA_RIGHT_REPEAT: 1116 + xmin++; 1117 + xmax++; 1118 + break; 1119 + default: 1120 + break; 1121 + } 1122 + } 1123 + } 1124 + 1125 + bool load_map(char *filename, char *amap) 1126 + { 1127 + int fd; 1128 + int x,y; 1129 + int maxxy; 1130 + size_t n; 1131 + char newton = BLOCK; 1132 + char map_size[2]; 1133 + 1134 + /* load a map */ 1135 + fd = rb->open(filename, O_RDONLY); 1136 + if (fd < 0) 1137 + { 1138 + LOGF("Invalid map file: %s\n", filename); 1139 + return false; 1140 + } 1141 + 1142 + n = rb->read(fd, map_size, sizeof(map_size)); 1143 + if (n <= 0) 1144 + { 1145 + LOGF("Invalid map size."); 1146 + return false; 1147 + } 1148 + 1149 + maze_size = (int)map_size[0] - 48; 1150 + maxxy = MAP_CONST * (maze_size + 1); 1151 + char line[maxxy + 1]; 1152 + 1153 + for(y=0; y < maxxy ; y++) 1154 + { 1155 + n = rb->read(fd, line, sizeof(line)); 1156 + if (n <= 0) 1157 + { 1158 + return false; 1159 + } 1160 + for(x=0; x < maxxy+1; x++) 1161 + { 1162 + switch(line[x]) 1163 + { 1164 + case '\n': 1165 + break; 1166 + case '0': case '1': case '2': case '3': 1167 + newton = line[x]; 1168 + break; 1169 + case START: 1170 + sy = y; 1171 + sx = x; 1172 + newton = START; 1173 + break; 1174 + case SPACE: 1175 + case BLOCK: 1176 + case OBSPACE: 1177 + newton = line[x]; 1178 + break; 1179 + case GOAL: 1180 + newton = GOAL; 1181 + gy = y; 1182 + gx = x; 1183 + break; 1184 + case A_DOWN: case A_LEFT: case A_UP: case A_RIGHT: 1185 + py = y; 1186 + px = x; 1187 + switch(line[x]) 1188 + { 1189 + case A_DOWN: 1190 + pdir = DIR_DOWN; 1191 + break; 1192 + case A_LEFT: 1193 + pdir = DIR_LEFT; 1194 + break; 1195 + case A_UP: 1196 + pdir = DIR_UP; 1197 + break; 1198 + case A_RIGHT: 1199 + pdir = DIR_RIGHT; 1200 + break; 1201 + } 1202 + /* FALLTHROUGH */ 1203 + case VISITED: 1204 + newton = VISITED; 1205 + break; 1206 + } 1207 + if (line[x] != '\n') 1208 + map_write(amap, y, x, newton); 1209 + } 1210 + } 1211 + rb->close(fd); 1212 + rb->remove(filename); 1213 + return true; 1214 + } 1215 + 1216 + bool load_game(void) 1217 + { 1218 + if (load_map(UMAP_FILE, umap) && load_map(MAP_FILE, map)) 1219 + return true; 1220 + else 1221 + return false; 1222 + } 1223 + 1224 + 1225 + bool save_map(char *filename, char *amap) 1226 + { 1227 + int x,y; 1228 + int maxy, maxx; 1229 + char map_unit; 1230 + int fd; 1231 + int line_len = (maze_size + 1) * MAP_CONST + 1; 1232 + char line[line_len]; 1233 + char map_size[2] = 1234 + {'0','\n'}; 1235 + 1236 + line[line_len - 1] = '\n'; /* last cell is a linefeed */ 1237 + map_size[0] = (char)(maze_size + 48); 1238 + 1239 + if ((fd = rb->open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) 1240 + return false; 1241 + 1242 + rb->write(fd, map_size, 2); 1243 + 1244 + getmaxyx(&maxy, &maxx); 1245 + 1246 + for(y=0; y < maxy; y++) 1247 + { 1248 + for (x=0; x < maxx; x++) 1249 + { 1250 + map_unit = map_read(amap, y, x); 1251 + 1252 + if(y == py && x == px) 1253 + line[x] = ptab[_TOI(pdir)]; 1254 + else if(y == sy && x == sx) 1255 + line[x] = START; 1256 + else 1257 + line[x] = map_unit; 1258 + } 1259 + rb->write(fd, line, line_len); 1260 + } 1261 + rb->close(fd); 1262 + 1263 + return true; 1264 + } 1265 + 1266 + bool save_game(void) 1267 + { 1268 + if (save_map(UMAP_FILE, umap) && save_map(MAP_FILE, map)) 1269 + return true; 1270 + else 1271 + return false; 1272 + } 1273 + 1274 + 1275 + bool ingame; 1276 + bool save_prefs(char *filename); 1277 + 1278 + static int menu_cb(int action, const struct menu_item_ex *this_item, 1279 + struct gui_synclist *this_list) 1280 + { 1281 + (void)this_list; 1282 + 1283 + int idx=((intptr_t)this_item); 1284 + if (action==ACTION_REQUEST_MENUITEM) { 1285 + if (ingame) { 1286 + if (idx==2) 1287 + return ACTION_EXIT_MENUITEM; 1288 + } 1289 + else { /* !ingame */ 1290 + if (idx==3 || idx==8) 1291 + return ACTION_EXIT_MENUITEM; 1292 + if (!loaded && (idx==0 || idx==9)) 1293 + return ACTION_EXIT_MENUITEM; 1294 + } 1295 + } 1296 + return action; 1297 + } 1298 + 1299 + int menu(void) 1300 + { 1301 + bool exit_menu = false; 1302 + int selection = 0, result = 0, status = 1; 1303 + 1304 + MENUITEM_STRINGLIST(menu, ID2P(LANG_AMAZE_MENU), menu_cb, 1305 + ID2P(LANG_CHESSBOX_MENU_RESUME_GAME), 1306 + ID2P(LANG_CHESSBOX_MENU_NEW_GAME), 1307 + ID2P(LANG_SET_MAZE_SIZE), 1308 + ID2P(LANG_VIEW_MAP), 1309 + ID2P(LANG_SHOW_COMPASS), 1310 + ID2P(LANG_SHOW_MAP), 1311 + ID2P(LANG_REMEMBER_PATH), 1312 + ID2P(LANG_USE_LARGE_TILES), 1313 + ID2P(LANG_SHOW_SOLUTION), 1314 + ID2P(LANG_QUIT_WITHOUT_SAVING), 1315 + ID2P(LANG_MENU_QUIT) 1316 + ); 1317 + 1318 + clearscreen(); 1319 + 1320 + while(!exit_menu) 1321 + { 1322 + result = rb->do_menu(&menu, &selection, NULL, false); 1323 + switch(result) 1324 + { 1325 + case 0: /* resume */ 1326 + exit_menu = true; 1327 + if (!ingame) { 1328 + save_prefs(PREF_FILE); 1329 + } 1330 + break; 1331 + case 1: /* new game */ 1332 + exit_menu = true; 1333 + if (ingame) 1334 + { 1335 + rb->splash(0, ID2P(LANG_GENERATING_MAZE)); 1336 + clearmap(umap); 1337 + makemaze(); 1338 + 1339 + /* Show where the goal is */ 1340 + copyumap(gy, gx, 1); 1341 + rb->lcd_update(); 1342 + 1343 + mappmove(py, px, pdir); 1344 + 1345 + if (remember_visited) 1346 + punder = VISITED; 1347 + else 1348 + punder = SPACE; 1349 + } 1350 + else { /* !ingame */ 1351 + loaded=false; 1352 + save_prefs(PREF_FILE); 1353 + } 1354 + break; 1355 + case 2: /* Set maze size */ 1356 + { 1357 + int old_size = maze_size; 1358 + rb->set_option(rb->str(LANG_SET_MAZE_SIZE), &maze_size, RB_INT, 1359 + mazesize_text, 4, NULL); 1360 + if (maze_size != old_size) 1361 + loaded = false; 1362 + } 1363 + break; 1364 + case 3: /* View map */ 1365 + exit_menu = true; 1366 + draw_portion_map(); 1367 + break; 1368 + case 4: /* Show compass option */ 1369 + rb->set_option(rb->str(LANG_SHOW_COMPASS), &compass, RB_BOOL, 1370 + noyes_text, 2, NULL); 1371 + break; 1372 + case 5: /* Show Map option */ 1373 + rb->set_option(rb->str(LANG_SHOW_MAP), &show_map, RB_BOOL, 1374 + noyes_text, 2, NULL); 1375 + break; 1376 + case 6: /* Remember Path option */ 1377 + rb->set_option(rb->str(LANG_REMEMBER_PATH), &remember_visited, RB_BOOL, 1378 + noyes_text, 2, NULL); 1379 + break; 1380 + case 7: /* Tilesize option */ 1381 + rb->set_option(rb->str(LANG_USE_LARGE_TILES), &use_large_tiles, RB_BOOL, 1382 + noyes_text, 2, NULL); 1383 + break; 1384 + case 8: /* solver */ 1385 + exit_menu = true; 1386 + cheated++; 1387 + walkleft(); 1388 + break; 1389 + case 9: /* quit w/o saving */ 1390 + exit_menu = true; 1391 + status = 0; 1392 + break; 1393 + case 10: /* save+quit */ 1394 + exit_menu = true; 1395 + if (ingame) { 1396 + if (save_game()) 1397 + status = 0; 1398 + else 1399 + rb->splash(HZ*3, ID2P(LANG_ERROR_WRITING_CONFIG)); 1400 + } 1401 + else { 1402 + if(loaded) 1403 + save_game(); 1404 + status = 0; 1405 + } 1406 + break; 1407 + } 1408 + } 1409 + return status; 1410 + } 1411 + 1412 + int amaze(void) 1413 + { 1414 + int quitting; 1415 + int i; 1416 + int input; 1417 + 1418 + clearscreen(); 1419 + rb->lcd_setfont(FONT_SYSFIXED); 1420 + if(!loaded) 1421 + rb->splash(0, ID2P(LANG_GENERATING_MAZE)); 1422 + 1423 + crd_x[0] = LCD_WIDTH + 1; 1424 + crd_y[0] = LCD_HEIGHT + 1; 1425 + for (depth=1; depth < MAX_DEPTH + 1; depth++) 1426 + { 1427 + crd_x[depth] = crd_x[depth-1]*2/3; 1428 + if(crd_x[depth] % 2 != 0) crd_x[depth]++; 1429 + crd_y[depth] = crd_y[depth-1]*2/3; 1430 + if(crd_y[depth] % 2 != 0) crd_y[depth]++; 1431 + if (crd_x[depth]==crd_x[depth-1] || crd_y[depth]==crd_y[depth-1]) 1432 + break; 1433 + } 1434 + --depth; 1435 + 1436 + if (!loaded) 1437 + { 1438 + clearmap(umap); 1439 + makemaze(); 1440 + } 1441 + 1442 + /* Show where the goal is */ 1443 + 1444 + copyumap(gy, gx, 1); 1445 + 1446 + rb->lcd_update(); 1447 + 1448 + quitting = 0; 1449 + 1450 + mappmove(py, px, pdir); 1451 + 1452 + if (remember_visited) 1453 + punder = VISITED; 1454 + else 1455 + punder = SPACE; 1456 + 1457 + clearscreen(); 1458 + graphic_view(); 1459 + 1460 + while (!quitting && !won) 1461 + { 1462 + 1463 + rb->lcd_update(); 1464 + 1465 + input = pluginlib_getaction(TIMEOUT_BLOCK, plugin_contexts, 1466 + ARRAYLEN(plugin_contexts)); 1467 + 1468 + switch (input) 1469 + { 1470 + case PLA_CANCEL: 1471 + case PLA_EXIT: 1472 + i = menu(); 1473 + rb->lcd_setfont(FONT_SYSFIXED); 1474 + clearscreen(); 1475 + graphic_view(); 1476 + 1477 + switch (i) 1478 + { 1479 + case 0: 1480 + quitting = 1; 1481 + break; 1482 + case 1: 1483 + break; 1484 + case 2: 1485 + return 0; 1486 + break; 1487 + } 1488 + break; 1489 + case PLA_UP: 1490 + case PLA_UP_REPEAT: 1491 + trymove(pdir); 1492 + break; 1493 + case PLA_DOWN: 1494 + case PLA_DOWN_REPEAT: 1495 + trymove(REVERSE_OF(pdir)); 1496 + break; 1497 + case PLA_LEFT: 1498 + mappmove(py, px, LEFT_OF(pdir)); 1499 + graphic_view(); 1500 + break; 1501 + case PLA_RIGHT: 1502 + mappmove(py, px, RIGHT_OF(pdir)); 1503 + graphic_view(); 1504 + break; 1505 + case PLA_SELECT: 1506 + if (punder==SPACE || punder==VISITED) 1507 + { /* mark ground */ 1508 + punder = pdir + '0'; 1509 + } 1510 + else 1511 + { /* clear mark */ 1512 + if (remember_visited) 1513 + punder = VISITED; 1514 + else 1515 + punder = SPACE; 1516 + } 1517 + graphic_view(); 1518 + break; 1519 + } 1520 + } 1521 + 1522 + rb->lcd_update(); 1523 + //graphic_view(); 1524 + if (won) 1525 + { 1526 + won = false; /* reset boolean */ 1527 + if (cheated) 1528 + { 1529 + rb->splash(HZ*2, ID2P(LANG_YOU_CHEATED)); 1530 + return 0; 1531 + } 1532 + rb->splash(HZ*2, ID2P(LANG_YOU_WIN)); 1533 + return 1; 1534 + } 1535 + else 1536 + { 1537 + return 0; 1538 + } 1539 + } 1540 + 1541 + bool save_prefs(char *filename) 1542 + { 1543 + int fd; 1544 + char ms[2] = { (char)(maze_size) + '0', '\n' }; 1545 + char sm[2] = { (char)(show_map) + '0', '\n' }; 1546 + char rv[2] = { (char)(remember_visited) + '0', '\n' }; 1547 + char lt[2] = { (char)(use_large_tiles) + '0', '\n' }; 1548 + 1549 + fd = rb->open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666); 1550 + if(fd >= 0) 1551 + { 1552 + rb->write(fd, ms, 2); 1553 + rb->write(fd, sm, 2); 1554 + rb->write(fd, rv, 2); 1555 + rb->write(fd, lt, 2); 1556 + } 1557 + else 1558 + { 1559 + rb->splash(HZ, ID2P(LANG_ERROR_WRITING_CONFIG)); 1560 + return false; 1561 + } 1562 + rb->close(fd); 1563 + return true; 1564 + } 1565 + 1566 + bool load_prefs(char *filename) 1567 + { 1568 + int fd; 1569 + char instr[2]; 1570 + 1571 + fd = rb->open(filename, O_RDONLY); 1572 + if (fd < 0) 1573 + { 1574 + LOGF("Invalid preferences file: %s\n", filename); 1575 + return false; 1576 + } 1577 + 1578 + rb->read(fd, instr, sizeof(instr)); 1579 + maze_size = (int)(instr[0] - '0'); 1580 + rb->read(fd, instr, sizeof(instr)); 1581 + show_map = (bool)(instr[0] - '0'); 1582 + rb->read(fd, instr, sizeof(instr)); 1583 + remember_visited = (bool)(instr[0] - '0'); 1584 + rb->read(fd, instr, sizeof(instr)); 1585 + use_large_tiles = (bool)(instr[0] - '0'); 1586 + rb->close(fd); 1587 + 1588 + return true; 1589 + } 1590 + 1591 + enum plugin_status plugin_start(const void *parameter) 1592 + { 1593 + (void) parameter; 1594 + int ret; 1595 + 1596 + rb->srand(*rb->current_tick); 1597 + 1598 + /* hard-code in program default options */ 1599 + show_map=1; 1600 + remember_visited=1; 1601 + use_large_tiles=1; 1602 + maze_size=1; 1603 + 1604 + loaded=load_game(); 1605 + 1606 + /* let's go, gentlemen, we have some work to do */ 1607 + #if LCD_DEPTH > 1 1608 + rb->lcd_set_backdrop(NULL); 1609 + #endif 1610 + ingame = false; 1611 + ret = menu(); 1612 + if (ret) { 1613 + ingame = true; 1614 + amaze(); 1615 + } 1616 + 1617 + rb->lcd_setfont(FONT_UI); 1618 + 1619 + return PLUGIN_OK; 1620 + }
+38
apps/plugins/bitmaps/native/SOURCES
··· 27 27 #endif 28 28 #undef MIN 29 29 30 + /* amaze */ 31 + #if defined(HAVE_LCD_COLOR) 32 + #if LCD_WIDTH >= 220 || LCD_HEIGHT >= 220 33 + amaze_tiles_9.9x9x16.bmp 34 + amaze_tiles_7.7x7x16.bmp 35 + #elif LCD_WIDTH >= 160 || LCD_HEIGHT >= 160 36 + amaze_tiles_7.7x7x16.bmp 37 + amaze_tiles_5.5x5x16.bmp 38 + #else 39 + amaze_tiles_5.5x5x16.bmp 40 + amaze_tiles_3.3x3x16.bmp 41 + #endif 42 + 43 + #elif LCD_DEPTH > 1 44 + #if LCD_WIDTH >= 220 || LCD_HEIGHT >= 220 45 + amaze_tiles_9.9x9x2.bmp 46 + amaze_tiles_7.7x7x2.bmp 47 + #elif LCD_WIDTH >= 160 || LCD_HEIGHT >= 160 48 + amaze_tiles_7.7x7x2.bmp 49 + amaze_tiles_5.5x5x2.bmp 50 + #else 51 + amaze_tiles_5.5x5x2.bmp 52 + amaze_tiles_3.3x3x2.bmp 53 + #endif 54 + 55 + #else /* mono */ 56 + #if LCD_WIDTH >= 220 || LCD_HEIGHT >= 220 57 + amaze_tiles_9.9x9x1.bmp 58 + amaze_tiles_7.7x7x1.bmp 59 + #elif LCD_WIDTH >= 160 || LCD_HEIGHT >= 160 60 + amaze_tiles_7.7x7x1.bmp 61 + amaze_tiles_5.5x5x1.bmp 62 + #else 63 + amaze_tiles_5.5x5x1.bmp 64 + amaze_tiles_3.3x3x1.bmp 65 + #endif 66 + #endif /* amaze */ 67 + 30 68 /* Brickmania */ 31 69 #ifdef HAVE_LCD_COLOR 32 70 #if LCD_WIDTH >= 112
apps/plugins/bitmaps/native/amaze_tiles_3.3x3x1.bmp

This is a binary file and will not be displayed.

apps/plugins/bitmaps/native/amaze_tiles_3.3x3x16.bmp

This is a binary file and will not be displayed.

apps/plugins/bitmaps/native/amaze_tiles_3.3x3x2.bmp

This is a binary file and will not be displayed.

apps/plugins/bitmaps/native/amaze_tiles_5.5x5x1.bmp

This is a binary file and will not be displayed.

apps/plugins/bitmaps/native/amaze_tiles_5.5x5x16.bmp

This is a binary file and will not be displayed.

apps/plugins/bitmaps/native/amaze_tiles_5.5x5x2.bmp

This is a binary file and will not be displayed.

apps/plugins/bitmaps/native/amaze_tiles_7.7x7x1.bmp

This is a binary file and will not be displayed.

apps/plugins/bitmaps/native/amaze_tiles_7.7x7x16.bmp

This is a binary file and will not be displayed.

apps/plugins/bitmaps/native/amaze_tiles_7.7x7x2.bmp

This is a binary file and will not be displayed.

apps/plugins/bitmaps/native/amaze_tiles_9.9x9x1.bmp

This is a binary file and will not be displayed.

apps/plugins/bitmaps/native/amaze_tiles_9.9x9x16.bmp

This is a binary file and will not be displayed.

apps/plugins/bitmaps/native/amaze_tiles_9.9x9x2.bmp

This is a binary file and will not be displayed.

+1
docs/CREDITS
··· 717 717 Mihaly 'Hermit' Horvath 718 718 Uwe Kleine-König 719 719 JJ Style 720 + Jerry Chapman 720 721 721 722 The libmad team 722 723 The wavpack team
+6
manual/plugins/amaze.tex
··· 1 + \subsection{Amaze} 2 + \screenshot{plugins/images/ss-amaze}{Amaze}{img:amaze} 3 + Amaze is a simple 3D maze game. 4 + 5 + Based upon the curses-based amaze by David Leonard, graciously placed 6 + into the public domain. More information can be found here: \url{https://www.adaptive-enterprises.com.au/~d/software/amaze/}
manual/plugins/images/ss-amaze-128x160x24.png

This is a binary file and will not be displayed.

manual/plugins/images/ss-amaze-128x64x1.png

This is a binary file and will not be displayed.

manual/plugins/images/ss-amaze-138x110x2.png

This is a binary file and will not be displayed.

manual/plugins/images/ss-amaze-176x132x16.png

This is a binary file and will not be displayed.

manual/plugins/images/ss-amaze-240x320x24.png

This is a binary file and will not be displayed.

manual/plugins/images/ss-amaze-320x240x16.png

This is a binary file and will not be displayed.

+2
manual/plugins/main.tex
··· 25 25 26 26 \input{plugins/2048.tex} 27 27 28 + \input{plugins/amaze.tex} 29 + 28 30 \input{plugins/blackjack.tex} 29 31 30 32 \opt{large_plugin_buffer}{\input{plugins/boomshine.tex}}