1880 lines
35 KiB
C
1880 lines
35 KiB
C
// 3D_PLAY.C
|
|
|
|
#include "3D_DEF.H"
|
|
#pragma hdrstop
|
|
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
LOCAL CONSTANTS
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
#define sc_Question 0x35
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
GLOBAL VARIABLES
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
|
|
unsigned char music_num=0;
|
|
|
|
#if LOOK_FOR_DEAD_GUYS
|
|
objtype *DeadGuys[MAXACTORS];
|
|
unsigned char NumDeadGuys;
|
|
#endif
|
|
|
|
boolean madenoise; // true when shooting or screaming
|
|
unsigned char alerted = 0,alerted_areanum;
|
|
|
|
|
|
exit_t playstate;
|
|
|
|
boolean PowerBall = false;
|
|
|
|
#if TECH_SUPPORT_VERSION
|
|
int bordertime,DebugOk = true,InstantWin = 0,InstantQuit = 0;
|
|
#else
|
|
int bordertime,DebugOk = false,InstantWin = 0,InstantQuit = 0;
|
|
#endif
|
|
|
|
unsigned ExtraRadarFlags = 0;
|
|
|
|
|
|
|
|
#if IN_DEVELOPMENT
|
|
|
|
int TestQuickSave = 0, TestAutoMapper = 0;
|
|
|
|
#endif
|
|
|
|
objtype objlist[MAXACTORS],*new,*player,*lastobj,
|
|
*objfreelist,*killerobj;
|
|
|
|
unsigned farmapylookup[MAPSIZE];
|
|
byte *nearmapylookup[MAPSIZE];
|
|
|
|
boolean singlestep=false,godmode; //,noclip;
|
|
int extravbls = 0;
|
|
|
|
byte tilemap[MAPSIZE][MAPSIZE]; // wall values only
|
|
byte spotvis[MAPSIZE][MAPSIZE];
|
|
objtype *actorat[MAPSIZE][MAPSIZE];
|
|
|
|
//
|
|
// replacing refresh manager
|
|
//
|
|
unsigned mapwidth,mapheight,tics,realtics;
|
|
boolean compatability,usedummy=false, nevermark = false;
|
|
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,sc_5,sc_6,sc_7};
|
|
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;
|
|
|
|
// Light sourcing flag
|
|
|
|
byte lightson;
|
|
|
|
//
|
|
// 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(boolean preload);
|
|
void PlayLoop (void);
|
|
void SpaceEntryExit(boolean entry);
|
|
void FinishPaletteShifts (void);
|
|
void ShowQuickInstructions(void);
|
|
void CleanDrawPlayBorder(void);
|
|
void PopupAutoMap(void);
|
|
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
LOCAL VARIABLES
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
|
|
objtype dummyobj;
|
|
|
|
//
|
|
// LIST OF SONGS FOR EACH LEVEL
|
|
//
|
|
|
|
int far songs[]=
|
|
{
|
|
MAJMIN_MUS, // 0
|
|
STICKS_MUS, // 1
|
|
MOURNING_MUS, // 2
|
|
LURKING_MUS, // 3
|
|
CIRCLES_MUS, // 4
|
|
TIME_MUS, // 5
|
|
TOHELL_MUS, // 6
|
|
FORTRESS_MUS, // 7
|
|
GIVING_MUS, // 8
|
|
HARTBEAT_MUS, // 9
|
|
MOURNING_MUS, // 10
|
|
MAJMIN_MUS, // 11
|
|
VACCINAP_MUS, // 12
|
|
LURKING_MUS, // 13
|
|
MONASTRY_MUS, // 14
|
|
TOMBP_MUS, // 15
|
|
DARKNESS_MUS, // 16
|
|
MOURNING_MUS, // 17
|
|
SERPENT_MUS, // 18
|
|
TIME_MUS, // 19
|
|
CATACOMB_MUS, // 20
|
|
PLOT_MUS, // 21
|
|
GIVING_MUS, // 22
|
|
VACCINAP_MUS, // 23
|
|
};
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
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
|
|
=
|
|
===================
|
|
*/
|
|
|
|
|
|
boolean pollMouseUsed=false;
|
|
|
|
void PollMouseMove (void)
|
|
{
|
|
int mousexmove,mouseymove;
|
|
|
|
Mouse(MDelta);
|
|
mousexmove = _CX;
|
|
mouseymove = _DX;
|
|
|
|
// Double speed when shift is pressed.
|
|
//
|
|
if (Keyboard[sc_LShift] || Keyboard[sc_RShift] || buttonstate[bt_run])
|
|
{
|
|
controly += (mouseymove*20/(13-mouseadjustment))*4;
|
|
controlx += (mousexmove*10/(13-mouseadjustment))/2;
|
|
}
|
|
|
|
controlx += mousexmove*10/(13-mouseadjustment);
|
|
controly += mouseymove*20/(13-mouseadjustment);
|
|
|
|
if (mousexmove || mouseymove)
|
|
pollMouseUsed=true;
|
|
else
|
|
pollMouseUsed=false;
|
|
}
|
|
|
|
|
|
/*
|
|
===================
|
|
=
|
|
= 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;
|
|
|
|
controlx = 0;
|
|
controly = 0;
|
|
memcpy (buttonheld,buttonstate,sizeof(buttonstate));
|
|
memset (buttonstate,0,sizeof(buttonstate));
|
|
|
|
#ifdef MYPROFILE
|
|
controlx = 100; // just spin in place
|
|
return;
|
|
#endif
|
|
|
|
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++;
|
|
tics = *demoptr++;
|
|
|
|
while (TimeCount-lasttimecount < tics)
|
|
;
|
|
lasttimecount = TimeCount;
|
|
|
|
if (demoptr == lastdemoptr)
|
|
playstate = ex_completed; // demo is done
|
|
|
|
controlx *= (int)tics;
|
|
controly *= (int)tics;
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// get timing info for last frame
|
|
//
|
|
CalcTics ();
|
|
|
|
//
|
|
// get button states
|
|
//
|
|
PollKeyboardButtons ();
|
|
|
|
if (mouseenabled)
|
|
PollMouseButtons ();
|
|
|
|
if (joystickenabled)
|
|
PollJoystickButtons ();
|
|
|
|
#if 0
|
|
if (buttonstate[bt_run])
|
|
VL_ColorBorder (1);
|
|
else
|
|
VL_ColorBorder (0);
|
|
#endif
|
|
|
|
//
|
|
// 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;
|
|
|
|
#ifdef DEMOS_EXTERN
|
|
|
|
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;
|
|
*demoptr++ = tics;
|
|
|
|
if (demoptr >= lastdemoptr)
|
|
PLAY_ERROR(POLLCONTROLS_DEMO_OV);
|
|
|
|
controlx *= (int)tics;
|
|
controly *= (int)tics;
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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
|
|
=
|
|
=====================
|
|
*/
|
|
|
|
extern boolean PP_step,sqActive;
|
|
extern int pickquick;
|
|
|
|
boolean refresh_screen;
|
|
#if (GAME_VERSION != SHAREWARE_VERSION) || GEORGE_CHEAT
|
|
byte jam_buff_cmp[]={sc_J,sc_A,sc_M};
|
|
byte jam_buff[sizeof(jam_buff_cmp)];
|
|
#endif
|
|
|
|
char far PAUSED_MSG[]="^ST1^CEGame Paused\r^CEPress any key to resume.^XX";
|
|
|
|
void CheckKeys (void)
|
|
{
|
|
boolean one_eighty=false;
|
|
int i;
|
|
byte scan;
|
|
unsigned temp;
|
|
static boolean Plus_KeyReleased;
|
|
static boolean Minus_KeyReleased;
|
|
static boolean I_KeyReleased;
|
|
static boolean S_KeyReleased;
|
|
|
|
#if IN_DEVELOPMENT || BETA_TEST
|
|
// if (DebugOk && (Keyboard[sc_P] || PP_step))
|
|
// PicturePause ();
|
|
#endif
|
|
|
|
|
|
if (screenfaded || demoplayback) // don't do anything with a faded screen
|
|
return;
|
|
|
|
scan = LastScan;
|
|
|
|
|
|
#if IN_DEVELOPMENT
|
|
#ifdef ACTIVATE_TERMINAL
|
|
if (Keyboard[sc_9] && Keyboard[sc_0])
|
|
ActivateTerminal(true);
|
|
#endif
|
|
#endif
|
|
|
|
//
|
|
// SECRET CHEAT CODE: 'JAM'
|
|
//
|
|
|
|
#if GAME_VERSION != SHAREWARE_VERSION
|
|
if (Keyboard[sc_J] || Keyboard[sc_A] || Keyboard[sc_M])
|
|
{
|
|
if (jam_buff[sizeof(jam_buff_cmp)-1] != LastScan)
|
|
{
|
|
memcpy(jam_buff,jam_buff+1,sizeof(jam_buff_cmp)-1);
|
|
jam_buff[sizeof(jam_buff_cmp)-1] = LastScan;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
CheckMusicToggle();
|
|
|
|
if (gamestate.rpower)
|
|
{
|
|
if (Keyboard[sc_Plus] || Keyboard[sc_kpPlus])
|
|
{
|
|
if (Plus_KeyReleased && gamestate.rzoom<2)
|
|
{
|
|
UpdateRadarGuage();
|
|
gamestate.rzoom++;
|
|
Plus_KeyReleased=false;
|
|
}
|
|
}
|
|
else
|
|
Plus_KeyReleased=true;
|
|
|
|
if (Keyboard[sc_Minus] || Keyboard[sc_kpMinus])
|
|
{
|
|
if (Minus_KeyReleased && gamestate.rzoom)
|
|
{
|
|
UpdateRadarGuage();
|
|
gamestate.rzoom--;
|
|
Minus_KeyReleased=false;
|
|
}
|
|
}
|
|
else
|
|
Minus_KeyReleased=true;
|
|
}
|
|
|
|
if (Keyboard[sc_S])
|
|
{
|
|
if (S_KeyReleased)
|
|
{
|
|
if ((SoundMode != sdm_Off) || (DigiMode!=sds_Off))
|
|
{
|
|
if (SoundMode != sdm_Off)
|
|
{
|
|
SD_WaitSoundDone();
|
|
SD_SetSoundMode(sdm_Off);
|
|
}
|
|
|
|
if (DigiMode!=sds_Off)
|
|
SD_SetDigiDevice(sds_Off);
|
|
|
|
_fmemcpy((char far *)&SoundOn[55],"OFF.",4);
|
|
}
|
|
else
|
|
{
|
|
ClearMemory();
|
|
if (SoundBlasterPresent || AdLibPresent)
|
|
SD_SetSoundMode(sdm_AdLib);
|
|
else
|
|
SD_SetSoundMode(sdm_PC);
|
|
|
|
if (SoundBlasterPresent)
|
|
SD_SetDigiDevice(sds_SoundBlaster);
|
|
else
|
|
if (SoundSourcePresent)
|
|
SD_SetDigiDevice(sds_SoundSource);
|
|
else
|
|
SD_SetDigiDevice(sds_Off);
|
|
|
|
CA_LoadAllSounds();
|
|
PM_CheckMainMem();
|
|
|
|
_fmemcpy((char far *)&SoundOn[55],"ON. ",4);
|
|
}
|
|
|
|
DISPLAY_TIMED_MSG(SoundOn,MP_BONUS,MT_GENERAL);
|
|
S_KeyReleased=false;
|
|
}
|
|
}
|
|
else
|
|
S_KeyReleased=true;
|
|
|
|
if (Keyboard[sc_Enter])
|
|
{
|
|
#if (GAME_VERSION != SHAREWARE_VERSION) || GEORGE_CHEAT
|
|
char loop;
|
|
|
|
if ((!memcmp(jam_buff,jam_buff_cmp,sizeof(jam_buff_cmp))))
|
|
{
|
|
jam_buff[0]=0;
|
|
|
|
for (loop=0; loop<NUMKEYS; loop++)
|
|
if (gamestate.numkeys[loop] < MAXKEYS)
|
|
gamestate.numkeys[loop]=1;
|
|
|
|
gamestate.health = 100;
|
|
gamestate.ammo = MAX_AMMO;
|
|
gamestate.rpower = MAX_RADAR_ENERGY;
|
|
|
|
if (!DebugOk)
|
|
{
|
|
gamestate.score = 0;
|
|
gamestate.nextextra = EXTRAPOINTS;
|
|
}
|
|
|
|
gamestate.TimeCount += 42000L;
|
|
|
|
for (loop=0; loop<NUMWEAPONS-1; loop++)
|
|
GiveWeapon(loop);
|
|
|
|
DrawWeapon();
|
|
DrawHealth();
|
|
DrawKeys();
|
|
DrawScore();
|
|
DISPLAY_TIMED_MSG("\r\r YOU CHEATER!",MP_INTERROGATE,MT_GENERAL);
|
|
ForceUpdateStatusBar();
|
|
|
|
ClearMemory ();
|
|
ClearSplitVWB ();
|
|
VW_ScreenToScreen (displayofs,bufferofs,80,160);
|
|
|
|
Message("\n NOW you're jammin'!! \n");
|
|
|
|
PM_CheckMainMem ();
|
|
IN_ClearKeysDown();
|
|
IN_Ack();
|
|
|
|
CleanDrawPlayBorder();
|
|
}
|
|
else
|
|
#endif
|
|
one_eighty=true;
|
|
}
|
|
|
|
// Handle quick turning!
|
|
//
|
|
if (!gamestate.turn_around)
|
|
{
|
|
// 90 degrees left
|
|
//
|
|
if (Keyboard[sc_Q])
|
|
{
|
|
gamestate.turn_around = -90;
|
|
gamestate.turn_angle = player->angle + 90;
|
|
if (gamestate.turn_angle > 359)
|
|
gamestate.turn_angle -= ANGLES;
|
|
}
|
|
|
|
// 180 degrees right
|
|
//
|
|
if ((Keyboard[sc_W]) || (one_eighty))
|
|
{
|
|
gamestate.turn_around = 180;
|
|
gamestate.turn_angle = player->angle + 180;
|
|
if (gamestate.turn_angle > 359)
|
|
gamestate.turn_angle -= ANGLES;
|
|
}
|
|
|
|
// 90 degrees right
|
|
//
|
|
if (Keyboard[sc_E])
|
|
{
|
|
gamestate.turn_around = 90;
|
|
gamestate.turn_angle = player->angle - 90;
|
|
if (gamestate.turn_angle < 0)
|
|
gamestate.turn_angle += ANGLES;
|
|
}
|
|
}
|
|
|
|
//
|
|
// pause key weirdness can't be checked as a scan code
|
|
//
|
|
if (Paused || Keyboard[sc_P])
|
|
{
|
|
SD_MusicOff();
|
|
fontnumber = 4;
|
|
BMAmsg(PAUSED_MSG);
|
|
IN_Ack();
|
|
IN_ClearKeysDown();
|
|
fontnumber = 2;
|
|
RedrawStatusAreas();
|
|
SD_MusicOn();
|
|
Paused = false;
|
|
if (MousePresent)
|
|
Mouse(MDelta); // Clear accumulated mouse movement
|
|
return;
|
|
}
|
|
|
|
#if IN_DEVELOPMENT
|
|
if (TestQuickSave)
|
|
{
|
|
// TestQuickSave--;
|
|
scan = sc_F8;
|
|
}
|
|
|
|
if (TestAutoMapper)
|
|
PopupAutoMap();
|
|
|
|
#endif
|
|
|
|
switch (scan)
|
|
{
|
|
case sc_F7: // END GAME
|
|
case sc_F10: // QUIT TO DOS
|
|
FinishPaletteShifts();
|
|
ClearMemory();
|
|
US_ControlPanel(scan);
|
|
PM_CheckMainMem();
|
|
CleanDrawPlayBorder();
|
|
return;
|
|
|
|
case sc_F2: // SAVE MISSION
|
|
case sc_F8: // QUICK SAVE
|
|
// Make sure there's room to save...
|
|
//
|
|
ClearMemory();
|
|
FinishPaletteShifts();
|
|
if (!CheckDiskSpace(DISK_SPACE_NEEDED,CANT_SAVE_GAME_TXT,cds_id_print))
|
|
{
|
|
PM_CheckMainMem();
|
|
CleanDrawPlayBorder();
|
|
break;
|
|
}
|
|
|
|
case sc_F1: // HELP
|
|
case sc_F3: // LOAD MISSION
|
|
case sc_F4: // SOUND MENU
|
|
case sc_F5: // RESIZE VIEW
|
|
case sc_F6: // CONTROLS MENU
|
|
case sc_F9: // QUICK LOAD
|
|
case sc_Escape: // MAIN MENU
|
|
refresh_screen=true;
|
|
if (scan < sc_F8)
|
|
VW_FadeOut();
|
|
StopMusic();
|
|
ClearMemory();
|
|
ClearSplitVWB();
|
|
US_ControlPanel(scan);
|
|
if (refresh_screen)
|
|
{
|
|
boolean old=loadedgame;
|
|
|
|
loadedgame=false;
|
|
DrawPlayScreen(false);
|
|
loadedgame=old;
|
|
}
|
|
ClearMemory();
|
|
if (!sqActive || !loadedgame)
|
|
StartMusic(false);
|
|
PM_CheckMainMem();
|
|
IN_ClearKeysDown();
|
|
if (loadedgame)
|
|
{
|
|
PreloadGraphics();
|
|
loadedgame=false;
|
|
DrawPlayScreen(false);
|
|
}
|
|
else
|
|
if (!refresh_screen)
|
|
CleanDrawPlayBorder();
|
|
if (!sqActive)
|
|
StartMusic(false);
|
|
return;
|
|
}
|
|
|
|
if (Keyboard[sc_Tab])
|
|
PopupAutoMap();
|
|
|
|
if (Keyboard[sc_Tilde])
|
|
{
|
|
Keyboard[sc_Tilde] = 0;
|
|
TryDropPlasmaDetonator();
|
|
}
|
|
|
|
|
|
if ((DebugOk || gamestate.flags & GS_MUSIC_TEST) && (Keyboard[sc_BackSpace]))
|
|
{
|
|
unsigned char old_num=music_num;
|
|
|
|
if (gamestate.flags & GS_MUSIC_TEST)
|
|
{
|
|
if (Keyboard[sc_LeftArrow])
|
|
{
|
|
if (music_num)
|
|
music_num--;
|
|
Keyboard[sc_LeftArrow]=false;
|
|
}
|
|
else
|
|
if (Keyboard[sc_RightArrow])
|
|
{
|
|
if (music_num < LASTMUSIC-1)
|
|
music_num++;
|
|
Keyboard[sc_RightArrow]=false;
|
|
}
|
|
|
|
if (old_num != music_num)
|
|
{
|
|
ClearMemory();
|
|
MM_FreePtr ((memptr *)&audiosegs[STARTMUSIC + old_num]);
|
|
StartMusic(false);
|
|
PM_CheckMainMem();
|
|
DrawScore();
|
|
}
|
|
}
|
|
|
|
if (old_num == music_num)
|
|
{
|
|
fontnumber=4;
|
|
SETFONTCOLOR(0,15);
|
|
if (DebugKeys())
|
|
{
|
|
CleanDrawPlayBorder();
|
|
}
|
|
|
|
if (MousePresent)
|
|
Mouse(MDelta); // Clear accumulated mouse movement
|
|
lasttimecount = TimeCount;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (Keyboard[sc_I])
|
|
{
|
|
if (I_KeyReleased)
|
|
{
|
|
gamestate.flags ^= GS_ATTACK_INFOAREA;
|
|
if (gamestate.flags & GS_ATTACK_INFOAREA)
|
|
DISPLAY_TIMED_MSG(attacker_info_enabled,MP_ATTACK_INFO,MT_GENERAL);
|
|
else
|
|
DISPLAY_TIMED_MSG(attacker_info_disabled,MP_ATTACK_INFO,MT_GENERAL);
|
|
I_KeyReleased = false;
|
|
}
|
|
}
|
|
else
|
|
I_KeyReleased = true;
|
|
|
|
|
|
#ifdef CEILING_FLOOR_COLORS
|
|
if (Keyboard[sc_C])
|
|
{
|
|
gamestate.flags ^= GS_DRAW_CEILING;
|
|
Keyboard[sc_C] = 0;
|
|
}
|
|
|
|
if (Keyboard[sc_F])
|
|
{
|
|
ThreeDRefresh();
|
|
ThreeDRefresh();
|
|
|
|
gamestate.flags ^= GS_DRAW_FLOOR;
|
|
|
|
Keyboard[sc_F] = 0;
|
|
#if DUAL_SWAP_FILES
|
|
ChangeSwapFiles(true);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
if (Keyboard[sc_L])
|
|
{
|
|
Keyboard[sc_L]=0;
|
|
gamestate.flags ^= GS_LIGHTING;
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
// CheckMusicToggle()
|
|
//-------------------------------------------------------------------------
|
|
void CheckMusicToggle(void)
|
|
{
|
|
static boolean M_KeyReleased;
|
|
|
|
if (Keyboard[sc_M])
|
|
{
|
|
if (M_KeyReleased
|
|
#if GAME_VERSION != SHAREWARE_VERSION
|
|
&& ((jam_buff[0] != sc_J) || (jam_buff[1] != sc_A))
|
|
#endif
|
|
)
|
|
{
|
|
if (!AdLibPresent)
|
|
{
|
|
DISPLAY_TIMED_MSG(NoAdLibCard,MP_BONUS,MT_GENERAL);
|
|
SD_PlaySound(NOWAYSND);
|
|
return;
|
|
}
|
|
else
|
|
if (MusicMode != smm_Off)
|
|
{
|
|
SD_SetMusicMode(smm_Off);
|
|
_fmemcpy((char far *)&MusicOn[58],"OFF.",4);
|
|
}
|
|
else
|
|
{
|
|
SD_SetMusicMode(smm_AdLib);
|
|
StartMusic(false);
|
|
_fmemcpy((char far *)&MusicOn[58],"ON. ",4);
|
|
}
|
|
|
|
DISPLAY_TIMED_MSG(MusicOn,MP_BONUS,MT_GENERAL);
|
|
M_KeyReleased=false;
|
|
}
|
|
}
|
|
else
|
|
M_KeyReleased=true;
|
|
}
|
|
|
|
|
|
char far Computing[] = {"Computing..."};
|
|
|
|
#if DUAL_SWAP_FILES
|
|
//--------------------------------------------------------------------------
|
|
// ChangeSwapFiles()
|
|
//
|
|
// PURPOSE: To chance out swap files durring game play -
|
|
//
|
|
// ASSUMES: PageManager is installed.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
void ChangeSwapFiles(boolean display)
|
|
{
|
|
ClearMemory();
|
|
|
|
if (display)
|
|
{
|
|
WindowX=WindowY=0;
|
|
WindowW=320;
|
|
WindowH=200;
|
|
Message(Computing);
|
|
}
|
|
|
|
PM_Shutdown();
|
|
PM_Startup ();
|
|
|
|
PM_CheckMainMem();
|
|
|
|
if (display)
|
|
{
|
|
IN_UserInput(50);
|
|
CleanDrawPlayBorder();
|
|
IN_ClearKeysDown();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// OpenPageFile()
|
|
//--------------------------------------------------------------------------
|
|
void OpenPageFile(void)
|
|
{
|
|
#if DUAL_SWAP_FILES
|
|
|
|
if (gamestate.flags & GS_DRAW_FLOOR || (!ShadowsAvail))
|
|
{
|
|
PML_OpenPageFile(PageFileName);
|
|
FileUsed = sd_NO_SHADOWS;
|
|
}
|
|
else
|
|
{
|
|
PML_OpenPageFile(AltPageFileName);
|
|
FileUsed = sd_SHADOWS;
|
|
}
|
|
|
|
#else
|
|
PML_OpenPageFile(PageFileName);
|
|
#endif
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// PopupAutoMap()
|
|
//--------------------------------------------------------------------------
|
|
void PopupAutoMap()
|
|
{
|
|
#define BASE_X 64
|
|
#define BASE_Y 44
|
|
|
|
ThreeDRefresh();
|
|
ThreeDRefresh();
|
|
|
|
SD_StopSound();
|
|
ClearMemory();
|
|
CacheDrawPic(BASE_X,BASE_Y,AUTOMAPPIC);
|
|
|
|
ShowStats(BASE_X+101,BASE_Y+22,ss_quick,&gamestuff.level[gamestate.mapon].stats);
|
|
|
|
while (Keyboard[sc_Tilde])
|
|
CalcTics();
|
|
|
|
#if GAME_VERSION != SHAREWARE_VERSION && IN_DEVELOPMENT
|
|
// if (DebugOk && PP_step)
|
|
// PicturePause();
|
|
#endif
|
|
|
|
IN_StartAck ();
|
|
while (!IN_CheckAck ())
|
|
CalcTics();
|
|
|
|
PM_CheckMainMem();
|
|
CleanDrawPlayBorder();
|
|
IN_ClearKeysDown();
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
|
|
/*
|
|
#############################################################################
|
|
|
|
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
|
|
//
|
|
#if LOOK_FOR_DEAD_GUYS
|
|
NumDeadGuys=0;
|
|
memset(DeadGuys,0,sizeof(DeadGuys));
|
|
#endif
|
|
|
|
memset(statobjlist,0,sizeof(statobjlist));
|
|
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 (objcount >= MAXACTORS-1)
|
|
{
|
|
objtype *obj=player->next;
|
|
|
|
while (obj)
|
|
{
|
|
if ((obj->flags & (FL_DEADGUY|FL_VISABLE)) == FL_DEADGUY)
|
|
{
|
|
RemoveObj(obj);
|
|
obj = NULL;
|
|
}
|
|
else
|
|
obj = obj->next;
|
|
}
|
|
}
|
|
|
|
if (!objfreelist)
|
|
if (usedummy)
|
|
{
|
|
new = &dummyobj;
|
|
memset (new,0,sizeof(*new));
|
|
}
|
|
else
|
|
PLAY_ERROR(GETNEWACTOR_NO_FREE_SPOTS);
|
|
else
|
|
{
|
|
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 == &dummyobj)
|
|
return;
|
|
|
|
if (gone == player)
|
|
PLAY_ERROR(REMOVEOBJ_REMOVED_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_FreePtr(&((memptr)audiosegs[STARTMUSIC + i]));
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
//-------------------------------------------------------------------------
|
|
// StartMusic()
|
|
// o preload = true, music is cached but not started
|
|
//-------------------------------------------------------------------------
|
|
void StartMusic(boolean preload)
|
|
{
|
|
musicnames musicchunk;
|
|
|
|
SD_MusicOff();
|
|
#if IN_DEVELOPMENT || GAME_VERSION != SHAREWARE_VERSION || TECH_SUPPORT_VERSION
|
|
if (gamestate.flags & GS_MUSIC_TEST)
|
|
musicchunk=music_num;
|
|
else
|
|
#endif
|
|
if (playstate==ex_victorious)
|
|
musicchunk = FORTRESS_MUS;
|
|
else
|
|
musicchunk = songs[gamestate.mapon+gamestate.episode*MAPS_PER_EPISODE];
|
|
|
|
if (!audiosegs[STARTMUSIC+musicchunk])
|
|
{
|
|
MM_BombOnError(false);
|
|
CA_CacheAudioChunk(STARTMUSIC + musicchunk);
|
|
MM_BombOnError(true);
|
|
}
|
|
|
|
if (mmerror)
|
|
mmerror = false;
|
|
else
|
|
{
|
|
MM_SetLock(&((memptr)audiosegs[STARTMUSIC + musicchunk]),true);
|
|
if (!preload)
|
|
SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC + musicchunk]);
|
|
}
|
|
}
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
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 vgapal;
|
|
|
|
/*
|
|
=====================
|
|
=
|
|
= 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 = &vgapal;
|
|
|
|
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 = &vgapal;
|
|
|
|
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 (0,256,redshifts[red-1]);
|
|
palshifted = true;
|
|
}
|
|
else if (white)
|
|
{
|
|
VW_WaitVBL(1);
|
|
VL_SetPalette (0,256,whiteshifts[white-1]);
|
|
palshifted = true;
|
|
}
|
|
else if (palshifted)
|
|
{
|
|
VW_WaitVBL(1);
|
|
VL_SetPalette (0,256,&vgapal); // back to normal
|
|
palshifted = false;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=====================
|
|
=
|
|
= FinishPaletteShifts
|
|
=
|
|
= Resets palette to normal if needed
|
|
=
|
|
=====================
|
|
*/
|
|
|
|
void FinishPaletteShifts (void)
|
|
{
|
|
if (palshifted)
|
|
{
|
|
palshifted = 0;
|
|
VW_WaitVBL(1);
|
|
VL_SetPalette (0,256,&vgapal);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
CORE PLAYLOOP
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
|
|
/*
|
|
=====================
|
|
=
|
|
= DoActor
|
|
=
|
|
=====================
|
|
*/
|
|
|
|
void DoActor (objtype *ob)
|
|
{
|
|
void (*think)(objtype *);
|
|
objtype *actor;
|
|
|
|
|
|
if (ob->flags & FL_FREEZE)
|
|
return;
|
|
|
|
#pragma warn -pia
|
|
if (ob->flags & FL_BARRIER)
|
|
{
|
|
actor = actorat[ob->tilex][ob->tiley];
|
|
if (BARRIER_STATE(ob) == bt_ON)
|
|
{
|
|
if (actor)
|
|
{
|
|
short damage = 0;
|
|
|
|
actor->flags |= FL_BARRIER_DAMAGE;
|
|
if ((US_RndT() < 0x7f) && (actor->flags & FL_SHOOTABLE))
|
|
{
|
|
switch (ob->obclass)
|
|
{
|
|
case arc_barrierobj: // arc barrier - Mild Damage
|
|
damage = 500; // 100
|
|
break;
|
|
|
|
case post_barrierobj: // post barrier - Butt kicker
|
|
damage = 500;
|
|
break;
|
|
}
|
|
DamageActor(actor,damage,ob);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (actor)
|
|
actor->flags &= ~FL_BARRIER_DAMAGE;
|
|
}
|
|
#pragma warn +pia
|
|
|
|
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) )
|
|
{
|
|
if (ob->flags&FL_NONMARK)
|
|
{
|
|
if (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) )
|
|
{
|
|
if (ob->flags&FL_NONMARK)
|
|
{
|
|
if (actorat[ob->tilex][ob->tiley])
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
actorat[ob->tilex][ob->tiley] = ob;
|
|
}
|
|
return;
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
|
|
/*
|
|
===================
|
|
=
|
|
= PlayLoop
|
|
=
|
|
===================
|
|
*/
|
|
|
|
extern boolean ShowQuickMsg;
|
|
|
|
|
|
void PlayLoop (void)
|
|
{
|
|
boolean reset_areas=false;
|
|
int give;
|
|
objtype *obj;
|
|
|
|
playstate = TimeCount = lasttimecount = 0;
|
|
framecount = frameon = 0;
|
|
pwallstate = anglefrac = 0;
|
|
memset (buttonstate,0,sizeof(buttonstate));
|
|
ClearPaletteShifts ();
|
|
ForceUpdateStatusBar();
|
|
|
|
if (MousePresent)
|
|
Mouse(MDelta); // Clear accumulated mouse movement
|
|
|
|
tics = 1; // for first time through
|
|
if (demoplayback)
|
|
IN_StartAck ();
|
|
|
|
do
|
|
{
|
|
PollControls();
|
|
|
|
//
|
|
// actor thinking
|
|
//
|
|
madenoise = false;
|
|
|
|
if (alerted)
|
|
alerted--;
|
|
|
|
MoveDoors ();
|
|
MovePWalls ();
|
|
|
|
for (obj = player;obj;obj = obj->next)
|
|
{
|
|
if ((obj != player) && (Keyboard[sc_6] || Keyboard[sc_7]) && Keyboard[sc_8] && DebugOk)
|
|
{
|
|
if (!reset_areas)
|
|
memset(areabyplayer,1,sizeof(areabyplayer));
|
|
reset_areas=true;
|
|
|
|
if ((((!(obj->flags & FL_INFORMANT)) && (obj->flags & FL_SHOOTABLE))) ||
|
|
(obj->obclass == liquidobj && !(obj->flags & FL_DEADGUY)))
|
|
DamageActor(obj,1000,player);
|
|
}
|
|
else
|
|
if (reset_areas)
|
|
{
|
|
ConnectAreas();
|
|
reset_areas=false;
|
|
}
|
|
DoActor (obj);
|
|
}
|
|
|
|
if (NumEAWalls)
|
|
CheckSpawnEA();
|
|
|
|
if ((!GoldsternInfo.GoldSpawned) && GoldsternInfo.SpawnCnt)
|
|
CheckSpawnGoldstern();
|
|
|
|
UpdatePaletteShifts ();
|
|
|
|
|
|
ThreeDRefresh ();
|
|
|
|
gamestate.TimeCount+=tics;
|
|
|
|
SD_Poll ();
|
|
UpdateSoundLoc(); // JAB
|
|
|
|
if (screenfaded & !playstate)
|
|
VW_FadeIn();
|
|
|
|
// Display first-time instructions.
|
|
//
|
|
if (ShowQuickMsg)
|
|
ShowQuickInstructions();
|
|
|
|
CheckKeys();
|
|
|
|
if (demoplayback && demoptr == lastdemoptr)
|
|
playstate = ex_title;
|
|
|
|
//
|
|
// debug aids
|
|
//
|
|
if (singlestep)
|
|
{
|
|
VW_WaitVBL(14);
|
|
lasttimecount = TimeCount;
|
|
}
|
|
if (extravbls)
|
|
VW_WaitVBL(extravbls);
|
|
|
|
if ((demoplayback) && (IN_CheckAck()))
|
|
{
|
|
IN_ClearKeysDown ();
|
|
playstate = ex_abort;
|
|
}
|
|
|
|
|
|
}while (!playstate && !startgame);
|
|
|
|
if (playstate != ex_died)
|
|
FinishPaletteShifts ();
|
|
|
|
gamestate.flags &= ~GS_VIRGIN_LEVEL;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// ShowQuickInstructions()
|
|
//--------------------------------------------------------------------------
|
|
void ShowQuickInstructions()
|
|
{
|
|
ShowQuickMsg=false;
|
|
|
|
if ((demoplayback) || (gamestate.mapon) || (gamestate.flags & GS_QUICKRUN))
|
|
return;
|
|
|
|
ThreeDRefresh();
|
|
ThreeDRefresh();
|
|
ClearMemory();
|
|
WindowX=0; WindowY=16; WindowW=320; WindowH=168;
|
|
CacheMessage(QUICK_INFO1_TEXT);
|
|
VW_WaitVBL(120);
|
|
CacheMessage(QUICK_INFO2_TEXT);
|
|
IN_Ack();
|
|
IN_ClearKeysDown();
|
|
PM_CheckMainMem();
|
|
CleanDrawPlayBorder();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CleanDrawPlayBorder()
|
|
//--------------------------------------------------------------------------
|
|
void CleanDrawPlayBorder()
|
|
{
|
|
DrawPlayBorder();
|
|
ThreeDRefresh();
|
|
DrawPlayBorder();
|
|
ThreeDRefresh();
|
|
DrawPlayBorder();
|
|
}
|
|
|