summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranklin Wei <frankhwei536@gmail.com>2014-09-03 19:16:37 -0400
committerSolomon Peachy <pizza@shaftnet.org>2024-04-24 17:37:58 -0400
commit6efd7f8f3e4a9de578646c77c7527c54b3c8e557 (patch)
tree97bff19881dfc7db5b87801ccf74d07cc24d12cb
parent2dbf26f11aff960ddac01fb625d857e2d1e42263 (diff)
downloadrockbox-6efd7f8f3e4a9de578646c77c7527c54b3c8e557.tar.gz
rockbox-6efd7f8f3e4a9de578646c77c7527c54b3c8e557.zip
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
-rw-r--r--apps/lang/english.lang224
-rw-r--r--apps/plugins/CATEGORIES1
-rw-r--r--apps/plugins/SOURCES1
-rw-r--r--apps/plugins/amaze.c1620
-rw-r--r--apps/plugins/bitmaps/native/SOURCES38
-rw-r--r--apps/plugins/bitmaps/native/amaze_tiles_3.3x3x1.bmpbin0 -> 182 bytes
-rw-r--r--apps/plugins/bitmaps/native/amaze_tiles_3.3x3x16.bmpbin0 -> 414 bytes
-rw-r--r--apps/plugins/bitmaps/native/amaze_tiles_3.3x3x2.bmpbin0 -> 1198 bytes
-rw-r--r--apps/plugins/bitmaps/native/amaze_tiles_5.5x5x1.bmpbin0 -> 262 bytes
-rw-r--r--apps/plugins/bitmaps/native/amaze_tiles_5.5x5x16.bmpbin0 -> 854 bytes
-rw-r--r--apps/plugins/bitmaps/native/amaze_tiles_5.5x5x2.bmpbin0 -> 270 bytes
-rw-r--r--apps/plugins/bitmaps/native/amaze_tiles_7.7x7x1.bmpbin0 -> 342 bytes
-rw-r--r--apps/plugins/bitmaps/native/amaze_tiles_7.7x7x16.bmpbin0 -> 1734 bytes
-rw-r--r--apps/plugins/bitmaps/native/amaze_tiles_7.7x7x2.bmpbin0 -> 1638 bytes
-rw-r--r--apps/plugins/bitmaps/native/amaze_tiles_9.9x9x1.bmpbin0 -> 422 bytes
-rw-r--r--apps/plugins/bitmaps/native/amaze_tiles_9.9x9x16.bmpbin0 -> 2574 bytes
-rw-r--r--apps/plugins/bitmaps/native/amaze_tiles_9.9x9x2.bmpbin0 -> 2158 bytes
-rw-r--r--docs/CREDITS1
-rw-r--r--manual/plugins/amaze.tex6
-rw-r--r--manual/plugins/images/ss-amaze-128x160x24.pngbin0 -> 803 bytes
-rw-r--r--manual/plugins/images/ss-amaze-128x64x1.pngbin0 -> 961 bytes
-rw-r--r--manual/plugins/images/ss-amaze-138x110x2.pngbin0 -> 687 bytes
-rw-r--r--manual/plugins/images/ss-amaze-176x132x16.pngbin0 -> 883 bytes
-rw-r--r--manual/plugins/images/ss-amaze-240x320x24.pngbin0 -> 1215 bytes
-rw-r--r--manual/plugins/images/ss-amaze-320x240x16.pngbin0 -> 1057 bytes
-rw-r--r--manual/plugins/main.tex2
26 files changed, 1893 insertions, 0 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index b060c8230e..3a1f52c9b1 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -16711,3 +16711,227 @@
16711 *: "Default Browser" 16711 *: "Default Browser"
16712 </voice> 16712 </voice>
16713</phrase> 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>
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES
index 5320015772..28b8b67c68 100644
--- a/apps/plugins/CATEGORIES
+++ b/apps/plugins/CATEGORIES
@@ -2,6 +2,7 @@
2alpine_cdc,apps 2alpine_cdc,apps
3alarmclock,apps 3alarmclock,apps
4announce_status,demos 4announce_status,demos
5amaze,games
5autostart,apps 6autostart,apps
6battery_bench,apps 7battery_bench,apps
7bench_scaler,apps 8bench_scaler,apps
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
index bf36d50a40..3d520dea39 100644
--- a/apps/plugins/SOURCES
+++ b/apps/plugins/SOURCES
@@ -112,6 +112,7 @@ pictureflow.c
112metronome.c 112metronome.c
113 113
1142048.c 1142048.c
115amaze.c
115 116
116/* Lua needs at least 160 KB to work in */ 117/* Lua needs at least 160 KB to work in */
117#if PLUGIN_BUFFER_SIZE >= 0x80000 118#if PLUGIN_BUFFER_SIZE >= 0x80000
diff --git a/apps/plugins/amaze.c b/apps/plugins/amaze.c
new file mode 100644
index 0000000000..2af9463a16
--- /dev/null
+++ b/apps/plugins/amaze.c
@@ -0,0 +1,1620 @@
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
30const struct button_mapping *plugin_contexts[] = { pla_main_ctx };
31
32static const struct opt_items noyes_text[] = {
33 { STR(LANG_SET_BOOL_NO) },
34 { STR(LANG_SET_BOOL_YES) }
35};
36
37static 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
44bool show_map;
45bool remember_visited;
46bool use_large_tiles;
47int 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
89enum 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
96static struct { int y, x; } dirtab[4] =
97 { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } };
98static char ptab[4] = { A_DOWN, A_RIGHT, A_UP, A_LEFT };
99
100int px, py; /* Player position */
101enum dir pdir; /* Player direction */
102char punder; /* character under player, if any */
103int sx, sy; /* Start position */
104int gx, gy; /* Goal position */
105int gdist; /* Distance from start to goal */
106int won = 0; /* Reached goal */
107int cheated = 0; /* Cheated somehow */
108bool compass = false; /* show compass */
109int button; /* Button data */
110bool loaded=false; /* Loaded? */
111
112#define FIELD_SIZE 80
113#define MAP_CONST 20
114
115static char map[FIELD_SIZE * FIELD_SIZE]; /* map storage */
116static char umap[FIELD_SIZE * FIELD_SIZE];
117
118/* visible depth */
119#define MAX_DEPTH 20
120int depth;
121
122/* CX,CY = center of screen */
123#define CX LCD_WIDTH / 2
124#define CY LCD_HEIGHT / 2
125
126int 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
156void 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
166void getmaxyx(int *y, int *x)
167{
168 *y = (maze_size + 1) * MAP_CONST;
169 *x = (maze_size + 1) * MAP_CONST;
170}
171
172void 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}
183char 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 */
197void 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 */
212char 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
228void 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
238struct 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 */
253void 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 */
382void 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
395void 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 */
409void 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 */
438void 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
472void 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 */
498void 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
539void 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
549void 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
588void 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
605void 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
647void 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
689void 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
741bool 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
751void 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
845void 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 */
865void 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
887void 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
934void 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
946void 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
1003void 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
1034void 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
1073void 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
1125bool 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
1216bool 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
1225bool 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
1266bool 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
1275bool ingame;
1276bool save_prefs(char *filename);
1277
1278static 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
1299int 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
1412int 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
1541bool 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
1566bool 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
1591enum 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}
diff --git a/apps/plugins/bitmaps/native/SOURCES b/apps/plugins/bitmaps/native/SOURCES
index 814845dc5b..cfc9ebcf6a 100644
--- a/apps/plugins/bitmaps/native/SOURCES
+++ b/apps/plugins/bitmaps/native/SOURCES
@@ -27,6 +27,44 @@ _2048_background.56x56x24.bmp
27#endif 27#endif
28#undef MIN 28#undef MIN
29 29
30/* amaze */
31#if defined(HAVE_LCD_COLOR)
32#if LCD_WIDTH >= 220 || LCD_HEIGHT >= 220
33amaze_tiles_9.9x9x16.bmp
34amaze_tiles_7.7x7x16.bmp
35#elif LCD_WIDTH >= 160 || LCD_HEIGHT >= 160
36amaze_tiles_7.7x7x16.bmp
37amaze_tiles_5.5x5x16.bmp
38#else
39amaze_tiles_5.5x5x16.bmp
40amaze_tiles_3.3x3x16.bmp
41#endif
42
43#elif LCD_DEPTH > 1
44#if LCD_WIDTH >= 220 || LCD_HEIGHT >= 220
45amaze_tiles_9.9x9x2.bmp
46amaze_tiles_7.7x7x2.bmp
47#elif LCD_WIDTH >= 160 || LCD_HEIGHT >= 160
48amaze_tiles_7.7x7x2.bmp
49amaze_tiles_5.5x5x2.bmp
50#else
51amaze_tiles_5.5x5x2.bmp
52amaze_tiles_3.3x3x2.bmp
53#endif
54
55#else /* mono */
56#if LCD_WIDTH >= 220 || LCD_HEIGHT >= 220
57amaze_tiles_9.9x9x1.bmp
58amaze_tiles_7.7x7x1.bmp
59#elif LCD_WIDTH >= 160 || LCD_HEIGHT >= 160
60amaze_tiles_7.7x7x1.bmp
61amaze_tiles_5.5x5x1.bmp
62#else
63amaze_tiles_5.5x5x1.bmp
64amaze_tiles_3.3x3x1.bmp
65#endif
66#endif /* amaze */
67
30/* Brickmania */ 68/* Brickmania */
31#ifdef HAVE_LCD_COLOR 69#ifdef HAVE_LCD_COLOR
32#if LCD_WIDTH >= 112 70#if LCD_WIDTH >= 112
diff --git a/apps/plugins/bitmaps/native/amaze_tiles_3.3x3x1.bmp b/apps/plugins/bitmaps/native/amaze_tiles_3.3x3x1.bmp
new file mode 100644
index 0000000000..66418779de
--- /dev/null
+++ b/apps/plugins/bitmaps/native/amaze_tiles_3.3x3x1.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/amaze_tiles_3.3x3x16.bmp b/apps/plugins/bitmaps/native/amaze_tiles_3.3x3x16.bmp
new file mode 100644
index 0000000000..930d4c62fc
--- /dev/null
+++ b/apps/plugins/bitmaps/native/amaze_tiles_3.3x3x16.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/amaze_tiles_3.3x3x2.bmp b/apps/plugins/bitmaps/native/amaze_tiles_3.3x3x2.bmp
new file mode 100644
index 0000000000..504525b7f4
--- /dev/null
+++ b/apps/plugins/bitmaps/native/amaze_tiles_3.3x3x2.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x1.bmp b/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x1.bmp
new file mode 100644
index 0000000000..d5973cfc5e
--- /dev/null
+++ b/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x1.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x16.bmp b/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x16.bmp
new file mode 100644
index 0000000000..7ec316df6a
--- /dev/null
+++ b/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x16.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x2.bmp b/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x2.bmp
new file mode 100644
index 0000000000..e06075310e
--- /dev/null
+++ b/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x2.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x1.bmp b/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x1.bmp
new file mode 100644
index 0000000000..820f5a873b
--- /dev/null
+++ b/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x1.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x16.bmp b/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x16.bmp
new file mode 100644
index 0000000000..e9d6bc5086
--- /dev/null
+++ b/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x16.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x2.bmp b/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x2.bmp
new file mode 100644
index 0000000000..2e8e76593b
--- /dev/null
+++ b/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x2.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x1.bmp b/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x1.bmp
new file mode 100644
index 0000000000..0f2212e7e5
--- /dev/null
+++ b/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x1.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x16.bmp b/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x16.bmp
new file mode 100644
index 0000000000..0188dd9726
--- /dev/null
+++ b/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x16.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x2.bmp b/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x2.bmp
new file mode 100644
index 0000000000..f095368d30
--- /dev/null
+++ b/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x2.bmp
Binary files differ
diff --git a/docs/CREDITS b/docs/CREDITS
index 4783033466..363c7b7dfb 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -717,6 +717,7 @@ Richard Goedeken
717Mihaly 'Hermit' Horvath 717Mihaly 'Hermit' Horvath
718Uwe Kleine-König 718Uwe Kleine-König
719JJ Style 719JJ Style
720Jerry Chapman
720 721
721The libmad team 722The libmad team
722The wavpack team 723The wavpack team
diff --git a/manual/plugins/amaze.tex b/manual/plugins/amaze.tex
new file mode 100644
index 0000000000..66b3abeb4b
--- /dev/null
+++ b/manual/plugins/amaze.tex
@@ -0,0 +1,6 @@
1\subsection{Amaze}
2\screenshot{plugins/images/ss-amaze}{Amaze}{img:amaze}
3Amaze is a simple 3D maze game.
4
5Based upon the curses-based amaze by David Leonard, graciously placed
6into the public domain. More information can be found here: \url{https://www.adaptive-enterprises.com.au/~d/software/amaze/}
diff --git a/manual/plugins/images/ss-amaze-128x160x24.png b/manual/plugins/images/ss-amaze-128x160x24.png
new file mode 100644
index 0000000000..71305d47d9
--- /dev/null
+++ b/manual/plugins/images/ss-amaze-128x160x24.png
Binary files differ
diff --git a/manual/plugins/images/ss-amaze-128x64x1.png b/manual/plugins/images/ss-amaze-128x64x1.png
new file mode 100644
index 0000000000..f0a9680fda
--- /dev/null
+++ b/manual/plugins/images/ss-amaze-128x64x1.png
Binary files differ
diff --git a/manual/plugins/images/ss-amaze-138x110x2.png b/manual/plugins/images/ss-amaze-138x110x2.png
new file mode 100644
index 0000000000..6a2014ecae
--- /dev/null
+++ b/manual/plugins/images/ss-amaze-138x110x2.png
Binary files differ
diff --git a/manual/plugins/images/ss-amaze-176x132x16.png b/manual/plugins/images/ss-amaze-176x132x16.png
new file mode 100644
index 0000000000..9d581393a6
--- /dev/null
+++ b/manual/plugins/images/ss-amaze-176x132x16.png
Binary files differ
diff --git a/manual/plugins/images/ss-amaze-240x320x24.png b/manual/plugins/images/ss-amaze-240x320x24.png
new file mode 100644
index 0000000000..2fce9b7865
--- /dev/null
+++ b/manual/plugins/images/ss-amaze-240x320x24.png
Binary files differ
diff --git a/manual/plugins/images/ss-amaze-320x240x16.png b/manual/plugins/images/ss-amaze-320x240x16.png
new file mode 100644
index 0000000000..77e9ca8bb8
--- /dev/null
+++ b/manual/plugins/images/ss-amaze-320x240x16.png
Binary files differ
diff --git a/manual/plugins/main.tex b/manual/plugins/main.tex
index 4725818029..19636292ad 100644
--- a/manual/plugins/main.tex
+++ b/manual/plugins/main.tex
@@ -25,6 +25,8 @@ text files%
25 25
26\input{plugins/2048.tex} 26\input{plugins/2048.tex}
27 27
28\input{plugins/amaze.tex}
29
28\input{plugins/blackjack.tex} 30\input{plugins/blackjack.tex}
29 31
30\opt{large_plugin_buffer}{\input{plugins/boomshine.tex}} 32\opt{large_plugin_buffer}{\input{plugins/boomshine.tex}}