0,0 → 1,1530 |
// WL_STATE.C |
|
#include "wl_def.h" |
#pragma hdrstop |
|
/* |
============================================================================= |
|
LOCAL CONSTANTS |
|
============================================================================= |
*/ |
|
|
/* |
============================================================================= |
|
GLOBAL VARIABLES |
|
============================================================================= |
*/ |
|
|
static const dirtype opposite[9] = |
{west,southwest,south,southeast,east,northeast,north,northwest,nodir}; |
|
static const dirtype diagonal[9][9] = |
{ |
/* east */ {nodir,nodir,northeast,nodir,nodir,nodir,southeast,nodir,nodir}, |
{nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}, |
/* north */ {northeast,nodir,nodir,nodir,northwest,nodir,nodir,nodir,nodir}, |
{nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}, |
/* west */ {nodir,nodir,northwest,nodir,nodir,nodir,southwest,nodir,nodir}, |
{nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}, |
/* south */ {southeast,nodir,nodir,nodir,southwest,nodir,nodir,nodir,nodir}, |
{nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}, |
{nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir} |
}; |
|
|
|
void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state); |
void NewState (objtype *ob, statetype *state); |
|
boolean TryWalk (objtype *ob); |
void MoveObj (objtype *ob, int32_t move); |
|
void KillActor (objtype *ob); |
void DamageActor (objtype *ob, unsigned damage); |
|
boolean CheckLine (objtype *ob); |
void FirstSighting (objtype *ob); |
boolean CheckSight (objtype *ob); |
|
/* |
============================================================================= |
|
LOCAL VARIABLES |
|
============================================================================= |
*/ |
|
|
|
//=========================================================================== |
|
|
/* |
=================== |
= |
= SpawnNewObj |
= |
= Spaws a new actor at the given TILE coordinates, with the given state, and |
= the given size in GLOBAL units. |
= |
= newobj = a pointer to an initialized new actor |
= |
=================== |
*/ |
|
void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state) |
{ |
GetNewActor (); |
newobj->state = state; |
if (state->tictime) |
newobj->ticcount = DEMOCHOOSE_ORIG_SDL( |
US_RndT () % state->tictime, |
US_RndT () % state->tictime + 1); // Chris' moonwalk bugfix ;D |
else |
newobj->ticcount = 0; |
|
newobj->tilex = (short) tilex; |
newobj->tiley = (short) tiley; |
newobj->x = ((int32_t)tilex<<TILESHIFT)+TILEGLOBAL/2; |
newobj->y = ((int32_t)tiley<<TILESHIFT)+TILEGLOBAL/2; |
newobj->dir = nodir; |
|
actorat[tilex][tiley] = newobj; |
newobj->areanumber = |
*(mapsegs[0] + (newobj->tiley<<mapshift)+newobj->tilex) - AREATILE; |
} |
|
|
|
/* |
=================== |
= |
= NewState |
= |
= Changes ob to a new state, setting ticcount to the max for that state |
= |
=================== |
*/ |
|
void NewState (objtype *ob, statetype *state) |
{ |
ob->state = state; |
ob->ticcount = state->tictime; |
} |
|
|
|
/* |
============================================================================= |
|
ENEMY TILE WORLD MOVEMENT CODE |
|
============================================================================= |
*/ |
|
|
/* |
================================== |
= |
= TryWalk |
= |
= Attempts to move ob in its current (ob->dir) direction. |
= |
= If blocked by either a wall or an actor returns FALSE |
= |
= If move is either clear or blocked only by a door, returns TRUE and sets |
= |
= ob->tilex = new destination |
= ob->tiley |
= ob->areanumber = the floor tile number (0-(NUMAREAS-1)) of destination |
= ob->distance = TILEGLOBAl, or -doornumber if a door is blocking the way |
= |
= If a door is in the way, an OpenDoor call is made to start it opening. |
= The actor code should wait until |
= doorobjlist[-ob->distance].action = dr_open, meaning the door has been |
= fully opened |
= |
================================== |
*/ |
|
#define CHECKDIAG(x,y) \ |
{ \ |
temp=(uintptr_t)actorat[x][y]; \ |
if (temp) \ |
{ \ |
if (temp<256) \ |
return false; \ |
if (((objtype *)temp)->flags&FL_SHOOTABLE) \ |
return false; \ |
} \ |
} |
|
#ifdef PLAYDEMOLIKEORIGINAL |
#define DOORCHECK \ |
if(DEMOCOND_ORIG) \ |
doornum = temp&63; \ |
else \ |
{ \ |
doornum = (int) temp & 127; \ |
OpenDoor(doornum); \ |
ob->distance = -doornum - 1; \ |
return true; \ |
} |
#else |
#define DOORCHECK \ |
doornum = (int) temp & 127; \ |
OpenDoor(doornum); \ |
ob->distance = -doornum - 1; \ |
return true; |
#endif |
|
#define CHECKSIDE(x,y) \ |
{ \ |
temp=(uintptr_t)actorat[x][y]; \ |
if (temp) \ |
{ \ |
if (temp<128) \ |
return false; \ |
if (temp<256) \ |
{ \ |
DOORCHECK \ |
} \ |
else if (((objtype *)temp)->flags&FL_SHOOTABLE) \ |
return false; \ |
} \ |
} |
|
|
boolean TryWalk (objtype *ob) |
{ |
int doornum = -1; |
uintptr_t temp; |
|
if (ob->obclass == inertobj) |
{ |
switch (ob->dir) |
{ |
case north: |
ob->tiley--; |
break; |
|
case northeast: |
ob->tilex++; |
ob->tiley--; |
break; |
|
case east: |
ob->tilex++; |
break; |
|
case southeast: |
ob->tilex++; |
ob->tiley++; |
break; |
|
case south: |
ob->tiley++; |
break; |
|
case southwest: |
ob->tilex--; |
ob->tiley++; |
break; |
|
case west: |
ob->tilex--; |
break; |
|
case northwest: |
ob->tilex--; |
ob->tiley--; |
break; |
} |
} |
else |
{ |
switch (ob->dir) |
{ |
case north: |
if (ob->obclass == dogobj || ob->obclass == fakeobj |
|| ob->obclass == ghostobj || ob->obclass == spectreobj) |
{ |
CHECKDIAG(ob->tilex,ob->tiley-1); |
} |
else |
{ |
CHECKSIDE(ob->tilex,ob->tiley-1); |
} |
ob->tiley--; |
break; |
|
case northeast: |
CHECKDIAG(ob->tilex+1,ob->tiley-1); |
CHECKDIAG(ob->tilex+1,ob->tiley); |
CHECKDIAG(ob->tilex,ob->tiley-1); |
ob->tilex++; |
ob->tiley--; |
break; |
|
case east: |
if (ob->obclass == dogobj || ob->obclass == fakeobj |
|| ob->obclass == ghostobj || ob->obclass == spectreobj) |
{ |
CHECKDIAG(ob->tilex+1,ob->tiley); |
} |
else |
{ |
CHECKSIDE(ob->tilex+1,ob->tiley); |
} |
ob->tilex++; |
break; |
|
case southeast: |
CHECKDIAG(ob->tilex+1,ob->tiley+1); |
CHECKDIAG(ob->tilex+1,ob->tiley); |
CHECKDIAG(ob->tilex,ob->tiley+1); |
ob->tilex++; |
ob->tiley++; |
break; |
|
case south: |
if (ob->obclass == dogobj || ob->obclass == fakeobj |
|| ob->obclass == ghostobj || ob->obclass == spectreobj) |
{ |
CHECKDIAG(ob->tilex,ob->tiley+1); |
} |
else |
{ |
CHECKSIDE(ob->tilex,ob->tiley+1); |
} |
ob->tiley++; |
break; |
|
case southwest: |
CHECKDIAG(ob->tilex-1,ob->tiley+1); |
CHECKDIAG(ob->tilex-1,ob->tiley); |
CHECKDIAG(ob->tilex,ob->tiley+1); |
ob->tilex--; |
ob->tiley++; |
break; |
|
case west: |
if (ob->obclass == dogobj || ob->obclass == fakeobj |
|| ob->obclass == ghostobj || ob->obclass == spectreobj) |
{ |
CHECKDIAG(ob->tilex-1,ob->tiley); |
} |
else |
{ |
CHECKSIDE(ob->tilex-1,ob->tiley); |
} |
ob->tilex--; |
break; |
|
case northwest: |
CHECKDIAG(ob->tilex-1,ob->tiley-1); |
CHECKDIAG(ob->tilex-1,ob->tiley); |
CHECKDIAG(ob->tilex,ob->tiley-1); |
ob->tilex--; |
ob->tiley--; |
break; |
|
case nodir: |
return false; |
|
default: |
Quit ("Walk: Bad dir"); |
} |
} |
|
#ifdef PLAYDEMOLIKEORIGINAL |
if (DEMOCOND_ORIG && doornum != -1) |
{ |
OpenDoor(doornum); |
ob->distance = -doornum-1; |
return true; |
} |
#endif |
|
ob->areanumber = |
*(mapsegs[0] + (ob->tiley<<mapshift)+ob->tilex) - AREATILE; |
|
ob->distance = TILEGLOBAL; |
return true; |
} |
|
|
/* |
================================== |
= |
= SelectDodgeDir |
= |
= Attempts to choose and initiate a movement for ob that sends it towards |
= the player while dodging |
= |
= If there is no possible move (ob is totally surrounded) |
= |
= ob->dir = nodir |
= |
= Otherwise |
= |
= ob->dir = new direction to follow |
= ob->distance = TILEGLOBAL or -doornumber |
= ob->tilex = new destination |
= ob->tiley |
= ob->areanumber = the floor tile number (0-(NUMAREAS-1)) of destination |
= |
================================== |
*/ |
|
void SelectDodgeDir (objtype *ob) |
{ |
int deltax,deltay,i; |
unsigned absdx,absdy; |
dirtype dirtry[5]; |
dirtype turnaround,tdir; |
|
if (ob->flags & FL_FIRSTATTACK) |
{ |
// |
// turning around is only ok the very first time after noticing the |
// player |
// |
turnaround = nodir; |
ob->flags &= ~FL_FIRSTATTACK; |
} |
else |
turnaround=opposite[ob->dir]; |
|
deltax = player->tilex - ob->tilex; |
deltay = player->tiley - ob->tiley; |
|
// |
// arange 5 direction choices in order of preference |
// the four cardinal directions plus the diagonal straight towards |
// the player |
// |
|
if (deltax>0) |
{ |
dirtry[1]= east; |
dirtry[3]= west; |
} |
else |
{ |
dirtry[1]= west; |
dirtry[3]= east; |
} |
|
if (deltay>0) |
{ |
dirtry[2]= south; |
dirtry[4]= north; |
} |
else |
{ |
dirtry[2]= north; |
dirtry[4]= south; |
} |
|
// |
// randomize a bit for dodging |
// |
absdx = abs(deltax); |
absdy = abs(deltay); |
|
if (absdx > absdy) |
{ |
tdir = dirtry[1]; |
dirtry[1] = dirtry[2]; |
dirtry[2] = tdir; |
tdir = dirtry[3]; |
dirtry[3] = dirtry[4]; |
dirtry[4] = tdir; |
} |
|
if (US_RndT() < 128) |
{ |
tdir = dirtry[1]; |
dirtry[1] = dirtry[2]; |
dirtry[2] = tdir; |
tdir = dirtry[3]; |
dirtry[3] = dirtry[4]; |
dirtry[4] = tdir; |
} |
|
dirtry[0] = diagonal [ dirtry[1] ] [ dirtry[2] ]; |
|
// |
// try the directions util one works |
// |
for (i=0;i<5;i++) |
{ |
if ( dirtry[i] == nodir || dirtry[i] == turnaround) |
continue; |
|
ob->dir = dirtry[i]; |
if (TryWalk(ob)) |
return; |
} |
|
// |
// turn around only as a last resort |
// |
if (turnaround != nodir) |
{ |
ob->dir = turnaround; |
|
if (TryWalk(ob)) |
return; |
} |
|
ob->dir = nodir; |
} |
|
|
/* |
============================ |
= |
= SelectChaseDir |
= |
= As SelectDodgeDir, but doesn't try to dodge |
= |
============================ |
*/ |
|
void SelectChaseDir (objtype *ob) |
{ |
int deltax,deltay; |
dirtype d[3]; |
dirtype tdir, olddir, turnaround; |
|
|
olddir=ob->dir; |
turnaround=opposite[olddir]; |
|
deltax=player->tilex - ob->tilex; |
deltay=player->tiley - ob->tiley; |
|
d[1]=nodir; |
d[2]=nodir; |
|
if (deltax>0) |
d[1]= east; |
else if (deltax<0) |
d[1]= west; |
if (deltay>0) |
d[2]=south; |
else if (deltay<0) |
d[2]=north; |
|
if (abs(deltay)>abs(deltax)) |
{ |
tdir=d[1]; |
d[1]=d[2]; |
d[2]=tdir; |
} |
|
if (d[1]==turnaround) |
d[1]=nodir; |
if (d[2]==turnaround) |
d[2]=nodir; |
|
|
if (d[1]!=nodir) |
{ |
ob->dir=d[1]; |
if (TryWalk(ob)) |
return; /*either moved forward or attacked*/ |
} |
|
if (d[2]!=nodir) |
{ |
ob->dir=d[2]; |
if (TryWalk(ob)) |
return; |
} |
|
/* there is no direct path to the player, so pick another direction */ |
|
if (olddir!=nodir) |
{ |
ob->dir=olddir; |
if (TryWalk(ob)) |
return; |
} |
|
if (US_RndT()>128) /*randomly determine direction of search*/ |
{ |
for (tdir=north; tdir<=west; tdir=(dirtype)(tdir+1)) |
{ |
if (tdir!=turnaround) |
{ |
ob->dir=tdir; |
if ( TryWalk(ob) ) |
return; |
} |
} |
} |
else |
{ |
for (tdir=west; tdir>=north; tdir=(dirtype)(tdir-1)) |
{ |
if (tdir!=turnaround) |
{ |
ob->dir=tdir; |
if ( TryWalk(ob) ) |
return; |
} |
} |
} |
|
if (turnaround != nodir) |
{ |
ob->dir=turnaround; |
if (ob->dir != nodir) |
{ |
if ( TryWalk(ob) ) |
return; |
} |
} |
|
ob->dir = nodir; // can't move |
} |
|
|
/* |
============================ |
= |
= SelectRunDir |
= |
= Run Away from player |
= |
============================ |
*/ |
|
void SelectRunDir (objtype *ob) |
{ |
int deltax,deltay; |
dirtype d[3]; |
dirtype tdir; |
|
|
deltax=player->tilex - ob->tilex; |
deltay=player->tiley - ob->tiley; |
|
if (deltax<0) |
d[1]= east; |
else |
d[1]= west; |
if (deltay<0) |
d[2]=south; |
else |
d[2]=north; |
|
if (abs(deltay)>abs(deltax)) |
{ |
tdir=d[1]; |
d[1]=d[2]; |
d[2]=tdir; |
} |
|
ob->dir=d[1]; |
if (TryWalk(ob)) |
return; /*either moved forward or attacked*/ |
|
ob->dir=d[2]; |
if (TryWalk(ob)) |
return; |
|
/* there is no direct path to the player, so pick another direction */ |
|
if (US_RndT()>128) /*randomly determine direction of search*/ |
{ |
for (tdir=north; tdir<=west; tdir=(dirtype)(tdir+1)) |
{ |
ob->dir=tdir; |
if ( TryWalk(ob) ) |
return; |
} |
} |
else |
{ |
for (tdir=west; tdir>=north; tdir=(dirtype)(tdir-1)) |
{ |
ob->dir=tdir; |
if ( TryWalk(ob) ) |
return; |
} |
} |
|
ob->dir = nodir; // can't move |
} |
|
|
/* |
================= |
= |
= MoveObj |
= |
= Moves ob be move global units in ob->dir direction |
= Actors are not allowed to move inside the player |
= Does NOT check to see if the move is tile map valid |
= |
= ob->x = adjusted for new position |
= ob->y |
= |
================= |
*/ |
|
void MoveObj (objtype *ob, int32_t move) |
{ |
int32_t deltax,deltay; |
|
switch (ob->dir) |
{ |
case north: |
ob->y -= move; |
break; |
case northeast: |
ob->x += move; |
ob->y -= move; |
break; |
case east: |
ob->x += move; |
break; |
case southeast: |
ob->x += move; |
ob->y += move; |
break; |
case south: |
ob->y += move; |
break; |
case southwest: |
ob->x -= move; |
ob->y += move; |
break; |
case west: |
ob->x -= move; |
break; |
case northwest: |
ob->x -= move; |
ob->y -= move; |
break; |
|
case nodir: |
return; |
|
default: |
Quit ("MoveObj: bad dir!"); |
} |
|
// |
// check to make sure it's not on top of player |
// |
if (areabyplayer[ob->areanumber]) |
{ |
deltax = ob->x - player->x; |
if (deltax < -MINACTORDIST || deltax > MINACTORDIST) |
goto moveok; |
deltay = ob->y - player->y; |
if (deltay < -MINACTORDIST || deltay > MINACTORDIST) |
goto moveok; |
|
if (ob->hidden) // move closer until he meets CheckLine |
goto moveok; |
|
if (ob->obclass == ghostobj || ob->obclass == spectreobj) |
TakeDamage (tics*2,ob); |
|
// |
// back up |
// |
switch (ob->dir) |
{ |
case north: |
ob->y += move; |
break; |
case northeast: |
ob->x -= move; |
ob->y += move; |
break; |
case east: |
ob->x -= move; |
break; |
case southeast: |
ob->x -= move; |
ob->y -= move; |
break; |
case south: |
ob->y -= move; |
break; |
case southwest: |
ob->x += move; |
ob->y -= move; |
break; |
case west: |
ob->x += move; |
break; |
case northwest: |
ob->x += move; |
ob->y += move; |
break; |
|
case nodir: |
return; |
} |
return; |
} |
moveok: |
ob->distance -=move; |
} |
|
/* |
============================================================================= |
|
STUFF |
|
============================================================================= |
*/ |
|
/* |
=============== |
= |
= DropItem |
= |
= Tries to drop a bonus item somewhere in the tiles surrounding the |
= given tilex/tiley |
= |
=============== |
*/ |
|
void DropItem (wl_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 = (word)(ob->x >> TILESHIFT); // drop item on center |
tiley = ob->tiley = (word)(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); |
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); |
break; |
#else |
case spectreobj: |
if (ob->flags&FL_BONUS) |
{ |
GivePoints (200); // Get points once for each |
ob->flags &= ~FL_BONUS; |
} |
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 -= (short)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 hit point |
{ |
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 partial,delta; |
int32_t 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 = ((int32_t)delta<<8)/deltafrac; |
if (ltemp > 0x7fffl) |
ystep = 0x7fff; |
else if (ltemp < -0x7fffl) |
ystep = -0x7fff; |
else |
ystep = ltemp; |
yfrac = y1 + (((int32_t)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 = ((int32_t)delta<<8)/deltafrac; |
if (ltemp > 0x7fffl) |
xstep = 0x7fff; |
else if (ltemp < -0x7fffl) |
xstep = -0x7fff; |
else |
xstep = ltemp; |
xfrac = x1 + (((int32_t)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) |
{ |
int32_t 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; |
|
// check diagonal moving guards fix |
|
case northwest: |
if (DEMOCOND_SDL && deltay > -deltax) |
return false; |
break; |
|
case northeast: |
if (DEMOCOND_SDL && deltay > deltax) |
return false; |
break; |
|
case southwest: |
if (DEMOCOND_SDL && deltax > deltay) |
return false; |
break; |
|
case southeast: |
if (DEMOCOND_SDL && -deltax > deltay) |
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; |
|
#ifndef APOGEE_1_0 |
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; |
#endif |
|
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 -= (short) 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; |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |