diff options
Diffstat (limited to 'apps/plugins/sdl/progs/wolf3d/wl_state.c')
-rw-r--r-- | apps/plugins/sdl/progs/wolf3d/wl_state.c | 1530 |
1 files changed, 1530 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/wolf3d/wl_state.c b/apps/plugins/sdl/progs/wolf3d/wl_state.c new file mode 100644 index 0000000000..92b8ca1713 --- /dev/null +++ b/apps/plugins/sdl/progs/wolf3d/wl_state.c @@ -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; +} |