- /* 
-  * src/game.c 
-  * 
-  * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net). All rights reserved. 
-  * 
-  * The use and distribution terms for this software are contained in the file 
-  * named README, which can be found in the root of this distribution. By 
-  * using this software in any fashion, you are agreeing to be bound by the 
-  * terms of this license. 
-  * 
-  * You must not remove this notice, or any other, from this software. 
-  */ 
-   
- #include <stdio.h> 
- #include <stdlib.h> 
-   
- #include "system.h" 
- #include "game.h" 
-   
- #include "draw.h" 
- #include "maps.h" 
- #include "ents.h" 
- #include "e_rick.h" 
- #include "e_sbonus.h" 
- #include "e_them.h" 
- #include "screens.h" 
- #include "rects.h" 
- #include "scroller.h" 
- #include "control.h" 
-   
-   
- /* 
-  * local typedefs 
-  */ 
- typedef enum 
- { 
-    INIT_GAME, INIT_BUFFER, 
-    INTRO_MAIN, INTRO_MAP, 
-    PAUSE_PRESSED1, PAUSE_PRESSED1B, PAUSED, PAUSE_PRESSED2, 
-    PLAY0, PLAY1, PLAY2, PLAY3, 
-    CHAIN_SUBMAP, CHAIN_MAP, CHAIN_END, 
-    SCROLL_UP, SCROLL_DOWN, 
-    RESTART, GAMEOVER, GETNAME, EXIT 
- } game_state_t; 
-   
-   
- /* 
-  * global vars 
-  */ 
- U8 game_period = 0; 
- U8 game_waitevt = FALSE; 
- rect_t *game_rects = NULL; 
-   
- U8 game_lives = 0; 
- U8 game_bombs = 0; 
- U8 game_bullets = 0; 
- U32 game_score = 0; 
-   
- U16 game_map = 0; 
- U16 game_submap = 0; 
-   
- U8 game_dir = 0; 
- U8 game_chsm = FALSE; 
-   
- U8 want_infinitelives = FALSE; 
- U8 want_infiniteammo = FALSE; 
- U8 want_last_map = FALSE; 
- U8 want_last_submap = FALSE; 
- U8 enable_endkey = TRUE; 
-   
-   
- hscore_t game_hscores[8] = 
- { 
-    { 8000, "DANGERSTU@" }, 
-    { 7000, "SIMES@@@@@" }, 
-    { 6000, "KEN@T@ZEN@" }, 
-    { 5000, "BOBBLE@@@@" }, 
-    { 4000, "GREG@LAA@@" }, 
-    { 3000, "TELLY@@@@@" }, 
-    { 2000, "CHIGLET@@@" }, 
-    { 1000, "ANDYSPLEEN" } 
- }; 
-   
- sound_t *WAV_GAMEOVER; 
- sound_t *WAV_SBONUS2; 
- sound_t *WAV_BULLET; 
- sound_t *WAV_BOMBSHHT; 
- sound_t *WAV_EXPLODE; 
- sound_t *WAV_STICK; 
- sound_t *WAV_WALK; 
- sound_t *WAV_CRAWL; 
- sound_t *WAV_JUMP; 
- sound_t *WAV_PAD; 
- sound_t *WAV_BOX; 
- sound_t *WAV_BONUS; 
- sound_t *WAV_SBONUS1; 
- sound_t *WAV_DIE; 
- sound_t *WAV_ENTITY[10]; 
-   
-   
- /* 
-  * local vars 
-  */ 
- static U8 isave_frow; 
- static game_state_t game_state; 
- static sound_t *music_snd; 
-   
-   
- /* 
-  * prototypes 
-  */ 
- static void frame (void); 
- static void init (void); 
- static void play0 (void); 
- static void play3 (void); 
- static void restart (void); 
- static void isave (void); 
- static void irestore (void); 
- static void loaddata (void); 
- static void freedata (void); 
-   
-   
- /* 
-  * Music 
-  */ 
- void game_setmusic (char *name, U8 loop) 
- { 
-    U8 channel; 
-   
-    if (music_snd) 
-       game_stopmusic (); 
-   
-    music_snd = syssnd_load (name); 
-   
-    if (music_snd) 
-    { 
-       music_snd->dispose = TRUE; /* music is always "fire and forget" */ 
-       channel = syssnd_play(music_snd, loop); 
-    } 
- } 
-   
-   
- void game_stopmusic (void) 
- { 
-    syssnd_stopsound (music_snd); 
-    music_snd = NULL; 
- } 
-   
-   
- /* 
-  * Main loop 
-  */ 
- void game_run (void) 
- { 
-    U32 tm, tmx; 
-   
-    loaddata (); /* load cached data */ 
-   
-    tm = sys_gettime (); 
-    game_state = INIT_GAME; 
-   
-    /* main loop */ 
-    while (game_state != EXIT) 
-    { 
-       // Pierre-Marie Baty -- intro runs faster 
-       if (game_state != INTRO_MAP) 
-          game_period = (sysarg_args_period ? sysarg_args_period : GAME_PERIOD); 
-       else 
-          game_period = (sysarg_args_period ? sysarg_args_period : GAME_PERIOD) / 2; 
-   
-       /* timer */ 
-       tmx = tm; tm = sys_gettime (); tmx = tm - tmx; 
-       if (tmx < game_period) 
-          sys_sleep (game_period - tmx); 
-   
-       /* video */ 
-       /*DEBUG*//*game_rects=&draw_SCREENRECT;*//*DEBUG*/ 
-       sysvid_paint (game_rects); 
-       draw_STATUSRECT.next = NULL; /* FIXME freerects should handle this */ 
-   
-       /* sound */ 
-       /*snd_mix ();*/ 
-   
-       /* events */ 
-       if (game_waitevt) 
-          sysevt_wait (); /* wait for an event */ 
-       else 
-          sysevt_poll (); /* process events (non-blocking) */ 
-   
-       /* frame */ 
-       frame (); 
-    } 
-   
-    freedata (); /* free cached data */ 
- } 
-   
-   
- // Pierre-Marie Baty -- addition: sort high scores 
- int sort_hscores (const void *q1, const void *q2) 
- { 
-    return (((hscore_t *) q1)->score < ((hscore_t *) q2)->score); 
- } 
-   
-   
- /* 
-  * Prepare frame 
-  * 
-  * This function loops forever: use 'return' when a frame is ready. 
-  * When returning, game_rects must contain every parts of the buffer 
-  * that have been modified. 
-  */ 
- static void frame (void) 
- { 
-    while (1) 
-    { 
-   
-       switch (game_state) 
-       { 
-   
-   
-       case INIT_GAME: 
-          init (); 
-          game_state = INTRO_MAIN; 
-          break; 
-   
-   
-   
-       case INTRO_MAIN: 
-          switch (screen_introMain ()) 
-          { 
-          case SCREEN_RUNNING: 
-             return; 
-          case SCREEN_DONE: 
-             game_state = INTRO_MAP; 
-             break; 
-          case SCREEN_EXIT: 
-             game_state = EXIT; 
-             return; 
-          } 
-       break; 
-   
-   
-   
-       case INTRO_MAP: 
-          switch (screen_introMap ()) 
-          { 
-          case SCREEN_RUNNING: 
-             return; 
-          case SCREEN_DONE: 
-             game_waitevt = FALSE; 
-             game_state = INIT_BUFFER; 
-             break; 
-          case SCREEN_EXIT: 
-             game_state = EXIT; 
-             return; 
-          } 
-       break; 
-   
-   
-   
-       case INIT_BUFFER: 
-          syssnd_pause (FALSE, TRUE); // reset sounds 
-          sysvid_clear (); /* clear buffer */ 
-          draw_map (); /* draw the map onto the buffer */ 
-          draw_drawStatus (); /* draw the status bar onto the buffer */ 
-          game_rects = &draw_SCREENRECT; /* request full buffer refresh */ 
-          game_state = PLAY0; 
-          return; 
-   
-   
-   
-       case PAUSE_PRESSED1: 
-          screen_pause (TRUE); 
-          game_state = PAUSE_PRESSED1B; 
-          break; 
-   
-   
-   
-       case PAUSE_PRESSED1B: 
-          if (control_status & CONTROL_PAUSE) 
-             return; 
-          game_state = PAUSED; 
-          break; 
-   
-   
-   
-       case PAUSED: 
-          if (control_status & CONTROL_PAUSE) 
-             game_state = PAUSE_PRESSED2; 
-          if (control_status & CONTROL_EXIT) 
-             game_state = EXIT; 
-          return; 
-   
-   
-   
-       case PAUSE_PRESSED2: 
-          if (!(control_status & CONTROL_PAUSE)) 
-          { 
-             game_waitevt = FALSE; 
-             screen_pause (FALSE); 
-             syssnd_pause (FALSE, FALSE); 
-             game_state = PLAY2; 
-          } 
-       return; 
-   
-   
-   
-       case PLAY0: 
-          play0 (); 
-          break; 
-   
-   
-   
-       case PLAY1: 
-          if (control_status & CONTROL_PAUSE) 
-          { 
-             syssnd_pause (TRUE, FALSE); 
-             game_waitevt = TRUE; 
-             game_state = PAUSE_PRESSED1; 
-          } 
-          else 
-             game_state = PLAY2; 
-          break; 
-   
-   
-   
-       case PLAY2: 
-          if (E_RICK_STTST (E_RICK_STDEAD)) 
-          { 
-             /* rick is dead */ 
-             if (--game_lives) 
-             { 
-                game_state = RESTART; 
-                if (want_infinitelives) 
-                   game_lives = 6; 
-             } 
-             else 
-                game_state = GAMEOVER; 
-          } 
-          else if (game_chsm) 
-             game_state = CHAIN_SUBMAP; // request to chain to next submap 
-          else 
-             game_state = PLAY3; 
-          break; 
-   
-   
-   
-       case PLAY3: 
-          play3 (); 
-          return; 
-   
-   
-   
-       case CHAIN_SUBMAP: 
-          if (map_chain ()) 
-             game_state = CHAIN_END; 
-          else 
-          { 
-             game_bullets = 6; 
-             game_bombs = 6; 
-             game_map++; 
-             if (want_last_map) 
-                sysarg_args_map = game_map; 
-   
-             if (game_map == 0x04) 
-             { 
-                /* reached end of game */ 
-                /* FIXME @292?*/ 
-             } 
-   
-             game_state = CHAIN_MAP; 
-          } 
-          break; 
-   
-   
-   
-       case CHAIN_MAP:/* CHAIN MAP */ 
-          switch (screen_introMap ()) 
-          { 
-          case SCREEN_RUNNING: 
-             return; 
-          case SCREEN_DONE: 
-             if (game_map >= 0x04) 
-             { 
-                /* reached end of game */ 
-                sysarg_args_map = 0; 
-                sysarg_args_submap = 0; 
-                sysarg_args_score = 0; 
-                game_state = GAMEOVER; 
-             } 
-             else 
-             { 
-                /* initialize game */ 
-                ent_ents[1].x = map_maps[game_map].x; 
-                ent_ents[1].y = map_maps[game_map].y; 
-                map_frow = (U8) map_maps[game_map].row; 
-                game_submap = map_maps[game_map].submap; 
-                game_state = CHAIN_END; 
-             } 
-             break; 
-                case SCREEN_EXIT: 
-             game_state = EXIT; 
-             return; 
-          } 
-          break; 
-   
-   
-   
-       case CHAIN_END: 
-          syssnd_pause (FALSE, TRUE); // reset sounds 
-          map_init (); /* initialize the map */ 
-          isave (); /* save data in case of a restart */ 
-          ent_clprev (); /* cleanup entities */ 
-          draw_map (); /* draw the map onto the buffer */ 
-          draw_drawStatus (); /* draw the status bar onto the buffer */ 
-          draw_STATUSRECT.next = NULL; 
-          game_state = PLAY3; 
-          frame (); // Pierre-Marie Baty -- patch by Jason Andersen: skip refreshing the screen for 2 pumps 
-          frame (); // to allow the sprites to settle into the appropriate frame 
-          game_rects = &draw_SCREENRECT;  /* request full screen refresh */ 
-          return; 
-   
-   
-   
-       case SCROLL_UP: 
-          switch (scroll_up ()) 
-          { 
-          case SCROLL_RUNNING: 
-             return; 
-          case SCROLL_DONE: 
-             game_state = PLAY0; 
-             break; 
-          } 
-          break; 
-   
-   
-   
-       case SCROLL_DOWN: 
-          switch (scroll_down ()) 
-          { 
-          case SCROLL_RUNNING: 
-             return; 
-          case SCROLL_DONE: 
-             game_state = PLAY0; 
-             break; 
-          } 
-          break; 
-   
-   
-   
-       case RESTART: 
-          restart (); 
-          game_state = PLAY0; 
-          return; 
-   
-   
-   
-       case GAMEOVER: 
-          switch (screen_gameover ()) 
-          { 
-          case SCREEN_RUNNING: 
-             return; 
-          case SCREEN_DONE: 
-             game_state = GETNAME; 
-             break; 
-          case SCREEN_EXIT: 
-             game_state = EXIT; 
-             break; 
-          } 
-          break; 
-   
-   
-   
-       case GETNAME: 
-          switch (screen_getname ()) { 
-          case SCREEN_RUNNING: 
-             return; 
-          case SCREEN_DONE: 
-             game_state = INIT_GAME; 
-             return; 
-          case SCREEN_EXIT: 
-             game_state = EXIT; 
-             break; 
-          } 
-          break; 
-   
-   
-   
-       case EXIT: 
-          return; 
-   
-       } 
-    } 
- } 
-   
-   
- /* 
-  * Initialize the game 
-  */ 
- static void init (void) 
- { 
-    U8 i; 
-   
-    E_RICK_STRST (0xff); 
-   
-    game_lives = 6; 
-    game_bombs = 6; 
-    game_bullets = 6; 
-    game_score = 0; 
-   
-    game_map = sysarg_args_map; 
-   
-    if (sysarg_args_submap == 0) 
-    { 
-       game_submap = map_maps[game_map].submap; 
-       map_frow = (U8)map_maps[game_map].row; 
-    } 
-    else 
-    { 
-       /* dirty hack to determine frow */ 
-       game_submap = sysarg_args_submap; 
-       i = 0; 
-       while (i < MAP_NBR_CONNECT && (map_connect[i].submap != game_submap || map_connect[i].dir != RIGHT)) 
-          i++; 
-       map_frow = map_connect[i].rowin - 0x10; 
-       ent_ents[1].y = 0x10 << 3; 
-    } 
-   
-    // Pierre-Marie Baty -- addition: start score 
-    if (sysarg_args_score != 0) 
-       game_score = sysarg_args_score + 1; 
-   
-    ent_ents[1].x = map_maps[game_map].x; 
-    ent_ents[1].y = map_maps[game_map].y; 
-    ent_ents[1].w = 0x18; 
-    ent_ents[1].h = 0x15; 
-    ent_ents[1].n = 0x01; 
-    ent_ents[1].sprite = 0x01; 
-    ent_ents[1].front = FALSE; 
-    ent_ents[ENT_ENTSNUM].n = 0xFF; 
-   
-    map_resetMarks (); 
-    map_init (); 
-    isave (); 
- } 
-   
-   
- /* 
-  * play0 
-  * 
-  */ 
- static void play0 (void) 
- { 
-    if (control_status & CONTROL_END) 
-    { 
-       /* request to end the game */ 
-       game_state = GAMEOVER; 
-       return; 
-    } 
-   
-    if (control_last == CONTROL_EXIT) 
-    { 
-       /* request to exit the game */ 
-       game_state = EXIT; 
-       return; 
-    } 
-   
-    ent_action (); /* run entities */ 
-    e_them_rndseed++; /* (0270) */ 
-   
-    game_state = PLAY1; 
- } 
-   
-   
- /* 
-  * play3 
-  * 
-  */ 
- static void play3 (void) 
- { 
-    static rect_t *r; 
-   
-    ent_draw (); /* draw all entities onto the buffer */ 
-   
-    /* sound */ 
-    draw_drawStatus (); /* draw the status bar onto the buffer*/ 
-   
-    r = &draw_STATUSRECT; 
-    r->next = ent_rects; /* refresh status bar too */ 
-    game_rects = r; /* take care to cleanup draw_STATUSRECT->next later! */ 
-   
-    if (!E_RICK_STTST (E_RICK_STZOMBIE)) 
-    { 
-       /* need to scroll ? */ 
-       if (ent_ents[1].y >= 200 + 4) 
-       { 
-          game_state = SCROLL_UP; 
-          return; 
-       } 
-       if (ent_ents[1].y <= 100 - 4) 
-       { 
-          game_state = SCROLL_DOWN; 
-          return; 
-       } 
-    } 
-   
-    game_state = PLAY0; 
- } 
-   
-   
- /* 
-  * restart 
-  * 
-  */ 
- static void restart (void) 
- { 
-    E_RICK_STRST (/*E_RICK_STDEAD | E_RICK_STZOMBIE*/ 0xff); // Pierre-Marie Baty -- correct sprite position on restart 
-   
-    game_bullets = 6; 
-    game_bombs = 6; 
-   
-    ent_ents[1].n = 1; 
-   
-    irestore (); 
-    map_init (); 
-    isave (); 
-    ent_clprev (); 
-    draw_map (); 
-    draw_drawStatus (); 
-    game_rects = &draw_SCREENRECT; 
- } 
-   
-   
- /* 
-  * isave (0bbb) 
-  * 
-  */ 
- static void isave (void) 
- { 
-    e_rick_save (); 
-    isave_frow = map_frow; 
- } 
-   
-   
- /* 
-  * irestore (0bdc) 
-  * 
-  */ 
- static void irestore (void) 
- { 
-    e_rick_restore (); 
-    map_frow = isave_frow; 
- } 
-   
-   
- /* 
-  * 
-  */ 
- static void loaddata (void) 
- { 
-    /* 
-     * Cache sounds 
-     * 
-     * tune[0-5].wav not cached 
-     */ 
-    WAV_GAMEOVER = syssnd_load ("sounds/gameover.wav"); 
-    WAV_SBONUS2 = syssnd_load ("sounds/sbonus2.wav"); 
-    WAV_BULLET = syssnd_load ("sounds/bullet.wav"); 
-    WAV_BOMBSHHT = syssnd_load ("sounds/bombshht.wav"); 
-    WAV_EXPLODE = syssnd_load ("sounds/explode.wav"); 
-    WAV_STICK = syssnd_load ("sounds/stick.wav"); 
-    WAV_WALK = syssnd_load ("sounds/walk.wav"); 
-    WAV_CRAWL = syssnd_load ("sounds/crawl.wav"); 
-    WAV_JUMP = syssnd_load ("sounds/jump.wav"); 
-    WAV_PAD = syssnd_load ("sounds/pad.wav"); 
-    WAV_BOX = syssnd_load ("sounds/box.wav"); 
-    WAV_BONUS = syssnd_load ("sounds/bonus.wav"); 
-    WAV_SBONUS1 = syssnd_load ("sounds/sbonus1.wav"); 
-    WAV_DIE = syssnd_load ("sounds/die.wav"); 
-    WAV_ENTITY[0] = syssnd_load ("sounds/ent0.wav"); 
-    WAV_ENTITY[1] = syssnd_load ("sounds/ent1.wav"); 
-    WAV_ENTITY[2] = syssnd_load ("sounds/ent2.wav"); 
-    WAV_ENTITY[3] = syssnd_load ("sounds/ent3.wav"); 
-    WAV_ENTITY[4] = syssnd_load ("sounds/ent4.wav"); 
-    WAV_ENTITY[5] = syssnd_load ("sounds/ent5.wav"); 
-    WAV_ENTITY[6] = syssnd_load ("sounds/ent6.wav"); 
-    WAV_ENTITY[7] = syssnd_load ("sounds/ent7.wav"); 
-    WAV_ENTITY[8] = syssnd_load ("sounds/ent8.wav"); 
-   
-    // Pierre-Marie Baty -- addition: load high scores 
-    { 
-       char hiscorefile_fullpathname[1024]; 
-       char linebuf[256]; 
-       hscore_t *hscore; 
-       U32 score; 
-       char *ptr; 
-       size_t i, j; 
-       FILE *fp; 
-       sprintf_s (hiscorefile_fullpathname, 1024, "%s/%s", sys_getbasepath (), "hiscores.txt"); 
-       fopen_s (&fp, hiscorefile_fullpathname, "rb"); 
-       if (fp != NULL) 
-       { 
-          for (- i  = 0; (fgets (- linebuf , sizeof (- linebuf ),-  fp ) !=-  NULL ) && (- i  < 8);)
 
-          { 
-             score  = strtol (- linebuf , &- ptr , 10);
-             if (ptr <= linebuf) 
-                continue; 
-             while ((*ptr == '\t') || (*ptr == ' ')) 
-                ptr++; 
-             hscore = &game_hscores[i++]; 
-             hscore->score = score; 
-             for (j = 0; j < sizeof (hscore->name); j++) 
-                hscore->name[j] = '@'; 
-             for (j = 0; j < sizeof (hscore->name); j++, ptr++) 
-                hscore->name[j] = (((*ptr >= 'A') && (*ptr <= 'Z')) || (*ptr == '.') ? *ptr : '@'); 
-          } 
-          qsort (- game_hscores , 8, sizeof (- hscore_t ),-  sort_hscores );
 
-       } 
-    } 
- } 
-   
-   
- /* 
-  * 
-  */ 
- static void freedata (void) 
- { 
-    syssnd_stopall (); 
-    syssnd_free (WAV_GAMEOVER); 
-    syssnd_free (WAV_SBONUS2); 
-    syssnd_free (WAV_BULLET); 
-    syssnd_free (WAV_BOMBSHHT); 
-    syssnd_free (WAV_EXPLODE); 
-    syssnd_free (WAV_STICK); 
-    syssnd_free (WAV_WALK); 
-    syssnd_free (WAV_CRAWL); 
-    syssnd_free (WAV_JUMP); 
-    syssnd_free (WAV_PAD); 
-    syssnd_free (WAV_BOX); 
-    syssnd_free (WAV_BONUS); 
-    syssnd_free (WAV_SBONUS1); 
-    syssnd_free (WAV_DIE); 
-    syssnd_free (WAV_ENTITY[0]); 
-    syssnd_free (WAV_ENTITY[1]); 
-    syssnd_free (WAV_ENTITY[2]); 
-    syssnd_free (WAV_ENTITY[3]); 
-    syssnd_free (WAV_ENTITY[4]); 
-    syssnd_free (WAV_ENTITY[5]); 
-    syssnd_free (WAV_ENTITY[6]); 
-    syssnd_free (WAV_ENTITY[7]); 
-    syssnd_free (WAV_ENTITY[8]); 
-   
-    // Pierre-Marie Baty -- addition: save high scores 
-    { 
-       char hiscorefile_fullpathname[1024]; 
-       size_t i, j; 
-       FILE *fp; 
-       sprintf_s (hiscorefile_fullpathname, 1024, "%s/%s", sys_getbasepath (), "hiscores.txt"); 
-       fopen_s (&fp, hiscorefile_fullpathname, "wb"); 
-       if (fp != NULL) 
-       { 
-          for (i = 0; i < sizeof (game_hscores) / sizeof (game_hscores[0]); i++) 
-          { 
-             fprintf (- fp , "%d\t",-  game_hscores [- i ]- . score);
 
-             for (j = 0; j < sizeof (game_hscores[i].name); j++) 
-                fputc ((- game_hscores [- i ]- . name[- j ] != '@' ?-  game_hscores [- i ]- . name[- j ] : ' '),-  fp );
 
-          } 
-       } 
-    } 
- } 
-