diff options
author | Franklin Wei <frankhwei536@gmail.com> | 2014-09-03 19:16:37 -0400 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2024-04-24 17:37:58 -0400 |
commit | 6efd7f8f3e4a9de578646c77c7527c54b3c8e557 (patch) | |
tree | 97bff19881dfc7db5b87801ccf74d07cc24d12cb | |
parent | 2dbf26f11aff960ddac01fb625d857e2d1e42263 (diff) | |
download | rockbox-6efd7f8f3e.tar.gz rockbox-6efd7f8f3e.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
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 @@ *: "Default Browser" </voice> </phrase> +<phrase> + id: LANG_AMAZE_MENU + desc: Amaze game + user: core + <source> + *: "Amaze Main Menu" + </source> + <dest> + *: "Amaze Main Menu" + </dest> + <voice> + *: "Amaze Main Menu" + </voice> +</phrase> +<phrase> + id: LANG_SET_MAZE_SIZE + desc: Maze size in Amaze game + user: core + <source> + *: "Set Maze Size" + </source> + <dest> + *: "Set Maze Size" + </dest> + <voice> + *: "Set Maze Size" + </voice> +</phrase> +<phrase> + id: LANG_VIEW_MAP + desc: Map in Amaze game + user: core + <source> + *: "View Map" + </source> + <dest> + *: "View Map" + </dest> + <voice> + *: "View Map" + </voice> +</phrase> +<phrase> + id: LANG_SHOW_COMPASS + desc: Compass in Amaze game + user: core + <source> + *: "Show Compass" + </source> + <dest> + *: "Show Compass" + </dest> + <voice> + *: "Show Compass" + </voice> +</phrase> +<phrase> + id: LANG_SHOW_MAP + desc: Map in Amaze game + user: core + <source> + *: "Show Map" + </source> + <dest> + *: "Show Map" + </dest> + <voice> + *: "Show Map" + </voice> +</phrase> +<phrase> + id: LANG_REMEMBER_PATH + desc: Map in Amaze game + user: core + <source> + *: "Remember Path" + </source> + <dest> + *: "Remember Path" + </dest> + <voice> + *: "Remember Path" + </voice> +</phrase> +<phrase> + id: LANG_USE_LARGE_TILES + desc: Map in Amaze game + user: core + <source> + *: "Use Large Tiles" + </source> + <dest> + *: "Use Large Tiles" + </dest> + <voice> + *: "Use Large Tiles" + </voice> +</phrase> +<phrase> + id: LANG_SHOW_SOLUTION + desc: Map in Amaze game + user: core + <source> + *: "Show Solution" + </source> + <dest> + *: "Show Solution" + </dest> + <voice> + *: "Show Solution" + </voice> +</phrase> +<phrase> + id: LANG_QUIT_WITHOUT_SAVING + desc: + user: core + <source> + *: "Quit without saving" + </source> + <dest> + *: "Quit without saving" + </dest> + <voice> + *: "Quit without saving" + </voice> +</phrase> +<phrase> + id: LANG_GENERATING_MAZE + desc: Amaze game + user: core + <source> + *: "Generating maze..." + </source> + <dest> + *: "Generating maze..." + </dest> + <voice> + *: "Generating maze..." + </voice> +</phrase> +<phrase> + id: LANG_YOU_WIN + desc: Success in game + user: core + <source> + *: "You win!" + </source> + <dest> + *: "You win!" + </dest> + <voice> + *: "You win!" + </voice> +</phrase> +<phrase> + id: LANG_YOU_CHEATED + desc: Cheated in game + user: core + <source> + *: "You cheated!" + </source> + <dest> + *: "You cheated!" + </dest> + <voice> + *: "You cheated!" + </voice> +</phrase> +<phrase> + id: LANG_DIFFICULTY_EASY + desc: Game difficulty + user: core + <source> + *: "Easy" + </source> + <dest> + *: "Easy" + </dest> + <voice> + *: "Easy" + </voice> +</phrase> +<phrase> + id: LANG_DIFFICULTY_MEDIUM + desc: Game difficulty + user: core + <source> + *: "Medium" + </source> + <dest> + *: "Medium" + </dest> + <voice> + *: "Medium" + </voice> +</phrase> +<phrase> + id: LANG_DIFFICULTY_HARD + desc: Game difficulty + user: core + <source> + *: "Hard" + </source> + <dest> + *: "Hard" + </dest> + <voice> + *: "Hard" + </voice> +</phrase> +<phrase> + id: LANG_DIFFICULTY_EXPERT + desc: Game difficulty + user: core + <source> + *: "Expert" + </source> + <dest> + *: "Expert" + </dest> + <voice> + *: "Expert" + </voice> +</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 @@ alpine_cdc,apps alarmclock,apps announce_status,demos +amaze,games autostart,apps battery_bench,apps bench_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 metronome.c 2048.c +amaze.c /* Lua needs at least 160 KB to work in */ #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 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2014 Franklin Wei, (c) 2018 Sebastian Leonhardt + * + * Original work (C) 2000 David Leonard, public domain according to + * http://www.adaptive-enterprises.com.au/~d/software/amaze/ + * + * Original Rockbox port by Jerry Chapman, 2007 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "plugin.h" +#include "lib/pluginlib_actions.h" + +const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; + +static const struct opt_items noyes_text[] = { + { STR(LANG_SET_BOOL_NO) }, + { STR(LANG_SET_BOOL_YES) } +}; + +static const struct opt_items mazesize_text[] = { + { STR(LANG_DIFFICULTY_EASY) }, + { STR(LANG_DIFFICULTY_MEDIUM) }, + { STR(LANG_DIFFICULTY_HARD) }, + { STR(LANG_DIFFICULTY_EXPERT) } +}; + +bool show_map; +bool remember_visited; +bool use_large_tiles; +int maze_size; + +#if LCD_DEPTH >= 16 +#define COLOR_GROUND LCD_RGBPACK(51,51,51) +#define COLOR_SKY LCD_RGBPACK(51,51,102) +#define COLOR_VISITED LCD_RGBPACK(102,77,51) +#define COLOR_MARK LCD_RGBPACK(255,100,61) +#define COLOR_GOAL LCD_RGBPACK(128,0,0) /* red */ +#define COLOR_COMPASS LCD_RGBPACK(255,255,0) /* yellow */ +#define COLOR_PARA LCD_RGBPACK(153,153,102) /* color side wall */ +/* #define COLOR_PERP LCD_RGBPACK(102,51,0) */ +#define COLOR_PERP LCD_RGBPACK(204,153,102) /* color wall perp */ +#elif LCD_DEPTH == 2 +#define COLOR_GROUND LCD_BLACK +#define COLOR_SKY LCD_WHITE +#define COLOR_VISITED LCD_DARKGRAY +#define COLOR_GOAL LCD_WHITE +#define COLOR_COMPASS LCD_BLACK +#define COLOR_MARK LCD_WHITE +#define COLOR_PARA LCD_DARKGRAY /* color side wall */ +#define COLOR_PERP LCD_LIGHTGRAY /* color wall perp */ +#else /* mono */ +#define COLOR_GROUND LCD_BLACK +#define COLOR_SKY LCD_BLACK +#define COLOR_VISITED LCD_BLACK +#define COLOR_GOAL LCD_BLACK +#define COLOR_COMPASS LCD_WHITE +#define COLOR_PARA LCD_BLACK /* color side wall */ +#define COLOR_PERP LCD_WHITE /* color wall perp */ +#endif + +#define A_DOWN 'v' +#define A_RIGHT '>' +#define A_UP '^' +#define A_LEFT '<' +#define SPACE ' ' /* Space you can walk through */ +#define BLOCK 'B' /* A block that you can't walk through */ +#define OBSPACE '#' /* Obscured space */ +#define VISITED '.' /* Visited space */ +#define GOAL '%' /* Exit from the maze */ +#define START '+' /* Starting point in the maze */ + +enum dir { DIR_DOWN=0, DIR_RIGHT=1, DIR_UP=2, DIR_LEFT=3 }; +#define _TOD(d) (enum dir)((d) % 4) +#define _TOI(d) (int)(d) +#define LEFT_OF(d) _TOD(_TOI(d) + 1) +#define REVERSE_OF(d) _TOD(_TOI(d) + 2) +#define RIGHT_OF(d) _TOD(_TOI(d) + 3) + +static struct { int y, x; } dirtab[4] = + { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } }; +static char ptab[4] = { A_DOWN, A_RIGHT, A_UP, A_LEFT }; + +int px, py; /* Player position */ +enum dir pdir; /* Player direction */ +char punder; /* character under player, if any */ +int sx, sy; /* Start position */ +int gx, gy; /* Goal position */ +int gdist; /* Distance from start to goal */ +int won = 0; /* Reached goal */ +int cheated = 0; /* Cheated somehow */ +bool compass = false; /* show compass */ +int button; /* Button data */ +bool loaded=false; /* Loaded? */ + +#define FIELD_SIZE 80 +#define MAP_CONST 20 + +static char map[FIELD_SIZE * FIELD_SIZE]; /* map storage */ +static char umap[FIELD_SIZE * FIELD_SIZE]; + +/* visible depth */ +#define MAX_DEPTH 20 +int depth; + +/* CX,CY = center of screen */ +#define CX LCD_WIDTH / 2 +#define CY LCD_HEIGHT / 2 + +int crd_x[MAX_DEPTH], crd_y[MAX_DEPTH]; /* screen vertices */ + +#if LCD_WIDTH >= 220 || LCD_HEIGHT >= 220 +#include "pluginbitmaps/amaze_tiles_9.h" +#define amaze_tiles_large amaze_tiles_9 +#define TILESIZE_LARGE BMPWIDTH_amaze_tiles_9 +#include "pluginbitmaps/amaze_tiles_7.h" +#define amaze_tiles_small amaze_tiles_7 +#define TILESIZE_SMALL BMPWIDTH_amaze_tiles_7 +#elif LCD_WIDTH >= 160 || LCD_HEIGHT >= 160 +#include "pluginbitmaps/amaze_tiles_7.h" +#define amaze_tiles_large amaze_tiles_7 +#define TILESIZE_LARGE BMPWIDTH_amaze_tiles_7 +#include "pluginbitmaps/amaze_tiles_5.h" +#define amaze_tiles_small amaze_tiles_5 +#define TILESIZE_SMALL BMPWIDTH_amaze_tiles_5 +#else +#include "pluginbitmaps/amaze_tiles_5.h" +#define amaze_tiles_large amaze_tiles_5 +#define TILESIZE_LARGE BMPWIDTH_amaze_tiles_5 +#include "pluginbitmaps/amaze_tiles_3.h" +#define amaze_tiles_small amaze_tiles_3 +#define TILESIZE_SMALL BMPWIDTH_amaze_tiles_3 +#endif + +/* save file names */ +#define UMAP_FILE PLUGIN_GAMES_DIR "/amaze_umap.sav" +#define MAP_FILE PLUGIN_GAMES_DIR "/amaze_map.sav" +#define PREF_FILE PLUGIN_GAMES_DIR "/amaze_prefs.sav" + +void clearscreen (void) +{ +#if LCD_DEPTH > 1 + rb->lcd_set_background(LCD_BLACK); + rb->lcd_set_foreground(LCD_WHITE); +#endif + rb->lcd_clear_display(); + rb->lcd_update(); +} + +void getmaxyx(int *y, int *x) +{ + *y = (maze_size + 1) * MAP_CONST; + *x = (maze_size + 1) * MAP_CONST; +} + +void map_write (char *pane, int y, int x, char c) +{ + int maxy, maxx; + + getmaxyx(&maxy, &maxx); + + if (x<0 || x>=maxx || y<0 || y>=maxy) return; + + pane[x * FIELD_SIZE + y] = c; + +} +char map_read (char *pane, int y, int x) +{ + int maxy, maxx; + + getmaxyx(&maxy, &maxx); + + if (x<0 || x>=maxx || y<0 || y>=maxy) { + return SPACE; + } + + return pane[x * FIELD_SIZE + y]; +} + +/* redefine ncurses werase */ +void werase (char *pane) +{ + int y, x; + int maxy, maxx; + + getmaxyx(&maxy, &maxx); + + for (y = 0; y < maxy; y++) + for (x = 0; x < maxx; x++) + map_write(pane, y, x, SPACE); +} + +/* start of David Leonard's code */ + +/* Look at position (y,x) in the maze map */ +char at(int y, int x) +{ + int maxy, maxx; + + getmaxyx(&maxy, &maxx); + + if (y == py && x == px) + return punder; + + if (y < 0 || y >= maxy || x < 0 || x >= maxx) + return SPACE; + else { + return map_read(map, y, x); + } +} + +void copyumap(int y, int x, int fullvis) +{ + char c; + + c = at(y, x); + if (!fullvis && c == SPACE && map_read(umap, y, x) != SPACE) + c = OBSPACE; + map_write(umap, y, x, c); +} + +struct path { + int y, x; + int ttl; /* Time until this path stops */ + int spawns; /* Max number of forks this path can do */ + int distance; /* Distance from start */ + struct path *next; +}; + +/* + * A better maze-digging algorithm. + * Simultaneously advance multiple digging paths through the map. + * This is done by having a work queue of advancing paths. + * Occasionally a path can fork; thus adding more to the work + * queue and diversifying the maze. + */ +void eatmaze(int starty, int startx) +{ + struct path { + int y, x; + int ttl; /* Time until this path stops */ + int spawns; /* Max number of forks this path can do */ + int distance; /* Distance from start */ + struct path *next; + }; + struct path *path_free, *path_head, *path_tail; + struct path *p, *s; + /* static -- per <hcs> in #rockbox -- was having stack issues */ + static struct path path_storage[2000]; + int try; + unsigned i; + int y, x, dy, dx; + int sdir; + + /* Set up the free list of path cells */ + for (i = 2; i < sizeof path_storage / sizeof path_storage[0]; i++) + path_storage[i].next = &path_storage[i-1]; + path_storage[1].next = NULL; + path_free = &path_storage[sizeof path_storage / sizeof path_storage[0] - 1]; + + /* Set up the initial path cell */ + path_storage[0].y = starty; + path_storage[0].x = startx; + map_write(map, starty, startx, SPACE); + + /* Set up the initial goal. It will move later. */ + gy = starty; + gx = startx; + gdist = 0; + + /* Initial properties of the root path */ + path_storage[0].ttl = 50; + path_storage[0].spawns = 20; + path_storage[0].distance = 0; + + /* Put the initial path into the queue */ + path_storage[0].next = NULL; + path_head = path_tail = &path_storage[0]; + + while (path_head != NULL) { + /* Dequeue */ + p = path_head; + path_head = p->next; + if (path_head == NULL) + path_tail = NULL; + + /* There's a large chance that some paths miss a turn */ + if (rb->rand() % 100 < 60) + goto requeue; + + /* First thing we do is advance the path. */ + y = p->y; + x = p->x; + + sdir = rb->rand() % 4; + for (try = 0; try < 4; try ++) { + dx = dirtab[(sdir + try) % 4].x; + dy = dirtab[(sdir + try) % 4].y; + + /* Going back on ourselves? */ + if (at(y + dy, x + dx) != BLOCK) + continue; + + /* Connecting to another path? */ + if (at(y + dy * 2, x + dx * 2) != BLOCK) + continue; + if (at(y + dy + dx, x + dx - dy) != BLOCK) + continue; + if (at(y + dy - dx, x + dx + dy) != BLOCK) + continue; + + break; + } + if (try == 4 || p->ttl <= 0) { + /* Failed: the path is placed on the free list. */ + p->next = path_free; + path_free = p; + continue; + } + + /* Dig the path a bit */ + p->y = y + dy; + p->x = x + dx; + map_write(map, p->y, p->x, SPACE); + p->ttl--; + p->distance++; + + if (p->distance > gdist) { + gx = p->x; + gy = p->y; + gdist = p->distance; + } + + /* Decide if we should spawn */ + if (/* rb->rand() % (p->ttl + 1) < p->spawns && */ path_free) { + /* Take a new path element off the free list */ + s = path_free; + path_free = s->next; + + /* Insert it at the tail of the queue */ + s->next = NULL; + if (path_tail) path_tail->next = s; + else path_head = s; + path_tail = s; + + /* Newly spawned path s will inherit most properties from p */ + s->y = p->y; + s->x = p->x; + s->ttl = p->ttl + rb->rand() % 10; + s->spawns = p->spawns; + s->distance = p->distance; + + /* p->spawns--; */ + } + + requeue: + /* Put p onto the tail of the queue */ + p->next = NULL; + if (path_tail) path_tail->next = p; + else path_head = p; + path_tail = p; + } +} + +/* Move the player to a new position/direction in the maze map */ +void mappmove(int newpy, int newpx, enum dir newpdir) +{ + map_write(map, py, px, punder); + copyumap(py, px, 1); + punder = at(newpy, newpx); + py = newpy; + px = newpx; + pdir = newpdir; + copyumap(py, px, 1); + map_write(umap, py, px, ptab[_TOI(pdir)]); + rb->lcd_update(); +} + +void clearmap (char *amap) +{ + int maxy, maxx; + int y, x; + + getmaxyx(&maxy, &maxx); + + + for (y = 0; y < maxy; y++) + for (x = 0; x < maxx; x++) + map_write(amap, y, x, BLOCK); +} + +/* Reveal the solution to the user */ +void showmap(void) +{ + int maxy, maxx, y, x; + char ch, och; + + getmaxyx(&maxy, &maxx); + for (y = 0; y < maxy; y++) + for (x = 0; x < maxx; x++) { + ch = at(y, x); + if (ch == SPACE) { + och = map_read(umap, y, x); + if (och == BLOCK || och == OBSPACE) + ch = OBSPACE; + } + map_write(umap, y, x, ch); + rb->yield(); + } + map_write(umap, py, px, ptab[_TOI(pdir)]); + rb->lcd_update(); +} + +/* + * Create a new maze map + * The algorithm here is quite inferior to that presented in the + * magazine. I could only remember the gist of it: recursively dig a + * trail that doesn't touch any other part of the maze, keeping track + * of all possible points where the path could fork. Later on try those + * possible branches; put limits on the segment lengths etc. + */ +void makemaze(void) +{ + int maxy, maxx; + int i; + + /* Get the window dimensions */ + getmaxyx(&maxy, &maxx); + + clearmap(map); + + py = rb->rand() % (maxy - 2) + 1; /* maxy/2 */ + px = rb->rand() % (maxx - 2) + 1; /* maxx/2 */ + + eatmaze(py, px); + + sx = px; /* starting position */ + sy = py; + + /* Face in an interesting direction: */ + pdir = DIR_UP; + for (i = 0; + i < 4 && at(py + dirtab[pdir].y, + px + dirtab[pdir].x) == BLOCK; + i++) + pdir = LEFT_OF(pdir); + + map_write(map, py, px, START); + map_write(map, gy, gx, GOAL); + punder = START; + mappmove(py, px, pdir); +} + +/* new drawing routines */ + +void draw_arrow(int dir, int sx, int sy, int pass) +{ + if (pass > 2) return; + + rb->lcd_fillrect(sx, sy, 1, 1); + switch(dir) { + case 0: /* down */ + rb->lcd_fillrect(sx + 2*pass, sy, 1, 1); + draw_arrow(dir, sx - 1, sy - 1, pass + 1); + break; + case 2: /* up */ + rb->lcd_fillrect(sx + 2*pass, sy, 1, 1); + draw_arrow(dir, sx - 1, sy + 1, pass + 1); + break; + case 1: /* left */ + rb->lcd_fillrect(sx, sy + 2*pass, 1, 1); + draw_arrow(dir, sx + 1, sy - 1, pass + 1); + break; + case 3: /* right */ + rb->lcd_fillrect(sx, sy + 2*pass, 1, 1); + draw_arrow(dir, sx - 1, sy - 1, pass +1); + break; + } +} + +/* Provide a compass pointing 'north' or draw arrow mark on the floor */ +void draw_pointer(int dir, bool is_compass) +{ + int offset; + + if(is_compass) + offset = -crd_y[1]*2/3; /* draw compass at the top */ + else + offset = crd_y[1]/2; /* draw mark on the floor */ + +#if LCD_DEPTH > 1 + if(is_compass) + rb->lcd_set_foreground(COLOR_COMPASS); + else + rb->lcd_set_foreground(COLOR_MARK); +#else + rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); +#endif + switch(dir) { + case 0: /* point down */ + draw_arrow(dir, CX - 1, CY + offset + 6, 0); + rb->lcd_fillrect(CX - 1, CY + offset + 1, 1, 3); + break; + case 2: /* point up */ + draw_arrow(dir, CX - 1, CY + offset, 0); + rb->lcd_fillrect(CX - 1, CY + offset + 3, 1, 3); + break; + case 1: /* point left */ + draw_arrow(dir, CX - 6, CY + offset + 6, 0); + rb->lcd_fillrect(CX - 3, CY + offset + 6, 3, 1); + break; + case 3: /* point right */ + draw_arrow(dir, CX + 1, CY + offset + 6, 0); + rb->lcd_fillrect(CX - 4, CY + offset + 6, 3, 1); + break; + } +#if LCD_DEPTH == 1 + rb->lcd_set_drawmode(DRMODE_SOLID); +#endif + rb->lcd_update(); +} + +void draw_end_wall(int bx, int by) +{ +#if LCD_DEPTH > 1 + rb->lcd_set_foreground(COLOR_PERP); + rb->lcd_fillrect(CX - bx/2, CY - by/2, bx + 1, by); +#else + rb->lcd_drawrect(CX - bx/2, CY - by/2, bx + 1, by); +#endif +} + +void draw_side(int fx, int bx, int by, int tan_n, int tan_d, bool isleft) +{ + int signx; + + if(isleft) + signx = -1; + else + signx = 1; + +#if LCD_DEPTH > 1 + for(int i = bx; i < fx + 1; i++) + { + /* add some stripes */ + if(i % 3 == 0) + rb->lcd_set_foreground(COLOR_PERP); + else + rb->lcd_set_foreground(COLOR_PARA); + rb->lcd_vline(CX + signx * i/2, + CY - tan_n * (i-bx)/2 / tan_d - by/2, + CY + tan_n * (i-bx)/2 / tan_d + by/2); + } +#else + rb->lcd_vline(CX + signx * bx/2, + CY - by/2, + CY + by/2); + rb->lcd_vline(CX + signx * (fx + 1)/2, + CY - tan_n * (fx - bx + 1)/2 / tan_d - by/2, + CY + tan_n * (fx - bx + 1)/2 / tan_d + by/2); + rb->lcd_drawline(CX + signx * bx/2, + CY - by/2, + CX + signx * (fx + 1)/2, + CY - tan_n * (fx - bx + 1)/2 / tan_d - by/2); + rb->lcd_drawline(CX + signx * bx/2, + CY + by/2, + CX + signx * (fx + 1)/2, + CY + tan_n * (fx - bx + 1)/2 / tan_d + by/2); +#endif +} + +void draw_hall(int fx, int bx, int by, bool isleft) +{ +#if LCD_DEPTH > 1 + rb->lcd_set_foreground(COLOR_PERP); + + if(isleft) + rb->lcd_fillrect(CX - fx/2, CY - by/2, (fx - bx)/2 + 1, by); + else + rb->lcd_fillrect(CX + bx/2, CY - by/2, (fx - bx)/2 + 1, by); +#else + if(isleft) + rb->lcd_drawrect(CX - fx/2, CY - by/2, (fx - bx)/2 + 1, by); + else + rb->lcd_drawrect(CX + bx/2, CY - by/2, (fx - bx)/2 + 1, by); +#endif +} + +void draw_side_tri(int fx, int fy, int bx, int tan_n, int tan_d, + bool isvisited, bool isgoal) +{ + int i; + int signx, signy; + + signy = 1; + + while(signy >= -1) + { +#if LCD_DEPTH > 1 + if(signy == 1) + if(isgoal) + rb->lcd_set_foreground(COLOR_GOAL); + else if(isvisited) + rb->lcd_set_foreground(COLOR_VISITED); + else + rb->lcd_set_foreground(COLOR_GROUND); + else + rb->lcd_set_foreground(COLOR_SKY); +#endif + + signx = 1; + + while(signx >= -1) + { + for(i = fx; i > bx; i--) { +#if LCD_DEPTH == 1 /* if unvisited floor draw pattern, otherwise solid */ + if (signy!=1 || isgoal || isvisited || (CX + signx * i/2) & 1) +#endif + rb->lcd_vline(CX + signx * i/2, + CY + signy * fy/2, + CY + signy * fy/2 + + signy * tan_n + * (i - fx)/2 / tan_d); + } + signx-=2; + } + signy-=2; + } +} + +void draw_hall_crnr(int fx, int fy, int bx, int by, + bool isleft, bool isvisited, bool isgoal) +{ +#if LCD_DEPTH > 1 + rb->lcd_set_foreground(COLOR_SKY); +#endif + if(isleft) + rb->lcd_fillrect(CX - fx/2, CY - fy/2, + (fx - bx)/2 + 1, (fy - by)/2); + else + rb->lcd_fillrect(CX + bx/2, CY - fy/2, + (fx - bx)/2 + 1, (fy - by)/2); + +#if LCD_DEPTH > 1 + if(isgoal) + rb->lcd_set_foreground(COLOR_GOAL); + else if(isvisited) + rb->lcd_set_foreground(COLOR_VISITED); + else + rb->lcd_set_foreground(COLOR_GROUND); + + if(isleft) + rb->lcd_fillrect(CX - fx/2, CY + by/2, + (fx - bx)/2 + 1, (fy - by)/2); + else + rb->lcd_fillrect(CX + bx/2, CY + by/2, + (fx - bx)/2 + 1, (fy - by)/2); +#else /* LCD_DEPTH == 1 */ + /* if unvisited floor draw pattern, otherwise solid */ + if(isleft) + for (int x = CX-fx/2; x <= CX-bx/2; x++) { + if (isgoal || isvisited || x & 1) + rb->lcd_vline(x, CY + by/2, CY + fy/2); + } + else + for (int x = CX+bx/2; x <= CX+fx/2; x++) { + if (isgoal || isvisited || x & 1) + rb->lcd_vline(x, CY + by/2, CY + fy/2); + } +#endif +} + +void draw_center_sq(int fy, int bx, int by, bool isvisited, bool isgoal, + bool isfront, int chr) +{ + chr = chr - '0'; /* get the integer value */ + +#if LCD_DEPTH > 1 + rb->lcd_set_foreground(COLOR_SKY); +#endif + rb->lcd_fillrect(CX - bx/2, CY - fy/2, bx, (fy - by)/2); + +#if LCD_DEPTH > 1 + if(isgoal) + rb->lcd_set_foreground(COLOR_GOAL); + else if(isvisited) + rb->lcd_set_foreground(COLOR_VISITED); + else + rb->lcd_set_foreground(COLOR_GROUND); + rb->lcd_fillrect(CX - bx/2, CY + by/2, bx, (fy - by)/2 + 1); +#else + /* if unvisited floor draw pattern, otherwise solid */ + for (int x = CX-bx/2; x <= CX+bx/2; x++) { + if (isgoal || isvisited || x & 1) + rb->lcd_vline(x, CY + by/2, CY + fy/2 + 1); + } +#endif + + if(isvisited && chr >= 0 && chr <= 3) + { +#if LCD_DEPTH > 1 + rb->lcd_set_foreground(COLOR_MARK); +#else + rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); +#endif + if(isfront) + { /* cell is marked in front, draw arrow */ + if (chr == ((int)(pdir) + 3) % 4) + draw_pointer(DIR_LEFT, false); + else if (chr == ((int)(pdir) + 1) % 4) + draw_pointer(DIR_RIGHT, false); + else if (chr == ((int)(pdir) + 2) % 4) + draw_pointer(DIR_DOWN, false); + else /* same direction */ + draw_pointer(DIR_UP, false); + } + else /* cell is marked but is in distance */ + rb->lcd_fillrect(CX, CY + (fy + by)/4, 2, 2); +#if LCD_DEPTH == 1 + rb->lcd_set_drawmode(DRMODE_SOLID); +#endif + } +} + +bool is_visited(char cell) +{ + if (cell - '0' >= 0 && cell - '0' <= 3) + return true; + else if (cell == VISITED) + return true; + else + return false; +} + +void graphic_view(void) +{ + int dist; + int x, y, dx, dy; + int a, l, r; /* is block? ahead/left/right */ + bool g, gl, gr; /* ground visted? under/left/right */ + bool e, el, er; /* is goal? under/left/right */ + int tan_n, tan_d; /* tangent numerator/denominator */ + + dx = dirtab[(int)pdir].x; + dy = dirtab[(int)pdir].y; + + for (dist = 1; dist < depth; dist++) + if (at(py + dy * dist, px + dx * dist) == BLOCK) + break; + + if (!show_map) + { + clearmap(umap); + copyumap(gy, gx, 1); + } + +#if LCD_DEPTH == 1 + clearscreen(); +#endif + + while (--dist >= 0) + { + x = px + dx * dist; + y = py + dy * dist; + + /* ground */ + g = is_visited(at(y, x)); + gl = is_visited(at(y - dx, x + dy)); + gr = is_visited(at(y + dx, x - dy)); + /* goal/end */ + e = at(y, x) == GOAL; + el = at(y - dx, x + dy) == GOAL; + er = at(y + dx, x - dy) == GOAL; + /* ahead */ + a = at(y + dy, x + dx) == BLOCK; + /* to the left */ + l = at(y - dx, x + dy) == BLOCK; + /* to the right */ + r = at(y + dx, x - dy) == BLOCK; + + tan_n = crd_y[dist] - crd_y[dist+1]; + tan_d = crd_x[dist] - crd_x[dist+1]; + + if (a) + draw_end_wall(crd_x[dist+1], crd_y[dist+1]); + if (l) + { + draw_side(crd_x[dist], crd_x[dist+1], + crd_y[dist+1], tan_n, tan_d, true); + } + else + { + draw_hall(crd_x[dist], crd_x[dist+1], + crd_y[dist+1], true); + draw_hall_crnr(crd_x[dist], crd_y[dist], crd_x[dist+1], + crd_y[dist+1], true, gl, el); + } + if (r) + { + draw_side(crd_x[dist], crd_x[dist+1], + crd_y[dist+1], tan_n, tan_d, false); + } + else + { + draw_hall(crd_x[dist], crd_x[dist+1], + crd_y[dist+1], false); + draw_hall_crnr(crd_x[dist], crd_y[dist], + crd_x[dist+1], crd_y[dist+1], false, gr, er); + } + + draw_center_sq(crd_y[dist], crd_x[dist+1], crd_y[dist+1], + g, e, dist==0, (int)(at(y, x))); + draw_side_tri(crd_x[dist], crd_y[dist], + crd_x[dist+1], tan_n, tan_d, g, e); + + copyumap(y + dy, x + dx, 0); /* ahead */ + copyumap(y, x, 1); /* here */ + copyumap(y - dx, x + dy, 0); /* left */ + copyumap(y + dx, x - dy, 0); /* right */ + if (!l) + copyumap(y - dx + dy, x + dy + dx, 0); /* lft ahead */ + if (!r) + copyumap(y + dx + dy, x - dy + dx, 0); /* rt ahead */ + } + if (compass) + draw_pointer(pdir, true); +} + +void win(void) +{ + /* + int i; + char amazed[8] = "amazing!"; + char newton; + + for (i=0; i <= 8; i++) + { + newton = amazed[i]; + map_write(msg, 0, i + 31, newton); + } + */ + won++; + showmap(); + show_map = 1; +} + + +/* Try to move the player in the direction given */ +void trymove(enum dir dir) +{ + int nx, ny; + + ny = py + dirtab[(int)dir].y; + nx = px + dirtab[(int)dir].x; + + if (at(ny, nx) == BLOCK) + { + graphic_view(); + return; + } + + if (at(ny, nx) == GOAL) + win(); + + mappmove(ny, nx, pdir); + if (remember_visited && punder == SPACE) + punder = VISITED; + graphic_view(); +} + +void walkleft(void) +{ + int a, l; + int dx, dy; + int owon = won; + + while (1) + { + int input = pluginlib_getaction(TIMEOUT_NOBLOCK, plugin_contexts, + ARRAYLEN(plugin_contexts)); + if(input==PLA_CANCEL || input==PLA_EXIT) + { + return; + } + rb->lcd_update(); + if (won != owon) + { + break; + } + + dx = dirtab[(int)pdir].x; + dy = dirtab[(int)pdir].y; + + /* ahead */ + a = at(py + dy, px + dx) == BLOCK; + /* to the left */ + l = at(py - dx, px + dy) == BLOCK; + + if (!l) + { + mappmove(py, px, LEFT_OF(pdir)); + graphic_view(); + rb->sleep(2); + trymove(pdir); + continue; + } + if (a) + { + mappmove(py, px, RIGHT_OF(pdir)); + graphic_view(); + continue; + } + trymove(pdir); + rb->yield(); + } +} + +void draw_tile(int index, int x, int y) +{ + if (use_large_tiles == 1) + rb->lcd_bitmap_part (amaze_tiles_large, 0, index * TILESIZE_LARGE, + TILESIZE_LARGE, x * TILESIZE_LARGE, y * TILESIZE_LARGE, + TILESIZE_LARGE, TILESIZE_LARGE); + else + rb->lcd_bitmap_part (amaze_tiles_small, 0, index * TILESIZE_SMALL, + TILESIZE_SMALL, x * TILESIZE_SMALL, y * TILESIZE_SMALL, + TILESIZE_SMALL, TILESIZE_SMALL); +} + +void draw_tile_map(int xmin, int xmax, int ymin, int ymax) +{ + int x,y; + char map_unit; + int tdex = 7; /* tile index */ + + enum tile_index + { t_down=0, t_right=1, t_up=2, t_left=3, t_visited=4, + t_obspace=5, t_goal=6, t_block=7, t_space=8, t_start=9 }; + + for(y = ymin; y <= ymax; y++) + for(x = xmin; x <= xmax; x++) + { + + map_unit = map_read(umap, y, x); + + switch (map_unit) + { + case VISITED: + case '0': case '1': case '2': case '3': + tdex = t_visited; + break; + case OBSPACE: + tdex = t_obspace; + break; + case START: + tdex = t_start; + break; + case GOAL: + tdex = t_goal; + break; + case SPACE: + tdex = t_space; + break; + case BLOCK: + tdex = t_block; + break; + } + draw_tile(tdex, x - xmin, y - ymin); + } + if(sx>=xmin && sx<=xmax && sy>=ymin && sy<=ymax) + { + x = sx; + y = sy; + draw_tile(t_start, x - xmin, y - ymin); + } + + if(px>=xmin && px<=xmax && py>=ymin && py<=ymax) + { + x = px; + y = py; + draw_tile(pdir, x - xmin, y - ymin); + } + + rb->lcd_update(); +} + +void check_map_bounds(int *xmin, int *xmax, int *ymin, int *ymax) +{ + int maxx, maxy; + + getmaxyx(&maxy, &maxx); + + /* bounds check x */ + if(*xmin < 0) + { + *xmax = *xmax - *xmin; + *xmin = 0; + } + if(*xmax >= maxx) + { + *xmin = *xmin - *xmax + maxx - 1; + *xmax = maxx - 1; + } + + /* bounds check y */ + if(*ymin < 0) + { + *ymax = *ymax - *ymin; + *ymin = 0; + } + if(*ymax >= maxy) + { + *ymin = *ymin - *ymax + maxy - 1; + *ymax = maxy - 1; + } +} + +void calc_map_size(int *xmin, int *xmax, int *ymin, int *ymax) +{ + int tile_size; /* runtime option */ + int vx, vy; /* maxx, maxy of view */ + int midx, midy; /* midpoint x, y of view */ + int maxx, maxy; /* maxx, maxy of map */ + + getmaxyx(&maxy, &maxx); + + if (use_large_tiles == 1) + tile_size = TILESIZE_LARGE; + else + tile_size = TILESIZE_SMALL; + + vx = LCD_WIDTH / tile_size; + if (vx > maxx) + vx = maxx; + vy = LCD_HEIGHT / tile_size; + if (vy > maxy) + vy = maxy; + + midx = vx / 2; + midy = vy / 2; + + *xmin = px - midx; + if(vx % 2 == 0) + *xmax = px + midx - 1; + else + *xmax = px + midx; + + *ymin = py - midy; + if(vy % 2 == 0) + *ymax = py + midy - 1; + else + *ymax = py + midy; + +} + + +void draw_portion_map(void) +{ + int xmin, xmax, ymin, ymax; /* coords of map corners */ + bool quit_map; + int input; + + clearscreen(); + + calc_map_size(&xmin, &xmax, &ymin, &ymax); + + quit_map = false; + + while (!quit_map) + { + check_map_bounds(&xmin, &xmax, &ymin, &ymax); + draw_tile_map(xmin, xmax, ymin, ymax); + + input = pluginlib_getaction(TIMEOUT_BLOCK, plugin_contexts, + ARRAYLEN(plugin_contexts)); + + switch(input) + { + case PLA_CANCEL: + case PLA_EXIT: + quit_map = true; + break; + case PLA_UP: + case PLA_UP_REPEAT: + ymin--; + ymax--; + break; + case PLA_DOWN: + case PLA_DOWN_REPEAT: + ymin++; + ymax++; + break; + case PLA_LEFT: + case PLA_LEFT_REPEAT: + xmin--; + xmax--; + break; + case PLA_RIGHT: + case PLA_RIGHT_REPEAT: + xmin++; + xmax++; + break; + default: + break; + } + } +} + +bool load_map(char *filename, char *amap) +{ + int fd; + int x,y; + int maxxy; + size_t n; + char newton = BLOCK; + char map_size[2]; + + /* load a map */ + fd = rb->open(filename, O_RDONLY); + if (fd < 0) + { + LOGF("Invalid map file: %s\n", filename); + return false; + } + + n = rb->read(fd, map_size, sizeof(map_size)); + if (n <= 0) + { + LOGF("Invalid map size."); + return false; + } + + maze_size = (int)map_size[0] - 48; + maxxy = MAP_CONST * (maze_size + 1); + char line[maxxy + 1]; + + for(y=0; y < maxxy ; y++) + { + n = rb->read(fd, line, sizeof(line)); + if (n <= 0) + { + return false; + } + for(x=0; x < maxxy+1; x++) + { + switch(line[x]) + { + case '\n': + break; + case '0': case '1': case '2': case '3': + newton = line[x]; + break; + case START: + sy = y; + sx = x; + newton = START; + break; + case SPACE: + case BLOCK: + case OBSPACE: + newton = line[x]; + break; + case GOAL: + newton = GOAL; + gy = y; + gx = x; + break; + case A_DOWN: case A_LEFT: case A_UP: case A_RIGHT: + py = y; + px = x; + switch(line[x]) + { + case A_DOWN: + pdir = DIR_DOWN; + break; + case A_LEFT: + pdir = DIR_LEFT; + break; + case A_UP: + pdir = DIR_UP; + break; + case A_RIGHT: + pdir = DIR_RIGHT; + break; + } + /* FALLTHROUGH */ + case VISITED: + newton = VISITED; + break; + } + if (line[x] != '\n') + map_write(amap, y, x, newton); + } + } + rb->close(fd); + rb->remove(filename); + return true; +} + +bool load_game(void) +{ + if (load_map(UMAP_FILE, umap) && load_map(MAP_FILE, map)) + return true; + else + return false; +} + + +bool save_map(char *filename, char *amap) +{ + int x,y; + int maxy, maxx; + char map_unit; + int fd; + int line_len = (maze_size + 1) * MAP_CONST + 1; + char line[line_len]; + char map_size[2] = + {'0','\n'}; + + line[line_len - 1] = '\n'; /* last cell is a linefeed */ + map_size[0] = (char)(maze_size + 48); + + if ((fd = rb->open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) + return false; + + rb->write(fd, map_size, 2); + + getmaxyx(&maxy, &maxx); + + for(y=0; y < maxy; y++) + { + for (x=0; x < maxx; x++) + { + map_unit = map_read(amap, y, x); + + if(y == py && x == px) + line[x] = ptab[_TOI(pdir)]; + else if(y == sy && x == sx) + line[x] = START; + else + line[x] = map_unit; + } + rb->write(fd, line, line_len); + } + rb->close(fd); + + return true; +} + +bool save_game(void) +{ + if (save_map(UMAP_FILE, umap) && save_map(MAP_FILE, map)) + return true; + else + return false; +} + + +bool ingame; +bool save_prefs(char *filename); + +static int menu_cb(int action, const struct menu_item_ex *this_item, + struct gui_synclist *this_list) +{ + (void)this_list; + + int idx=((intptr_t)this_item); + if (action==ACTION_REQUEST_MENUITEM) { + if (ingame) { + if (idx==2) + return ACTION_EXIT_MENUITEM; + } + else { /* !ingame */ + if (idx==3 || idx==8) + return ACTION_EXIT_MENUITEM; + if (!loaded && (idx==0 || idx==9)) + return ACTION_EXIT_MENUITEM; + } + } + return action; +} + +int menu(void) +{ + bool exit_menu = false; + int selection = 0, result = 0, status = 1; + + MENUITEM_STRINGLIST(menu, ID2P(LANG_AMAZE_MENU), menu_cb, + ID2P(LANG_CHESSBOX_MENU_RESUME_GAME), + ID2P(LANG_CHESSBOX_MENU_NEW_GAME), + ID2P(LANG_SET_MAZE_SIZE), + ID2P(LANG_VIEW_MAP), + ID2P(LANG_SHOW_COMPASS), + ID2P(LANG_SHOW_MAP), + ID2P(LANG_REMEMBER_PATH), + ID2P(LANG_USE_LARGE_TILES), + ID2P(LANG_SHOW_SOLUTION), + ID2P(LANG_QUIT_WITHOUT_SAVING), + ID2P(LANG_MENU_QUIT) + ); + + clearscreen(); + + while(!exit_menu) + { + result = rb->do_menu(&menu, &selection, NULL, false); + switch(result) + { + case 0: /* resume */ + exit_menu = true; + if (!ingame) { + save_prefs(PREF_FILE); + } + break; + case 1: /* new game */ + exit_menu = true; + if (ingame) + { + rb->splash(0, ID2P(LANG_GENERATING_MAZE)); + clearmap(umap); + makemaze(); + + /* Show where the goal is */ + copyumap(gy, gx, 1); + rb->lcd_update(); + + mappmove(py, px, pdir); + + if (remember_visited) + punder = VISITED; + else + punder = SPACE; + } + else { /* !ingame */ + loaded=false; + save_prefs(PREF_FILE); + } + break; + case 2: /* Set maze size */ + { + int old_size = maze_size; + rb->set_option(rb->str(LANG_SET_MAZE_SIZE), &maze_size, RB_INT, + mazesize_text, 4, NULL); + if (maze_size != old_size) + loaded = false; + } + break; + case 3: /* View map */ + exit_menu = true; + draw_portion_map(); + break; + case 4: /* Show compass option */ + rb->set_option(rb->str(LANG_SHOW_COMPASS), &compass, RB_BOOL, + noyes_text, 2, NULL); + break; + case 5: /* Show Map option */ + rb->set_option(rb->str(LANG_SHOW_MAP), &show_map, RB_BOOL, + noyes_text, 2, NULL); + break; + case 6: /* Remember Path option */ + rb->set_option(rb->str(LANG_REMEMBER_PATH), &remember_visited, RB_BOOL, + noyes_text, 2, NULL); + break; + case 7: /* Tilesize option */ + rb->set_option(rb->str(LANG_USE_LARGE_TILES), &use_large_tiles, RB_BOOL, + noyes_text, 2, NULL); + break; + case 8: /* solver */ + exit_menu = true; + cheated++; + walkleft(); + break; + case 9: /* quit w/o saving */ + exit_menu = true; + status = 0; + break; + case 10: /* save+quit */ + exit_menu = true; + if (ingame) { + if (save_game()) + status = 0; + else + rb->splash(HZ*3, ID2P(LANG_ERROR_WRITING_CONFIG)); + } + else { + if(loaded) + save_game(); + status = 0; + } + break; + } + } + return status; +} + +int amaze(void) +{ + int quitting; + int i; + int input; + + clearscreen(); + rb->lcd_setfont(FONT_SYSFIXED); + if(!loaded) + rb->splash(0, ID2P(LANG_GENERATING_MAZE)); + + crd_x[0] = LCD_WIDTH + 1; + crd_y[0] = LCD_HEIGHT + 1; + for (depth=1; depth < MAX_DEPTH + 1; depth++) + { + crd_x[depth] = crd_x[depth-1]*2/3; + if(crd_x[depth] % 2 != 0) crd_x[depth]++; + crd_y[depth] = crd_y[depth-1]*2/3; + if(crd_y[depth] % 2 != 0) crd_y[depth]++; + if (crd_x[depth]==crd_x[depth-1] || crd_y[depth]==crd_y[depth-1]) + break; + } + --depth; + + if (!loaded) + { + clearmap(umap); + makemaze(); + } + + /* Show where the goal is */ + + copyumap(gy, gx, 1); + + rb->lcd_update(); + + quitting = 0; + + mappmove(py, px, pdir); + + if (remember_visited) + punder = VISITED; + else + punder = SPACE; + + clearscreen(); + graphic_view(); + + while (!quitting && !won) + { + + rb->lcd_update(); + + input = pluginlib_getaction(TIMEOUT_BLOCK, plugin_contexts, + ARRAYLEN(plugin_contexts)); + + switch (input) + { + case PLA_CANCEL: + case PLA_EXIT: + i = menu(); + rb->lcd_setfont(FONT_SYSFIXED); + clearscreen(); + graphic_view(); + + switch (i) + { + case 0: + quitting = 1; + break; + case 1: + break; + case 2: + return 0; + break; + } + break; + case PLA_UP: + case PLA_UP_REPEAT: + trymove(pdir); + break; + case PLA_DOWN: + case PLA_DOWN_REPEAT: + trymove(REVERSE_OF(pdir)); + break; + case PLA_LEFT: + mappmove(py, px, LEFT_OF(pdir)); + graphic_view(); + break; + case PLA_RIGHT: + mappmove(py, px, RIGHT_OF(pdir)); + graphic_view(); + break; + case PLA_SELECT: + if (punder==SPACE || punder==VISITED) + { /* mark ground */ + punder = pdir + '0'; + } + else + { /* clear mark */ + if (remember_visited) + punder = VISITED; + else + punder = SPACE; + } + graphic_view(); + break; + } + } + + rb->lcd_update(); + //graphic_view(); + if (won) + { + won = false; /* reset boolean */ + if (cheated) + { + rb->splash(HZ*2, ID2P(LANG_YOU_CHEATED)); + return 0; + } + rb->splash(HZ*2, ID2P(LANG_YOU_WIN)); + return 1; + } + else + { + return 0; + } +} + +bool save_prefs(char *filename) +{ + int fd; + char ms[2] = { (char)(maze_size) + '0', '\n' }; + char sm[2] = { (char)(show_map) + '0', '\n' }; + char rv[2] = { (char)(remember_visited) + '0', '\n' }; + char lt[2] = { (char)(use_large_tiles) + '0', '\n' }; + + fd = rb->open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666); + if(fd >= 0) + { + rb->write(fd, ms, 2); + rb->write(fd, sm, 2); + rb->write(fd, rv, 2); + rb->write(fd, lt, 2); + } + else + { + rb->splash(HZ, ID2P(LANG_ERROR_WRITING_CONFIG)); + return false; + } + rb->close(fd); + return true; +} + +bool load_prefs(char *filename) +{ + int fd; + char instr[2]; + + fd = rb->open(filename, O_RDONLY); + if (fd < 0) + { + LOGF("Invalid preferences file: %s\n", filename); + return false; + } + + rb->read(fd, instr, sizeof(instr)); + maze_size = (int)(instr[0] - '0'); + rb->read(fd, instr, sizeof(instr)); + show_map = (bool)(instr[0] - '0'); + rb->read(fd, instr, sizeof(instr)); + remember_visited = (bool)(instr[0] - '0'); + rb->read(fd, instr, sizeof(instr)); + use_large_tiles = (bool)(instr[0] - '0'); + rb->close(fd); + + return true; +} + +enum plugin_status plugin_start(const void *parameter) +{ + (void) parameter; + int ret; + + rb->srand(*rb->current_tick); + + /* hard-code in program default options */ + show_map=1; + remember_visited=1; + use_large_tiles=1; + maze_size=1; + + loaded=load_game(); + + /* let's go, gentlemen, we have some work to do */ +#if LCD_DEPTH > 1 + rb->lcd_set_backdrop(NULL); +#endif + ingame = false; + ret = menu(); + if (ret) { + ingame = true; + amaze(); + } + + rb->lcd_setfont(FONT_UI); + + return PLUGIN_OK; +} 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 #endif #undef MIN +/* amaze */ +#if defined(HAVE_LCD_COLOR) +#if LCD_WIDTH >= 220 || LCD_HEIGHT >= 220 +amaze_tiles_9.9x9x16.bmp +amaze_tiles_7.7x7x16.bmp +#elif LCD_WIDTH >= 160 || LCD_HEIGHT >= 160 +amaze_tiles_7.7x7x16.bmp +amaze_tiles_5.5x5x16.bmp +#else +amaze_tiles_5.5x5x16.bmp +amaze_tiles_3.3x3x16.bmp +#endif + +#elif LCD_DEPTH > 1 +#if LCD_WIDTH >= 220 || LCD_HEIGHT >= 220 +amaze_tiles_9.9x9x2.bmp +amaze_tiles_7.7x7x2.bmp +#elif LCD_WIDTH >= 160 || LCD_HEIGHT >= 160 +amaze_tiles_7.7x7x2.bmp +amaze_tiles_5.5x5x2.bmp +#else +amaze_tiles_5.5x5x2.bmp +amaze_tiles_3.3x3x2.bmp +#endif + +#else /* mono */ +#if LCD_WIDTH >= 220 || LCD_HEIGHT >= 220 +amaze_tiles_9.9x9x1.bmp +amaze_tiles_7.7x7x1.bmp +#elif LCD_WIDTH >= 160 || LCD_HEIGHT >= 160 +amaze_tiles_7.7x7x1.bmp +amaze_tiles_5.5x5x1.bmp +#else +amaze_tiles_5.5x5x1.bmp +amaze_tiles_3.3x3x1.bmp +#endif +#endif /* amaze */ + /* Brickmania */ #ifdef HAVE_LCD_COLOR #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 Binary files differnew file mode 100644 index 0000000000..66418779de --- /dev/null +++ b/apps/plugins/bitmaps/native/amaze_tiles_3.3x3x1.bmp diff --git a/apps/plugins/bitmaps/native/amaze_tiles_3.3x3x16.bmp b/apps/plugins/bitmaps/native/amaze_tiles_3.3x3x16.bmp Binary files differnew file mode 100644 index 0000000000..930d4c62fc --- /dev/null +++ b/apps/plugins/bitmaps/native/amaze_tiles_3.3x3x16.bmp diff --git a/apps/plugins/bitmaps/native/amaze_tiles_3.3x3x2.bmp b/apps/plugins/bitmaps/native/amaze_tiles_3.3x3x2.bmp Binary files differnew file mode 100644 index 0000000000..504525b7f4 --- /dev/null +++ b/apps/plugins/bitmaps/native/amaze_tiles_3.3x3x2.bmp diff --git a/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x1.bmp b/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x1.bmp Binary files differnew file mode 100644 index 0000000000..d5973cfc5e --- /dev/null +++ b/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x1.bmp diff --git a/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x16.bmp b/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x16.bmp Binary files differnew file mode 100644 index 0000000000..7ec316df6a --- /dev/null +++ b/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x16.bmp diff --git a/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x2.bmp b/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x2.bmp Binary files differnew file mode 100644 index 0000000000..e06075310e --- /dev/null +++ b/apps/plugins/bitmaps/native/amaze_tiles_5.5x5x2.bmp diff --git a/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x1.bmp b/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x1.bmp Binary files differnew file mode 100644 index 0000000000..820f5a873b --- /dev/null +++ b/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x1.bmp diff --git a/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x16.bmp b/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x16.bmp Binary files differnew file mode 100644 index 0000000000..e9d6bc5086 --- /dev/null +++ b/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x16.bmp diff --git a/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x2.bmp b/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x2.bmp Binary files differnew file mode 100644 index 0000000000..2e8e76593b --- /dev/null +++ b/apps/plugins/bitmaps/native/amaze_tiles_7.7x7x2.bmp diff --git a/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x1.bmp b/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x1.bmp Binary files differnew file mode 100644 index 0000000000..0f2212e7e5 --- /dev/null +++ b/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x1.bmp diff --git a/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x16.bmp b/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x16.bmp Binary files differnew file mode 100644 index 0000000000..0188dd9726 --- /dev/null +++ b/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x16.bmp diff --git a/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x2.bmp b/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x2.bmp Binary files differnew file mode 100644 index 0000000000..f095368d30 --- /dev/null +++ b/apps/plugins/bitmaps/native/amaze_tiles_9.9x9x2.bmp diff --git a/docs/CREDITS b/docs/CREDITS index 4783033466..363c7b7dfb 100644 --- a/docs/CREDITS +++ b/docs/CREDITS @@ -717,6 +717,7 @@ Richard Goedeken Mihaly 'Hermit' Horvath Uwe Kleine-König JJ Style +Jerry Chapman The libmad team The 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 @@ +\subsection{Amaze} +\screenshot{plugins/images/ss-amaze}{Amaze}{img:amaze} +Amaze is a simple 3D maze game. + +Based upon the curses-based amaze by David Leonard, graciously placed +into 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 Binary files differnew file mode 100644 index 0000000000..71305d47d9 --- /dev/null +++ b/manual/plugins/images/ss-amaze-128x160x24.png diff --git a/manual/plugins/images/ss-amaze-128x64x1.png b/manual/plugins/images/ss-amaze-128x64x1.png Binary files differnew file mode 100644 index 0000000000..f0a9680fda --- /dev/null +++ b/manual/plugins/images/ss-amaze-128x64x1.png diff --git a/manual/plugins/images/ss-amaze-138x110x2.png b/manual/plugins/images/ss-amaze-138x110x2.png Binary files differnew file mode 100644 index 0000000000..6a2014ecae --- /dev/null +++ b/manual/plugins/images/ss-amaze-138x110x2.png diff --git a/manual/plugins/images/ss-amaze-176x132x16.png b/manual/plugins/images/ss-amaze-176x132x16.png Binary files differnew file mode 100644 index 0000000000..9d581393a6 --- /dev/null +++ b/manual/plugins/images/ss-amaze-176x132x16.png diff --git a/manual/plugins/images/ss-amaze-240x320x24.png b/manual/plugins/images/ss-amaze-240x320x24.png Binary files differnew file mode 100644 index 0000000000..2fce9b7865 --- /dev/null +++ b/manual/plugins/images/ss-amaze-240x320x24.png diff --git a/manual/plugins/images/ss-amaze-320x240x16.png b/manual/plugins/images/ss-amaze-320x240x16.png Binary files differnew file mode 100644 index 0000000000..77e9ca8bb8 --- /dev/null +++ b/manual/plugins/images/ss-amaze-320x240x16.png 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% \input{plugins/2048.tex} +\input{plugins/amaze.tex} + \input{plugins/blackjack.tex} \opt{large_plugin_buffer}{\input{plugins/boomshine.tex}} |