Subversion Repositories Games.Rick Dangerous

Rev

Rev 7 | 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.          game_rects = &draw_SCREENRECT; /* request full screen refresh */
  401.          game_state = PLAY3;
  402.          return;
  403.  
  404.  
  405.  
  406.       case SCROLL_UP:
  407.          switch (scroll_up ())
  408.          {
  409.          case SCROLL_RUNNING:
  410.             return;
  411.          case SCROLL_DONE:
  412.             game_state = PLAY0;
  413.             break;
  414.          }
  415.          break;
  416.  
  417.  
  418.  
  419.       case SCROLL_DOWN:
  420.          switch (scroll_down ())
  421.          {
  422.          case SCROLL_RUNNING:
  423.             return;
  424.          case SCROLL_DONE:
  425.             game_state = PLAY0;
  426.             break;
  427.          }
  428.          break;
  429.  
  430.  
  431.  
  432.       case RESTART:
  433.          restart ();
  434.          game_state = PLAY0;
  435.          return;
  436.  
  437.  
  438.  
  439.       case GAMEOVER:
  440.          switch (screen_gameover ())
  441.          {
  442.          case SCREEN_RUNNING:
  443.             return;
  444.          case SCREEN_DONE:
  445.             game_state = GETNAME;
  446.             break;
  447.          case SCREEN_EXIT:
  448.             game_state = EXIT;
  449.             break;
  450.          }
  451.          break;
  452.  
  453.  
  454.  
  455.       case GETNAME:
  456.          switch (screen_getname ()) {
  457.          case SCREEN_RUNNING:
  458.             return;
  459.          case SCREEN_DONE:
  460.             game_state = INIT_GAME;
  461.             return;
  462.          case SCREEN_EXIT:
  463.             game_state = EXIT;
  464.             break;
  465.          }
  466.          break;
  467.  
  468.  
  469.  
  470.       case EXIT:
  471.          return;
  472.  
  473.       }
  474.    }
  475. }
  476.  
  477.  
  478. /*
  479.  * Initialize the game
  480.  */
  481. static void init (void)
  482. {
  483.    U8 i;
  484.  
  485.    E_RICK_STRST (0xff);
  486.  
  487.    game_lives = 6;
  488.    game_bombs = 6;
  489.    game_bullets = 6;
  490.    game_score = 0;
  491.  
  492.    game_map = sysarg_args_map;
  493.  
  494.    if (sysarg_args_submap == 0)
  495.    {
  496.       game_submap = map_maps[game_map].submap;
  497.       map_frow = (U8)map_maps[game_map].row;
  498.    }
  499.    else
  500.    {
  501.       /* dirty hack to determine frow */
  502.       game_submap = sysarg_args_submap;
  503.       i = 0;
  504.       while (i < MAP_NBR_CONNECT && (map_connect[i].submap != game_submap || map_connect[i].dir != RIGHT))
  505.          i++;
  506.       map_frow = map_connect[i].rowin - 0x10;
  507.       ent_ents[1].y = 0x10 << 3;
  508.    }
  509.  
  510.    ent_ents[1].x = map_maps[game_map].x;
  511.    ent_ents[1].y = map_maps[game_map].y;
  512.    ent_ents[1].w = 0x18;
  513.    ent_ents[1].h = 0x15;
  514.    ent_ents[1].n = 0x01;
  515.    ent_ents[1].sprite = 0x01;
  516.    ent_ents[1].front = FALSE;
  517.    ent_ents[ENT_ENTSNUM].n = 0xFF;
  518.  
  519.    map_resetMarks ();
  520.    map_init ();
  521.    isave ();
  522. }
  523.  
  524.  
  525. /*
  526.  * play0
  527.  *
  528.  */
  529. static void play0 (void)
  530. {
  531.    if (control_status & CONTROL_END)
  532.    {
  533.       /* request to end the game */
  534.       game_state = GAMEOVER;
  535.       return;
  536.    }
  537.  
  538.    if (control_last == CONTROL_EXIT)
  539.    {
  540.       /* request to exit the game */
  541.       game_state = EXIT;
  542.       return;
  543.    }
  544.  
  545.    ent_action (); /* run entities */
  546.    e_them_rndseed++; /* (0270) */
  547.  
  548.    game_state = PLAY1;
  549. }
  550.  
  551.  
  552. /*
  553.  * play3
  554.  *
  555.  */
  556. static void play3 (void)
  557. {
  558.    static rect_t *r;
  559.  
  560.    ent_draw (); /* draw all entities onto the buffer */
  561.  
  562.    /* sound */
  563.    draw_drawStatus (); /* draw the status bar onto the buffer*/
  564.  
  565.    r = &draw_STATUSRECT;
  566.    r->next = ent_rects; /* refresh status bar too */
  567.    game_rects = r; /* take care to cleanup draw_STATUSRECT->next later! */
  568.  
  569.    if (!E_RICK_STTST (E_RICK_STZOMBIE))
  570.    {
  571.       /* need to scroll ? */
  572.       if (ent_ents[1].y >= 0xCC)
  573.       {
  574.          game_state = SCROLL_UP;
  575.          return;
  576.       }
  577.       if (ent_ents[1].y <= 0x60)
  578.       {
  579.          game_state = SCROLL_DOWN;
  580.          return;
  581.       }
  582.    }
  583.  
  584.    game_state = PLAY0;
  585. }
  586.  
  587.  
  588. /*
  589.  * restart
  590.  *
  591.  */
  592. static void restart (void)
  593. {
  594.    E_RICK_STRST (E_RICK_STDEAD | E_RICK_STZOMBIE);
  595.  
  596.    game_bullets = 6;
  597.    game_bombs = 6;
  598.  
  599.    ent_ents[1].n = 1;
  600.  
  601.    irestore ();
  602.    map_init ();
  603.    isave ();
  604.    ent_clprev ();
  605.    draw_map ();
  606.    draw_drawStatus ();
  607.    game_rects = &draw_SCREENRECT;
  608. }
  609.  
  610.  
  611. /*
  612.  * isave (0bbb)
  613.  *
  614.  */
  615. static void isave (void)
  616. {
  617.    e_rick_save ();
  618.    isave_frow = map_frow;
  619. }
  620.  
  621.  
  622. /*
  623.  * irestore (0bdc)
  624.  *
  625.  */
  626. static void irestore (void)
  627. {
  628.    e_rick_restore ();
  629.    map_frow = isave_frow;
  630. }
  631.  
  632.  
  633. /*
  634.  *
  635.  */
  636. static void loaddata (void)
  637. {
  638.    /*
  639.     * Cache sounds
  640.     *
  641.     * tune[0-5].wav not cached
  642.     */
  643.    WAV_GAMEOVER = syssnd_load ("sounds/gameover.wav");
  644.    WAV_SBONUS2 = syssnd_load ("sounds/sbonus2.wav");
  645.    WAV_BULLET = syssnd_load ("sounds/bullet.wav");
  646.    WAV_BOMBSHHT = syssnd_load ("sounds/bombshht.wav");
  647.    WAV_EXPLODE = syssnd_load ("sounds/explode.wav");
  648.    WAV_STICK = syssnd_load ("sounds/stick.wav");
  649.    WAV_WALK = syssnd_load ("sounds/walk.wav");
  650.    WAV_CRAWL = syssnd_load ("sounds/crawl.wav");
  651.    WAV_JUMP = syssnd_load ("sounds/jump.wav");
  652.    WAV_PAD = syssnd_load ("sounds/pad.wav");
  653.    WAV_BOX = syssnd_load ("sounds/box.wav");
  654.    WAV_BONUS = syssnd_load ("sounds/bonus.wav");
  655.    WAV_SBONUS1 = syssnd_load ("sounds/sbonus1.wav");
  656.    WAV_DIE = syssnd_load ("sounds/die.wav");
  657.    WAV_ENTITY[0] = syssnd_load ("sounds/ent0.wav");
  658.    WAV_ENTITY[1] = syssnd_load ("sounds/ent1.wav");
  659.    WAV_ENTITY[2] = syssnd_load ("sounds/ent2.wav");
  660.    WAV_ENTITY[3] = syssnd_load ("sounds/ent3.wav");
  661.    WAV_ENTITY[4] = syssnd_load ("sounds/ent4.wav");
  662.    WAV_ENTITY[5] = syssnd_load ("sounds/ent5.wav");
  663.    WAV_ENTITY[6] = syssnd_load ("sounds/ent6.wav");
  664.    WAV_ENTITY[7] = syssnd_load ("sounds/ent7.wav");
  665.    WAV_ENTITY[8] = syssnd_load ("sounds/ent8.wav");
  666. }
  667.  
  668.  
  669. /*
  670.  *
  671.  */
  672. static void freedata (void)
  673. {
  674.    syssnd_stopall ();
  675.    syssnd_free (WAV_GAMEOVER);
  676.    syssnd_free (WAV_SBONUS2);
  677.    syssnd_free (WAV_BULLET);
  678.    syssnd_free (WAV_BOMBSHHT);
  679.    syssnd_free (WAV_EXPLODE);
  680.    syssnd_free (WAV_STICK);
  681.    syssnd_free (WAV_WALK);
  682.    syssnd_free (WAV_CRAWL);
  683.    syssnd_free (WAV_JUMP);
  684.    syssnd_free (WAV_PAD);
  685.    syssnd_free (WAV_BOX);
  686.    syssnd_free (WAV_BONUS);
  687.    syssnd_free (WAV_SBONUS1);
  688.    syssnd_free (WAV_DIE);
  689.    syssnd_free (WAV_ENTITY[0]);
  690.    syssnd_free (WAV_ENTITY[1]);
  691.    syssnd_free (WAV_ENTITY[2]);
  692.    syssnd_free (WAV_ENTITY[3]);
  693.    syssnd_free (WAV_ENTITY[4]);
  694.    syssnd_free (WAV_ENTITY[5]);
  695.    syssnd_free (WAV_ENTITY[6]);
  696.    syssnd_free (WAV_ENTITY[7]);
  697.    syssnd_free (WAV_ENTITY[8]);
  698. }
  699.