Subversion Repositories Games.Rick Dangerous

Rev

Rev 1 | Rev 9 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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