5291 lines
118 KiB
C
5291 lines
118 KiB
C
// 3D_AGENT.C
|
|
|
|
#include "3D_DEF.H"
|
|
#pragma hdrstop
|
|
|
|
#include <ctype.h>
|
|
|
|
#include "jm_tp.h"
|
|
|
|
void InitWeaponBounce(void);
|
|
void HandleWeaponBounce(void);
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
LOCAL CONSTANTS
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
//#define ACTIVATE_TERMINAL
|
|
|
|
#define MAXMOUSETURN 10
|
|
|
|
#define MOVESCALE 150l
|
|
#define BACKMOVESCALE 100l
|
|
#define ANGLESCALE 20
|
|
#define MAX_DA 100
|
|
|
|
#define MAX_TERM_COMMAND_LEN 31
|
|
|
|
// Max Score displayable
|
|
|
|
#define MAX_DISPLAY_SCORE (9999999L)
|
|
#define SCORE_ROLL_WAIT (60*10) // Tics
|
|
|
|
// IFDEF switches
|
|
|
|
//#define NO_STATUS_BAR
|
|
|
|
// ECG scroll rate (delay).
|
|
|
|
#define HEALTH_SCROLL_RATE 7
|
|
#define HEALTH_PULSE 70
|
|
|
|
// Text "InfoArea" defines
|
|
#define INFOAREA_X 3
|
|
#define INFOAREA_Y ((unsigned)200-STATUSLINES+3)
|
|
#define INFOAREA_W 109
|
|
#define INFOAREA_H 37
|
|
|
|
#define INFOAREA_BCOLOR 0x01
|
|
#define INFOAREA_CCOLOR 0x1A
|
|
#define INFOAREA_TCOLOR 0xA6
|
|
#define INFOAREA_TSHAD_COLOR 0x04 // Text Shadow Color
|
|
|
|
#define GRENADE_ENERGY_USE 4
|
|
#define BFG_ENERGY_USE (GRENADE_ENERGY_USE<<1)
|
|
|
|
|
|
#define NUM_AMMO_SEGS 21
|
|
|
|
|
|
#define AMMO_SMALL_FONT_NUM_WIDTH 5
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
GLOBAL VARIABLES
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
extern boolean noShots;
|
|
extern short bounceOk;
|
|
|
|
short tryDetonatorDelay=0;
|
|
|
|
//
|
|
// player state info
|
|
//
|
|
long thrustspeed;
|
|
|
|
//unsigned plux,pluy; // player coordinates scaled to unsigned
|
|
|
|
int anglefrac;
|
|
|
|
objtype *LastAttacker;
|
|
|
|
boolean PlayerInvisable = false;
|
|
|
|
char LocationText[MAX_LOCATION_DESC_LEN];
|
|
|
|
#ifdef ACTIVATE_TERMINAL
|
|
char term_com_name[13]= {"TERM_CMD."};
|
|
char term_msg_name[13]= {"TERM_MSG."};
|
|
#endif
|
|
|
|
unsigned player_oldtilex;
|
|
unsigned player_oldtiley;
|
|
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
LOCAL VARIABLES
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
void writeTokenStr(char far *str);
|
|
|
|
void ShowOverheadChunk(void);
|
|
void LoadOverheadChunk(short tpNum);
|
|
void SaveOverheadChunk(short tpNum);
|
|
void DisplayTeleportName(char tpNum, boolean locked);
|
|
|
|
void ForceUpdateStatusBar(void);
|
|
|
|
void UpdateRadarGuage(void);
|
|
void DrawLedStrip(short x,short y,short frac,short max);
|
|
void DisplayPinballBonus(void);
|
|
void CheckPinballBonus(long points);
|
|
byte LevelCompleted(void);
|
|
void T_Player (objtype *ob);
|
|
void T_Attack (objtype *ob);
|
|
|
|
statetype s_player = {0,0,0,&T_Player,NULL,NULL};
|
|
statetype s_attack = {0,0,0,&T_Attack,NULL,NULL};
|
|
|
|
long playerxmove,playerymove;
|
|
|
|
atkinf_t far attackinfo[7][14] =
|
|
|
|
{
|
|
{ {6,0,1},{6,2,2},{6,0,3},{6,-1,4} }, // Auto charge
|
|
{ {6,0,1},{6,1,2},{6,0,3},{6,-1,4} }, // Pistol
|
|
{ {6,0,1},{6,1,2},{5,3,3},{5,-1,4} }, // Pulse
|
|
{ {6,0,1},{6,1,2},{3,4,3},{3,-1,4} }, // ION
|
|
{ {6,0,1},{6,5,2},{6,6,3},{6,-1,4} },
|
|
{ {6,0,1},{6,9,2},{6,10,3},{6,-1,4} },
|
|
{ {5,7,0},{5,8,0},{2,-2,0},{0,0,0} },
|
|
};
|
|
|
|
//int strafeangle[9] = {0,90,180,270,45,135,225,315,0};
|
|
|
|
#define GD0 0x55
|
|
#define YD0 0x35
|
|
#define RD0 0x15
|
|
|
|
#define GD1 0x53
|
|
#define YD1 0x33
|
|
#define RD1 0x13
|
|
|
|
char far DimAmmo[2][22] = {{GD0,GD0,GD0,GD0,GD0,GD0,GD0,YD0,YD0,YD0,YD0,YD0,YD0,YD0,RD0,RD0,RD0,RD0,RD0,RD0,RD0,RD0},
|
|
{GD1,GD1,GD1,GD1,GD1,GD1,GD1,YD1,YD1,YD1,YD1,YD1,YD1,YD1,RD1,RD1,RD1,RD1,RD1,RD1,RD1,RD1}};
|
|
|
|
#define GL0 0x58
|
|
#define YL0 0x38
|
|
#define RL0 0x18
|
|
|
|
#define GL1 0x56
|
|
#define YL1 0x36
|
|
#define RL1 0x16
|
|
|
|
char far LitAmmo[2][22] = {{GL0,GL0,GL0,GL0,GL0,GL0,GL0,YL0,YL0,YL0,YL0,YL0,YL0,YL0,RL0,RL0,RL0,RL0,RL0,RL0,RL0,RL0},
|
|
{GL1,GL1,GL1,GL1,GL1,GL1,GL1,YL1,YL1,YL1,YL1,YL1,YL1,YL1,RL1,RL1,RL1,RL1,RL1,RL1,RL1,RL1}};
|
|
|
|
|
|
#define IA_MAX_LINE 30
|
|
typedef struct InfoArea_Struct
|
|
{
|
|
int x,y;
|
|
int text_color;
|
|
int backgr_color;
|
|
int left_margin;
|
|
char delay;
|
|
char numanims;
|
|
char framecount;
|
|
} InfoArea_Struct;
|
|
|
|
unsigned LastMsgPri = 0;
|
|
short MsgTicsRemain = 0;
|
|
classtype LastInfoAttacker = nothing;
|
|
int LastInfoAttacker_Cloaked = 0;
|
|
infomsg_type LastMsgType = MT_NOTHING;
|
|
InfoArea_Struct InfoAreaSetup;
|
|
|
|
char DrawRadarGuage_COUNT = 3;
|
|
char DrawAmmoNum_COUNT = 3;
|
|
char DrawAmmoPic_COUNT = 3;
|
|
//char DrawPDAmmoPic_COUNT = 3;
|
|
char DrawScoreNum_COUNT = 3;
|
|
char DrawWeaponPic_COUNT = 3;
|
|
char DrawKeyPics_COUNT = 3;
|
|
char DrawHealthNum_COUNT = 3;
|
|
|
|
char DrawInfoArea_COUNT = 3;
|
|
char InitInfoArea_COUNT = 3;
|
|
char ClearInfoArea_COUNT = 3;
|
|
|
|
void DrawWeapon (void);
|
|
void GiveWeapon (int weapon);
|
|
void GiveAmmo (int ammo);
|
|
void DrawGAmmoNum(void);
|
|
void DrawMAmmoNum(void);
|
|
void DrawPDAmmoMsg(void);
|
|
void ComputeAvailWeapons(void);
|
|
void SW_HandleActor(objtype *obj);
|
|
void SW_HandleStatic(statobj_t *stat,unsigned tilex, unsigned tiley);
|
|
|
|
//===========================================================================
|
|
|
|
//----------
|
|
|
|
byte ShowRatio(short bx, short by, short px, short py, long total, long perc, ss_type type);
|
|
void Attack (void);
|
|
void Use (void);
|
|
void Search (objtype *ob);
|
|
void SelectWeapon (void);
|
|
void SelectItem (void);
|
|
|
|
//----------
|
|
|
|
void SpawnPlayer (int tilex, int tiley, int dir);
|
|
void Thrust (int angle, long speed);
|
|
boolean TryMove (objtype *ob);
|
|
void T_Player (objtype *ob);
|
|
|
|
boolean ClipMove (objtype *ob, long xmove, long ymove);
|
|
|
|
void SocketToggle(boolean TurnOn);
|
|
void CheckStatsBonus(void);
|
|
|
|
void T_Stand (objtype *ob);
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
CONTROL STUFF
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
/*
|
|
======================
|
|
=
|
|
= CheckWeaponChange
|
|
=
|
|
= Keys 1-6 change weapons
|
|
=
|
|
=
|
|
======================
|
|
*/
|
|
|
|
|
|
void CheckWeaponChange (void)
|
|
{
|
|
int i,buttons,last;
|
|
|
|
for (i=wp_autocharge;i<=wp_bfg_cannon;i++)
|
|
{
|
|
if (buttonstate[bt_ready_autocharge+i-wp_autocharge])
|
|
{
|
|
if (gamestate.useable_weapons & (1<<i))
|
|
{
|
|
gamestate.weapon = gamestate.chosenweapon = i;
|
|
|
|
DISPLAY_TIMED_MSG(WeaponAvailMsg, MP_WEAPON_AVAIL, MT_GENERAL);
|
|
DrawWeapon();
|
|
return;
|
|
}
|
|
else
|
|
DISPLAY_TIMED_MSG(WeaponNotAvailMsg, MP_WEAPON_AVAIL, MT_GENERAL);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=======================
|
|
=
|
|
= ControlMovement
|
|
=
|
|
= Takes controlx,controly, and buttonstate[bt_strafe]
|
|
=
|
|
= Changes the player's angle and position
|
|
=
|
|
= There is an angle hack because when going 70 fps, the roundoff becomes
|
|
= significant
|
|
=
|
|
=======================
|
|
*/
|
|
|
|
void ControlMovement (objtype *ob)
|
|
{
|
|
long oldx,oldy;
|
|
int angle,maxxmove;
|
|
int angleunits;
|
|
long speed;
|
|
|
|
thrustspeed = 0;
|
|
|
|
oldx = player->x;
|
|
oldy = player->y;
|
|
|
|
//
|
|
// side to side move
|
|
//
|
|
|
|
if ((buttonstate[bt_strafe]) && !(gamestate.turn_around))
|
|
{
|
|
//
|
|
// strafing
|
|
//
|
|
//
|
|
if (controlx > 0)
|
|
{
|
|
angle = ob->angle - ANGLES/4;
|
|
if (angle < 0)
|
|
angle += ANGLES;
|
|
Thrust (angle,controlx*MOVESCALE); // move to left
|
|
}
|
|
else if (controlx < 0)
|
|
{
|
|
angle = ob->angle + ANGLES/4;
|
|
if (angle >= ANGLES)
|
|
angle -= ANGLES;
|
|
Thrust (angle,-controlx*MOVESCALE); // move to right
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (gamestate.turn_around)
|
|
{
|
|
controlx = 100*tics;
|
|
if (gamestate.turn_around < 0)
|
|
controlx = -controlx;
|
|
}
|
|
|
|
//
|
|
// not strafing
|
|
//
|
|
anglefrac += controlx;
|
|
angleunits = anglefrac/ANGLESCALE;
|
|
anglefrac -= angleunits*ANGLESCALE;
|
|
ob->angle -= angleunits;
|
|
|
|
if (ob->angle >= ANGLES)
|
|
ob->angle -= ANGLES;
|
|
if (ob->angle < 0)
|
|
ob->angle += ANGLES;
|
|
|
|
if (gamestate.turn_around)
|
|
{
|
|
boolean done=false;
|
|
|
|
if (gamestate.turn_around > 0)
|
|
{
|
|
gamestate.turn_around -= angleunits;
|
|
if (gamestate.turn_around <= 0)
|
|
done=true;
|
|
}
|
|
else
|
|
{
|
|
gamestate.turn_around -= angleunits;
|
|
if (gamestate.turn_around >= 0)
|
|
done=true;
|
|
}
|
|
|
|
if (done)
|
|
{
|
|
gamestate.turn_around=0;
|
|
ob->angle = gamestate.turn_angle;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// forward/backwards move
|
|
//
|
|
if (controly < 0)
|
|
{
|
|
Thrust (ob->angle,-controly*MOVESCALE); // move forwards
|
|
}
|
|
else if (controly > 0)
|
|
{
|
|
angle = ob->angle + ANGLES/2;
|
|
if (angle >= ANGLES)
|
|
angle -= ANGLES;
|
|
Thrust (angle,controly*BACKMOVESCALE); // move backwards
|
|
}
|
|
else
|
|
if (bounceOk)
|
|
bounceOk--;
|
|
|
|
if (controly)
|
|
bounceOk = 8;
|
|
else
|
|
if (bounceOk)
|
|
bounceOk--;
|
|
|
|
ob->dir = ((ob->angle + 22) % 360)/45;
|
|
|
|
//
|
|
// calculate total move
|
|
//
|
|
playerxmove = player->x - oldx;
|
|
playerymove = player->y - oldy;
|
|
}
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
STATUS WINDOW STUFF
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
#define STATUSDRAWPIC(x, y, picnum) JLatchDrawPic((x),(y+(200-STATUSLINES)),(picnum))
|
|
|
|
|
|
/*
|
|
==================
|
|
=
|
|
= StatusDrawPic
|
|
=
|
|
==================
|
|
*/
|
|
void StatusAllDrawPic(unsigned x, unsigned y, unsigned picnum)
|
|
{
|
|
unsigned temp;
|
|
|
|
#ifdef PAGEFLIP
|
|
|
|
temp = bufferofs;
|
|
bufferofs = PAGE1START+(200-STATUSLINES)*SCREENWIDTH;
|
|
JLatchDrawPic (x,y,picnum);
|
|
bufferofs = PAGE2START+(200-STATUSLINES)*SCREENWIDTH;
|
|
JLatchDrawPic (x,y,picnum);
|
|
bufferofs = PAGE3START+(200-STATUSLINES)*SCREENWIDTH;
|
|
JLatchDrawPic (x,y,picnum);
|
|
bufferofs = temp;
|
|
|
|
#else
|
|
|
|
temp = bufferofs;
|
|
bufferofs = screenloc[0]+(200-STATUSLINES)*SCREENWIDTH;
|
|
JLatchDrawPic (x,y,picnum);
|
|
bufferofs = screenloc[1]+(200-STATUSLINES)*SCREENWIDTH;
|
|
JLatchDrawPic (x,y,picnum);
|
|
bufferofs = screenloc[2]+(200-STATUSLINES)*SCREENWIDTH;
|
|
JLatchDrawPic (x,y,picnum);
|
|
bufferofs = temp;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
void JLatchDrawPic (unsigned x, unsigned y, unsigned picnum)
|
|
{
|
|
unsigned wide, height, source;
|
|
|
|
x <<= 3;
|
|
wide = pictable[picnum-STARTPICS].width;
|
|
height = pictable[picnum-STARTPICS].height;
|
|
source = latchpics[2+picnum-LATCHPICS_LUMP_START];
|
|
VL_LatchToScreen (source,wide/4,height,x,y);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
===============
|
|
=
|
|
= LatchNumber
|
|
=
|
|
= right justifies and pads with blanks
|
|
=
|
|
===============
|
|
*/
|
|
void LatchNumber (int x, int y, int width, long number)
|
|
{
|
|
unsigned length,wide=0,c;
|
|
char str[20];
|
|
|
|
ltoa(number,str,10);
|
|
|
|
length = strlen(str);
|
|
|
|
while ((length<width) && (wide < width))
|
|
{
|
|
STATUSDRAWPIC(x,y,N_BLANKPIC);
|
|
x++;
|
|
wide++;
|
|
length++;
|
|
}
|
|
|
|
c = 0;
|
|
|
|
while (wide<width)
|
|
{
|
|
STATUSDRAWPIC (x,y,str[c]-'0'+ N_0PIC);
|
|
x++;
|
|
c++;
|
|
wide++;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
//
|
|
//
|
|
// SCORE DISPLAY ROUTINES
|
|
//
|
|
//
|
|
//===========================================================================
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// DrawHealth()
|
|
//
|
|
// PURPOSE : Marks the Health_NUM to be refreshed durring the next
|
|
// StatusBarRefresh.
|
|
//--------------------------------------------------------------------------
|
|
void DrawHealth (void)
|
|
{
|
|
char *ptr = gamestate.health_str;
|
|
|
|
itoa(gamestate.health,gamestate.health_str,10);
|
|
while (*ptr)
|
|
*ptr++ -= '0';
|
|
|
|
DrawHealthNum_COUNT=3;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// DrawHealthNum()
|
|
//--------------------------------------------------------------------------
|
|
void DrawHealthNum(void)
|
|
{
|
|
char loop,num;
|
|
short check=100;
|
|
|
|
DrawHealthNum_COUNT--;
|
|
|
|
for (loop=num=0; loop<3; loop++,check /= 10)
|
|
if (gamestate.health < check)
|
|
JLatchDrawPic(16+loop,162,NG_BLANKPIC);
|
|
else
|
|
JLatchDrawPic(16+loop,162,gamestate.health_str[num++]+NG_0PIC);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// TakeDamage()
|
|
//---------------------------------------------------------------------------
|
|
void TakeDamage (int points, objtype *attacker)
|
|
{
|
|
LastAttacker = attacker;
|
|
|
|
if (gamestate.flags & GS_ATTACK_INFOAREA)
|
|
if (attacker)
|
|
{
|
|
if ((LastMsgType == MT_ATTACK) && (LastInfoAttacker == attacker->obclass))
|
|
MsgTicsRemain = DISPLAY_MSG_STD_TIME;
|
|
else
|
|
{
|
|
if (DISPLAY_TIMED_MSG(ActorInfoMsg[attacker->obclass-rentacopobj],MP_TAKE_DAMAGE,MT_ATTACK))
|
|
{
|
|
LastInfoAttacker = attacker->obclass;
|
|
LastInfoAttacker_Cloaked = attacker->flags2 & FL2_CLOAKED;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (godmode)
|
|
return;
|
|
|
|
if (gamestate.difficulty==gd_baby)
|
|
points>>=2;
|
|
|
|
gamestate.health -= points;
|
|
|
|
if (gamestate.health<=0)
|
|
{
|
|
gamestate.health = 0;
|
|
playstate = ex_died;
|
|
killerobj = attacker;
|
|
if (killerobj)
|
|
killerobj->flags |= FL_FREEZE;
|
|
}
|
|
|
|
StartDamageFlash (points);
|
|
DrawHealth();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// HealSelf()
|
|
//---------------------------------------------------------------------------
|
|
void HealSelf(int points)
|
|
{
|
|
gamestate.health += points;
|
|
if (gamestate.health > 100)
|
|
gamestate.health = 100;
|
|
|
|
DrawHealth ();
|
|
}
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
//
|
|
//
|
|
// SCORE DISPLAY ROUTINES
|
|
//
|
|
//
|
|
//===========================================================================
|
|
|
|
//--------------------------------------------------------------------------
|
|
// DrawScore()
|
|
//
|
|
// PURPOSE : Marks the Score to be refreshed durring the next
|
|
// StatusBarRefresh.
|
|
//--------------------------------------------------------------------------
|
|
void DrawScore(void)
|
|
{
|
|
DrawScoreNum_COUNT = 3;
|
|
}
|
|
|
|
extern unsigned char music_num;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// DrawScoreNum()
|
|
//
|
|
// NOTE : Could do some sort of "scrolling" animation on LED screen with
|
|
// chars and a simple table.....
|
|
//--------------------------------------------------------------------------
|
|
void DrawScoreNum(void)
|
|
{
|
|
#define Y 3
|
|
#define X 32
|
|
|
|
if (gamestate.tic_score > MAX_DISPLAY_SCORE)
|
|
{
|
|
if (gamestate.score_roll_wait)
|
|
{
|
|
JLatchDrawPic(X+0,(200-STATUSLINES)+Y,N_BLANKPIC);
|
|
JLatchDrawPic(X+1,(200-STATUSLINES)+Y,N_DASHPIC);
|
|
JLatchDrawPic(X+2,(200-STATUSLINES)+Y,N_RPIC);
|
|
JLatchDrawPic(X+3,(200-STATUSLINES)+Y,N_OPIC);
|
|
JLatchDrawPic(X+4,(200-STATUSLINES)+Y,N_LPIC);
|
|
JLatchDrawPic(X+5,(200-STATUSLINES)+Y,N_LPIC);
|
|
JLatchDrawPic(X+6,(200-STATUSLINES)+Y,N_DASHPIC);
|
|
}
|
|
else
|
|
{
|
|
LatchNumber(X,Y,7,gamestate.tic_score%(MAX_DISPLAY_SCORE+1));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (gamestate.flags & GS_TICS_FOR_SCORE)
|
|
LatchNumber(X,Y,7,realtics);
|
|
else
|
|
if (gamestate.flags & GS_MUSIC_TEST)
|
|
LatchNumber(X,Y,7,music_num);
|
|
else
|
|
LatchNumber(X,Y,7,gamestate.tic_score);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// UpdateScore()
|
|
//--------------------------------------------------------------------------
|
|
void UpdateScore(void)
|
|
{
|
|
long score_diff, temp_tics;
|
|
boolean RollSound;
|
|
|
|
score_diff = gamestate.score - gamestate.tic_score;
|
|
|
|
if (score_diff)
|
|
{
|
|
if (score_diff > 1500)
|
|
temp_tics = score_diff>>2;
|
|
else
|
|
temp_tics = tics<<3;
|
|
|
|
if (score_diff > temp_tics)
|
|
gamestate.tic_score += temp_tics;
|
|
else
|
|
gamestate.tic_score = gamestate.score;
|
|
|
|
DrawScore();
|
|
}
|
|
|
|
|
|
if (gamestate.score_roll_wait)
|
|
{
|
|
if ((gamestate.score_roll_wait-=tics) <= 0)
|
|
{
|
|
gamestate.score_roll_wait = 0;
|
|
}
|
|
DrawScore();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// GivePoints()
|
|
//
|
|
// .score = Holds real score
|
|
// .tic_score = Holds displayed score (tic'ing toward .score)
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void GivePoints(long points,boolean add_to_stats)
|
|
{
|
|
// Add score to statistics.
|
|
//
|
|
if (add_to_stats)
|
|
gamestuff.level[gamestate.mapon].stats.accum_points += points;
|
|
|
|
// Check for bonuses!
|
|
//
|
|
CheckPinballBonus(points);
|
|
|
|
// Add points to score
|
|
//
|
|
gamestate.score += points;
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
//
|
|
// SECURITY KEY DISPLAY ROUTINES
|
|
//
|
|
//
|
|
//===========================================================================
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DrawKeys()
|
|
//
|
|
// PURPOSE : Marks the security key pics to be refreshed during the next
|
|
// StatusBarRefresh.
|
|
//---------------------------------------------------------------------------
|
|
void DrawKeys (void)
|
|
{
|
|
DrawKeyPics_COUNT = 3;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DrawKeyPics()
|
|
//---------------------------------------------------------------------------
|
|
void DrawKeyPics(void)
|
|
{
|
|
char loop;
|
|
|
|
DrawKeyPics_COUNT--;
|
|
|
|
for (loop=0; loop<NUMKEYS; loop++)
|
|
if (gamestate.numkeys[loop])
|
|
JLatchDrawPic(15+2*loop,179,RED_KEYPIC+loop);
|
|
else
|
|
JLatchDrawPic(15+2*loop,179,NO_KEYPIC);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// GiveKey
|
|
//---------------------------------------------------------------------------
|
|
void GiveKey (int key)
|
|
{
|
|
gamestate.numkeys[key]++;
|
|
DrawKeys();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// TakeKey
|
|
//---------------------------------------------------------------------------
|
|
void TakeKey (int key)
|
|
{
|
|
gamestate.numkeys[key]--;
|
|
DrawKeys();
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
//
|
|
//
|
|
// WEAPON DISPLAY ROUTINES
|
|
//
|
|
//
|
|
//===========================================================================
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DrawWeapon()
|
|
//
|
|
// PURPOSE : Marks the Weapon pics to be refreshed durring the next
|
|
// StatusBarRefresh.
|
|
//---------------------------------------------------------------------------
|
|
void DrawWeapon(void)
|
|
{
|
|
DrawWeaponPic_COUNT=3;
|
|
DrawAmmo(true);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DrawWeaponPic()
|
|
//---------------------------------------------------------------------------
|
|
void DrawWeaponPic(void)
|
|
{
|
|
if (gamestate.weapon == -1)
|
|
return;
|
|
|
|
JLatchDrawPic(31,176,WEAPON1PIC+gamestate.weapon);
|
|
|
|
DrawWeaponPic_COUNT--;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// GiveWeapon()
|
|
//---------------------------------------------------------------------------
|
|
void GiveWeapon (int weapon)
|
|
{
|
|
GiveAmmo (6);
|
|
|
|
if (!(gamestate.weapons & (1<<weapon)))
|
|
{
|
|
gamestate.weapons |= (1<<weapon);
|
|
|
|
if (gamestate.weapon < weapon)
|
|
{
|
|
gamestate.weapon = gamestate.chosenweapon = weapon;
|
|
DrawWeapon();
|
|
}
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
//
|
|
// AMMO DISPLAY ROUTINES
|
|
//
|
|
//
|
|
//===========================================================================
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DrawAmmo()
|
|
//
|
|
// PURPOSE : Marks the AMMO NUM & AMMO PIC (if necessary) to be refreshed
|
|
// durring the next StatusBarRefresh.
|
|
//
|
|
// NOTE : This re-computes the number of LEDs to be lit.
|
|
//---------------------------------------------------------------------------
|
|
void DrawAmmo(boolean ForceRefresh)
|
|
{
|
|
int temp;
|
|
unsigned ammo,max_ammo;
|
|
|
|
ComputeAvailWeapons();
|
|
|
|
//
|
|
// Which weapon are we needing a refresh for?
|
|
//
|
|
|
|
switch (gamestate.weapon)
|
|
{
|
|
// case wp_plasma_detonators:
|
|
// DrawAmmoPic_COUNT = 3;
|
|
// DrawAmmoNum_COUNT = 0;
|
|
// return;
|
|
|
|
case wp_autocharge:
|
|
DrawAmmoPic_COUNT = 3;
|
|
DrawAmmoNum_COUNT = 0;
|
|
return;
|
|
|
|
default:
|
|
ammo = gamestate.ammo;
|
|
max_ammo = MAX_AMMO;
|
|
break;
|
|
}
|
|
|
|
if (ammo)
|
|
{
|
|
temp = (ammo*NUM_AMMO_SEGS)/max_ammo;
|
|
if (!temp)
|
|
temp = 1;
|
|
}
|
|
else
|
|
temp = 0;
|
|
|
|
gamestate.ammo_leds = temp;
|
|
|
|
if ((temp != gamestate.lastammo_leds) || ForceRefresh)
|
|
{
|
|
gamestate.lastammo_leds = temp;
|
|
DrawAmmoPic_COUNT = 3;
|
|
}
|
|
|
|
DrawAmmoNum_COUNT=3;
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DrawAmmoNum()
|
|
//---------------------------------------------------------------------------
|
|
void DrawAmmoNum(void)
|
|
{
|
|
if (gamestate.weapon == -1)
|
|
return;
|
|
|
|
fontnumber = 2;
|
|
fontcolor = 0x9D;
|
|
|
|
PrintX = 252;
|
|
PrintY = 200-STATUSLINES+38;
|
|
|
|
#if 0
|
|
switch (gamestate.weapon)
|
|
{
|
|
case wp_plasma_detonators:
|
|
case wp_autocharge:
|
|
break;
|
|
|
|
default:
|
|
DrawGAmmoNum();
|
|
break;
|
|
}
|
|
#else
|
|
|
|
DrawGAmmoNum();
|
|
|
|
#endif
|
|
|
|
DrawAmmoNum_COUNT--;
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DrawGAmmoNum()
|
|
//---------------------------------------------------------------------------
|
|
void DrawGAmmoNum(void)
|
|
{
|
|
char buffer[32];
|
|
|
|
if (gamestate.ammo <100)
|
|
{
|
|
PrintX+=AMMO_SMALL_FONT_NUM_WIDTH;
|
|
if (gamestate.ammo <10)
|
|
PrintX+=AMMO_SMALL_FONT_NUM_WIDTH;
|
|
}
|
|
|
|
JLatchDrawPic(31,184,W1_CORNERPIC+gamestate.weapon);
|
|
|
|
px = PrintX;
|
|
py = PrintY;
|
|
VW_DrawPropString(ultoa(gamestate.ammo,buffer,10));
|
|
VW_DrawPropString("%");
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DrawAmmoPic()
|
|
//---------------------------------------------------------------------------
|
|
void DrawAmmoPic(void)
|
|
{
|
|
switch (gamestate.weapon)
|
|
{
|
|
case wp_autocharge:
|
|
DrawAmmoMsg();
|
|
break;
|
|
|
|
// case wp_plasma_detonators:
|
|
// DrawPDAmmoMsg();
|
|
// break;
|
|
|
|
default:
|
|
DrawAmmoGuage();
|
|
break;
|
|
}
|
|
|
|
DrawAmmoPic_COUNT--;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DrawAmmoMsg() -
|
|
//---------------------------------------------------------------------------
|
|
void DrawAmmoMsg(void)
|
|
{
|
|
if (gamestate.weapon_wait)
|
|
JLatchDrawPic(30,(200-STATUSLINES),WAITPIC);
|
|
else
|
|
JLatchDrawPic(30,(200-STATUSLINES),READYPIC);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DrawPDAmmoMsg() -
|
|
//---------------------------------------------------------------------------
|
|
void DrawPDAmmoMsg(void)
|
|
{
|
|
if (gamestate.plasma_detonators)
|
|
JLatchDrawPic(30,(200-STATUSLINES),READYPIC);
|
|
else
|
|
JLatchDrawPic(30,(200-STATUSLINES),WAITPIC);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// UpdateAmmoMsg() -
|
|
//---------------------------------------------------------------------------
|
|
void UpdateAmmoMsg(void)
|
|
{
|
|
if (gamestate.weapon_wait)
|
|
if ((gamestate.weapon_wait -= tics)<=0)
|
|
{
|
|
gamestate.weapon_wait = 0;
|
|
DrawAmmoPic_COUNT = 3;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DrawAmmoGuage()
|
|
//---------------------------------------------------------------------------
|
|
void DrawAmmoGuage(void)
|
|
{
|
|
DrawLedStrip(243,155,gamestate.ammo_leds,NUM_AMMO_SEGS);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// UpdateRadarGuage()
|
|
//---------------------------------------------------------------------------
|
|
void UpdateRadarGuage(void)
|
|
{
|
|
int temp;
|
|
|
|
if (gamestate.rpower)
|
|
{
|
|
temp = ((long)gamestate.rpower*NUM_AMMO_SEGS)/MAX_RADAR_ENERGY;
|
|
|
|
if (temp > NUM_AMMO_SEGS)
|
|
temp = NUM_AMMO_SEGS;
|
|
|
|
if (!temp)
|
|
temp = 1;
|
|
}
|
|
else
|
|
temp = 0;
|
|
|
|
gamestate.radar_leds = temp;
|
|
|
|
if (temp != gamestate.lastradar_leds)
|
|
gamestate.lastradar_leds = temp;
|
|
|
|
DrawRadarGuage_COUNT=3;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DrawRadarGuage()
|
|
//---------------------------------------------------------------------------
|
|
void DrawRadarGuage(void)
|
|
{
|
|
char zoom;
|
|
|
|
DrawLedStrip(235,155,gamestate.radar_leds,NUM_AMMO_SEGS);
|
|
|
|
if (gamestate.rpower)
|
|
zoom = gamestate.rzoom;
|
|
else
|
|
zoom = 0;
|
|
|
|
JLatchDrawPic(22,152,ONEXZOOMPIC+zoom);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DrawLedStrip()
|
|
//---------------------------------------------------------------------------
|
|
void DrawLedStrip(short x,short y,short frac,short max)
|
|
{
|
|
int ypos;
|
|
unsigned amount;
|
|
char leds;
|
|
|
|
leds = frac;
|
|
|
|
if (leds)
|
|
amount = max-leds;
|
|
else
|
|
amount = max;
|
|
|
|
// Draw dim LEDs.
|
|
//
|
|
for (ypos = 0;ypos < amount;ypos++)
|
|
{
|
|
VW_Hlin (x,x+4,y++,DimAmmo[0][amount]);
|
|
VW_Hlin (x,x+4,y++,DimAmmo[1][amount]);
|
|
}
|
|
|
|
// Draw lit LEDs.
|
|
//
|
|
for (;ypos<NUM_AMMO_SEGS;ypos++)
|
|
{
|
|
VW_Hlin (x,x+4,y++,LitAmmo[0][amount]);
|
|
VW_Hlin (x,x+4,y++,LitAmmo[1][amount]);
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// GiveAmmo()
|
|
//---------------------------------------------------------------------------
|
|
void GiveAmmo (int ammo)
|
|
{
|
|
|
|
#if MP_NO_MORE_AMMO > MP_BONUS
|
|
if (LastMsgType == MT_OUT_OF_AMMO)
|
|
{
|
|
MsgTicsRemain = 1;
|
|
LastMsgType = MT_CLEAR;
|
|
}
|
|
#endif
|
|
|
|
gamestate.ammo += ammo;
|
|
if (gamestate.ammo > MAX_AMMO)
|
|
{
|
|
gamestate.ammo = MAX_AMMO;
|
|
}
|
|
|
|
DrawAmmo(false);
|
|
|
|
if (gamestate.weapon != gamestate.chosenweapon)
|
|
{
|
|
if (gamestate.useable_weapons & (1<<gamestate.chosenweapon))
|
|
{
|
|
gamestate.weapon = gamestate.chosenweapon;
|
|
DrawWeapon ();
|
|
}
|
|
}
|
|
|
|
SD_PlaySound (GETAMMOSND);
|
|
|
|
|
|
#if 0
|
|
#if MP_NO_MORE_AMMO > MP_BONUS
|
|
if (LastMsgType == MT_OUT_OF_AMMO)
|
|
{
|
|
MsgTicsRemain = 1;
|
|
LastMsgType = MT_CLEAR;
|
|
}
|
|
#endif
|
|
|
|
gamestate.ammo += ammo;
|
|
if (gamestate.ammo > MAX_AMMO)
|
|
{
|
|
gamestate.ammo = MAX_AMMO;
|
|
}
|
|
|
|
// JIM - This needs to be optomized.
|
|
|
|
if (gamestate.weapon != gamestate.chosenweapon)
|
|
{
|
|
if (!((gamestate.chosenweapon == wp_grenade) && (gamestate.ammo < GRENADE_ENERGY_USE)) ||
|
|
!((gamestate.chosenweapon == wp_bfg_cannon) && (gamestate.ammo < BFG_ENERGY_USE)))
|
|
{
|
|
gamestate.weapon = gamestate.chosenweapon;
|
|
DrawWeapon ();
|
|
}
|
|
}
|
|
|
|
DrawAmmo(false);
|
|
SD_PlaySound (GETAMMOSND);
|
|
#endif
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
//ComputeAvailWeapons()
|
|
//
|
|
// This function creates a Bit MASK for gamestate.weapons according to what
|
|
// weapon is available for useage due to ammo avail.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void ComputeAvailWeapons(void)
|
|
{
|
|
|
|
//
|
|
// Determine what ammo ammounts we have avail
|
|
//
|
|
|
|
if (gamestate.ammo)
|
|
{
|
|
if (gamestate.ammo >= BFG_ENERGY_USE)
|
|
gamestate.useable_weapons = (1<<wp_bfg_cannon)
|
|
| (1<<wp_grenade)
|
|
| (1<<wp_ion_cannon)
|
|
| (1<<wp_burst_rifle)
|
|
| (1<<wp_pistol)
|
|
| (1<<wp_autocharge);
|
|
else
|
|
if (gamestate.ammo >= GRENADE_ENERGY_USE)
|
|
gamestate.useable_weapons = (1<<wp_grenade)
|
|
| (1<<wp_ion_cannon)
|
|
| (1<<wp_burst_rifle)
|
|
| (1<<wp_pistol)
|
|
| (1<<wp_autocharge);
|
|
else
|
|
gamestate.useable_weapons = (1<<wp_ion_cannon)
|
|
| (1<<wp_burst_rifle)
|
|
| (1<<wp_pistol)
|
|
| (1<<wp_autocharge);
|
|
}
|
|
else
|
|
gamestate.useable_weapons = (1<<wp_autocharge);
|
|
|
|
//
|
|
// Do special weapons.
|
|
//
|
|
|
|
// if (gamestate.plasma_detonators)
|
|
// gamestate.useable_weapons |= (1<<wp_plasma_detonators);
|
|
|
|
//
|
|
// mask off with the weapons being carried.
|
|
//
|
|
|
|
gamestate.useable_weapons &= gamestate.weapons;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// TakePlasmaDetonator()
|
|
//---------------------------------------------------------------------------
|
|
void TakePlasmaDetonator(int count)
|
|
{
|
|
if (gamestate.plasma_detonators < count)
|
|
gamestate.plasma_detonators = 0;
|
|
else
|
|
gamestate.plasma_detonators -= count;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// GivePlasmaDetonator()
|
|
//---------------------------------------------------------------------------
|
|
void GivePlasmaDetonator(int count)
|
|
{
|
|
gamestate.plasma_detonators += count;
|
|
|
|
if (gamestate.plasma_detonators > MAX_PLASMA_DETONATORS)
|
|
gamestate.plasma_detonators = MAX_PLASMA_DETONATORS;
|
|
|
|
// if (gamestate.chosenweapon == wp_plasma_detonators)
|
|
// {
|
|
// gamestate.weapon = gamestate.chosenweapon;
|
|
// DrawWeapon ();
|
|
// }
|
|
|
|
ComputeAvailWeapons();
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// GiveToken()
|
|
//---------------------------------------------------------------------------
|
|
void GiveToken (int tokens)
|
|
{
|
|
#if MP_NO_MORE_TOKENS > MP_BONUS
|
|
if (LastMsgType == MT_NO_MO_FOOD_TOKENS)
|
|
{
|
|
MsgTicsRemain = 1;
|
|
LastMsgType = MT_CLEAR;
|
|
}
|
|
#endif
|
|
|
|
gamestate.tokens += tokens;
|
|
if (gamestate.tokens > MAX_TOKENS)
|
|
{
|
|
gamestate.tokens = MAX_TOKENS;
|
|
}
|
|
|
|
SD_PlaySound (GOTTOKENSND);
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
//
|
|
// INFO AREA ROUTINES
|
|
//
|
|
//
|
|
//===========================================================================
|
|
|
|
//--------------------------------------------------------------------------
|
|
// DisplayInfoMsg() - Returns if Higher Pri message is holding.
|
|
//
|
|
// SEE MACROS: DISPLAY_TIMED_MSG() & DISPLAY_MSG() -- Def.h
|
|
//
|
|
// DISPLAY_TIMED_MSG(msg,pri,type) - For E-Z Timed Msgs (std. display time)
|
|
// DISPLAY_MSG(msg,pri,type) - For E-Z NON-Timed Msgs.
|
|
//--------------------------------------------------------------------------
|
|
boolean DisplayInfoMsg(char far *Msg,msg_priorities Priority,short DisplayTime,short MsgType)
|
|
{
|
|
if (Priority >= LastMsgPri)
|
|
{
|
|
if (Priority == MP_max_val) // "System" msgs
|
|
LastMsgPri = MP_min_val;
|
|
else
|
|
LastMsgPri = Priority;
|
|
|
|
#pragma warn -pia
|
|
if (MsgTicsRemain = DisplayTime)
|
|
StatusAllDrawPic(0,40,BRI_LIGHTPIC);
|
|
#pragma warn +pia
|
|
|
|
gamestate.msg = Msg;
|
|
|
|
DrawInfoArea_COUNT = InitInfoArea_COUNT = 3;
|
|
|
|
LastMsgType = MsgType;
|
|
|
|
if (LastMsgType != MT_ATTACK)
|
|
LastInfoAttacker_Cloaked = 0;
|
|
|
|
return(true);
|
|
}
|
|
else
|
|
return(false);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// ClearInfoArea()
|
|
//--------------------------------------------------------------------------
|
|
void ClearInfoArea(void)
|
|
{
|
|
unsigned i,old_ofs;
|
|
|
|
#if IN_DEVELOPMENT
|
|
if (gamestate.flags & GS_SHOW_OVERHEAD)
|
|
return;
|
|
#endif
|
|
|
|
if (ClearInfoArea_COUNT)
|
|
ClearInfoArea_COUNT--;
|
|
|
|
InfoAreaSetup.x = InfoAreaSetup.left_margin;
|
|
InfoAreaSetup.y = INFOAREA_Y;
|
|
InfoAreaSetup.framecount = InfoAreaSetup.numanims = 0;
|
|
|
|
JLatchDrawPic(0,200-STATUSLINES,INFOAREAPIC);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// InitInfoArea()
|
|
//--------------------------------------------------------------------------
|
|
void InitInfoArea(void)
|
|
{
|
|
InfoAreaSetup.left_margin = INFOAREA_X;
|
|
InfoAreaSetup.text_color = INFOAREA_TCOLOR;
|
|
InfoAreaSetup.backgr_color = INFOAREA_BCOLOR;
|
|
InitInfoArea_COUNT--;
|
|
|
|
ClearInfoArea();
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// UpdateInfoArea()
|
|
//--------------------------------------------------------------------------
|
|
void UpdateInfoArea(void)
|
|
{
|
|
|
|
if (InfoAreaSetup.numanims)
|
|
{
|
|
AnimatePage();
|
|
}
|
|
|
|
if (InitInfoArea_COUNT)
|
|
InitInfoArea();
|
|
else
|
|
if (ClearInfoArea_COUNT)
|
|
ClearInfoArea();
|
|
|
|
if (DrawInfoArea_COUNT)
|
|
DrawInfoArea();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// UpdateInfoAreaClock() - This routine is called ONLY ONCE per refresh
|
|
// to update the InfoArea Clock and to release
|
|
// any messages that have expired.
|
|
//---------------------------------------------------------------------------
|
|
void UpdateInfoAreaClock(void)
|
|
{
|
|
|
|
if (playstate == ex_title || playstate == ex_victorious)
|
|
return;
|
|
|
|
//
|
|
// Check for existing timed messages
|
|
//
|
|
|
|
if (LastMsgPri && MsgTicsRemain)
|
|
{
|
|
//
|
|
// Tic' that 'Puppy' down - Yea!
|
|
//
|
|
|
|
if ((MsgTicsRemain -= tics) <= 0)
|
|
{
|
|
// Message has expired.
|
|
DisplayNoMoMsgs();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DisplayTokens()
|
|
//---------------------------------------------------------------------------
|
|
char default_msg[] = { "\r NO MESSAGES."
|
|
"^FCA8\r FOOD TOKENS: "
|
|
" "
|
|
};
|
|
|
|
char needDetonator_msg[]="\r\r^FC39 FIND THE DETONATOR!";
|
|
|
|
char haveDetonator_msg[]="\r\r^FC39DESTROY SECURITY CUBE!";
|
|
|
|
char destroyGoldfire_msg[]="\r\r^FC39 DESTROY GOLDFIRE!";
|
|
|
|
void DisplayNoMoMsgs(void)
|
|
{
|
|
char buffer[9];
|
|
|
|
LastMsgPri = MP_min_val;
|
|
|
|
if (BONUS_QUEUE)
|
|
{
|
|
DisplayPinballBonus();
|
|
return;
|
|
}
|
|
|
|
MsgTicsRemain = 0;
|
|
StatusAllDrawPic (0,40,DIM_LIGHTPIC);
|
|
sprintf((char *)&default_msg[40],"%-d",gamestate.tokens);
|
|
if (gamestuff.level[gamestate.mapon+1].locked)
|
|
{
|
|
switch (gamestate.mapon)
|
|
{
|
|
case 19:
|
|
strcat(default_msg,destroyGoldfire_msg);
|
|
break;
|
|
|
|
case 20:
|
|
case 21:
|
|
case 22:
|
|
case 23:
|
|
break;
|
|
|
|
default:
|
|
if (gamestate.plasma_detonators)
|
|
strcat(default_msg,haveDetonator_msg);
|
|
else
|
|
strcat(default_msg,needDetonator_msg);
|
|
break;
|
|
}
|
|
}
|
|
|
|
DisplayInfoMsg(default_msg,MP_max_val,0,MT_NOTHING);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// DrawInfoArea()
|
|
//
|
|
//
|
|
// Active control codes:
|
|
//
|
|
// ^ANnn - define animation
|
|
// ^FCnn - set font color
|
|
// ^LMnnn - set left margin (if 'nnn' == "fff" uses current x)
|
|
// ^EP - end of page (waits for 'M' to read MORE)
|
|
// ^PXnnn - move x to coordinate 'n'
|
|
// ^PYnnn - move y to coordinate 'n'
|
|
// ^SHnnn - display shape 'n' at current x,y
|
|
// ^BGn - set background color
|
|
// ^DM - Default Margins
|
|
//
|
|
// Other info:
|
|
//
|
|
// All 'n' values are hex numbers (0 - f), case insensitive.
|
|
// The number of N's listed is the number of digits REQUIRED by that control
|
|
// code. (IE: ^LMnnn MUST have 3 values! --> 003, 1a2, 01f, etc...)
|
|
//
|
|
// If a line consists only of control codes, the cursor is NOT advanced
|
|
// to the next line (the ending <CR><LF> is skipped). If just ONE non-control
|
|
// code is added, the number "8" for example, then the "8" is displayed
|
|
// and the cursor is advanced to the next line.
|
|
//
|
|
// The text presenter now handles sprites, but they are NOT masked! Also,
|
|
// sprite animations will be difficult to implement unless all frames are
|
|
// of the same dimensions.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
char far *HandleControlCodes(char far *first_ch);
|
|
|
|
|
|
void DrawInfoArea(void)
|
|
{
|
|
#define IA_FONT_HEIGHT 6
|
|
|
|
// short length,i;
|
|
char far *first_ch;
|
|
char far *scan_ch,temp;
|
|
unsigned old_ofs;
|
|
|
|
#if IN_DEVELOPMENT
|
|
if (gamestate.flags & GS_SHOW_OVERHEAD)
|
|
return;
|
|
#endif
|
|
|
|
DrawInfoArea_COUNT--;
|
|
|
|
if (!*gamestate.msg)
|
|
return;
|
|
|
|
first_ch = gamestate.msg;
|
|
|
|
fontnumber = 2;
|
|
fontcolor = InfoAreaSetup.text_color;
|
|
|
|
while (first_ch && *first_ch)
|
|
{
|
|
|
|
if (*first_ch != TP_CONTROL_CHAR)
|
|
{
|
|
scan_ch = first_ch;
|
|
|
|
while ((*scan_ch) && (*scan_ch != '\n') && (*scan_ch != TP_RETURN_CHAR) && (*scan_ch != TP_CONTROL_CHAR))
|
|
scan_ch++;
|
|
|
|
// print current line
|
|
//
|
|
|
|
temp = *scan_ch;
|
|
*scan_ch = 0;
|
|
|
|
if (*first_ch != TP_RETURN_CHAR)
|
|
{
|
|
int i;
|
|
char temp_color;
|
|
|
|
temp_color = fontcolor;
|
|
fontcolor = INFOAREA_TSHAD_COLOR;
|
|
|
|
px = InfoAreaSetup.x+1;
|
|
py = InfoAreaSetup.y+1;
|
|
VW_DrawPropString(first_ch);
|
|
fontcolor = temp_color;
|
|
|
|
px = InfoAreaSetup.x;
|
|
py = InfoAreaSetup.y;
|
|
VW_DrawPropString(first_ch);
|
|
}
|
|
|
|
*scan_ch = temp;
|
|
first_ch = scan_ch;
|
|
|
|
// skip SPACES / RETURNS at end of line
|
|
//
|
|
|
|
if ((*first_ch==' ') || (*first_ch==TP_RETURN_CHAR))
|
|
first_ch++;
|
|
|
|
// TP_CONTROL_CHARs don't advance to next character line
|
|
//
|
|
|
|
if (*scan_ch != TP_CONTROL_CHAR)
|
|
{
|
|
InfoAreaSetup.x = InfoAreaSetup.left_margin;
|
|
InfoAreaSetup.y += IA_FONT_HEIGHT;
|
|
}
|
|
else
|
|
InfoAreaSetup.x = px;
|
|
}
|
|
else
|
|
first_ch = HandleControlCodes(first_ch);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// HandleControlCodes()
|
|
//---------------------------------------------------------------------------
|
|
char far *HandleControlCodes(char far *first_ch)
|
|
{
|
|
spritetabletype far *spr;
|
|
// piShapeInfo far *shape_info;
|
|
piShapeInfo far *shape;
|
|
piAnimInfo far *anim;
|
|
unsigned shapenum;
|
|
short length,width;
|
|
char far *s;
|
|
|
|
first_ch++;
|
|
|
|
#ifndef TP_CASE_SENSITIVE
|
|
*first_ch=toupper(*first_ch);
|
|
*(first_ch+1)=toupper(*(first_ch+1));
|
|
#endif
|
|
|
|
switch (*((unsigned far *)first_ch)++)
|
|
{
|
|
|
|
// INIT ANIMATION ---------------------------------------------------
|
|
//
|
|
case TP_CNVT_CODE('A','N'):
|
|
shapenum = TP_VALUE(first_ch,2);
|
|
first_ch += 2;
|
|
_fmemcpy(&piAnimList[InfoAreaSetup.numanims],&piAnimTable[shapenum],sizeof(piAnimInfo));
|
|
anim = &piAnimList[InfoAreaSetup.numanims++];
|
|
shape = &piShapeTable[anim->baseshape+anim->frame]; // BUG!! (assumes "pia_shapetable")
|
|
// spr = &spritetable[shape->shapenum-STARTSPRITES];
|
|
|
|
anim->y=InfoAreaSetup.y;
|
|
anim->x=DrawShape(InfoAreaSetup.x,InfoAreaSetup.y,shape->shapenum,shape->shapetype);
|
|
InfoAreaSetup.framecount = 3;
|
|
InfoAreaSetup.left_margin = InfoAreaSetup.x;
|
|
break;
|
|
|
|
// DRAW SHAPE -------------------------------------------------------
|
|
//
|
|
case TP_CNVT_CODE('S','H'):
|
|
|
|
// NOTE : This needs to handle the left margin....
|
|
|
|
shapenum = TP_VALUE(first_ch,3);
|
|
first_ch += 3;
|
|
shape = &piShapeTable[shapenum];
|
|
// spr = &spritetable[shape->shapenum-STARTSPRITES];
|
|
|
|
DrawShape(InfoAreaSetup.x,InfoAreaSetup.y,shape->shapenum,shape->shapetype);
|
|
InfoAreaSetup.left_margin = InfoAreaSetup.x;
|
|
break;
|
|
|
|
// FONT COLOR -------------------------------------------------------
|
|
//
|
|
case TP_CNVT_CODE('F','C'):
|
|
InfoAreaSetup.text_color = fontcolor = TP_VALUE(first_ch,2);
|
|
first_ch += 2;
|
|
break;
|
|
|
|
// BACKGROUND COLOR -------------------------------------------------
|
|
//
|
|
case TP_CNVT_CODE('B','G'):
|
|
InfoAreaSetup.backgr_color = TP_VALUE(first_ch,2);
|
|
first_ch += 2;
|
|
break;
|
|
|
|
// DEFAULT MARGINS -------------------------------------------------
|
|
//
|
|
case TP_CNVT_CODE('D','M'):
|
|
InfoAreaSetup.left_margin = INFOAREA_X;
|
|
break;
|
|
|
|
// LEFT MARGIN ------------------------------------------------------
|
|
//
|
|
case TP_CNVT_CODE('L','M'):
|
|
shapenum = TP_VALUE(first_ch,3);
|
|
first_ch += 3;
|
|
if (shapenum == 0xfff)
|
|
InfoAreaSetup.left_margin = InfoAreaSetup.x;
|
|
else
|
|
InfoAreaSetup.left_margin = shapenum;
|
|
break;
|
|
|
|
#ifdef UNLOCK_FLOORS
|
|
// UNLOCK FLOOR ----------------------------------------------------
|
|
//
|
|
case TP_CNVT_CODE('U','F'):
|
|
shapenum = TP_VALUE(first_ch++,1);
|
|
gamestuff.level[shapenum].locked=false;
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
return(first_ch);
|
|
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// DrawShape()
|
|
//--------------------------------------------------------------------------
|
|
short DrawShape(short x, short y, short shapenum, pisType shapetype)
|
|
{
|
|
short width;
|
|
unsigned i,old_ofs,shade;
|
|
|
|
// width=TP_BoxAroundShape(x,y,shapenum,shapetype);
|
|
|
|
//
|
|
// If Image is Cloaked... Shade the image
|
|
//
|
|
if (LastInfoAttacker_Cloaked)
|
|
shade = 35; // 63 == BLACK | 0 == NO SHADING
|
|
else
|
|
shade = 0;
|
|
|
|
switch (shapetype)
|
|
{
|
|
case pis_scaled:
|
|
// old_ofs = bufferofs;
|
|
// for (i=0;i<3;i++)
|
|
// {
|
|
// bufferofs = screenloc[i];
|
|
// VWB_Bar(x,y,37,37,InfoAreaSetup.backgr_color);
|
|
VW_Bar(x,y,37,37,InfoAreaSetup.backgr_color); // JTR changed
|
|
MegaSimpleScaleShape(x+19,y+20,shapenum,37,shade);
|
|
// }
|
|
// bufferofs = old_ofs;
|
|
width = 37;
|
|
break;
|
|
|
|
#if NUMPICS
|
|
case pis_latchpic:
|
|
x = (x+7) & 0xFFF8;
|
|
// old_ofs = bufferofs;
|
|
// for (i=0;i<3;i++)
|
|
// {
|
|
// bufferofs = screenloc[i];
|
|
JLatchDrawPic(x>>3,y,shapenum);
|
|
// }
|
|
// bufferofs = old_ofs;
|
|
break;
|
|
|
|
case pis_pic:
|
|
x = (x+7) & 0xFFF8;
|
|
width = pictable[shapenum-STARTPICS].width;
|
|
CA_MarkGrChunk(shapenum);
|
|
CA_CacheMarks();
|
|
// old_ofs = bufferofs;
|
|
// for (i=0;i<3;i++)
|
|
// {
|
|
// bufferofs = screenloc[i];
|
|
VWB_DrawPic(x,y,shapenum);
|
|
// }
|
|
// bufferofs = old_ofs;
|
|
UNCACHEGRCHUNK(shapenum);
|
|
break;
|
|
#endif
|
|
|
|
#if NUMSPRITES && 0
|
|
case pis_sprite:
|
|
// VW_geDrawSprite(x,y-(spr->orgy>>G_P_SHIFT),shapenum,shapetype == pis_sprite2x);
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
InfoAreaSetup.x += width;
|
|
return(x);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// AnimatePage()
|
|
//--------------------------------------------------------------------------
|
|
void AnimatePage(void)
|
|
{
|
|
piAnimInfo far *anim=piAnimList;
|
|
piShapeInfo far *shape;
|
|
|
|
// Dec Timers
|
|
//
|
|
|
|
anim->delay += tics;
|
|
|
|
if (anim->delay >= anim->maxdelay)
|
|
{
|
|
InfoAreaSetup.framecount = 3;
|
|
anim->delay = 0;
|
|
}
|
|
|
|
// Test framecount - Do we need to draw a shape?
|
|
//
|
|
|
|
if (InfoAreaSetup.framecount)
|
|
{
|
|
// Draw shapes
|
|
|
|
switch (anim->animtype)
|
|
{
|
|
case pia_shapetable:
|
|
shape = &piShapeTable[anim->baseshape+anim->frame];
|
|
DrawShape(anim->x,anim->y,shape->shapenum,shape->shapetype);
|
|
break;
|
|
|
|
case pia_grabscript:
|
|
shape = &piShapeTable[anim->baseshape];
|
|
DrawShape(anim->x,anim->y,shape->shapenum+anim->frame,shape->shapetype);
|
|
break;
|
|
}
|
|
|
|
// Dec frame count
|
|
|
|
InfoAreaSetup.framecount--;
|
|
if (!InfoAreaSetup.framecount)
|
|
{
|
|
// Have drawn all pages... Inc Frame count
|
|
|
|
anim->frame++;
|
|
if (anim->frame == anim->maxframes)
|
|
anim->frame = 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
//--------------------------------------------------------------------------
|
|
// AnimatePage()
|
|
//--------------------------------------------------------------------------
|
|
void AnimatePage(short numanims)
|
|
{
|
|
piAnimInfo far *anim=piAnimList;
|
|
piShapeInfo far *shape;
|
|
|
|
anim->delay += tics;
|
|
|
|
if (anim->delay >= anim->maxdelay)
|
|
{
|
|
anim->delay = 0;
|
|
anim->frame++;
|
|
|
|
if (anim->frame == anim->maxframes)
|
|
anim->frame = 0;
|
|
|
|
switch (anim->animtype)
|
|
{
|
|
case pia_shapetable:
|
|
shape = &piShapeTable[anim->baseshape+anim->frame];
|
|
DrawShape(anim->x,anim->y,shape->shapenum,shape->shapetype);
|
|
break;
|
|
|
|
case pia_grabscript:
|
|
shape = &piShapeTable[anim->baseshape];
|
|
DrawShape(anim->x,anim->y,shape->shapenum+anim->frame,shape->shapetype);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
//===========================================================================
|
|
//
|
|
//
|
|
// STATUS BAR REFRESH ROUTINES
|
|
//
|
|
//
|
|
//===========================================================================
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// UpdateStatusBar()
|
|
//---------------------------------------------------------------------------
|
|
void UpdateStatusBar(void)
|
|
{
|
|
if (playstate == ex_title || playstate == ex_victorious)
|
|
return;
|
|
|
|
#ifdef NO_STATUS_BAR
|
|
return;
|
|
#endif
|
|
|
|
|
|
//
|
|
// Call specific status bar managers
|
|
//
|
|
|
|
UpdateScore();
|
|
UpdateInfoArea();
|
|
|
|
//
|
|
// Refresh Status Area
|
|
//
|
|
|
|
if (DrawAmmoPic_COUNT)
|
|
DrawAmmoPic();
|
|
|
|
// if (DrawScoreNum_COUNT)
|
|
DrawScoreNum();
|
|
|
|
if (DrawWeaponPic_COUNT)
|
|
DrawWeaponPic();
|
|
|
|
if (DrawRadarGuage_COUNT)
|
|
DrawRadarGuage();
|
|
|
|
// if (DrawAmmoNum_COUNT)
|
|
DrawAmmoNum();
|
|
|
|
if (DrawKeyPics_COUNT)
|
|
DrawKeyPics();
|
|
|
|
if (DrawHealthNum_COUNT)
|
|
DrawHealthNum();
|
|
|
|
if (gamestate.flags & (GS_TICS_FOR_SCORE))
|
|
DrawScore();
|
|
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// ForceUpdateStatusBar() - Force Draw status bar onto ALL display pages
|
|
//---------------------------------------------------------------------------
|
|
void ForceUpdateStatusBar(void)
|
|
{
|
|
unsigned old_ofs,i;
|
|
|
|
old_ofs = bufferofs;
|
|
|
|
DrawScore();
|
|
DrawWeapon();
|
|
DrawKeys();
|
|
DrawHealth();
|
|
UpdateRadarGuage();
|
|
|
|
for (i=0;i<3;i++)
|
|
{
|
|
bufferofs = screenloc[i];
|
|
UpdateStatusBar();
|
|
}
|
|
|
|
bufferofs = old_ofs;
|
|
}
|
|
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
MOVEMENT
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
===================
|
|
=
|
|
= GetBonus
|
|
=
|
|
===================
|
|
*/
|
|
|
|
unsigned far static_points[]={ 100, // money bag
|
|
500, // loot
|
|
250, // gold1
|
|
500, // gold2
|
|
750, // gold3
|
|
1000, // major gold!
|
|
5000 // bonus
|
|
};
|
|
|
|
unsigned far static_health[][3] =
|
|
{
|
|
{100,HEALTH2SND,-1}, // Full Heal
|
|
{ 30,HEALTH1SND,-1}, // First Aid
|
|
{ 20,HEALTH1SND,SPR_STAT_45}, // Steak
|
|
{ 15,HEALTH1SND,SPR_STAT_43}, // Chicken Leg
|
|
{ 10,HEALTH1SND,SPR_SANDWICH_WRAPER}, // Sandwich
|
|
{ 8,HEALTH1SND,SPR_CANDY_WRAPER}, // Candy Bar
|
|
{ 5,HEALTH1SND,SPR_STAT_41}, // Water bowl
|
|
{ 5,HEALTH1SND,-1}, // Water puddle
|
|
};
|
|
|
|
extern char far bonus_msg24[];
|
|
extern char far bonus_msg25[];
|
|
|
|
void GetBonus (statobj_t *check)
|
|
{
|
|
boolean givepoints=false;
|
|
short shapenum = -1,possible;
|
|
|
|
switch (check->itemnumber)
|
|
{
|
|
case bo_red_key:
|
|
case bo_yellow_key:
|
|
case bo_blue_key:
|
|
{
|
|
unsigned keynum = check->itemnumber - bo_red_key;
|
|
|
|
if (gamestate.numkeys[keynum] >= MAXKEYS)
|
|
return;
|
|
|
|
GiveKey(keynum);
|
|
SD_PlaySound(GETKEYSND);
|
|
TravelTable[check->tilex][check->tiley] &= ~TT_KEYS;
|
|
break;
|
|
}
|
|
|
|
case bo_money_bag:
|
|
SD_PlaySound (BONUS1SND);
|
|
givepoints=true;
|
|
break;
|
|
|
|
case bo_loot:
|
|
SD_PlaySound (BONUS2SND);
|
|
givepoints=true;
|
|
break;
|
|
|
|
|
|
case bo_gold1:
|
|
case bo_gold2:
|
|
case bo_gold3:
|
|
case bo_gold:
|
|
SD_PlaySound (BONUS3SND);
|
|
givepoints=true;
|
|
break;
|
|
|
|
|
|
case bo_bonus:
|
|
SD_PlaySound (BONUS4SND);
|
|
givepoints=true;
|
|
break;
|
|
|
|
case bo_water_puddle:
|
|
if (gamestate.health > 15)
|
|
return;
|
|
case bo_fullheal:
|
|
case bo_firstaid:
|
|
case bo_ham: // STEAK
|
|
case bo_chicken:
|
|
case bo_sandwich:
|
|
case bo_candybar:
|
|
case bo_water:
|
|
if (gamestate.health == 100)
|
|
return;
|
|
SD_PlaySound (static_health[check->itemnumber-bo_fullheal][1]);
|
|
HealSelf (static_health[check->itemnumber-bo_fullheal][0]);
|
|
check->flags &= ~FL_BONUS;
|
|
shapenum = static_health[check->itemnumber-bo_fullheal][2];
|
|
break;
|
|
|
|
case bo_clip:
|
|
if (gamestate.ammo == MAX_AMMO)
|
|
return;
|
|
GiveAmmo (8);
|
|
bonus_msg7[45] = '8';
|
|
break;
|
|
|
|
case bo_clip2:
|
|
{
|
|
unsigned char ammo;
|
|
|
|
if (gamestate.ammo == MAX_AMMO)
|
|
return;
|
|
|
|
ammo = 1+(US_RndT() & 0x7);
|
|
bonus_msg7[45] = '0'+ammo;
|
|
GiveAmmo (ammo);
|
|
}
|
|
break;
|
|
|
|
case bo_plasma_detonator:
|
|
TravelTable[check->tilex][check->tiley] &= ~TT_KEYS;
|
|
GivePlasmaDetonator(1);
|
|
SD_PlaySound (GETDETONATORSND);
|
|
break;
|
|
|
|
case bo_pistol:
|
|
SD_PlaySound (GETPISTOLSND);
|
|
GiveWeapon(wp_pistol);
|
|
break;
|
|
|
|
case bo_burst_rifle:
|
|
SD_PlaySound (GETBURSTRIFLESND);
|
|
GiveWeapon (wp_burst_rifle);
|
|
break;
|
|
|
|
case bo_ion_cannon:
|
|
SD_PlaySound (GETIONCANNONSND);
|
|
GiveWeapon (wp_ion_cannon);
|
|
break;
|
|
|
|
case bo_grenade:
|
|
SD_PlaySound (GETCANNONSND);
|
|
GiveWeapon (wp_grenade);
|
|
break;
|
|
|
|
|
|
case bo_bfg_cannon:
|
|
SD_PlaySound (GETCANNONSND);
|
|
GiveWeapon (wp_bfg_cannon);
|
|
break;
|
|
|
|
|
|
case bo_coin:
|
|
if (gamestate.tokens == MAX_TOKENS)
|
|
return;
|
|
GiveToken(1);
|
|
|
|
writeTokenStr(bonus_msg24);
|
|
break;
|
|
|
|
case bo_coin5:
|
|
if (gamestate.tokens == MAX_TOKENS)
|
|
return;
|
|
GiveToken(5);
|
|
|
|
writeTokenStr(bonus_msg25);
|
|
break;
|
|
|
|
case bo_automapper1:
|
|
if (gamestate.rpower > MAX_RADAR_ENERGY-(RADAR_PAK_VALUE/8))
|
|
return;
|
|
gamestate.rpower += RADAR_PAK_VALUE;
|
|
SD_PlaySound(RADAR_POWERUPSND);
|
|
UpdateRadarGuage();
|
|
break;
|
|
}
|
|
|
|
if (givepoints)
|
|
{
|
|
GivePoints(static_points[check->itemnumber-bo_money_bag],true);
|
|
#if IN_DEVELOPMENT
|
|
#ifdef DEBUG_STATICS
|
|
debug_bonus[1][db_count++] = static_points[check->itemnumber-bo_money_bag];
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
DISPLAY_TIMED_MSG(BonusMsg[check->itemnumber-1],MP_BONUS,MT_BONUS);
|
|
StartBonusFlash ();
|
|
check->shapenum = shapenum; // remove from list if shapenum == -1
|
|
check->itemnumber = bo_nothing;
|
|
}
|
|
|
|
void writeTokenStr(char far *str)
|
|
{
|
|
char buffer[3],len;
|
|
|
|
len = _fstrlen(str);
|
|
if (gamestate.tokens > 9)
|
|
itoa(gamestate.tokens,buffer,10);
|
|
else
|
|
{
|
|
buffer[0]='0';
|
|
itoa(gamestate.tokens,buffer+1,10);
|
|
}
|
|
|
|
_fstrcpy(str+len-2,buffer);
|
|
}
|
|
|
|
|
|
/*
|
|
===================
|
|
=
|
|
= TryMove
|
|
=
|
|
= returns true if move ok
|
|
= debug: use pointers to optimize
|
|
===================
|
|
*/
|
|
|
|
|
|
boolean TryMove (objtype *ob)
|
|
{
|
|
int xl,yl,xh,yh,x,y,xx,yy;
|
|
objtype *check;
|
|
long deltax,deltay;
|
|
|
|
if (ob==player)
|
|
{
|
|
xl = (ob->x-PLAYERSIZE) >>TILESHIFT;
|
|
yl = (ob->y-PLAYERSIZE) >>TILESHIFT;
|
|
xh = (ob->x+PLAYERSIZE) >>TILESHIFT;
|
|
yh = (ob->y+PLAYERSIZE) >>TILESHIFT;
|
|
}
|
|
else
|
|
{
|
|
if (ob->obclass == blakeobj)
|
|
{
|
|
xl = (ob->x-(0x1000l)) >>TILESHIFT;
|
|
yl = (ob->y-(0x1000l)) >>TILESHIFT;
|
|
xh = (ob->x+(0x1000l)) >>TILESHIFT;
|
|
yh = (ob->y+(0x1000l)) >>TILESHIFT;
|
|
}
|
|
else
|
|
{
|
|
xl = (ob->x-(0x7FFFl)) >>TILESHIFT;
|
|
yl = (ob->y-(0x7FFFl)) >>TILESHIFT;
|
|
xh = (ob->x+(0x7FFFl)) >>TILESHIFT;
|
|
yh = (ob->y+(0x7FFFl)) >>TILESHIFT;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// check for solid walls
|
|
//
|
|
#pragma warn -pia
|
|
|
|
|
|
for (y=yl;y<=yh;y++)
|
|
for (x=xl;x<=xh;x++)
|
|
{
|
|
if (check = actorat[x][y])
|
|
if ((check < objlist) || (check->flags & FL_FAKE_STATIC))
|
|
return(false);
|
|
}
|
|
|
|
#pragma warn +pia
|
|
|
|
//
|
|
// check for actors....
|
|
//
|
|
|
|
yl-=2;
|
|
yh+=2;
|
|
xl-=2;
|
|
xh+=2;
|
|
|
|
// NOTE: xl,yl may go NEGITIVE!
|
|
// ---- xh,yh may exceed 63 (MAPWIDTH-1)
|
|
|
|
for (y=yl;y<=yh;y++)
|
|
for (x=xl;x<=xh;x++)
|
|
{
|
|
xx = x & 0x3f;
|
|
|
|
yy = y & 0x3f;
|
|
|
|
check = actorat[xx][yy];
|
|
|
|
if ((check > objlist) && ((check->flags & (FL_SOLID|FL_FAKE_STATIC)) == FL_SOLID))
|
|
{
|
|
deltax = ob->x - check->x;
|
|
if ((deltax < -MINACTORDIST) || (deltax > MINACTORDIST))
|
|
continue;
|
|
|
|
deltay = ob->y - check->y;
|
|
if ((deltay < -MINACTORDIST) || (deltay > MINACTORDIST))
|
|
continue;
|
|
|
|
return(false);
|
|
}
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
|
|
/*
|
|
===================
|
|
=
|
|
= ClipMove
|
|
=
|
|
= returns true if object hit a wall
|
|
=
|
|
===================
|
|
*/
|
|
|
|
boolean ClipMove (objtype *ob, long xmove, long ymove)
|
|
{
|
|
long basex,basey;
|
|
|
|
basex = ob->x;
|
|
basey = ob->y;
|
|
|
|
ob->x = (basex+xmove);
|
|
ob->y = (basey+ymove);
|
|
|
|
if (TryMove(ob))
|
|
return(false);
|
|
|
|
#if (!BETA_TEST) && IN_DEVELOPMENT
|
|
if ((!(gamestate.flags & GS_CLIP_WALLS)) && (ob == player))
|
|
return(true);
|
|
#endif
|
|
|
|
if (!SD_SoundPlaying())
|
|
SD_PlaySound (HITWALLSND);
|
|
|
|
ob->x = (basex+xmove);
|
|
ob->y = basey;
|
|
|
|
if (TryMove (ob))
|
|
return(true);
|
|
|
|
ob->x = basex;
|
|
ob->y = (basey+ymove);
|
|
|
|
|
|
if (TryMove (ob))
|
|
return(true);
|
|
|
|
ob->x = basex;
|
|
ob->y = basey;
|
|
|
|
return(true);
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
/*
|
|
===================
|
|
=
|
|
= Thrust
|
|
=
|
|
===================
|
|
*/
|
|
|
|
void Thrust (int angle, long speed)
|
|
{
|
|
extern byte far TravelTable[MAPSIZE][MAPSIZE];
|
|
objtype dumb;
|
|
long xmove,ymove;
|
|
long slowmax;
|
|
unsigned offset, far *map[2];
|
|
short dx,dy;
|
|
int dangle;
|
|
boolean ignore_map1;
|
|
|
|
thrustspeed += speed;
|
|
//
|
|
// moving bounds speed
|
|
//
|
|
if (speed >= MINDIST*2)
|
|
speed = MINDIST*2-1;
|
|
|
|
xmove = FixedByFrac(speed,costable[angle]);
|
|
ymove = -FixedByFrac(speed,sintable[angle]);
|
|
|
|
ClipMove(player,xmove,ymove);
|
|
|
|
player_oldtilex = player->tilex;
|
|
player_oldtiley = player->tiley;
|
|
player->tilex = player->x >> TILESHIFT; // scale to tile values
|
|
player->tiley = player->y >> TILESHIFT;
|
|
|
|
player->areanumber=GetAreaNumber(player->tilex,player->tiley);
|
|
areabyplayer[player->areanumber] = true;
|
|
TravelTable[player->tilex][player->tiley] |= TT_TRAVELED;
|
|
|
|
offset = farmapylookup[player->tiley]+player->tilex;
|
|
map[0]=mapsegs[0]+offset;
|
|
map[1]=mapsegs[1]+offset;
|
|
|
|
// Check for trigger tiles.
|
|
//
|
|
switch (*map[0])
|
|
{
|
|
case DOORTRIGGERTILE:
|
|
dx = *map[1]>>8; // x
|
|
dy = *map[1]&255; // y
|
|
if (OperateSmartSwitch(dx,dy,ST_TOGGLE,false)) // Operate & Check for removeal
|
|
*map[0] = AREATILE+player->areanumber; // Remove switch
|
|
ignore_map1 = true;
|
|
break;
|
|
|
|
case SMART_OFF_TRIGGER:
|
|
case SMART_ON_TRIGGER:
|
|
dx = *map[1]>>8;
|
|
dy = *map[1]&255;
|
|
OperateSmartSwitch(dx,dy,(*map[0])-SMART_OFF_TRIGGER,false);
|
|
ignore_map1 = true;
|
|
break;
|
|
|
|
case WINTIGGERTILE:
|
|
playstate = ex_victorious;
|
|
dumb.x = ((long)gamestate.wintilex<<TILESHIFT)+TILEGLOBAL/2;
|
|
dumb.y = ((long)gamestate.wintiley<<TILESHIFT)+TILEGLOBAL/2;
|
|
dumb.flags = 0;
|
|
dangle=CalcAngle(player,&dumb);
|
|
RotateView(dangle,2);
|
|
ignore_map1 = true;
|
|
break;
|
|
|
|
default:
|
|
ignore_map1 = false;
|
|
break;
|
|
}
|
|
|
|
if (!ignore_map1)
|
|
{
|
|
// Change sky and ground color on-the-fly.
|
|
//
|
|
|
|
offset=*(map[1]+1); // 'offset' used as temp...
|
|
switch (*map[1])
|
|
{
|
|
#ifdef CEILING_FLOOR_COLORS
|
|
case 0xfe00:
|
|
TopColor = offset&0xff00;
|
|
TopColor |= TopColor>>8;
|
|
BottomColor = offset&0xff;
|
|
BottomColor |= BottomColor<<8;
|
|
break;
|
|
#else
|
|
#if IN_DEVELOPMENT
|
|
case 0xfe00:
|
|
// Give error
|
|
break;
|
|
#endif
|
|
#endif
|
|
|
|
#if 0
|
|
case 0xF600: // Lighting effects
|
|
normalshade_div = (offset&0xff00) >> 8;
|
|
if (normalshade_div > 12)
|
|
AGENT_ERROR(NORMAL_SHADE_TOO_BIG);
|
|
shade_max = offset&0xff;
|
|
if (shade_max > 63 || shade_max < 5)
|
|
AGENT_ERROR(SHADEMAX_VALUE_BAD);
|
|
normalshade=(3*(maxscale>>2))/normalshade_div;
|
|
break;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
extern short an_offset[];
|
|
|
|
#pragma warn -pia
|
|
|
|
boolean GAN_HiddenArea;
|
|
|
|
//------------------------------------------------------------------------
|
|
// GetAreaNumber()
|
|
//------------------------------------------------------------------------
|
|
char GetAreaNumber(char tilex, char tiley)
|
|
{
|
|
unsigned offset, far *map, far *ptr[2], loop;
|
|
byte areanumber;
|
|
|
|
GAN_HiddenArea = false;
|
|
|
|
// Are we on a wall?
|
|
//
|
|
if (tilemap[tilex][tiley] && (!(tilemap[tilex][tiley]&0xc0)))
|
|
return(127);
|
|
|
|
// Get initial areanumber from map
|
|
//
|
|
offset = farmapylookup[tiley]+tilex;
|
|
ptr[0]=mapsegs[0]+offset;
|
|
ptr[1]=mapsegs[1]+offset;
|
|
|
|
// Special tile areas must use a valid areanumber tile around it.
|
|
//
|
|
if (!(areanumber=ValidAreaTile(ptr[0])))
|
|
{
|
|
for (loop=0; loop<8; loop++)
|
|
if (areanumber=ValidAreaTile(ptr[0]+an_offset[loop]))
|
|
break;
|
|
|
|
if (loop==8)
|
|
areanumber = AREATILE;
|
|
}
|
|
|
|
// Merge hidden areanumbers into non-hidden areanumbers AND pull all
|
|
// values down to an indexable range.
|
|
//
|
|
if (areanumber >= HIDDENAREATILE)
|
|
{
|
|
GAN_HiddenArea = true;
|
|
areanumber -= HIDDENAREATILE;
|
|
}
|
|
else
|
|
areanumber -= AREATILE;
|
|
|
|
return(areanumber);
|
|
}
|
|
|
|
#pragma warn +pia
|
|
|
|
#pragma warn -rch
|
|
#pragma warn -rvl
|
|
|
|
//------------------------------------------------------------------------
|
|
// ValidAreaTile()
|
|
//------------------------------------------------------------------------
|
|
byte ValidAreaTile(unsigned far *ptr)
|
|
{
|
|
switch (*ptr)
|
|
{
|
|
case AREATILE:
|
|
case HIDDENAREATILE:
|
|
case DOORTRIGGERTILE:
|
|
case WINTIGGERTILE:
|
|
case SMART_ON_TRIGGER:
|
|
case SMART_OFF_TRIGGER:
|
|
case AMBUSHTILE:
|
|
case LINC_TILE:
|
|
case CLOAK_AMBUSH_TILE:
|
|
break;
|
|
|
|
default:
|
|
if (*ptr > AREATILE)
|
|
return(*ptr);
|
|
break;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
#pragma warn +rch
|
|
#pragma warn +rvl
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
ACTIONS
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
|
|
/*
|
|
===============
|
|
=
|
|
= Cmd_Fire
|
|
=
|
|
===============
|
|
*/
|
|
|
|
void Cmd_Fire (void)
|
|
{
|
|
if (noShots)
|
|
return;
|
|
|
|
if ((gamestate.weapon == wp_autocharge) && (gamestate.weapon_wait))
|
|
return;
|
|
|
|
buttonheld[bt_attack] = true;
|
|
|
|
gamestate.weaponframe = 0;
|
|
|
|
player->state = &s_attack;
|
|
|
|
gamestate.attackframe = 0;
|
|
gamestate.attackcount = attackinfo[gamestate.weapon][gamestate.attackframe].tics;
|
|
gamestate.weaponframe = attackinfo[gamestate.weapon][gamestate.attackframe].frame;
|
|
}
|
|
|
|
//===========================================================================
|
|
|
|
|
|
void Cmd_Use (void)
|
|
{
|
|
objtype *check;
|
|
int checkx,checky,doornum,dir;
|
|
unsigned iconnum;
|
|
unsigned offset,new_level;
|
|
unsigned char static interrogate_delay=0;
|
|
boolean tryDetonator = false;
|
|
|
|
// Find which cardinal direction the player is facing
|
|
//
|
|
if (player->angle < ANGLES/8 || player->angle > 7*ANGLES/8)
|
|
{
|
|
checkx = player->tilex + 1;
|
|
checky = player->tiley;
|
|
dir = di_east;
|
|
}
|
|
else if (player->angle < 3*ANGLES/8)
|
|
{
|
|
checkx = player->tilex;
|
|
checky = player->tiley-1;
|
|
dir = di_north;
|
|
}
|
|
else if (player->angle < 5*ANGLES/8)
|
|
{
|
|
checkx = player->tilex - 1;
|
|
checky = player->tiley;
|
|
dir = di_west;
|
|
}
|
|
else
|
|
{
|
|
checkx = player->tilex;
|
|
checky = player->tiley + 1;
|
|
dir = di_south;
|
|
}
|
|
|
|
doornum = tilemap[checkx][checky];
|
|
iconnum = *(mapsegs[1]+farmapylookup[checky]+checkx);
|
|
|
|
// Test for a pushable wall
|
|
//
|
|
if (iconnum == PUSHABLETILE)
|
|
{
|
|
PushWall (checkx,checky,dir);
|
|
}
|
|
else
|
|
if (!buttonheld[bt_use])
|
|
{
|
|
// Test for doors / elevator
|
|
//
|
|
if ((doornum & 0x80) && ((pwallx != checkx) || (pwally != checky)))
|
|
{
|
|
buttonheld[bt_use] = true;
|
|
OperateDoor(doornum & ~0x80);
|
|
}
|
|
else
|
|
// Test for special tile types...
|
|
//
|
|
switch (doornum & 63)
|
|
{
|
|
// Test for 'display elevator buttons'
|
|
//
|
|
case TRANSPORTERTILE:
|
|
{
|
|
short new_floor;
|
|
|
|
if ((new_floor=InputFloor()) != -1 && new_floor != gamestate.mapon)
|
|
{
|
|
int angle = player->angle;
|
|
|
|
gamestuff.level[gamestate.mapon].ptilex = player->tilex;
|
|
gamestuff.level[gamestate.mapon].ptiley = player->tiley;
|
|
angle = player->angle - 180;
|
|
if (angle < 0)
|
|
angle += ANGLES;
|
|
gamestuff.level[gamestate.mapon].pangle = angle;
|
|
|
|
playstate=ex_transported;
|
|
gamestate.lastmapon=gamestate.mapon;
|
|
gamestate.mapon=new_floor-1;
|
|
}
|
|
else
|
|
DrawPlayScreen(false);
|
|
}
|
|
break;
|
|
|
|
case DIRECTTRANSPORTTILE:
|
|
switch (iconnum & 0xff00)
|
|
{
|
|
case 0xf400:
|
|
playstate = ex_transported;
|
|
gamestate.lastmapon=gamestate.mapon;
|
|
gamestate.mapon=(iconnum & 0xff)-1;
|
|
break;
|
|
|
|
default:
|
|
// Stay in current level warp to new location
|
|
|
|
playstate = ex_transported;
|
|
Warped();
|
|
playstate = ex_stillplaying;
|
|
|
|
player->tilex = (iconnum >> 8);
|
|
player->tiley = iconnum & 0xff;
|
|
player->x = ((long)player->tilex<<TILESHIFT)+TILEGLOBAL/2;
|
|
player->y = ((long)player->tiley<<TILESHIFT)+TILEGLOBAL/2;
|
|
|
|
DrawWarpIn();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Test for Wall Switch Activation
|
|
//
|
|
case OFF_SWITCH:
|
|
case ON_SWITCH:
|
|
ActivateWallSwitch(iconnum,checkx,checky);
|
|
break;
|
|
|
|
|
|
// Test for Concession Machines
|
|
//
|
|
|
|
case FOODTILE:
|
|
case SODATILE:
|
|
OperateConcession((int)actorat[checkx][checky]);
|
|
break;
|
|
|
|
default:
|
|
tryDetonator = true;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
if (!interrogate_delay)
|
|
{
|
|
#define INTERROGATEDIST (MINACTORDIST)
|
|
#define MDIST 2
|
|
#define INTG_ANGLE 45
|
|
|
|
char x,y;
|
|
objtype *intg_ob=NULL,*ob;
|
|
long dx,dy,dist,intg_dist=INTERROGATEDIST+1;
|
|
|
|
for (y=-MDIST;y<MDIST+1;y++)
|
|
for (x=-MDIST;x<MDIST+1;x++)
|
|
{
|
|
if ((!tilemap[player->tilex+x][player->tiley+y]) &&
|
|
(actorat[player->tilex+x][player->tiley+y] >= objlist))
|
|
ob = actorat[player->tilex+x][player->tiley+y];
|
|
else
|
|
continue;
|
|
dx = player->x - ob->x;
|
|
dx = LABS(dx);
|
|
dy = player->y - ob->y;
|
|
dy = LABS(dy);
|
|
dist = dx<dy ? dx:dy;
|
|
if ((ob->obclass==gen_scientistobj) &&
|
|
((ob->flags&(FL_FRIENDLY|FL_VISABLE))==(FL_FRIENDLY|FL_VISABLE)) &&
|
|
(dist < intg_dist))
|
|
{
|
|
short angle=CalcAngle(player,ob);
|
|
|
|
angle = ABS(player->angle-angle);
|
|
if (angle > INTG_ANGLE/2)
|
|
continue;
|
|
|
|
intg_ob=ob;
|
|
intg_dist=dist;
|
|
}
|
|
}
|
|
|
|
if (intg_ob)
|
|
{
|
|
if (Interrogate(intg_ob))
|
|
interrogate_delay=20; // Informants have 1/3 sec delay
|
|
else
|
|
interrogate_delay=120; // Non-informants have 2 sec delay
|
|
}
|
|
else
|
|
tryDetonator = true;
|
|
}
|
|
else
|
|
{
|
|
if (tics < interrogate_delay)
|
|
interrogate_delay-=tics;
|
|
else
|
|
interrogate_delay=0;
|
|
|
|
tryDetonator = true;
|
|
}
|
|
|
|
if (tryDetonator)
|
|
{
|
|
if ((!tryDetonatorDelay) && gamestate.plasma_detonators)
|
|
{
|
|
TryDropPlasmaDetonator();
|
|
tryDetonatorDelay = 60;
|
|
}
|
|
}
|
|
else
|
|
tryDetonatorDelay = 60;
|
|
|
|
if (!buttonheld[bt_use])
|
|
interrogate_delay=0;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// INTERROGATE CODE
|
|
//
|
|
//==========================================================================
|
|
|
|
#define MSG_BUFFER_LEN 150
|
|
|
|
char far msg[MSG_BUFFER_LEN+1];
|
|
|
|
memptr InfAreaMsgs[MAX_INF_AREA_MSGS];
|
|
byte NumAreaMsgs,LastInfArea;
|
|
short FirstGenInfMsg,TotalGenInfMsgs;
|
|
|
|
scientist_t InfHintList; // Informant messages
|
|
scientist_t NiceSciList; // Non-informant, non-pissed messages
|
|
scientist_t MeanSciList; // Non-informant, pissed messages
|
|
|
|
char far int_interrogate[]="INTERROGATE:",
|
|
far int_informant[]=" ^FC3aINFORMANT^FCa6",
|
|
far int_rr[]="\r\r",
|
|
far int_xx[]="^XX",
|
|
far int_haveammo[]=" HEY BLAKE,\r TAKE MY CHARGE PACK!",
|
|
far int_havetoken[]=" HEY BLAKE,\r TAKE MY FOOD TOKENS!";
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Interrogate()
|
|
//--------------------------------------------------------------------------
|
|
boolean Interrogate(objtype *ob)
|
|
{
|
|
boolean rt_value=true;
|
|
char far *msgptr=NULL;
|
|
|
|
_fstrcpy(msg,int_interrogate);
|
|
|
|
if (ob->flags & FL_INFORMANT) // Informant
|
|
{
|
|
short msgnum;
|
|
|
|
_fstrcat(msg,int_informant);
|
|
|
|
if (ob->flags & FL_INTERROGATED)
|
|
{
|
|
if ((ob->flags & FL_HAS_AMMO) && (gamestate.ammo != MAX_AMMO))
|
|
{
|
|
GiveAmmo((US_RndT()%8)+1);
|
|
ob->flags &= ~FL_HAS_AMMO;
|
|
msgptr=int_haveammo;
|
|
}
|
|
else
|
|
if ((ob->flags & FL_HAS_TOKENS) && (gamestate.tokens != MAX_TOKENS))
|
|
{
|
|
GiveToken(5);
|
|
ob->flags &= ~FL_HAS_TOKENS;
|
|
msgptr=int_havetoken;
|
|
}
|
|
}
|
|
|
|
if (!msgptr)
|
|
{
|
|
// If new areanumber OR no 'area msgs' have been compiled, compile
|
|
// a list of all special messages for this areanumber.
|
|
//
|
|
if ((LastInfArea==0xff) || (LastInfArea!=ob->areanumber))
|
|
{
|
|
sci_mCacheInfo *ci = InfHintList.smInfo;
|
|
|
|
NumAreaMsgs=0;
|
|
for (;ci->areanumber != 0xff;ci++)
|
|
if (ci->areanumber == ob->areanumber)
|
|
InfAreaMsgs[NumAreaMsgs++]=InfHintList.smInfo[ci->mInfo.local_val].mInfo.mSeg;
|
|
|
|
LastInfArea=ob->areanumber;
|
|
}
|
|
|
|
// Randomly select an informant hint, either: specific to areanumber
|
|
// or general hint...
|
|
//
|
|
if (NumAreaMsgs)
|
|
{
|
|
if (ob->ammo != ob->areanumber)
|
|
ob->s_tilex = 0xff;
|
|
ob->ammo = ob->areanumber;
|
|
if (ob->s_tilex == 0xff)
|
|
ob->s_tilex=Random(NumAreaMsgs);
|
|
msgptr=InfAreaMsgs[ob->s_tilex];
|
|
}
|
|
else
|
|
{
|
|
if (ob->s_tiley == 0xff)
|
|
ob->s_tiley=FirstGenInfMsg+Random(TotalGenInfMsgs);
|
|
msgptr=InfHintList.smInfo[ob->s_tiley].mInfo.mSeg;
|
|
}
|
|
|
|
// Still no msgptr? This is a shared message! Use smInfo[local_val]
|
|
// for this message.
|
|
//
|
|
if (!msgptr)
|
|
msgptr=InfHintList.smInfo[InfHintList.smInfo[ob->s_tiley].mInfo.local_val].mInfo.mSeg;
|
|
|
|
ob->flags |= FL_INTERROGATED; // Scientist has been interrogated
|
|
}
|
|
}
|
|
else // Non-Informant
|
|
{
|
|
scientist_t *st;
|
|
|
|
rt_value=false;
|
|
if ((ob->flags & FL_MUST_ATTACK) || (US_RndT()&1)) // Mean
|
|
{
|
|
ob->flags &= ~FL_FRIENDLY; // Make him attack!
|
|
ob->flags |= FL_INTERROGATED; // " " "
|
|
st = &MeanSciList;
|
|
}
|
|
else // Nice
|
|
{
|
|
ob->flags |= FL_MUST_ATTACK; // Make him mean!
|
|
st = &NiceSciList;
|
|
}
|
|
|
|
msgptr=st->smInfo[Random(st->NumMsgs)].mInfo.mSeg;
|
|
}
|
|
|
|
if (msgptr)
|
|
{
|
|
_fstrcat(msg,int_rr);
|
|
_fstrcat(msg,msgptr);
|
|
_fstrcat(msg,int_xx);
|
|
if (_fstrlen(msg) > MSG_BUFFER_LEN)
|
|
AGENT_ERROR(INTERROGATE_LONG_MSG);
|
|
DisplayInfoMsg(msg,MP_INTERROGATE,DISPLAY_MSG_STD_TIME*2,MT_GENERAL);
|
|
SD_PlaySound(INTERROGATESND);
|
|
}
|
|
|
|
return(rt_value);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// ELEVATOR CODE
|
|
//
|
|
//==========================================================================
|
|
|
|
|
|
extern boolean pollMouseUsed;
|
|
|
|
char far if_help[]="UP/DN MOVES SELECTOR - ENTER ACTIVATES";
|
|
char far if_noImage[]=" AREA\n"
|
|
" UNMAPPED\n"
|
|
"\n"
|
|
"\n"
|
|
" PRESS ENTER\n"
|
|
" TO TELEPORT";
|
|
|
|
statsInfoType ov_stats;
|
|
memptr ov_buffer;
|
|
boolean ov_noImage=false;
|
|
|
|
#define TOV_X 16
|
|
#define TOV_Y 132
|
|
|
|
//--------------------------------------------------------------------------
|
|
// InputFloor
|
|
//--------------------------------------------------------------------------
|
|
short InputFloor(void)
|
|
{
|
|
#define RADAR_FLAGS OV_KEYS
|
|
#define MAX_TELEPORTS 20
|
|
#define MAX_MOVE_DELAY 10
|
|
|
|
short buttonPic,buttonY;
|
|
short rt_code=-2,tpNum=gamestate.mapon,lastTpNum=tpNum;
|
|
short teleX[MAX_TELEPORTS]={16,40,86,23,44,62,83,27,118,161,161,161,213,213,184,205,226,256,276,276};
|
|
short teleY[MAX_TELEPORTS]={13,26, 9,50,50,50,50,62, 42, 17, 26, 35, 41, 50, 62, 62, 62, 10, 10, 30};
|
|
char moveActive=0;
|
|
objtype old_player;
|
|
boolean locked=false,buttonsDrawn=false;
|
|
|
|
ClearMemory();
|
|
VW_FadeOut();
|
|
|
|
CacheDrawPic(0,0,TELEPORTBACKTOPPIC);
|
|
CacheDrawPic(0,12*8,TELEPORTBACKBOTPIC);
|
|
DisplayTeleportName(tpNum,locked);
|
|
CacheLump(TELEPORT_LUMP_START,TELEPORT_LUMP_END);
|
|
VWB_DrawMPic(teleX[tpNum],teleY[tpNum],TELEPORT1ONPIC+tpNum);
|
|
|
|
memcpy(&old_player,player,sizeof(objtype));
|
|
player->angle = 90;
|
|
player->x = player->y = ((long)32<<TILESHIFT)+(TILEGLOBAL/2);
|
|
|
|
MM_GetPtr(&ov_buffer,4096);
|
|
ShowStats(0,0,ss_justcalc,&gamestuff.level[gamestate.mapon].stats);
|
|
_fmemcpy(&ov_stats,&gamestuff.level[gamestate.mapon].stats,sizeof(statsInfoType));
|
|
ShowOverhead(TOV_X,TOV_Y,32,0,RADAR_FLAGS);
|
|
SaveOverheadChunk(tpNum);
|
|
|
|
px = 115;
|
|
py = 188;
|
|
fontcolor = 0xaf;
|
|
fontnumber = 2;
|
|
ShPrint(if_help,0,false);
|
|
|
|
controlx = controly = 0;
|
|
IN_ClearKeysDown();
|
|
while (rt_code == -2)
|
|
{
|
|
// Handle ABORT and ACCEPT
|
|
//
|
|
// if (!screenfaded)
|
|
// PollControls();
|
|
|
|
CalcTics();
|
|
if (Keyboard[sc_LeftArrow])
|
|
controlx = -1;
|
|
else
|
|
if (Keyboard[sc_RightArrow])
|
|
controlx = 1;
|
|
else
|
|
controlx = 0;
|
|
|
|
if (Keyboard[sc_UpArrow])
|
|
controly = -1;
|
|
else
|
|
if (Keyboard[sc_DownArrow])
|
|
controly = 1;
|
|
else
|
|
controly = 0;
|
|
|
|
if (Keyboard[sc_Escape] || buttonstate[bt_strafe])
|
|
{
|
|
rt_code=-1; // ABORT
|
|
|
|
LoadLocationText(gamestate.mapon+MAPS_PER_EPISODE*gamestate.episode);
|
|
break;
|
|
}
|
|
else
|
|
if (Keyboard[sc_Enter] || buttonstate[bt_attack])
|
|
{
|
|
if (locked)
|
|
{
|
|
if (!SD_SoundPlaying())
|
|
SD_PlaySound(NOWAYSND);
|
|
}
|
|
else
|
|
{
|
|
char loop;
|
|
|
|
rt_code=tpNum; // ACCEPT
|
|
|
|
// Flash selection
|
|
//
|
|
for (loop=0; loop<10; loop++)
|
|
{
|
|
VWB_DrawMPic(teleX[tpNum],teleY[tpNum],TELEPORT1OFFPIC+tpNum);
|
|
VW_UpdateScreen();
|
|
VW_WaitVBL(4);
|
|
|
|
VWB_DrawMPic(teleX[tpNum],teleY[tpNum],TELEPORT1ONPIC+tpNum);
|
|
VW_UpdateScreen();
|
|
VW_WaitVBL(4);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
CheckMusicToggle();
|
|
|
|
// Handle delay
|
|
//
|
|
if (moveActive)
|
|
{
|
|
moveActive -= tics;
|
|
if (moveActive<0)
|
|
moveActive=0;
|
|
}
|
|
|
|
// Move to NEXT / PREV teleport?
|
|
//
|
|
buttonY=0;
|
|
if (controlx>0 || controly>0)
|
|
{
|
|
if (!moveActive && tpNum<MAX_TELEPORTS-1)
|
|
{
|
|
tpNum++; // MOVE NEXT
|
|
moveActive=MAX_MOVE_DELAY;
|
|
}
|
|
|
|
buttonPic = TELEDNONPIC;
|
|
buttonY = 104;
|
|
}
|
|
else
|
|
if (controlx<0 || controly<0)
|
|
{
|
|
if (!moveActive && tpNum)
|
|
{
|
|
tpNum--; // MOVE PREV
|
|
moveActive=MAX_MOVE_DELAY;
|
|
}
|
|
|
|
buttonPic = TELEUPONPIC;
|
|
buttonY = 91;
|
|
}
|
|
|
|
// Light buttons?
|
|
//
|
|
if (buttonY)
|
|
{
|
|
VWB_DrawMPic(34,91,TELEUPOFFPIC);
|
|
VWB_DrawMPic(270,91,TELEUPOFFPIC);
|
|
VWB_DrawMPic(34,104,TELEDNOFFPIC);
|
|
VWB_DrawMPic(270,104,TELEDNOFFPIC);
|
|
|
|
VWB_DrawMPic(34,buttonY,buttonPic);
|
|
VWB_DrawMPic(270,buttonY,buttonPic);
|
|
buttonsDrawn=true;
|
|
}
|
|
else
|
|
// Unlight buttons?
|
|
//
|
|
if (buttonsDrawn)
|
|
{
|
|
VWB_DrawMPic(34,91,TELEUPOFFPIC);
|
|
VWB_DrawMPic(270,91,TELEUPOFFPIC);
|
|
VWB_DrawMPic(34,104,TELEDNOFFPIC);
|
|
VWB_DrawMPic(270,104,TELEDNOFFPIC);
|
|
buttonsDrawn=false;
|
|
}
|
|
|
|
// Change visual information
|
|
//
|
|
if (tpNum != lastTpNum)
|
|
{
|
|
locked = gamestuff.level[tpNum].locked;
|
|
DisplayTeleportName(tpNum,locked);
|
|
|
|
VWB_DrawMPic(teleX[lastTpNum],teleY[lastTpNum],TELEPORT1OFFPIC+lastTpNum);
|
|
VWB_DrawMPic(teleX[tpNum],teleY[tpNum],TELEPORT1ONPIC+tpNum);
|
|
|
|
LoadOverheadChunk(tpNum);
|
|
ShowOverheadChunk();
|
|
if (ov_noImage)
|
|
{
|
|
fontcolor = 0x57;
|
|
WindowX = WindowW = TOV_X;
|
|
WindowY = WindowH = TOV_Y;
|
|
WindowW += 63;
|
|
WindowH += 63;
|
|
PrintX = TOV_X+5;
|
|
PrintY = TOV_Y+13;
|
|
US_Print(if_noImage);
|
|
}
|
|
lastTpNum = tpNum;
|
|
}
|
|
|
|
if (locked)
|
|
{
|
|
ShowOverhead(TOV_X,TOV_Y,32,-1,RADAR_FLAGS);
|
|
VW_MarkUpdateBlock(TOV_X,TOV_Y,79,195);
|
|
}
|
|
|
|
CycleColors();
|
|
VW_UpdateScreen();
|
|
if (screenfaded)
|
|
{
|
|
VW_FadeIn();
|
|
ShowStats(235,138,ss_normal,&ov_stats);
|
|
IN_ClearKeysDown();
|
|
controlx = controly = 0;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
for (buttonY=63; buttonY>=0; buttonY -= 2)
|
|
{
|
|
char shps[]={TELEPORT1ONPIC,TELEPORT1OFFPIC};
|
|
|
|
if (rt_code != -1)
|
|
VWB_DrawMPic(teleX[tpNum],teleY[tpNum],shps[(buttonY&4)>>2]+tpNum);
|
|
|
|
if (locked)
|
|
{
|
|
ShowOverhead(TOV_X,TOV_Y,32,-locked,RADAR_FLAGS);
|
|
VW_MarkUpdateBlock(TOV_X,TOV_Y,79,195);
|
|
}
|
|
|
|
CycleColors();
|
|
VL_SetPaletteIntensity(0,255,&vgapal,buttonY);
|
|
VW_UpdateScreen();
|
|
}
|
|
#else
|
|
VW_FadeOut();
|
|
#endif
|
|
|
|
MM_FreePtr(&ov_buffer);
|
|
memcpy(player,&old_player,sizeof(objtype));
|
|
UnCacheLump(TELEPORT_LUMP_START,TELEPORT_LUMP_END);
|
|
|
|
PM_CheckMainMem();
|
|
DrawPlayScreen(false);
|
|
IN_ClearKeysDown();
|
|
|
|
return(rt_code);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// ShowOverheadChunk()
|
|
//--------------------------------------------------------------------------
|
|
void ShowOverheadChunk(void)
|
|
{
|
|
VL_MemToScreen(ov_buffer,64,64,TOV_X,TOV_Y);
|
|
VW_MarkUpdateBlock(TOV_X,TOV_Y,79,195);
|
|
ShowStats(235,138,ss_quick,&ov_stats);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// LoadOverheadChunk()
|
|
//--------------------------------------------------------------------------
|
|
void LoadOverheadChunk(short tpNum)
|
|
{
|
|
int handle;
|
|
long offset;
|
|
char chunk[5]="OVxx";
|
|
|
|
// Open PLAYTEMP file
|
|
//
|
|
MakeDestPath(PLAYTEMP_FILE);
|
|
if ((handle=open(tempPath,O_CREAT|O_RDWR|O_BINARY,S_IREAD|S_IWRITE))==-1)
|
|
MAIN_ERROR(SAVELEVEL_DISKERR);
|
|
|
|
// Find and load chunk
|
|
//
|
|
sprintf(&chunk[2],"%02x",tpNum);
|
|
if (FindChunk(handle,chunk))
|
|
{
|
|
ov_noImage=false;
|
|
IO_FarRead(handle,ov_buffer,4096);
|
|
IO_FarRead(handle,(char far *)&ov_stats,sizeof(statsInfoType));
|
|
}
|
|
else
|
|
{
|
|
ov_noImage=true;
|
|
_fmemset(ov_buffer,0x52,4096);
|
|
memset(&ov_stats,0,sizeof(statsInfoType));
|
|
}
|
|
|
|
// Close file
|
|
//
|
|
close(handle);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// SaveOverheadChunk()
|
|
//--------------------------------------------------------------------------
|
|
void SaveOverheadChunk(short tpNum)
|
|
{
|
|
int handle;
|
|
long cksize=4096+sizeof(statsInfoType);
|
|
char chunk[5]="OVxx";
|
|
|
|
// Open PLAYTEMP file
|
|
//
|
|
MakeDestPath(PLAYTEMP_FILE);
|
|
if ((handle=open(tempPath,O_CREAT|O_RDWR|O_BINARY,S_IREAD|S_IWRITE))==-1)
|
|
MAIN_ERROR(SAVELEVEL_DISKERR);
|
|
|
|
// Remove level chunk from file
|
|
//
|
|
sprintf(&chunk[2],"%02x",tpNum);
|
|
DeleteChunk(handle,chunk);
|
|
|
|
// Prepare buffer
|
|
//
|
|
VL_ScreenToMem(ov_buffer, 64, 64, TOV_X, TOV_Y);
|
|
|
|
// Write chunk ID, SIZE, and IMAGE
|
|
//
|
|
write(handle,chunk,4);
|
|
IO_FarWrite(handle,(char far *)&cksize,sizeof(cksize));
|
|
IO_FarWrite(handle,ov_buffer,4096);
|
|
IO_FarWrite(handle,(char far *)&ov_stats,sizeof(statsInfoType));
|
|
|
|
// Close file
|
|
//
|
|
close(handle);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// DisplayTeleportName()
|
|
//--------------------------------------------------------------------------
|
|
void DisplayTeleportName(char tpNum, boolean locked)
|
|
{
|
|
char far *s;
|
|
word w,h;
|
|
|
|
if (locked)
|
|
{
|
|
fontcolor = 0xf5;
|
|
s = "-- TELEPORT DISABLED --";
|
|
}
|
|
else
|
|
{
|
|
fontcolor = 0x57;
|
|
LoadLocationText(tpNum);
|
|
s = LocationText;
|
|
}
|
|
VW_MeasurePropString(s,&w,&h);
|
|
py = 103;
|
|
px = 160-w/2;
|
|
VW_Bar(54,101,212,9,0x52);
|
|
VW_MarkUpdateBlock(54,101,265,108);
|
|
ShPrint(s,0,false);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CacheDrawPic()
|
|
//--------------------------------------------------------------------------
|
|
void CacheDrawPic(short x, short y, short pic)
|
|
{
|
|
CA_CacheGrChunk(pic);
|
|
VWB_DrawPic(x,y,pic);
|
|
UNCACHEGRCHUNK(pic);
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// MISSION STATISTICS CODE
|
|
//
|
|
//===========================================================================
|
|
|
|
#define BAR_W 48
|
|
#define BAR_H 5
|
|
|
|
#define BAR1_COLOR 0xe0
|
|
#define BAR2_COLOR 0x30
|
|
#define BAR3_COLOR 0x10
|
|
|
|
#define PERC_W 13
|
|
#define PERC_H 5
|
|
|
|
boolean show_stats_quick;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// ShowStats()
|
|
//--------------------------------------------------------------------------
|
|
short ShowStats(short bx, short by, ss_type type, statsInfoType far *stats)
|
|
{
|
|
short floor,total=0,mission=0,p1,p2,p3,loop,maxPerFloor;
|
|
|
|
// Define max points per floor...
|
|
//
|
|
if (stats->total_points || stats->total_inf || stats->total_enemy)
|
|
maxPerFloor = 300;
|
|
else
|
|
maxPerFloor = 0;
|
|
|
|
// Setup to test for bypassing stats.
|
|
//
|
|
LastScan=0;
|
|
|
|
if (type == ss_quick)
|
|
show_stats_quick=true;
|
|
else
|
|
show_stats_quick=false;
|
|
|
|
// Show ratio for each statistic:
|
|
//
|
|
// TOTAL POINTS, INFORMANTS ALIVE, ENEMY DESTROYED,
|
|
// OVERALL FLOOR, OVERALL MISSION
|
|
//
|
|
|
|
// Show TOTAL POINTS ratio.
|
|
//
|
|
p1=ShowRatio(bx,by,bx+52,by,stats->total_points,stats->accum_points,type);
|
|
|
|
// Show INFORMANTS ALIVE ratio.
|
|
//
|
|
by += 7;
|
|
p2=ShowRatio(bx,by,bx+52,by,stats->total_inf,stats->accum_inf,type);
|
|
|
|
// Show ENEMY DESTROYED ratio.
|
|
//
|
|
by += 7;
|
|
p3=ShowRatio(bx,by,bx+52,by,stats->total_enemy,stats->accum_enemy,type);
|
|
|
|
// Show OVERALL FLOOR ratio.
|
|
//
|
|
by += 13;
|
|
floor=p1+p2+p3;
|
|
ShowRatio(bx,by,bx+52,by,maxPerFloor,floor,type);
|
|
|
|
// Show OVERALL MISSION ratio.
|
|
//
|
|
by += 7;
|
|
stats->overall_floor=floor;
|
|
for (loop=0; loop<MAPS_WITH_STATS; loop++)
|
|
{
|
|
total+=300;
|
|
mission+=gamestuff.level[loop].stats.overall_floor;
|
|
}
|
|
mission=ShowRatio(bx,by,bx+52,by,total,mission,type);
|
|
|
|
if (show_stats_quick)
|
|
VW_UpdateScreen();
|
|
|
|
return(mission);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// ShowRatio()
|
|
//--------------------------------------------------------------------------
|
|
byte ShowRatio(short bx, short by, short nx, short ny, long total, long perc, ss_type type)
|
|
{
|
|
char numbars;
|
|
char maxperc;
|
|
char percentage=1,loop;
|
|
|
|
// if (perc > total)
|
|
// perc = total;
|
|
|
|
// Catch those nasty divide-by-zeros!
|
|
//
|
|
if (total)
|
|
{
|
|
maxperc=LRATIO(100,total,perc,10);
|
|
numbars=LRATIO(48,100,maxperc,10);
|
|
}
|
|
else
|
|
{
|
|
if (type != ss_justcalc)
|
|
{
|
|
fontcolor = 0x57;
|
|
VW_Bar(bx,by,BAR_W,BAR_H,0);
|
|
VW_MarkUpdateBlock(bx,by,bx+(BAR_W-1),by+(BAR_H-1));
|
|
VW_Bar(nx,ny,PERC_W+6,PERC_H,0);
|
|
PrintX=nx; PrintY=ny;
|
|
US_Print("N/A");
|
|
}
|
|
return(100);
|
|
}
|
|
|
|
if (type == ss_justcalc)
|
|
return(maxperc);
|
|
|
|
PrintY=ny;
|
|
fontcolor=0xaf;
|
|
fontnumber=2;
|
|
|
|
VW_Bar(bx,by,BAR_W,BAR_H,0x07);
|
|
PrintStatPercent(nx,ny,0);
|
|
VW_MarkUpdateBlock(bx,by,bx+(BAR_W-1),by+(BAR_H-1));
|
|
for (loop=0; loop<numbars; loop++)
|
|
{
|
|
if (LastScan)
|
|
show_stats_quick=true;
|
|
|
|
// Print one line of bar
|
|
//
|
|
VW_MarkUpdateBlock(bx,by,bx,by+(BAR_H-1));
|
|
VL_Vlin(bx++,by,BAR_H,0xc8);
|
|
|
|
// Keep up with current percentage
|
|
//
|
|
if (loop==numbars-1)
|
|
percentage = maxperc;
|
|
else
|
|
percentage += 2;
|
|
|
|
PrintStatPercent(nx,ny,percentage);
|
|
|
|
if (!show_stats_quick)
|
|
{
|
|
if (!(loop%2))
|
|
SD_PlaySound(STATS1SND);
|
|
VW_WaitVBL(1);
|
|
VW_UpdateScreen();
|
|
}
|
|
}
|
|
|
|
if (!show_stats_quick && numbars)
|
|
{
|
|
SD_PlaySound(STATS2SND);
|
|
while (SD_SoundPlaying() && !LastScan);
|
|
}
|
|
|
|
return(maxperc);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// PrintStatPercent()
|
|
//--------------------------------------------------------------------------
|
|
void PrintStatPercent(short nx, short ny, char percentage)
|
|
{
|
|
if (percentage < 10)
|
|
PrintX=nx+9;
|
|
else
|
|
if (percentage < 100)
|
|
PrintX=nx+4;
|
|
else
|
|
PrintX=nx-1;
|
|
|
|
VW_Bar(nx,ny,PERC_W+5,PERC_H,0);
|
|
US_PrintUnsigned(percentage);
|
|
US_Print("%");
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// PerfectStats()
|
|
//--------------------------------------------------------------------------
|
|
boolean PerfectStats()
|
|
{
|
|
if ((gamestuff.level[gamestate.mapon].stats.total_points == gamestuff.level[gamestate.mapon].stats.accum_points) &&
|
|
(gamestuff.level[gamestate.mapon].stats.total_inf == gamestuff.level[gamestate.mapon].stats.accum_inf) &&
|
|
(gamestuff.level[gamestate.mapon].stats.total_enemy == gamestuff.level[gamestate.mapon].stats.accum_enemy))
|
|
return(true);
|
|
|
|
return(false);
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// PINBALL BONUS DISPLAY CODE
|
|
//
|
|
//===========================================================================
|
|
|
|
//--------------------------------------------------------------------------
|
|
// B_GAliFunc()
|
|
//--------------------------------------------------------------------------
|
|
void B_GAliFunc()
|
|
{
|
|
extern char far B_GAlienDead2[];
|
|
|
|
if (gamestate.episode == 5)
|
|
DisplayInfoMsg(B_GAlienDead2,MP_PINBALL_BONUS,7*60,MT_BONUS);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// B_EManFunc()
|
|
//--------------------------------------------------------------------------
|
|
void B_EManFunc()
|
|
{
|
|
unsigned temp,i;
|
|
|
|
SD_PlaySound(EXTRA_MANSND);
|
|
fontnumber = 2;
|
|
|
|
temp = bufferofs;
|
|
|
|
for (i=0;i<3;i++)
|
|
{
|
|
bufferofs = screenloc[i];
|
|
JLatchDrawPic(0,0,TOP_STATUSBARPIC);
|
|
ShadowPrintLocationText(sp_normal);
|
|
}
|
|
|
|
bufferofs = temp;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// B_MillFunc()
|
|
//--------------------------------------------------------------------------
|
|
void B_MillFunc()
|
|
{
|
|
GiveAmmo(99);
|
|
HealSelf(99);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// B_RollFunc()
|
|
//--------------------------------------------------------------------------
|
|
void B_RollFunc()
|
|
{
|
|
B_MillFunc();
|
|
gamestate.score_roll_wait = SCORE_ROLL_WAIT;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Pinball Bonus Text
|
|
//--------------------------------------------------------------------------
|
|
|
|
char far B_GAlienDead2[] = "^FC57 GUARDIAN ALIEN\r"
|
|
" DESTROYED!\r\r"
|
|
"^FCA6 FIND AND DESTROY ALL\r"
|
|
"PROJECTION GENERATORS!";
|
|
|
|
char far B_GAlienDead[] = "^FC57 GUARDIAN ALIEN\r"
|
|
" DESTROYED!\r\r"
|
|
"^FCA6 FIND THE EXIT TO\r"
|
|
"COMPLETE THIS MISSION";
|
|
|
|
char far B_ScoreRolled[] = "^FC57\rROLLED SCORE DISPLAY!\r"
|
|
"^FCA6 FULL AMMO BONUS!\r"
|
|
" FULL HEALTH BONUS!\r"
|
|
"1,000,000 POINT BONUS!";
|
|
|
|
char far B_OneMillion[] = "^FC57\r GREAT SCORE!\r"
|
|
"^FCA6 FULL AMMO BONUS!\r"
|
|
" FULL HEALTH BONUS!\r"
|
|
"1,000,000 POINT BONUS!";
|
|
|
|
char far B_ExtraMan[] = "^FC57\r\r GREAT SCORE!\r"
|
|
"^FCA6 EXTRA LIFE BONUS!\r";
|
|
|
|
char far B_EnemyDestroyed[] = "^FC57\r\r ALL ENEMY DESTROYED!\r"
|
|
"^FCA6 50,000 POINT BONUS!\r";
|
|
|
|
char far B_TotalPoints[] = "^FC57\r\r ALL POINTS COLLECTED!\r"
|
|
"^FCA6 50,000 POINT BONUS!\r";
|
|
|
|
char far B_InformantsAlive[] = "^FC57\r\r ALL INFORMANTS ALIVE!\r"
|
|
"^FCA6 50,000 POINT BONUS!\r";
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Pinball Bonus Table
|
|
//--------------------------------------------------------------------------
|
|
PinballBonusInfo far PinballBonus[]={
|
|
|
|
// Special
|
|
// BonusText Points Recur? Function
|
|
//-----------------------------------------------------
|
|
{B_GAlienDead, 0, false, B_GAliFunc},
|
|
{B_ScoreRolled, 1000000l,true, B_RollFunc},
|
|
{B_OneMillion, 1000000l,false, B_MillFunc},
|
|
{B_ExtraMan, 0, true, B_EManFunc},
|
|
{B_EnemyDestroyed, 50000l, false, NULL},
|
|
{B_TotalPoints, 50000l, false, NULL},
|
|
{B_InformantsAlive, 50000l, false, NULL},
|
|
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
// DisplayPinballBonus()
|
|
//--------------------------------------------------------------------------
|
|
void DisplayPinballBonus()
|
|
{
|
|
char loop;
|
|
|
|
// Check queue for bonuses
|
|
//
|
|
for (loop=0; loop<sizeof(gamestuff.level[0].bonus_queue)*8; loop++)
|
|
if ((BONUS_QUEUE & (1<<loop)) && (LastMsgPri < MP_PINBALL_BONUS))
|
|
{
|
|
// Start this bonus!
|
|
//
|
|
SD_PlaySound(ROLL_SCORESND);
|
|
DisplayInfoMsg(PinballBonus[loop].BonusText,MP_PINBALL_BONUS,7*60,MT_BONUS);
|
|
|
|
// Add to "shown" ... Remove from "queue"
|
|
//
|
|
if (!PinballBonus[loop].Recurring)
|
|
BONUS_SHOWN |= (1<<loop);
|
|
BONUS_QUEUE &= ~(1<<loop);
|
|
|
|
// Give points and execute special function.
|
|
//
|
|
GivePoints(PinballBonus[loop].Points,false);
|
|
if (PinballBonus[loop].func)
|
|
PinballBonus[loop].func();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CheckPinballBonus()
|
|
//--------------------------------------------------------------------------
|
|
void CheckPinballBonus(long points)
|
|
{
|
|
long score_before=gamestate.score,
|
|
score_after=gamestate.score+points;
|
|
|
|
// Check SCORE ROLLED bonus
|
|
//
|
|
if (score_before <= MAX_DISPLAY_SCORE && score_after > MAX_DISPLAY_SCORE)
|
|
ActivatePinballBonus(B_SCORE_ROLLED);
|
|
|
|
// Check ONE MILLION bonus
|
|
//
|
|
if (score_before < 500000l && score_after >= 500000l)
|
|
ActivatePinballBonus(B_ONE_MILLION);
|
|
|
|
// Check EXTRA MAN bonus
|
|
//
|
|
if (score_after >= gamestate.nextextra)
|
|
{
|
|
gamestate.nextextra += EXTRAPOINTS;
|
|
if (gamestate.lives < MAX_EXTRA_LIVES)
|
|
{
|
|
gamestate.lives++;
|
|
ActivatePinballBonus(B_EXTRA_MAN);
|
|
}
|
|
}
|
|
|
|
// Check TOTAL ENEMY bonus
|
|
//
|
|
if (gamestuff.level[gamestate.mapon].stats.total_enemy == gamestuff.level[gamestate.mapon].stats.accum_enemy)
|
|
ActivatePinballBonus(B_ENEMY_DESTROYED);
|
|
|
|
// Check TOTAL POINTS bonus
|
|
//
|
|
if (gamestuff.level[gamestate.mapon].stats.total_points == gamestuff.level[gamestate.mapon].stats.accum_points)
|
|
ActivatePinballBonus(B_TOTAL_POINTS);
|
|
|
|
// Check INFORMANTS ALIVE bonus
|
|
//
|
|
if ((gamestuff.level[gamestate.mapon].stats.total_inf == gamestuff.level[gamestate.mapon].stats.accum_inf) && // All informants alive?
|
|
(gamestuff.level[gamestate.mapon].stats.total_inf) && // Any informants in level?
|
|
((BONUS_SHOWN & (B_TOTAL_POINTS|B_ENEMY_DESTROYED)) == (B_TOTAL_POINTS|B_ENEMY_DESTROYED))) // Got ENEMY and POINTS bonuses?
|
|
ActivatePinballBonus(B_INFORMANTS_ALIVE);
|
|
|
|
// Display bonuses?
|
|
//
|
|
if (BONUS_QUEUE)
|
|
DisplayPinballBonus();
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
//
|
|
// COMPUTER TERMINAL ROUTINES
|
|
//
|
|
//
|
|
//===========================================================================
|
|
|
|
#ifdef ACTIVATE_TERMINAL
|
|
|
|
#define TERM_BUFFERED_DISPLAY
|
|
#define TERM_VIEW_WIDTH 246
|
|
#define TERM_VIEW_HEIGHT 95
|
|
//#define TERM_BACK_COLOR 2 // Defined in 3d)menu.h
|
|
#define TERM_BACK_XOFS 8
|
|
#define TERM_BACK_YOFS 22
|
|
#define TERM_BACK_WIDTH 304
|
|
#define TERM_BACK_HEIGHT 124
|
|
|
|
#define TERM_BCOLOR 3 // Dark Grey
|
|
#define TERM_TCOLOR 88 // Green MONO text color 87=LOW intensity
|
|
#define TERM_TSHAD_COLOR 0 // "Shadow" color
|
|
|
|
#define TERM_SCREEN_XOFS (TERM_BACK_XOFS+19)
|
|
#define TERM_SCREEN_YOFS (TERM_BACK_YOFS+14)
|
|
|
|
static unsigned far tcursor_x = TERM_SCREEN_XOFS,
|
|
far tcursor_y = TERM_SCREEN_YOFS;
|
|
|
|
|
|
char TERM_sound_on = 1;
|
|
|
|
|
|
char far *Commands[TC_LAST];
|
|
|
|
memptr TermMessages = NULL;
|
|
memptr TermCommands = NULL;
|
|
|
|
#define FreeTerminalCommands() MM_FreePtr(&TermCommands)
|
|
#define FreeTerminalMessages() MM_FreePtr(&TermMessages)
|
|
#define LoadTerminalText() IO_LoadFile(term_msg_name,&TermMessages)
|
|
//#define LoadTerminalText() IO_LoadFile("TERM_MSG.TXT",&TermMessages)
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// LoadTerminalCommands()
|
|
//
|
|
// Caches in the commands in TERM_COMMANDS grsegs and sparces the file for
|
|
// commands - Assigning Commands[] to the beginning of each command and
|
|
// null terminating the command. Each command is seperated with ^XX. Leading
|
|
// returns&linefeeds are skipped.
|
|
//
|
|
// NOTE: This expects that TC_LAST in the enum list of commands is concurrent
|
|
// with the grseg TERM_COMMANDS.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void LoadTerminalCommands(void)
|
|
{
|
|
char far *Message;
|
|
unsigned char pos;
|
|
|
|
// IO_LoadFile("TERM_CMD.TXT",&TermCommands);
|
|
IO_LoadFile(term_com_name,&TermCommands);
|
|
Message = TermCommands;
|
|
|
|
for (pos = 0;pos<TC_LAST;pos++)
|
|
{
|
|
// Bump past any leading returns/linefeeds
|
|
|
|
while (*Message == '\n' || *Message == '\r')
|
|
Message++;
|
|
|
|
// Assign ptrs
|
|
|
|
Commands[pos] = Message;
|
|
|
|
if (!(Message = _fstrstr(Message,int_xx)))
|
|
ACT1_ERROR(INVALID_CACHE_MSG_NUM);
|
|
|
|
*Message = 0; // Null Terminate String
|
|
Message += 3; // Bump to start of next Message
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean term_cursor_vis = true;
|
|
boolean shadow_text = true;
|
|
|
|
#if 1
|
|
|
|
PresenterInfo Terminal_PI;
|
|
|
|
//---------------------------------------------------------------------------
|
|
// TerminalPrint()
|
|
//---------------------------------------------------------------------------
|
|
void TerminalPrint(char far *msg, boolean FastPrint)
|
|
{
|
|
Terminal_PI.print_delay = !FastPrint;
|
|
Terminal_PI.script[0] = msg;
|
|
TP_Presenter(&Terminal_PI);
|
|
}
|
|
|
|
#else
|
|
|
|
//---------------------------------------------------------------------------
|
|
// TerminalPrint()
|
|
//
|
|
// NOTE : Terminal Control Chars
|
|
//
|
|
// @ - Square Box (IE. Cursor)
|
|
//---------------------------------------------------------------------------
|
|
|
|
void TerminalPrint(char far *msg,boolean FastPrint)
|
|
{
|
|
#define TERM_PRINT_DELAY 1
|
|
fontstruct _seg *font;
|
|
char buf[2] = {0,0};
|
|
char old_color,old_color2;
|
|
char fontheight;
|
|
|
|
font = (fontstruct _seg *)grsegs[STARTFONT+fontnumber];
|
|
fontheight = font->height;
|
|
|
|
while (msg && *msg)
|
|
{
|
|
buf[0] = *msg++;
|
|
|
|
if (buf[0] == '^')
|
|
{
|
|
//
|
|
// Handle Control Codes
|
|
//
|
|
|
|
switch (*((unsigned far *)msg)++)
|
|
{
|
|
// FONT COLOR
|
|
//
|
|
case TP_CNVT_CODE('F','C'):
|
|
fontcolor = TP_VALUE(msg,2);
|
|
msg += 2;
|
|
break;
|
|
|
|
// BELL
|
|
//
|
|
case TP_CNVT_CODE('B','E'):
|
|
SD_PlaySound(TERM_BEEPSND);
|
|
SD_WaitSoundDone();
|
|
break;
|
|
|
|
// HIDE CURSOR
|
|
//
|
|
case TP_CNVT_CODE('H','I'):
|
|
px = tcursor_x;
|
|
py = tcursor_y;
|
|
old_color = fontcolor;
|
|
fontcolor = TERM_BCOLOR;
|
|
VW_DrawPropString("@");
|
|
fontcolor = old_color;
|
|
break;
|
|
|
|
|
|
// PAUSE
|
|
//
|
|
case TP_CNVT_CODE('P','A'):
|
|
VW_WaitVBL(30);
|
|
break;
|
|
|
|
|
|
// END OF MSG
|
|
//
|
|
|
|
case TP_CNVT_CODE('X','X'):
|
|
msg = NULL;
|
|
break;
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Process Text Char (Like print it!)
|
|
//
|
|
|
|
bufferofs = displayofs;
|
|
|
|
if (term_cursor_vis)
|
|
{
|
|
px = tcursor_x;
|
|
py = tcursor_y;
|
|
|
|
old_color = fontcolor; // Store Cursor Color
|
|
fontcolor = TERM_BCOLOR;
|
|
|
|
VW_DrawPropString("@");
|
|
|
|
fontcolor = old_color;
|
|
}
|
|
|
|
if (buf[0] != '\n')
|
|
{
|
|
// Blast "Shadow" on screen
|
|
|
|
if (shadow_text)
|
|
{
|
|
px = tcursor_x+1;
|
|
py = tcursor_y+1;
|
|
old_color2 = fontcolor; // STORE Old Colr
|
|
fontcolor = TERM_TSHAD_COLOR;
|
|
VW_DrawPropString(buf);
|
|
fontcolor = old_color2; // RESTORE Old Colr
|
|
}
|
|
|
|
// Blast normal Text color to screen
|
|
|
|
px = tcursor_x;
|
|
py = tcursor_y;
|
|
VW_DrawPropString(buf);
|
|
|
|
if (sound_on)
|
|
if (buf[0] != ' ')
|
|
SD_PlaySound(TERM_TYPESND);
|
|
|
|
tcursor_x = px;
|
|
|
|
if (term_cursor_vis)
|
|
{
|
|
VW_DrawPropString("@");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (tcursor_y > 90+TERM_SCREEN_XOFS)
|
|
VL_ScreenToScreen(displayofs+((TERM_SCREEN_YOFS+fontheight)*SCREENWIDTH)+(TERM_SCREEN_XOFS/4),
|
|
displayofs+TERM_SCREEN_YOFS*SCREENWIDTH+TERM_SCREEN_XOFS/4,
|
|
(248/4),93);
|
|
else
|
|
tcursor_y += fontheight;
|
|
|
|
tcursor_x = TERM_SCREEN_XOFS;
|
|
}
|
|
|
|
if (!FastPrint)
|
|
VL_WaitVBL(TERM_PRINT_DELAY);
|
|
|
|
VW_UpdateScreen();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// CacheTerminalPrint()
|
|
//
|
|
// This prints a message in the TERM_MESSAGES grsegs which MUST
|
|
// already be loaded into memory.
|
|
//---------------------------------------------------------------------------
|
|
void CacheTerminalPrint(short MsgNum,boolean FastPrint)
|
|
{
|
|
char far *Message;
|
|
|
|
Message = TermMessages;
|
|
|
|
// Search for end of MsgNum-1 (Start of our message)
|
|
//
|
|
#pragma warn -pia
|
|
while (MsgNum--)
|
|
{
|
|
if (!(Message = _fstrstr(Message,int_xx)))
|
|
AGENT_ERROR(BAD_TERMINAL_MSG_NUM);
|
|
Message += 3; // Bump to start of next Message
|
|
}
|
|
#pragma warn +pia
|
|
|
|
// Move past LFs and CRs that follow "^XX"
|
|
//
|
|
// while ((*Message=='\n') || (*Message=='\r'))
|
|
// Message++;
|
|
|
|
Message += 2; // Move past LF and CR that follows "^XX"
|
|
|
|
TerminalPrint(Message,FastPrint);
|
|
}
|
|
|
|
|
|
|
|
char far TERM_MSG[]="^ST1^CEEnter commands and press ENTER.\r^CEPress ESC to exit terminal.^XX";
|
|
|
|
//---------------------------------------------------------------------------
|
|
// ActivateTerminal()
|
|
//---------------------------------------------------------------------------
|
|
void ActivateTerminal(boolean skiplink)
|
|
{
|
|
#define MAX_INPUT 30
|
|
char buffer[MAX_INPUT];
|
|
boolean temp_caps = allcaps,ExitMoFo;
|
|
unsigned oldwidth;
|
|
US_CursorStruct TermCursor = {'@',0,0x58,2}; // Holds Font#, etc.
|
|
short msgnum;
|
|
|
|
|
|
// Setup for text presenter
|
|
//
|
|
memset(&Terminal_PI,0,sizeof(Terminal_PI));
|
|
Terminal_PI.flags=TPF_USE_CURRENT|TPF_SHOW_CURSOR|TPF_SCROLL_REGION;
|
|
Terminal_PI.xl=21;
|
|
Terminal_PI.yl=32;
|
|
Terminal_PI.xh=277;
|
|
Terminal_PI.yh=134;
|
|
Terminal_PI.ltcolor=255;
|
|
Terminal_PI.bgcolor=TERM_BCOLOR;
|
|
Terminal_PI.dkcolor=255;
|
|
Terminal_PI.shcolor=TERM_TSHAD_COLOR;
|
|
Terminal_PI.fontnumber=2;
|
|
Terminal_PI.cur_x = -1;
|
|
Terminal_PI.print_delay=1;
|
|
|
|
|
|
#ifndef TERM_BUFFERED_DISPLAY
|
|
bufferofs = displayofs;
|
|
#endif
|
|
|
|
ClearMemory();
|
|
|
|
oldwidth = viewwidth/16;
|
|
if (oldwidth != FULL_VIEW_WIDTH)
|
|
NewViewSize(FULL_VIEW_WIDTH);
|
|
|
|
|
|
DrawPlayScreen(false);
|
|
|
|
StopMusic();
|
|
|
|
fontnumber = 1;
|
|
CA_CacheGrChunk(STARTFONT+FONT2); // Medium font
|
|
|
|
BMAmsg(TERM_MSG);
|
|
|
|
CacheDrawPic(TERM_BACK_XOFS,TERM_BACK_YOFS,TERMINAL_SCREENPIC);
|
|
|
|
LoadTerminalText();
|
|
LoadTerminalCommands();
|
|
|
|
#ifdef TERM_BUFFERED_DISPLAY
|
|
VW_UpdateScreen();
|
|
#endif
|
|
|
|
|
|
fontnumber = 2;
|
|
allcaps = true;
|
|
fontcolor = TERM_TCOLOR;
|
|
tcursor_x = TERM_SCREEN_XOFS;
|
|
tcursor_y = TERM_SCREEN_YOFS;
|
|
|
|
//
|
|
// Set up custom cursor
|
|
//
|
|
|
|
use_custom_cursor = true;
|
|
US_CustomCursor = TermCursor;
|
|
|
|
//
|
|
// Start term stuff..
|
|
//
|
|
|
|
VW_FadeIn();
|
|
|
|
ExitMoFo = false;
|
|
|
|
TerminalPrint("^ST1^XX",false);
|
|
if (!skiplink)
|
|
{
|
|
CacheTerminalPrint(TM_LINK,false);
|
|
|
|
if (Keyboard[sc_H] & Keyboard[sc_O] & Keyboard[sc_T])
|
|
{
|
|
CacheTerminalPrint(TM_CHEATER,false);
|
|
}
|
|
else
|
|
{
|
|
VW_WaitVBL(1*60 + (US_RndT() % 60*2));
|
|
|
|
if (gamestate.TimeCount & 0x1000)
|
|
{
|
|
CacheTerminalPrint(TM_LINK_BAD,false);
|
|
IN_Ack();
|
|
ExitMoFo = true;
|
|
}
|
|
else
|
|
{
|
|
CacheTerminalPrint(TM_LINK_OK,false);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
IN_ClearKeysDown();
|
|
|
|
while (!ExitMoFo)
|
|
{
|
|
backcolor = TERM_BCOLOR;
|
|
CacheTerminalPrint(TM_READY,false);
|
|
|
|
if (US_LineInput(px+1,py,buffer,nil,true,MAX_INPUT,240+TERM_SCREEN_XOFS-px))
|
|
{
|
|
CacheTerminalPrint(TM_RETURN,false);
|
|
if (*buffer)
|
|
switch (msgnum = US_CheckParm(buffer,Commands))
|
|
{
|
|
case TC_HINT:
|
|
// case TC_GOLDSTERN:
|
|
case TC_JAM:
|
|
case TC_HELP:
|
|
case TC_APOGEE:
|
|
case TC_THANKS:
|
|
case TC_GOOBERS:
|
|
// case TC_BSTONE:
|
|
case TC_JERRY:
|
|
case TC_MIKE:
|
|
case TC_JIM:
|
|
CacheTerminalPrint(msgnum,false);
|
|
break;
|
|
|
|
|
|
case TC_EXIT:
|
|
case TC_QUIT:
|
|
case TC_OFF:
|
|
case TC_BYE:
|
|
ExitMoFo = true;
|
|
break;
|
|
|
|
case TC_STAR:
|
|
CacheTerminalPrint(TM_STAR,false);
|
|
break;
|
|
|
|
case TC_JOSHUA:
|
|
CacheTerminalPrint(TM_JOSHUA,false);
|
|
// PowerBall = 1;
|
|
break;
|
|
|
|
case TC_BLUEPRINT:
|
|
FloorCheat(255);
|
|
break;
|
|
|
|
case TC_SOUND:
|
|
TERM_sound_on ^= 1;
|
|
CacheTerminalPrint(TM_SOUND_OFF+TERM_sound_on,false);
|
|
break;
|
|
|
|
case TC_ARRIVAL_GOLDSTERN:
|
|
{
|
|
if (GoldsternInfo.GoldSpawned)
|
|
CacheTerminalPrint(TM_GOLDSTERN_ARRIVED,false);
|
|
else
|
|
if (GoldsternInfo.flags == GS_COORDFOUND)
|
|
{
|
|
CacheTerminalPrint(TM_GOLDSTERN_WILL_AR,false);
|
|
sprintf(buffer," %d^XX",GoldsternInfo.WaitTime/60);
|
|
TerminalPrint(buffer,false);
|
|
CacheTerminalPrint(TM_SECONDS,false);
|
|
}
|
|
else
|
|
{
|
|
if (GoldsternInfo.WaitTime)
|
|
{
|
|
CacheTerminalPrint(TM_GOLDSTERN_NO_PICK,false);
|
|
sprintf(buffer," %d^XX",GoldsternInfo.WaitTime/60);
|
|
TerminalPrint(buffer,false);
|
|
CacheTerminalPrint(TM_SECONDS,false);
|
|
}
|
|
else
|
|
CacheTerminalPrint(TM_GOLDSTERN_NO_INFO,false);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TC_DEACTIVATE_SECURITY:
|
|
{
|
|
objtype *obj;
|
|
|
|
CacheTerminalPrint(TM_RESET_SECURITY,false);
|
|
for (obj = player;obj;obj = obj->next)
|
|
{
|
|
if (obj->obclass == security_lightobj)
|
|
{
|
|
obj->temp1 = 0;
|
|
obj->flags &= ~FL_ALERTED;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TC_SATALITE_STATUS:
|
|
{
|
|
CacheTerminalPrint(TM_VITALS1,false);
|
|
TerminalPrint(buffer,false);
|
|
|
|
CacheTerminalPrint(TM_VITALS2,false);
|
|
sprintf(buffer, " %d\r\n^XX", gamestate.VitalsRemain);
|
|
TerminalPrint(buffer,false);
|
|
}
|
|
break;
|
|
|
|
case TC_PROFILE:
|
|
CacheTerminalPrint(TM_PROFILE_WHO,false);
|
|
if (US_LineInput(px+1,py,buffer,nil,true,MAX_INPUT,246+TERM_SCREEN_XOFS-px))
|
|
{
|
|
CacheTerminalPrint(TM_RETURN,false);
|
|
if (*buffer)
|
|
switch (US_CheckParm(buffer,Commands))
|
|
{
|
|
case TC_GOLDSTERN:
|
|
CacheTerminalPrint(TM_PROFILE_GOLDSTERN,false);
|
|
break;
|
|
|
|
case TC_BSTONE:
|
|
CacheTerminalPrint(TM_PROFILE_BLAKE,false);
|
|
break;
|
|
|
|
case TC_SSTONE:
|
|
CacheTerminalPrint(TM_PROFILE_SARA,false);
|
|
break;
|
|
|
|
default:
|
|
CacheTerminalPrint(TM_PROFILE_UNKNOWN,false);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
CacheTerminalPrint(TM_UNRECOGNIZED_COMMAND,false);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// User pressed escape....
|
|
|
|
ExitMoFo = true;
|
|
}
|
|
|
|
#ifdef TERM_BUFFERED_DISPLAY
|
|
VW_UpdateScreen();
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Free everything cached in...Exit terminal
|
|
//
|
|
|
|
FreeTerminalCommands();
|
|
FreeTerminalMessages();
|
|
|
|
UNCACHEGRCHUNK(STARTFONT+1);
|
|
NewViewSize(oldwidth);
|
|
|
|
|
|
StartMusic(false);
|
|
PM_CheckMainMem();
|
|
|
|
DrawPlayScreen(false);
|
|
|
|
IN_ClearKeysDown();
|
|
allcaps = temp_caps;
|
|
use_custom_cursor = false;
|
|
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// FloorCheat()
|
|
//---------------------------------------------------------------------------
|
|
void FloorCheat(unsigned RadarFlags)
|
|
{
|
|
#define FC_EMBED_COLOR(ColorCodes) {_fstrncpy(&pbuffer[pos],ColorCodes,5);pos+=5;}
|
|
#define FC_NORM_COLOR() FC_EMBED_COLOR("^FC57")
|
|
|
|
unsigned x,y,pos;
|
|
objtype *actor;
|
|
char far *pbuffer;
|
|
memptr buffer;
|
|
|
|
MM_GetPtr(&buffer,512);
|
|
|
|
pbuffer = buffer;
|
|
|
|
CacheTerminalPrint(TM_BLUEPRINTS,false);
|
|
|
|
shadow_text = term_cursor_vis = false;
|
|
Terminal_PI.flags &= ~TPF_SHOW_CURSOR;
|
|
|
|
//
|
|
// Cache in the "Radar Font"
|
|
//
|
|
|
|
CA_CacheGrChunk(STARTFONT+5);
|
|
// fontnumber = 5;
|
|
Terminal_PI.fontnumber = 5;
|
|
|
|
//
|
|
// Display the radar/floor-plans
|
|
|
|
// TerminalPrint("\r\n^XX",true);
|
|
for (y=0;y<64;y++)
|
|
{
|
|
pos = 0;
|
|
for (x=0;x<64;x++)
|
|
{
|
|
//
|
|
// Get wall/actor && Check for force placement of player on radar..
|
|
//
|
|
|
|
if (DebugOk && x == player->tilex && y == player->tiley)
|
|
actor = player;
|
|
else
|
|
actor = actorat[x][y];
|
|
|
|
//
|
|
// Check for walls
|
|
|
|
if (!TravelTable[x][y]) // Map only shows where you've seen!
|
|
{
|
|
pbuffer[pos++]='!';
|
|
}
|
|
else
|
|
if (((unsigned)actor && (unsigned)actor<108) || // 108 == LAST WALL TILE
|
|
|
|
#if IN_DEVELOPMENT
|
|
|
|
(*(mapsegs[0]+farmapylookup[y]+x) >= HIDDENAREATILE && (!DebugOk)) ||
|
|
|
|
#endif
|
|
|
|
(((unsigned)actor & 0x80) && actor<objlist && (!DebugOk))) // Treat doors as walls in NoDebug
|
|
{
|
|
// Mark Wall piece
|
|
//
|
|
pbuffer[pos++] = '!';
|
|
}
|
|
else
|
|
{
|
|
// Not a wall Piece
|
|
//
|
|
if (((RadarFlags & RS_PERSONNEL_TRACKER) && actor >= objlist) && (!(actor->flags & FL_DEADGUY)))
|
|
{
|
|
switch (actor->obclass)
|
|
{
|
|
case playerobj:
|
|
if (RadarFlags & RS_PERSONNEL_TRACKER)
|
|
{
|
|
//
|
|
// Mark map piece as the "player"
|
|
//
|
|
FC_EMBED_COLOR("^FC0F"); // WHITE
|
|
pbuffer[pos++] = '!';
|
|
FC_NORM_COLOR();
|
|
}
|
|
else
|
|
pbuffer[pos++] = ' ';
|
|
break;
|
|
|
|
case security_lightobj:
|
|
if (RadarFlags & RS_SECURITY_STATUS)
|
|
{
|
|
//
|
|
// Mark map piece as "Alerted Security Lamp"
|
|
//
|
|
if (actor->temp1)
|
|
{
|
|
FC_EMBED_COLOR("^FC1C"); // Red
|
|
}
|
|
else
|
|
{
|
|
FC_EMBED_COLOR("^FC5C"); // Green
|
|
}
|
|
|
|
pbuffer[pos++] = '!';
|
|
FC_NORM_COLOR();
|
|
break;
|
|
}
|
|
else
|
|
pbuffer[pos++] = ' ';
|
|
break;
|
|
|
|
case lcan_wait_alienobj:
|
|
case scan_wait_alienobj:
|
|
case hang_terrotobj:
|
|
case gurney_waitobj:
|
|
pbuffer[pos++] = ' ';
|
|
break;
|
|
|
|
case goldsternobj:
|
|
if (RadarFlags & RS_GOLDSTERN_TRACKER)
|
|
{
|
|
//
|
|
// Mark map piece as "goldstern"
|
|
//
|
|
FC_EMBED_COLOR("^FC38"); // Yellow ...or.. err, like gold!
|
|
pbuffer[pos++] = '!';
|
|
FC_NORM_COLOR();
|
|
break;
|
|
}
|
|
else
|
|
pbuffer[pos++] = ' ';
|
|
break;
|
|
|
|
default:
|
|
if (RadarFlags & RS_PERSONNEL_TRACKER)
|
|
{
|
|
//
|
|
// Mark map piece as a "general object"
|
|
//
|
|
FC_EMBED_COLOR("^FC18"); // Red
|
|
pbuffer[pos++] = '!';
|
|
FC_NORM_COLOR();
|
|
}
|
|
else
|
|
pbuffer[pos++] = ' ';
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
pbuffer[pos++] = ' ';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// pbuffer[pos++] = '\n';
|
|
_fstrcpy(pbuffer+pos,"\r\n^XX");
|
|
pbuffer[pos+5] = 0;
|
|
|
|
TerminalPrint(pbuffer,true);
|
|
}
|
|
|
|
|
|
TerminalPrint("\r\n\r\n\r\n\r\n^XX",true);
|
|
MM_FreePtr(&buffer);
|
|
|
|
UNCACHEGRCHUNK(STARTFONT+5);
|
|
Terminal_PI.fontnumber = 2;
|
|
TerminalPrint("\r\n^XX",true);
|
|
Terminal_PI.flags |= TPF_SHOW_CURSOR;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
PLAYER CONTROL
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
|
|
|
|
|
|
void SpawnPlayer (int tilex, int tiley, int dir)
|
|
{
|
|
if (gamestuff.level[gamestate.mapon].ptilex &&
|
|
gamestuff.level[gamestate.mapon].ptiley)
|
|
{
|
|
tilex = gamestuff.level[gamestate.mapon].ptilex;
|
|
tiley = gamestuff.level[gamestate.mapon].ptiley;
|
|
dir = 1+(gamestuff.level[gamestate.mapon].pangle/90);
|
|
}
|
|
|
|
player->obclass = playerobj;
|
|
player->active = true;
|
|
player->tilex = tilex;
|
|
player->tiley = tiley;
|
|
|
|
player->areanumber=GetAreaNumber(player->tilex,player->tiley);
|
|
|
|
player->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;
|
|
player->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;
|
|
player->state = &s_player;
|
|
player->angle = (1-dir)*90;
|
|
if (player->angle<0)
|
|
player->angle += ANGLES;
|
|
player->flags = FL_NEVERMARK;
|
|
Thrust (0,0); // set some variables
|
|
|
|
InitAreas ();
|
|
|
|
InitWeaponBounce();
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//------------------------------------------------------------------------
|
|
// GunAttack()
|
|
//------------------------------------------------------------------------
|
|
void GunAttack (objtype *ob)
|
|
{
|
|
objtype *check,*closest,*oldclosest;
|
|
int damage;
|
|
int dx,dy,dist;
|
|
long viewdist;
|
|
boolean skip = false;
|
|
|
|
if (gamestate.weapon != wp_autocharge)
|
|
{
|
|
MakeAlertNoise(ob);
|
|
}
|
|
|
|
switch (gamestate.weapon)
|
|
{
|
|
case wp_autocharge:
|
|
SD_PlaySound (ATKAUTOCHARGESND);
|
|
skip = true;
|
|
break;
|
|
|
|
case wp_pistol:
|
|
SD_PlaySound (ATKCHARGEDSND);
|
|
skip = true;
|
|
break;
|
|
|
|
case wp_burst_rifle:
|
|
SD_PlaySound (ATKBURSTRIFLESND);
|
|
break;
|
|
|
|
case wp_ion_cannon:
|
|
SD_PlaySound (ATKIONCANNONSND);
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// find potential targets
|
|
//
|
|
|
|
viewdist = 0x7fffffffl;
|
|
closest = NULL;
|
|
|
|
while (1)
|
|
{
|
|
oldclosest = closest;
|
|
|
|
for (check=ob->next ; check ; check=check->next)
|
|
if ((check->flags & FL_SHOOTABLE) &&
|
|
(check->flags & FL_VISABLE) &&
|
|
(abs(check->viewx-centerx) < shootdelta))
|
|
{
|
|
if (check->transx < viewdist)
|
|
{
|
|
if ((skip && (check->obclass == hang_terrotobj))
|
|
|| (check->flags2 & FL2_NOTGUNSHOOTABLE))
|
|
continue;
|
|
|
|
viewdist = check->transx;
|
|
closest = check;
|
|
}
|
|
}
|
|
|
|
if (closest == oldclosest)
|
|
return; // no more targets, all missed
|
|
|
|
//
|
|
// trace a line from player to enemey
|
|
//
|
|
if (CheckLine(closest,player))
|
|
break;
|
|
}
|
|
|
|
//
|
|
// hit something
|
|
//
|
|
|
|
dx = abs(closest->tilex - player->tilex);
|
|
dy = abs(closest->tiley - player->tiley);
|
|
dist = dx>dy ? dx:dy;
|
|
|
|
if (dist<2)
|
|
damage = US_RndT() / 2; // 4
|
|
else if (dist<4)
|
|
damage = US_RndT() / 4; // 6
|
|
else
|
|
{
|
|
if ( (US_RndT() / 12) < dist) // missed
|
|
return;
|
|
damage = US_RndT() / 4; // 6
|
|
}
|
|
|
|
DamageActor (closest,damage,player);
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
|
|
/*
|
|
===============
|
|
=
|
|
= T_Attack
|
|
=
|
|
===============
|
|
*/
|
|
|
|
|
|
void T_Attack (objtype *ob)
|
|
{
|
|
atkinf_t far *cur;
|
|
int x, wp_start;
|
|
|
|
if (noShots)
|
|
{
|
|
ob->state = &s_player;
|
|
gamestate.attackframe = gamestate.weaponframe = 0;
|
|
return;
|
|
}
|
|
|
|
if (gamestate.weapon == wp_autocharge)
|
|
UpdateAmmoMsg();
|
|
|
|
if ( buttonstate[bt_use] && !buttonheld[bt_use] )
|
|
buttonstate[bt_use] = false;
|
|
|
|
if ( buttonstate[bt_attack] && !buttonheld[bt_attack])
|
|
buttonstate[bt_attack] = false;
|
|
|
|
ControlMovement (ob);
|
|
|
|
player->tilex = player->x >> TILESHIFT; // scale to tile values
|
|
player->tiley = player->y >> TILESHIFT;
|
|
|
|
//
|
|
// change frame and fire
|
|
//
|
|
gamestate.attackcount -= tics;
|
|
if (gamestate.attackcount <= 0)
|
|
{
|
|
cur = &attackinfo[gamestate.weapon][gamestate.attackframe];
|
|
switch (cur->attack)
|
|
{
|
|
case -1:
|
|
ob->state = &s_player;
|
|
|
|
if (!gamestate.ammo)
|
|
{
|
|
if (gamestate.weapon != wp_autocharge)
|
|
{
|
|
gamestate.weapon = wp_autocharge;
|
|
DrawWeapon();
|
|
DisplayInfoMsg(EnergyPackDepleted,MP_NO_MORE_AMMO,DISPLAY_MSG_STD_TIME<<1,MT_OUT_OF_AMMO);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(gamestate.useable_weapons & (1<<gamestate.weapon)))
|
|
{
|
|
gamestate.weapon = wp_autocharge;
|
|
DrawWeapon();
|
|
DisplayInfoMsg(NotEnoughEnergyForWeapon,MP_NO_MORE_AMMO,DISPLAY_MSG_STD_TIME<<1,MT_OUT_OF_AMMO);
|
|
}
|
|
};
|
|
gamestate.attackframe = gamestate.weaponframe = 0;
|
|
return;
|
|
|
|
case -2:
|
|
ob->state = &s_player;
|
|
if (!gamestate.plasma_detonators)
|
|
{
|
|
// Check to see what weapons are possible.
|
|
//
|
|
|
|
for (x=wp_bfg_cannon;x>=wp_autocharge;x--)
|
|
{
|
|
if (gamestate.useable_weapons & (1<<x))
|
|
{
|
|
gamestate.weapon = x;
|
|
break;
|
|
}
|
|
}
|
|
|
|
DrawWeapon();
|
|
// DisplayInfoMsg(pd_switching,MP_NO_MORE_AMMO,DISPLAY_MSG_STD_TIME<<1,MT_OUT_OF_AMMO);
|
|
}
|
|
gamestate.attackframe = gamestate.weaponframe = 0;
|
|
return;
|
|
|
|
case 4:
|
|
if (!gamestate.ammo)
|
|
break;
|
|
if (buttonstate[bt_attack])
|
|
gamestate.attackframe -= 2;
|
|
|
|
case 0:
|
|
if (gamestate.weapon == wp_grenade)
|
|
if (!objfreelist)
|
|
{
|
|
DISPLAY_TIMED_MSG(WeaponMalfunction,MP_WEAPON_MALFUNCTION,MT_MALFUNCTION);
|
|
gamestate.attackframe++;
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
if (!gamestate.ammo)
|
|
{ // can only happen with chain gun
|
|
gamestate.attackframe++;
|
|
break;
|
|
}
|
|
GunAttack (ob);
|
|
if (!godmode)
|
|
gamestate.ammo--;
|
|
DrawAmmo(false);
|
|
break;
|
|
|
|
case 2:
|
|
if (gamestate.weapon_wait)
|
|
break;
|
|
GunAttack (ob);
|
|
gamestate.weapon_wait = AUTOCHARGE_WAIT;
|
|
DrawAmmo(false);
|
|
break;
|
|
|
|
case 3:
|
|
if (gamestate.ammo && buttonstate[bt_attack])
|
|
gamestate.attackframe -= 2;
|
|
break;
|
|
|
|
case 6:
|
|
if (gamestate.ammo && buttonstate[bt_attack])
|
|
if (objfreelist)
|
|
gamestate.attackframe -= 2;
|
|
else
|
|
{
|
|
DISPLAY_TIMED_MSG(WeaponMalfunction,MP_WEAPON_MALFUNCTION,MT_MALFUNCTION);
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
if (!objfreelist)
|
|
{
|
|
DISPLAY_TIMED_MSG(WeaponMalfunction,MP_WEAPON_MALFUNCTION,MT_MALFUNCTION);
|
|
gamestate.attackframe++;
|
|
}
|
|
else
|
|
{
|
|
if (LastMsgType == MT_MALFUNCTION)
|
|
MsgTicsRemain = 1; // Clear Malfuction Msg before anim
|
|
|
|
if (!godmode)
|
|
{
|
|
if (gamestate.ammo >= GRENADE_ENERGY_USE)
|
|
{
|
|
gamestate.ammo-=GRENADE_ENERGY_USE;
|
|
DrawAmmo(false);
|
|
}
|
|
else
|
|
gamestate.attackframe++;
|
|
}
|
|
SD_PlaySound(ATKGRENADESND);
|
|
SpawnProjectile(ob,grenadeobj);
|
|
MakeAlertNoise(ob);
|
|
}
|
|
break;
|
|
|
|
|
|
case 7:
|
|
TryDropPlasmaDetonator();
|
|
DrawAmmo(false);
|
|
break;
|
|
|
|
case 8:
|
|
if (gamestate.plasma_detonators && buttonstate[bt_attack])
|
|
gamestate.attackframe -= 2;
|
|
break;
|
|
|
|
case 9:
|
|
if (!objfreelist)
|
|
{
|
|
DISPLAY_TIMED_MSG(WeaponMalfunction,MP_WEAPON_MALFUNCTION,MT_MALFUNCTION);
|
|
gamestate.attackframe++;
|
|
}
|
|
else
|
|
{
|
|
if (LastMsgType == MT_MALFUNCTION)
|
|
MsgTicsRemain = 1; // Clear Malfuction Msg before anim
|
|
|
|
if (!godmode)
|
|
{
|
|
if (gamestate.ammo >= BFG_ENERGY_USE)
|
|
{
|
|
gamestate.ammo-=BFG_ENERGY_USE;
|
|
DrawAmmo(false);
|
|
}
|
|
else
|
|
gamestate.attackframe++;
|
|
}
|
|
SD_PlaySound(ATKIONCANNONSND); // JTR - this needs to change
|
|
SpawnProjectile(ob,bfg_shotobj);
|
|
MakeAlertNoise(ob);
|
|
}
|
|
break;
|
|
|
|
case 10:
|
|
if (gamestate.ammo && buttonstate[bt_attack])
|
|
if (objfreelist)
|
|
gamestate.attackframe -= 2;
|
|
else
|
|
{
|
|
DISPLAY_TIMED_MSG(WeaponMalfunction,MP_WEAPON_MALFUNCTION,MT_MALFUNCTION);
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
gamestate.attackcount += cur->tics;
|
|
gamestate.attackframe++;
|
|
gamestate.weaponframe =
|
|
attackinfo[gamestate.weapon][gamestate.attackframe].frame;
|
|
}
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
|
|
/*
|
|
===============
|
|
=
|
|
= T_Player
|
|
=
|
|
===============
|
|
*/
|
|
|
|
void T_Player (objtype *ob)
|
|
{
|
|
CheckWeaponChange ();
|
|
|
|
if (gamestate.weapon == wp_autocharge)
|
|
UpdateAmmoMsg();
|
|
|
|
if (tryDetonatorDelay > tics)
|
|
tryDetonatorDelay -= tics;
|
|
else
|
|
tryDetonatorDelay = 0;
|
|
|
|
if ( buttonstate[bt_use] )
|
|
{
|
|
Cmd_Use();
|
|
SD_PlaySound(HITWALLSND);
|
|
}
|
|
|
|
if ( buttonstate[bt_attack] && !buttonheld[bt_attack])
|
|
Cmd_Fire ();
|
|
|
|
ControlMovement (ob);
|
|
HandleWeaponBounce();
|
|
|
|
|
|
// plux = player->x >> UNSIGNEDSHIFT; // scale to fit in unsigned
|
|
// pluy = player->y >> UNSIGNEDSHIFT;
|
|
player->tilex = player->x >> TILESHIFT; // scale to tile values
|
|
player->tiley = player->y >> TILESHIFT;
|
|
}
|
|
|
|
#if 0
|
|
//-------------------------------------------------------------------------
|
|
// RunBlakeRun()
|
|
//-------------------------------------------------------------------------
|
|
void RunBlakeRun()
|
|
{
|
|
#define BLAKE_SPEED (MOVESCALE*50)
|
|
|
|
long xmove,ymove,speed;
|
|
objtype *blake;
|
|
short startx,starty,dx,dy;
|
|
|
|
// Spawn Blake and set pointer.
|
|
//
|
|
SpawnPatrol(en_blake,player->tilex,player->tiley,player->dir>>1);
|
|
blake=new;
|
|
|
|
// Blake object starts one tile behind player object.
|
|
//
|
|
switch (blake->dir)
|
|
{
|
|
case north:
|
|
blake->tiley+=2;
|
|
break;
|
|
|
|
case south:
|
|
blake->tiley-=2;
|
|
break;
|
|
|
|
case east:
|
|
blake->tilex-=2;
|
|
break;
|
|
|
|
case west:
|
|
blake->tilex+=2;
|
|
break;
|
|
}
|
|
|
|
// Align Blake on the middle of the tile.
|
|
//
|
|
blake->x = ((long)blake->tilex<<TILESHIFT)+TILEGLOBAL/2;
|
|
blake->y = ((long)blake->tiley<<TILESHIFT)+TILEGLOBAL/2;
|
|
startx=blake->tilex = blake->x >> TILESHIFT;
|
|
starty=blake->tiley = blake->y >> TILESHIFT;
|
|
|
|
// Run, Blake, Run!
|
|
//
|
|
do
|
|
{
|
|
// Calc movement in X and Y directions.
|
|
//
|
|
xmove = FixedByFrac(BLAKE_SPEED,costable[player->angle]);
|
|
ymove = -FixedByFrac(BLAKE_SPEED,sintable[player->angle]);
|
|
|
|
// Move, animate, and redraw.
|
|
//
|
|
if (ClipMove(blake,xmove,ymove))
|
|
break;
|
|
DoActor(blake);
|
|
ThreeDRefresh();
|
|
|
|
// Calc new tile X/Y.
|
|
//
|
|
blake->tilex = blake->x >> TILESHIFT;
|
|
blake->tiley = blake->y >> TILESHIFT;
|
|
|
|
// Evaluate distance from start.
|
|
//
|
|
dx=blake->tilex-startx;
|
|
dx=ABS(dx);
|
|
dy=blake->tiley-starty;
|
|
dy=ABS(dy);
|
|
|
|
} while ((dx < 6) && (dy < 6));
|
|
}
|
|
|
|
#endif
|
|
|
|
//-------------------------------------------------------------------------
|
|
// SW_HandleActor() - Handle all actors connected to a smart switch.
|
|
//-------------------------------------------------------------------------
|
|
void SW_HandleActor(objtype *obj)
|
|
{
|
|
if (!obj->active)
|
|
obj->active = ac_yes;
|
|
|
|
switch (obj->obclass)
|
|
{
|
|
case rentacopobj:
|
|
case gen_scientistobj:
|
|
case swatobj:
|
|
case goldsternobj:
|
|
case proguardobj:
|
|
if (!(obj->flags & (FL_ATTACKMODE|FL_FIRSTATTACK)))
|
|
FirstSighting(obj);
|
|
break;
|
|
|
|
case morphing_spider_mutantobj:
|
|
case morphing_reptilian_warriorobj:
|
|
case morphing_mutanthuman2obj:
|
|
case crate1obj:
|
|
case crate2obj:
|
|
case crate3obj:
|
|
case podeggobj:
|
|
KillActor(obj);
|
|
break;
|
|
|
|
case gurney_waitobj:
|
|
case scan_wait_alienobj:
|
|
case lcan_wait_alienobj:
|
|
break;
|
|
|
|
// case electrosphereobj:
|
|
// break;
|
|
|
|
case floatingbombobj:
|
|
case volatiletransportobj:
|
|
if (obj->flags & FL_STATIONARY)
|
|
KillActor(obj);
|
|
else
|
|
if (!(obj->flags & (FL_ATTACKMODE|FL_FIRSTATTACK)))
|
|
FirstSighting(obj);
|
|
break;
|
|
|
|
case spider_mutantobj:
|
|
case breather_beastobj:
|
|
case cyborg_warriorobj:
|
|
case reptilian_warriorobj:
|
|
case acid_dragonobj:
|
|
case mech_guardianobj:
|
|
case liquidobj:
|
|
case genetic_guardobj:
|
|
case mutant_human1obj:
|
|
case mutant_human2obj:
|
|
case lcan_alienobj:
|
|
case scan_alienobj:
|
|
case gurneyobj:
|
|
case podobj:
|
|
case final_boss1obj:
|
|
case final_boss2obj:
|
|
case final_boss3obj:
|
|
case final_boss4obj:
|
|
if (!(obj->flags & (FL_ATTACKMODE|FL_FIRSTATTACK)))
|
|
FirstSighting(obj);
|
|
break;
|
|
|
|
// case electroobj:
|
|
// case liquidobj:
|
|
// break;
|
|
|
|
case post_barrierobj:
|
|
case arc_barrierobj:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
// SW_HandleStatic() - Handle all statics connected to a smart switch.
|
|
//-------------------------------------------------------------------------
|
|
void SW_HandleStatic(statobj_t *stat, unsigned tilex, unsigned tiley)
|
|
{
|
|
switch (stat->itemnumber)
|
|
{
|
|
case bo_clip:
|
|
case bo_clip2:
|
|
SpawnCusExplosion((((fixed)tilex)<<TILESHIFT)+0x7FFF,
|
|
(((fixed)tiley)<<TILESHIFT)+0x7FFF,
|
|
SPR_CLIP_EXP1, 7, 30+(US_RndT()&0x27),explosionobj);
|
|
stat->shapenum = -1;
|
|
stat->itemnumber = bo_nothing;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
// OperateSmartSwitch() - Operates a Smart Switch
|
|
//
|
|
// PARAMETERS:
|
|
// tilex - Tile X coord that the Smart switch points to.
|
|
// tiley - Tile Y coord that the Smart switch points to.
|
|
// force - Force switch operation. Will not check the players current
|
|
// and last tilex & tiley coords. This is usefull for other
|
|
// actors toggling barrier switches.
|
|
//
|
|
// RETURNS: Boolean: TRUE - Remove switch from map
|
|
// FALSE - Keep switch in map
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
boolean OperateSmartSwitch(unsigned tilex, unsigned tiley, char Operation, boolean Force)
|
|
{
|
|
typedef enum
|
|
{
|
|
wit_NOTHING,
|
|
wit_DOOR,
|
|
wit_WALL,
|
|
wit_STATIC,
|
|
wit_ACTOR,
|
|
} what_is_it;
|
|
|
|
what_is_it WhatItIs;
|
|
objtype *obj;
|
|
statobj_t *stat;
|
|
unsigned char tile, DoorNum;
|
|
unsigned iconnum;
|
|
|
|
//
|
|
// Get some information about what
|
|
// this switch is pointing to.
|
|
//
|
|
|
|
tile = tilemap[tilex][tiley];
|
|
obj = actorat[tilex][tiley];
|
|
iconnum = *(mapsegs[1]+farmapylookup[tiley]+tilex);
|
|
WhatItIs = wit_NOTHING;
|
|
|
|
//
|
|
// Deterimine if the switch points to an
|
|
// actor, door, wall, static or is Special.
|
|
//
|
|
|
|
if (obj < objlist)
|
|
{
|
|
if (obj == (objtype *)1 && tile == 0)
|
|
{
|
|
// We have a SOLID static!
|
|
|
|
WhatItIs = wit_STATIC;
|
|
}
|
|
else
|
|
{
|
|
if (tile)
|
|
{
|
|
//
|
|
// We have a wall of some type (maybe a door).
|
|
//
|
|
|
|
if (tile & 0x80)
|
|
{
|
|
// We have a door
|
|
|
|
WhatItIs = wit_DOOR;
|
|
DoorNum = tile & 0x7f;
|
|
}
|
|
else
|
|
{
|
|
// We have a wall
|
|
|
|
WhatItIs = wit_WALL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#pragma warn -pia
|
|
if (stat = FindStatic(tilex,tiley))
|
|
WhatItIs = wit_STATIC;
|
|
#pragma warn +pia
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (obj < &objlist[MAXACTORS])
|
|
{
|
|
// We have an actor.
|
|
|
|
WhatItIs = wit_ACTOR;
|
|
}
|
|
else
|
|
WhatItIs = wit_NOTHING;
|
|
}
|
|
|
|
//
|
|
// Ok... Now do that voodoo that you do so well...
|
|
//
|
|
|
|
switch (WhatItIs)
|
|
{
|
|
//
|
|
// Handle Doors
|
|
//
|
|
case wit_DOOR:
|
|
if (doorobjlist[DoorNum].action == dr_jammed)
|
|
return(false);
|
|
|
|
doorobjlist[DoorNum].lock = kt_none;
|
|
OpenDoor(DoorNum);
|
|
return(false);
|
|
|
|
|
|
//
|
|
// Handle Actors
|
|
//
|
|
case wit_ACTOR:
|
|
if (!(obj->flags & FL_DEADGUY))
|
|
SW_HandleActor(obj);
|
|
return(true);
|
|
|
|
|
|
//
|
|
// Handle Walls
|
|
//
|
|
case wit_WALL:
|
|
{
|
|
if (Force || player_oldtilex != player->tilex || player_oldtiley != player->tiley)
|
|
switch (tile)
|
|
{
|
|
case OFF_SWITCH:
|
|
if (Operation == ST_TURN_OFF)
|
|
return(false);
|
|
|
|
ActivateWallSwitch(iconnum, tilex, tiley);
|
|
break;
|
|
|
|
case ON_SWITCH:
|
|
if (Operation == ST_TURN_ON)
|
|
return(false);
|
|
ActivateWallSwitch(iconnum, tilex, tiley);
|
|
break;
|
|
}
|
|
}
|
|
return(false);
|
|
|
|
|
|
//
|
|
// Handle Statics
|
|
//
|
|
case wit_STATIC:
|
|
SW_HandleStatic(stat,tilex,tiley);
|
|
return (true);
|
|
|
|
|
|
//
|
|
// Handle NON connected smart switches...
|
|
//
|
|
case wit_NOTHING:
|
|
// Actor (or something) that was to be triggered has
|
|
// moved... SSSOOOoo, Remove the switch.
|
|
return(true);
|
|
}
|
|
|
|
return(false);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// WEAPON BOUNCE CODE
|
|
//
|
|
//==========================================================================
|
|
|
|
#define wb_MaxPoint ((long)10 << TILESHIFT)
|
|
#define wb_MidPoint ((long)6 << TILESHIFT)
|
|
#define wb_MinPoint ((long)2 << TILESHIFT)
|
|
#define wb_MaxGoalDist (wb_MaxPoint - wb_MidPoint)
|
|
|
|
#define wb_MaxOffset (wb_MaxPoint+((long)2 << TILESHIFT))
|
|
#define wb_MinOffset (wb_MinPoint-((long)2 << TILESHIFT))
|
|
|
|
extern fixed bounceOffset;
|
|
|
|
fixed bounceVel,bounceDest;
|
|
short bounceOk;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// InitWeaponBounce()
|
|
//--------------------------------------------------------------------------
|
|
void InitWeaponBounce()
|
|
{
|
|
bounceOffset = wb_MidPoint;
|
|
bounceDest = wb_MaxPoint;
|
|
bounceVel = bounceOk = 0;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// HandleWeaponBounce()
|
|
//--------------------------------------------------------------------------
|
|
void HandleWeaponBounce()
|
|
{
|
|
short bounceSpeed;
|
|
|
|
bounceSpeed = 90-((20-viewsize)*6);
|
|
|
|
if (bounceOk)
|
|
{
|
|
if (bounceOffset < bounceDest)
|
|
{
|
|
bounceVel += (sintable[bounceSpeed]+1) >> 1;
|
|
bounceOffset += bounceVel;
|
|
if (bounceOffset > bounceDest)
|
|
{
|
|
bounceDest = wb_MinPoint;
|
|
bounceVel >>= 2;
|
|
}
|
|
}
|
|
else
|
|
if (bounceOffset > bounceDest)
|
|
{
|
|
bounceVel -= sintable[bounceSpeed] >> 2;
|
|
bounceOffset += bounceVel;
|
|
|
|
if (bounceOffset < bounceDest)
|
|
{
|
|
bounceDest = wb_MaxPoint;
|
|
bounceVel >>= 2;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bounceOffset > wb_MidPoint)
|
|
{
|
|
bounceOffset -= ((long)2<<TILESHIFT);
|
|
if (bounceOffset < wb_MidPoint)
|
|
bounceOffset = wb_MidPoint;
|
|
}
|
|
else
|
|
if (bounceOffset < wb_MidPoint)
|
|
{
|
|
bounceOffset += ((long)2<<TILESHIFT);
|
|
if (bounceOffset > wb_MidPoint)
|
|
bounceOffset = wb_MidPoint;
|
|
}
|
|
|
|
bounceDest = wb_MaxPoint;
|
|
bounceVel = 0;
|
|
}
|
|
|
|
if (bounceOffset > wb_MaxOffset)
|
|
bounceOffset = wb_MaxOffset;
|
|
else
|
|
if (bounceOffset < wb_MinOffset)
|
|
bounceOffset = wb_MinOffset;
|
|
}
|
|
|