--- /dev/null
+// WL_STATE.C\r
+\r
+#include "WL_DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+ LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+ GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+dirtype opposite[9] =\r
+ {west,southwest,south,southeast,east,northeast,north,northwest,nodir};\r
+\r
+dirtype diagonal[9][9] =\r
+{\r
+/* east */ {nodir,nodir,northeast,nodir,nodir,nodir,southeast,nodir,nodir},\r
+ {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},\r
+/* north */ {northeast,nodir,nodir,nodir,northwest,nodir,nodir,nodir,nodir},\r
+ {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},\r
+/* west */ {nodir,nodir,northwest,nodir,nodir,nodir,southwest,nodir,nodir},\r
+ {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},\r
+/* south */ {southeast,nodir,nodir,nodir,southwest,nodir,nodir,nodir,nodir},\r
+ {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},\r
+ {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}\r
+};\r
+\r
+\r
+\r
+void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state);\r
+void NewState (objtype *ob, statetype *state);\r
+\r
+boolean TryWalk (objtype *ob);\r
+void MoveObj (objtype *ob, long move);\r
+\r
+void KillActor (objtype *ob);\r
+void DamageActor (objtype *ob, unsigned damage);\r
+\r
+boolean CheckLine (objtype *ob);\r
+void FirstSighting (objtype *ob);\r
+boolean CheckSight (objtype *ob);\r
+\r
+/*\r
+=============================================================================\r
+\r
+ LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= SpawnNewObj\r
+=\r
+= Spaws a new actor at the given TILE coordinates, with the given state, and\r
+= the given size in GLOBAL units.\r
+=\r
+= new = a pointer to an initialized new actor\r
+=\r
+===================\r
+*/\r
+\r
+void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state)\r
+{\r
+ GetNewActor ();\r
+ new->state = state;\r
+ if (state->tictime)\r
+ new->ticcount = US_RndT () % state->tictime;\r
+ else\r
+ new->ticcount = 0;\r
+\r
+ new->tilex = tilex;\r
+ new->tiley = tiley;\r
+ new->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+ new->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+ new->dir = nodir;\r
+\r
+ actorat[tilex][tiley] = new;\r
+ new->areanumber =\r
+ *(mapsegs[0] + farmapylookup[new->tiley]+new->tilex) - AREATILE;\r
+}\r
+\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= NewState\r
+=\r
+= Changes ob to a new state, setting ticcount to the max for that state\r
+=\r
+===================\r
+*/\r
+\r
+void NewState (objtype *ob, statetype *state)\r
+{\r
+ ob->state = state;\r
+ ob->ticcount = state->tictime;\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+ ENEMY TILE WORLD MOVEMENT CODE\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+==================================\r
+=\r
+= TryWalk\r
+=\r
+= Attempts to move ob in its current (ob->dir) direction.\r
+=\r
+= If blocked by either a wall or an actor returns FALSE\r
+=\r
+= If move is either clear or blocked only by a door, returns TRUE and sets\r
+=\r
+= ob->tilex = new destination\r
+= ob->tiley\r
+= ob->areanumber = the floor tile number (0-(NUMAREAS-1)) of destination\r
+= ob->distance = TILEGLOBAl, or -doornumber if a door is blocking the way\r
+=\r
+= If a door is in the way, an OpenDoor call is made to start it opening.\r
+= The actor code should wait until\r
+= doorobjlist[-ob->distance].action = dr_open, meaning the door has been\r
+= fully opened\r
+=\r
+==================================\r
+*/\r
+\r
+#define CHECKDIAG(x,y) \\r
+{ \\r
+ temp=(unsigned)actorat[x][y]; \\r
+ if (temp) \\r
+ { \\r
+ if (temp<256) \\r
+ return false; \\r
+ if (((objtype *)temp)->flags&FL_SHOOTABLE) \\r
+ return false; \\r
+ } \\r
+}\r
+\r
+#define CHECKSIDE(x,y) \\r
+{ \\r
+ temp=(unsigned)actorat[x][y]; \\r
+ if (temp) \\r
+ { \\r
+ if (temp<128) \\r
+ return false; \\r
+ if (temp<256) \\r
+ doornum = temp&63; \\r
+ else if (((objtype *)temp)->flags&FL_SHOOTABLE)\\r
+ return false; \\r
+ } \\r
+}\r
+\r
+\r
+boolean TryWalk (objtype *ob)\r
+{\r
+ int doornum;\r
+ unsigned temp;\r
+\r
+ doornum = -1;\r
+\r
+ if (ob->obclass == inertobj)\r
+ {\r
+ switch (ob->dir)\r
+ {\r
+ case north:\r
+ ob->tiley--;\r
+ break;\r
+\r
+ case northeast:\r
+ ob->tilex++;\r
+ ob->tiley--;\r
+ break;\r
+\r
+ case east:\r
+ ob->tilex++;\r
+ break;\r
+\r
+ case southeast:\r
+ ob->tilex++;\r
+ ob->tiley++;\r
+ break;\r
+\r
+ case south:\r
+ ob->tiley++;\r
+ break;\r
+\r
+ case southwest:\r
+ ob->tilex--;\r
+ ob->tiley++;\r
+ break;\r
+\r
+ case west:\r
+ ob->tilex--;\r
+ break;\r
+\r
+ case northwest:\r
+ ob->tilex--;\r
+ ob->tiley--;\r
+ break;\r
+ }\r
+ }\r
+ else\r
+ switch (ob->dir)\r
+ {\r
+ case north:\r
+ if (ob->obclass == dogobj || ob->obclass == fakeobj)\r
+ {\r
+ CHECKDIAG(ob->tilex,ob->tiley-1);\r
+ }\r
+ else\r
+ {\r
+ CHECKSIDE(ob->tilex,ob->tiley-1);\r
+ }\r
+ ob->tiley--;\r
+ break;\r
+\r
+ case northeast:\r
+ CHECKDIAG(ob->tilex+1,ob->tiley-1);\r
+ CHECKDIAG(ob->tilex+1,ob->tiley);\r
+ CHECKDIAG(ob->tilex,ob->tiley-1);\r
+ ob->tilex++;\r
+ ob->tiley--;\r
+ break;\r
+\r
+ case east:\r
+ if (ob->obclass == dogobj || ob->obclass == fakeobj)\r
+ {\r
+ CHECKDIAG(ob->tilex+1,ob->tiley);\r
+ }\r
+ else\r
+ {\r
+ CHECKSIDE(ob->tilex+1,ob->tiley);\r
+ }\r
+ ob->tilex++;\r
+ break;\r
+\r
+ case southeast:\r
+ CHECKDIAG(ob->tilex+1,ob->tiley+1);\r
+ CHECKDIAG(ob->tilex+1,ob->tiley);\r
+ CHECKDIAG(ob->tilex,ob->tiley+1);\r
+ ob->tilex++;\r
+ ob->tiley++;\r
+ break;\r
+\r
+ case south:\r
+ if (ob->obclass == dogobj || ob->obclass == fakeobj)\r
+ {\r
+ CHECKDIAG(ob->tilex,ob->tiley+1);\r
+ }\r
+ else\r
+ {\r
+ CHECKSIDE(ob->tilex,ob->tiley+1);\r
+ }\r
+ ob->tiley++;\r
+ break;\r
+\r
+ case southwest:\r
+ CHECKDIAG(ob->tilex-1,ob->tiley+1);\r
+ CHECKDIAG(ob->tilex-1,ob->tiley);\r
+ CHECKDIAG(ob->tilex,ob->tiley+1);\r
+ ob->tilex--;\r
+ ob->tiley++;\r
+ break;\r
+\r
+ case west:\r
+ if (ob->obclass == dogobj || ob->obclass == fakeobj)\r
+ {\r
+ CHECKDIAG(ob->tilex-1,ob->tiley);\r
+ }\r
+ else\r
+ {\r
+ CHECKSIDE(ob->tilex-1,ob->tiley);\r
+ }\r
+ ob->tilex--;\r
+ break;\r
+\r
+ case northwest:\r
+ CHECKDIAG(ob->tilex-1,ob->tiley-1);\r
+ CHECKDIAG(ob->tilex-1,ob->tiley);\r
+ CHECKDIAG(ob->tilex,ob->tiley-1);\r
+ ob->tilex--;\r
+ ob->tiley--;\r
+ break;\r
+\r
+ case nodir:\r
+ return false;\r
+\r
+ default:\r
+ Quit ("Walk: Bad dir");\r
+ }\r
+\r
+ if (doornum != -1)\r
+ {\r
+ OpenDoor (doornum);\r
+ ob->distance = -doornum-1;\r
+ return true;\r
+ }\r
+\r
+\r
+ ob->areanumber =\r
+ *(mapsegs[0] + farmapylookup[ob->tiley]+ob->tilex) - AREATILE;\r
+\r
+ ob->distance = TILEGLOBAL;\r
+ return true;\r
+}\r
+\r
+\r
+\r
+/*\r
+==================================\r
+=\r
+= SelectDodgeDir\r
+=\r
+= Attempts to choose and initiate a movement for ob that sends it towards\r
+= the player while dodging\r
+=\r
+= If there is no possible move (ob is totally surrounded)\r
+=\r
+= ob->dir = nodir\r
+=\r
+= Otherwise\r
+=\r
+= ob->dir = new direction to follow\r
+= ob->distance = TILEGLOBAL or -doornumber\r
+= ob->tilex = new destination\r
+= ob->tiley\r
+= ob->areanumber = the floor tile number (0-(NUMAREAS-1)) of destination\r
+=\r
+==================================\r
+*/\r
+\r
+void SelectDodgeDir (objtype *ob)\r
+{\r
+ int deltax,deltay,i;\r
+ unsigned absdx,absdy;\r
+ dirtype dirtry[5];\r
+ dirtype turnaround,tdir;\r
+\r
+ if (ob->flags & FL_FIRSTATTACK)\r
+ {\r
+ //\r
+ // turning around is only ok the very first time after noticing the\r
+ // player\r
+ //\r
+ turnaround = nodir;\r
+ ob->flags &= ~FL_FIRSTATTACK;\r
+ }\r
+ else\r
+ turnaround=opposite[ob->dir];\r
+\r
+ deltax = player->tilex - ob->tilex;\r
+ deltay = player->tiley - ob->tiley;\r
+\r
+//\r
+// arange 5 direction choices in order of preference\r
+// the four cardinal directions plus the diagonal straight towards\r
+// the player\r
+//\r
+\r
+ if (deltax>0)\r
+ {\r
+ dirtry[1]= east;\r
+ dirtry[3]= west;\r
+ }\r
+ else\r
+ {\r
+ dirtry[1]= west;\r
+ dirtry[3]= east;\r
+ }\r
+\r
+ if (deltay>0)\r
+ {\r
+ dirtry[2]= south;\r
+ dirtry[4]= north;\r
+ }\r
+ else\r
+ {\r
+ dirtry[2]= north;\r
+ dirtry[4]= south;\r
+ }\r
+\r
+//\r
+// randomize a bit for dodging\r
+//\r
+ absdx = abs(deltax);\r
+ absdy = abs(deltay);\r
+\r
+ if (absdx > absdy)\r
+ {\r
+ tdir = dirtry[1];\r
+ dirtry[1] = dirtry[2];\r
+ dirtry[2] = tdir;\r
+ tdir = dirtry[3];\r
+ dirtry[3] = dirtry[4];\r
+ dirtry[4] = tdir;\r
+ }\r
+\r
+ if (US_RndT() < 128)\r
+ {\r
+ tdir = dirtry[1];\r
+ dirtry[1] = dirtry[2];\r
+ dirtry[2] = tdir;\r
+ tdir = dirtry[3];\r
+ dirtry[3] = dirtry[4];\r
+ dirtry[4] = tdir;\r
+ }\r
+\r
+ dirtry[0] = diagonal [ dirtry[1] ] [ dirtry[2] ];\r
+\r
+//\r
+// try the directions util one works\r
+//\r
+ for (i=0;i<5;i++)\r
+ {\r
+ if ( dirtry[i] == nodir || dirtry[i] == turnaround)\r
+ continue;\r
+\r
+ ob->dir = dirtry[i];\r
+ if (TryWalk(ob))\r
+ return;\r
+ }\r
+\r
+//\r
+// turn around only as a last resort\r
+//\r
+ if (turnaround != nodir)\r
+ {\r
+ ob->dir = turnaround;\r
+\r
+ if (TryWalk(ob))\r
+ return;\r
+ }\r
+\r
+ ob->dir = nodir;\r
+}\r
+\r
+\r
+/*\r
+============================\r
+=\r
+= SelectChaseDir\r
+=\r
+= As SelectDodgeDir, but doesn't try to dodge\r
+=\r
+============================\r
+*/\r
+\r
+void SelectChaseDir (objtype *ob)\r
+{\r
+ int deltax,deltay,i;\r
+ dirtype d[3];\r
+ dirtype tdir, olddir, turnaround;\r
+\r
+\r
+ olddir=ob->dir;\r
+ turnaround=opposite[olddir];\r
+\r
+ deltax=player->tilex - ob->tilex;\r
+ deltay=player->tiley - ob->tiley;\r
+\r
+ d[1]=nodir;\r
+ d[2]=nodir;\r
+\r
+ if (deltax>0)\r
+ d[1]= east;\r
+ else if (deltax<0)\r
+ d[1]= west;\r
+ if (deltay>0)\r
+ d[2]=south;\r
+ else if (deltay<0)\r
+ d[2]=north;\r
+\r
+ if (abs(deltay)>abs(deltax))\r
+ {\r
+ tdir=d[1];\r
+ d[1]=d[2];\r
+ d[2]=tdir;\r
+ }\r
+\r
+ if (d[1]==turnaround)\r
+ d[1]=nodir;\r
+ if (d[2]==turnaround)\r
+ d[2]=nodir;\r
+\r
+\r
+ if (d[1]!=nodir)\r
+ {\r
+ ob->dir=d[1];\r
+ if (TryWalk(ob))\r
+ return; /*either moved forward or attacked*/\r
+ }\r
+\r
+ if (d[2]!=nodir)\r
+ {\r
+ ob->dir=d[2];\r
+ if (TryWalk(ob))\r
+ return;\r
+ }\r
+\r
+/* there is no direct path to the player, so pick another direction */\r
+\r
+ if (olddir!=nodir)\r
+ {\r
+ ob->dir=olddir;\r
+ if (TryWalk(ob))\r
+ return;\r
+ }\r
+\r
+ if (US_RndT()>128) /*randomly determine direction of search*/\r
+ {\r
+ for (tdir=north;tdir<=west;tdir++)\r
+ {\r
+ if (tdir!=turnaround)\r
+ {\r
+ ob->dir=tdir;\r
+ if ( TryWalk(ob) )\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for (tdir=west;tdir>=north;tdir--)\r
+ {\r
+ if (tdir!=turnaround)\r
+ {\r
+ ob->dir=tdir;\r
+ if ( TryWalk(ob) )\r
+ return;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (turnaround != nodir)\r
+ {\r
+ ob->dir=turnaround;\r
+ if (ob->dir != nodir)\r
+ {\r
+ if ( TryWalk(ob) )\r
+ return;\r
+ }\r
+ }\r
+\r
+ ob->dir = nodir; // can't move\r
+}\r
+\r
+\r
+/*\r
+============================\r
+=\r
+= SelectRunDir\r
+=\r
+= Run Away from player\r
+=\r
+============================\r
+*/\r
+\r
+void SelectRunDir (objtype *ob)\r
+{\r
+ int deltax,deltay,i;\r
+ dirtype d[3];\r
+ dirtype tdir, olddir, turnaround;\r
+\r
+\r
+ deltax=player->tilex - ob->tilex;\r
+ deltay=player->tiley - ob->tiley;\r
+\r
+ if (deltax<0)\r
+ d[1]= east;\r
+ else\r
+ d[1]= west;\r
+ if (deltay<0)\r
+ d[2]=south;\r
+ else\r
+ d[2]=north;\r
+\r
+ if (abs(deltay)>abs(deltax))\r
+ {\r
+ tdir=d[1];\r
+ d[1]=d[2];\r
+ d[2]=tdir;\r
+ }\r
+\r
+ ob->dir=d[1];\r
+ if (TryWalk(ob))\r
+ return; /*either moved forward or attacked*/\r
+\r
+ ob->dir=d[2];\r
+ if (TryWalk(ob))\r
+ return;\r
+\r
+/* there is no direct path to the player, so pick another direction */\r
+\r
+ if (US_RndT()>128) /*randomly determine direction of search*/\r
+ {\r
+ for (tdir=north;tdir<=west;tdir++)\r
+ {\r
+ ob->dir=tdir;\r
+ if ( TryWalk(ob) )\r
+ return;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for (tdir=west;tdir>=north;tdir--)\r
+ {\r
+ ob->dir=tdir;\r
+ if ( TryWalk(ob) )\r
+ return;\r
+ }\r
+ }\r
+\r
+ ob->dir = nodir; // can't move\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= MoveObj\r
+=\r
+= Moves ob be move global units in ob->dir direction\r
+= Actors are not allowed to move inside the player\r
+= Does NOT check to see if the move is tile map valid\r
+=\r
+= ob->x = adjusted for new position\r
+= ob->y\r
+=\r
+=================\r
+*/\r
+\r
+void MoveObj (objtype *ob, long move)\r
+{\r
+ long deltax,deltay;\r
+\r
+ switch (ob->dir)\r
+ {\r
+ case north:\r
+ ob->y -= move;\r
+ break;\r
+ case northeast:\r
+ ob->x += move;\r
+ ob->y -= move;\r
+ break;\r
+ case east:\r
+ ob->x += move;\r
+ break;\r
+ case southeast:\r
+ ob->x += move;\r
+ ob->y += move;\r
+ break;\r
+ case south:\r
+ ob->y += move;\r
+ break;\r
+ case southwest:\r
+ ob->x -= move;\r
+ ob->y += move;\r
+ break;\r
+ case west:\r
+ ob->x -= move;\r
+ break;\r
+ case northwest:\r
+ ob->x -= move;\r
+ ob->y -= move;\r
+ break;\r
+\r
+ case nodir:\r
+ return;\r
+\r
+ default:\r
+ Quit ("MoveObj: bad dir!");\r
+ }\r
+\r
+//\r
+// check to make sure it's not on top of player\r
+//\r
+ if (areabyplayer[ob->areanumber])\r
+ {\r
+ deltax = ob->x - player->x;\r
+ if (deltax < -MINACTORDIST || deltax > MINACTORDIST)\r
+ goto moveok;\r
+ deltay = ob->y - player->y;\r
+ if (deltay < -MINACTORDIST || deltay > MINACTORDIST)\r
+ goto moveok;\r
+\r
+ if (ob->obclass == ghostobj || ob->obclass == spectreobj)\r
+ TakeDamage (tics*2,ob);\r
+\r
+ //\r
+ // back up\r
+ //\r
+ switch (ob->dir)\r
+ {\r
+ case north:\r
+ ob->y += move;\r
+ break;\r
+ case northeast:\r
+ ob->x -= move;\r
+ ob->y += move;\r
+ break;\r
+ case east:\r
+ ob->x -= move;\r
+ break;\r
+ case southeast:\r
+ ob->x -= move;\r
+ ob->y -= move;\r
+ break;\r
+ case south:\r
+ ob->y -= move;\r
+ break;\r
+ case southwest:\r
+ ob->x += move;\r
+ ob->y -= move;\r
+ break;\r
+ case west:\r
+ ob->x += move;\r
+ break;\r
+ case northwest:\r
+ ob->x += move;\r
+ ob->y += move;\r
+ break;\r
+\r
+ case nodir:\r
+ return;\r
+ }\r
+ return;\r
+ }\r
+moveok:\r
+ ob->distance -=move;\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+ STUFF\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+===============\r
+=\r
+= DropItem\r
+=\r
+= Tries to drop a bonus item somewhere in the tiles surrounding the\r
+= given tilex/tiley\r
+=\r
+===============\r
+*/\r
+\r
+void DropItem (stat_t itemtype, int tilex, int tiley)\r
+{\r
+ int x,y,xl,xh,yl,yh;\r
+\r
+//\r
+// find a free spot to put it in\r
+//\r
+ if (!actorat[tilex][tiley])\r
+ {\r
+ PlaceItemType (itemtype, tilex,tiley);\r
+ return;\r
+ }\r
+\r
+ xl = tilex-1;\r
+ xh = tilex+1;\r
+ yl = tiley-1;\r
+ yh = tiley+1;\r
+\r
+ for (x=xl ; x<= xh ; x++)\r
+ for (y=yl ; y<= yh ; y++)\r
+ if (!actorat[x][y])\r
+ {\r
+ PlaceItemType (itemtype, x,y);\r
+ return;\r
+ }\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= KillActor\r
+=\r
+===============\r
+*/\r
+\r
+void KillActor (objtype *ob)\r
+{\r
+ int tilex,tiley;\r
+\r
+ tilex = ob->tilex = ob->x >> TILESHIFT; // drop item on center\r
+ tiley = ob->tiley = ob->y >> TILESHIFT;\r
+\r
+ switch (ob->obclass)\r
+ {\r
+ case guardobj:\r
+ GivePoints (100);\r
+ NewState (ob,&s_grddie1);\r
+ PlaceItemType (bo_clip2,tilex,tiley);\r
+ break;\r
+\r
+ case officerobj:\r
+ GivePoints (400);\r
+ NewState (ob,&s_ofcdie1);\r
+ PlaceItemType (bo_clip2,tilex,tiley);\r
+ break;\r
+\r
+ case mutantobj:\r
+ GivePoints (700);\r
+ NewState (ob,&s_mutdie1);\r
+ PlaceItemType (bo_clip2,tilex,tiley);\r
+ break;\r
+\r
+ case ssobj:\r
+ GivePoints (500);\r
+ NewState (ob,&s_ssdie1);\r
+ if (gamestate.bestweapon < wp_machinegun)\r
+ PlaceItemType (bo_machinegun,tilex,tiley);\r
+ else\r
+ PlaceItemType (bo_clip2,tilex,tiley);\r
+ break;\r
+\r
+ case dogobj:\r
+ GivePoints (200);\r
+ NewState (ob,&s_dogdie1);\r
+ break;\r
+\r
+#ifndef SPEAR\r
+ case bossobj:\r
+ GivePoints (5000);\r
+ NewState (ob,&s_bossdie1);\r
+ PlaceItemType (bo_key1,tilex,tiley);\r
+ break;\r
+\r
+ case gretelobj:\r
+ GivePoints (5000);\r
+ NewState (ob,&s_greteldie1);\r
+ PlaceItemType (bo_key1,tilex,tiley);\r
+ break;\r
+\r
+ case giftobj:\r
+ GivePoints (5000);\r
+ gamestate.killx = player->x;\r
+ gamestate.killy = player->y;\r
+ NewState (ob,&s_giftdie1);\r
+ break;\r
+\r
+ case fatobj:\r
+ GivePoints (5000);\r
+ gamestate.killx = player->x;\r
+ gamestate.killy = player->y;\r
+ NewState (ob,&s_fatdie1);\r
+ break;\r
+\r
+ case schabbobj:\r
+ GivePoints (5000);\r
+ gamestate.killx = player->x;\r
+ gamestate.killy = player->y;\r
+ NewState (ob,&s_schabbdie1);\r
+ A_DeathScream(ob);\r
+ break;\r
+ case fakeobj:\r
+ GivePoints (2000);\r
+ NewState (ob,&s_fakedie1);\r
+ break;\r
+\r
+ case mechahitlerobj:\r
+ GivePoints (5000);\r
+ NewState (ob,&s_mechadie1);\r
+ break;\r
+ case realhitlerobj:\r
+ GivePoints (5000);\r
+ gamestate.killx = player->x;\r
+ gamestate.killy = player->y;\r
+ NewState (ob,&s_hitlerdie1);\r
+ A_DeathScream(ob);\r
+ break;\r
+#else\r
+ case spectreobj:\r
+ GivePoints (200);\r
+ NewState (ob,&s_spectredie1);\r
+ break;\r
+\r
+ case angelobj:\r
+ GivePoints (5000);\r
+ NewState (ob,&s_angeldie1);\r
+ break;\r
+\r
+ case transobj:\r
+ GivePoints (5000);\r
+ NewState (ob,&s_transdie0);\r
+ PlaceItemType (bo_key1,tilex,tiley);\r
+ break;\r
+\r
+ case uberobj:\r
+ GivePoints (5000);\r
+ NewState (ob,&s_uberdie0);\r
+ PlaceItemType (bo_key1,tilex,tiley);\r
+ break;\r
+\r
+ case willobj:\r
+ GivePoints (5000);\r
+ NewState (ob,&s_willdie1);\r
+ PlaceItemType (bo_key1,tilex,tiley);\r
+ break;\r
+\r
+ case deathobj:\r
+ GivePoints (5000);\r
+ NewState (ob,&s_deathdie1);\r
+ PlaceItemType (bo_key1,tilex,tiley);\r
+ break;\r
+#endif\r
+ }\r
+\r
+ gamestate.killcount++;\r
+ ob->flags &= ~FL_SHOOTABLE;\r
+ actorat[ob->tilex][ob->tiley] = NULL;\r
+ ob->flags |= FL_NONMARK;\r
+}\r
+\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= DamageActor\r
+=\r
+= Called when the player succesfully hits an enemy.\r
+=\r
+= Does damage points to enemy ob, either putting it into a stun frame or\r
+= killing it.\r
+=\r
+===================\r
+*/\r
+\r
+void DamageActor (objtype *ob, unsigned damage)\r
+{\r
+ madenoise = true;\r
+\r
+//\r
+// do double damage if shooting a non attack mode actor\r
+//\r
+ if ( !(ob->flags & FL_ATTACKMODE) )\r
+ damage <<= 1;\r
+\r
+ ob->hitpoints -= damage;\r
+\r
+ if (ob->hitpoints<=0)\r
+ KillActor (ob);\r
+ else\r
+ {\r
+ if (! (ob->flags & FL_ATTACKMODE) )\r
+ FirstSighting (ob); // put into combat mode\r
+\r
+ switch (ob->obclass) // dogs only have one hit point\r
+ {\r
+ case guardobj:\r
+ if (ob->hitpoints&1)\r
+ NewState (ob,&s_grdpain);\r
+ else\r
+ NewState (ob,&s_grdpain1);\r
+ break;\r
+\r
+ case officerobj:\r
+ if (ob->hitpoints&1)\r
+ NewState (ob,&s_ofcpain);\r
+ else\r
+ NewState (ob,&s_ofcpain1);\r
+ break;\r
+\r
+ case mutantobj:\r
+ if (ob->hitpoints&1)\r
+ NewState (ob,&s_mutpain);\r
+ else\r
+ NewState (ob,&s_mutpain1);\r
+ break;\r
+\r
+ case ssobj:\r
+ if (ob->hitpoints&1)\r
+ NewState (ob,&s_sspain);\r
+ else\r
+ NewState (ob,&s_sspain1);\r
+\r
+ break;\r
+\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+ CHECKSIGHT\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= CheckLine\r
+=\r
+= Returns true if a straight line between the player and ob is unobstructed\r
+=\r
+=====================\r
+*/\r
+\r
+boolean CheckLine (objtype *ob)\r
+{\r
+ int x1,y1,xt1,yt1,x2,y2,xt2,yt2;\r
+ int x,y;\r
+ int xdist,ydist,xstep,ystep;\r
+ int temp;\r
+ int partial,delta;\r
+ long ltemp;\r
+ int xfrac,yfrac,deltafrac;\r
+ unsigned value,intercept;\r
+\r
+ x1 = ob->x >> UNSIGNEDSHIFT; // 1/256 tile precision\r
+ y1 = ob->y >> UNSIGNEDSHIFT;\r
+ xt1 = x1 >> 8;\r
+ yt1 = y1 >> 8;\r
+\r
+ x2 = plux;\r
+ y2 = pluy;\r
+ xt2 = player->tilex;\r
+ yt2 = player->tiley;\r
+\r
+\r
+ xdist = abs(xt2-xt1);\r
+\r
+ if (xdist > 0)\r
+ {\r
+ if (xt2 > xt1)\r
+ {\r
+ partial = 256-(x1&0xff);\r
+ xstep = 1;\r
+ }\r
+ else\r
+ {\r
+ partial = x1&0xff;\r
+ xstep = -1;\r
+ }\r
+\r
+ deltafrac = abs(x2-x1);\r
+ delta = y2-y1;\r
+ ltemp = ((long)delta<<8)/deltafrac;\r
+ if (ltemp > 0x7fffl)\r
+ ystep = 0x7fff;\r
+ else if (ltemp < -0x7fffl)\r
+ ystep = -0x7fff;\r
+ else\r
+ ystep = ltemp;\r
+ yfrac = y1 + (((long)ystep*partial) >>8);\r
+\r
+ x = xt1+xstep;\r
+ xt2 += xstep;\r
+ do\r
+ {\r
+ y = yfrac>>8;\r
+ yfrac += ystep;\r
+\r
+ value = (unsigned)tilemap[x][y];\r
+ x += xstep;\r
+\r
+ if (!value)\r
+ continue;\r
+\r
+ if (value<128 || value>256)\r
+ return false;\r
+\r
+ //\r
+ // see if the door is open enough\r
+ //\r
+ value &= ~0x80;\r
+ intercept = yfrac-ystep/2;\r
+\r
+ if (intercept>doorposition[value])\r
+ return false;\r
+\r
+ } while (x != xt2);\r
+ }\r
+\r
+ ydist = abs(yt2-yt1);\r
+\r
+ if (ydist > 0)\r
+ {\r
+ if (yt2 > yt1)\r
+ {\r
+ partial = 256-(y1&0xff);\r
+ ystep = 1;\r
+ }\r
+ else\r
+ {\r
+ partial = y1&0xff;\r
+ ystep = -1;\r
+ }\r
+\r
+ deltafrac = abs(y2-y1);\r
+ delta = x2-x1;\r
+ ltemp = ((long)delta<<8)/deltafrac;\r
+ if (ltemp > 0x7fffl)\r
+ xstep = 0x7fff;\r
+ else if (ltemp < -0x7fffl)\r
+ xstep = -0x7fff;\r
+ else\r
+ xstep = ltemp;\r
+ xfrac = x1 + (((long)xstep*partial) >>8);\r
+\r
+ y = yt1 + ystep;\r
+ yt2 += ystep;\r
+ do\r
+ {\r
+ x = xfrac>>8;\r
+ xfrac += xstep;\r
+\r
+ value = (unsigned)tilemap[x][y];\r
+ y += ystep;\r
+\r
+ if (!value)\r
+ continue;\r
+\r
+ if (value<128 || value>256)\r
+ return false;\r
+\r
+ //\r
+ // see if the door is open enough\r
+ //\r
+ value &= ~0x80;\r
+ intercept = xfrac-xstep/2;\r
+\r
+ if (intercept>doorposition[value])\r
+ return false;\r
+ } while (y != yt2);\r
+ }\r
+\r
+ return true;\r
+}\r
+\r
+\r
+\r
+/*\r
+================\r
+=\r
+= CheckSight\r
+=\r
+= Checks a straight line between player and current object\r
+=\r
+= If the sight is ok, check alertness and angle to see if they notice\r
+=\r
+= returns true if the player has been spoted\r
+=\r
+================\r
+*/\r
+\r
+#define MINSIGHT 0x18000l\r
+\r
+boolean CheckSight (objtype *ob)\r
+{\r
+ long deltax,deltay;\r
+\r
+//\r
+// don't bother tracing a line if the area isn't connected to the player's\r
+//\r
+ if (!areabyplayer[ob->areanumber])\r
+ return false;\r
+\r
+//\r
+// if the player is real close, sight is automatic\r
+//\r
+ deltax = player->x - ob->x;\r
+ deltay = player->y - ob->y;\r
+\r
+ if (deltax > -MINSIGHT && deltax < MINSIGHT\r
+ && deltay > -MINSIGHT && deltay < MINSIGHT)\r
+ return true;\r
+\r
+//\r
+// see if they are looking in the right direction\r
+//\r
+ switch (ob->dir)\r
+ {\r
+ case north:\r
+ if (deltay > 0)\r
+ return false;\r
+ break;\r
+\r
+ case east:\r
+ if (deltax < 0)\r
+ return false;\r
+ break;\r
+\r
+ case south:\r
+ if (deltay < 0)\r
+ return false;\r
+ break;\r
+\r
+ case west:\r
+ if (deltax > 0)\r
+ return false;\r
+ break;\r
+ }\r
+\r
+//\r
+// trace a line to check for blocking tiles (corners)\r
+//\r
+ return CheckLine (ob);\r
+\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= FirstSighting\r
+=\r
+= Puts an actor into attack mode and possibly reverses the direction\r
+= if the player is behind it\r
+=\r
+===============\r
+*/\r
+\r
+void FirstSighting (objtype *ob)\r
+{\r
+//\r
+// react to the player\r
+//\r
+ switch (ob->obclass)\r
+ {\r
+ case guardobj:\r
+ PlaySoundLocActor(HALTSND,ob);\r
+ NewState (ob,&s_grdchase1);\r
+ ob->speed *= 3; // go faster when chasing player\r
+ break;\r
+\r
+ case officerobj:\r
+ PlaySoundLocActor(SPIONSND,ob);\r
+ NewState (ob,&s_ofcchase1);\r
+ ob->speed *= 5; // go faster when chasing player\r
+ break;\r
+\r
+ case mutantobj:\r
+ NewState (ob,&s_mutchase1);\r
+ ob->speed *= 3; // go faster when chasing player\r
+ break;\r
+\r
+ case ssobj:\r
+ PlaySoundLocActor(SCHUTZADSND,ob);\r
+ NewState (ob,&s_sschase1);\r
+ ob->speed *= 4; // go faster when chasing player\r
+ break;\r
+\r
+ case dogobj:\r
+ PlaySoundLocActor(DOGBARKSND,ob);\r
+ NewState (ob,&s_dogchase1);\r
+ ob->speed *= 2; // go faster when chasing player\r
+ break;\r
+\r
+#ifndef SPEAR\r
+ case bossobj:\r
+ SD_PlaySound(GUTENTAGSND);\r
+ NewState (ob,&s_bosschase1);\r
+ ob->speed = SPDPATROL*3; // go faster when chasing player\r
+ break;\r
+\r
+ case gretelobj:\r
+ SD_PlaySound(KEINSND);\r
+ NewState (ob,&s_gretelchase1);\r
+ ob->speed *= 3; // go faster when chasing player\r
+ break;\r
+\r
+ case giftobj:\r
+ SD_PlaySound(EINESND);\r
+ NewState (ob,&s_giftchase1);\r
+ ob->speed *= 3; // go faster when chasing player\r
+ break;\r
+\r
+ case fatobj:\r
+ SD_PlaySound(ERLAUBENSND);\r
+ NewState (ob,&s_fatchase1);\r
+ ob->speed *= 3; // go faster when chasing player\r
+ break;\r
+\r
+ case schabbobj:\r
+ SD_PlaySound(SCHABBSHASND);\r
+ NewState (ob,&s_schabbchase1);\r
+ ob->speed *= 3; // go faster when chasing player\r
+ break;\r
+\r
+ case fakeobj:\r
+ SD_PlaySound(TOT_HUNDSND);\r
+ NewState (ob,&s_fakechase1);\r
+ ob->speed *= 3; // go faster when chasing player\r
+ break;\r
+\r
+ case mechahitlerobj:\r
+ SD_PlaySound(DIESND);\r
+ NewState (ob,&s_mechachase1);\r
+ ob->speed *= 3; // go faster when chasing player\r
+ break;\r
+\r
+ case realhitlerobj:\r
+ SD_PlaySound(DIESND);\r
+ NewState (ob,&s_hitlerchase1);\r
+ ob->speed *= 5; // go faster when chasing player\r
+ break;\r
+\r
+ case ghostobj:\r
+ NewState (ob,&s_blinkychase1);\r
+ ob->speed *= 2; // go faster when chasing player\r
+ break;\r
+#else\r
+\r
+ case spectreobj:\r
+ SD_PlaySound(GHOSTSIGHTSND);\r
+ NewState (ob,&s_spectrechase1);\r
+ ob->speed = 800; // go faster when chasing player\r
+ break;\r
+\r
+ case angelobj:\r
+ SD_PlaySound(ANGELSIGHTSND);\r
+ NewState (ob,&s_angelchase1);\r
+ ob->speed = 1536; // go faster when chasing player\r
+ break;\r
+\r
+ case transobj:\r
+ SD_PlaySound(TRANSSIGHTSND);\r
+ NewState (ob,&s_transchase1);\r
+ ob->speed = 1536; // go faster when chasing player\r
+ break;\r
+\r
+ case uberobj:\r
+ NewState (ob,&s_uberchase1);\r
+ ob->speed = 3000; // go faster when chasing player\r
+ break;\r
+\r
+ case willobj:\r
+ SD_PlaySound(WILHELMSIGHTSND);\r
+ NewState (ob,&s_willchase1);\r
+ ob->speed = 2048; // go faster when chasing player\r
+ break;\r
+\r
+ case deathobj:\r
+ SD_PlaySound(KNIGHTSIGHTSND);\r
+ NewState (ob,&s_deathchase1);\r
+ ob->speed = 2048; // go faster when chasing player\r
+ break;\r
+\r
+#endif\r
+ }\r
+\r
+ if (ob->distance < 0)\r
+ ob->distance = 0; // ignore the door opening command\r
+\r
+ ob->flags |= FL_ATTACKMODE|FL_FIRSTATTACK;\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SightPlayer\r
+=\r
+= Called by actors that ARE NOT chasing the player. If the player\r
+= is detected (by sight, noise, or proximity), the actor is put into\r
+= it's combat frame and true is returned.\r
+=\r
+= Incorporates a random reaction delay\r
+=\r
+===============\r
+*/\r
+\r
+boolean SightPlayer (objtype *ob)\r
+{\r
+ if (ob->flags & FL_ATTACKMODE)\r
+ Quit ("An actor in ATTACKMODE called SightPlayer!");\r
+\r
+ if (ob->temp2)\r
+ {\r
+ //\r
+ // count down reaction time\r
+ //\r
+ ob->temp2 -= tics;\r
+ if (ob->temp2 > 0)\r
+ return false;\r
+ ob->temp2 = 0; // time to react\r
+ }\r
+ else\r
+ {\r
+ if (!areabyplayer[ob->areanumber])\r
+ return false;\r
+\r
+ if (ob->flags & FL_AMBUSH)\r
+ {\r
+ if (!CheckSight (ob))\r
+ return false;\r
+ ob->flags &= ~FL_AMBUSH;\r
+ }\r
+ else\r
+ {\r
+ if (!madenoise && !CheckSight (ob))\r
+ return false;\r
+ }\r
+\r
+\r
+ switch (ob->obclass)\r
+ {\r
+ case guardobj:\r
+ ob->temp2 = 1+US_RndT()/4;\r
+ break;\r
+ case officerobj:\r
+ ob->temp2 = 2;\r
+ break;\r
+ case mutantobj:\r
+ ob->temp2 = 1+US_RndT()/6;\r
+ break;\r
+ case ssobj:\r
+ ob->temp2 = 1+US_RndT()/6;\r
+ break;\r
+ case dogobj:\r
+ ob->temp2 = 1+US_RndT()/8;\r
+ break;\r
+\r
+ case bossobj:\r
+ case schabbobj:\r
+ case fakeobj:\r
+ case mechahitlerobj:\r
+ case realhitlerobj:\r
+ case gretelobj:\r
+ case giftobj:\r
+ case fatobj:\r
+ case spectreobj:\r
+ case angelobj:\r
+ case transobj:\r
+ case uberobj:\r
+ case willobj:\r
+ case deathobj:\r
+ ob->temp2 = 1;\r
+ break;\r
+ }\r
+ return false;\r
+ }\r
+\r
+ FirstSighting (ob);\r
+\r
+ return true;\r
+}\r
+\r
+\r