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