A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 1620 lines 42 kB view raw
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}