A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 1346 lines 37 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2006 Eli Sherer 11 * 2007 Antoine Cellerier 12 * 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License 15 * as published by the Free Software Foundation; either version 2 16 * of the License, or (at your option) any later version. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ****************************************************************************/ 22 23#include "plugin.h" 24#include "lib/helper.h" 25#include "lib/playback_control.h" 26#include "lib/highscore.h" 27 28 29 30#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) 31 32#define QUIT BUTTON_OFF 33#define LEFT BUTTON_LEFT 34#define RIGHT BUTTON_RIGHT 35#define PAUSE BUTTON_MODE 36#define UP BUTTON_UP 37#define DOWN BUTTON_DOWN 38 39#define RC_QUIT BUTTON_RC_STOP 40 41#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ 42 (CONFIG_KEYPAD == IPOD_3G_PAD) || \ 43 (CONFIG_KEYPAD == IPOD_1G2G_PAD) 44 45#define QUIT (BUTTON_SELECT | BUTTON_REPEAT) 46#define LEFT BUTTON_LEFT 47#define RIGHT BUTTON_RIGHT 48#define PAUSE (BUTTON_SELECT | BUTTON_REL) 49#define MENU_UP BUTTON_SCROLL_FWD 50#define MENU_DOWN BUTTON_SCROLL_BACK 51#define UP BUTTON_MENU 52#define DOWN BUTTON_PLAY 53 54#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD 55 56#define QUIT BUTTON_POWER 57#define LEFT BUTTON_LEFT 58#define RIGHT BUTTON_RIGHT 59#define UP BUTTON_UP 60#define DOWN BUTTON_DOWN 61#define PAUSE BUTTON_PLAY 62 63#elif (CONFIG_KEYPAD == GIGABEAT_PAD) 64 65#define QUIT BUTTON_POWER 66#define LEFT BUTTON_LEFT 67#define RIGHT BUTTON_RIGHT 68#define UP BUTTON_UP 69#define DOWN BUTTON_DOWN 70#define PAUSE BUTTON_A 71 72#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \ 73(CONFIG_KEYPAD == SANSA_C200_PAD) 74 75#define QUIT BUTTON_POWER 76#define LEFT BUTTON_LEFT 77#define RIGHT BUTTON_RIGHT 78#define UP BUTTON_UP 79#define DOWN BUTTON_DOWN 80#define PAUSE BUTTON_REC 81 82#elif (CONFIG_KEYPAD == SANSA_CLIP_PAD) 83 84#define QUIT BUTTON_POWER 85#define LEFT BUTTON_LEFT 86#define RIGHT BUTTON_RIGHT 87#define UP BUTTON_UP 88#define DOWN BUTTON_DOWN 89#define PAUSE BUTTON_HOME 90 91#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD) 92 93#define QUIT (BUTTON_HOME|BUTTON_REPEAT) 94#define LEFT BUTTON_LEFT 95#define RIGHT BUTTON_RIGHT 96#define UP BUTTON_UP 97#define DOWN BUTTON_DOWN 98#define PAUSE BUTTON_SELECT 99 100#elif (CONFIG_KEYPAD == SANSA_M200_PAD) 101 102#define QUIT BUTTON_POWER 103#define LEFT BUTTON_LEFT 104#define RIGHT BUTTON_RIGHT 105#define UP BUTTON_UP 106#define DOWN BUTTON_DOWN 107#define PAUSE BUTTON_SELECT 108 109#elif CONFIG_KEYPAD == IRIVER_H10_PAD 110 111#define QUIT BUTTON_POWER 112#define LEFT BUTTON_LEFT 113#define RIGHT BUTTON_RIGHT 114#define UP BUTTON_SCROLL_UP 115#define DOWN BUTTON_SCROLL_DOWN 116#define PAUSE BUTTON_PLAY 117 118#elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) 119 120#define QUIT BUTTON_BACK 121#define LEFT BUTTON_LEFT 122#define RIGHT BUTTON_RIGHT 123#define UP BUTTON_UP 124#define DOWN BUTTON_DOWN 125#define PAUSE BUTTON_PLAY 126 127#elif (CONFIG_KEYPAD == MROBE100_PAD) 128 129#define QUIT BUTTON_POWER 130#define LEFT BUTTON_LEFT 131#define RIGHT BUTTON_RIGHT 132#define UP BUTTON_UP 133#define DOWN BUTTON_DOWN 134#define PAUSE BUTTON_DISPLAY 135 136#elif CONFIG_KEYPAD == IAUDIO_M3_PAD 137 138#define QUIT BUTTON_RC_REC 139#define LEFT BUTTON_RC_REW 140#define RIGHT BUTTON_RC_FF 141#define UP BUTTON_RC_VOL_UP 142#define DOWN BUTTON_RC_VOL_DOWN 143#define PAUSE BUTTON_RC_PLAY 144 145#elif CONFIG_KEYPAD == COWON_D2_PAD 146 147#define QUIT BUTTON_POWER 148 149#elif CONFIG_KEYPAD == CREATIVEZVM_PAD 150 151#define QUIT BUTTON_BACK 152#define LEFT BUTTON_LEFT 153#define RIGHT BUTTON_RIGHT 154#define UP BUTTON_UP 155#define DOWN BUTTON_DOWN 156#define PAUSE BUTTON_PLAY 157 158#elif CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD 159#define QUIT BUTTON_POWER 160#define LEFT BUTTON_BACK 161#define RIGHT BUTTON_MENU 162#define UP BUTTON_UP 163#define DOWN BUTTON_DOWN 164#define PAUSE BUTTON_PLAY 165 166#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD 167 168#define QUIT BUTTON_POWER 169#define LEFT BUTTON_LEFT 170#define RIGHT BUTTON_RIGHT 171#define UP BUTTON_UP 172#define DOWN BUTTON_DOWN 173#define PAUSE BUTTON_VIEW 174 175#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD 176 177#define QUIT BUTTON_POWER 178#define LEFT BUTTON_PREV 179#define RIGHT BUTTON_NEXT 180#define UP BUTTON_UP 181#define DOWN BUTTON_DOWN 182#define PAUSE BUTTON_MENU 183 184#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD 185 186#define QUIT BUTTON_POWER 187#define LEFT BUTTON_PREV 188#define RIGHT BUTTON_NEXT 189#define UP BUTTON_UP 190#define DOWN BUTTON_DOWN 191#define PAUSE BUTTON_MENU 192 193#elif CONFIG_KEYPAD == ONDAVX747_PAD || \ 194CONFIG_KEYPAD == ONDAVX777_PAD || \ 195CONFIG_KEYPAD == MROBE500_PAD 196 197#define QUIT BUTTON_POWER 198 199#elif CONFIG_KEYPAD == SAMSUNG_YH820_PAD || \ 200 CONFIG_KEYPAD == SAMSUNG_YH92X_PAD 201 202#define QUIT BUTTON_REW 203#define LEFT BUTTON_LEFT 204#define RIGHT BUTTON_RIGHT 205#define UP BUTTON_UP 206#define DOWN BUTTON_DOWN 207#define PAUSE BUTTON_PLAY 208 209#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD 210 211#define QUIT BUTTON_REC 212#define LEFT BUTTON_PREV 213#define RIGHT BUTTON_NEXT 214#define UP BUTTON_UP 215#define DOWN BUTTON_DOWN 216#define PAUSE BUTTON_PLAY 217 218#elif CONFIG_KEYPAD == MPIO_HD200_PAD 219 220#define QUIT (BUTTON_REC|BUTTON_PLAY) 221#define LEFT BUTTON_VOL_DOWN 222#define RIGHT BUTTON_VOL_UP 223#define UP BUTTON_REW 224#define DOWN BUTTON_FF 225#define PAUSE BUTTON_PLAY 226 227#elif CONFIG_KEYPAD == MPIO_HD300_PAD 228 229#define QUIT (BUTTON_MENU | BUTTON_REPEAT) 230#define LEFT BUTTON_REW 231#define RIGHT BUTTON_FF 232#define UP BUTTON_UP 233#define DOWN BUTTON_DOWN 234#define PAUSE BUTTON_PLAY 235 236#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD 237 238#define QUIT BUTTON_POWER 239#define LEFT BUTTON_LEFT 240#define RIGHT BUTTON_RIGHT 241#define UP BUTTON_UP 242#define DOWN BUTTON_DOWN 243#define PAUSE BUTTON_PLAYPAUSE 244 245#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD 246 247#define QUIT BUTTON_POWER 248#define LEFT BUTTON_LEFT 249#define RIGHT BUTTON_RIGHT 250#define UP BUTTON_UP 251#define DOWN BUTTON_DOWN 252#define PAUSE BUTTON_SELECT 253 254#elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD) 255 256#define QUIT BUTTON_BACK 257#define LEFT BUTTON_LEFT 258#define RIGHT BUTTON_RIGHT 259#define UP BUTTON_UP 260#define DOWN BUTTON_DOWN 261#define PAUSE BUTTON_SELECT 262 263#elif (CONFIG_KEYPAD == HM60X_PAD) || \ 264 (CONFIG_KEYPAD == HM801_PAD) 265 266#define QUIT BUTTON_POWER 267#define LEFT BUTTON_LEFT 268#define RIGHT BUTTON_RIGHT 269#define UP BUTTON_UP 270#define DOWN BUTTON_DOWN 271#define PAUSE BUTTON_SELECT 272 273#elif CONFIG_KEYPAD == SONY_NWZ_PAD 274#define QUIT BUTTON_BACK 275#define LEFT BUTTON_LEFT 276#define RIGHT BUTTON_RIGHT 277#define UP BUTTON_UP 278#define DOWN BUTTON_DOWN 279#define PAUSE BUTTON_PLAY 280 281#elif CONFIG_KEYPAD == CREATIVE_ZEN_PAD 282#define QUIT BUTTON_BACK 283#define LEFT BUTTON_LEFT 284#define RIGHT BUTTON_RIGHT 285#define UP BUTTON_UP 286#define DOWN BUTTON_DOWN 287#define PAUSE BUTTON_PLAYPAUSE 288 289#elif CONFIG_KEYPAD == DX50_PAD 290#define QUIT BUTTON_POWER 291#define LEFT BUTTON_LEFT 292#define RIGHT BUTTON_RIGHT 293#define UP BUTTON_VOL_UP 294#define DOWN BUTTON_VOL_DOWN 295#define PAUSE BUTTON_PLAY 296 297#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD 298#define QUIT BUTTON_POWER 299#define PAUSE BUTTON_MENU 300 301#elif CONFIG_KEYPAD == AGPTEK_ROCKER_PAD 302#define QUIT BUTTON_POWER 303#define LEFT BUTTON_LEFT 304#define RIGHT BUTTON_RIGHT 305#define UP BUTTON_UP 306#define DOWN BUTTON_DOWN 307#define PAUSE BUTTON_SELECT 308 309#elif CONFIG_KEYPAD == XDUOO_X3_PAD || CONFIG_KEYPAD == XDUOO_X3II_PAD || CONFIG_KEYPAD == XDUOO_X20_PAD 310 311#define QUIT BUTTON_POWER 312#define LEFT BUTTON_PREV 313#define RIGHT BUTTON_NEXT 314#define UP BUTTON_HOME 315#define DOWN BUTTON_OPTION 316#define PAUSE BUTTON_PLAY 317 318#elif CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD 319 320#define QUIT BUTTON_POWER 321#define LEFT BUTTON_PREV 322#define RIGHT BUTTON_NEXT 323#define UP BUTTON_HOME 324#define DOWN BUTTON_OPTION 325#define PAUSE BUTTON_PLAY 326 327#elif CONFIG_KEYPAD == IHIFI_770_PAD || CONFIG_KEYPAD == IHIFI_800_PAD 328 329#define QUIT BUTTON_POWER 330#define LEFT BUTTON_HOME 331#define RIGHT BUTTON_VOL_DOWN 332#define UP BUTTON_PREV 333#define DOWN BUTTON_NEXT 334#define PAUSE BUTTON_PLAY 335 336#elif CONFIG_KEYPAD == EROSQ_PAD 337 338#define QUIT BUTTON_POWER 339#define LEFT BUTTON_SCROLL_BACK 340#define RIGHT BUTTON_SCROLL_FWD 341#define UP BUTTON_PREV 342#define DOWN BUTTON_NEXT 343#define PAUSE BUTTON_PLAY 344 345#elif CONFIG_KEYPAD == FIIO_M3K_PAD 346 347#define QUIT BUTTON_POWER 348#define LEFT BUTTON_LEFT 349#define RIGHT BUTTON_RIGHT 350#define UP BUTTON_UP 351#define DOWN BUTTON_DOWN 352#define PAUSE BUTTON_PLAY 353 354#elif CONFIG_KEYPAD == SDL_PAD 355#define QUIT BUTTON_TOPLEFT 356#define LEFT BUTTON_MIDLEFT 357#define RIGHT BUTTON_MIDRIGHT 358#define UP BUTTON_TOPMIDDLE 359#define DOWN BUTTON_BOTTOMMIDDLE 360#define PAUSE BUTTON_CENTER 361#elif CONFIG_KEYPAD == MA_PAD 362 363#define QUIT BUTTON_BACK 364#define LEFT BUTTON_LEFT 365#define RIGHT BUTTON_RIGHT 366#define UP BUTTON_UP 367#define DOWN BUTTON_DOWN 368#define PAUSE BUTTON_PLAY 369 370#elif CONFIG_KEYPAD == SHANLING_Q1_PAD 371/* use touchscreen */ 372 373#elif CONFIG_KEYPAD == RG_NANO_PAD 374 375#define QUIT BUTTON_START 376#define LEFT BUTTON_LEFT 377#define RIGHT BUTTON_RIGHT 378#define UP BUTTON_UP 379#define DOWN BUTTON_DOWN 380#define PAUSE BUTTON_A 381 382#else 383#error "No keymap defined!" 384#endif 385 386#if defined(HAVE_TOUCHSCREEN) 387#ifndef QUIT 388#define QUIT BUTTON_TOPLEFT 389#endif 390#ifndef LEFT 391#define LEFT BUTTON_MIDLEFT 392#endif 393#ifndef RIGHT 394#define RIGHT BUTTON_MIDRIGHT 395#endif 396#ifndef UP 397#define UP BUTTON_TOPMIDDLE 398#endif 399#ifndef DOWN 400#define DOWN BUTTON_BOTTOMMIDDLE 401#endif 402#ifndef PAUSE 403#define PAUSE BUTTON_CENTER 404#endif 405#endif 406 407#define MOVE_NO 0 /* player movement */ 408#define MOVE_UP 1 /* 1 */ 409#define MOVE_DN 2 /* 3 0 4 */ 410#define MOVE_LT 3 /* 2 */ 411#define MOVE_RT 4 412 413/* ball movement (12 ways) */ 414/* UUL UR */ 415/* UL UR */ 416/* ULL . URR */ 417/* DLL DRR */ 418/* DL DR */ 419/* DDL DDR */ 420 421#define DIR_UU (1<<7) 422#define DIR_U (1<<6) 423#define DIR_RR (1<<5) 424#define DIR_R (1<<4) 425#define DIR_DD (1<<3) 426#define DIR_D (1<<2) 427#define DIR_LL (1<<1) 428#define DIR_L (1<<0) 429 430#define MOVE_UUR ( DIR_UU | DIR_R ) 431#define MOVE_UR ( DIR_U | DIR_R ) 432#define MOVE_URR ( DIR_U | DIR_RR ) 433#define MOVE_DRR ( DIR_D | DIR_RR ) 434#define MOVE_DR ( DIR_D | DIR_R ) 435#define MOVE_DDR ( DIR_DD | DIR_R ) 436#define MOVE_DDL ( DIR_DD | DIR_L ) 437#define MOVE_DL ( DIR_D | DIR_L ) 438#define MOVE_DLL ( DIR_D | DIR_LL ) 439#define MOVE_ULL ( DIR_U | DIR_LL ) 440#define MOVE_UL ( DIR_U | DIR_L ) 441#define MOVE_UUL ( DIR_UU | DIR_L ) 442 443#if (LCD_WIDTH>112) && (LCD_HEIGHT>64) 444# define CUBE_SIZE 8 /* 8x22=176 */ 445# define pos(a) ((a)>>3) 446#else 447# define CUBE_SIZE 4 448# define pos(a) ((a)>>2) 449#endif 450 451#define STARTING_QIXES 2 452#define MAX_LEVEL 10 453#define MAX_QIXES MAX_LEVEL+STARTING_QIXES 454#define BOARD_W ((int)(LCD_WIDTH/CUBE_SIZE)) 455#define BOARD_H ((int)(LCD_HEIGHT/CUBE_SIZE)) 456#define BOARD_X (LCD_WIDTH-BOARD_W*CUBE_SIZE)/2 457#define BOARD_Y (LCD_HEIGHT-BOARD_H*CUBE_SIZE)/2 458 459#ifdef HAVE_LCD_COLOR 460#define CLR_RED LCD_RGBPACK(255,0,0) /* used to imply danger */ 461#define CLR_LTBLUE LCD_RGBPACK(125, 145, 180) /* used for frame and filling */ 462#define PLR_COL LCD_WHITE /* color used for the player */ 463#elif LCD_DEPTH>=2 464#define CLR_RED LCD_DARKGRAY /* used to imply danger */ 465#define CLR_LTBLUE LCD_LIGHTGRAY /* used for frame and filling */ 466#define PLR_COL LCD_BLACK /* color used for the player */ 467#endif 468 469#if LCD_DEPTH>=2 470#define EMPTIED LCD_BLACK /* empty spot */ 471#define FILLED CLR_LTBLUE /* filled spot */ 472#define TRAIL CLR_RED /* the red trail of the player */ 473#define QIX LCD_WHITE 474#else 475#define EMPTIED 0 476#define FILLED 1 477#define TRAIL 2 478#define QIX 3 479#endif 480#define UNCHECKED 0 481#define CHECKED 1 482#define PAINTED -1 483#define PIC_QIX 0 484#define PIC_PLAYER 1 485 486/* The time (in ms) for one iteration through the game loop - decrease this 487 to speed up the game - note that current_tick is (currently) only accurate 488 to 10ms. 489*/ 490static int speed = 6; /* CYCLETIME = (11-speed)*10 ms */ 491static int difficulty = 75; /* Percentage of screen that needs to be filled 492 * in order to win the game */ 493 494static bool quit = false; 495static bool _ingame = false; 496 497#define RESUME_FILE PLUGIN_GAMES_DATA_DIR "/xobox.resume" 498#define SCORE_FILE PLUGIN_GAMES_DATA_DIR "/xobox.score" 499#define NUM_SCORES 5 500static struct highscore highscores[NUM_SCORES]; 501 502static unsigned int board[BOARD_H][BOARD_W]; 503static int testboard[BOARD_H][BOARD_W]; 504 505#if CUBE_SIZE == 8 506/* 507 00011000 0x18 - 11100111 0xe7 508 00111100 0x3c - 11100111 0xe7 509 01111110 0x7e - 11000011 0xc3 510 11111111 0xff - 00000000 0x00 511 11111111 0xff - 00000000 0x00 512 01111110 0x7e - 11000011 0xc3 513 00111100 0x3c - 11100111 0xe7 514 00011000 0x18 - 11100111 0xe7 515 */ 516const unsigned char pics[2][8] = { 517 {0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x3c, 0x18}, /* Alien (QIX) */ 518 {0xe7, 0xe7, 0xc3, 0x00, 0x00, 0xc3, 0xe7, 0xe7} /* Player (XONIX) */ 519}; 520#elif CUBE_SIZE == 4 521/* 522 0110 0x6 - 1001 0x9 523 1111 0xf - 0110 0x6 524 1111 0xf - 0110 0x6 525 0110 0x6 - 1001 0x9 526 */ 527const unsigned char pics[2][4] = { 528 {0x6, 0xf, 0xf, 0x6}, /* Alien (QIX) */ 529 {0x9, 0x6, 0x6, 0x9} /* Player (XONIX) */ 530}; 531#else 532#error Incorrect CUBE_SIZE value. 533#endif 534 535static struct qix 536{ 537 int velocity; /* velocity */ 538 int x, y; /* position on screen */ 539 int angle; /* angle */ 540} qixes[MAX_QIXES]; /* black_qix */ 541 542static struct splayer 543{ 544 int i, j; /* position on board */ 545 int move, score, level, lives; 546 bool drawing; 547 bool gameover; 548} player; 549 550static int percentage_cache; 551 552/*************************** STACK STUFF **********************/ 553 554/* the stack */ 555#define STACK_SIZE (2*BOARD_W*BOARD_H) 556static struct pos 557{ 558 int x, y; /* position on board */ 559} stack[STACK_SIZE]; 560static int stackPointer; 561 562static inline bool pop (struct pos *p) 563{ 564 if (stackPointer > 0) { 565 p->x = stack[stackPointer].x; 566 p->y = stack[stackPointer].y; 567 stackPointer--; 568 return true; 569 } else 570 return false; /* SE */ 571} 572 573static inline bool push (struct pos *p) 574{ 575 if (stackPointer < STACK_SIZE - 1) { 576 stackPointer++; 577 stack[stackPointer].x = p->x; 578 stack[stackPointer].y = p->y; 579 return true; 580 } else 581 return false; /* SOF */ 582} 583 584static inline void emptyStack (void) 585{ 586 stackPointer = 0; 587} 588 589/*********************** END OF STACK STUFF *********************/ 590 591/* calculate the new x coordinate of the ball according to angle and speed */ 592static inline int get_newx (int x, int len, int deg) 593{ 594 if (deg & DIR_R) 595 return x + len; 596 else if (deg & DIR_L) 597 return x - len; 598 else if (deg & DIR_RR) 599 return x + len * 2; 600 else /* (def & DIR_LL) */ 601 return x - len * 2; 602} 603 604/* calculate the new y coordinate of the ball according to angle and speed */ 605static inline int get_newy (int y, int len, int deg) 606{ 607 if (deg & DIR_D) 608 return y + len; 609 else if (deg & DIR_U) 610 return y - len; 611 else if (deg & DIR_DD) 612 return y + len * 2; 613 else /* (deg & DIR_UU) */ 614 return y - len * 2; 615} 616 617/* make random function get it's value from the device ticker */ 618static inline void randomize (void) 619{ 620 rb->srand (*rb->current_tick); 621} 622 623/* get a random number between 0 and range-1 */ 624static int t_rand (int range) 625{ 626 return rb->rand () % range; 627} 628 629/* initializes the test help board */ 630static void init_testboard (void) 631{ 632 int j; /* testboard */ 633 for (j = 0; j < BOARD_H; j++) 634 /* UNCHEKED == (int)0 */ 635 rb->memset( testboard[j], 0, BOARD_W * sizeof( int ) ); 636} 637 638/* initializes the game board on with the player,qix's and black qix */ 639static void init_board (void) 640{ 641 int i, j; 642 for (j = 0; j < BOARD_H; j++) 643 for (i = 0; i < BOARD_W; i++) { /* make a nice cyan frame */ 644 if ((i == 0) || (j <= 1) || (i == BOARD_W - 1) 645 || (j >= BOARD_H - 2)) 646 board[j][i] = FILLED; 647 else 648 board[j][i] = EMPTIED; 649 } 650 651 /* (level+2) is the number of qixes */ 652 for (j = 0; j < player.level + STARTING_QIXES; j++) { 653 qixes[j].velocity = t_rand (2) + 1; /* 1 or 2 pix-per-sec */ 654 655 /* not on frame */ 656 qixes[j].x = CUBE_SIZE*2 + 2*t_rand (((BOARD_W-4)*CUBE_SIZE)/2); 657 qixes[j].y = CUBE_SIZE*2 + 2*t_rand (((BOARD_H-4)*CUBE_SIZE)/2); 658 659 const int angle_table[] = { 660 MOVE_UUR, MOVE_UR, MOVE_URR, MOVE_DRR, MOVE_DR, MOVE_DDR, 661 MOVE_UUL, MOVE_UL, MOVE_ULL, MOVE_DLL, MOVE_DL, MOVE_DDL }; 662 qixes[j].angle = angle_table[t_rand (12)]; 663#if CUBE_SIZE == 4 664 /* Work arround a nasty bug. FIXME */ 665 if( qixes[j].angle & (DIR_LL|DIR_RR|DIR_UU|DIR_DD) ) 666 qixes[j].velocity = 1; 667#endif 668 } 669 /*black_qix.velocity=1; 670 black_qix.x=BOARD_X+(BOARD_W*CUBE_SIZE)/2-CUBE_SIZE/2; 671 black_qix.y=BOARD_Y+(BOARD_H*CUBE_SIZE)-CUBE_SIZE-CUBE_SIZE/2; 672 black_qix.angle=MOVE_UR; */ 673 player.move = MOVE_NO; 674 player.drawing = false; 675 player.i = BOARD_W / 2; 676 player.j = 1; 677 678 percentage_cache = 0; 679} 680 681/* calculates the percentage of the screen filling */ 682static int percentage (void) 683{ 684 int i, j, filled = 0; 685 for (j = 2; j < BOARD_H - 2; j++) 686 for (i = 1; i < BOARD_W - 1; i++) 687 if (board[j][i] == FILLED) 688 filled++; 689 return (filled * 100) / ((BOARD_W - 2) * (BOARD_H - 4)); 690} 691 692/* draw the board on with all the game figures */ 693static void refresh_board (void) 694{ 695 int i, j; 696 int x; 697 698#if LCD_DEPTH>=2 699 rb->lcd_set_background (LCD_BLACK); 700#endif 701 rb->lcd_clear_display (); 702 for (j = 0; j < BOARD_H; j++) 703 { 704 unsigned last_color = board[j][0]; 705 int last_i = 0; 706 for (i = 1; i < BOARD_W; i++) { 707 if( last_color != board[j][i] ) 708 { 709#if LCD_DEPTH>=2 710 rb->lcd_set_foreground (last_color); 711#else 712 if (last_color != EMPTIED) 713#endif 714 rb->lcd_fillrect (BOARD_X + CUBE_SIZE * (last_i), 715 BOARD_Y + CUBE_SIZE * j, 716 CUBE_SIZE * (i - last_i), CUBE_SIZE ); 717 last_color = board[j][i]; 718 last_i = i; 719 } 720 } 721#if LCD_DEPTH>=2 722 rb->lcd_set_foreground (last_color); 723#else 724 if (last_color != EMPTIED) 725#endif 726 rb->lcd_fillrect (BOARD_X + CUBE_SIZE * (last_i), 727 BOARD_Y + CUBE_SIZE * j, 728 CUBE_SIZE * (i - last_i), CUBE_SIZE); 729 } 730 731#if LCD_DEPTH>=2 732 rb->lcd_set_foreground (LCD_BLACK); 733 rb->lcd_set_background (CLR_LTBLUE); 734#else 735 rb->lcd_set_drawmode (DRMODE_COMPLEMENT); 736#endif 737 rb->lcd_putsxyf (BOARD_X, BOARD_Y, "Level %d", player.level + 1); 738 rb->lcd_putsxyf (BOARD_X + CUBE_SIZE * BOARD_W - 24, BOARD_Y, "%d%%", 739 percentage_cache); 740 rb->lcd_putsxyf (BOARD_X, BOARD_Y + CUBE_SIZE * BOARD_H - 8, "Score: %d", 741 player.score); 742#if LCD_DEPTH>=2 743 x = BOARD_X + CUBE_SIZE * BOARD_W - 60; 744#else 745 x = BOARD_X + CUBE_SIZE * BOARD_W - 40; 746#endif 747 rb->lcd_putsxyf (x, BOARD_Y + CUBE_SIZE * BOARD_H - 8, 748 (player.lives != 1) ? "%d Lives" : "%d Life", player.lives); 749 750#if LCD_DEPTH>=2 751 rb->lcd_set_foreground (PLR_COL); 752 rb->lcd_set_background (board[player.j][player.i]); 753#endif 754 rb->lcd_mono_bitmap (pics[PIC_PLAYER], player.i * CUBE_SIZE + BOARD_X, 755 player.j * CUBE_SIZE + BOARD_Y, CUBE_SIZE, CUBE_SIZE); 756 757#if LCD_DEPTH>=2 758 rb->lcd_set_background (EMPTIED); 759 rb->lcd_set_foreground (LCD_WHITE); 760 rb->lcd_set_drawmode (DRMODE_FG); 761#else 762 rb->lcd_set_drawmode (DRMODE_FG); 763#endif 764 for (j = 0; j < player.level + STARTING_QIXES; j++) 765 rb->lcd_mono_bitmap (pics[PIC_QIX], qixes[j].x + BOARD_X, 766 qixes[j].y + BOARD_Y, CUBE_SIZE, CUBE_SIZE); 767#if LCD_DEPTH>=2 768 rb->lcd_set_foreground (LCD_BLACK); 769#endif 770 rb->lcd_set_drawmode (DRMODE_SOLID); 771 772 rb->lcd_update (); 773} 774 775static inline int infested_area (int i, int j, int v) 776{ 777 struct pos p; 778 p.x = i; 779 p.y = j; 780 emptyStack (); 781 if (!push (&p)) 782 return -1; 783 while (pop (&p)) { 784 if (testboard[p.y][p.x] == v) continue; 785 if (testboard[p.y][p.x] > UNCHECKED) 786 return 1; /* This area was previously flagged as infested */ 787 testboard[p.y][p.x] = v; 788 if (board[p.y][p.x] == QIX) 789 return 1; /* Infested area */ 790 { 791 struct pos p1 = { p.x+1, p.y }; 792 if ((p1.x < BOARD_W) 793 && (board[p1.y][p1.x] != FILLED) 794 && (!push (&p1))) 795 return -1; 796 } 797 { 798 struct pos p1 = { p.x-1, p.y }; 799 if ((p1.x >= 0) 800 && (board[p1.y][p1.x] != FILLED) 801 && (!push (&p1))) 802 return -1; 803 } 804 { 805 struct pos p1 = { p.x, p.y+1 }; 806 if ((p1.y < BOARD_H) 807 && (board[p1.y][p1.x] != FILLED) 808 && (!push (&p1))) 809 return -1; 810 } 811 { 812 struct pos p1 = { p.x, p.y-1 }; 813 if ((p1.y >= 0) 814 && (board[p1.y][p1.x] != FILLED) 815 && (!push (&p1))) 816 return -1; 817 } 818 } 819 return 0; 820} 821 822static inline int fill_area (int i, int j) 823{ 824 struct pos p; 825 p.x = i; 826 p.y = j; 827 int v = testboard[p.y][p.x]; 828 emptyStack (); 829 if (!push (&p)) 830 return -1; 831 while (pop (&p)) { 832 board[p.y][p.x] = FILLED; 833 testboard[p.y][p.x] = PAINTED; 834 { 835 struct pos p1 = { p.x+1, p.y }; 836 if ((p1.x < BOARD_W) 837 && (testboard[p1.y][p1.x] == v) 838 && (!push (&p1))) 839 return -1; 840 } 841 { 842 struct pos p1 = { p.x-1, p.y }; 843 if ((p1.x >= 0) 844 && (testboard[p1.y][p1.x] == v) 845 && (!push (&p1))) 846 return -1; 847 } 848 { 849 struct pos p1 = { p.x, p.y+1 }; 850 if ((p1.y < BOARD_H) 851 && (testboard[p1.y][p1.x] == v) 852 && (!push (&p1))) 853 return -1; 854 } 855 { 856 struct pos p1 = { p.x, p.y-1 }; 857 if ((p1.y >= 0) 858 && (testboard[p1.y][p1.x] == v) 859 && (!push (&p1))) 860 return -1; 861 } 862 } 863 return 0; 864} 865 866 867/* take care of stuff after xonix has landed on a filled spot */ 868static void complete_trail (int fill) 869{ 870 int i, j, ret; 871 for (j = 0; j < BOARD_H; j++) { 872 for (i = 0; i < BOARD_W; i++) { 873 if (board[j][i] == TRAIL) { 874 if (fill) 875 board[j][i] = FILLED; 876 else 877 board[j][i] = EMPTIED; 878 } 879 } 880 } 881 882 if (fill) { 883 int v = CHECKED; 884 for (i = 0; i < player.level + STARTING_QIXES; i++) /* add qixes to board */ 885 board[pos(qixes[i].y - BOARD_Y)] 886 [pos(qixes[i].x - BOARD_X)] = QIX; 887 888 init_testboard(); 889 for (j = 1; j < BOARD_H - 1; j++) { 890 for (i = 0; i < BOARD_W - 0; i++) { 891 if (board[j][i] != FILLED) { 892 ret = infested_area (i, j, v); 893 if (ret < 0 || ( ret == 0 && fill_area (i, j) ) ) 894 quit = true; 895 v++; 896 } 897 } 898 } 899 900 for (i = 0; i < player.level + STARTING_QIXES; i++) /* add qixes to board */ 901 board[pos(qixes[i].y - BOARD_Y)] 902 [pos(qixes[i].x - BOARD_X)] = EMPTIED; 903 percentage_cache = percentage(); 904 } 905 906 rb->button_clear_queue(); 907} 908 909/* returns the color the real pixel(x,y) on the lcd is pointing at */ 910static inline unsigned int getpixel (int x, int y) 911{ 912 const int a = pos (x - BOARD_X), b = pos (y - BOARD_Y); 913 if ((a > 0) && (a < BOARD_W) && (b > 0) && (b < BOARD_H)) /* if inside board */ 914 return board[b][a]; 915 else 916 return FILLED; 917} 918 919/* returns the color the ball on (newx,newy) is heading at *----* 920 checks the four edge points of the square if 1st of all | | 921 are a trail (cause it's a lose life situation) and 2nd | | 922 if it's filled so it needs to bounce. *____* 923 */ 924static inline unsigned int next_hit (int newx, int newy) 925{ 926 if ((getpixel (newx, newy) == TRAIL) 927 || (getpixel (newx, newy + CUBE_SIZE - 1) == TRAIL) 928 || (getpixel (newx + CUBE_SIZE - 1, newy) == TRAIL) 929 || (getpixel (newx + CUBE_SIZE - 1, newy + CUBE_SIZE - 1) == TRAIL)) 930 return TRAIL; 931 else if ((getpixel (newx, newy) == FILLED) 932 || (getpixel (newx, newy + CUBE_SIZE - 1) == FILLED) 933 || (getpixel (newx + CUBE_SIZE - 1, newy) == FILLED) 934 || (getpixel (newx + CUBE_SIZE - 1, newy + CUBE_SIZE - 1) == 935 FILLED)) 936 return FILLED; 937 else 938 return EMPTIED; 939} 940 941static void die (void) 942{ 943 player.lives--; 944 if (player.lives == 0) 945 player.gameover = true; 946 else { 947 refresh_board (); 948 rb->splash (HZ, "Crash!"); 949 complete_trail (false); 950 player.move = MOVE_NO; 951 player.drawing = false; 952 player.i = BOARD_W / 2; 953 player.j = 1; 954 } 955} 956 957/* returns true if the (side) of the block -***- 958 starting from (newx,newy) has any filled pixels * * 959 -***- 960 */ 961static inline bool line_check_lt (int newx, int newy) 962{ 963 return getpixel (newx, newy + CUBE_SIZE/2-1) == FILLED 964 && getpixel (newx, newy + CUBE_SIZE/2 ) == FILLED; 965} 966static inline bool line_check_rt (int newx, int newy) 967{ 968 return getpixel (newx + CUBE_SIZE-1, newy + CUBE_SIZE/2-1) == FILLED 969 && getpixel (newx + CUBE_SIZE-1, newy + CUBE_SIZE/2 ) == FILLED; 970} 971static inline bool line_check_up (int newx, int newy) 972{ 973 return getpixel (newx + CUBE_SIZE/2-1, newy) == FILLED 974 && getpixel (newx + CUBE_SIZE/2 , newy) == FILLED; 975} 976static inline bool line_check_dn (int newx, int newy) 977{ 978 return getpixel (newx + CUBE_SIZE/2-1, newy + CUBE_SIZE-1) == FILLED 979 && getpixel (newx + CUBE_SIZE/2 , newy + CUBE_SIZE-1) == FILLED; 980} 981 982static inline void move_qix (struct qix *q) 983{ 984 int newx, newy; 985 newx = get_newx (q->x, q->velocity, q->angle); 986 newy = get_newy (q->y, q->velocity, q->angle); 987 switch (next_hit (newx, newy)) 988 { 989 case EMPTIED: 990 q->x = newx; 991 q->y = newy; 992 break; 993 case FILLED: 994 { 995 const int a = q->angle; 996 q->angle = 997 ((a&(DIR_UU|DIR_U)) 998 ? (line_check_up (newx, newy) ? ((a&(DIR_UU|DIR_U))>>4) 999 : (a&(DIR_UU|DIR_U))) 1000 : 0) 1001 | 1002 ((a&(DIR_RR|DIR_R)) 1003 ? (line_check_rt (newx, newy) ? ((a&(DIR_RR|DIR_R))>>4) 1004 : (a&(DIR_RR|DIR_R))) 1005 : 0) 1006 | 1007 ((a&(DIR_DD|DIR_D)) 1008 ? (line_check_dn (newx, newy) ? ((a&(DIR_DD|DIR_D))<<4) 1009 : (a&(DIR_DD|DIR_D))) 1010 : 0) 1011 | 1012 ((a&(DIR_LL|DIR_L)) 1013 ? (line_check_lt (newx, newy) ? ((a&(DIR_LL|DIR_L))<<4) 1014 : (a&(DIR_LL|DIR_L))) 1015 : 0); 1016 q->x = get_newx (q->x, q->velocity, q->angle); 1017 q->y = get_newy (q->y, q->velocity, q->angle); 1018 break; 1019 } 1020 case TRAIL: 1021 die(); 1022 break; 1023 } 1024} 1025 1026/* move the board forward timewise */ 1027static inline void move_board (void) 1028{ 1029 int j, newi, newj; 1030 1031 for (j = 0; j < player.level + STARTING_QIXES; j++) 1032 move_qix (&qixes[j]); 1033 /* move_qix(&black_qix,true); */ 1034 if (player.move) { 1035 newi = player.i; 1036 newj = player.j; 1037 switch (player.move) { 1038 case MOVE_UP: 1039 if (player.j > 1) 1040 newj--; 1041 break; 1042 case MOVE_DN: 1043 if (player.j < BOARD_H - 2) 1044 newj++; 1045 break; 1046 case MOVE_LT: 1047 if (player.i > 0) 1048 newi--; 1049 break; 1050 case MOVE_RT: 1051 if (player.i < BOARD_W - 1) 1052 newi++; 1053 break; 1054 default: 1055 break; 1056 } 1057 1058 if ((player.drawing) && (board[newj][newi] == EMPTIED)) /* continue drawing */ 1059 board[newj][newi] = TRAIL; 1060 else if ((player.drawing) && (board[newj][newi] == FILLED)) { /* finish drawing */ 1061 player.move = MOVE_NO; /* stop moving */ 1062 player.drawing = false; 1063 complete_trail (true); 1064 } else if ((board[player.j][player.i] == FILLED) 1065 && (board[newj][newi] == EMPTIED)) { 1066 /* start drawing */ 1067 player.drawing = true; 1068 board[newj][newi] = TRAIL; 1069 /* if the block after next is empty and we're moving onto filled, stop */ 1070 } else if ((board[newj][newi] == FILLED) 1071 && (board[newj + newj-player.j][newi + newi-player.i] == EMPTIED)) { 1072 player.move = MOVE_NO; 1073 } 1074 player.i = newi; 1075 player.j = newj; 1076 } 1077 if (percentage_cache >= difficulty) { /* finished level */ 1078 refresh_board (); 1079 rb->splashf (HZ * 2, "Level %d finished", player.level+1); 1080 player.score += percentage_cache; 1081 if (player.level < MAX_LEVEL) 1082 player.level++; 1083 init_board (); 1084 refresh_board (); 1085 rb->button_clear_queue(); 1086 rb->splash (HZ * 2, "Ready?"); 1087 } 1088} 1089 1090/* init game's variables */ 1091static void init_game (void) 1092{ 1093 player.level = 0; 1094 player.score = 0; 1095 player.lives = 3; 1096 player.gameover = false; 1097 player.drawing = false; 1098 init_board (); 1099 refresh_board (); 1100 rb->splash (HZ * 2, "Ready?"); 1101} 1102 1103static bool load_game(void) 1104{ 1105 int fd = rb->open(RESUME_FILE, O_RDONLY); 1106 1107 if (fd < 0) { 1108 return true; 1109 } 1110 1111 bool load_success = 1112 rb->read(fd, &player, sizeof(player)) == sizeof(player) && 1113 rb->read(fd, &qixes, sizeof(qixes)) == sizeof(qixes) && 1114 rb->read(fd, &stack, sizeof(stack)) == sizeof(stack) && 1115 rb->read(fd, &board, sizeof(board)) == sizeof(board) && 1116 rb->read(fd, &testboard, sizeof(testboard)) == sizeof(testboard) && 1117 rb->read(fd, &speed, sizeof(speed)) == sizeof(speed) && 1118 rb->read(fd, &difficulty, sizeof(difficulty)) == sizeof(difficulty) && 1119 rb->read(fd, &stackPointer, sizeof(stackPointer)) == sizeof(stackPointer) && 1120 rb->read(fd, &percentage_cache, 1121 sizeof(percentage_cache)) == sizeof(percentage_cache); 1122 1123 rb->close(fd); 1124 _ingame = load_success; 1125 1126 return load_success; 1127} 1128 1129static bool save_game(void) 1130{ 1131 int fd = rb->open(RESUME_FILE, O_WRONLY|O_CREAT, 0666); 1132 1133 if (fd < 0) { 1134 return false; 1135 } 1136 1137 bool save_success = 1138 rb->write(fd, &player, sizeof(player)) > 0 && 1139 rb->write(fd, &qixes, sizeof(qixes)) > 0 && 1140 rb->write(fd, &stack, sizeof(stack)) > 0 && 1141 rb->write(fd, &board, sizeof(board)) > 0 && 1142 rb->write(fd, &testboard, sizeof(testboard)) > 0 && 1143 rb->write(fd, &speed, sizeof(speed)) > 0 && 1144 rb->write(fd, &difficulty, sizeof(difficulty)) > 0 && 1145 rb->write(fd, &stackPointer, sizeof(stackPointer)) > 0 && 1146 rb->write(fd, &percentage_cache, sizeof(percentage_cache)) > 0; 1147 1148 rb->close(fd); 1149 1150 if (!save_success) { 1151 rb->remove(RESUME_FILE); 1152 } 1153 1154 return save_success; 1155} 1156 1157/* the main menu */ 1158static int xobox_menu_cb(int action, 1159 const struct menu_item_ex *this_item, 1160 struct gui_synclist *this_list) 1161{ 1162 (void)this_list; 1163 intptr_t item = (intptr_t)this_item; 1164 if(action == ACTION_REQUEST_MENUITEM 1165 && !_ingame && (item == 0 || item == 6)) 1166 return ACTION_EXIT_MENUITEM; 1167 return action; 1168} 1169 1170static int xobox_menu(bool ingame) 1171{ 1172 rb->button_clear_queue(); 1173 1174 int selection = 0; 1175 MENUITEM_STRINGLIST(main_menu, "Xobox Menu", xobox_menu_cb, 1176 "Resume Game", "Start New Game", 1177 "Speed", "Difficulty", 1178 "High Scores", "Playback Control", 1179 "Quit Without Saving", "Quit"); 1180 _ingame = ingame; 1181 1182 while (true) { 1183 switch (rb->do_menu(&main_menu, &selection, NULL, false)) { 1184 case 0: 1185 rb->remove(RESUME_FILE); 1186 refresh_board(); 1187 rb->splash (HZ*2, "Ready?"); 1188 return 0; 1189 case 1: 1190 init_game (); 1191 return 0; 1192 case 2: 1193 rb->set_int ("Speed", "", UNIT_INT, &speed, NULL, 1, 1, 10, NULL); 1194 break; 1195 case 3: 1196 rb->set_int ("Difficulty", "", UNIT_INT, &difficulty, NULL, 1197 5, 50, 95, NULL); 1198 break; 1199 case 4: 1200 highscore_show(-1, highscores, NUM_SCORES, true); 1201 break; 1202 case 5: 1203 playback_control(NULL); 1204 break; 1205 case 6: 1206 return 1; 1207 case 7: 1208 if (_ingame) { 1209 rb->splash(HZ, "Saving game..."); 1210 1211 if (!save_game()) { 1212 rb->splash(HZ, "Failed to save game"); 1213 } 1214 } 1215 1216 return 1; 1217 case MENU_ATTACHED_USB: 1218 return 1; 1219 default: 1220 break; 1221 } 1222 } 1223} 1224 1225/* general keypad handler loop */ 1226static int xobox_loop (void) 1227{ 1228 int button = 0; 1229 bool pause = false; 1230 int end; 1231 1232 if (xobox_menu(_ingame)) { 1233 return PLUGIN_OK; 1234 } 1235 1236 while (!quit) { 1237 end = *rb->current_tick + ((11-speed)*HZ)/100; 1238 1239#ifdef HAS_BUTTON_HOLD 1240 if (rb->button_hold()) { 1241 pause = true; 1242 rb->splash (HZ, "Paused"); 1243 } 1244#endif 1245 1246 button = rb->button_get_w_tmo (1); 1247 switch (button) { 1248 case UP: 1249 case UP|BUTTON_REPEAT: 1250 player.move = MOVE_UP; 1251 break; 1252 case DOWN: 1253 case DOWN|BUTTON_REPEAT: 1254 player.move = MOVE_DN; 1255 break; 1256 case LEFT: 1257 case LEFT|BUTTON_REPEAT: 1258 player.move = MOVE_LT; 1259 break; 1260 case RIGHT: 1261 case RIGHT|BUTTON_REPEAT: 1262 player.move = MOVE_RT; 1263 break; 1264 case PAUSE: 1265 pause = !pause; 1266 if (pause) 1267 rb->splash (HZ, "Paused"); 1268 break; 1269 case QUIT: 1270 if (!pause) { 1271 if (xobox_menu(true)) { 1272 quit = true; 1273 } 1274 } 1275 break; 1276 default: 1277 if (rb->default_event_handler (button) == SYS_USB_CONNECTED) 1278 return PLUGIN_USB_CONNECTED; 1279 break; 1280 } 1281 if (!pause) { 1282 move_board (); 1283 refresh_board (); 1284 } 1285 if (player.gameover) { 1286 rb->splash (HZ, "Game Over!"); 1287 1288 int pos = highscore_update(player.score, player.level, "", 1289 highscores, NUM_SCORES); 1290 1291 if (pos != -1) { 1292 if (pos == 0) { 1293 rb->splashf(HZ, "New High Score: %d", player.score); 1294 } 1295 1296 highscore_show(pos, highscores, NUM_SCORES, true); 1297 } 1298 1299 if (xobox_menu(false)) { 1300 quit = true; 1301 } 1302 } 1303 1304 if (TIME_BEFORE(*rb->current_tick, end)) 1305 rb->sleep (end - *rb->current_tick); 1306 else 1307 rb->yield (); 1308 1309 } /* end while */ 1310 return PLUGIN_OK; /* for no warnings on compiling */ 1311} 1312 1313/* plugin main procedure */ 1314enum plugin_status plugin_start (const void *parameter) 1315{ 1316 int ret = PLUGIN_OK; 1317 1318 (void) parameter; 1319 1320 rb->lcd_setfont (FONT_SYSFIXED); 1321#if LCD_DEPTH>=2 1322 rb->lcd_set_backdrop(NULL); 1323#endif 1324 1325 /* Turn off backlight timeout */ 1326 backlight_ignore_timeout(); 1327 1328 highscore_load(SCORE_FILE, highscores, NUM_SCORES); 1329 1330 if (!load_game()) { 1331 rb->splash(HZ, "Failed to load saved game"); 1332 } 1333 1334 randomize (); 1335 ret = xobox_loop (); 1336 1337 1338 /* Turn on backlight timeout (revert to settings) */ 1339 backlight_use_settings(); 1340 1341 rb->lcd_setfont (FONT_UI); 1342 1343 highscore_save(SCORE_FILE, highscores, NUM_SCORES); 1344 1345 return ret; 1346}