Subversion Repositories Kolibri OS

Rev

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

  1. // WL_PLAY.C
  2.  
  3. #include "wl_def.h"
  4. #pragma hdrstop
  5.  
  6. #include "wl_cloudsky.h"
  7. #include "wl_shade.h"
  8.  
  9. /*
  10. =============================================================================
  11.  
  12.                                                  LOCAL CONSTANTS
  13.  
  14. =============================================================================
  15. */
  16.  
  17. #define sc_Question     0x35
  18.  
  19. /*
  20. =============================================================================
  21.  
  22.                                                  GLOBAL VARIABLES
  23.  
  24. =============================================================================
  25. */
  26.  
  27. boolean madenoise;              // true when shooting or screaming
  28.  
  29. exit_t playstate;
  30.  
  31. static musicnames lastmusicchunk = (musicnames) 0;
  32.  
  33. static int DebugOk;
  34.  
  35. objtype objlist[MAXACTORS];
  36. objtype *newobj, *obj, *player, *lastobj, *objfreelist, *killerobj;
  37.  
  38. boolean noclip, ammocheat;
  39. int godmode, singlestep, extravbls = 0;
  40.  
  41. byte tilemap[MAPSIZE][MAPSIZE]; // wall values only
  42. byte spotvis[MAPSIZE][MAPSIZE];
  43. objtype *actorat[MAPSIZE][MAPSIZE];
  44.  
  45. //
  46. // replacing refresh manager
  47. //
  48. unsigned tics;
  49.  
  50. //
  51. // control info
  52. //
  53. boolean mouseenabled, joystickenabled;
  54. int dirscan[4] = { sc_UpArrow, sc_RightArrow, sc_DownArrow, sc_LeftArrow };
  55. int buttonscan[NUMBUTTONS] = { sc_Control, sc_Alt, sc_LShift, sc_Space, sc_1, sc_2, sc_3, sc_4 };
  56. int buttonmouse[4] = { bt_attack, bt_strafe, bt_use, bt_nobutton };
  57. int buttonjoy[32] = {
  58. #ifdef _arch_dreamcast
  59.     bt_attack, bt_strafe, bt_use, bt_run, bt_esc, bt_prevweapon, bt_nobutton, bt_nextweapon,
  60.     bt_pause, bt_strafeleft, bt_straferight, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton,
  61. #else
  62.     bt_attack, bt_strafe, bt_use, bt_run, bt_strafeleft, bt_straferight, bt_esc, bt_pause,
  63.     bt_prevweapon, bt_nextweapon, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton,
  64. #endif
  65.     bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton,
  66.     bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton
  67. };
  68.  
  69. int viewsize;
  70.  
  71. boolean buttonheld[NUMBUTTONS];
  72.  
  73. boolean demorecord, demoplayback;
  74. int8_t *demoptr, *lastdemoptr;
  75. memptr demobuffer;
  76.  
  77. //
  78. // current user input
  79. //
  80. int controlx, controly;         // range from -100 to 100 per tic
  81. boolean buttonstate[NUMBUTTONS];
  82.  
  83. int lastgamemusicoffset = 0;
  84.  
  85.  
  86. //===========================================================================
  87.  
  88.  
  89. void CenterWindow (word w, word h);
  90. void InitObjList (void);
  91. void RemoveObj (objtype * gone);
  92. void PollControls (void);
  93. int StopMusic (void);
  94. void StartMusic (void);
  95. void ContinueMusic (int offs);
  96. void PlayLoop (void);
  97.  
  98. /*
  99. =============================================================================
  100.  
  101.                                                  LOCAL VARIABLES
  102.  
  103. =============================================================================
  104. */
  105.  
  106.  
  107. objtype dummyobj;
  108.  
  109. //
  110. // LIST OF SONGS FOR EACH VERSION
  111. //
  112. int songs[] = {
  113. #ifndef SPEAR
  114.     //
  115.     // Episode One
  116.     //
  117.     GETTHEM_MUS,
  118.     SEARCHN_MUS,
  119.     POW_MUS,
  120.     SUSPENSE_MUS,
  121.     GETTHEM_MUS,
  122.     SEARCHN_MUS,
  123.     POW_MUS,
  124.     SUSPENSE_MUS,
  125.  
  126.     WARMARCH_MUS,               // Boss level
  127.     CORNER_MUS,                 // Secret level
  128.  
  129.     //
  130.     // Episode Two
  131.     //
  132.     NAZI_OMI_MUS,
  133.     PREGNANT_MUS,
  134.     GOINGAFT_MUS,
  135.     HEADACHE_MUS,
  136.     NAZI_OMI_MUS,
  137.     PREGNANT_MUS,
  138.     HEADACHE_MUS,
  139.     GOINGAFT_MUS,
  140.  
  141.     WARMARCH_MUS,               // Boss level
  142.     DUNGEON_MUS,                // Secret level
  143.  
  144.     //
  145.     // Episode Three
  146.     //
  147.     INTROCW3_MUS,
  148.     NAZI_RAP_MUS,
  149.     TWELFTH_MUS,
  150.     ZEROHOUR_MUS,
  151.     INTROCW3_MUS,
  152.     NAZI_RAP_MUS,
  153.     TWELFTH_MUS,
  154.     ZEROHOUR_MUS,
  155.  
  156.     ULTIMATE_MUS,               // Boss level
  157.     PACMAN_MUS,                 // Secret level
  158.  
  159.     //
  160.     // Episode Four
  161.     //
  162.     GETTHEM_MUS,
  163.     SEARCHN_MUS,
  164.     POW_MUS,
  165.     SUSPENSE_MUS,
  166.     GETTHEM_MUS,
  167.     SEARCHN_MUS,
  168.     POW_MUS,
  169.     SUSPENSE_MUS,
  170.  
  171.     WARMARCH_MUS,               // Boss level
  172.     CORNER_MUS,                 // Secret level
  173.  
  174.     //
  175.     // Episode Five
  176.     //
  177.     NAZI_OMI_MUS,
  178.     PREGNANT_MUS,
  179.     GOINGAFT_MUS,
  180.     HEADACHE_MUS,
  181.     NAZI_OMI_MUS,
  182.     PREGNANT_MUS,
  183.     HEADACHE_MUS,
  184.     GOINGAFT_MUS,
  185.  
  186.     WARMARCH_MUS,               // Boss level
  187.     DUNGEON_MUS,                // Secret level
  188.  
  189.     //
  190.     // Episode Six
  191.     //
  192.     INTROCW3_MUS,
  193.     NAZI_RAP_MUS,
  194.     TWELFTH_MUS,
  195.     ZEROHOUR_MUS,
  196.     INTROCW3_MUS,
  197.     NAZI_RAP_MUS,
  198.     TWELFTH_MUS,
  199.     ZEROHOUR_MUS,
  200.  
  201.     ULTIMATE_MUS,               // Boss level
  202.     FUNKYOU_MUS                 // Secret level
  203. #else
  204.  
  205.     //////////////////////////////////////////////////////////////
  206.     //
  207.     // SPEAR OF DESTINY TRACKS
  208.     //
  209.     //////////////////////////////////////////////////////////////
  210.     XTIPTOE_MUS,
  211.     XFUNKIE_MUS,
  212.     XDEATH_MUS,
  213.     XGETYOU_MUS,                // DON'T KNOW
  214.     ULTIMATE_MUS,               // Trans Gr�sse
  215.  
  216.     DUNGEON_MUS,
  217.     GOINGAFT_MUS,
  218.     POW_MUS,
  219.     TWELFTH_MUS,
  220.     ULTIMATE_MUS,               // Barnacle Wilhelm BOSS
  221.  
  222.     NAZI_OMI_MUS,
  223.     GETTHEM_MUS,
  224.     SUSPENSE_MUS,
  225.     SEARCHN_MUS,
  226.     ZEROHOUR_MUS,
  227.     ULTIMATE_MUS,               // Super Mutant BOSS
  228.  
  229.     XPUTIT_MUS,
  230.     ULTIMATE_MUS,               // Death Knight BOSS
  231.  
  232.     XJAZNAZI_MUS,               // Secret level
  233.     XFUNKIE_MUS,                // Secret level (DON'T KNOW)
  234.  
  235.     XEVIL_MUS                   // Angel of Death BOSS
  236. #endif
  237. };
  238.  
  239.  
  240. /*
  241. =============================================================================
  242.  
  243.                                USER CONTROL
  244.  
  245. =============================================================================
  246. */
  247.  
  248. /*
  249. ===================
  250. =
  251. = PollKeyboardButtons
  252. =
  253. ===================
  254. */
  255.  
  256. void PollKeyboardButtons (void)
  257. {
  258.     int i;
  259.  
  260.     for (i = 0; i < NUMBUTTONS; i++)
  261.         if (Keyboard[buttonscan[i]])
  262.             buttonstate[i] = true;
  263. }
  264.  
  265.  
  266. /*
  267. ===================
  268. =
  269. = PollMouseButtons
  270. =
  271. ===================
  272. */
  273.  
  274. void PollMouseButtons (void)
  275. {
  276.     int buttons = IN_MouseButtons ();
  277.  
  278.     if (buttons & 1)
  279.         buttonstate[buttonmouse[0]] = true;
  280.     if (buttons & 2)
  281.         buttonstate[buttonmouse[1]] = true;
  282.     if (buttons & 4)
  283.         buttonstate[buttonmouse[2]] = true;
  284. }
  285.  
  286.  
  287.  
  288. /*
  289. ===================
  290. =
  291. = PollJoystickButtons
  292. =
  293. ===================
  294. */
  295.  
  296. void PollJoystickButtons (void)
  297. {
  298.     int buttons = IN_JoyButtons();
  299.  
  300.     for(int i = 0, val = 1; i < JoyNumButtons; i++, val <<= 1)
  301.     {
  302.         if(buttons & val)
  303.             buttonstate[buttonjoy[i]] = true;
  304.     }
  305. }
  306.  
  307.  
  308. /*
  309. ===================
  310. =
  311. = PollKeyboardMove
  312. =
  313. ===================
  314. */
  315.  
  316. void PollKeyboardMove (void)
  317. {
  318.     int delta = buttonstate[bt_run] ? RUNMOVE * tics : BASEMOVE * tics;
  319.  
  320.     if (Keyboard[dirscan[di_north]])
  321.         controly -= delta;
  322.     if (Keyboard[dirscan[di_south]])
  323.         controly += delta;
  324.     if (Keyboard[dirscan[di_west]])
  325.         controlx -= delta;
  326.     if (Keyboard[dirscan[di_east]])
  327.         controlx += delta;
  328. }
  329.  
  330.  
  331. /*
  332. ===================
  333. =
  334. = PollMouseMove
  335. =
  336. ===================
  337. */
  338.  
  339. void PollMouseMove (void)
  340. {
  341.     int mousexmove, mouseymove;
  342.  
  343.     SDL_GetMouseState(&mousexmove, &mouseymove);
  344.     if(IN_IsInputGrabbed())
  345.         IN_CenterMouse();
  346.  
  347.     mousexmove -= screenWidth / 2;
  348.     mouseymove -= screenHeight / 2;
  349.  
  350.     controlx += mousexmove * 10 / (13 - mouseadjustment);
  351.     controly += mouseymove * 20 / (13 - mouseadjustment);
  352. }
  353.  
  354.  
  355. /*
  356. ===================
  357. =
  358. = PollJoystickMove
  359. =
  360. ===================
  361. */
  362.  
  363. void PollJoystickMove (void)
  364. {
  365.     int joyx, joyy;
  366.  
  367.     IN_GetJoyDelta (&joyx, &joyy);
  368.  
  369.     int delta = buttonstate[bt_run] ? RUNMOVE * tics : BASEMOVE * tics;
  370.  
  371.     if (joyx > 64 || buttonstate[bt_turnright])
  372.         controlx += delta;
  373.     else if (joyx < -64  || buttonstate[bt_turnleft])
  374.         controlx -= delta;
  375.     if (joyy > 64 || buttonstate[bt_movebackward])
  376.         controly += delta;
  377.     else if (joyy < -64 || buttonstate[bt_moveforward])
  378.         controly -= delta;
  379. }
  380.  
  381. /*
  382. ===================
  383. =
  384. = PollControls
  385. =
  386. = Gets user or demo input, call once each frame
  387. =
  388. = controlx              set between -100 and 100 per tic
  389. = controly
  390. = buttonheld[]  the state of the buttons LAST frame
  391. = buttonstate[] the state of the buttons THIS frame
  392. =
  393. ===================
  394. */
  395.  
  396. void PollControls (void)
  397. {
  398.     int max, min, i;
  399.     byte buttonbits;
  400.  
  401.     IN_ProcessEvents();
  402.  
  403. //
  404. // get timing info for last frame
  405. //
  406.     if (demoplayback || demorecord)   // demo recording and playback needs to be constant
  407.     {
  408.         // wait up to DEMOTICS Wolf tics
  409.         uint32_t curtime =  uSDL_GetTicks();
  410.         lasttimecount += DEMOTICS;
  411.         int32_t timediff = (lasttimecount * 100) / 7 - curtime;
  412.         if(timediff > 0)
  413.             uSDL_Delay(timediff);
  414.  
  415.         if(timediff < -2 * DEMOTICS)       // more than 2-times DEMOTICS behind?
  416.             lasttimecount = (curtime * 7) / 100;    // yes, set to current timecount
  417.  
  418.         tics = DEMOTICS;
  419.     }
  420.     else
  421.         CalcTics ();
  422.  
  423.     controlx = 0;
  424.     controly = 0;
  425.     memcpy (buttonheld, buttonstate, sizeof (buttonstate));
  426.     memset (buttonstate, 0, sizeof (buttonstate));
  427.  
  428.     if (demoplayback)
  429.     {
  430.         //
  431.         // read commands from demo buffer
  432.         //
  433.         buttonbits = *demoptr++;
  434.         for (i = 0; i < NUMBUTTONS; i++)
  435.         {
  436.             buttonstate[i] = buttonbits & 1;
  437.             buttonbits >>= 1;
  438.         }
  439.  
  440.         controlx = *demoptr++;
  441.         controly = *demoptr++;
  442.  
  443.         if (demoptr == lastdemoptr)
  444.             playstate = ex_completed;   // demo is done
  445.  
  446.         controlx *= (int) tics;
  447.         controly *= (int) tics;
  448.  
  449.         return;
  450.     }
  451.  
  452.  
  453. //
  454. // get button states
  455. //
  456.     PollKeyboardButtons ();
  457.  
  458.     if (mouseenabled && IN_IsInputGrabbed())
  459.         PollMouseButtons ();
  460.  
  461.     if (joystickenabled)
  462.         PollJoystickButtons ();
  463.  
  464. //
  465. // get movements
  466. //
  467.     PollKeyboardMove ();
  468.  
  469.     if (mouseenabled && IN_IsInputGrabbed())
  470.         PollMouseMove ();
  471.  
  472.     if (joystickenabled)
  473.         PollJoystickMove ();
  474.  
  475. //
  476. // bound movement to a maximum
  477. //
  478.     max = 100 * tics;
  479.     min = -max;
  480.     if (controlx > max)
  481.         controlx = max;
  482.     else if (controlx < min)
  483.         controlx = min;
  484.  
  485.     if (controly > max)
  486.         controly = max;
  487.     else if (controly < min)
  488.         controly = min;
  489.  
  490.     if (demorecord)
  491.     {
  492.         //
  493.         // save info out to demo buffer
  494.         //
  495.         controlx /= (int) tics;
  496.         controly /= (int) tics;
  497.  
  498.         buttonbits = 0;
  499.  
  500.         // TODO: Support 32-bit buttonbits
  501.         for (i = NUMBUTTONS - 1; i >= 0; i--)
  502.         {
  503.             buttonbits <<= 1;
  504.             if (buttonstate[i])
  505.                 buttonbits |= 1;
  506.         }
  507.  
  508.         *demoptr++ = buttonbits;
  509.         *demoptr++ = controlx;
  510.         *demoptr++ = controly;
  511.  
  512.         if (demoptr >= lastdemoptr - 8)
  513.             playstate = ex_completed;
  514.         else
  515.         {
  516.             controlx *= (int) tics;
  517.             controly *= (int) tics;
  518.         }
  519.     }
  520. }
  521.  
  522.  
  523.  
  524. //==========================================================================
  525.  
  526.  
  527.  
  528. ///////////////////////////////////////////////////////////////////////////
  529. //
  530. //      CenterWindow() - Generates a window of a given width & height in the
  531. //              middle of the screen
  532. //
  533. ///////////////////////////////////////////////////////////////////////////
  534. #define MAXX    320
  535. #define MAXY    160
  536.  
  537. void CenterWindow (word w, word h)
  538. {
  539.     US_DrawWindow (((MAXX / 8) - w) / 2, ((MAXY / 8) - h) / 2, w, h);
  540. }
  541.  
  542. //===========================================================================
  543.  
  544.  
  545. /*
  546. =====================
  547. =
  548. = CheckKeys
  549. =
  550. =====================
  551. */
  552.  
  553. void CheckKeys (void)
  554. {
  555.     ScanCode scan;
  556.  
  557.  
  558.     if (screenfaded || demoplayback)    // don't do anything with a faded screen
  559.         return;
  560.  
  561.     scan = LastScan;
  562.  
  563.  
  564. #ifdef SPEAR
  565.     //
  566.     // SECRET CHEAT CODE: TAB-G-F10
  567.     //
  568.     if (Keyboard[sc_Tab] && Keyboard[sc_G] && Keyboard[sc_F10])
  569.     {
  570.         WindowH = 160;
  571.         if (godmode)
  572.         {
  573.             Message ("God mode OFF");
  574.             SD_PlaySound (NOBONUSSND);
  575.         }
  576.         else
  577.         {
  578.             Message ("God mode ON");
  579.             SD_PlaySound (ENDBONUS2SND);
  580.         }
  581.  
  582.         IN_Ack ();
  583.         godmode ^= 1;
  584.         DrawPlayBorderSides ();
  585.         IN_ClearKeysDown ();
  586.         return;
  587.     }
  588. #endif
  589.  
  590.  
  591.     //
  592.     // SECRET CHEAT CODE: 'MLI'
  593.     //
  594.     if (Keyboard[sc_M] && Keyboard[sc_L] && Keyboard[sc_I])
  595.     {
  596.         gamestate.health = 100;
  597.         gamestate.ammo = 99;
  598.         gamestate.keys = 3;
  599.         gamestate.score = 0;
  600.         gamestate.TimeCount += 42000L;
  601.         GiveWeapon (wp_chaingun);
  602.         DrawWeapon ();
  603.         DrawHealth ();
  604.         DrawKeys ();
  605.         DrawAmmo ();
  606.         DrawScore ();
  607.  
  608.         ClearMemory ();
  609.         CA_CacheGrChunk (STARTFONT + 1);
  610.         ClearSplitVWB ();
  611.  
  612.         Message (STR_CHEATER1 "\n"
  613.                  STR_CHEATER2 "\n\n" STR_CHEATER3 "\n" STR_CHEATER4 "\n" STR_CHEATER5);
  614.  
  615.         UNCACHEGRCHUNK (STARTFONT + 1);
  616.         IN_ClearKeysDown ();
  617.         IN_Ack ();
  618.  
  619.         if (viewsize < 17)
  620.             DrawPlayBorder ();
  621.     }
  622.  
  623.     //
  624.     // OPEN UP DEBUG KEYS
  625.     //
  626. #ifdef DEBUGKEYS
  627.     if (Keyboard[sc_BackSpace] && Keyboard[sc_LShift] && Keyboard[sc_Alt] && param_debugmode)
  628.     {
  629.         ClearMemory ();
  630.         CA_CacheGrChunk (STARTFONT + 1);
  631.         ClearSplitVWB ();
  632.  
  633.         Message ("Debugging keys are\nnow available!");
  634.         UNCACHEGRCHUNK (STARTFONT + 1);
  635.         IN_ClearKeysDown ();
  636.         IN_Ack ();
  637.  
  638.         DrawPlayBorderSides ();
  639.         DebugOk = 1;
  640.     }
  641. #endif
  642.  
  643.     //
  644.     // TRYING THE KEEN CHEAT CODE!
  645.     //
  646.     if (Keyboard[sc_B] && Keyboard[sc_A] && Keyboard[sc_T])
  647.     {
  648.         ClearMemory ();
  649.         CA_CacheGrChunk (STARTFONT + 1);
  650.         ClearSplitVWB ();
  651.  
  652.         Message ("Commander Keen is also\n"
  653.                  "available from Apogee, but\n"
  654.                  "then, you already know\n" "that - right, Cheatmeister?!");
  655.  
  656.         UNCACHEGRCHUNK (STARTFONT + 1);
  657.         IN_ClearKeysDown ();
  658.         IN_Ack ();
  659.  
  660.         if (viewsize < 18)
  661.             DrawPlayBorder ();
  662.     }
  663.  
  664. //
  665. // pause key weirdness can't be checked as a scan code
  666. //
  667.     if(buttonstate[bt_pause]) Paused = true;
  668.     if(Paused)
  669.     {
  670.         int lastoffs = StopMusic();
  671.         LatchDrawPic (20 - 4, 80 - 2 * 8, PAUSEDPIC);
  672.         VH_UpdateScreen();
  673.         IN_Ack ();
  674.         Paused = false;
  675.         ContinueMusic(lastoffs);
  676.         if (MousePresent && IN_IsInputGrabbed())
  677.             IN_CenterMouse();     // Clear accumulated mouse movement
  678.         lasttimecount = GetTimeCount();
  679.         return;
  680.     }
  681.  
  682. //
  683. // F1-F7/ESC to enter control panel
  684. //
  685.     if (
  686. #ifndef DEBCHECK
  687.            scan == sc_F10 ||
  688. #endif
  689.            scan == sc_F9 || scan == sc_F7 || scan == sc_F8)     // pop up quit dialog
  690.     {
  691.         short oldmapon = gamestate.mapon;
  692.         short oldepisode = gamestate.episode;
  693.         ClearMemory ();
  694.         ClearSplitVWB ();
  695.         US_ControlPanel (scan);
  696.  
  697.         DrawPlayBorderSides ();
  698.  
  699.         SETFONTCOLOR (0, 15);
  700.         IN_ClearKeysDown ();
  701.         return;
  702.     }
  703.  
  704.     if ((scan >= sc_F1 && scan <= sc_F9) || scan == sc_Escape || buttonstate[bt_esc])
  705.     {
  706.         int lastoffs = StopMusic ();
  707.         ClearMemory ();
  708.         VW_FadeOut ();
  709.  
  710.         US_ControlPanel (buttonstate[bt_esc] ? sc_Escape : scan);
  711.  
  712.         SETFONTCOLOR (0, 15);
  713.         IN_ClearKeysDown ();
  714.         VW_FadeOut();
  715.         if(viewsize != 21)
  716.             DrawPlayScreen ();
  717.         if (!startgame && !loadedgame)
  718.             ContinueMusic (lastoffs);
  719.         if (loadedgame)
  720.             playstate = ex_abort;
  721.         lasttimecount = GetTimeCount();
  722.         if (MousePresent && IN_IsInputGrabbed())
  723.             IN_CenterMouse();     // Clear accumulated mouse movement
  724.         return;
  725.     }
  726.  
  727. //
  728. // TAB-? debug keys
  729. //
  730. #ifdef DEBUGKEYS
  731.     if (Keyboard[sc_Tab] && DebugOk)
  732.     {
  733.         CA_CacheGrChunk (STARTFONT);
  734.         fontnumber = 0;
  735.         SETFONTCOLOR (0, 15);
  736.         if (DebugKeys () && viewsize < 20)
  737.             DrawPlayBorder ();       // dont let the blue borders flash
  738.  
  739.         if (MousePresent && IN_IsInputGrabbed())
  740.             IN_CenterMouse();     // Clear accumulated mouse movement
  741.  
  742.         lasttimecount = GetTimeCount();
  743.         return;
  744.     }
  745. #endif
  746. }
  747.  
  748.  
  749. //===========================================================================
  750.  
  751. /*
  752. #############################################################################
  753.  
  754.                                   The objlist data structure
  755.  
  756. #############################################################################
  757.  
  758. objlist containt structures for every actor currently playing.  The structure
  759. is accessed as a linked list starting at *player, ending when ob->next ==
  760. NULL.  GetNewObj inserts a new object at the end of the list, meaning that
  761. if an actor spawn another actor, the new one WILL get to think and react the
  762. same frame.  RemoveObj unlinks the given object and returns it to the free
  763. list, but does not damage the objects ->next pointer, so if the current object
  764. removes itself, a linked list following loop can still safely get to the
  765. next element.
  766.  
  767. <backwardly linked free list>
  768.  
  769. #############################################################################
  770. */
  771.  
  772.  
  773. /*
  774. =========================
  775. =
  776. = InitActorList
  777. =
  778. = Call to clear out the actor object lists returning them all to the free
  779. = list.  Allocates a special spot for the player.
  780. =
  781. =========================
  782. */
  783.  
  784. int objcount;
  785.  
  786. void InitActorList (void)
  787. {
  788.     int i;
  789.  
  790. //
  791. // init the actor lists
  792. //
  793.     for (i = 0; i < MAXACTORS; i++)
  794.     {
  795.         objlist[i].prev = &objlist[i + 1];
  796.         objlist[i].next = NULL;
  797.     }
  798.  
  799.     objlist[MAXACTORS - 1].prev = NULL;
  800.  
  801.     objfreelist = &objlist[0];
  802.     lastobj = NULL;
  803.  
  804.     objcount = 0;
  805.  
  806. //
  807. // give the player the first free spots
  808. //
  809.     GetNewActor ();
  810.     player = newobj;
  811.  
  812. }
  813.  
  814. //===========================================================================
  815.  
  816. /*
  817. =========================
  818. =
  819. = GetNewActor
  820. =
  821. = Sets the global variable new to point to a free spot in objlist.
  822. = The free spot is inserted at the end of the liked list
  823. =
  824. = When the object list is full, the caller can either have it bomb out ot
  825. = return a dummy object pointer that will never get used
  826. =
  827. =========================
  828. */
  829.  
  830. void GetNewActor (void)
  831. {
  832.     if (!objfreelist)
  833.         Quit ("GetNewActor: No free spots in objlist!");
  834.  
  835.     newobj = objfreelist;
  836.     objfreelist = newobj->prev;
  837.     memset (newobj, 0, sizeof (*newobj));
  838.  
  839.     if (lastobj)
  840.         lastobj->next = newobj;
  841.     newobj->prev = lastobj;     // new->next is allready NULL from memset
  842.  
  843.     newobj->active = ac_no;
  844.     lastobj = newobj;
  845.  
  846.     objcount++;
  847. }
  848.  
  849. //===========================================================================
  850.  
  851. /*
  852. =========================
  853. =
  854. = RemoveObj
  855. =
  856. = Add the given object back into the free list, and unlink it from it's
  857. = neighbors
  858. =
  859. =========================
  860. */
  861.  
  862. void RemoveObj (objtype * gone)
  863. {
  864.     if (gone == player)
  865.         Quit ("RemoveObj: Tried to remove the player!");
  866.  
  867.     gone->state = NULL;
  868.  
  869. //
  870. // fix the next object's back link
  871. //
  872.     if (gone == lastobj)
  873.         lastobj = (objtype *) gone->prev;
  874.     else
  875.         gone->next->prev = gone->prev;
  876.  
  877. //
  878. // fix the previous object's forward link
  879. //
  880.     gone->prev->next = gone->next;
  881.  
  882. //
  883. // add it back in to the free list
  884. //
  885.     gone->prev = objfreelist;
  886.     objfreelist = gone;
  887.  
  888.     objcount--;
  889. }
  890.  
  891. /*
  892. =============================================================================
  893.  
  894.                                                 MUSIC STUFF
  895.  
  896. =============================================================================
  897. */
  898.  
  899.  
  900. /*
  901. =================
  902. =
  903. = StopMusic
  904. =
  905. =================
  906. */
  907. int StopMusic (void)
  908. {
  909.     int lastoffs = SD_MusicOff ();
  910.  
  911.     UNCACHEAUDIOCHUNK (STARTMUSIC + lastmusicchunk);
  912.  
  913.     return lastoffs;
  914. }
  915.  
  916. //==========================================================================
  917.  
  918.  
  919. /*
  920. =================
  921. =
  922. = StartMusic
  923. =
  924. =================
  925. */
  926.  
  927. void StartMusic ()
  928. {
  929.     SD_MusicOff ();
  930.     lastmusicchunk = (musicnames) songs[gamestate.mapon + gamestate.episode * 10];
  931.     SD_StartMusic(STARTMUSIC + lastmusicchunk);
  932. }
  933.  
  934. void ContinueMusic (int offs)
  935. {
  936.     SD_MusicOff ();
  937.     lastmusicchunk = (musicnames) songs[gamestate.mapon + gamestate.episode * 10];
  938.     SD_ContinueMusic(STARTMUSIC + lastmusicchunk, offs);
  939. }
  940.  
  941. /*
  942. =============================================================================
  943.  
  944.                                         PALETTE SHIFTING STUFF
  945.  
  946. =============================================================================
  947. */
  948.  
  949. #define NUMREDSHIFTS    6
  950. #define REDSTEPS        8
  951.  
  952. #define NUMWHITESHIFTS  3
  953. #define WHITESTEPS      20
  954. #define WHITETICS       6
  955.  
  956.  
  957. SDL_Color redshifts[NUMREDSHIFTS][256];
  958. SDL_Color whiteshifts[NUMWHITESHIFTS][256];
  959.  
  960. int damagecount, bonuscount;
  961. boolean palshifted;
  962.  
  963. /*
  964. =====================
  965. =
  966. = InitRedShifts
  967. =
  968. =====================
  969. */
  970.  
  971. void InitRedShifts (void)
  972. {
  973.     SDL_Color *workptr, *baseptr;
  974.     int i, j, delta;
  975.  
  976.  
  977. //
  978. // fade through intermediate frames
  979. //
  980.     for (i = 1; i <= NUMREDSHIFTS; i++)
  981.     {
  982.         workptr = redshifts[i - 1];
  983.         baseptr = gamepal;
  984.  
  985.         for (j = 0; j <= 255; j++)
  986.         {
  987.             delta = 256 - baseptr->r;
  988.             workptr->r = baseptr->r + delta * i / REDSTEPS;
  989.             delta = -baseptr->g;
  990.             workptr->g = baseptr->g + delta * i / REDSTEPS;
  991.             delta = -baseptr->b;
  992.             workptr->b = baseptr->b + delta * i / REDSTEPS;
  993.             baseptr++;
  994.             workptr++;
  995.         }
  996.     }
  997.  
  998.     for (i = 1; i <= NUMWHITESHIFTS; i++)
  999.     {
  1000.         workptr = whiteshifts[i - 1];
  1001.         baseptr = gamepal;
  1002.  
  1003.         for (j = 0; j <= 255; j++)
  1004.         {
  1005.             delta = 256 - baseptr->r;
  1006.             workptr->r = baseptr->r + delta * i / WHITESTEPS;
  1007.             delta = 248 - baseptr->g;
  1008.             workptr->g = baseptr->g + delta * i / WHITESTEPS;
  1009.             delta = 0-baseptr->b;
  1010.             workptr->b = baseptr->b + delta * i / WHITESTEPS;
  1011.             baseptr++;
  1012.             workptr++;
  1013.         }
  1014.     }
  1015. }
  1016.  
  1017.  
  1018. /*
  1019. =====================
  1020. =
  1021. = ClearPaletteShifts
  1022. =
  1023. =====================
  1024. */
  1025.  
  1026. void ClearPaletteShifts (void)
  1027. {
  1028.     bonuscount = damagecount = 0;
  1029.     palshifted = false;
  1030. }
  1031.  
  1032.  
  1033. /*
  1034. =====================
  1035. =
  1036. = StartBonusFlash
  1037. =
  1038. =====================
  1039. */
  1040.  
  1041. void StartBonusFlash (void)
  1042. {
  1043.     bonuscount = NUMWHITESHIFTS * WHITETICS;    // white shift palette
  1044. }
  1045.  
  1046.  
  1047. /*
  1048. =====================
  1049. =
  1050. = StartDamageFlash
  1051. =
  1052. =====================
  1053. */
  1054.  
  1055. void StartDamageFlash (int damage)
  1056. {
  1057.     damagecount += damage;
  1058. }
  1059.  
  1060.  
  1061. /*
  1062. =====================
  1063. =
  1064. = UpdatePaletteShifts
  1065. =
  1066. =====================
  1067. */
  1068.  
  1069. void UpdatePaletteShifts (void)
  1070. {
  1071.     int red, white;
  1072.  
  1073.     if (bonuscount)
  1074.     {
  1075.         white = bonuscount / WHITETICS + 1;
  1076.         if (white > NUMWHITESHIFTS)
  1077.             white = NUMWHITESHIFTS;
  1078.         bonuscount -= tics;
  1079.         if (bonuscount < 0)
  1080.             bonuscount = 0;
  1081.     }
  1082.     else
  1083.         white = 0;
  1084.  
  1085.  
  1086.     if (damagecount)
  1087.     {
  1088.         red = damagecount / 10 + 1;
  1089.         if (red > NUMREDSHIFTS)
  1090.             red = NUMREDSHIFTS;
  1091.  
  1092.         damagecount -= tics;
  1093.         if (damagecount < 0)
  1094.             damagecount = 0;
  1095.     }
  1096.     else
  1097.         red = 0;
  1098.  
  1099.     if (red)
  1100.     {
  1101.         VL_SetPalette (redshifts[red - 1], false);
  1102.         palshifted = true;
  1103.     }
  1104.     else if (white)
  1105.     {
  1106.         VL_SetPalette (whiteshifts[white - 1], false);
  1107.         palshifted = true;
  1108.     }
  1109.     else if (palshifted)
  1110.     {
  1111.         VL_SetPalette (gamepal, false);        // back to normal
  1112.         palshifted = false;
  1113.     }
  1114. }
  1115.  
  1116.  
  1117. /*
  1118. =====================
  1119. =
  1120. = FinishPaletteShifts
  1121. =
  1122. = Resets palette to normal if needed
  1123. =
  1124. =====================
  1125. */
  1126.  
  1127. void FinishPaletteShifts (void)
  1128. {
  1129.     if (palshifted)
  1130.     {
  1131.         palshifted = 0;
  1132.         VL_SetPalette (gamepal, true);
  1133.     }
  1134. }
  1135.  
  1136.  
  1137. /*
  1138. =============================================================================
  1139.  
  1140.                                                 CORE PLAYLOOP
  1141.  
  1142. =============================================================================
  1143. */
  1144.  
  1145.  
  1146. /*
  1147. =====================
  1148. =
  1149. = DoActor
  1150. =
  1151. =====================
  1152. */
  1153.  
  1154. void DoActor (objtype * ob)
  1155. {
  1156.     void (*think) (objtype *);
  1157.  
  1158.     if (!ob->active && !areabyplayer[ob->areanumber])
  1159.         return;
  1160.  
  1161.     if (!(ob->flags & (FL_NONMARK | FL_NEVERMARK)))
  1162.         actorat[ob->tilex][ob->tiley] = NULL;
  1163.  
  1164. //
  1165. // non transitional object
  1166. //
  1167.  
  1168.     if (!ob->ticcount)
  1169.     {
  1170.         think = (void (*)(objtype *)) ob->state->think;
  1171.         if (think)
  1172.         {
  1173.             think (ob);
  1174.             if (!ob->state)
  1175.             {
  1176.                 RemoveObj (ob);
  1177.                 return;
  1178.             }
  1179.         }
  1180.  
  1181.         if (ob->flags & FL_NEVERMARK)
  1182.             return;
  1183.  
  1184.         if ((ob->flags & FL_NONMARK) && actorat[ob->tilex][ob->tiley])
  1185.             return;
  1186.  
  1187.         actorat[ob->tilex][ob->tiley] = ob;
  1188.         return;
  1189.     }
  1190.  
  1191. //
  1192. // transitional object
  1193. //
  1194.     ob->ticcount -= (short) tics;
  1195.     while (ob->ticcount <= 0)
  1196.     {
  1197.         think = (void (*)(objtype *)) ob->state->action;        // end of state action
  1198.         if (think)
  1199.         {
  1200.             think (ob);
  1201.             if (!ob->state)
  1202.             {
  1203.                 RemoveObj (ob);
  1204.                 return;
  1205.             }
  1206.         }
  1207.  
  1208.         ob->state = ob->state->next;
  1209.  
  1210.         if (!ob->state)
  1211.         {
  1212.             RemoveObj (ob);
  1213.             return;
  1214.         }
  1215.  
  1216.         if (!ob->state->tictime)
  1217.         {
  1218.             ob->ticcount = 0;
  1219.             goto think;
  1220.         }
  1221.  
  1222.         ob->ticcount += ob->state->tictime;
  1223.     }
  1224.  
  1225. think:
  1226.     //
  1227.     // think
  1228.     //
  1229.     think = (void (*)(objtype *)) ob->state->think;
  1230.     if (think)
  1231.     {
  1232.         think (ob);
  1233.         if (!ob->state)
  1234.         {
  1235.             RemoveObj (ob);
  1236.             return;
  1237.         }
  1238.     }
  1239.  
  1240.     if (ob->flags & FL_NEVERMARK)
  1241.         return;
  1242.  
  1243.     if ((ob->flags & FL_NONMARK) && actorat[ob->tilex][ob->tiley])
  1244.         return;
  1245.  
  1246.     actorat[ob->tilex][ob->tiley] = ob;
  1247. }
  1248.  
  1249. //==========================================================================
  1250.  
  1251.  
  1252. /*
  1253. ===================
  1254. =
  1255. = PlayLoop
  1256. =
  1257. ===================
  1258. */
  1259. int32_t funnyticount;
  1260.  
  1261.  
  1262. void PlayLoop (void)
  1263. {
  1264. #if defined(USE_FEATUREFLAGS) && defined(USE_CLOUDSKY)
  1265.     if(GetFeatureFlags() & FF_CLOUDSKY)
  1266.         InitSky();
  1267. #endif
  1268.  
  1269. #ifdef USE_SHADING
  1270.     InitLevelShadeTable();
  1271. #endif
  1272.  
  1273.     playstate = ex_stillplaying;
  1274.     lasttimecount = GetTimeCount();
  1275.     frameon = 0;
  1276.     anglefrac = 0;
  1277.     facecount = 0;
  1278.     funnyticount = 0;
  1279.     memset (buttonstate, 0, sizeof (buttonstate));
  1280.     ClearPaletteShifts ();
  1281.  
  1282.     if (MousePresent && IN_IsInputGrabbed())
  1283.         IN_CenterMouse();         // Clear accumulated mouse movement
  1284.  
  1285.     if (demoplayback)
  1286.         IN_StartAck ();
  1287.  
  1288.     do
  1289.     {
  1290.         PollControls ();
  1291.  
  1292. //
  1293. // actor thinking
  1294. //
  1295.         madenoise = false;
  1296.  
  1297.         MoveDoors ();
  1298.         MovePWalls ();
  1299.  
  1300.         for (obj = player; obj; obj = obj->next)
  1301.             DoActor (obj);
  1302.  
  1303.         UpdatePaletteShifts ();
  1304.  
  1305.         ThreeDRefresh ();
  1306.  
  1307.         //
  1308.         // MAKE FUNNY FACE IF BJ DOESN'T MOVE FOR AWHILE
  1309.         //
  1310. #ifdef SPEAR
  1311.         funnyticount += tics;
  1312.         if (funnyticount > 30l * 70)
  1313.         {
  1314.             funnyticount = 0;
  1315.             if(viewsize != 21)
  1316.                 StatusDrawFace(BJWAITING1PIC + (US_RndT () & 1));
  1317.             facecount = 0;
  1318.         }
  1319. #endif
  1320.  
  1321.         gamestate.TimeCount += tics;
  1322.  
  1323.         UpdateSoundLoc ();      // JAB
  1324.         if (screenfaded)
  1325.             VW_FadeIn ();
  1326.  
  1327.         CheckKeys ();
  1328.  
  1329. //
  1330. // debug aids
  1331. //
  1332.         if (singlestep)
  1333.         {
  1334.             VW_WaitVBL (singlestep);
  1335.             lasttimecount = GetTimeCount();
  1336.         }
  1337.         if (extravbls)
  1338.             VW_WaitVBL (extravbls);
  1339.  
  1340.         if (demoplayback)
  1341.         {
  1342.             if (IN_CheckAck ())
  1343.             {
  1344.                 IN_ClearKeysDown ();
  1345.                 playstate = ex_abort;
  1346.             }
  1347.         }
  1348.     }
  1349.     while (!playstate && !startgame);
  1350.  
  1351.     if (playstate != ex_died)
  1352.         FinishPaletteShifts ();
  1353. }
  1354.