--- /dev/null
+// 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