doom

a minimalistic implementation of doom
git clone git://ssnf.xyz/doom
Log | Files | Refs

p_enemy.c (26494B)


      1 #include <stdlib.h>
      2 
      3 #include "m_random.h"
      4 #include "i_system.h"
      5 #include "doomdef.h"
      6 #include "p_local.h"
      7 #include "s_sound.h"
      8 #include "g_game.h"
      9 #include "doomstat.h"
     10 #include "r_state.h"
     11 #include "sounds.h"
     12 
     13 #define	FATSPREAD (ANG90/8)
     14 #define MAXSPECIALCROSS	8
     15 #define	SKULLSPEED (20*FRACUNIT)
     16 
     17 typedef enum {
     18 	DI_EAST,
     19 	DI_NORTHEAST,
     20 	DI_NORTH,
     21 	DI_NORTHWEST,
     22 	DI_WEST,
     23 	DI_SOUTHWEST,
     24 	DI_SOUTH,
     25 	DI_SOUTHEAST,
     26 	DI_NODIR,
     27 	NUMDIRS
     28 } dirtype_t;
     29 
     30 extern	line_t*	spechit[MAXSPECIALCROSS];
     31 extern	int	numspechit;
     32 mobj_t*		corpsehit;
     33 mobj_t*		vileobj;
     34 mobj_t* braintargets[32];
     35 fixed_t		viletryx;
     36 fixed_t		viletryy;
     37 int     numbraintargets;
     38 int     braintargeton;
     39 int     TRACEANGLE = 0xc000000;
     40 fixed_t	xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
     41 fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
     42 dirtype_t opposite[] = {
     43   DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST,
     44   DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR
     45 };
     46 dirtype_t diags[] = {
     47 	DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST
     48 };
     49 
     50 
     51 void A_Fall (mobj_t *actor);
     52 void A_SpawnFly (mobj_t* mo);
     53 
     54 mobj_t*		soundtarget;
     55 
     56 void
     57 P_RecursiveSound(sector_t* sec, int soundblocks)
     58 {
     59 	sector_t* other;
     60     line_t*   check;
     61 	int       i;
     62 
     63 	if (sec->validcount == validcount && sec->soundtraversed <= soundblocks+1) return;
     64 	sec->validcount = validcount;
     65 	sec->soundtraversed = soundblocks+1;
     66 	sec->soundtarget = soundtarget;
     67 	for (i = 0; i < sec->linecount; ++i) {
     68 		check = sec->lines[i];
     69 		if (!(check->flags & ML_TWOSIDED)) continue;
     70 		P_LineOpening(check);
     71 		if (openrange <= 0) continue;
     72 		if (sides[check->sidenum[0]].sector == sec) other = sides[check->sidenum[1]].sector;
     73 		else other = sides[ check->sidenum[0] ].sector;
     74 		if (check->flags & ML_SOUNDBLOCK) {
     75 			if (!soundblocks)
     76 			P_RecursiveSound (other, 1);
     77 		} else P_RecursiveSound (other, soundblocks);
     78 	}
     79 }
     80 
     81 void
     82 P_NoiseAlert(mobj_t* target, mobj_t* emmiter)
     83 {
     84 	soundtarget = target;
     85 	validcount++;
     86 	P_RecursiveSound(emmiter->subsector->sector, 0);
     87 }
     88 
     89 boolean
     90 P_CheckMeleeRange(mobj_t* actor)
     91 {
     92 	mobj_t*	pl;
     93 	fixed_t	dist;
     94 
     95 	if (!actor->target) return false;
     96 	pl = actor->target;
     97 	dist = P_AproxDistance (pl->x-actor->x, pl->y-actor->y);
     98 	if (dist >= MELEERANGE-20*FRACUNIT+pl->info->radius) return false;
     99 	if (!P_CheckSight (actor, actor->target)) return false;
    100 	return true;
    101 }
    102 
    103 boolean
    104 P_CheckMissileRange(mobj_t* actor)
    105 {
    106 	fixed_t	dist;
    107 
    108 	if (!P_CheckSight(actor, actor->target)) return false;
    109 	if (actor->flags & MF_JUSTHIT) {
    110 		actor->flags &= ~MF_JUSTHIT;
    111 		return true;
    112 	}
    113 	if (actor->reactiontime) return false;
    114 	dist = P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) - 64*FRACUNIT;
    115 	if (!actor->info->meleestate) dist -= 128*FRACUNIT;
    116 	dist >>= 16;
    117 	if (actor->type == MT_VILE)
    118 		if (dist > 14*64) return false;
    119 	if (actor->type == MT_UNDEAD) {
    120 		if (dist < 196) return false;
    121 		dist >>= 1;
    122 	}
    123 	if (actor->type == MT_CYBORG || actor->type == MT_SPIDER || actor->type == MT_SKULL) dist >>= 1;
    124 	if (dist > 200) dist = 200;
    125 	if (actor->type == MT_CYBORG && dist > 160) dist = 160;
    126 	if (P_Random() < dist) return false;
    127 	return true;
    128 }
    129 
    130 boolean
    131 P_Move(mobj_t*	actor)
    132 {
    133 	line_t*	ld;
    134 	fixed_t	tryx, tryy;
    135 	boolean	good, try_ok;
    136 
    137 	if (actor->movedir == DI_NODIR) return false;
    138 	if ((unsigned)actor->movedir >= 8) I_Error("Weird actor->movedir!");
    139 	tryx = actor->x + actor->info->speed*xspeed[actor->movedir];
    140 	tryy = actor->y + actor->info->speed*yspeed[actor->movedir];
    141 	try_ok = P_TryMove (actor, tryx, tryy);
    142 	if (!try_ok) {
    143 		if (actor->flags & MF_FLOAT && floatok) {
    144 			if (actor->z < tmfloorz) actor->z += FLOATSPEED;
    145 			else actor->z -= FLOATSPEED;
    146 			actor->flags |= MF_INFLOAT;
    147 			return true;
    148 		}
    149 		if (!numspechit) return false;
    150 		actor->movedir = DI_NODIR;
    151 		good = false;
    152 		while (numspechit--) {
    153 			ld = spechit[numspechit];
    154 			if (P_UseSpecialLine (actor, ld,0)) good = true;
    155 		}
    156 		return good;
    157 	} else actor->flags &= ~MF_INFLOAT;
    158 	if (! (actor->flags & MF_FLOAT) ) actor->z = actor->floorz;
    159 	return true;
    160 }
    161 
    162 boolean
    163 P_TryWalk(mobj_t* actor)
    164 {
    165 	if (!P_Move(actor)) return false;
    166 	actor->movecount = P_Random() & 15;
    167 	return true;
    168 }
    169 
    170 void
    171 P_NewChaseDir(mobj_t* actor)
    172 {
    173 	fixed_t	deltax;
    174 	fixed_t	deltay;
    175 	dirtype_t	olddir, turnaround, d[3];
    176 	int		tdir;
    177 
    178 	if (!actor->target) I_Error("P_NewChaseDir: called with no target");
    179 	olddir = actor->movedir;
    180 	turnaround=opposite[olddir];
    181 	deltax = actor->target->x - actor->x;
    182 	deltay = actor->target->y - actor->y;
    183 	if (deltax>10*FRACUNIT) d[1] = DI_EAST;
    184 	else if (deltax<-10*FRACUNIT) d[1] = DI_WEST;
    185 	else d[1] =DI_NODIR;
    186 	if (deltay<-10*FRACUNIT) d[2] = DI_SOUTH;
    187 	else if (deltay>10*FRACUNIT) d[2] = DI_NORTH;
    188 	else d[2] = DI_NODIR;
    189 	if (d[1] != DI_NODIR && d[2] != DI_NODIR) {
    190 		actor->movedir = diags[((deltay<0) << 1) + (deltax > 0)];
    191 		if (actor->movedir != turnaround && P_TryWalk(actor)) return;
    192 	}
    193 	if (P_Random() > 200 || abs(deltay)>abs(deltax)) {
    194 		tdir=d[1];
    195 		d[1]=d[2];
    196 		d[2]=tdir;
    197 	}
    198 	if (d[1]==turnaround) d[1]=DI_NODIR;
    199 	if (d[2]==turnaround) d[2]=DI_NODIR;
    200 	if (d[1]!=DI_NODIR) {
    201 		actor->movedir = d[1];
    202 		if (P_TryWalk(actor)) return;
    203 	}
    204 	if (d[2]!=DI_NODIR) {
    205 		actor->movedir =d[2];
    206 		if (P_TryWalk(actor)) return;
    207 	}
    208 	if (olddir!=DI_NODIR) {
    209 		actor->movedir = olddir;
    210 		if (P_TryWalk(actor)) return;
    211 	}
    212 	if (P_Random() & 1) {
    213 		for (tdir=DI_EAST; tdir<=DI_SOUTHEAST; ++tdir) {
    214 			if (tdir!=turnaround) {
    215 				actor->movedir =tdir;
    216 				if (P_TryWalk(actor)) return;
    217 			}
    218 		}
    219 	} else {
    220 		for (tdir=DI_SOUTHEAST; tdir != (DI_EAST-1); --tdir) {
    221 			if (tdir!=turnaround) {
    222 				actor->movedir =tdir;
    223 				if (P_TryWalk(actor)) return;
    224 			}
    225 		}
    226 	}
    227 	if (turnaround !=  DI_NODIR) {
    228 		actor->movedir =turnaround;
    229 		if (P_TryWalk(actor)) return;
    230 	}
    231 	actor->movedir = DI_NODIR;
    232 }
    233 
    234 boolean
    235 P_LookForPlayers(mobj_t* actor, boolean allaround)
    236 {
    237 	player_t* player;
    238 	angle_t   an;
    239 	fixed_t   dist;
    240 	int       c, stop;
    241 
    242 	c = 0;
    243 	stop = (actor->lastlook-1) & 3;
    244 	for (;; actor->lastlook = (actor->lastlook+1)&3) {
    245 		if (!playeringame[actor->lastlook]) continue;
    246 		if (c++ == 2 || actor->lastlook == stop) return false;
    247 		player = &players[actor->lastlook];
    248 		if (player->health <= 0) continue;
    249 		if (!P_CheckSight (actor, player->mo)) continue;
    250 		if (!allaround) {
    251 			an = R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y) - actor->angle;
    252 			if (an > ANG90 && an < ANG270) {
    253 				dist = P_AproxDistance (player->mo->x - actor->x, player->mo->y - actor->y);
    254 				if (dist > MELEERANGE) continue;
    255 			}
    256 		}
    257 		actor->target = player->mo;
    258 		return true;
    259 	}
    260 	return false;
    261 }
    262 
    263 void
    264 A_KeenDie(mobj_t* mo)
    265 {
    266 	thinker_t* th;
    267 	mobj_t*    mo2;
    268 	line_t     junk;
    269 
    270 	A_Fall(mo);
    271 	for (th = thinkercap.next; th != &thinkercap; th = th->next) {
    272 		if (th->function.acp1 != (actionf_p1)P_MobjThinker) continue;
    273 		mo2 = (mobj_t *)th;
    274 		if (mo2 != mo && mo2->type == mo->type && mo2->health > 0) return;
    275 	}
    276 	junk.tag = 666;
    277 	EV_DoDoor(&junk, open);
    278 }
    279 
    280 void
    281 A_Look (mobj_t* actor)
    282 {
    283 	mobj_t* targ;
    284 	int     sound;
    285 
    286 	actor->threshold = 0;
    287 	targ = actor->subsector->sector->soundtarget;
    288 	if (targ && (targ->flags & MF_SHOOTABLE)) {
    289 		actor->target = targ;
    290 		if (actor->flags & MF_AMBUSH) {
    291 			if (P_CheckSight (actor, actor->target))
    292 			goto seeyou;
    293 		} else goto seeyou;
    294 		if (!P_LookForPlayers (actor, false)) return;
    295 		seeyou:
    296 		if (actor->info->seesound) {
    297 			switch (actor->info->seesound) {
    298 				case sfx_posit1:
    299 				case sfx_posit2:
    300 				case sfx_posit3:
    301 					sound = sfx_posit1+P_Random()%3;
    302 					break;
    303 				case sfx_bgsit1:
    304 				case sfx_bgsit2:
    305 					sound = sfx_bgsit1+P_Random()%2;
    306 					break;
    307 				default:
    308 					sound = actor->info->seesound;
    309 					break;
    310 			}
    311 			if (actor->type==MT_SPIDER || actor->type == MT_CYBORG) S_StartSound (NULL, sound);
    312 			else S_StartSound (actor, sound);
    313 		}
    314 	P_SetMobjState (actor, actor->info->seestate);
    315 	}
    316 }
    317 
    318 void
    319 A_Chase(mobj_t* actor)
    320 {
    321 	int delta;
    322 
    323 	if (actor->reactiontime) --actor->reactiontime;
    324 	if (actor->threshold) {
    325 		if (!actor->target || actor->target->health <= 0) actor->threshold = 0;
    326 		else actor->threshold--;
    327 	}
    328 	if (actor->movedir < 8) {
    329 		actor->angle &= (7<<29);
    330 		delta = actor->angle - (actor->movedir << 29);
    331 		if (delta > 0) actor->angle -= ANG90/2;
    332 		if (delta < 0) actor->angle += ANG90/2;
    333 	}
    334 	if (!actor->target || !(actor->target->flags&MF_SHOOTABLE)) {
    335 		if (P_LookForPlayers(actor,true)) return;
    336 		P_SetMobjState(actor, actor->info->spawnstate);
    337 		return;
    338 	}
    339 	if (actor->flags & MF_JUSTATTACKED) {
    340 		actor->flags &= ~MF_JUSTATTACKED;
    341 		if (gameskill != sk_nightmare && !fastparm) P_NewChaseDir(actor);
    342 		return;
    343 	}
    344 	if (actor->info->meleestate && P_CheckMeleeRange (actor)) {
    345 		if (actor->info->attacksound) S_StartSound (actor, actor->info->attacksound);
    346 		P_SetMobjState (actor, actor->info->meleestate);
    347 		return;
    348 	}
    349 	if (actor->info->missilestate) {
    350 		if (gameskill < sk_nightmare && !fastparm && actor->movecount) goto nomissile;
    351 		if (!P_CheckMissileRange(actor)) goto nomissile;
    352 		P_SetMobjState (actor, actor->info->missilestate);
    353 		actor->flags |= MF_JUSTATTACKED;
    354 		return;
    355 	}
    356 		nomissile:
    357 		if (netgame && !actor->threshold && !P_CheckSight (actor, actor->target))
    358 			if (P_LookForPlayers(actor,true)) return;
    359 		if (--actor->movecount < 0 || !P_Move (actor))
    360 			P_NewChaseDir (actor);
    361 		if (actor->info->activesound && P_Random() < 3) S_StartSound (actor, actor->info->activesound);
    362 }
    363 
    364 void
    365 A_FaceTarget(mobj_t* actor)
    366 {
    367 	if (!actor->target) return;
    368 	actor->flags &= ~MF_AMBUSH;
    369 	actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
    370 	if (actor->target->flags & MF_SHADOW) actor->angle += (P_Random()-P_Random())<<21;
    371 }
    372 
    373 void
    374 A_PosAttack(mobj_t* actor)
    375 {
    376 	int angle, damage, slope;
    377 
    378 	if (!actor->target) return;
    379 	A_FaceTarget (actor);
    380 	angle = actor->angle;
    381 	slope = P_AimLineAttack (actor, angle, MISSILERANGE);
    382 	S_StartSound (actor, sfx_pistol);
    383 	angle += (P_Random()-P_Random())<<20;
    384 	damage = ((P_Random()%5)+1)*3;
    385 	P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
    386 }
    387 
    388 void
    389 A_SPosAttack(mobj_t* actor)
    390 {
    391 	int		i, angle, bangle, damage, slope;
    392 
    393 	if (!actor->target) return;
    394 	S_StartSound(actor, sfx_shotgn);
    395 	A_FaceTarget(actor);
    396 	bangle = actor->angle;
    397 	slope = P_AimLineAttack (actor, bangle, MISSILERANGE);
    398 	for (i = 0; i < 3; ++i) {
    399 		angle = bangle + ((P_Random()-P_Random()) << 20);
    400 		damage = ((P_Random()%5)+1)*3;
    401 		P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
    402 	}
    403 }
    404 
    405 void
    406 A_CPosAttack(mobj_t* actor)
    407 {
    408 	int angle, bangle, damage, slope;
    409 
    410 	if (!actor->target) return;
    411 	S_StartSound(actor, sfx_shotgn);
    412 	A_FaceTarget(actor);
    413 	bangle = actor->angle;
    414 	slope = P_AimLineAttack(actor, bangle, MISSILERANGE);
    415 	angle = bangle + ((P_Random()-P_Random())<<20);
    416 	damage = ((P_Random()%5)+1)*3;
    417 	P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
    418 }
    419 
    420 void
    421 A_CPosRefire(mobj_t* actor)
    422 {
    423 	A_FaceTarget(actor);
    424 
    425 	if (P_Random() < 40) return;
    426 	if (!actor->target || actor->target->health <= 0 || !P_CheckSight (actor, actor->target)) P_SetMobjState (actor, actor->info->seestate);
    427 }
    428 
    429 void
    430 A_SpidRefire(mobj_t* actor)
    431 {
    432 	A_FaceTarget(actor);
    433 
    434 	if (P_Random() < 10) return;
    435 	if (!actor->target || actor->target->health <= 0 || !P_CheckSight (actor, actor->target)) P_SetMobjState (actor, actor->info->seestate);
    436 }
    437 
    438 void
    439 A_BspiAttack(mobj_t *actor)
    440 {
    441 	if (!actor->target) return;
    442 	A_FaceTarget (actor);
    443 	P_SpawnMissile (actor, actor->target, MT_ARACHPLAZ);
    444 }
    445 
    446 void
    447 A_TroopAttack(mobj_t* actor)
    448 {
    449 	int damage;
    450 
    451 	if (!actor->target) return;
    452 	A_FaceTarget (actor);
    453 	if (P_CheckMeleeRange (actor)) {
    454 		S_StartSound (actor, sfx_claw);
    455 		damage = (P_Random()%8+1)*3;
    456 		P_DamageMobj (actor->target, actor, actor, damage);
    457 		return;
    458 	}
    459 	P_SpawnMissile (actor, actor->target, MT_TROOPSHOT);
    460 }
    461 
    462 void
    463 A_SargAttack(mobj_t* actor)
    464 {
    465 	int damage;
    466 
    467 	if (!actor->target) return;
    468 	A_FaceTarget(actor);
    469 	if (P_CheckMeleeRange (actor)) {
    470 		damage = ((P_Random()%10)+1)*4;
    471 		P_DamageMobj (actor->target, actor, actor, damage);
    472 	}
    473 }
    474 
    475 void
    476 A_HeadAttack(mobj_t* actor)
    477 {
    478 	int damage;
    479 
    480 	if (!actor->target) return;
    481 	A_FaceTarget(actor);
    482 	if (P_CheckMeleeRange (actor)) {
    483 		damage = (P_Random()%6+1)*10;
    484 		P_DamageMobj (actor->target, actor, actor, damage);
    485 		return;
    486 	}
    487 	P_SpawnMissile (actor, actor->target, MT_HEADSHOT);
    488 }
    489 
    490 void
    491 A_CyberAttack(mobj_t* actor)
    492 {
    493 	if (!actor->target) return;
    494 	A_FaceTarget (actor);
    495 	P_SpawnMissile (actor, actor->target, MT_ROCKET);
    496 }
    497 
    498 void
    499 A_BruisAttack(mobj_t* actor)
    500 {
    501 	int damage;
    502 
    503 	if (!actor->target) return;
    504 	if (P_CheckMeleeRange (actor)) {
    505 		S_StartSound (actor, sfx_claw);
    506 		damage = (P_Random()%8+1)*10;
    507 		P_DamageMobj (actor->target, actor, actor, damage);
    508 		return;
    509 	}
    510 	P_SpawnMissile (actor, actor->target, MT_BRUISERSHOT);
    511 }
    512 
    513 void
    514 A_SkelMissile(mobj_t* actor)
    515 {
    516 	mobj_t*	mo;
    517 
    518 	if (!actor->target) return;
    519 	A_FaceTarget (actor);
    520 	actor->z += 16*FRACUNIT;
    521 	mo = P_SpawnMissile (actor, actor->target, MT_TRACER);
    522 	actor->z -= 16*FRACUNIT;
    523 	mo->x += mo->momx;
    524 	mo->y += mo->momy;
    525 	mo->tracer = actor->target;
    526 }
    527 
    528 
    529 void A_Tracer (mobj_t* actor)
    530 {
    531 	angle_t	exact;
    532 	fixed_t	dist;
    533 	fixed_t	slope;
    534 	mobj_t*	dest;
    535 	mobj_t*	th;
    536 
    537 	if (gametic & 3) return;
    538 	P_SpawnPuff(actor->x, actor->y, actor->z);
    539 	th = P_SpawnMobj (actor->x-actor->momx, actor->y-actor->momy, actor->z, MT_SMOKE);
    540 	th->momz = FRACUNIT;
    541 	th->tics -= P_Random() & 3;
    542 	if (th->tics < 1) th->tics = 1;
    543 	dest = actor->tracer;
    544 	if (!dest || dest->health <= 0) return;
    545 	exact = R_PointToAngle2(actor->x, actor->y, dest->x, dest->y);
    546 	if (exact != actor->angle) {
    547 		if (exact - actor->angle > 0x80000000) {
    548 			actor->angle -= TRACEANGLE;
    549 			if (exact - actor->angle < 0x80000000)
    550 			actor->angle = exact;
    551 		} else {
    552 			actor->angle += TRACEANGLE;
    553 			if (exact - actor->angle > 0x80000000)
    554 			actor->angle = exact;
    555 		}
    556 	}
    557 	exact = actor->angle>>ANGLETOFINESHIFT;
    558 	actor->momx = FixedMul (actor->info->speed, finecosine[exact]);
    559 	actor->momy = FixedMul (actor->info->speed, finesine[exact]);
    560 	dist = P_AproxDistance (dest->x - actor->x, dest->y - actor->y);
    561 	dist = dist / actor->info->speed;
    562 	if (dist < 1) dist = 1;
    563 	slope = (dest->z+40*FRACUNIT - actor->z) / dist;
    564 	if (slope < actor->momz) actor->momz -= FRACUNIT/8;
    565 	else actor->momz += FRACUNIT/8;
    566 }
    567 
    568 void
    569 A_SkelWhoosh(mobj_t* actor)
    570 {
    571 	if (!actor->target) return;
    572 	A_FaceTarget (actor);
    573 	S_StartSound (actor,sfx_skeswg);
    574 }
    575 
    576 void
    577 A_SkelFist(mobj_t* actor)
    578 {
    579 	int damage;
    580 
    581 	if (!actor->target) return;
    582 	A_FaceTarget (actor);
    583 	if (P_CheckMeleeRange (actor)) {
    584 		damage = ((P_Random()%10)+1)*6;
    585 		S_StartSound (actor, sfx_skepch);
    586 		P_DamageMobj (actor->target, actor, actor, damage);
    587 	}
    588 }
    589 
    590 boolean
    591 PIT_VileCheck(mobj_t* thing)
    592 {
    593 	boolean check;
    594 	int     maxdist;
    595 
    596 	if (!(thing->flags & MF_CORPSE)) return true;
    597 	if (thing->tics != -1) return true;
    598 	if (thing->info->raisestate == S_NULL) return true;
    599 	maxdist = thing->info->radius + mobjinfo[MT_VILE].radius;
    600 	if (abs(thing->x - viletryx) > maxdist || abs(thing->y - viletryy) > maxdist) return true;
    601 	corpsehit = thing;
    602 	corpsehit->momx = corpsehit->momy = 0;
    603 	corpsehit->height <<= 2;
    604 	check = P_CheckPosition (corpsehit, corpsehit->x, corpsehit->y);
    605 	corpsehit->height >>= 2;
    606 	if (!check) return true;
    607 	return false;
    608 }
    609 
    610 void
    611 A_VileChase(mobj_t* actor)
    612 {
    613 	mobjinfo_t* info;
    614 	mobj_t*     temp;
    615 	int         xl, xh, yl, yh, bx, by;
    616 
    617 	if (actor->movedir != DI_NODIR) {
    618 		viletryx = actor->x + actor->info->speed*xspeed[actor->movedir];
    619 		viletryy = actor->y + actor->info->speed*yspeed[actor->movedir];
    620 		xl = (viletryx - bmaporgx - MAXRADIUS*2)>>MAPBLOCKSHIFT;
    621 		xh = (viletryx - bmaporgx + MAXRADIUS*2)>>MAPBLOCKSHIFT;
    622 		yl = (viletryy - bmaporgy - MAXRADIUS*2)>>MAPBLOCKSHIFT;
    623 		yh = (viletryy - bmaporgy + MAXRADIUS*2)>>MAPBLOCKSHIFT;
    624 		vileobj = actor;
    625 		for (bx=xl ; bx<=xh ; bx++) {
    626 			for (by=yl ; by<=yh ; by++) {
    627 				if (!P_BlockThingsIterator(bx,by,PIT_VileCheck)) {
    628 					temp = actor->target;
    629 					actor->target = corpsehit;
    630 					A_FaceTarget (actor);
    631 					actor->target = temp;
    632 					P_SetMobjState (actor, S_VILE_HEAL1);
    633 					S_StartSound (corpsehit, sfx_slop);
    634 					info = corpsehit->info;
    635 					P_SetMobjState (corpsehit,info->raisestate);
    636 					corpsehit->height <<= 2;
    637 					corpsehit->flags = info->flags;
    638 					corpsehit->health = info->spawnhealth;
    639 					corpsehit->target = NULL;
    640 					return;
    641 				}
    642 			}
    643 		}
    644 	}
    645 	A_Chase (actor);
    646 }
    647 
    648 void
    649 A_VileStart(mobj_t* actor)
    650 {
    651 	S_StartSound (actor, sfx_vilatk);
    652 }
    653 
    654 void A_Fire(mobj_t* actor);
    655 
    656 void
    657 A_StartFire(mobj_t* actor)
    658 {
    659 	S_StartSound(actor,sfx_flamst);
    660 	A_Fire(actor);
    661 }
    662 
    663 void
    664 A_FireCrackle(mobj_t* actor)
    665 {
    666 	S_StartSound(actor,sfx_flame);
    667 	A_Fire(actor);
    668 }
    669 
    670 void A_Fire (mobj_t* actor)
    671 {
    672 	mobj_t*	dest;
    673 	unsigned	an;
    674 
    675 	dest = actor->tracer;
    676 	if (!dest) return;
    677 	if (!P_CheckSight (actor->target, dest)) return;
    678 	an = dest->angle >> ANGLETOFINESHIFT;
    679 	P_UnsetThingPosition (actor);
    680 	actor->x = dest->x + FixedMul (24*FRACUNIT, finecosine[an]);
    681 	actor->y = dest->y + FixedMul (24*FRACUNIT, finesine[an]);
    682 	actor->z = dest->z;
    683 	P_SetThingPosition (actor);
    684 }
    685 
    686 void
    687 A_VileTarget(mobj_t* actor)
    688 {
    689 	mobj_t*	fog;
    690 
    691 	if (!actor->target) return;
    692 	A_FaceTarget (actor);
    693 	fog = P_SpawnMobj (actor->target->x, actor->target->x, actor->target->z, MT_FIRE);
    694 	actor->tracer = fog;
    695 	fog->target = actor;
    696 	fog->tracer = actor->target;
    697 	A_Fire (fog);
    698 }
    699 
    700 void
    701 A_VileAttack(mobj_t* actor)
    702 {
    703 	mobj_t* fire;
    704 	int     an;
    705 
    706 	if (!actor->target) return;
    707 	A_FaceTarget(actor);
    708 	if (!P_CheckSight (actor, actor->target)) return;
    709 	S_StartSound (actor, sfx_barexp);
    710 	P_DamageMobj (actor->target, actor, actor, 20);
    711 	actor->target->momz = 1000*FRACUNIT/actor->target->info->mass;
    712 	an = actor->angle >> ANGLETOFINESHIFT;
    713 	fire = actor->tracer;
    714 	if (!fire) return;
    715 	fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]);
    716 	fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]);
    717 	P_RadiusAttack (fire, actor, 70 );
    718 }
    719 
    720 
    721 void
    722 A_FatRaise(mobj_t *actor)
    723 {
    724 	A_FaceTarget(actor);
    725 	S_StartSound(actor, sfx_manatk);
    726 }
    727 
    728 void
    729 A_FatAttack1(mobj_t* actor)
    730 {
    731 	mobj_t*	mo;
    732 	int		an;
    733 
    734 	A_FaceTarget (actor);
    735 	actor->angle += FATSPREAD;
    736 	P_SpawnMissile (actor, actor->target, MT_FATSHOT);
    737 	mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
    738 	mo->angle += FATSPREAD;
    739 	an = mo->angle >> ANGLETOFINESHIFT;
    740 	mo->momx = FixedMul (mo->info->speed, finecosine[an]);
    741 	mo->momy = FixedMul (mo->info->speed, finesine[an]);
    742 }
    743 
    744 void
    745 A_FatAttack2(mobj_t* actor)
    746 {
    747 	mobj_t*	mo;
    748 	int		an;
    749 
    750 	A_FaceTarget (actor);
    751 	actor->angle -= FATSPREAD;
    752 	P_SpawnMissile (actor, actor->target, MT_FATSHOT);
    753 	mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
    754 	mo->angle -= FATSPREAD*2;
    755 	an = mo->angle >> ANGLETOFINESHIFT;
    756 	mo->momx = FixedMul (mo->info->speed, finecosine[an]);
    757 	mo->momy = FixedMul (mo->info->speed, finesine[an]);
    758 }
    759 
    760 void
    761 A_FatAttack3(mobj_t* actor)
    762 {
    763 	mobj_t*	mo;
    764 	int		an;
    765 
    766 	A_FaceTarget (actor);
    767 	mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
    768 	mo->angle -= FATSPREAD/2;
    769 	an = mo->angle >> ANGLETOFINESHIFT;
    770 	mo->momx = FixedMul (mo->info->speed, finecosine[an]);
    771 	mo->momy = FixedMul (mo->info->speed, finesine[an]);
    772 	mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
    773 	mo->angle += FATSPREAD/2;
    774 	an = mo->angle >> ANGLETOFINESHIFT;
    775 	mo->momx = FixedMul (mo->info->speed, finecosine[an]);
    776 	mo->momy = FixedMul (mo->info->speed, finesine[an]);
    777 }
    778 
    779 void A_SkullAttack (mobj_t* actor)
    780 {
    781 	mobj_t*		dest;
    782 	angle_t		an;
    783 	int			dist;
    784 
    785 	if (!actor->target) return;
    786 	dest = actor->target;
    787 	actor->flags |= MF_SKULLFLY;
    788 	S_StartSound(actor, actor->info->attacksound);
    789 	A_FaceTarget(actor);
    790 	an = actor->angle >> ANGLETOFINESHIFT;
    791 	actor->momx = FixedMul(SKULLSPEED, finecosine[an]);
    792 	actor->momy = FixedMul(SKULLSPEED, finesine[an]);
    793 	dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y);
    794 	dist = dist / SKULLSPEED;
    795 	if (dist < 1) dist = 1;
    796 	actor->momz = (dest->z+(dest->height>>1) - actor->z) / dist;
    797 }
    798 
    799 void
    800 A_PainShootSkull(mobj_t* actor, angle_t angle)
    801 {
    802 	mobj_t*    newmobj;
    803 	thinker_t* currentthinker;
    804 	fixed_t    x, y, z;
    805 	angle_t	   an;
    806 	int		   prestep, count;
    807 
    808 	count = 0;
    809 	currentthinker = thinkercap.next;
    810 	while (currentthinker != &thinkercap) {
    811 		if ((currentthinker->function.acp1 == (actionf_p1)P_MobjThinker) && ((mobj_t*)currentthinker)->type == MT_SKULL) ++count;
    812 		currentthinker = currentthinker->next;
    813 	}
    814 	if (count > 20) return;
    815 	an = angle >> ANGLETOFINESHIFT;
    816 	prestep = 4 * FRACUNIT + 3 *(actor->info->radius + mobjinfo[MT_SKULL].radius)/2;
    817 	x = actor->x + FixedMul(prestep, finecosine[an]);
    818 	y = actor->y + FixedMul(prestep, finesine[an]);
    819 	z = actor->z + 8 * FRACUNIT;
    820 	newmobj = P_SpawnMobj (x, y, z, MT_SKULL);
    821 	if (!P_TryMove (newmobj, newmobj->x, newmobj->y)) {
    822 		P_DamageMobj (newmobj,actor,actor,10000);
    823 		return;
    824 	}
    825 	newmobj->target = actor->target;
    826 	A_SkullAttack (newmobj);
    827 }
    828 
    829 void
    830 A_PainAttack(mobj_t* actor)
    831 {
    832 	if (!actor->target) return;
    833 	A_FaceTarget(actor);
    834 	A_PainShootSkull(actor, actor->angle);
    835 }
    836 
    837 void
    838 A_PainDie(mobj_t* actor)
    839 {
    840 	A_Fall(actor);
    841 	A_PainShootSkull(actor, actor->angle+ANG90);
    842 	A_PainShootSkull(actor, actor->angle+ANG180);
    843 	A_PainShootSkull(actor, actor->angle+ANG270);
    844 }
    845 
    846 void
    847 A_Scream(mobj_t* actor)
    848 {
    849 	int sound;
    850 
    851 	switch (actor->info->deathsound) {
    852 		case 0:
    853 			return;
    854 		case sfx_podth1:
    855 		case sfx_podth2:
    856 		case sfx_podth3:
    857 			sound = sfx_podth1 + P_Random ()%3;
    858 			break;
    859 		case sfx_bgdth1:
    860 		case sfx_bgdth2:
    861 			sound = sfx_bgdth1 + P_Random ()%2;
    862 			break;
    863 		default:
    864 			sound = actor->info->deathsound;
    865 			break;
    866 	}
    867 	if (actor->type==MT_SPIDER || actor->type == MT_CYBORG) S_StartSound(NULL, sound);
    868 	else S_StartSound(actor, sound);
    869 }
    870 
    871 void
    872 A_XScream(mobj_t* actor)
    873 {
    874 	S_StartSound (actor, sfx_slop);
    875 }
    876 
    877 void
    878 A_Pain(mobj_t* actor)
    879 {
    880 	if (actor->info->painsound) S_StartSound(actor, actor->info->painsound);
    881 }
    882 
    883 void
    884 A_Fall(mobj_t *actor)
    885 {
    886 	actor->flags &= ~MF_SOLID;
    887 }
    888 
    889 void
    890 A_Explode(mobj_t* thingy)
    891 {
    892 	P_RadiusAttack ( thingy, thingy->target, 128 );
    893 }
    894 
    895 void
    896 A_BossDeath(mobj_t* mo)
    897 {
    898 	thinker_t* th;
    899 	mobj_t*    mo2;
    900 	line_t     junk;
    901 	int        i;
    902 
    903 	switch (gameepisode) {
    904 		case 1:
    905 			if (gamemap != 8) return;
    906 			if (mo->type != MT_BRUISER) return;
    907 			break;
    908 		case 2:
    909 			if (gamemap != 8) return;
    910 			if (mo->type != MT_CYBORG) return;
    911 			break;
    912 		case 3:
    913 			if (gamemap != 8) return;
    914 			if (mo->type != MT_SPIDER) return;
    915 			break;
    916 		case 4:
    917 			switch (gamemap) {
    918 				case 6:
    919 					if (mo->type != MT_CYBORG)
    920 					return;
    921 					break;
    922 				case 8:
    923 					if (mo->type != MT_SPIDER)
    924 					return;
    925 					break;
    926 				default:
    927 					return;
    928 					break;
    929 			}
    930 			break;
    931 		default:
    932 			if (gamemap != 8) return;
    933 			break;
    934 	}
    935 	for (i = 0; i < MAXPLAYERS; ++i)
    936 		if (playeringame[i] && players[i].health > 0) break;
    937 	if (i == MAXPLAYERS) return;
    938 	for (th = thinkercap.next ; th != &thinkercap ; th=th->next) {
    939 		if (th->function.acp1 != (actionf_p1)P_MobjThinker) continue;
    940 		mo2 = (mobj_t*)th;
    941 		if (mo2 != mo && mo2->type == mo->type && mo2->health > 0) return;
    942 	}
    943 	switch (gameepisode) {
    944 		case 1:
    945 			junk.tag = 666;
    946 			EV_DoFloor (&junk, lowerFloorToLowest);
    947 			return;
    948 			break;
    949 		case 4:
    950 			switch (gamemap) {
    951 				case 6:
    952 					junk.tag = 666;
    953 					EV_DoDoor (&junk, blazeOpen);
    954 					return;
    955 					break;
    956 				case 8:
    957 					junk.tag = 666;
    958 					EV_DoFloor (&junk, lowerFloorToLowest);
    959 					return;
    960 					break;
    961 			}
    962 	}
    963 	G_ExitLevel();
    964 }
    965 
    966 void
    967 A_Hoof(mobj_t* mo)
    968 {
    969 	S_StartSound(mo, sfx_hoof);
    970 	A_Chase(mo);
    971 }
    972 
    973 void
    974 A_Metal(mobj_t* mo)
    975 {
    976 	S_StartSound(mo, sfx_metal);
    977 	A_Chase(mo);
    978 }
    979 
    980 void
    981 A_BabyMetal(mobj_t* mo)
    982 {
    983 	S_StartSound(mo, sfx_bspwlk);
    984 	A_Chase(mo);
    985 }
    986 
    987 void
    988 A_OpenShotgun2(player_t* player, pspdef_t* psp)
    989 {
    990 	S_StartSound(player->mo, sfx_dbopn);
    991 }
    992 
    993 void
    994 A_LoadShotgun2(player_t* player, pspdef_t* psp)
    995 {
    996 	S_StartSound (player->mo, sfx_dbload);
    997 }
    998 
    999 void A_ReFire(player_t* player, pspdef_t* psp);
   1000 
   1001 void
   1002 A_CloseShotgun2(player_t* player, pspdef_t* psp)
   1003 {
   1004 	S_StartSound(player->mo, sfx_dbcls);
   1005 	A_ReFire(player,psp);
   1006 }
   1007 
   1008 void A_BrainAwake (mobj_t* mo)
   1009 {
   1010 	thinker_t* thinker;
   1011 	mobj_t*    m;
   1012 
   1013 	numbraintargets = 0;
   1014 	braintargeton = 0;
   1015 	thinker = thinkercap.next;
   1016 	for (thinker = thinkercap.next; thinker != &thinkercap; thinker = thinker->next) {
   1017 		if (thinker->function.acp1 != (actionf_p1)P_MobjThinker) continue;
   1018 		m = (mobj_t *)thinker;
   1019 		if (m->type == MT_BOSSTARGET) {
   1020 			braintargets[numbraintargets] = m;
   1021 			numbraintargets++;
   1022 		}
   1023 	}
   1024 	S_StartSound(NULL,sfx_bossit);
   1025 }
   1026 
   1027 void
   1028 A_BrainPain(mobj_t* mo)
   1029 {
   1030 	S_StartSound(NULL,sfx_bospn);
   1031 }
   1032 
   1033 void
   1034 A_BrainScream(mobj_t* mo)
   1035 {
   1036 	mobj_t*	th;
   1037 	int x, y, z;
   1038 
   1039 	for (x=mo->x - 196*FRACUNIT; x < mo->x + 320*FRACUNIT; x += FRACUNIT*8) {
   1040 		y = mo->y - 320*FRACUNIT;
   1041 		z = 128 + P_Random()*2*FRACUNIT;
   1042 		th = P_SpawnMobj (x,y,z, MT_ROCKET);
   1043 		th->momz = P_Random()*512;
   1044 		P_SetMobjState(th, S_BRAINEXPLODE1);
   1045 		th->tics -= P_Random() & 7;
   1046 		if (th->tics < 1) th->tics = 1;
   1047 	}
   1048 	S_StartSound(NULL, sfx_bosdth);
   1049 }
   1050 
   1051 void
   1052 A_BrainExplode(mobj_t* mo)
   1053 {
   1054 	mobj_t*	th;
   1055 	int     x, y, z;
   1056 
   1057 	x = mo->x + (P_Random() - P_Random()) * 2048;
   1058 	y = mo->y;
   1059 	z = 128 + P_Random()*2*FRACUNIT;
   1060 	th = P_SpawnMobj (x,y,z, MT_ROCKET);
   1061 	th->momz = P_Random()*512;
   1062 	P_SetMobjState(th, S_BRAINEXPLODE1);
   1063 	th->tics -= P_Random() & 7;
   1064 	if (th->tics < 1) th->tics = 1;
   1065 }
   1066 
   1067 void
   1068 A_BrainDie(mobj_t* mo)
   1069 {
   1070 	G_ExitLevel();
   1071 }
   1072 
   1073 
   1074 void
   1075 A_BrainSpit(mobj_t* mo)
   1076 {
   1077 	static int easy = 0;
   1078 	mobj_t*    targ;
   1079 	mobj_t*    newmobj;
   1080 
   1081 	easy ^= 1;
   1082 	if (gameskill <= sk_easy && (!easy)) return;
   1083 	targ = braintargets[braintargeton];
   1084 	braintargeton = (braintargeton+1)%numbraintargets;
   1085 	newmobj = P_SpawnMissile(mo, targ, MT_SPAWNSHOT);
   1086 	newmobj->target = targ;
   1087 	newmobj->reactiontime = ((targ->y - mo->y)/newmobj->momy) / newmobj->state->tics;
   1088 	S_StartSound(NULL, sfx_bospit);
   1089 }
   1090 
   1091 void
   1092 A_SpawnSound(mobj_t* mo)
   1093 {
   1094 	S_StartSound(mo,sfx_boscub);
   1095 	A_SpawnFly(mo);
   1096 }
   1097 
   1098 void
   1099 A_SpawnFly(mobj_t* mo)
   1100 {
   1101 	mobj_t*    newmobj, *fog, *targ;
   1102 	mobjtype_t type;
   1103 	int        r;
   1104 
   1105 	if (--mo->reactiontime) return;
   1106 	targ = mo->target;
   1107 	fog = P_SpawnMobj(targ->x, targ->y, targ->z, MT_SPAWNFIRE);
   1108 	S_StartSound(fog, sfx_telept);
   1109 	r = P_Random();
   1110 	if (r < 50) type = MT_TROOP;
   1111 	else if (r < 90) type = MT_SERGEANT;
   1112 	else if (r < 120) type = MT_SHADOWS;
   1113 	else if (r < 130) type = MT_PAIN;
   1114 	else if (r < 160) type = MT_HEAD;
   1115 	else if (r < 162) type = MT_VILE;
   1116 	else if (r < 172) type = MT_UNDEAD;
   1117 	else if (r < 192) type = MT_BABY;
   1118 	else if (r < 222) type = MT_FATSO;
   1119 	else if (r < 246) type = MT_KNIGHT;
   1120 	else type = MT_BRUISER;
   1121 	newmobj	= P_SpawnMobj (targ->x, targ->y, targ->z, type);
   1122 	if (P_LookForPlayers (newmobj, true)) P_SetMobjState(newmobj, newmobj->info->seestate);
   1123 	P_TeleportMove(newmobj, newmobj->x, newmobj->y);
   1124 	P_RemoveMobj(mo);
   1125 }
   1126 
   1127 void
   1128 A_PlayerScream(mobj_t* mo)
   1129 {
   1130 	int sound;
   1131 
   1132 	sound = sfx_pldeth;
   1133 	S_StartSound(mo, sound);
   1134 }