A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 2171 lines 59 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2006 by Mat Holton 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21 22#include "plugin.h" 23#include "lib/display_text.h" 24#include "lib/helper.h" 25#include "lib/highscore.h" 26#include "lib/playback_control.h" 27 28 29 30/* variable button definitions */ 31#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ 32 (CONFIG_KEYPAD == IRIVER_H300_PAD) 33#define AST_PAUSE BUTTON_REC 34#define AST_QUIT BUTTON_OFF 35#define AST_THRUST BUTTON_UP 36#define AST_HYPERSPACE BUTTON_DOWN 37#define AST_LEFT BUTTON_LEFT 38#define AST_RIGHT BUTTON_RIGHT 39#define AST_FIRE BUTTON_SELECT 40 41#define AST_RC_QUIT BUTTON_RC_STOP 42 43#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) 44#define AST_PAUSE BUTTON_PLAY 45#define AST_QUIT BUTTON_POWER 46#define AST_THRUST BUTTON_UP 47#define AST_HYPERSPACE BUTTON_DOWN 48#define AST_LEFT BUTTON_LEFT 49#define AST_RIGHT BUTTON_RIGHT 50#define AST_FIRE BUTTON_SELECT 51 52#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ 53 (CONFIG_KEYPAD == IPOD_1G2G_PAD) 54#define AST_PAUSE BUTTON_PLAY 55#define AST_QUIT BUTTON_MENU 56#define AST_THRUST BUTTON_RIGHT 57#define AST_HYPERSPACE BUTTON_LEFT 58#define AST_LEFT BUTTON_SCROLL_BACK 59#define AST_RIGHT BUTTON_SCROLL_FWD 60#define AST_FIRE BUTTON_SELECT 61 62#elif (CONFIG_KEYPAD == GIGABEAT_PAD) 63#define AST_PAUSE BUTTON_A 64#define AST_QUIT BUTTON_POWER 65#define AST_THRUST BUTTON_UP 66#define AST_HYPERSPACE BUTTON_DOWN 67#define AST_LEFT BUTTON_LEFT 68#define AST_RIGHT BUTTON_RIGHT 69#define AST_FIRE BUTTON_SELECT 70 71#elif (CONFIG_KEYPAD == SANSA_E200_PAD) 72#define AST_PAUSE BUTTON_REC 73#define AST_QUIT BUTTON_POWER 74#define AST_THRUST BUTTON_UP 75#define AST_HYPERSPACE BUTTON_DOWN 76#define AST_LEFT BUTTON_SCROLL_BACK 77#define AST_RIGHT BUTTON_SCROLL_FWD 78#define AST_FIRE BUTTON_SELECT 79 80#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD) 81#define AST_PAUSE (BUTTON_SELECT | BUTTON_UP) 82#define AST_QUIT (BUTTON_HOME|BUTTON_REPEAT) 83#define AST_THRUST BUTTON_UP 84#define AST_HYPERSPACE BUTTON_DOWN 85#define AST_LEFT BUTTON_SCROLL_BACK 86#define AST_RIGHT BUTTON_SCROLL_FWD 87#define AST_FIRE BUTTON_SELECT 88 89#elif (CONFIG_KEYPAD == SANSA_C200_PAD) 90#define AST_PAUSE BUTTON_REC 91#define AST_QUIT BUTTON_POWER 92#define AST_THRUST BUTTON_UP 93#define AST_HYPERSPACE BUTTON_DOWN 94#define AST_LEFT BUTTON_LEFT 95#define AST_RIGHT BUTTON_RIGHT 96#define AST_FIRE BUTTON_SELECT 97 98#elif (CONFIG_KEYPAD == SANSA_CLIP_PAD) 99#define AST_PAUSE BUTTON_HOME 100#define AST_QUIT BUTTON_POWER 101#define AST_THRUST BUTTON_UP 102#define AST_HYPERSPACE BUTTON_DOWN 103#define AST_LEFT BUTTON_LEFT 104#define AST_RIGHT BUTTON_RIGHT 105#define AST_FIRE BUTTON_SELECT 106 107#elif (CONFIG_KEYPAD == SANSA_M200_PAD) 108#define AST_PAUSE (BUTTON_SELECT | BUTTON_UP) 109#define AST_QUIT BUTTON_POWER 110#define AST_THRUST BUTTON_UP 111#define AST_HYPERSPACE BUTTON_DOWN 112#define AST_LEFT BUTTON_LEFT 113#define AST_RIGHT BUTTON_RIGHT 114#define AST_FIRE (BUTTON_SELECT | BUTTON_REL) 115 116#elif (CONFIG_KEYPAD == IRIVER_H10_PAD) 117#define AST_PAUSE BUTTON_PLAY 118#define AST_QUIT BUTTON_POWER 119#define AST_THRUST BUTTON_SCROLL_UP 120#define AST_HYPERSPACE BUTTON_SCROLL_DOWN 121#define AST_LEFT BUTTON_LEFT 122#define AST_RIGHT BUTTON_RIGHT 123#define AST_FIRE BUTTON_REW 124 125#elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) 126#define AST_PAUSE BUTTON_PLAY 127#define AST_QUIT BUTTON_BACK 128#define AST_THRUST BUTTON_UP 129#define AST_HYPERSPACE BUTTON_DOWN 130#define AST_LEFT BUTTON_LEFT 131#define AST_RIGHT BUTTON_RIGHT 132#define AST_FIRE BUTTON_SELECT 133 134#elif (CONFIG_KEYPAD == MROBE100_PAD) 135#define AST_PAUSE BUTTON_DISPLAY 136#define AST_QUIT BUTTON_POWER 137#define AST_THRUST BUTTON_UP 138#define AST_HYPERSPACE BUTTON_DOWN 139#define AST_LEFT BUTTON_LEFT 140#define AST_RIGHT BUTTON_RIGHT 141#define AST_FIRE BUTTON_SELECT 142 143#elif CONFIG_KEYPAD == IAUDIO_M3_PAD 144#define AST_PAUSE BUTTON_RC_PLAY 145#define AST_QUIT BUTTON_RC_REC 146#define AST_THRUST BUTTON_RC_VOL_UP 147#define AST_HYPERSPACE BUTTON_RC_VOL_DOWN 148#define AST_LEFT BUTTON_RC_REW 149#define AST_RIGHT BUTTON_RC_FF 150#define AST_FIRE BUTTON_RC_MODE 151 152#elif (CONFIG_KEYPAD == COWON_D2_PAD) 153#define AST_QUIT BUTTON_POWER 154 155#elif CONFIG_KEYPAD == CREATIVEZVM_PAD 156#define AST_PAUSE BUTTON_PLAY 157#define AST_QUIT BUTTON_BACK 158#define AST_THRUST BUTTON_UP 159#define AST_HYPERSPACE BUTTON_DOWN 160#define AST_LEFT BUTTON_LEFT 161#define AST_RIGHT BUTTON_RIGHT 162#define AST_FIRE BUTTON_SELECT 163 164#elif CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD 165#define AST_PAUSE (BUTTON_PLAY | BUTTON_REL) 166#define AST_QUIT BUTTON_POWER 167#define AST_THRUST BUTTON_UP 168#define AST_HYPERSPACE BUTTON_DOWN 169#define AST_LEFT BUTTON_BACK 170#define AST_RIGHT BUTTON_MENU 171#define AST_FIRE BUTTON_VOL_UP 172 173#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD 174#define AST_PAUSE BUTTON_VIEW 175#define AST_QUIT BUTTON_POWER 176#define AST_THRUST BUTTON_UP 177#define AST_HYPERSPACE BUTTON_DOWN 178#define AST_LEFT BUTTON_LEFT 179#define AST_RIGHT BUTTON_RIGHT 180#define AST_FIRE BUTTON_PLAYLIST 181 182#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD 183#define AST_PAUSE BUTTON_PLAY 184#define AST_QUIT BUTTON_POWER 185#define AST_THRUST BUTTON_UP 186#define AST_HYPERSPACE BUTTON_DOWN 187#define AST_LEFT BUTTON_LEFT 188#define AST_RIGHT BUTTON_RIGHT 189#define AST_FIRE BUTTON_VOL_DOWN 190 191#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD 192#define AST_PAUSE BUTTON_RIGHT 193#define AST_QUIT BUTTON_POWER 194#define AST_THRUST BUTTON_UP 195#define AST_HYPERSPACE BUTTON_DOWN 196#define AST_LEFT BUTTON_PREV 197#define AST_RIGHT BUTTON_NEXT 198#define AST_FIRE BUTTON_LEFT 199 200#elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \ 201 (CONFIG_KEYPAD == ONDAVX777_PAD) || \ 202 (CONFIG_KEYPAD == MROBE500_PAD) 203#define AST_QUIT BUTTON_POWER 204 205#elif (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) || \ 206 (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD) 207 208#define AST_PAUSE BUTTON_FFWD 209#define AST_QUIT BUTTON_REW 210#define AST_THRUST BUTTON_UP 211#define AST_HYPERSPACE BUTTON_DOWN 212#define AST_LEFT BUTTON_LEFT 213#define AST_RIGHT BUTTON_RIGHT 214#define AST_FIRE BUTTON_PLAY 215 216#elif (CONFIG_KEYPAD == PBELL_VIBE500_PAD) 217 218#define AST_PAUSE BUTTON_PLAY 219#define AST_QUIT BUTTON_REC 220#define AST_THRUST BUTTON_UP 221#define AST_HYPERSPACE BUTTON_DOWN 222#define AST_LEFT BUTTON_PREV 223#define AST_RIGHT BUTTON_NEXT 224#define AST_FIRE BUTTON_OK 225 226#elif (CONFIG_KEYPAD == MPIO_HD200_PAD) 227 228#define AST_PAUSE (BUTTON_PLAY|BUTTON_FUNC) 229#define AST_QUIT (BUTTON_REC|BUTTON_PLAY) 230#define AST_THRUST BUTTON_REC 231#define AST_HYPERSPACE BUTTON_PLAY 232#define AST_LEFT BUTTON_REW 233#define AST_RIGHT BUTTON_FF 234#define AST_FIRE BUTTON_FUNC 235 236#elif (CONFIG_KEYPAD == MPIO_HD300_PAD) 237 238#define AST_PAUSE (BUTTON_PLAY|BUTTON_REL) 239#define AST_QUIT (BUTTON_MENU|BUTTON_REPEAT) 240#define AST_THRUST BUTTON_REC 241#define AST_HYPERSPACE (BUTTON_PLAY|BUTTON_REPEAT) 242#define AST_LEFT BUTTON_UP 243#define AST_RIGHT BUTTON_DOWN 244#define AST_FIRE BUTTON_ENTER 245 246#elif (CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD) 247 248#define AST_PAUSE BUTTON_PLAYPAUSE 249#define AST_QUIT BUTTON_POWER 250#define AST_THRUST BUTTON_UP 251#define AST_HYPERSPACE BUTTON_BACK 252#define AST_LEFT BUTTON_LEFT 253#define AST_RIGHT BUTTON_RIGHT 254#define AST_FIRE BUTTON_SELECT 255 256#elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD) 257 258#define ALT_PAUSE BUTTON_VOL_DOWN 259#define AST_QUIT BUTTON_POWER 260#define AST_THRUST BUTTON_UP 261#define AST_HYPERSPACE BUTTON_DOWN 262#define AST_LEFT BUTTON_SCROLL_BACK 263#define AST_RIGHT BUTTON_SCROLL_FWD 264#define AST_FIRE BUTTON_SELECT 265 266#elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD) 267#define AST_PAUSE BUTTON_MENU 268#define AST_QUIT BUTTON_BACK 269#define AST_THRUST BUTTON_UP 270#define AST_HYPERSPACE BUTTON_DOWN 271#define AST_LEFT BUTTON_LEFT 272#define AST_RIGHT BUTTON_RIGHT 273#define AST_FIRE BUTTON_SELECT 274 275#elif (CONFIG_KEYPAD == HM60X_PAD) 276#define AST_PAUSE (BUTTON_SELECT|BUTTON_POWER) 277#define AST_QUIT BUTTON_POWER 278#define AST_THRUST BUTTON_UP 279#define AST_HYPERSPACE BUTTON_DOWN 280#define AST_LEFT BUTTON_LEFT 281#define AST_RIGHT BUTTON_RIGHT 282#define AST_FIRE BUTTON_SELECT 283 284#elif (CONFIG_KEYPAD == HM801_PAD) 285#define AST_PAUSE BUTTON_PLAY 286#define AST_QUIT BUTTON_POWER 287#define AST_THRUST BUTTON_UP 288#define AST_HYPERSPACE BUTTON_DOWN 289#define AST_LEFT BUTTON_LEFT 290#define AST_RIGHT BUTTON_RIGHT 291#define AST_FIRE BUTTON_SELECT 292 293#elif CONFIG_KEYPAD == SONY_NWZ_PAD 294#define AST_PAUSE BUTTON_POWER 295#define AST_QUIT BUTTON_BACK 296#define AST_THRUST BUTTON_UP 297#define AST_HYPERSPACE BUTTON_DOWN 298#define AST_LEFT BUTTON_LEFT 299#define AST_RIGHT BUTTON_RIGHT 300#define AST_FIRE BUTTON_PLAY 301 302#elif CONFIG_KEYPAD == CREATIVE_ZEN_PAD 303#define AST_PAUSE BUTTON_PLAYPAUSE 304#define AST_QUIT BUTTON_BACK 305#define AST_THRUST BUTTON_UP 306#define AST_HYPERSPACE BUTTON_DOWN 307#define AST_LEFT BUTTON_LEFT 308#define AST_RIGHT BUTTON_RIGHT 309#define AST_FIRE BUTTON_SELECT 310 311#elif (CONFIG_KEYPAD == DX50_PAD) 312#define AST_QUIT BUTTON_POWER 313#define AST_THRUST BUTTON_VOL_UP 314#define AST_HYPERSPACE BUTTON_VOL_DOWN 315#define AST_LEFT BUTTON_LEFT 316#define AST_RIGHT BUTTON_PLAY 317#define AST_FIRE BUTTON_RIGHT 318 319#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD 320#define AST_QUIT BUTTON_POWER 321 322#elif (CONFIG_KEYPAD == AGPTEK_ROCKER_PAD) 323#define AST_QUIT BUTTON_POWER 324#define AST_THRUST BUTTON_UP 325#define AST_HYPERSPACE BUTTON_VOLUP 326#define AST_LEFT BUTTON_LEFT 327#define AST_RIGHT BUTTON_RIGHT 328#define AST_FIRE BUTTON_SELECT 329 330#elif (CONFIG_KEYPAD == XDUOO_X3_PAD) || (CONFIG_KEYPAD == XDUOO_X3II_PAD) || (CONFIG_KEYPAD == XDUOO_X20_PAD) 331#define AST_PAUSE BUTTON_VOL_UP 332#define AST_QUIT BUTTON_POWER 333#define AST_THRUST BUTTON_HOME 334#define AST_HYPERSPACE BUTTON_OPTION 335#define AST_LEFT BUTTON_PREV 336#define AST_RIGHT BUTTON_NEXT 337#define AST_FIRE BUTTON_PLAY 338 339#elif (CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD) 340#define AST_PAUSE BUTTON_VOL_UP 341#define AST_QUIT BUTTON_POWER 342#define AST_THRUST BUTTON_HOME 343#define AST_HYPERSPACE BUTTON_OPTION 344#define AST_LEFT BUTTON_PREV 345#define AST_RIGHT BUTTON_NEXT 346#define AST_FIRE BUTTON_PLAY 347 348#elif (CONFIG_KEYPAD == IHIFI_770_PAD) || (CONFIG_KEYPAD == IHIFI_800_PAD) 349#define AST_PAUSE BUTTON_PLAY 350#define AST_QUIT BUTTON_POWER 351#define AST_THRUST BUTTON_NEXT 352#define AST_HYPERSPACE BUTTON_PREV 353#define AST_LEFT BUTTON_HOME 354#define AST_RIGHT BUTTON_VOL_DOWN 355#define AST_FIRE BUTTON_VOL_UP 356 357#elif (CONFIG_KEYPAD == EROSQ_PAD) 358#define AST_PAUSE BUTTON_PREV 359#define AST_QUIT BUTTON_POWER 360#define AST_THRUST BUTTON_PLAY 361#define AST_HYPERSPACE BUTTON_MENU 362#define AST_LEFT BUTTON_SCROLL_BACK 363#define AST_RIGHT BUTTON_SCROLL_FWD 364#define AST_FIRE BUTTON_BACK 365 366#elif CONFIG_KEYPAD == FIIO_M3K_PAD 367#define AST_PAUSE BUTTON_MENU 368#define AST_QUIT BUTTON_POWER 369#define AST_THRUST BUTTON_SELECT 370#define AST_HYPERSPACE BUTTON_BACK 371#define AST_LEFT BUTTON_LEFT 372#define AST_RIGHT BUTTON_RIGHT 373#define AST_FIRE BUTTON_PLAY 374 375#elif CONFIG_KEYPAD == SHANLING_Q1_PAD 376/* use touchscreen */ 377 378#elif CONFIG_KEYPAD == SDL_PAD 379/* use touchscreen */ 380#elif CONFIG_KEYPAD == MA_PAD 381#define AST_PAUSE BUTTON_MENU 382#define AST_QUIT BUTTON_BACK 383#define AST_THRUST BUTTON_PLAY 384#define AST_HYPERSPACE BUTTON_UP 385#define AST_LEFT BUTTON_LEFT 386#define AST_RIGHT BUTTON_RIGHT 387#define AST_FIRE BUTTON_DOWN 388 389#elif CONFIG_KEYPAD == RG_NANO_PAD 390#define AST_PAUSE BUTTON_X 391#define AST_QUIT BUTTON_START 392#define AST_THRUST BUTTON_UP 393#define AST_HYPERSPACE BUTTON_DOWN 394#define AST_LEFT BUTTON_LEFT 395#define AST_RIGHT BUTTON_RIGHT 396#define AST_FIRE BUTTON_A 397 398#else 399#error No keymap defined! 400#endif 401 402#ifdef HAVE_TOUCHSCREEN 403#ifndef AST_PAUSE 404#define AST_PAUSE BUTTON_CENTER 405#endif 406#ifndef AST_QUIT 407#define AST_QUIT BUTTON_TOPLEFT 408#endif 409#ifndef AST_THRUST 410#define AST_THRUST BUTTON_TOPMIDDLE 411#endif 412#ifndef AST_HYPERSPACE 413#define AST_HYPERSPACE BUTTON_TOPRIGHT 414#endif 415#ifndef AST_LEFT 416#define AST_LEFT BUTTON_MIDLEFT 417#endif 418#ifndef AST_RIGHT 419#define AST_RIGHT BUTTON_MIDRIGHT 420#endif 421#ifndef AST_FIRE 422#define AST_FIRE BUTTON_BOTTOMMIDDLE 423#endif 424#endif 425 426#define RES MAX(LCD_WIDTH, LCD_HEIGHT) 427#define LARGE_LCD (RES >= 200) 428 429#define CYCLETIME 30 430 431#define SHOW_COL 0 432#define SCALE 5000 433#define WRAP_GAP (LARGE*SCALE*3) 434#define POINT_SIZE 2 435#define START_LEVEL 1 436#define SHOW_LEVEL_TIME 50 437#define EXPLOSION_LENGTH 20 438 439#define MAX_NUM_ASTEROIDS 25 440#define MAX_NUM_MISSILES 6 441#define NUM_STARS 50 442#define NUM_TRAIL_POINTS 70 443#define MAX_LEVEL MAX_NUM_ASTEROIDS 444 445#define NUM_ASTEROID_VERTICES 10 446#define NUM_SHIP_VERTICES 4 447#define NUM_ENEMY_VERTICES 8 448 449#define INVULNERABLE_TIME 30 450#define BLINK_TIME 10 451#define EXTRA_LIFE 250 452#define START_LIVES 3 453#define MISSILE_LIFE_LENGTH 40 454 455#define ASTEROID_SPEED (RES/20) 456#define SPACE_CHECK_SIZE 30*SCALE 457 458#if (LARGE_LCD) 459#define SIZE_SHIP_COLLISION 8*SCALE 460#else 461#define SIZE_SHIP_COLLISION 6*SCALE 462#endif 463 464#define LITTLE_SHIP 1 465#define BIG_SHIP 2 466#define ENEMY_BIG_PROBABILITY_START 10 467#define ENEMY_APPEAR_PROBABILITY_START 35 468#define ENEMY_APPEAR_TIMING_START 600 469#define ENEMY_SPEED 4 470#define ENEMY_MISSILE_LIFE_LENGTH (RES/2) 471#if (LARGE_LCD) 472#define SIZE_ENEMY_COLLISION 7*SCALE 473#else 474#define SIZE_ENEMY_COLLISION 5*SCALE 475#endif 476 477#define SIN_COS_SCALE 10000 478 479#define FAST_ROT_CW_SIN 873 480#define FAST_ROT_CW_COS 9963 481#define FAST_ROT_ACW_SIN -873 482#define FAST_ROT_ACW_COS 9963 483 484#define MEDIUM_ROT_CW_SIN 350 485#define MEDIUM_ROT_CW_COS 9994 486#define MEDIUM_ROT_ACW_SIN -350 487#define MEDIUM_ROT_ACW_COS 9994 488 489#define SLOW_ROT_CW_SIN 350 490#define SLOW_ROT_CW_COS 9994 491#define SLOW_ROT_ACW_SIN -350 492#define SLOW_ROT_ACW_COS 9994 493 494#ifdef HAVE_LCD_COLOR 495#define SHIP_ROT_CW_SIN 2419 496#define SHIP_ROT_CW_COS 9702 497#define SHIP_ROT_ACW_SIN -2419 498#define SHIP_ROT_ACW_COS 9702 499#else 500#define SHIP_ROT_CW_SIN 3827 501#define SHIP_ROT_CW_COS 9239 502#define SHIP_ROT_ACW_SIN -3827 503#define SHIP_ROT_ACW_COS 9239 504#endif 505 506 507#define SCALED_WIDTH (LCD_WIDTH*SCALE) 508#define SCALED_HEIGHT (LCD_HEIGHT*SCALE) 509#define CENTER_LCD_X (LCD_WIDTH/2) 510#define CENTER_LCD_Y (LCD_HEIGHT/2) 511 512#ifdef HAVE_LCD_COLOR 513#define ASTEROID_R 230 514#define ASTEROID_G 200 515#define ASTEROID_B 100 516#define SHIP_R 255 517#define SHIP_G 255 518#define SHIP_B 255 519#define ENEMY_R 50 520#define ENEMY_G 220 521#define ENEMY_B 50 522#define THRUST_R 200 523#define THRUST_G 200 524#define THRUST_B 0 525 526#define COL_MISSILE LCD_RGBPACK(200,0,0) 527#define COL_PLAYER LCD_RGBPACK(200,200,200) 528#define COL_INVULN LCD_RGBPACK(100,100,200) 529#define COL_STARS LCD_WHITE 530#define COL_ASTEROID LCD_RGBPACK(ASTEROID_R,ASTEROID_G,ASTEROID_B) 531#define COL_TEXT LCD_RGBPACK(200,200,255) 532#define COL_ENEMY LCD_RGBPACK(ENEMY_R,ENEMY_G,ENEMY_B) 533#define SET_FG rb->lcd_set_foreground 534#define SET_BG rb->lcd_set_background 535#else 536#define SET_FG(x) 537#define SET_BG(x) 538#endif 539 540#define SCORE_FILE PLUGIN_GAMES_DATA_DIR "/spacerocks.score" 541#define NUM_SCORES 5 542 543static struct highscore highscores[NUM_SCORES]; 544 545/* The array of points that make up an asteroid */ 546static const short asteroid_one[NUM_ASTEROID_VERTICES*2] = 547{ 548 -2, -12, 549 4, -8, 550 8, -14, 551 16, -5, 552 14, 0, 553 20, 2, 554 12, 14, 555 -4, 14, 556 -10, 6, 557 -10, -8, 558}; 559 560/* The array of points that make up an asteroid */ 561static const short asteroid_two[NUM_ASTEROID_VERTICES*2] = 562{ 563 -2, -12, 564 4, -16, 565 6, -14, 566 16, -8, 567 14, 0, 568 20, 2, 569 12, 14, 570 -4, 14, 571 -10, 6, 572 -10, -8, 573}; 574 575/* The array of points that make up an asteroid */ 576static const short asteroid_three[NUM_ASTEROID_VERTICES*2] = 577{ 578 -2, -12, 579 4, -16, 580 6, -14, 581 2, -8, 582 14, 0, 583 20, 2, 584 12, 14, 585 -4, 14, 586 -16, 6, 587 -10, -8, 588}; 589 590/* The array of points the make up the ship */ 591static const short ship_vertices[NUM_SHIP_VERTICES*2] = 592{ 593#if (LARGE_LCD) 594 0, -6, 595 4, 6, 596 0, 2, 597 -4, 6, 598#else 599 0, -4, 600 3, 4, 601 0, 1, 602 -3, 4, 603#endif 604}; 605 606/* The array of points the make up the bad spaceship */ 607static const short enemy_vertices[NUM_ENEMY_VERTICES*2] = 608{ 609#if (LARGE_LCD) 610 -8, 0, 611 -4, 4, 612 4, 4, 613 8, 0, 614 -8, 0, 615 8, 0, 616 4, -4, 617 -4, -4, 618#else 619 -5, 0, 620 -2, 2, 621 2, 2, 622 5, 0, 623 -5, 0, 624 5, 0, 625 2, -2, 626 -2, -2, 627#endif 628}; 629 630enum asteroid_type 631{ 632#if (LARGE_LCD) 633 SMALL = 2, 634 MEDIUM = 4, 635 LARGE = 6, 636#else 637 SMALL = 1, 638 MEDIUM = 2, 639 LARGE = 3, 640#endif 641}; 642 643enum explosion_type 644{ 645 EXPLOSION_SHIP, 646 EXPLOSION_ASTEROID, 647 EXPLOSION_ENEMY, 648 EXPLOSION_THRUST, 649}; 650 651enum game_state 652{ 653 GAME_OVER, 654 SHOW_LEVEL, 655 PLAY_MODE, 656 PAUSE_MODE, 657}; 658 659struct Point 660{ 661 int x; 662 int y; 663 int dx; 664 int dy; 665}; 666 667struct TrailPoint 668{ 669 struct Point position; 670 int alive; 671#ifdef HAVE_LCD_COLOR 672 short r; 673 short g; 674 short b; 675 short dec; 676#endif 677}; 678 679/* Asteroid structure, contains an array of points */ 680struct Asteroid 681{ 682 struct Point position; 683 struct Point rotation; 684 struct Point vertices[NUM_ASTEROID_VERTICES]; 685 bool exists; 686 int explode_countdown; 687 enum asteroid_type type; 688 int radius; 689 long speed_cos; 690 long speed_sin; 691}; 692 693struct Ship 694{ 695 struct Point position; 696 struct Point rotation; 697 struct Point vertices[NUM_SHIP_VERTICES]; 698 bool exists; 699 int explode_countdown; 700 int invulnerable_time; 701}; 702 703struct Enemy 704{ 705 struct Point position; 706 struct Point vertices[NUM_ENEMY_VERTICES]; 707 bool exists; 708 int explode_countdown; 709 int appear_countdown; 710 short size_probability; 711 short appear_probability; 712 short appear_timing; 713}; 714 715struct Missile 716{ 717 struct Point position; 718 struct Point oldpoint; 719 int alive; 720}; 721 722static enum game_state game_state; 723static int asteroid_count; 724static int next_missile_count; 725static int next_thrust_count; 726static int num_lives; 727static int extra_life; 728static int show_level_timeout; 729static int current_level; 730static int current_score; 731 732static struct Ship ship; 733static struct Point stars[NUM_STARS]; 734static struct Asteroid asteroids_array[MAX_NUM_ASTEROIDS]; 735static struct Missile missiles_array[MAX_NUM_MISSILES]; 736static struct Missile enemy_missile; 737static struct Enemy enemy; 738static struct Point lives_points[NUM_SHIP_VERTICES]; 739static struct TrailPoint trail_points[NUM_TRAIL_POINTS]; 740 741/************************************************* 742** Handle polygon and point 743*************************************************/ 744 745/* Check if point is in a polygon */ 746static bool is_point_in_polygon(struct Point* vertices, int num_vertices, 747 int x, int y) 748{ 749 struct Point* pi; 750 struct Point* pj; 751 int n; 752 bool c = false; 753 754 if (x < -SCALED_WIDTH/2) x += SCALED_WIDTH; 755 else if (x > SCALED_WIDTH/2) x -= SCALED_WIDTH; 756 if (y < -SCALED_HEIGHT/2) y += SCALED_HEIGHT; 757 else if (y > SCALED_HEIGHT/2) y -= SCALED_HEIGHT; 758 759 pi = vertices; 760 pj = vertices + num_vertices-1; 761 762 n = num_vertices; 763 while (n--) 764 { 765 if ((((pi->y <= y) && (y < pj->y)) || ((pj->y <= y) && (y < pi->y))) && 766 (x < (pj->x - pi->x) * (y - pi->y) / (pj->y - pi->y) + pi->x)) 767 c = !c; 768 769 pj = pi; 770 pi++; 771 } 772 773 return c; 774} 775 776/* Check if point is within a rectangle */ 777static bool is_point_within_rectangle(struct Point* rect, struct Point* p, 778 int size) 779{ 780 int dx = p->x - rect->x; 781 int dy = p->y - rect->y; 782#if SHOW_COL 783 rb->lcd_drawrect((rect->x - size)/SCALE, (rect->y - size)/SCALE, 784 (size*2+1)/SCALE, (size*2+1)/SCALE); 785#endif 786 if (dx < -SCALED_WIDTH/2) dx += SCALED_WIDTH; 787 else if (dx > SCALED_WIDTH/2) dx -= SCALED_WIDTH; 788 if (dy < -SCALED_HEIGHT/2) dy += SCALED_HEIGHT; 789 else if (dy > SCALED_HEIGHT/2) dy -= SCALED_HEIGHT; 790 return (dx > -size && dx < size && dy > -size && dy < size); 791} 792 793/* Rotate polygon */ 794static void rotate_polygon(struct Point* vertices, int num_vertices, 795 struct Point* rotation, int cos, int sin) 796{ 797 struct Point* point; 798 int n; 799 long temp_x, temp_y; 800 801 temp_x = rotation->x; 802 temp_y = rotation->y; 803 rotation->x = (temp_x*cos - temp_y*sin)/SIN_COS_SCALE; 804 rotation->y = (temp_y*cos + temp_x*sin)/SIN_COS_SCALE; 805#define MIN_SCALE (SIN_COS_SCALE-10) 806#define MAX_SCALE (SIN_COS_SCALE+10) 807 /* normalize vector. this is not accurate but would be enough. */ 808 temp_x = rotation->x*rotation->x + rotation->y*rotation->y; 809 if (temp_x <= MIN_SCALE*MIN_SCALE) 810 { 811 rotation->x = rotation->x*SIN_COS_SCALE/MIN_SCALE; 812 rotation->y = rotation->y*SIN_COS_SCALE/MIN_SCALE; 813 } 814 else if (temp_x >= MAX_SCALE*MAX_SCALE) 815 { 816 rotation->x = rotation->x*SIN_COS_SCALE/MAX_SCALE; 817 rotation->y = rotation->y*SIN_COS_SCALE/MAX_SCALE; 818 } 819#undef MIN_SCALE 820#undef MAX_SCALE 821 822 point = vertices; 823 n = num_vertices; 824 while (n--) 825 { 826 point->x = (point->dx*rotation->x - point->dy*rotation->y)/SIN_COS_SCALE; 827 point->y = (point->dy*rotation->x + point->dx*rotation->y)/SIN_COS_SCALE; 828 point++; 829 } 830} 831 832/* Draw polygon */ 833static void draw_polygon(struct Point* vertices, int num_vertices, 834 int px, int py) 835{ 836 int n, new_x, new_y, old_x, old_y; 837 struct Point *p; 838 bool draw_wrap; 839 840 if (px > SCALED_WIDTH - WRAP_GAP) 841 px -= SCALED_WIDTH; 842 if (py > SCALED_HEIGHT - WRAP_GAP) 843 py -= SCALED_HEIGHT; 844 845 draw_wrap = (px < WRAP_GAP || py < WRAP_GAP); 846 847 p = vertices + num_vertices - 1; 848 old_x = (p->x + px)/SCALE; 849 old_y = (p->y + py)/SCALE; 850 p = vertices; 851 n = num_vertices; 852 while (n--) 853 { 854 new_x = (p->x + px)/SCALE; 855 new_y = (p->y + py)/SCALE; 856 857 rb->lcd_drawline(old_x, old_y, new_x, new_y); 858 if (draw_wrap) 859 { 860 rb->lcd_drawline(old_x + LCD_WIDTH, old_y, new_x + LCD_WIDTH, new_y); 861 rb->lcd_drawline(old_x, old_y + LCD_HEIGHT, new_x, new_y + LCD_HEIGHT); 862 rb->lcd_drawline(old_x + LCD_WIDTH, old_y + LCD_HEIGHT, 863 new_x + LCD_WIDTH, new_y + LCD_HEIGHT); 864 } 865 old_x = new_x; 866 old_y = new_y; 867 p++; 868 } 869} 870 871static void move_point(struct Point* point) 872{ 873 point->x += point->dx; 874 point->y += point->dy; 875 876 /* Check bounds on the x-axis: */ 877 point->x %= SCALED_WIDTH; 878 if (point->x < 0) 879 point->x += SCALED_WIDTH; 880 881 /* Check bounds on the y-axis: */ 882 point->y %= SCALED_HEIGHT; 883 if (point->y < 0) 884 point->y += SCALED_HEIGHT; 885} 886 887/************************************************* 888** Handle trail blaiz. 889*************************************************/ 890 891static void create_ship_trail(struct TrailPoint* tpoint) 892{ 893 tpoint->position.x += ship.vertices[2].x; 894 tpoint->position.y += ship.vertices[2].y; 895 tpoint->position.dx = -( ship.vertices[0].x - ship.vertices[2].x )/10; 896 tpoint->position.dy = -( ship.vertices[0].y - ship.vertices[2].y )/10; 897} 898 899static void create_explosion_trail(struct TrailPoint* tpoint) 900{ 901 tpoint->position.dx = (rb->rand()%5001)-2500; 902 tpoint->position.dy = (rb->rand()%5001)-2500; 903} 904 905static void create_trail_blaze(int colour, struct Point* position) 906{ 907 int numtoadd; 908 struct TrailPoint* tpoint; 909 int n; 910 911 if (colour != EXPLOSION_SHIP) 912 { 913 numtoadd = NUM_TRAIL_POINTS/5; 914 } 915 else 916 { 917 numtoadd = NUM_TRAIL_POINTS/8; 918 } 919 920 /* give the point a random countdown timer, so they dissapears at different 921 times */ 922 tpoint = trail_points; 923 n = NUM_TRAIL_POINTS; 924 while (n--) 925 { 926 /* find a space in the array of trail_points that is NULL or DEAD or 927 whatever and place this one here. */ 928 if (tpoint->alive <= 0) 929 { 930 /* take a random point near the position. */ 931 tpoint->position.x = (rb->rand()%18000)-9000 + position->x; 932 tpoint->position.y = (rb->rand()%18000)-9000 + position->y; 933 934 switch(colour) 935 { 936 case EXPLOSION_SHIP: 937 create_explosion_trail(tpoint); 938 tpoint->alive = 51; 939#ifdef HAVE_LCD_COLOR 940 tpoint->r = SHIP_R; 941 tpoint->g = SHIP_G; 942 tpoint->b = SHIP_B; 943 tpoint->dec = 2; 944#endif 945 break; 946 case EXPLOSION_ASTEROID: 947 create_explosion_trail(tpoint); 948 tpoint->alive = 51; 949#ifdef HAVE_LCD_COLOR 950 tpoint->r = ASTEROID_R; 951 tpoint->g = ASTEROID_G; 952 tpoint->b = ASTEROID_B; 953 tpoint->dec = 2; 954#endif 955 break; 956 case EXPLOSION_ENEMY: 957 create_explosion_trail(tpoint); 958 tpoint->alive = 51; 959#ifdef HAVE_LCD_COLOR 960 tpoint->r = ENEMY_R; 961 tpoint->g = ENEMY_G; 962 tpoint->b = ENEMY_B; 963 tpoint->dec = 2; 964#endif 965 break; 966 case EXPLOSION_THRUST: 967 create_ship_trail(tpoint); 968 tpoint->alive = 17; 969#ifdef HAVE_LCD_COLOR 970 tpoint->r = THRUST_R; 971 tpoint->g = THRUST_G; 972 tpoint->b = THRUST_B; 973 tpoint->dec = 4; 974#endif 975 break; 976 } 977 978 /* give the points a speed based on direction of travel 979 - i.e. opposite */ 980 tpoint->position.dx += position->dx; 981 tpoint->position.dy += position->dy; 982 983 numtoadd--; 984 if (numtoadd <= 0) 985 break; 986 } 987 tpoint++; 988 } 989} 990 991static void draw_and_move_trail_blaze(void) 992{ 993 struct TrailPoint* tpoint; 994 int n; 995 996 /* loop through, if alive then move and draw. 997 when drawn, countdown it's timer. 998 if zero kill it! */ 999 1000 tpoint = trail_points; 1001 n = NUM_TRAIL_POINTS; 1002 while (n--) 1003 { 1004 if (tpoint->alive > 0) 1005 { 1006 if (game_state != PAUSE_MODE) 1007 { 1008 tpoint->alive--; 1009 move_point(&(tpoint->position)); 1010#ifdef HAVE_LCD_COLOR 1011 /* intensity = tpoint->alive/2; */ 1012 if (tpoint->r >= tpoint->dec) tpoint->r -= tpoint->dec; 1013 if (tpoint->g >= tpoint->dec) tpoint->g -= tpoint->dec; 1014 if (tpoint->b >= tpoint->dec) tpoint->b -= tpoint->dec; 1015#endif 1016 } 1017 SET_FG(LCD_RGBPACK(tpoint->r, tpoint->g, tpoint->b)); 1018 rb->lcd_drawpixel(tpoint->position.x/SCALE, tpoint->position.y/SCALE); 1019 } 1020 tpoint++; 1021 } 1022} 1023 1024/************************************************* 1025** Handle asteroid. 1026*************************************************/ 1027 1028static void rotate_asteroid(struct Asteroid* asteroid) 1029{ 1030 rotate_polygon(asteroid->vertices, NUM_ASTEROID_VERTICES, 1031 &asteroid->rotation, 1032 asteroid->speed_cos, asteroid->speed_sin); 1033} 1034 1035/* Initialise the passed Asteroid. 1036 * if position is NULL, place it at the random loacation 1037 * where ship doesn't exist 1038 */ 1039static void initialise_asteroid(struct Asteroid* asteroid, 1040 enum asteroid_type type, struct Point *position) 1041{ 1042 const short *asteroid_vertices; 1043 struct Point* point; 1044 int n; 1045 1046 asteroid->exists = true; 1047 asteroid->explode_countdown = 0; 1048 asteroid->type = type; 1049 1050 /* Set the radius of the asteroid: */ 1051 asteroid->radius = (int)type*SCALE*3; 1052 1053 /* shall we move Clockwise and Fast */ 1054 n = rb->rand()%100; 1055 if (n < 25) 1056 { 1057 asteroid->speed_cos = FAST_ROT_CW_COS; 1058 asteroid->speed_sin = FAST_ROT_CW_SIN; 1059 } 1060 else if (n < 50) 1061 { 1062 asteroid->speed_cos = FAST_ROT_ACW_COS; 1063 asteroid->speed_sin = FAST_ROT_ACW_SIN; 1064 } 1065 else if (n < 75) 1066 { 1067 asteroid->speed_cos = SLOW_ROT_ACW_COS; 1068 asteroid->speed_sin = SLOW_ROT_ACW_SIN; 1069 } 1070 else 1071 { 1072 asteroid->speed_cos = SLOW_ROT_CW_COS; 1073 asteroid->speed_sin = SLOW_ROT_CW_SIN; 1074 } 1075 1076 n = rb->rand()%99; 1077 if (n < 33) 1078 asteroid_vertices = asteroid_one; 1079 else if (n < 66) 1080 asteroid_vertices = asteroid_two; 1081 else 1082 asteroid_vertices = asteroid_three; 1083 1084 point = asteroid->vertices; 1085 for(n = 0; n < NUM_ASTEROID_VERTICES*2; n += 2) 1086 { 1087 point->x = asteroid_vertices[n]; 1088 point->y = asteroid_vertices[n+1]; 1089 point->x *= asteroid->radius/20; 1090 point->y *= asteroid->radius/20; 1091 /* dx and dy are used when rotate polygon */ 1092 point->dx = point->x; 1093 point->dy = point->y; 1094 point++; 1095 } 1096 1097 if (!position) 1098 { 1099 do { 1100 /* Set the position randomly: */ 1101 asteroid->position.x = (rb->rand()%SCALED_WIDTH); 1102 asteroid->position.y = (rb->rand()%SCALED_HEIGHT); 1103 } while (is_point_within_rectangle(&ship.position, &asteroid->position, 1104 SPACE_CHECK_SIZE)); 1105 } 1106 else 1107 { 1108 asteroid->position.x = position->x; 1109 asteroid->position.y = position->y; 1110 } 1111 1112 do { 1113 asteroid->position.dx = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2; 1114 } while (asteroid->position.dx == 0); 1115 1116 do { 1117 asteroid->position.dy = (rb->rand()%ASTEROID_SPEED)-ASTEROID_SPEED/2; 1118 } while (asteroid->position.dy == 0); 1119 1120 asteroid->position.dx *= SCALE/10; 1121 asteroid->position.dy *= SCALE/10; 1122 1123 asteroid->rotation.x = SIN_COS_SCALE; 1124 asteroid->rotation.y = 0; 1125 1126 /* Now rotate the asteroid a bit, so they all look a bit different */ 1127 for(n = (rb->rand()%30)+2; n--; ) 1128 rotate_asteroid(asteroid); 1129 1130 /* great, we've created an asteroid, don't forget to increment the total: */ 1131 asteroid_count++; 1132} 1133 1134/* 1135 * Creates a new asteroid of the given 4type (size) and at the given location. 1136 */ 1137static void create_asteroid(enum asteroid_type type, struct Point *position) 1138{ 1139 struct Asteroid* asteroid; 1140 int n; 1141 1142 asteroid = asteroids_array; 1143 n = MAX_NUM_ASTEROIDS; 1144 while (n--) 1145 { 1146 if (!asteroid->exists && asteroid->explode_countdown <= 0) 1147 { 1148 initialise_asteroid(asteroid, type, position); 1149 break; 1150 } 1151 asteroid++; 1152 } 1153} 1154 1155/* Draw and move all asteroids */ 1156static void draw_and_move_asteroids(void) 1157{ 1158 struct Asteroid* asteroid; 1159 int n; 1160 1161 SET_FG(COL_ASTEROID); 1162 1163 asteroid = asteroids_array; 1164 n = MAX_NUM_ASTEROIDS; 1165 while (n--) 1166 { 1167 if (asteroid->exists) 1168 { 1169 draw_polygon(asteroid->vertices, NUM_ASTEROID_VERTICES, 1170 asteroid->position.x, asteroid->position.y); 1171 } 1172 if (game_state != PAUSE_MODE) 1173 { 1174 if (asteroid->exists) 1175 { 1176 move_point(&asteroid->position); 1177 rotate_asteroid(asteroid); 1178 } 1179 else if (asteroid->explode_countdown > 0) 1180 { 1181 asteroid->explode_countdown--; 1182 } 1183 } 1184 asteroid++; 1185 } 1186} 1187 1188static void explode_asteroid(struct Asteroid* asteroid) 1189{ 1190 struct Point p; 1191 p.dx = asteroid->position.dx; 1192 p.dy = asteroid->position.dy; 1193 p.x = asteroid->position.x; 1194 p.y = asteroid->position.y; 1195 1196 asteroid_count--; 1197 asteroid->exists = false; 1198 1199 switch(asteroid->type) 1200 { 1201 case SMALL: 1202 asteroid->explode_countdown = EXPLOSION_LENGTH; 1203 create_trail_blaze(EXPLOSION_ASTEROID, &p); 1204 break; 1205 1206 case MEDIUM: 1207 create_asteroid(SMALL, &p); 1208 create_asteroid(SMALL, &p); 1209 break; 1210 1211 case LARGE: 1212 create_asteroid(MEDIUM, &p); 1213 create_asteroid(MEDIUM, &p); 1214 break; 1215 } 1216} 1217 1218/************************************************* 1219** Handle ship. 1220*************************************************/ 1221 1222/* Initialise the ship */ 1223static void initialise_ship(void) 1224{ 1225 struct Point* point; 1226 struct Point* lives_point; 1227 int n; 1228 1229 ship.position.x = CENTER_LCD_X * SCALE; 1230 ship.position.y = CENTER_LCD_Y * SCALE; 1231 ship.position.dx = 0; 1232 ship.position.dy = 0; 1233 ship.rotation.x = SIN_COS_SCALE; 1234 ship.rotation.y = 0; 1235 ship.exists = true; 1236 ship.explode_countdown = 0; 1237 ship.invulnerable_time = INVULNERABLE_TIME; 1238 1239 point = ship.vertices; 1240 lives_point = lives_points; 1241 for(n = 0; n < NUM_SHIP_VERTICES*2; n += 2) 1242 { 1243 point->x = ship_vertices[n]; 1244 point->y = ship_vertices[n+1]; 1245 point->x *= SCALE; 1246 point->y *= SCALE; 1247 /* dx and dy are used when rotate polygon */ 1248 point->dx = point->x; 1249 point->dy = point->y; 1250 /* grab a copy of the ships points for the lives display: */ 1251 lives_point->x = point->x; 1252 lives_point->y = point->y; 1253 1254 point++; 1255 lives_point++; 1256 } 1257} 1258 1259/* 1260 * Draws the ship, moves the ship and creates a new 1261 * one if it's finished exploding. 1262 */ 1263static void draw_and_move_ship(void) 1264{ 1265 if (ship.invulnerable_time > BLINK_TIME || ship.invulnerable_time % 2 != 0) 1266 { 1267 SET_FG(COL_INVULN); 1268 } 1269 else 1270 { 1271 SET_FG(COL_PLAYER); 1272 } 1273 1274 if (ship.exists) 1275 { 1276 draw_polygon(ship.vertices, NUM_SHIP_VERTICES, 1277 ship.position.x, ship.position.y); 1278 } 1279 1280 if (game_state != PAUSE_MODE) 1281 { 1282 if (ship.exists) 1283 { 1284 if (ship.invulnerable_time > 0) 1285 ship.invulnerable_time--; 1286 move_point(&ship.position); 1287 } 1288 else if (ship.explode_countdown > 0) 1289 { 1290 ship.explode_countdown--; 1291 if (ship.explode_countdown <= 0) 1292 { 1293 num_lives--; 1294 if (num_lives <= 0) 1295 { 1296 game_state = GAME_OVER; 1297 } 1298 else 1299 { 1300 initialise_ship(); 1301 } 1302 } 1303 } 1304 } 1305} 1306 1307static void explode_ship(void) 1308{ 1309 if (!ship.invulnerable_time) 1310 { 1311 /* if not invulnerable, blow up ship */ 1312 ship.explode_countdown = EXPLOSION_LENGTH; 1313 ship.exists = false; 1314 create_trail_blaze(EXPLOSION_SHIP, &ship.position); 1315 } 1316} 1317 1318/* Rotate the ship using the passed sin & cos values */ 1319static void rotate_ship(int cos, int sin) 1320{ 1321 if (ship.exists) 1322 { 1323 rotate_polygon(ship.vertices, NUM_SHIP_VERTICES, 1324 &ship.rotation, cos, sin); 1325 } 1326} 1327 1328static void thrust_ship(void) 1329{ 1330 if (ship.exists) 1331 { 1332 ship.position.dx += ( ship.vertices[0].x - ship.vertices[2].x )/20; 1333 ship.position.dy += ( ship.vertices[0].y - ship.vertices[2].y )/20; 1334 1335 /* if dx and dy are below a certain threshold, then set 'em to 0 1336 but to do this we need to ascertain if the spacehip as moved on 1337 screen for more than a certain amount. */ 1338 1339 create_trail_blaze(EXPLOSION_THRUST, &ship.position); 1340 } 1341} 1342 1343/* stop movement of ship, 'cos that's what happens when you go into hyperspace. */ 1344static void hyperspace(void) 1345{ 1346 if (ship.exists) 1347 { 1348 ship.position.dx = ship.position.dy = 0; 1349 ship.position.x = (rb->rand()%SCALED_WIDTH); 1350 ship.position.y = (rb->rand()%SCALED_HEIGHT); 1351 } 1352} 1353 1354static void draw_lives(void) 1355{ 1356 int n; 1357#if (LARGE_LCD) 1358 int px = (LCD_WIDTH-1 - 4)*SCALE; 1359 int py = (LCD_HEIGHT-1 - 6)*SCALE; 1360#else 1361 int px = (LCD_WIDTH-1 - 3)*SCALE; 1362 int py = (LCD_HEIGHT-1 - 4)*SCALE; 1363#endif 1364 1365 SET_FG(COL_PLAYER); 1366 1367 n = num_lives-1; 1368 while (n--) 1369 { 1370 draw_polygon(lives_points, NUM_SHIP_VERTICES, px, py); 1371#if (LARGE_LCD) 1372 px -= 8*SCALE; 1373#else 1374 px -= 6*SCALE; 1375#endif 1376 } 1377} 1378 1379/* 1380 * missile 1381 */ 1382 1383/* Initialise a missile */ 1384static void initialise_missile(struct Missile* missile) 1385{ 1386 missile->position.x = ship.position.x + ship.vertices[0].x; 1387 missile->position.y = ship.position.y + ship.vertices[0].y; 1388 missile->position.dx = (ship.vertices[0].x - ship.vertices[2].x)/2; 1389 missile->position.dy = (ship.vertices[0].y - ship.vertices[2].y)/2; 1390 missile->alive = MISSILE_LIFE_LENGTH; 1391 missile->oldpoint.x = missile->position.x; 1392 missile->oldpoint.y = missile->position.y; 1393} 1394 1395/* Fire the next missile */ 1396static void fire_missile(void) 1397{ 1398 struct Missile* missile; 1399 int n; 1400 1401 if (ship.exists) 1402 { 1403 missile = missiles_array; 1404 n = MAX_NUM_MISSILES; 1405 while (n--) 1406 { 1407 if (missile->alive <= 0) 1408 { 1409 initialise_missile(missile); 1410 break; 1411 } 1412 missile++; 1413 } 1414 } 1415} 1416 1417/* Draw and Move all the missiles */ 1418static void draw_and_move_missiles(void) 1419{ 1420 struct Missile* missile; 1421 struct Point vertices[2]; 1422 int n; 1423 1424 SET_FG(COL_MISSILE); 1425 1426 missile = missiles_array; 1427 n = MAX_NUM_MISSILES; 1428 while (n--) 1429 { 1430 if (missile->alive > 0) 1431 { 1432 vertices[0].x = 0; 1433 vertices[0].y = 0; 1434 vertices[1].x = -missile->position.dx; 1435 vertices[1].y = -missile->position.dy; 1436 draw_polygon(vertices, 2, missile->position.x, missile->position.y); 1437 1438 if (game_state != PAUSE_MODE) 1439 { 1440 missile->oldpoint.x = missile->position.x; 1441 missile->oldpoint.y = missile->position.y; 1442 move_point(&missile->position); 1443 missile->alive--; 1444 } 1445 } 1446 missile++; 1447 } 1448} 1449 1450/************************************************* 1451** Handle enemy. 1452*************************************************/ 1453 1454static void initialise_enemy(void) 1455{ 1456 struct Point* point; 1457 int n; 1458 int size; 1459 1460 if (rb->rand()%100 > enemy.size_probability) 1461 { 1462 size = BIG_SHIP; 1463 enemy.size_probability++; 1464 if (enemy.size_probability > 90) 1465 { 1466 enemy.size_probability = ENEMY_BIG_PROBABILITY_START; 1467 } 1468 } 1469 else 1470 { 1471 size = LITTLE_SHIP; 1472 enemy.size_probability = ENEMY_BIG_PROBABILITY_START; 1473 } 1474 1475 enemy.exists = true; 1476 enemy.explode_countdown = 0; 1477 enemy.appear_countdown = enemy.appear_timing; 1478 1479 point = enemy.vertices; 1480 for(n = 0; n < NUM_ENEMY_VERTICES*2; n += 2) 1481 { 1482 point->x = enemy_vertices[n]; 1483 point->y = enemy_vertices[n+1]; 1484 point->x *= size*SCALE/2; 1485 point->y *= size*SCALE/2; 1486 point++; 1487 } 1488 1489 if (ship.position.x >= SCALED_WIDTH/2) 1490 { 1491 enemy.position.dx = ENEMY_SPEED; 1492 enemy.position.x = 0; 1493 } 1494 else 1495 { 1496 enemy.position.dx = -ENEMY_SPEED; 1497 enemy.position.x = SCALED_WIDTH; 1498 } 1499 1500 if (ship.position.y >= SCALED_HEIGHT/2) 1501 { 1502 enemy.position.dy = ENEMY_SPEED; 1503 enemy.position.y = 0; 1504 } 1505 else 1506 { 1507 enemy.position.dy = -ENEMY_SPEED; 1508 enemy.position.y = SCALED_HEIGHT; 1509 } 1510 1511 enemy.position.dx *= SCALE/10; 1512 enemy.position.dy *= SCALE/10; 1513} 1514 1515static void draw_and_move_enemy(void) 1516{ 1517 SET_FG(COL_ENEMY); 1518 1519 if (enemy.exists) 1520 { 1521 draw_polygon(enemy.vertices, NUM_ENEMY_VERTICES, 1522 enemy.position.x, enemy.position.y); 1523 } 1524 1525 if (game_state != PAUSE_MODE) 1526 { 1527 if (enemy.exists) 1528 { 1529 enemy.position.x += enemy.position.dx; 1530 enemy.position.y += enemy.position.dy; 1531 1532 if (enemy.position.x > SCALED_WIDTH || enemy.position.x < 0) 1533 enemy.exists = false; 1534 1535 enemy.position.y %= SCALED_HEIGHT; 1536 if (enemy.position.y < 0) 1537 enemy.position.y += SCALED_HEIGHT; 1538 1539 if ((rb->rand()%1000) < 10) 1540 enemy.position.dy = -enemy.position.dy; 1541 } 1542 else if (enemy.explode_countdown > 0) 1543 { 1544 enemy.explode_countdown--; 1545 } 1546 else 1547 { 1548 if (enemy.appear_countdown > 0) 1549 enemy.appear_countdown--; 1550 else if (rb->rand()%100 >= enemy.appear_probability) 1551 initialise_enemy(); 1552 } 1553 } 1554 1555 if (enemy_missile.alive <= 0) 1556 { 1557 /* if no missile and the enemy is here and not exploding.. 1558 then shoot baby! */ 1559 if (enemy.exists && ship.exists && 1560 game_state == PLAY_MODE && (rb->rand()%10) >= 5 ) 1561 { 1562 int dx = ship.position.x - enemy.position.x; 1563 int dy = ship.position.y - enemy.position.y; 1564 1565 if (dx < -SCALED_WIDTH/2) dx += SCALED_WIDTH; 1566 else if (dx > SCALED_WIDTH/2) dx -= SCALED_WIDTH; 1567 if (dy < -SCALED_HEIGHT/2) dy += SCALED_HEIGHT; 1568 else if (dy > SCALED_HEIGHT/2) dy -= SCALED_HEIGHT; 1569 1570 enemy_missile.position.x = enemy.position.x; 1571 enemy_missile.position.y = enemy.position.y; 1572 1573 /* lame, needs to be sorted - it's trying to shoot at the ship */ 1574 if (dx < -5*SCALE) 1575 enemy_missile.position.dx = -1; 1576 else if (dx > 5*SCALE) 1577 enemy_missile.position.dx = 1; 1578 else 1579 enemy_missile.position.dx = 0; 1580 1581 if (dy < -5*SCALE) 1582 enemy_missile.position.dy = -1; 1583 else if (dy > 5*SCALE) 1584 enemy_missile.position.dy = 1; 1585 else 1586 enemy_missile.position.dy = 0; 1587 1588 while (enemy_missile.position.dx == 0 && 1589 enemy_missile.position.dy == 0) 1590 { 1591 enemy_missile.position.dx = rb->rand()%2-1; 1592 enemy_missile.position.dy = rb->rand()%2-1; 1593 } 1594 1595 enemy_missile.position.dx *= SCALE; 1596 enemy_missile.position.dy *= SCALE; 1597 enemy_missile.alive = ENEMY_MISSILE_LIFE_LENGTH; 1598 } 1599 } 1600 else 1601 { 1602 rb->lcd_fillrect( enemy_missile.position.x/SCALE, 1603 enemy_missile.position.y/SCALE, 1604 POINT_SIZE, POINT_SIZE ); 1605 if (game_state != PAUSE_MODE) 1606 { 1607 move_point(&enemy_missile.position); 1608 enemy_missile.alive--; 1609 } 1610 } 1611} 1612 1613/************************************************* 1614** Check collisions. 1615*************************************************/ 1616 1617/* Add score if missile hit asteroid or enemy */ 1618static void add_score(int val) 1619{ 1620 current_score += val; 1621 if (current_score >= extra_life) 1622 { 1623 num_lives++; 1624 extra_life += EXTRA_LIFE; 1625 } 1626} 1627 1628static bool is_point_within_asteroid(struct Asteroid* asteroid, 1629 struct Point* point) 1630{ 1631 if (is_point_within_rectangle(&asteroid->position, point, asteroid->radius) 1632 && is_point_in_polygon(asteroid->vertices, NUM_ASTEROID_VERTICES, 1633 point->x - asteroid->position.x, 1634 point->y - asteroid->position.y)) 1635 { 1636 explode_asteroid(asteroid); 1637 return true; 1638 } 1639 else 1640 return false; 1641} 1642 1643static bool is_point_within_ship(struct Point* point) 1644{ 1645 if (is_point_within_rectangle(&ship.position, point, SIZE_SHIP_COLLISION) 1646 && is_point_in_polygon(ship.vertices, NUM_SHIP_VERTICES, 1647 point->x - ship.position.x, 1648 point->y - ship.position.y)) 1649 { 1650 return true; 1651 } 1652 else 1653 return false; 1654} 1655 1656static bool is_point_within_enemy(struct Point* point) 1657{ 1658 if (is_point_within_rectangle(&enemy.position, point, SIZE_ENEMY_COLLISION)) 1659 { 1660 add_score(5); 1661 enemy.explode_countdown = EXPLOSION_LENGTH; 1662 enemy.exists = false; 1663 create_trail_blaze(EXPLOSION_ENEMY, &enemy.position); 1664 return true; 1665 } 1666 else 1667 return false; 1668} 1669 1670static bool is_ship_within_asteroid(struct Asteroid* asteroid) 1671{ 1672 struct Point p; 1673 1674 if (!is_point_within_rectangle(&asteroid->position, &ship.position, 1675 asteroid->radius+SIZE_SHIP_COLLISION)) 1676 return false; 1677 1678 p.x = ship.position.x + ship.vertices[0].x; 1679 p.y = ship.position.y + ship.vertices[0].y; 1680 if (is_point_within_asteroid(asteroid, &p)) 1681 return true; 1682 1683 p.x = ship.position.x + ship.vertices[1].x; 1684 p.y = ship.position.y + ship.vertices[1].y; 1685 if (is_point_within_asteroid(asteroid, &p)) 1686 return true; 1687 1688 p.x = ship.position.x + ship.vertices[3].x; 1689 p.y = ship.position.y + ship.vertices[3].y; 1690 if (is_point_within_asteroid(asteroid, &p)) 1691 return true; 1692 1693 return false; 1694} 1695 1696/* Check for collsions between the missiles and the asteroids and the ship */ 1697static void check_collisions(void) 1698{ 1699 struct Missile* missile; 1700 struct Asteroid* asteroid; 1701 int m, n; 1702 bool asteroids_onscreen = false; 1703 1704 asteroid = asteroids_array; 1705 m = MAX_NUM_ASTEROIDS; 1706 while (m--) 1707 { 1708 /* if the asteroids exists then test missile collision: */ 1709 if (asteroid->exists) 1710 { 1711 missile = missiles_array; 1712 n = MAX_NUM_MISSILES; 1713 while (n--) 1714 { 1715 /* if the missiles exists: */ 1716 if (missile->alive > 0) 1717 { 1718 /* has the missile hit the asteroid? */ 1719 if (is_point_within_asteroid(asteroid, &missile->position) || 1720 is_point_within_asteroid(asteroid, &missile->oldpoint)) 1721 { 1722 add_score(1); 1723 missile->alive = 0; 1724 break; 1725 } 1726 } 1727 missile++; 1728 } 1729 1730 /* now check collision with ship: */ 1731 if (asteroid->exists && ship.exists) 1732 { 1733 if (is_ship_within_asteroid(asteroid)) 1734 { 1735 add_score(1); 1736 explode_ship(); 1737 } 1738 } 1739 1740 /* has the enemy missile blown something up? */ 1741 if (asteroid->exists && enemy_missile.alive > 0) 1742 { 1743 if (is_point_within_asteroid(asteroid, &enemy_missile.position)) 1744 { 1745 enemy_missile.alive = 0; 1746 } 1747 } 1748 } 1749 1750 /* is an asteroid still exploding? */ 1751 if (asteroid->explode_countdown > 0) 1752 asteroids_onscreen = true; 1753 1754 asteroid++; 1755 } 1756 1757 /* now check collision between ship and enemy */ 1758 if (enemy.exists && ship.exists) 1759 { 1760 /* has the enemy collided with the ship? */ 1761 if (is_point_within_enemy(&ship.position)) 1762 { 1763 explode_ship(); 1764 create_trail_blaze(EXPLOSION_ENEMY, &enemy.position); 1765 } 1766 1767 if (enemy.exists) 1768 { 1769 /* Now see if the enemy has been shot at by the ships missiles: */ 1770 missile = missiles_array; 1771 n = MAX_NUM_MISSILES; 1772 while (n--) 1773 { 1774 if (missile->alive > 0 && 1775 is_point_within_enemy(&missile->position)) 1776 { 1777 missile->alive = 0; 1778 break; 1779 } 1780 missile++; 1781 } 1782 } 1783 } 1784 1785 /* test collision with enemy missile and ship: */ 1786 if (enemy_missile.alive > 0 && is_point_within_ship(&enemy_missile.position)) 1787 { 1788 explode_ship(); 1789 enemy_missile.alive = 0; 1790 enemy_missile.position.x = enemy_missile.position.y = 0; 1791 } 1792 1793 /* if all asteroids cleared then start again: */ 1794 if (asteroid_count == 0 && !asteroids_onscreen 1795 && !enemy.exists && enemy.explode_countdown <= 0) 1796 { 1797 current_level++; 1798 if (current_level > MAX_LEVEL) 1799 current_level = START_LEVEL; 1800 enemy.appear_probability += 5; 1801 if (enemy.appear_probability >= 100) 1802 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START; 1803 enemy.appear_timing -= 30; 1804 if (enemy.appear_timing < 30) 1805 enemy.appear_timing = 30; 1806 game_state = SHOW_LEVEL; 1807 show_level_timeout = SHOW_LEVEL_TIME; 1808 } 1809} 1810 1811/* 1812 * stars 1813 */ 1814 1815static void create_stars(void) 1816{ 1817 struct Point* p; 1818 int n; 1819 1820 p = stars; 1821 n = NUM_STARS; 1822 while (n--) 1823 { 1824 p->x = (rb->rand()%LCD_WIDTH); 1825 p->y = (rb->rand()%LCD_HEIGHT); 1826 p++; 1827 } 1828} 1829 1830static void drawstars(void) 1831{ 1832 struct Point* p; 1833 int n; 1834 1835 SET_FG(COL_STARS); 1836 1837 p = stars; 1838 n = NUM_STARS; 1839 while (n--) 1840 { 1841 rb->lcd_drawpixel(p->x , p->y); 1842 p++; 1843 } 1844} 1845 1846/************************************************* 1847** Creates start_num number of new asteroids of 1848** full size. 1849**************************************************/ 1850static void initialise_level(int start_num) 1851{ 1852 struct Asteroid* asteroid; 1853 struct Missile* missile; 1854 struct TrailPoint* tpoint; 1855 int n; 1856 asteroid_count = next_missile_count = next_thrust_count = 0; 1857 1858 /* no enemy */ 1859 enemy.exists = 0; 1860 enemy.explode_countdown = 0; 1861 enemy_missile.alive = 0; 1862 1863 /* clear asteroids */ 1864 asteroid = asteroids_array; 1865 n = MAX_NUM_ASTEROIDS; 1866 while (n--) 1867 { 1868 asteroid->exists = false; 1869 asteroid++; 1870 } 1871 1872 /* make some LARGE asteroids */ 1873 for(n = 0; n < start_num; n++) 1874 initialise_asteroid(&asteroids_array[n], LARGE, NULL); 1875 1876 /* ensure all missiles are out of action: */ 1877 missile = missiles_array; 1878 n = MAX_NUM_MISSILES; 1879 while (n--) 1880 { 1881 missile->alive = 0; 1882 missile++; 1883 } 1884 1885 tpoint = trail_points; 1886 n = NUM_TRAIL_POINTS; 1887 while (n--) 1888 { 1889 tpoint->alive = 0; 1890 tpoint++; 1891 } 1892} 1893 1894static void initialise_game(void) 1895{ 1896 enemy.appear_probability = ENEMY_APPEAR_PROBABILITY_START; 1897 enemy.appear_timing = ENEMY_APPEAR_TIMING_START; 1898 enemy.appear_countdown = enemy.appear_timing; 1899 enemy.size_probability = ENEMY_BIG_PROBABILITY_START; 1900 current_level = START_LEVEL; 1901 num_lives = START_LIVES; 1902 extra_life = EXTRA_LIFE; 1903 current_score = 0; 1904 initialise_ship(); 1905 initialise_level(0); 1906 game_state = SHOW_LEVEL; 1907 show_level_timeout = SHOW_LEVEL_TIME; 1908} 1909 1910/* menu stuff */ 1911static bool spacerocks_help(void) 1912{ 1913 static char *help_text[] = { 1914 "Spacerocks", "", "Aim", "", 1915 "The", "goal", "of", "the", "game", "is", "to", "blow", "up", 1916 "the", "asteroids", "and", "avoid", "being", "hit", "by", "them.", 1917 "Also", "you'd", "better", "watch", "out", "for", "the", "UFOs!" 1918 }; 1919 static struct style_text formation[]={ 1920 { 0, TEXT_CENTER|TEXT_UNDERLINE }, 1921 { 2, C_RED }, 1922 LAST_STYLE_ITEM 1923 }; 1924 1925 rb->lcd_setfont(FONT_UI); 1926 SET_BG(LCD_BLACK); 1927 SET_FG(LCD_WHITE); 1928 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true)) 1929 return true; 1930 rb->lcd_setfont(FONT_SYSFIXED); 1931 1932 return false; 1933} 1934 1935#define PLUGIN_OTHER 10 1936static bool ingame; 1937static int spacerocks_menu_cb(int action, 1938 const struct menu_item_ex *this_item, 1939 struct gui_synclist *this_list) 1940{ 1941 (void)this_list; 1942 if (action == ACTION_REQUEST_MENUITEM 1943 && !ingame && ((intptr_t)this_item)==0) 1944 return ACTION_EXIT_MENUITEM; 1945 return action; 1946} 1947 1948static int spacerocks_menu(void) 1949{ 1950 int selection = 0; 1951 MENUITEM_STRINGLIST(main_menu, "Spacerocks Menu", spacerocks_menu_cb, 1952 "Resume Game", "Start New Game", 1953 "Help", "High Scores", 1954 "Playback Control", "Quit"); 1955 rb->button_clear_queue(); 1956 1957 while (1) 1958 { 1959 switch (rb->do_menu(&main_menu, &selection, NULL, false)) 1960 { 1961 case 0: 1962 return PLUGIN_OTHER; 1963 case 1: 1964 initialise_game(); 1965 return PLUGIN_OTHER; 1966 case 2: 1967 if (spacerocks_help()) 1968 return PLUGIN_USB_CONNECTED; 1969 break; 1970 case 3: 1971 highscore_show(-1, highscores, NUM_SCORES, true); 1972 break; 1973 case 4: 1974 playback_control(NULL); 1975 break; 1976 case 5: 1977 return PLUGIN_OK; 1978 case MENU_ATTACHED_USB: 1979 return PLUGIN_USB_CONNECTED; 1980 default: 1981 break; 1982 } 1983 } 1984} 1985 1986static int spacerocks_game_loop(void) 1987{ 1988 int button; 1989 int end; 1990 int position; 1991 int ret; 1992 1993 if ((ret = spacerocks_menu()) != PLUGIN_OTHER) 1994 return ret; 1995 1996 SET_BG(LCD_BLACK); 1997 1998 ingame = true; 1999 while (true) 2000 { 2001 end = *rb->current_tick + (CYCLETIME * HZ) / 1000; 2002 rb->lcd_clear_display(); 2003 SET_FG(COL_TEXT); 2004 switch(game_state) 2005 { 2006 case GAME_OVER: 2007 ingame = false; 2008 rb->splash (HZ * 2, "Game Over"); 2009 rb->lcd_clear_display(); 2010 position = highscore_update(current_score, current_level, "", 2011 highscores, NUM_SCORES); 2012 if (position != -1) 2013 { 2014 if (position == 0) 2015 rb->splash(HZ*2, "New High Score"); 2016 highscore_show(position, highscores, NUM_SCORES, true); 2017 } 2018 return PLUGIN_OTHER; 2019 break; 2020 2021 case PAUSE_MODE: 2022 rb->lcd_putsxyf(1,LCD_HEIGHT-8, "score %d ", current_score); 2023 rb->lcd_putsxy(CENTER_LCD_X - 15, 2024 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, "pause"); 2025 draw_and_move_missiles(); 2026 draw_lives(); 2027 draw_and_move_ship(); 2028 break; 2029 2030 case PLAY_MODE: 2031 rb->lcd_putsxyf(1, LCD_HEIGHT-8, "score %d ", current_score); 2032 draw_and_move_missiles(); 2033 draw_lives(); 2034 check_collisions(); 2035 draw_and_move_ship(); 2036 break; 2037 2038 case SHOW_LEVEL: 2039 rb->lcd_putsxyf(1, LCD_HEIGHT-8, "score %d ", current_score); 2040 rb->lcd_putsxyf(CENTER_LCD_X - 20, 2041 CENTER_LCD_Y + CENTER_LCD_Y/2 - 4, 2042 "stage %d ", current_level); 2043 draw_lives(); 2044 draw_and_move_ship(); 2045 show_level_timeout--; 2046 if (show_level_timeout <= 0) 2047 { 2048 initialise_level(current_level); 2049 game_state = PLAY_MODE; 2050 } 2051 break; 2052 } 2053 draw_and_move_trail_blaze(); 2054 drawstars(); 2055 draw_and_move_asteroids(); 2056 draw_and_move_enemy(); 2057 2058 rb->lcd_update(); 2059 2060#ifdef HAS_BUTTON_HOLD 2061 if (rb->button_hold() && game_state == PLAY_MODE) 2062 game_state = PAUSE_MODE; 2063#endif 2064 button = rb->button_get(false); 2065 switch(button) 2066 { 2067 case(AST_QUIT): 2068 return PLUGIN_OTHER; 2069 break; 2070#ifdef AST_PAUSE 2071 case(AST_PAUSE): 2072 if (game_state == PAUSE_MODE) 2073 game_state = PLAY_MODE; 2074 else if (game_state == PLAY_MODE) 2075 game_state = PAUSE_MODE; 2076 break; 2077#endif 2078 case (AST_LEFT): 2079 case (AST_LEFT | BUTTON_REPEAT): 2080 if (game_state == PLAY_MODE || game_state == SHOW_LEVEL) 2081 rotate_ship(SHIP_ROT_ACW_COS, SHIP_ROT_ACW_SIN); 2082 break; 2083 2084 case (AST_RIGHT): 2085 case (AST_RIGHT | BUTTON_REPEAT): 2086 if (game_state == PLAY_MODE || game_state == SHOW_LEVEL) 2087 rotate_ship(SHIP_ROT_CW_COS, SHIP_ROT_CW_SIN); 2088 break; 2089 2090 case (AST_THRUST): 2091 case (AST_THRUST | BUTTON_REPEAT): 2092 if (game_state == PLAY_MODE || game_state == SHOW_LEVEL) 2093 { 2094 if (next_thrust_count <= 0) 2095 { 2096 next_thrust_count = 5; 2097 thrust_ship(); 2098 } 2099 } 2100 break; 2101 2102 case (AST_HYPERSPACE): 2103 if (game_state == PLAY_MODE) 2104 hyperspace(); 2105 /* maybe shield if it gets too hard */ 2106 break; 2107 2108 case (AST_FIRE): 2109 case (AST_FIRE | BUTTON_REPEAT): 2110 if (game_state == PLAY_MODE) 2111 { 2112 if (next_missile_count <= 0) 2113 { 2114 fire_missile(); 2115 next_missile_count = 10; 2116 } 2117 } 2118 else if(game_state == PAUSE_MODE) 2119 game_state = PLAY_MODE; 2120 break; 2121 2122 default: 2123 if (rb->default_event_handler(button)==SYS_USB_CONNECTED) 2124 return PLUGIN_USB_CONNECTED; 2125 break; 2126 } 2127 2128 if (next_missile_count > 0) 2129 next_missile_count--; 2130 2131 if (next_thrust_count > 0) 2132 next_thrust_count--; 2133 2134 if (TIME_BEFORE(*rb->current_tick, end)) 2135 rb->sleep(end-*rb->current_tick); 2136 else 2137 rb->yield(); 2138 } 2139} 2140 2141enum plugin_status plugin_start(const void* parameter) 2142{ 2143 (void)parameter; 2144 int ret = PLUGIN_OTHER; 2145 2146#if LCD_DEPTH > 1 2147 rb->lcd_set_backdrop(NULL); 2148#endif 2149 /* universal font */ 2150 rb->lcd_setfont(FONT_SYSFIXED); 2151 2152 /* Turn off backlight timeout */ 2153 backlight_ignore_timeout(); 2154 2155 highscore_load(SCORE_FILE, highscores, NUM_SCORES); 2156 rb->srand(*rb->current_tick); 2157 2158 /* create stars once, and once only: */ 2159 create_stars(); 2160 2161 while (ret == PLUGIN_OTHER) 2162 ret = spacerocks_game_loop(); 2163 2164 rb->lcd_setfont(FONT_UI); 2165 highscore_save(SCORE_FILE, highscores, NUM_SCORES); 2166 2167 /* Turn on backlight timeout (revert to settings) */ 2168 backlight_use_settings(); 2169 2170 return ret; 2171}