/*
=============================================================================
STUFF
=============================================================================
*/
/*
===============
=
= DropItem
=
= Tries to drop a bonus item somewhere in the tiles surrounding the
= given tilex/tiley
=
===============
*/
void DropItem (stat_t itemtype, int tilex, int tiley)
{
int x,y,xl,xh,yl,yh;
//
// find a free spot to put it in
//
if (!actorat[tilex][tiley])
{
PlaceItemType (itemtype, tilex,tiley);
return;
}
xl = tilex-1;
xh = tilex+1;
yl = tiley-1;
yh = tiley+1;
for (x=xl ; x = xh ; x++)
for (y=yl ; y = yh ; y++)
if (!actorat[x][y])
{
PlaceItemType (itemtype, x,y);
return;
}
}
/*
===============
=
= KillActor
=
===============
*/
void KillActor (objtype *ob)
{
int tilex,tiley;
tilex = ob->tilex = ob->x >> TILESHIFT; // drop item on center
tiley = ob->tiley = ob->y >> TILESHIFT;
switch (ob->obclass)
{
case guardobj:
GivePoints (100);
NewState (ob,&s_grddie1);
PlaceItemType (bo_clip2,tilex,tiley);
break;
case officerobj:
GivePoints (400);
NewState (ob,&s_ofcdie1);
PlaceItemType (bo_clip2,tilex,tiley);
break;
case mutantobj:
GivePoints (700);
NewState (ob,&s_mutdie1);
PlaceItemType (bo_clip2,tilex,tiley);
break;
case ssobj:
GivePoints (500);
NewState (ob,&s_ssdie1);
if (gamestate.bestweapon wp_machinegun)
PlaceItemType (bo_machinegun,tilex,tiley);
else
PlaceItemType (bo_clip2,tilex,tiley);
break;
case dogobj:
GivePoints (200);
NewState (ob,&s_dogdie1);
break;
#ifndef SPEAR
case bossobj:
GivePoints (5000);
NewState (ob,&s_bossdie1);
PlaceItemType (bo_key1,tilex,tiley);
break;
case gretelobj:
GivePoints (5000);
NewState (ob,&s_greteldie1);
PlaceItemType (bo_key1,tilex,tiley);
break;
case giftobj:
GivePoints (5000);
gamestate.killx = player->x;
gamestate.killy = player->y;
NewState (ob,&s_giftdie1);
break;
case fatobj:
GivePoints (5000);
gamestate.killx = player->x;
gamestate.killy = player->y;
NewState (ob,&s_fatdie1);
break;
case schabbobj:
GivePoints (5000);
gamestate.killx = player->x;
gamestate.killy = player->y;
NewState (ob,&s_schabbdie1);
A_DeathScream(ob);
break;
case fakeobj:
GivePoints (2000);
NewState (ob,&s_fakedie1);
break;
case mechahitlerobj:
GivePoints (5000);
NewState (ob,&s_mechadie1);
break;
case realhitlerobj:
GivePoints (5000);
gamestate.killx = player->x;
gamestate.killy = player->y;
NewState (ob,&s_hitlerdie1);
A_DeathScream(ob);
break;
#else
case spectreobj:
GivePoints (200);
NewState (ob,&s_spectredie1);
break;
case angelobj:
GivePoints (5000);
NewState (ob,&s_angeldie1);
break;
case transobj:
GivePoints (5000);
NewState (ob,&s_transdie0);
PlaceItemType (bo_key1,tilex,tiley);
break;
case uberobj:
GivePoints (5000);
NewState (ob,&s_uberdie0);
PlaceItemType (bo_key1,tilex,tiley);
break;
case willobj:
GivePoints (5000);
NewState (ob,&s_willdie1);
PlaceItemType (bo_key1,tilex,tiley);
break;
case deathobj:
GivePoints (5000);
NewState (ob,&s_deathdie1);
PlaceItemType (bo_key1,tilex,tiley);
break;
#endif
}
gamestate.killcount++;
ob->flags &= ~FL_SHOOTABLE;
actorat[ob->tilex][ob->tiley] = NULL;
ob->flags |= FL_NONMARK;
}
/*
===================
=
= DamageActor
=
= Called when the player succesfully hits an enemy.
=
= Does damage points to enemy ob, either putting it into a stun frame or
= killing it.
=
===================
*/
void DamageActor (objtype *ob, unsigned damage)
{
madenoise = true;
//
// do double damage if shooting a non attack mode actor
//
if ( !(ob->flags & FL_ATTACKMODE) )
damage = 1;
ob->hitpoints -= damage;
if (ob->hitpoints =0)
KillActor (ob);
else
{
if (! (ob->flags & FL_ATTACKMODE) )
FirstSighting (ob); // put into combat mode
switch (ob->obclass) // dogs only have one hitpoint
{
case guardobj:
if (ob->hitpoints&1)
NewState (ob,&s_grdpain);
else
NewState (ob,&s_grdpain1);
break;
case officerobj:
if (ob->hitpoints&1)
NewState (ob,&s_ofcpain);
else
NewState (ob,&s_ofcpain1);
break;
case mutantobj:
if (ob->hitpoints&1)
NewState (ob,&s_mutpain);
else
NewState (ob,&s_mutpain1);
break;
case ssobj:
if (ob->hitpoints&1)
NewState (ob,&s_sspain);
else
NewState (ob,&s_sspain1);
break;
}
}
}
/*
=============================================================================
CHECKSIGHT
=============================================================================
*/
/*
=====================
=
= CheckLine
=
= returns true if a straight line between the player and ob is unobstructed
=
=====================
*/
boolean CheckLine (objtype *ob)
{
int x1,y1,xt1,yt1,x2,y2,xt2,yt2;
int x,y;
int xdist,ydist,xstep,ystep;
int temp;
int partial,delta;
long ltemp;
int xfrac,yfrac,deltafrac;
unsigned value,intercept;
x1 = ob->x >> unsignedSHIFT; // 1/256 tile precision
y1 = ob->y >> unsignedSHIFT;
xt1 = x1 >> 8;
yt1 = y1 >> 8;
x2 = plux;
y2 = pluy;
xt2 = player->tilex;
yt2 = player->tiley;
xdist = abs(xt2-xt1);
if (xdist > 0)
{
if (xt2 > xt1)
{
partial = 256-(x1&0xff);
xstep = 1;
}
else
{
partial = x1&0xff;
xstep = -1;
}
deltafrac = abs(x2-x1);
delta = y2-y1;
ltemp = ((long)delta 8)/deltafrac;
if (ltemp > 0x7fffl)
ystep = 0x7fff;
else if (ltemp -0x7fffl)
ystep = -0x7fff;
else
ystep = ltemp;
yfrac = y1 + (((long)ystep*partial) >>8);
x = xt1+xstep;
xt2 += xstep;
do
{
y = yfrac>>8;
yfrac += ystep;
value = (unsigned)tilemap[x][y];
x += xstep;
if (!value)
continue;
if (value 128 || value>256)
return false;
//
// see if the door is open enough
//
value &= ~0x80;
intercept = yfrac-ystep/2;
if (intercept>doorposition[value])
return false;
} while (x != xt2);
}
ydist = abs(yt2-yt1);
if (ydist > 0)
{
if (yt2 > yt1)
{
partial = 256-(y1&0xff);
ystep = 1;
}
else
{
partial = y1&0xff;
ystep = -1;
}
deltafrac = abs(y2-y1);
delta = x2-x1;
ltemp = ((long)delta 8)/deltafrac;
if (ltemp > 0x7fffl)
xstep = 0x7fff;
else if (ltemp -0x7fffl)
xstep = -0x7fff;
else
xstep = ltemp;
xfrac = x1 + (((long)xstep*partial) >>8);
y = yt1 + ystep;
yt2 += ystep;
do
{
x = xfrac>>8;
xfrac += xstep;
value = (unsigned)tilemap[x][y];
y += ystep;
if (!value)
continue;
if (value 128 || value>256)
return false;
//
// see if the door is open enough
//
value &= ~0x80;
intercept = xfrac-xstep/2;
if (intercept>doorposition[value])
return false;
} while (y != yt2);
}
return true;
}
/*
================
=
= CheckSight
=
= Checks a straight line between player and current object
=
= if the sight is ok, check alertness and angle to see if they notice
=
= returns true if the player has been spoted
=
================
*/
#define MINSIGHT 0x18000l
boolean CheckSight (objtype *ob)
{
long deltax,deltay;
//
// don't bother tracing a line if the area isn't connected to the player's
//
if (!areabyplayer[ob->areanumber])
return false;
//
// if the player is real close, sight is automatic
//
deltax = player->x - ob->x;
deltay = player->y - ob->y;
if (deltax > -MINSIGHT && deltax MINSIGHT
&& deltay > -MINSIGHT && deltay MINSIGHT)
return true;
//
// see if they are looking in the right direction
//
switch (ob->dir)
{
case north:
if (deltay > 0)
return false;
break;
case east:
if (deltax 0)
return false;
break;
case south:
if (deltay 0)
return false;
break;
case west:
if (deltax > 0)
return false;
break;
}
//
// trace a line to check for blocking tiles (corners)
//
return CheckLine (ob);
}
/*
===============
=
= FirstSighting
=
= Puts an actor into attack mode and possibly reverses the direction
= if the player is behind it
=
===============
*/
void FirstSighting (objtype *ob)
{
//
// react to the player
//
switch (ob->obclass)
{
case guardobj:
PlaySoundLocActor(HALTSND,ob);
NewState (ob,&s_grdchase1);
ob->speed *= 3; // go faster when chasing player
break;
case officerobj:
PlaySoundLocActor(SPIONSND,ob);
NewState (ob,&s_ofcchase1);
ob->speed *= 5; // go faster when chasing player
break;
case mutantobj:
NewState (ob,&s_mutchase1);
ob->speed *= 3; // go faster when chasing player
break;
case ssobj:
PlaySoundLocActor(SCHUTZADSND,ob);
NewState (ob,&s_sschase1);
ob->speed *= 4; // go faster when chasing player
break;
case dogobj:
PlaySoundLocActor(DOGBARKSND,ob);
NewState (ob,&s_dogchase1);
ob->speed *= 2; // go faster when chasing player
break;
#ifndef SPEAR
case bossobj:
SD_PlaySound(GUTENTAGSND);
NewState (ob,&s_bosschase1);
ob->speed = SPDPATROL*3; // go faster when chasing player
break;
case gretelobj:
SD_PlaySound(KEINSND);
NewState (ob,&s_gretelchase1);
ob->speed *= 3; // go faster when chasing player
break;
case giftobj:
SD_PlaySound(EINESND);
NewState (ob,&s_giftchase1);
ob->speed *= 3; // go faster when chasing player
break;
case fatobj:
SD_PlaySound(ERLAUBENSND);
NewState (ob,&s_fatchase1);
ob->speed *= 3; // go faster when chasing player
break;
case schabbobj:
SD_PlaySound(SCHABBSHASND);
NewState (ob,&s_schabbchase1);
ob->speed *= 3; // go faster when chasing player
break;
case fakeobj:
SD_PlaySound(TOT_HUNDSND);
NewState (ob,&s_fakechase1);
ob->speed *= 3; // go faster when chasing player
break;
case mechahitlerobj:
SD_PlaySound(DIESND);
NewState (ob,&s_mechachase1);
ob->speed *= 3; // go faster when chasing player
break;
case realhitlerobj:
SD_PlaySound(DIESND);
NewState (ob,&s_hitlerchase1);
ob->speed *= 5; // go faster when chasing player
break;
case ghostobj:
NewState (ob,&s_blinkychase1);
ob->speed *= 2; // go faster when chasing player
break;
#else
case spectreobj:
SD_PlaySound(GHOSTSIGHTSND);
NewState (ob,&s_spectrechase1);
ob->speed = 800; // go faster when chasing player
break;
case angelobj:
SD_PlaySound(ANGELSIGHTSND);
NewState (ob,&s_angelchase1);
ob->speed = 1536; // go faster when chasing player
break;
case transobj:
SD_PlaySound(TRANSSIGHTSND);
NewState (ob,&s_transchase1);
ob->speed = 1536; // go faster when chasing player
break;
case uberobj:
NewState (ob,&s_uberchase1);
ob->speed = 3000; // go faster when chasing player
break;
case willobj:
SD_PlaySound(WILHELMSIGHTSND);
NewState (ob,&s_willchase1);
ob->speed = 2048; // go faster when chasing player
break;
case deathobj:
SD_PlaySound(KNIGHTSIGHTSND);
NewState (ob,&s_deathchase1);
ob->speed = 2048; // go faster when chasing player
break;
#endif
}
if (ob->distance 0)
ob->distance = 0; // ignore the door opening command
ob->flags |= FL_ATTACKMODE|FL_FIRSTATTACK;
}
/*
===============
=
= SightPlayer
=
= Called by actors that ARE NOT chasing the player. if the player
= is detected (by sight, noise, or proximity), the actor is put into
= it's combat frame and true is returned.
=
= Incorporates a random reaction delay
=
===============
*/
boolean SightPlayer (objtype *ob)
{
if (ob->flags & FL_ATTACKMODE)
Quit ("An actor in ATTACKMODE called SightPlayer!");
if (ob->temp2)
{
//
// count down reaction time
//
ob->temp2 -= tics;
if (ob->temp2 > 0)
return false;
ob->temp2 = 0; // time to react
}
else
{
if (!areabyplayer[ob->areanumber])
return false;
if (ob->flags & FL_AMBUSH)
{
if (!CheckSight (ob))
return false;
ob->flags &= ~FL_AMBUSH;
}
else
{
if (!madenoise && !CheckSight (ob))
return false;
}
switch (ob->obclass)
{
case guardobj:
ob->temp2 = 1+US_RndT()/4;
break;
case officerobj:
ob->temp2 = 2;
break;
case mutantobj:
ob->temp2 = 1+US_RndT()/6;
break;
case ssobj:
ob->temp2 = 1+US_RndT()/6;
break;
case dogobj:
ob->temp2 = 1+US_RndT()/8;
break;
case bossobj:
case schabbobj:
case fakeobj:
case mechahitlerobj:
case realhitlerobj:
case gretelobj:
case giftobj:
case fatobj:
case spectreobj:
case angelobj:
case transobj:
case uberobj:
case willobj:
case deathobj:
ob->temp2 = 1;
break;
}
return false;
}
FirstSighting (ob);
return true;
}