A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 722 lines 14 kB view raw
1/* 2 * xrick/game.c 3 * 4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net). 5 * Copyright (C) 2008-2014 Pierluigi Vicinanza. 6 * All rights reserved. 7 * 8 * The use and distribution terms for this software are contained in the file 9 * named README, which can be found in the root of this distribution. By 10 * using this software in any fashion, you are agreeing to be bound by the 11 * terms of this license. 12 * 13 * You must not remove this notice, or any other, from this software. 14 */ 15 16#include "xrick/game.h" 17 18#include "xrick/draw.h" 19#include "xrick/maps.h" 20#include "xrick/ents.h" 21#include "xrick/e_rick.h" 22#include "xrick/e_sbonus.h" 23#include "xrick/e_them.h" 24#include "xrick/screens.h" 25#include "xrick/rects.h" 26#include "xrick/scroller.h" 27#include "xrick/control.h" 28#include "xrick/resources.h" 29 30#ifdef ENABLE_DEVTOOLS 31#include "xrick/devtools.h" 32#endif 33 34 35/* 36 * local typedefs 37 */ 38typedef enum { 39#ifdef ENABLE_DEVTOOLS 40 DEVTOOLS, 41#endif 42 XRICK, 43 INIT_GAME, INIT_BUFFER, 44 INTRO_MAIN, INTRO_MAP, 45 PAUSE_PRESSED1, PAUSE_PRESSED1B, PAUSED, PAUSE_PRESSED2, 46 PLAY0, PLAY1, PLAY2, PLAY3, 47 CHAIN_SUBMAP, CHAIN_MAP, CHAIN_END, 48 SCROLL_UP, SCROLL_DOWN, 49 RESTART, GAMEOVER, GETNAME, EXIT 50} game_state_t; 51 52 53/* 54 * global vars 55 */ 56U8 game_period = 0; 57bool game_waitevt = false; 58const rect_t *game_rects = NULL; 59 60U8 game_lives = 0; 61U8 game_bombs = 0; 62U8 game_bullets = 0; 63U32 game_score = 0; 64 65U16 game_map = 0; 66U16 game_submap = 0; 67 68U8 game_dir = RIGHT; 69bool game_chsm = false; 70 71bool game_cheat1 = false; 72bool game_cheat2 = false; 73bool game_cheat3 = false; 74 75 76/* 77 * local vars 78 */ 79static U8 isave_frow; 80static game_state_t game_state; 81#ifdef ENABLE_SOUND 82static sound_t *currentMusic = NULL; 83#endif 84 85 86/* 87 * prototypes 88 */ 89static void frame(void); 90static void init(void); 91static void play0(void); 92static void play3(void); 93static void restart(void); 94static void isave(void); 95static void irestore(void); 96 97 98/* 99 * Cheats 100 */ 101#ifdef ENABLE_CHEATS 102void 103game_toggleCheat(cheat_t cheat) 104{ 105 if (game_state != INTRO_MAIN && game_state != INTRO_MAP && 106 game_state != GAMEOVER && game_state != GETNAME && 107#ifdef ENABLE_DEVTOOLS 108 game_state != DEVTOOLS && 109#endif 110 game_state != XRICK && game_state != EXIT) 111 { 112 switch (cheat) 113 { 114 case Cheat_UNLIMITED_ALL: 115 { 116 game_cheat1 = !game_cheat1; 117 game_lives = 6; 118 game_bombs = 6; 119 game_bullets = 6; 120 break; 121 } 122 case Cheat_NEVER_DIE: 123 { 124 game_cheat2 = !game_cheat2; 125 break; 126 } 127 case Cheat_EXPOSE: 128 { 129 game_cheat3 = !game_cheat3; 130 break; 131 } 132 } 133 draw_infos(); 134 /* FIXME this should probably only raise a flag ... */ 135 /* plus we only need to update INFORECT not the whole screen */ 136 sysvid_update(&draw_SCREENRECT); 137 } 138} 139#endif 140 141#ifdef ENABLE_SOUND 142/* 143 * Music 144 */ 145void 146game_setmusic(sound_t * newMusic, S8 loop) 147{ 148 if (!newMusic) 149 { 150 return; 151 } 152 153 if (currentMusic) 154 { 155 game_stopmusic(); 156 } 157 158 syssnd_play(newMusic, loop); 159 160 currentMusic = newMusic; 161} 162 163void 164game_stopmusic(void) 165{ 166 syssnd_stop(currentMusic); 167 currentMusic = NULL; 168} 169#endif /*ENABLE_SOUND */ 170 171/* 172 * Main loop 173 */ 174void 175game_run(void) 176{ 177 U32 currentTime, 178#ifdef ENABLE_SOUND 179 lastSoundTime = 0, 180#endif 181 lastFrameTime = 0; 182 183 if (!resources_load()) 184 { 185 resources_unload(); 186 return; 187 } 188 189 if (!sys_cacheData()) 190 { 191 sys_uncacheData(); 192 return; 193 } 194 195 game_period = sysarg_args_period ? sysarg_args_period : GAME_PERIOD; 196 game_state = XRICK; 197 198 /* main loop */ 199 while (game_state != EXIT) 200 { 201 currentTime = sys_gettime(); 202 203 if (currentTime - lastFrameTime >= game_period) 204 { 205 /* frame */ 206 frame(); 207 208 /* video */ 209 /*DEBUG*//*game_rects=&draw_SCREENRECT;*//*DEBUG*/ 210 sysvid_update(game_rects); 211 212 /* reset rectangles list */ 213 rects_free(ent_rects); 214 ent_rects = NULL; 215 draw_STATUSRECT.next = NULL; /* FIXME freerects should handle this */ 216 217 /* events */ 218 if (game_waitevt) 219 { 220 sysevt_wait(); /* wait for an event */ 221 } 222 else 223 { 224 sysevt_poll(); /* process events (non-blocking) */ 225 } 226 227 lastFrameTime = currentTime; 228 } 229 230#ifdef ENABLE_SOUND 231 if (currentTime - lastSoundTime >= syssnd_period) 232 { 233 /* sound */ 234 syssnd_update(); 235 236 lastSoundTime = currentTime; 237 } 238#endif /* ENABLE_SOUND */ 239 240 sys_yield(); 241 } 242 243#ifdef ENABLE_SOUND 244 syssnd_stopAll(); 245#endif 246 247 sys_uncacheData(); 248 249 resources_unload(); 250} 251 252/* 253 * Prepare frame 254 * 255 * This function loops forever: use 'return' when a frame is ready. 256 * When returning, game_rects must contain every parts of the buffer 257 * that have been modified. 258 */ 259static void 260frame(void) 261{ 262 while (1) { 263 264 switch (game_state) { 265 266 267 268#ifdef ENABLE_DEVTOOLS 269 case DEVTOOLS: 270 switch (devtools_run()) { 271 case SCREEN_RUNNING: 272 return; 273 case SCREEN_DONE: 274 game_state = INIT_GAME; 275 break; 276 case SCREEN_EXIT: 277 game_state = EXIT; 278 return; 279 } 280 break; 281#endif 282 283 284 285 case XRICK: 286 switch(screen_xrick()) { 287 case SCREEN_RUNNING: 288 return; 289 case SCREEN_DONE: 290#ifdef ENABLE_DEVTOOLS 291 game_state = DEVTOOLS; 292#else 293 game_state = INIT_GAME; 294#endif 295 break; 296 case SCREEN_EXIT: 297 game_state = EXIT; 298 return; 299 } 300 break; 301 302 303 304 case INIT_GAME: 305 init(); 306 game_state = INTRO_MAIN; 307 break; 308 309 310 311 case INTRO_MAIN: 312 switch (screen_introMain()) { 313 case SCREEN_RUNNING: 314 return; 315 case SCREEN_DONE: 316 game_state = INTRO_MAP; 317 break; 318 case SCREEN_EXIT: 319 game_state = EXIT; 320 return; 321 } 322 break; 323 324 325 326 case INTRO_MAP: 327 switch (screen_introMap()) { 328 case SCREEN_RUNNING: 329 return; 330 case SCREEN_DONE: 331 game_waitevt = false; 332 game_state = INIT_BUFFER; 333 break; 334 case SCREEN_EXIT: 335 game_state = EXIT; 336 return; 337 } 338 break; 339 340 341 342 case INIT_BUFFER: 343 sysvid_clear(); /* clear buffer */ 344 draw_map(); /* draw the map onto the buffer */ 345 draw_drawStatus(); /* draw the status bar onto the buffer */ 346#ifdef ENABLE_CHEATS 347 draw_infos(); /* draw the info bar onto the buffer */ 348#endif 349 game_rects = &draw_SCREENRECT; /* request full buffer refresh */ 350 game_state = PLAY0; 351 return; 352 353 354 355 case PAUSE_PRESSED1: 356 screen_pause(true); 357 game_state = PAUSE_PRESSED1B; 358 break; 359 360 361 362 case PAUSE_PRESSED1B: 363 if (control_test(Control_PAUSE)) 364 return; 365 game_state = PAUSED; 366 break; 367 368 369 370 case PAUSED: 371 if (control_test(Control_PAUSE)) 372 game_state = PAUSE_PRESSED2; 373 if (control_test(Control_EXIT)) 374 game_state = EXIT; 375 return; 376 377 378 379 case PAUSE_PRESSED2: 380 if (!(control_test(Control_PAUSE))) { 381 game_waitevt = false; 382 screen_pause(false); 383#ifdef ENABLE_SOUND 384 syssnd_pauseAll(false); 385#endif 386 game_state = PLAY2; 387 } 388 return; 389 390 391 392 case PLAY0: 393 play0(); 394 break; 395 396 397 398 case PLAY1: 399 if (control_test(Control_PAUSE)) { 400#ifdef ENABLE_SOUND 401 syssnd_pauseAll(true); 402#endif 403 game_waitevt = true; 404 game_state = PAUSE_PRESSED1; 405 } 406 else if (!control_active) { 407#ifdef ENABLE_SOUND 408 syssnd_pauseAll(true); 409#endif 410 game_waitevt = true; 411 screen_pause(true); 412 game_state = PAUSED; 413 } 414 else 415 game_state = PLAY2; 416 break; 417 418 419 420 case PLAY2: 421 if (e_rick_state_test(E_RICK_STDEAD)) { /* rick is dead */ 422 if (game_cheat1 || --game_lives) { 423 game_state = RESTART; 424 } else { 425 game_state = GAMEOVER; 426 } 427 } 428 else if (game_chsm) /* request to chain to next submap */ 429 game_state = CHAIN_SUBMAP; 430 else 431 game_state = PLAY3; 432 break; 433 434 435 436 case PLAY3: 437 play3(); 438 return; 439 440 441 442 case CHAIN_SUBMAP: 443 if (map_chain()) 444 game_state = CHAIN_END; 445 else { 446 game_bullets = 0x06; 447 game_bombs = 0x06; 448 game_map++; 449 450 if (game_map == map_nbr_maps - 1) { 451 /* reached end of game */ 452 /* FIXME @292?*/ 453 } 454 455 game_state = CHAIN_MAP; 456 } 457 break; 458 459 460 461 case CHAIN_MAP: /* CHAIN MAP */ 462 switch (screen_introMap()) { 463 case SCREEN_RUNNING: 464 return; 465 case SCREEN_DONE: 466 if (game_map >= map_nbr_maps - 1) { /* reached end of game */ 467 sysarg_args_map = 0; 468 sysarg_args_submap = 0; 469 game_state = GAMEOVER; 470 } 471 else { /* initialize game */ 472 ent_ents[1].x = map_maps[game_map].x; 473 ent_ents[1].y = map_maps[game_map].y; 474 map_frow = (U8)map_maps[game_map].row; 475 game_submap = map_maps[game_map].submap; 476 game_state = CHAIN_END; 477 } 478 break; 479 case SCREEN_EXIT: 480 game_state = EXIT; 481 return; 482 } 483 break; 484 485 486 487 case CHAIN_END: 488 map_init(); /* initialize the map */ 489 isave(); /* save data in case of a restart */ 490 ent_clprev(); /* cleanup entities */ 491 draw_map(); /* draw the map onto the buffer */ 492 draw_drawStatus(); /* draw the status bar onto the buffer */ 493 game_rects = &draw_SCREENRECT; /* request full screen refresh */ 494 game_state = PLAY0; 495 return; 496 497 498 499 case SCROLL_UP: 500 switch (scroll_up()) { 501 case SCROLL_RUNNING: 502 return; 503 case SCROLL_DONE: 504 game_state = PLAY0; 505 break; 506 } 507 break; 508 509 510 511 case SCROLL_DOWN: 512 switch (scroll_down()) { 513 case SCROLL_RUNNING: 514 return; 515 case SCROLL_DONE: 516 game_state = PLAY0; 517 break; 518 } 519 break; 520 521 522 523 case RESTART: 524 restart(); 525 game_state = PLAY0; 526 return; 527 528 529 530 case GAMEOVER: 531 switch (screen_gameover()) { 532 case SCREEN_RUNNING: 533 return; 534 case SCREEN_DONE: 535 game_state = GETNAME; 536 break; 537 case SCREEN_EXIT: 538 game_state = EXIT; 539 break; 540 } 541 break; 542 543 544 545 case GETNAME: 546 switch (screen_getname()) { 547 case SCREEN_RUNNING: 548 return; 549 case SCREEN_DONE: 550 game_state = INIT_GAME; 551 return; 552 case SCREEN_EXIT: 553 game_state = EXIT; 554 break; 555 } 556 break; 557 558 559 560 case EXIT: 561 return; 562 563 } 564 } 565} 566 567 568/* 569 * Initialize the game 570 */ 571static void 572init(void) 573{ 574 U8 i; 575 576 e_rick_state_clear(0xff); 577 578 game_lives = 6; 579 game_bombs = 6; 580 game_bullets = 6; 581 game_score = 0; 582 583 game_map = sysarg_args_map; 584 585 if (sysarg_args_submap == 0) 586 { 587 game_submap = map_maps[game_map].submap; 588 map_frow = (U8)map_maps[game_map].row; 589 } 590 else 591 { 592 /* dirty hack to determine frow */ 593 game_submap = sysarg_args_submap; 594 i = 0; 595 while (i < map_nbr_connect && 596 (map_connect[i].submap != game_submap || 597 map_connect[i].dir != RIGHT)) 598 { 599 i++; 600 } 601 map_frow = map_connect[i].rowin - 0x10; 602 ent_ents[1].y = 0x10 << 3; 603 } 604 605 ent_ents[1].x = map_maps[game_map].x; 606 ent_ents[1].y = map_maps[game_map].y; 607 ent_ents[1].w = 0x18; 608 ent_ents[1].h = 0x15; 609 ent_ents[1].n = 0x01; 610 ent_ents[1].sprite = 0x01; 611 ent_ents[1].front = false; 612 ent_ents[ENT_ENTSNUM].n = 0xFF; 613 614 map_resetMarks(); 615 616 map_init(); 617 isave(); 618} 619 620 621/* 622 * play0 623 * 624 */ 625static void 626play0(void) 627{ 628 if (control_test(Control_END)) { /* request to end the game */ 629 game_state = GAMEOVER; 630 return; 631 } 632 633 if (control_test(Control_EXIT)) { /* request to exit the game */ 634 game_state = EXIT; 635 return; 636 } 637 638 ent_action(); /* run entities */ 639 e_them_rndseed++; /* (0270) */ 640 641 game_state = PLAY1; 642} 643 644 645/* 646 * play3 647 * 648 */ 649static void 650play3(void) 651{ 652 draw_clearStatus(); /* clear the status bar */ 653 ent_draw(); /* draw all entities onto the buffer */ 654 /* sound */ 655 draw_drawStatus(); /* draw the status bar onto the buffer*/ 656 657 game_rects = &draw_STATUSRECT; /* refresh status bar too */ 658 draw_STATUSRECT.next = ent_rects; /* take care to cleanup draw_STATUSRECT->next later! */ 659 660 if (!e_rick_state_test(E_RICK_STZOMBIE)) { /* need to scroll ? */ 661 if (ent_ents[1].y >= 0xCC) { 662 game_state = SCROLL_UP; 663 return; 664 } 665 if (ent_ents[1].y <= 0x60) { 666 game_state = SCROLL_DOWN; 667 return; 668 } 669 } 670 671 game_state = PLAY0; 672} 673 674 675/* 676 * restart 677 * 678 */ 679static void 680restart(void) 681{ 682 e_rick_state_clear(E_RICK_STDEAD|E_RICK_STZOMBIE); 683 684 game_bullets = 6; 685 game_bombs = 6; 686 687 ent_ents[1].n = 1; 688 689 irestore(); 690 map_init(); 691 isave(); 692 ent_clprev(); 693 draw_map(); 694 draw_drawStatus(); 695 game_rects = &draw_SCREENRECT; 696} 697 698 699/* 700 * isave (0bbb) 701 * 702 */ 703static void 704isave(void) 705{ 706 e_rick_save(); 707 isave_frow = map_frow; 708} 709 710 711/* 712 * irestore (0bdc) 713 * 714 */ 715static void 716irestore(void) 717{ 718 e_rick_restore(); 719 map_frow = isave_frow; 720} 721 722/* eof */