]> 4ch.mooo.com Git - 16.git/blobdiff - 16/WOLFSRC/wl_play.c
got 8086 port of wolf3d to work and sod to work
[16.git] / 16 / WOLFSRC / wl_play.c
diff --git a/16/WOLFSRC/wl_play.c b/16/WOLFSRC/wl_play.c
new file mode 100755 (executable)
index 0000000..447c893
--- /dev/null
@@ -0,0 +1,1473 @@
+// WL_PLAY.C\r
+\r
+#include "WL_DEF.H"\r
+#pragma hdrstop\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define sc_Question    0x35\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+boolean                madenoise;                                      // true when shooting or screaming\r
+\r
+exit_t         playstate;\r
+\r
+int                    DebugOk;\r
+\r
+objtype        objlist[MAXACTORS],*new,*obj,*player,*lastobj,\r
+                       *objfreelist,*killerobj;\r
+\r
+unsigned       farmapylookup[MAPSIZE];\r
+byte           *nearmapylookup[MAPSIZE];\r
+\r
+boolean                singlestep,godmode,noclip;\r
+int                    extravbls;\r
+\r
+byte           tilemap[MAPSIZE][MAPSIZE];      // wall values only\r
+byte           spotvis[MAPSIZE][MAPSIZE];\r
+objtype                *actorat[MAPSIZE][MAPSIZE];\r
+\r
+//\r
+// replacing refresh manager\r
+//\r
+unsigned       mapwidth,mapheight,tics;\r
+boolean                compatability;\r
+byte           *updateptr;\r
+unsigned       mapwidthtable[64];\r
+unsigned       uwidthtable[UPDATEHIGH];\r
+unsigned       blockstarts[UPDATEWIDE*UPDATEHIGH];\r
+//uso: replace: byte            update[UPDATESIZE];\r
+//uso: is needed? byte    update[UPDATEHIGH][UPDATEWIDE];\r
+\r
+//\r
+// control info\r
+//\r
+boolean                mouseenabled,joystickenabled,joypadenabled,joystickprogressive;\r
+int                    joystickport;\r
+int                    dirscan[4] = {sc_UpArrow,sc_RightArrow,sc_DownArrow,sc_LeftArrow};\r
+int                    buttonscan[NUMBUTTONS] =\r
+                       {sc_Control,sc_Alt,sc_RShift,sc_Space,sc_1,sc_2,sc_3,sc_4};\r
+int                    buttonmouse[4]={bt_attack,bt_strafe,bt_use,bt_nobutton};\r
+int                    buttonjoy[4]={bt_attack,bt_strafe,bt_use,bt_run};\r
+\r
+int                    viewsize;\r
+\r
+boolean                buttonheld[NUMBUTTONS];\r
+\r
+boolean                demorecord,demoplayback;\r
+char           far *demoptr, far *lastdemoptr;\r
+memptr         demobuffer;\r
+\r
+//\r
+// curent user input\r
+//\r
+int                    controlx,controly;              // range from -100 to 100 per tic\r
+boolean                buttonstate[NUMBUTTONS];\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+void   CenterWindow(word w,word h);\r
+void   InitObjList (void);\r
+void   RemoveObj (objtype *gone);\r
+void   PollControls (void);\r
+void   StopMusic(void);\r
+void   StartMusic(void);\r
+void   PlayLoop (void);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+objtype dummyobj;\r
+\r
+//\r
+// LIST OF SONGS FOR EACH VERSION\r
+//\r
+int songs[]=\r
+{\r
+#ifndef SPEAR\r
+ //\r
+ // Episode One\r
+ //\r
+ GETTHEM_MUS,\r
+ SEARCHN_MUS,\r
+ POW_MUS,\r
+ SUSPENSE_MUS,\r
+ GETTHEM_MUS,\r
+ SEARCHN_MUS,\r
+ POW_MUS,\r
+ SUSPENSE_MUS,\r
+\r
+ WARMARCH_MUS, // Boss level\r
+ CORNER_MUS,   // Secret level\r
+\r
+ //\r
+ // Episode Two\r
+ //\r
+ NAZI_OMI_MUS,\r
+ PREGNANT_MUS,\r
+ GOINGAFT_MUS,\r
+ HEADACHE_MUS,\r
+ NAZI_OMI_MUS,\r
+ PREGNANT_MUS,\r
+ HEADACHE_MUS,\r
+ GOINGAFT_MUS,\r
+\r
+ WARMARCH_MUS, // Boss level\r
+ DUNGEON_MUS,  // Secret level\r
+\r
+ //\r
+ // Episode Three\r
+ //\r
+ INTROCW3_MUS,\r
+ NAZI_RAP_MUS,\r
+ TWELFTH_MUS,\r
+ ZEROHOUR_MUS,\r
+ INTROCW3_MUS,\r
+ NAZI_RAP_MUS,\r
+ TWELFTH_MUS,\r
+ ZEROHOUR_MUS,\r
+\r
+ ULTIMATE_MUS, // Boss level\r
+ PACMAN_MUS,   // Secret level\r
+\r
+ //\r
+ // Episode Four\r
+ //\r
+ GETTHEM_MUS,\r
+ SEARCHN_MUS,\r
+ POW_MUS,\r
+ SUSPENSE_MUS,\r
+ GETTHEM_MUS,\r
+ SEARCHN_MUS,\r
+ POW_MUS,\r
+ SUSPENSE_MUS,\r
+\r
+ WARMARCH_MUS, // Boss level\r
+ CORNER_MUS,   // Secret level\r
+\r
+ //\r
+ // Episode Five\r
+ //\r
+ NAZI_OMI_MUS,\r
+ PREGNANT_MUS,\r
+ GOINGAFT_MUS,\r
+ HEADACHE_MUS,\r
+ NAZI_OMI_MUS,\r
+ PREGNANT_MUS,\r
+ HEADACHE_MUS,\r
+ GOINGAFT_MUS,\r
+\r
+ WARMARCH_MUS, // Boss level\r
+ DUNGEON_MUS,  // Secret level\r
+\r
+ //\r
+ // Episode Six\r
+ //\r
+ INTROCW3_MUS,\r
+ NAZI_RAP_MUS,\r
+ TWELFTH_MUS,\r
+ ZEROHOUR_MUS,\r
+ INTROCW3_MUS,\r
+ NAZI_RAP_MUS,\r
+ TWELFTH_MUS,\r
+ ZEROHOUR_MUS,\r
+\r
+ ULTIMATE_MUS, // Boss level\r
+ FUNKYOU_MUS           // Secret level\r
+#else\r
+\r
+ //////////////////////////////////////////////////////////////\r
+ //\r
+ // SPEAR OF DESTINY TRACKS\r
+ //\r
+ //////////////////////////////////////////////////////////////\r
+ XTIPTOE_MUS,\r
+ XFUNKIE_MUS,\r
+ XDEATH_MUS,\r
+ XGETYOU_MUS,          // DON'T KNOW\r
+ ULTIMATE_MUS, // Trans Gr\94sse\r
+\r
+ DUNGEON_MUS,\r
+ GOINGAFT_MUS,\r
+ POW_MUS,\r
+ TWELFTH_MUS,\r
+ ULTIMATE_MUS, // Barnacle Wilhelm BOSS\r
+\r
+ NAZI_OMI_MUS,\r
+ GETTHEM_MUS,\r
+ SUSPENSE_MUS,\r
+ SEARCHN_MUS,\r
+ ZEROHOUR_MUS,\r
+ ULTIMATE_MUS, // Super Mutant BOSS\r
+\r
+ XPUTIT_MUS,\r
+ ULTIMATE_MUS, // Death Knight BOSS\r
+\r
+ XJAZNAZI_MUS, // Secret level\r
+ XFUNKIE_MUS,  // Secret level (DON'T KNOW)\r
+\r
+ XEVIL_MUS             // Angel of Death BOSS\r
+\r
+#endif\r
+};\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                 USER CONTROL\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+#define BASEMOVE               35\r
+#define RUNMOVE                        70\r
+#define BASETURN               35\r
+#define RUNTURN                        70\r
+\r
+#define JOYSCALE               2\r
+\r
+/*\r
+===================\r
+=\r
+= PollKeyboardButtons\r
+=\r
+===================\r
+*/\r
+\r
+void PollKeyboardButtons (void)\r
+{\r
+       int             i;\r
+\r
+       for (i=0;i<NUMBUTTONS;i++)\r
+               if (Keyboard[buttonscan[i]])\r
+                       buttonstate[i] = true;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PollMouseButtons\r
+=\r
+===================\r
+*/\r
+\r
+void PollMouseButtons (void)\r
+{\r
+       int     buttons;\r
+\r
+       buttons = IN_MouseButtons ();\r
+\r
+       if (buttons&1)\r
+               buttonstate[buttonmouse[0]] = true;\r
+       if (buttons&2)\r
+               buttonstate[buttonmouse[1]] = true;\r
+       if (buttons&4)\r
+               buttonstate[buttonmouse[2]] = true;\r
+}\r
+\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PollJoystickButtons\r
+=\r
+===================\r
+*/\r
+\r
+void PollJoystickButtons (void)\r
+{\r
+       int     buttons;\r
+\r
+       buttons = IN_JoyButtons ();\r
+\r
+       if (joystickport && !joypadenabled)\r
+       {\r
+               if (buttons&4)\r
+                       buttonstate[buttonjoy[0]] = true;\r
+               if (buttons&8)\r
+                       buttonstate[buttonjoy[1]] = true;\r
+       }\r
+       else\r
+       {\r
+               if (buttons&1)\r
+                       buttonstate[buttonjoy[0]] = true;\r
+               if (buttons&2)\r
+                       buttonstate[buttonjoy[1]] = true;\r
+               if (joypadenabled)\r
+               {\r
+                       if (buttons&4)\r
+                               buttonstate[buttonjoy[2]] = true;\r
+                       if (buttons&8)\r
+                               buttonstate[buttonjoy[3]] = true;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PollKeyboardMove\r
+=\r
+===================\r
+*/\r
+\r
+void PollKeyboardMove (void)\r
+{\r
+       if (buttonstate[bt_run])\r
+       {\r
+               if (Keyboard[dirscan[di_north]])\r
+                       controly -= RUNMOVE*tics;\r
+               if (Keyboard[dirscan[di_south]])\r
+                       controly += RUNMOVE*tics;\r
+               if (Keyboard[dirscan[di_west]])\r
+                       controlx -= RUNMOVE*tics;\r
+               if (Keyboard[dirscan[di_east]])\r
+                       controlx += RUNMOVE*tics;\r
+       }\r
+       else\r
+       {\r
+               if (Keyboard[dirscan[di_north]])\r
+                       controly -= BASEMOVE*tics;\r
+               if (Keyboard[dirscan[di_south]])\r
+                       controly += BASEMOVE*tics;\r
+               if (Keyboard[dirscan[di_west]])\r
+                       controlx -= BASEMOVE*tics;\r
+               if (Keyboard[dirscan[di_east]])\r
+                       controlx += BASEMOVE*tics;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PollMouseMove\r
+=\r
+===================\r
+*/\r
+\r
+void PollMouseMove (void)\r
+{\r
+       int     mousexmove,mouseymove;\r
+\r
+       Mouse(MDelta);\r
+       mousexmove = _CX;\r
+       mouseymove = _DX;\r
+\r
+       controlx += mousexmove*10/(13-mouseadjustment);\r
+       controly += mouseymove*20/(13-mouseadjustment);\r
+}\r
+\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PollJoystickMove\r
+=\r
+===================\r
+*/\r
+\r
+void PollJoystickMove (void)\r
+{\r
+       int     joyx,joyy;\r
+\r
+       INL_GetJoyDelta(joystickport,&joyx,&joyy);\r
+\r
+       if (joystickprogressive)\r
+       {\r
+               if (joyx > 64)\r
+                       controlx += (joyx-64)*JOYSCALE*tics;\r
+               else if (joyx < -64)\r
+                       controlx -= (-joyx-64)*JOYSCALE*tics;\r
+               if (joyy > 64)\r
+                       controlx += (joyy-64)*JOYSCALE*tics;\r
+               else if (joyy < -64)\r
+                       controly -= (-joyy-64)*JOYSCALE*tics;\r
+       }\r
+       else if (buttonstate[bt_run])\r
+       {\r
+               if (joyx > 64)\r
+                       controlx += RUNMOVE*tics;\r
+               else if (joyx < -64)\r
+                       controlx -= RUNMOVE*tics;\r
+               if (joyy > 64)\r
+                       controly += RUNMOVE*tics;\r
+               else if (joyy < -64)\r
+                       controly -= RUNMOVE*tics;\r
+       }\r
+       else\r
+       {\r
+               if (joyx > 64)\r
+                       controlx += BASEMOVE*tics;\r
+               else if (joyx < -64)\r
+                       controlx -= BASEMOVE*tics;\r
+               if (joyy > 64)\r
+                       controly += BASEMOVE*tics;\r
+               else if (joyy < -64)\r
+                       controly -= BASEMOVE*tics;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PollControls\r
+=\r
+= Gets user or demo input, call once each frame\r
+=\r
+= controlx             set between -100 and 100 per tic\r
+= controly\r
+= buttonheld[] the state of the buttons LAST frame\r
+= buttonstate[]        the state of the buttons THIS frame\r
+=\r
+===================\r
+*/\r
+\r
+void PollControls (void)\r
+{\r
+       int             max,min,i;\r
+       byte    buttonbits;\r
+\r
+//\r
+// get timing info for last frame\r
+//\r
+       if (demoplayback)\r
+       {\r
+               while (TimeCount<lasttimecount+DEMOTICS)\r
+               ;\r
+               TimeCount = lasttimecount + DEMOTICS;\r
+               lasttimecount += DEMOTICS;\r
+               tics = DEMOTICS;\r
+       }\r
+       else if (demorecord)                    // demo recording and playback needs\r
+       {                                                               // to be constant\r
+//\r
+// take DEMOTICS or more tics, and modify Timecount to reflect time taken\r
+//\r
+               while (TimeCount<lasttimecount+DEMOTICS)\r
+               ;\r
+               TimeCount = lasttimecount + DEMOTICS;\r
+               lasttimecount += DEMOTICS;\r
+               tics = DEMOTICS;\r
+       }\r
+       else\r
+               CalcTics ();\r
+\r
+       controlx = 0;\r
+       controly = 0;\r
+       memcpy (buttonheld,buttonstate,sizeof(buttonstate));\r
+       memset (buttonstate,0,sizeof(buttonstate));\r
+\r
+       if (demoplayback)\r
+       {\r
+       //\r
+       // read commands from demo buffer\r
+       //\r
+               buttonbits = *demoptr++;\r
+               for (i=0;i<NUMBUTTONS;i++)\r
+               {\r
+                       buttonstate[i] = buttonbits&1;\r
+                       buttonbits >>= 1;\r
+               }\r
+\r
+               controlx = *demoptr++;\r
+               controly = *demoptr++;\r
+\r
+               if (demoptr == lastdemoptr)\r
+                       playstate = ex_completed;               // demo is done\r
+\r
+               controlx *= (int)tics;\r
+               controly *= (int)tics;\r
+\r
+               return;\r
+       }\r
+\r
+\r
+//\r
+// get button states\r
+//\r
+       PollKeyboardButtons ();\r
+\r
+       if (mouseenabled)\r
+               PollMouseButtons ();\r
+\r
+       if (joystickenabled)\r
+               PollJoystickButtons ();\r
+\r
+//\r
+// get movements\r
+//\r
+       PollKeyboardMove ();\r
+\r
+       if (mouseenabled)\r
+               PollMouseMove ();\r
+\r
+       if (joystickenabled)\r
+               PollJoystickMove ();\r
+\r
+//\r
+// bound movement to a maximum\r
+//\r
+       max = 100*tics;\r
+       min = -max;\r
+       if (controlx > max)\r
+               controlx = max;\r
+       else if (controlx < min)\r
+               controlx = min;\r
+\r
+       if (controly > max)\r
+               controly = max;\r
+       else if (controly < min)\r
+               controly = min;\r
+\r
+       if (demorecord)\r
+       {\r
+       //\r
+       // save info out to demo buffer\r
+       //\r
+               controlx /= (int)tics;\r
+               controly /= (int)tics;\r
+\r
+               buttonbits = 0;\r
+\r
+               for (i=NUMBUTTONS-1;i>=0;i--)\r
+               {\r
+                       buttonbits <<= 1;\r
+                       if (buttonstate[i])\r
+                               buttonbits |= 1;\r
+               }\r
+\r
+               *demoptr++ = buttonbits;\r
+               *demoptr++ = controlx;\r
+               *demoptr++ = controly;\r
+\r
+               if (demoptr >= lastdemoptr)\r
+                       Quit ("Demo buffer overflowed!");\r
+\r
+               controlx *= (int)tics;\r
+               controly *= (int)tics;\r
+       }\r
+}\r
+\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     CenterWindow() - Generates a window of a given width & height in the\r
+//             middle of the screen\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+\r
+#define MAXX   320\r
+#define MAXY   160\r
+\r
+void   CenterWindow(word w,word h)\r
+{\r
+       FixOfs ();\r
+       US_DrawWindow(((MAXX / 8) - w) / 2,((MAXY / 8) - h) / 2,w,h);\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= CheckKeys\r
+=\r
+=====================\r
+*/\r
+\r
+void CheckKeys (void)\r
+{\r
+       int             i;\r
+       byte    scan;\r
+       unsigned        temp;\r
+\r
+\r
+       if (screenfaded || demoplayback)        // don't do anything with a faded screen\r
+               return;\r
+\r
+       scan = LastScan;\r
+\r
+\r
+       #ifdef SPEAR\r
+       //\r
+       // SECRET CHEAT CODE: TAB-G-F10\r
+       //\r
+       if (Keyboard[sc_Tab] &&\r
+               Keyboard[sc_G] &&\r
+               Keyboard[sc_F10])\r
+       {\r
+               WindowH = 160;\r
+               if (godmode)\r
+               {\r
+                       Message ("God mode OFF");\r
+                       SD_PlaySound (NOBONUSSND);\r
+               }\r
+               else\r
+               {\r
+                       Message ("God mode ON");\r
+                       SD_PlaySound (ENDBONUS2SND);\r
+               }\r
+\r
+               IN_Ack();\r
+               godmode ^= 1;\r
+               DrawAllPlayBorderSides ();\r
+               IN_ClearKeysDown();\r
+               return;\r
+       }\r
+       #endif\r
+\r
+\r
+       //\r
+       // SECRET CHEAT CODE: 'MLI'\r
+       //\r
+       if (Keyboard[sc_M] &&\r
+               Keyboard[sc_L] &&\r
+               Keyboard[sc_I])\r
+       {\r
+               gamestate.health = 100;\r
+               gamestate.ammo = 99;\r
+               gamestate.keys = 3;\r
+               gamestate.score = 0;\r
+               gamestate.TimeCount += 42000L;\r
+               GiveWeapon (wp_chaingun);\r
+\r
+               DrawWeapon();\r
+               DrawHealth();\r
+               DrawKeys();\r
+               DrawAmmo();\r
+               DrawScore();\r
+\r
+               ClearMemory ();\r
+               CA_CacheGrChunk (STARTFONT+1);\r
+               ClearSplitVWB ();\r
+               VW_ScreenToScreen (displayofs,bufferofs,80,160);\r
+\r
+               Message(STR_CHEATER1"\n"\r
+                               STR_CHEATER2"\n\n"\r
+                               STR_CHEATER3"\n"\r
+                               STR_CHEATER4"\n"\r
+                               STR_CHEATER5);\r
+\r
+               UNCACHEGRCHUNK(STARTFONT+1);\r
+               PM_CheckMainMem ();\r
+               IN_ClearKeysDown();\r
+               IN_Ack();\r
+\r
+               DrawAllPlayBorder ();\r
+       }\r
+\r
+       //\r
+       // OPEN UP DEBUG KEYS\r
+       //\r
+#ifndef SPEAR\r
+       if (Keyboard[sc_BackSpace] &&\r
+               Keyboard[sc_LShift] &&\r
+               Keyboard[sc_Alt] &&\r
+               MS_CheckParm("goobers"))\r
+#else\r
+       if (Keyboard[sc_BackSpace] &&\r
+               Keyboard[sc_LShift] &&\r
+               Keyboard[sc_Alt] &&\r
+               MS_CheckParm("debugmode"))\r
+#endif\r
+       {\r
+        ClearMemory ();\r
+        CA_CacheGrChunk (STARTFONT+1);\r
+        ClearSplitVWB ();\r
+        VW_ScreenToScreen (displayofs,bufferofs,80,160);\r
+\r
+        Message("Debugging keys are\nnow available!");\r
+        UNCACHEGRCHUNK(STARTFONT+1);\r
+        PM_CheckMainMem ();\r
+        IN_ClearKeysDown();\r
+        IN_Ack();\r
+\r
+        DrawAllPlayBorderSides ();\r
+        DebugOk=1;\r
+       }\r
+\r
+       //\r
+       // TRYING THE KEEN CHEAT CODE!\r
+       //\r
+       if (Keyboard[sc_B] &&\r
+               Keyboard[sc_A] &&\r
+               Keyboard[sc_T])\r
+       {\r
+        ClearMemory ();\r
+        CA_CacheGrChunk (STARTFONT+1);\r
+        ClearSplitVWB ();\r
+        VW_ScreenToScreen (displayofs,bufferofs,80,160);\r
+\r
+        Message("Commander Keen is also\n"\r
+                        "available from Apogee, but\n"\r
+                        "then, you already know\n"\r
+                        "that - right, Cheatmeister?!");\r
+\r
+        UNCACHEGRCHUNK(STARTFONT+1);\r
+        PM_CheckMainMem ();\r
+        IN_ClearKeysDown();\r
+        IN_Ack();\r
+\r
+        DrawAllPlayBorder ();\r
+       }\r
+\r
+//\r
+// pause key weirdness can't be checked as a scan code\r
+//\r
+       if (Paused)\r
+       {\r
+               bufferofs = displayofs;\r
+               LatchDrawPic (20-4,80-2*8,PAUSEDPIC);\r
+               SD_MusicOff();\r
+               IN_Ack();\r
+               IN_ClearKeysDown ();\r
+               SD_MusicOn();\r
+               Paused = false;\r
+               if (MousePresent)\r
+                       Mouse(MDelta);  // Clear accumulated mouse movement\r
+               return;\r
+       }\r
+\r
+\r
+//\r
+// F1-F7/ESC to enter control panel\r
+//\r
+       if (\r
+#ifndef DEBCHECK\r
+               scan == sc_F10 ||\r
+#endif\r
+               scan == sc_F9 ||\r
+               scan == sc_F7 ||\r
+               scan == sc_F8)                  // pop up quit dialog\r
+       {\r
+               ClearMemory ();\r
+               ClearSplitVWB ();\r
+               VW_ScreenToScreen (displayofs,bufferofs,80,160);\r
+               US_ControlPanel(scan);\r
+\r
+                DrawAllPlayBorderSides ();\r
+\r
+               if (scan == sc_F9)\r
+                 StartMusic ();\r
+\r
+               PM_CheckMainMem ();\r
+               SETFONTCOLOR(0,15);\r
+               IN_ClearKeysDown();\r
+               return;\r
+       }\r
+\r
+       if ( (scan >= sc_F1 && scan <= sc_F9) || scan == sc_Escape)\r
+       {\r
+               StopMusic ();\r
+               ClearMemory ();\r
+               VW_FadeOut ();\r
+\r
+               US_ControlPanel(scan);\r
+\r
+               SETFONTCOLOR(0,15);\r
+               IN_ClearKeysDown();\r
+               DrawPlayScreen ();\r
+               if (!startgame && !loadedgame)\r
+               {\r
+                       VW_FadeIn ();\r
+                       StartMusic ();\r
+               }\r
+               if (loadedgame)\r
+                       playstate = ex_abort;\r
+               lasttimecount = TimeCount;\r
+               if (MousePresent)\r
+                       Mouse(MDelta);  // Clear accumulated mouse movement\r
+               PM_CheckMainMem ();\r
+               return;\r
+       }\r
+\r
+//\r
+// TAB-? debug keys\r
+//\r
+       if (Keyboard[sc_Tab] && DebugOk)\r
+       {\r
+               CA_CacheGrChunk (STARTFONT);\r
+               fontnumber=0;\r
+               SETFONTCOLOR(0,15);\r
+               DebugKeys();\r
+               if (MousePresent)\r
+                       Mouse(MDelta);  // Clear accumulated mouse movement\r
+               lasttimecount = TimeCount;\r
+               return;\r
+       }\r
+\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+#############################################################################\r
+\r
+                                 The objlist data structure\r
+\r
+#############################################################################\r
+\r
+objlist containt structures for every actor currently playing.  The structure\r
+is accessed as a linked list starting at *player, ending when ob->next ==\r
+NULL.  GetNewObj inserts a new object at the end of the list, meaning that\r
+if an actor spawn another actor, the new one WILL get to think and react the\r
+same frame.  RemoveObj unlinks the given object and returns it to the free\r
+list, but does not damage the objects ->next pointer, so if the current object\r
+removes itself, a linked list following loop can still safely get to the\r
+next element.\r
+\r
+<backwardly linked free list>\r
+\r
+#############################################################################\r
+*/\r
+\r
+\r
+/*\r
+=========================\r
+=\r
+= InitActorList\r
+=\r
+= Call to clear out the actor object lists returning them all to the free\r
+= list.  Allocates a special spot for the player.\r
+=\r
+=========================\r
+*/\r
+\r
+int    objcount;\r
+\r
+void InitActorList (void)\r
+{\r
+       int     i;\r
+\r
+//\r
+// init the actor lists\r
+//\r
+       for (i=0;i<MAXACTORS;i++)\r
+       {\r
+               objlist[i].prev = &objlist[i+1];\r
+               objlist[i].next = NULL;\r
+       }\r
+\r
+       objlist[MAXACTORS-1].prev = NULL;\r
+\r
+       objfreelist = &objlist[0];\r
+       lastobj = NULL;\r
+\r
+       objcount = 0;\r
+\r
+//\r
+// give the player the first free spots\r
+//\r
+       GetNewActor ();\r
+       player = new;\r
+\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=========================\r
+=\r
+= GetNewActor\r
+=\r
+= Sets the global variable new to point to a free spot in objlist.\r
+= The free spot is inserted at the end of the liked list\r
+=\r
+= When the object list is full, the caller can either have it bomb out ot\r
+= return a dummy object pointer that will never get used\r
+=\r
+=========================\r
+*/\r
+\r
+void GetNewActor (void)\r
+{\r
+       if (!objfreelist)\r
+               Quit ("GetNewActor: No free spots in objlist!");\r
+\r
+       new = objfreelist;\r
+       objfreelist = new->prev;\r
+       memset (new,0,sizeof(*new));\r
+\r
+       if (lastobj)\r
+               lastobj->next = new;\r
+       new->prev = lastobj;    // new->next is allready NULL from memset\r
+\r
+       new->active = false;\r
+       lastobj = new;\r
+\r
+       objcount++;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=========================\r
+=\r
+= RemoveObj\r
+=\r
+= Add the given object back into the free list, and unlink it from it's\r
+= neighbors\r
+=\r
+=========================\r
+*/\r
+\r
+void RemoveObj (objtype *gone)\r
+{\r
+       objtype **spotat;\r
+\r
+       if (gone == player)\r
+               Quit ("RemoveObj: Tried to remove the player!");\r
+\r
+       gone->state = NULL;\r
+\r
+//\r
+// fix the next object's back link\r
+//\r
+       if (gone == lastobj)\r
+               lastobj = (objtype *)gone->prev;\r
+       else\r
+               gone->next->prev = gone->prev;\r
+\r
+//\r
+// fix the previous object's forward link\r
+//\r
+       gone->prev->next = gone->next;\r
+\r
+//\r
+// add it back in to the free list\r
+//\r
+       gone->prev = objfreelist;\r
+       objfreelist = gone;\r
+\r
+       objcount--;\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                               MUSIC STUFF\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= StopMusic\r
+=\r
+=================\r
+*/\r
+\r
+void StopMusic(void)\r
+{\r
+       int     i;\r
+\r
+       SD_MusicOff();\r
+       for (i = 0;i < LASTMUSIC;i++)\r
+               if (audiosegs[STARTMUSIC + i])\r
+               {\r
+                       MM_SetPurge(&((memptr)audiosegs[STARTMUSIC + i]),3);\r
+                       MM_SetLock(&((memptr)audiosegs[STARTMUSIC + i]),false);\r
+               }\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= StartMusic\r
+=\r
+=================\r
+*/\r
+\r
+void StartMusic(void)\r
+{\r
+       musicnames      chunk;\r
+\r
+       SD_MusicOff();\r
+       chunk = songs[gamestate.mapon+gamestate.episode*10];\r
+\r
+//     if ((chunk == -1) || (MusicMode != smm_AdLib))\r
+//DEBUG control panel          return;\r
+\r
+       MM_BombOnError (false);\r
+       CA_CacheAudioChunk(STARTMUSIC + chunk);\r
+       MM_BombOnError (true);\r
+       if (mmerror)\r
+               mmerror = false;\r
+       else\r
+       {\r
+               MM_SetLock(&((memptr)audiosegs[STARTMUSIC + chunk]),true);\r
+               SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC + chunk]);\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                       PALETTE SHIFTING STUFF\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define NUMREDSHIFTS   6\r
+#define REDSTEPS               8\r
+\r
+#define NUMWHITESHIFTS 3\r
+#define WHITESTEPS             20\r
+#define WHITETICS              6\r
+\r
+\r
+byte   far redshifts[NUMREDSHIFTS][768];\r
+byte   far whiteshifts[NUMREDSHIFTS][768];\r
+\r
+int            damagecount,bonuscount;\r
+boolean        palshifted;\r
+\r
+extern         byte    far     gamepal;\r
+\r
+/*\r
+=====================\r
+=\r
+= InitRedShifts\r
+=\r
+=====================\r
+*/\r
+\r
+void InitRedShifts (void)\r
+{\r
+       byte    far *workptr, far *baseptr;\r
+       int             i,j,delta;\r
+\r
+\r
+//\r
+// fade through intermediate frames\r
+//\r
+       for (i=1;i<=NUMREDSHIFTS;i++)\r
+       {\r
+               workptr = (byte far *)&redshifts[i-1][0];\r
+               baseptr = &gamepal;\r
+\r
+               for (j=0;j<=255;j++)\r
+               {\r
+                       delta = 64-*baseptr;\r
+                       *workptr++ = *baseptr++ + delta * i / REDSTEPS;\r
+                       delta = -*baseptr;\r
+                       *workptr++ = *baseptr++ + delta * i / REDSTEPS;\r
+                       delta = -*baseptr;\r
+                       *workptr++ = *baseptr++ + delta * i / REDSTEPS;\r
+               }\r
+       }\r
+\r
+       for (i=1;i<=NUMWHITESHIFTS;i++)\r
+       {\r
+               workptr = (byte far *)&whiteshifts[i-1][0];\r
+               baseptr = &gamepal;\r
+\r
+               for (j=0;j<=255;j++)\r
+               {\r
+                       delta = 64-*baseptr;\r
+                       *workptr++ = *baseptr++ + delta * i / WHITESTEPS;\r
+                       delta = 62-*baseptr;\r
+                       *workptr++ = *baseptr++ + delta * i / WHITESTEPS;\r
+                       delta = 0-*baseptr;\r
+                       *workptr++ = *baseptr++ + delta * i / WHITESTEPS;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= ClearPaletteShifts\r
+=\r
+=====================\r
+*/\r
+\r
+void ClearPaletteShifts (void)\r
+{\r
+       bonuscount = damagecount = 0;\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= StartBonusFlash\r
+=\r
+=====================\r
+*/\r
+\r
+void StartBonusFlash (void)\r
+{\r
+       bonuscount = NUMWHITESHIFTS*WHITETICS;          // white shift palette\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= StartDamageFlash\r
+=\r
+=====================\r
+*/\r
+\r
+void StartDamageFlash (int damage)\r
+{\r
+       damagecount += damage;\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= UpdatePaletteShifts\r
+=\r
+=====================\r
+*/\r
+\r
+void UpdatePaletteShifts (void)\r
+{\r
+       int     red,white;\r
+\r
+       if (bonuscount)\r
+       {\r
+               white = bonuscount/WHITETICS +1;\r
+               if (white>NUMWHITESHIFTS)\r
+                       white = NUMWHITESHIFTS;\r
+               bonuscount -= tics;\r
+               if (bonuscount < 0)\r
+                       bonuscount = 0;\r
+       }\r
+       else\r
+               white = 0;\r
+\r
+\r
+       if (damagecount)\r
+       {\r
+               red = damagecount/10 +1;\r
+               if (red>NUMREDSHIFTS)\r
+                       red = NUMREDSHIFTS;\r
+\r
+               damagecount -= tics;\r
+               if (damagecount < 0)\r
+                       damagecount = 0;\r
+       }\r
+       else\r
+               red = 0;\r
+\r
+       if (red)\r
+       {\r
+               VW_WaitVBL(1);\r
+               VL_SetPalette (redshifts[red-1]);\r
+               palshifted = true;\r
+       }\r
+       else if (white)\r
+       {\r
+               VW_WaitVBL(1);\r
+               VL_SetPalette (whiteshifts[white-1]);\r
+               palshifted = true;\r
+       }\r
+       else if (palshifted)\r
+       {\r
+               VW_WaitVBL(1);\r
+               VL_SetPalette (&gamepal);               // back to normal\r
+               palshifted = false;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= FinishPaletteShifts\r
+=\r
+= Resets palette to normal if needed\r
+=\r
+=====================\r
+*/\r
+\r
+void FinishPaletteShifts (void)\r
+{\r
+       if (palshifted)\r
+       {\r
+               palshifted = 0;\r
+               VW_WaitVBL(1);\r
+               VL_SetPalette (&gamepal);\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                               CORE PLAYLOOP\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= DoActor\r
+=\r
+=====================\r
+*/\r
+\r
+void DoActor (objtype *ob)\r
+{\r
+       void (*think)(objtype *);\r
+\r
+       if (!ob->active && !areabyplayer[ob->areanumber])\r
+               return;\r
+\r
+       if (!(ob->flags&(FL_NONMARK|FL_NEVERMARK)) )\r
+               actorat[ob->tilex][ob->tiley] = NULL;\r
+\r
+//\r
+// non transitional object\r
+//\r
+\r
+       if (!ob->ticcount)\r
+       {\r
+               think = ob->state->think;\r
+               if (think)\r
+               {\r
+                       think (ob);\r
+                       if (!ob->state)\r
+                       {\r
+                               RemoveObj (ob);\r
+                               return;\r
+                       }\r
+               }\r
+\r
+               if (ob->flags&FL_NEVERMARK)\r
+                       return;\r
+\r
+               if ( (ob->flags&FL_NONMARK) && actorat[ob->tilex][ob->tiley])\r
+                       return;\r
+\r
+               actorat[ob->tilex][ob->tiley] = ob;\r
+               return;\r
+       }\r
+\r
+//\r
+// transitional object\r
+//\r
+       ob->ticcount-=tics;\r
+       while ( ob->ticcount <= 0)\r
+       {\r
+               think = ob->state->action;                      // end of state action\r
+               if (think)\r
+               {\r
+                       think (ob);\r
+                       if (!ob->state)\r
+                       {\r
+                               RemoveObj (ob);\r
+                               return;\r
+                       }\r
+               }\r
+\r
+               ob->state = ob->state->next;\r
+\r
+               if (!ob->state)\r
+               {\r
+                       RemoveObj (ob);\r
+                       return;\r
+               }\r
+\r
+               if (!ob->state->tictime)\r
+               {\r
+                       ob->ticcount = 0;\r
+                       goto think;\r
+               }\r
+\r
+               ob->ticcount += ob->state->tictime;\r
+       }\r
+\r
+think:\r
+       //\r
+       // think\r
+       //\r
+       think = ob->state->think;\r
+       if (think)\r
+       {\r
+               think (ob);\r
+               if (!ob->state)\r
+               {\r
+                       RemoveObj (ob);\r
+                       return;\r
+               }\r
+       }\r
+\r
+       if (ob->flags&FL_NEVERMARK)\r
+               return;\r
+\r
+       if ( (ob->flags&FL_NONMARK) && actorat[ob->tilex][ob->tiley])\r
+               return;\r
+\r
+       actorat[ob->tilex][ob->tiley] = ob;\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PlayLoop\r
+=\r
+===================\r
+*/\r
+long funnyticount;\r
+\r
+\r
+void PlayLoop (void)\r
+{\r
+       int             give;\r
+       int     helmetangle;\r
+\r
+       playstate = TimeCount = lasttimecount = 0;\r
+       frameon = 0;\r
+       running = false;\r
+       anglefrac = 0;\r
+       facecount = 0;\r
+       funnyticount = 0;\r
+       memset (buttonstate,0,sizeof(buttonstate));\r
+       ClearPaletteShifts ();\r
+\r
+       if (MousePresent)\r
+               Mouse(MDelta);  // Clear accumulated mouse movement\r
+\r
+       if (demoplayback)\r
+               IN_StartAck ();\r
+\r
+       do\r
+       {\r
+               if (virtualreality)\r
+               {\r
+                       helmetangle = peek (0x40,0xf0);\r
+                       player->angle += helmetangle;\r
+                       if (player->angle >= ANGLES)\r
+                               player->angle -= ANGLES;\r
+               }\r
+\r
+\r
+               PollControls();\r
+\r
+//\r
+// actor thinking\r
+//\r
+               madenoise = false;\r
+\r
+               MoveDoors ();\r
+               MovePWalls ();\r
+\r
+               for (obj = player;obj;obj = obj->next)\r
+                       DoActor (obj);\r
+\r
+               UpdatePaletteShifts ();\r
+\r
+               ThreeDRefresh ();\r
+\r
+               //\r
+               // MAKE FUNNY FACE IF BJ DOESN'T MOVE FOR AWHILE\r
+               //\r
+               #ifdef SPEAR\r
+               funnyticount += tics;\r
+               if (funnyticount > 30l*70)\r
+               {\r
+                       funnyticount = 0;\r
+                       StatusDrawPic (17,4,BJWAITING1PIC+(US_RndT()&1));\r
+                       facecount = 0;\r
+               }\r
+               #endif\r
+\r
+               gamestate.TimeCount+=tics;\r
+\r
+               SD_Poll ();\r
+               UpdateSoundLoc();       // JAB\r
+\r
+               if (screenfaded)\r
+                       VW_FadeIn ();\r
+\r
+               CheckKeys();\r
+\r
+//\r
+// debug aids\r
+//\r
+               if (singlestep)\r
+               {\r
+                       VW_WaitVBL(14);\r
+                       lasttimecount = TimeCount;\r
+               }\r
+               if (extravbls)\r
+                       VW_WaitVBL(extravbls);\r
+\r
+               if (demoplayback)\r
+               {\r
+                       if (IN_CheckAck ())\r
+                       {\r
+                               IN_ClearKeysDown ();\r
+                               playstate = ex_abort;\r
+                       }\r
+               }\r
+\r
+\r
+               if (virtualreality)\r
+               {\r
+                       player->angle -= helmetangle;\r
+                       if (player->angle < 0)\r
+                               player->angle += ANGLES;\r
+               }\r
+\r
+       }while (!playstate && !startgame);\r
+\r
+       if (playstate != ex_died)\r
+               FinishPaletteShifts ();\r
+}\r
+\r