DOOM64-RE

DOOM 64 Reverse Engineering
Log | Files | Refs | README | LICENSE

p_enemy.c (36741B)


      1 /* P_enemy.c */
      2 
      3 #include "doomdef.h"
      4 #include "p_local.h"
      5 
      6 void A_Fall (mobj_t *actor);
      7 
      8 typedef enum
      9 {
     10 	DP_STRAIGHT,
     11     DP_LEFT,
     12     DP_RIGHT
     13 } dirproj_e;
     14 
     15 mobj_t* P_MissileAttack(mobj_t *actor, dirproj_e direction);
     16 
     17 /*
     18 ===============================================================================
     19 
     20 							ENEMY THINKING
     21 
     22 enemies are allways spawned with targetplayer = -1, threshold = 0
     23 Most monsters are spawned unaware of all players, but some can be made preaware
     24 
     25 ===============================================================================
     26 */
     27 
     28 /*
     29 ================
     30 =
     31 = P_CheckMeleeRange
     32 =
     33 ================
     34 */
     35 
     36 boolean P_CheckMeleeRange (mobj_t *actor) // 80010B90
     37 {
     38 	mobj_t		*pl;
     39 	fixed_t		dist;
     40 
     41 	if (!(actor->flags&MF_SEETARGET))
     42 		return false;
     43 
     44 	if (!actor->target)
     45 		return false;
     46 
     47 	pl = actor->target;
     48 	dist = P_AproxDistance (pl->x-actor->x, pl->y-actor->y);
     49 	if (dist >= MELEERANGE)
     50 		return false;
     51 
     52 	return true;
     53 }
     54 
     55 /*
     56 ================
     57 =
     58 = P_CheckMissileRange
     59 =
     60 ================
     61 */
     62 
     63 boolean P_CheckMissileRange (mobj_t *actor) // 80010C10
     64 {
     65 	fixed_t		dist;
     66 
     67 	if (!(actor->flags & MF_SEETARGET))
     68 		return false;
     69 
     70 	if (actor->flags & MF_JUSTHIT)
     71 	{	/* the target just hit the enemy, so fight back! */
     72 		actor->flags &= ~MF_JUSTHIT;
     73 		return true;
     74 	}
     75 
     76 	if (actor->reactiontime)
     77 		return false;		/* don't attack yet */
     78 
     79 	dist = P_AproxDistance ( actor->x-actor->target->x, actor->y-actor->target->y) - 64*FRACUNIT;
     80 	if (!actor->info->meleestate)
     81 		dist -= 128*FRACUNIT;		/* no melee attack, so fire more */
     82 
     83 	dist >>= 16;
     84 
     85 	if (actor->type == MT_SKULL)
     86 		dist >>= 1;
     87 
     88 	if (dist > 200)
     89 		dist = 200;
     90 
     91 	if (P_Random() < dist)
     92 		return false;
     93 
     94 	return true;
     95 }
     96 
     97 
     98 /*
     99 ================
    100 =
    101 = P_Move
    102 =
    103 = Move in the current direction
    104 = returns false if the move is blocked
    105 ================
    106 */
    107 
    108 fixed_t	xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};// 8005ACC0
    109 fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};// 8005ACE0
    110 
    111 extern	line_t *blockline; // 800A5D9C
    112 
    113 boolean P_Move (mobj_t *actor) // 80010D08
    114 {
    115 	fixed_t	tryx, tryy;
    116 	boolean		good;
    117 	line_t		*blkline;
    118 
    119 	if (actor->movedir == DI_NODIR)
    120 		return false;
    121 
    122     if((actor->flags & MF_GRAVITY) != 0)
    123     {
    124         if(actor->floorz != actor->z)
    125         {
    126             return false;
    127         }
    128     }
    129 
    130 	tryx = actor->x + actor->info->speed * xspeed[actor->movedir];
    131 	tryy = actor->y + actor->info->speed * yspeed[actor->movedir];
    132 
    133 	if (!P_TryMove (actor, tryx, tryy) )
    134 	{	/* open any specials */
    135 		if (actor->flags & MF_FLOAT && floatok)
    136 		{	/* must adjust height */
    137 			if (actor->z < tmfloorz)
    138 				actor->z += FLOATSPEED;
    139 			else
    140 				actor->z -= FLOATSPEED;
    141 
    142 			//actor->flags |= MF_INFLOAT;
    143 			return true;
    144 		}
    145 
    146 		blkline = blockline;//(line_t *)DSPRead (&blockline);
    147 		if (!blkline || !blkline->special)
    148 			return false;
    149 
    150 		actor->movedir = DI_NODIR;
    151 		good = false;
    152 
    153         if(blockline->special & MLU_USE)
    154             good = P_UseSpecialLine (blkline, actor);
    155 
    156 		return good;
    157 	}
    158 	//else
    159 	//	actor->flags &= ~MF_INFLOAT;
    160 
    161 	//if (!(actor->flags & MF_FLOAT))
    162 	//	actor->z = actor->floorz;
    163 
    164 	return true;
    165 }
    166 
    167 
    168 /*
    169 ==================================
    170 =
    171 = TryWalk
    172 =
    173 = Attempts to move actoron in its current (ob->moveangle) direction.
    174 =
    175 = If blocked by either a wall or an actor returns FALSE
    176 = If move is either clear or blocked only by a door, returns TRUE and sets
    177 = If a door is in the way, an OpenDoor call is made to start it opening.
    178 =
    179 ==================================
    180 */
    181 
    182 boolean P_TryWalk (mobj_t *actor) // 80010E88
    183 {
    184 	if (!P_Move (actor))
    185 		return false;
    186 
    187 	actor->movecount = P_Random()&7;
    188 	return true;
    189 }
    190 
    191 
    192 /*
    193 ================
    194 =
    195 = P_NewChaseDir
    196 =
    197 ================
    198 */
    199 
    200 dirtype_t opposite[] = // 8005AD00
    201 {DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_EAST, DI_NORTHEAST,
    202 DI_NORTH, DI_NORTHWEST, DI_NODIR};
    203 
    204 dirtype_t diags[] = {DI_NORTHWEST,DI_NORTHEAST,DI_SOUTHWEST,DI_SOUTHEAST}; // 8005AD24
    205 
    206 void P_NewChaseDir (mobj_t *actor) // 80010ED0
    207 {
    208 	fixed_t		deltax,deltay;
    209 	dirtype_t	d[3];
    210 	dirtype_t	tdir, olddir, turnaround;
    211 
    212 	if (!actor->target)
    213 		I_Error ("P_NewChaseDir: called with no target");
    214 
    215 	olddir = actor->movedir;
    216 	turnaround=opposite[olddir];
    217 
    218 	deltax = actor->target->x - actor->x;
    219 	deltay = actor->target->y - actor->y;
    220 
    221 	if (deltax>10*FRACUNIT)
    222 		d[1]= DI_EAST;
    223 	else if (deltax<-10*FRACUNIT)
    224 		d[1]= DI_WEST;
    225 	else
    226 		d[1]=DI_NODIR;
    227 
    228 	if (deltay<-10*FRACUNIT)
    229 		d[2]= DI_SOUTH;
    230 	else if (deltay>10*FRACUNIT)
    231 		d[2]= DI_NORTH;
    232 	else
    233 		d[2]=DI_NODIR;
    234 
    235 /* try direct route */
    236 	if (d[1] != DI_NODIR && d[2] != DI_NODIR)
    237 	{
    238 		actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
    239 		if (actor->movedir != turnaround && P_TryWalk(actor))
    240 			return;
    241 	}
    242 
    243 /* try other directions */
    244 	if (P_Random() > 200 ||  abs(deltay)>abs(deltax))
    245 	{
    246 		tdir=d[1];
    247 		d[1]=d[2];
    248 		d[2]=tdir;
    249 	}
    250 
    251 	if (d[1]==turnaround)
    252 		d[1]=DI_NODIR;
    253 
    254 	if (d[2]==turnaround)
    255 		d[2]=DI_NODIR;
    256 
    257 	if (d[1]!=DI_NODIR)
    258 	{
    259 		actor->movedir = d[1];
    260 		if (P_TryWalk(actor))
    261 			return;     /*either moved forward or attacked*/
    262 	}
    263 
    264 	if (d[2]!=DI_NODIR)
    265 	{
    266 		actor->movedir =d[2];
    267 		if (P_TryWalk(actor))
    268 			return;
    269 	}
    270 
    271 /* there is no direct path to the player, so pick another direction */
    272 
    273 	if (olddir!=DI_NODIR)
    274 	{
    275 		actor->movedir =olddir;
    276 		if (P_TryWalk(actor))
    277 			return;
    278 	}
    279 
    280 	if (P_Random()&1) 	/*randomly determine direction of search*/
    281 	{
    282 		for (tdir=DI_EAST ; tdir<=DI_SOUTHEAST ; tdir++)
    283 		{
    284 			if (tdir!=turnaround)
    285 			{
    286 				actor->movedir =tdir;
    287 				if ( P_TryWalk(actor) )
    288 					return;
    289 			}
    290 		}
    291 	}
    292 	else
    293 	{
    294 		for (tdir=DI_SOUTHEAST ; (int)tdir >= (int)DI_EAST;tdir--)
    295 		{
    296 			if (tdir!=turnaround)
    297 			{
    298 				actor->movedir =tdir;
    299 				if ( P_TryWalk(actor) )
    300 				return;
    301 			}
    302 		}
    303 	}
    304 
    305 	if (turnaround !=  DI_NODIR)
    306 	{
    307 		actor->movedir =turnaround;
    308 		if ( P_TryWalk(actor) )
    309 			return;
    310 	}
    311 
    312 	actor->movedir = DI_NODIR;		/* can't move */
    313 }
    314 
    315 
    316 /*
    317 ================
    318 =
    319 = P_LookForPlayers
    320 =
    321 = If allaround is false, only look 180 degrees in front
    322 = returns true if a player is targeted
    323 ================
    324 */
    325 
    326 boolean P_LookForPlayers (mobj_t *actor, boolean allaround) // 8001115C
    327 {
    328 	angle_t		an;
    329 	fixed_t		dist, dist2;
    330 	mobj_t		*mo;
    331 	mobj_t		*mobj;
    332 
    333 	mo = actor->target;
    334 	if (!mo || mo->health <= 0 || !(actor->flags & MF_SEETARGET))
    335 	{
    336 		if(actor->type > MT_PLAYERBOT3)   /* for monsters */
    337         {
    338             actor->target = players[0].mo;
    339         }
    340         else /* special case for player bots */
    341         {
    342             dist2 = MAXINT;
    343 
    344             for(mobj = mobjhead.next; mobj != &mobjhead; mobj = mobj->next)
    345             {
    346 
    347                 if((mobj->flags & MF_COUNTKILL) == 0 ||
    348                      mobj->type <= MT_PLAYERBOT3 ||
    349                      mobj->health <= 0           ||
    350                      mobj == actor)
    351                 {
    352                     continue;
    353                 }
    354 
    355                 /* find a killable target as close as possible */
    356                 dist = P_AproxDistance(mobj->x - actor->x, mobj->y - actor->y);
    357                 if(!(dist < dist2))
    358                     continue;
    359 
    360                 actor->target = mobj;
    361                 dist2 = dist;
    362             }
    363         }
    364 
    365 		return false;
    366 	}
    367 
    368 	if (!actor->subsector->sector->soundtarget)
    369     {
    370         if (!allaround)
    371         {
    372             an = R_PointToAngle2 (actor->x, actor->y, mo->x, mo->y) - actor->angle;
    373             if (an > ANG90 && an < ANG270)
    374             {
    375                 dist = P_AproxDistance (mo->x - actor->x, mo->y - actor->y);
    376                 /* if real close, react anyway */
    377                 if (dist > MELEERANGE)
    378                     return false;		/* behind back */
    379             }
    380         }
    381     }
    382 
    383 	return true;
    384 }
    385 
    386 
    387 /*
    388 ===============================================================================
    389 
    390 						ACTION ROUTINES
    391 
    392 ===============================================================================
    393 */
    394 
    395 /*
    396 ==============
    397 =
    398 = A_Look
    399 =
    400 = Stay in state until a player is sighted
    401 =
    402 ==============
    403 */
    404 
    405 void A_Look (mobj_t *actor) // 80011340
    406 {
    407 	mobj_t	*targ;
    408 	int		sound;
    409 
    410 	/* if current target is visible, start attacking */
    411 	if (!P_LookForPlayers(actor, false))
    412 	{
    413 		/* if the sector has a living soundtarget, make that the new target */
    414 		actor->threshold = 0;		/* any shot will wake up */
    415 		targ = actor->subsector->sector->soundtarget;
    416 		if (targ == NULL || !(targ->flags & MF_SHOOTABLE) || (actor->flags & MF_AMBUSH))
    417 			return;
    418 		actor->target = targ;
    419 	}
    420 
    421 	/* go into chase state */
    422 	if (actor->info->seesound)
    423 	{
    424 		switch (actor->info->seesound)
    425 		{
    426 		case sfx_possit1://sfx_posit1:
    427 		case sfx_possit2://sfx_posit2:
    428 		case sfx_possit3://sfx_posit3:
    429 			sound = sfx_possit1+(P_Random()&1);
    430 			break;
    431 		case sfx_impsit1://sfx_bgsit1:
    432 		case sfx_impsit2://sfx_bgsit2:
    433 			sound = sfx_impsit1+(P_Random()&1);
    434 			break;
    435 		default:
    436 			sound = actor->info->seesound;
    437 			break;
    438 		}
    439 
    440 		if (actor->type == MT_RESURRECTOR || actor->type == MT_CYBORG)
    441 			S_StartSound(NULL, sound);	// full volume
    442 		else
    443 			S_StartSound(actor, sound);
    444 	}
    445 
    446 	P_SetMobjState (actor, actor->info->seestate);
    447 }
    448 
    449 
    450 /*
    451 ==============
    452 =
    453 = A_Chase
    454 =
    455 = Actor has a melee attack, so it tries to close as fast as possible
    456 =
    457 ==============
    458 */
    459 
    460 void A_Chase (mobj_t *actor) // 8001146C
    461 {
    462 	int		delta;
    463 
    464 	if (actor->reactiontime)
    465 		actor->reactiontime--;
    466 
    467 	/* */
    468 	/* modify target threshold */
    469 	/* */
    470 	if (actor->threshold)
    471 		actor->threshold--;
    472 
    473 	/* */
    474 	/* turn towards movement direction if not there yet */
    475 	/* */
    476 	if (actor->movedir < 8)
    477 	{
    478 		actor->angle &= (7<<29);
    479 		delta = actor->angle - (actor->movedir << 29);
    480 		if (delta > 0)
    481 			actor->angle -= ANG90/2;
    482 		else if (delta < 0)
    483 			actor->angle += ANG90/2;
    484 	}
    485 
    486 	if (!actor->target || !(actor->target->flags&MF_SHOOTABLE))
    487 	{	/* look for a new target */
    488 		if (P_LookForPlayers(actor,true))
    489 			return;		/* got a new target */
    490 		P_SetMobjState (actor, actor->info->spawnstate);
    491 		return;
    492 	}
    493 
    494 	/* */
    495 	/* don't attack twice in a row */
    496 	/* */
    497 	if (actor->flags & MF_JUSTATTACKED)
    498 	{
    499 		actor->flags &= ~MF_JUSTATTACKED;
    500 		P_NewChaseDir (actor);
    501 		return;
    502 	}
    503 
    504 	/* */
    505 	/* check for melee attack */
    506 	/* */
    507 	if (actor->info->meleestate && P_CheckMeleeRange (actor))
    508 	{
    509 		if (actor->info->attacksound)
    510 			S_StartSound (actor, actor->info->attacksound);
    511 		P_SetMobjState (actor, actor->info->meleestate);
    512 		return;
    513 	}
    514 
    515 	/* */
    516 	/* check for missile attack */
    517 	/* */
    518 	#if ENABLE_NIGHTMARE == 1
    519 	if ((gameskill == sk_nightmare || !actor->movecount) && actor->info->missilestate
    520 	&& P_CheckMissileRange (actor))
    521 	{
    522 		P_SetMobjState (actor, actor->info->missilestate);
    523 		if (gameskill != sk_nightmare)
    524 			actor->flags |= MF_JUSTATTACKED;
    525 		return;
    526 	}
    527 	#else
    528 	if ( (/*gameskill == sk_nightmare || */!actor->movecount) && actor->info->missilestate
    529 	&& P_CheckMissileRange (actor))
    530 	{
    531 		P_SetMobjState (actor, actor->info->missilestate);
    532 		//if (gameskill != sk_nightmare)
    533 			actor->flags |= MF_JUSTATTACKED;
    534 		return;
    535 	}
    536 	#endif // ENABLE_NIGHTMARE
    537 
    538 
    539 	/* */
    540 	/* chase towards player */
    541 	/* */
    542 	if (--actor->movecount<0 || !P_Move (actor))
    543 		P_NewChaseDir (actor);
    544 
    545 	/* */
    546 	/* make active sound */
    547 	/* */
    548 	if (actor->info->activesound && P_Random () < 3)
    549 		S_StartSound (actor, actor->info->activesound);
    550 }
    551 
    552 /*============================================================================= */
    553 
    554 /*
    555 ==============
    556 =
    557 = A_FaceTarget
    558 =
    559 ==============
    560 */
    561 
    562 void A_FaceTarget (mobj_t *actor) // 800116A8
    563 {
    564     int rnd1, rnd2;
    565 	if (!actor->target)
    566 		return;
    567 
    568 	actor->flags &= ~MF_AMBUSH;
    569 	actor->angle = R_PointToAngle2 (actor->x, actor->y , actor->target->x, actor->target->y);
    570 
    571 	if (actor->target->flags & MF_SHADOW)
    572     {
    573         rnd1 = P_Random();
    574         rnd2 = P_Random();
    575 		actor->angle += (rnd2 - rnd1) << 21;
    576     }
    577 }
    578 
    579 /*
    580 ==============
    581 =
    582 = A_Scream
    583 =
    584 ==============
    585 */
    586 
    587 void A_Scream (mobj_t *actor) // 80011740
    588 {
    589 	int		sound;
    590 
    591 	switch (actor->info->deathsound)
    592 	{
    593 	case 0:
    594 		return;
    595 
    596 	case sfx_posdie1://sfx_podth1:
    597 	case sfx_posdie2://sfx_podth2:
    598 	case sfx_posdie3://sfx_podth3:
    599 		sound = sfx_posdie1 + (P_Random ()&1);
    600 		break;
    601 
    602 	case sfx_impdth1://sfx_bgdth1:
    603 	case sfx_impdth2://sfx_bgdth2:
    604 		sound = sfx_impdth1 + (P_Random ()&1);
    605 		break;
    606 
    607 	default:
    608 		sound = actor->info->deathsound;
    609 		break;
    610 	}
    611 
    612     S_StartSound(actor, sound);
    613 }
    614 
    615 /*
    616 ==============
    617 =
    618 = A_XScream
    619 =
    620 ==============
    621 */
    622 
    623 void A_XScream (mobj_t *actor) // 800117E4
    624 {
    625 	S_StartSound (actor, sfx_slop);
    626 }
    627 
    628 /*
    629 ==============
    630 =
    631 = A_Pain
    632 =
    633 ==============
    634 */
    635 
    636 void A_Pain (mobj_t *actor) // 80011804
    637 {
    638     if(actor->info->painsound)
    639     {
    640         if(actor->type == MT_RESURRECTOR)
    641             S_StartSound(NULL, actor->info->painsound);
    642         else
    643             S_StartSound(actor, actor->info->painsound);
    644     }
    645 }
    646 
    647 /*
    648 ==============
    649 =
    650 = A_Fall
    651 =
    652 ==============
    653 */
    654 
    655 void A_Fall (mobj_t *actor) // 8001185C
    656 {
    657 /* actor is on ground, it can be walked over */
    658 	actor->flags &= ~MF_SOLID;
    659 }
    660 
    661 
    662 /*
    663 ================
    664 =
    665 = A_Explode
    666 =
    667 ================
    668 */
    669 
    670 void A_Explode (mobj_t *thingy) // 80011870
    671 {
    672 	P_RadiusAttack(thingy, thingy->target, 128);
    673 }
    674 
    675 
    676 /*
    677 ================
    678 =
    679 = A_OnDeathTrigger(A_BossDeath)
    680 =
    681 = Possibly trigger special effects
    682 ================
    683 */
    684 
    685 void A_OnDeathTrigger (mobj_t *mo) // 80011894
    686 {
    687 	mobj_t		*mo2;
    688 
    689     if(!(mo->flags & MF_TRIGDEATH))
    690         return;
    691 
    692     for(mo2 = mobjhead.next; mo2 != &mobjhead; mo2 = mo2->next)
    693     {
    694         if((mo2->tid == mo->tid) && (mo2->health > 0))
    695             return;
    696     }
    697 
    698     if(!P_ActivateLineByTag(mo->tid, mo))
    699     {
    700         macroqueue[macroidx1].activator = mo;
    701         macroqueue[macroidx1].tag = mo->tid;
    702         macroidx1 = (macroidx1 + 1) & 3;
    703     }
    704 }
    705 
    706 /*
    707 ==============
    708 =
    709 = A_PosAttack
    710 =
    711 ==============
    712 */
    713 
    714 void A_PosAttack (mobj_t *actor) // 80011954
    715 {
    716 	int		angle, damage, rnd1, rnd2;
    717 
    718 	if (!actor->target)
    719 		return;
    720 
    721 	A_FaceTarget (actor);
    722 	angle = actor->angle;
    723 
    724 	S_StartSound (actor, sfx_pistol);
    725 
    726     rnd1 = P_Random();
    727     rnd2 = P_Random();
    728 	angle += (rnd2-rnd1)<<20;
    729 
    730 	damage = ((P_Random() & 7) * 3) + 3;
    731 	P_LineAttack (actor, angle, 0, MISSILERANGE, MAXINT, damage);
    732 }
    733 
    734 /*
    735 ==============
    736 =
    737 = A_SPosAttack
    738 =
    739 ==============
    740 */
    741 
    742 void A_SPosAttack (mobj_t *actor) // 800119FC
    743 {
    744 	int		i;
    745 	int		angle, bangle, damage;
    746 
    747 	if (!actor->target)
    748 		return;
    749 
    750 	S_StartSound (actor, sfx_shotgun);
    751 	A_FaceTarget (actor);
    752 	bangle = actor->angle;
    753 
    754 	for (i=0 ; i<3 ; i++)
    755 	{
    756 		angle = bangle + ((P_Random()-P_Random())<<20);
    757 		damage = ((P_Random() % 5) * 3) + 3;
    758 		P_LineAttack (actor, angle, 0, MISSILERANGE, MAXINT, damage);
    759 	}
    760 }
    761 
    762 /*
    763 ==============
    764 =
    765 = A_PlayAttack(A_CPosAttack)
    766 =
    767 ==============
    768 */
    769 
    770 void A_PlayAttack(mobj_t* actor) // 80011b1C
    771 {
    772 	int		angle;
    773 	int		bangle;
    774 	int		damage;
    775 	int		slope;
    776 
    777 	if (!actor->target)
    778 		return;
    779 
    780 	S_StartSound(actor, sfx_pistol);
    781 	A_FaceTarget(actor);
    782 	bangle = actor->angle;
    783 
    784 	slope = P_AimLineAttack(actor, bangle, 0, MISSILERANGE);
    785 
    786 	angle = bangle + ((P_Random() - P_Random()) << 20);
    787 	damage = ((P_Random() % 5) * 3) + 3;
    788 	P_LineAttack(actor, angle, 0, MISSILERANGE, slope, damage);
    789 }
    790 
    791 /*
    792 ==============
    793 =
    794 = A_CPosRefire
    795 =
    796 ==============
    797 */
    798 
    799 void A_CPosRefire(mobj_t* actor) // 80011BD4
    800 {
    801 	A_FaceTarget(actor);
    802 
    803 	if (P_Random() < 40)
    804 		return;
    805 
    806 	if (!actor->target || actor->target->health <= 0
    807 		|| !P_CheckSight(actor, actor->target))
    808 	{
    809 		P_SetMobjState(actor, actor->info->seestate);
    810 	}
    811 }
    812 
    813 /*
    814 ==============
    815 =
    816 = A_BspiFaceTarget
    817 =
    818 ==============
    819 */
    820 
    821 void A_BspiFaceTarget(mobj_t *actor) // 80011C50
    822 {
    823 	A_FaceTarget(actor);
    824     actor->extradata = (int *)5;
    825 }
    826 
    827 /*
    828 ==============
    829 =
    830 = A_BspiAttack
    831 =
    832 ==============
    833 */
    834 
    835 void A_BspiAttack(mobj_t *actor) // 80011C74
    836 {
    837 	if (!actor->target)
    838 		return;
    839 
    840 	A_FaceTarget(actor);
    841 
    842 /* */
    843 /* launch a missile */
    844 /* */
    845 	P_MissileAttack(actor, DP_LEFT);
    846     P_MissileAttack(actor, DP_RIGHT);
    847 }
    848 
    849 /*
    850 ==============
    851 =
    852 = A_SpidRefire
    853 =
    854 ==============
    855 */
    856 
    857 void A_SpidRefire (mobj_t *actor) // 80011CBC
    858 {
    859 	A_FaceTarget (actor);
    860 
    861 	if (P_Random () < 10)
    862 		return;
    863 
    864 	if (!actor->target || actor->target->health <= 0 || !(actor->flags&MF_SEETARGET) )
    865     {
    866 		P_SetMobjState (actor, actor->info->seestate);
    867 		actor->extradata = (int *)5;
    868 		return;
    869     }
    870 
    871     if(--actor->extradata <= 0)
    872     {
    873         P_SetMobjState(actor, actor->info->missilestate);
    874         actor->extradata = (int *)5;
    875     }
    876 }
    877 
    878 /*
    879 ==============
    880 =
    881 = A_TroopMelee
    882 =
    883 ==============
    884 */
    885 
    886 void A_TroopMelee(mobj_t* actor) // 80011D78
    887 {
    888     int    damage;
    889 
    890     if(!actor->target)
    891         return;
    892 
    893     A_FaceTarget (actor);
    894     if(P_CheckMeleeRange(actor))
    895     {
    896         S_StartSound(actor, sfx_scratch);
    897         damage = ((P_Random() & 7) * 3) + 3;
    898         P_DamageMobj(actor->target, actor, actor, damage);
    899     }
    900 }
    901 
    902 /*
    903 ==============
    904 =
    905 = A_TroopAttack
    906 =
    907 ==============
    908 */
    909 
    910 void A_TroopAttack (mobj_t *actor) // 80011DEC
    911 {
    912 	int		damage;
    913 
    914 	if (!actor->target)
    915 		return;
    916 
    917     A_FaceTarget (actor);
    918 
    919 /* */
    920 /* launch a missile */
    921 /* */
    922 	P_MissileAttack(actor, DP_STRAIGHT);
    923 }
    924 
    925 /*
    926 ==============
    927 =
    928 = A_SargAttack
    929 =
    930 ==============
    931 */
    932 
    933 void A_SargAttack (mobj_t *actor) // 80011E28
    934 {
    935 	int		damage;
    936 
    937 	if (!actor->target)
    938 		return;
    939 
    940 	A_FaceTarget (actor);
    941 	if(P_CheckMeleeRange(actor))
    942     {
    943         damage = ((P_Random() & 7) * 4) + 4;
    944         P_DamageMobj(actor->target, actor, actor, damage);
    945     }
    946 }
    947 
    948 /*
    949 ==============
    950 =
    951 = A_HeadAttack
    952 =
    953 ==============
    954 */
    955 
    956 void A_HeadAttack (mobj_t *actor) // 80011E90
    957 {
    958 	int		damage;
    959 
    960 	if (!actor->target)
    961 		return;
    962 
    963 	A_FaceTarget (actor);
    964 	if (P_CheckMeleeRange (actor))
    965 	{
    966 		damage = ((P_Random() & 7) * 8) + 8;
    967 		P_DamageMobj (actor->target, actor, actor, damage);
    968 		return;
    969 	}
    970 /* */
    971 /* launch a missile */
    972 /* */
    973 	P_MissileAttack(actor, DP_STRAIGHT);
    974 }
    975 
    976 /*
    977 ==============
    978 =
    979 = A_CyberAttack
    980 =
    981 ==============
    982 */
    983 
    984 void A_CyberAttack (mobj_t *actor) // 80011F08
    985 {
    986 	if (!actor->target)
    987 		return;
    988 
    989 	A_FaceTarget (actor);
    990 	P_MissileAttack(actor, DP_LEFT);
    991 }
    992 
    993 /*
    994 ==============
    995 =
    996 = A_CyberDeathEvent
    997 =
    998 ==============
    999 */
   1000 
   1001 void A_CyberDeathEvent(mobj_t* actor) // 80011F44
   1002 {
   1003     mobjexp_t *exp;
   1004 
   1005     //P_BossExplode(actor, 4, 12);
   1006     exp = Z_Malloc (sizeof(*exp), PU_LEVSPEC, 0);
   1007     P_AddThinker (&exp->thinker);
   1008     exp->thinker.function = T_MobjExplode;
   1009     exp->mobj = actor;
   1010     exp->delay = 0;
   1011     exp->delaydefault = 4;
   1012     exp->lifetime = 12;
   1013     S_StartSound(NULL, actor->info->deathsound);
   1014 }
   1015 
   1016 /*
   1017 ==============
   1018 =
   1019 = A_BruisAttack
   1020 =
   1021 ==============
   1022 */
   1023 
   1024 void A_BruisAttack (mobj_t *actor) // 80011FC4
   1025 {
   1026 	int		damage;
   1027 
   1028 	if (!actor->target)
   1029 		return;
   1030 
   1031 	if (P_CheckMeleeRange (actor))
   1032 	{
   1033 		S_StartSound (actor, sfx_scratch);
   1034 		damage = ((P_Random() & 7) * 11) + 11;
   1035 		P_DamageMobj (actor->target, actor, actor, damage);
   1036 		return;
   1037 	}
   1038 /* */
   1039 /* launch a missile */
   1040 /* */
   1041 	P_MissileAttack(actor, DP_STRAIGHT);
   1042 }
   1043 
   1044 /*
   1045 ==============
   1046 =
   1047 = A_SpawnSmoke
   1048 =
   1049 ==============
   1050 */
   1051 
   1052 void A_SpawnSmoke(mobj_t *actor) // 8001204C
   1053 {
   1054     mobj_t *smoke;
   1055 
   1056     smoke = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMOKE_GRAY);
   1057     smoke->momz = FRACUNIT/2;
   1058 }
   1059 
   1060 /*
   1061 ==============
   1062 =
   1063 = A_Tracer
   1064 =
   1065 ==============
   1066 */
   1067 
   1068 #define TRACEANGLE 0x10000000
   1069 
   1070 void A_Tracer(mobj_t *actor) // 80012088
   1071 {
   1072 	angle_t	exact;
   1073 	fixed_t	dist;
   1074 	fixed_t	slope;
   1075 	mobj_t *dest;
   1076 	mobj_t *th;
   1077 
   1078     th = P_SpawnMobj(actor->x - actor->momx, actor->y - actor->momy, actor->z, MT_SMOKE_RED);
   1079 
   1080     th->momz = FRACUNIT;
   1081     th->tics -= P_Random() & 3;
   1082 
   1083     if (th->tics < 1)
   1084         th->tics = 1;
   1085 
   1086     if(actor->threshold-- < -100)
   1087         return;
   1088 
   1089     // adjust direction
   1090     dest = actor->tracer;
   1091 
   1092     if (!dest || dest->health <= 0)
   1093         return;
   1094 
   1095     // change angle
   1096     exact = R_PointToAngle2(actor->x, actor->y, dest->x, dest->y);
   1097 
   1098     if (exact != actor->angle)
   1099     {
   1100         if (exact - actor->angle > 0x80000000)
   1101         {
   1102             actor->angle -= TRACEANGLE;
   1103             if (exact - actor->angle < 0x80000000)
   1104                 actor->angle = exact;
   1105         }
   1106         else
   1107         {
   1108             actor->angle += TRACEANGLE;
   1109             if (exact - actor->angle > 0x80000000)
   1110                 actor->angle = exact;
   1111         }
   1112     }
   1113 
   1114     exact = actor->angle >> ANGLETOFINESHIFT;
   1115     actor->momx = (actor->info->speed * finecosine[exact]);
   1116     actor->momy = (actor->info->speed * finesine[exact]);
   1117 
   1118     // change slope
   1119     dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y);
   1120     dist = dist / (actor->info->speed << FRACBITS);
   1121 
   1122     if (dist < 1)
   1123         dist = 1;
   1124 
   1125     slope = (dest->height * 3);
   1126     if(slope < 0) {
   1127         slope = slope + 3;
   1128     }
   1129 
   1130     slope = (dest->z + (slope >> 2) - actor->z) / dist;
   1131 
   1132     if (slope < actor->momz)
   1133         actor->momz -= FRACUNIT / 8;
   1134     else
   1135         actor->momz += FRACUNIT / 4;
   1136 }
   1137 
   1138 /*
   1139 ==============
   1140 =
   1141 = A_FatRaise
   1142 =
   1143 ==============
   1144 */
   1145 
   1146 #define	FATSPREAD	(ANG90/4)
   1147 
   1148 void A_FatRaise(mobj_t *actor) // 800122F4
   1149 {
   1150 	A_FaceTarget(actor);
   1151 	S_StartSound(actor, sfx_fattatk);
   1152 }
   1153 
   1154 /*
   1155 ==============
   1156 =
   1157 = A_FatAttack1
   1158 =
   1159 ==============
   1160 */
   1161 
   1162 void A_FatAttack1(mobj_t *actor) // 80012320
   1163 {
   1164 	mobj_t  *mo;
   1165 	int	    an;
   1166 
   1167 	A_FaceTarget(actor);
   1168 
   1169 	// Change direction  to ...
   1170 	P_MissileAttack(actor, DP_RIGHT);
   1171 	mo = P_MissileAttack(actor, DP_LEFT);
   1172 
   1173 	mo->angle += FATSPREAD;
   1174 	an = mo->angle >> ANGLETOFINESHIFT;
   1175 	mo->momx = (mo->info->speed * finecosine[an]);
   1176 	mo->momy = (mo->info->speed * finesine[an]);
   1177 }
   1178 
   1179 /*
   1180 ==============
   1181 =
   1182 = A_FatAttack2
   1183 =
   1184 ==============
   1185 */
   1186 
   1187 void A_FatAttack2(mobj_t *actor) // 800123B0
   1188 {
   1189     mobj_t  *mo;
   1190 	mobj_t  *target;
   1191 	int	    an;
   1192 
   1193 	A_FaceTarget(actor);
   1194 
   1195 	// Now here choose opposite deviation.
   1196 	P_MissileAttack(actor, DP_LEFT);
   1197 	mo = P_MissileAttack(actor, DP_RIGHT);
   1198 
   1199 	mo->angle -= FATSPREAD;
   1200 	an = mo->angle >> ANGLETOFINESHIFT;
   1201 	mo->momx = (mo->info->speed * finecosine[an]);
   1202 	mo->momy = (mo->info->speed * finesine[an]);
   1203 }
   1204 
   1205 /*
   1206 ==============
   1207 =
   1208 = A_FatAttack3
   1209 =
   1210 ==============
   1211 */
   1212 
   1213 void A_FatAttack3(mobj_t *actor) // 80012440
   1214 {
   1215     mobj_t  *mo;
   1216 	mobj_t  *target;
   1217 	int	    an;
   1218 
   1219 	A_FaceTarget(actor);
   1220 
   1221 	mo = P_MissileAttack(actor, DP_RIGHT);
   1222 	mo->angle -= FATSPREAD / 4;
   1223 	an = mo->angle >> ANGLETOFINESHIFT;
   1224 	mo->momx = (mo->info->speed * finecosine[an]);
   1225 	mo->momy = (mo->info->speed * finesine[an]);
   1226 
   1227 	mo = P_MissileAttack(actor, DP_LEFT);
   1228 	mo->angle += FATSPREAD / 4;
   1229 	an = mo->angle >> ANGLETOFINESHIFT;
   1230 	mo->momx = (mo->info->speed * finecosine[an]);
   1231 	mo->momy = (mo->info->speed * finesine[an]);
   1232 }
   1233 
   1234 
   1235 /*
   1236 ==================
   1237 =
   1238 = SkullAttack
   1239 =
   1240 = Fly at the player like a missile
   1241 =
   1242 ==================
   1243 */
   1244 
   1245 #define	SKULLSPEED		(40*FRACUNIT)
   1246 
   1247 void A_SkullAttack (mobj_t *actor) // 80012528
   1248 {
   1249 	mobj_t			*dest;
   1250 	angle_t			an;
   1251 	int				dist;
   1252 
   1253 	if (!actor->target)
   1254 		return;
   1255 
   1256 	dest = actor->target;
   1257 	actor->flags |= MF_SKULLFLY;
   1258 
   1259 	S_StartSound (actor, actor->info->attacksound);
   1260 	A_FaceTarget (actor);
   1261 	an = actor->angle >> ANGLETOFINESHIFT;
   1262 	actor->momx = (finecosine[an] * (SKULLSPEED/FRACUNIT));
   1263 	actor->momy = (finesine[an] * (SKULLSPEED/FRACUNIT));
   1264 	dist = P_AproxDistance (dest->x - actor->x, dest->y - actor->y);
   1265 	dist = dist / SKULLSPEED;
   1266 	if (dist < 1)
   1267 		dist = 1;
   1268 	actor->momz = (dest->z+(dest->height>>1) - actor->z) / dist;
   1269 }
   1270 
   1271 
   1272 /*
   1273 ==============
   1274 =
   1275 = PIT_PainCheckLine
   1276 =
   1277 ==============
   1278 */
   1279 boolean PIT_PainCheckLine(intercept_t *in) // 80012654
   1280 {
   1281   if (!(in->d.line->backsector))
   1282     return false;
   1283 
   1284   return true;
   1285 }
   1286 
   1287 /*
   1288 ==============
   1289 =
   1290 = A_PainShootSkull
   1291 =
   1292 ==============
   1293 */
   1294 
   1295 void A_PainShootSkull(mobj_t *actor, angle_t angle) // 8001267C
   1296 {
   1297 	fixed_t	x;
   1298 	fixed_t	y;
   1299 	fixed_t	z;
   1300 
   1301 	mobj_t*	newmobj;
   1302 	angle_t	an;
   1303 	int		prestep;
   1304 	int		count;
   1305 
   1306 	mobj_t	*mo;
   1307 
   1308 	// count total number of skull currently on the level
   1309 	count = 0;
   1310 	for (mo=mobjhead.next ; mo != &mobjhead ; mo=mo->next)
   1311 	{
   1312 		if ((mo->type == MT_SKULL))
   1313         {
   1314             count++;
   1315 
   1316             // if there are allready 17 skulls on the level,
   1317             // don't spit another one
   1318             if (count >= 17)
   1319                 return;
   1320         }
   1321 	}
   1322 
   1323 	// okay, there's playe for another one
   1324 	an = angle >> ANGLETOFINESHIFT;
   1325 
   1326 	prestep = (mobjinfo[MT_SKULL].radius + (4 * FRACUNIT) + actor->info->radius) >> FRACBITS;
   1327 
   1328 	x = actor->x + (finecosine[an] * prestep);
   1329 	y = actor->y + (finesine[an] * prestep);
   1330 	z = actor->z + 16 * FRACUNIT;
   1331 
   1332 	newmobj = P_SpawnMobj(x, y, z, MT_SKULL);
   1333 
   1334 	// Check for movements.
   1335 	if (!P_PathTraverse(actor->x, actor->y, newmobj->x, newmobj->y, PT_ADDLINES, PIT_PainCheckLine) ||
   1336         !P_TryMove(newmobj, newmobj->x, newmobj->y))
   1337 	{
   1338 		// kill it immediately
   1339 		P_DamageMobj(newmobj, actor, actor, 10000);
   1340         P_RadiusAttack(newmobj, newmobj, 128);
   1341 		return;
   1342 	}
   1343 
   1344 	newmobj->target = actor->target;
   1345 	P_SetMobjState(newmobj,newmobj->info->missilestate);
   1346 	A_SkullAttack(newmobj);
   1347 }
   1348 
   1349 /*
   1350 ==============
   1351 =
   1352 = A_PainAttack
   1353 =
   1354 ==============
   1355 */
   1356 
   1357 void A_PainAttack(mobj_t *actor) // 80012804
   1358 {
   1359 	if (!actor->target)
   1360 		return;
   1361 
   1362 	A_FaceTarget(actor);
   1363 	A_PainShootSkull(actor, actor->angle-0x15550000);
   1364 	A_PainShootSkull(actor, actor->angle+0x15550000);
   1365 }
   1366 
   1367 /*
   1368 ==============
   1369 =
   1370 = A_PainDie
   1371 =
   1372 ==============
   1373 */
   1374 
   1375 void A_PainDie(mobj_t *actor) // 8001285C
   1376 {
   1377 	A_Fall(actor);
   1378 	A_PainShootSkull(actor, actor->angle + ANG90);
   1379 	A_PainShootSkull(actor, actor->angle + ANG180);
   1380 	A_PainShootSkull(actor, actor->angle + ANG270);
   1381 
   1382 	A_OnDeathTrigger(actor);
   1383 }
   1384 
   1385 
   1386 /*
   1387 ==============
   1388 =
   1389 = A_RectChase
   1390 =
   1391 ==============
   1392 */
   1393 
   1394 void A_RectChase(mobj_t* actor) // 800128C4
   1395 {
   1396     if(!(actor->target) || (actor->target->health <= 0) ||
   1397        !(P_AproxDistance(actor->target->x-actor->x, actor->target->y-actor->y) < (600*FRACUNIT)))
   1398     {
   1399         A_Chase(actor);
   1400         return;
   1401     }
   1402 
   1403     A_FaceTarget(actor);
   1404     S_StartSound(NULL, actor->info->attacksound);
   1405     P_SetMobjState(actor, actor->info->meleestate);
   1406 
   1407 }
   1408 
   1409 /*
   1410 ==============
   1411 =
   1412 = A_RectGroundFire
   1413 =
   1414 ==============
   1415 */
   1416 
   1417 void A_RectGroundFire(mobj_t* actor) // 8001296C
   1418 {
   1419     mobj_t* mo;
   1420     angle_t an;
   1421 
   1422     A_FaceTarget(actor);
   1423 
   1424     mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PROJ_RECTFIRE);
   1425     mo->target = actor;
   1426     an = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
   1427 
   1428     mo->angle = an;
   1429     mo->momx = finecosine[mo->angle >> ANGLETOFINESHIFT] * mo->info->speed;
   1430     mo->momy = finesine[mo->angle >> ANGLETOFINESHIFT] * mo->info->speed;
   1431 
   1432     mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PROJ_RECTFIRE);
   1433     mo->target = actor;
   1434     mo->angle = an - ANG45;
   1435     mo->momx = finecosine[mo->angle >> ANGLETOFINESHIFT] * mo->info->speed;
   1436     mo->momy = finesine[mo->angle >> ANGLETOFINESHIFT] * mo->info->speed;
   1437 
   1438     mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PROJ_RECTFIRE);
   1439     mo->target = actor;
   1440     mo->angle = an + ANG45;
   1441     mo->momx = finecosine[mo->angle >> ANGLETOFINESHIFT] * mo->info->speed;
   1442     mo->momy = finesine[mo->angle >> ANGLETOFINESHIFT] * mo->info->speed;
   1443 
   1444     S_StartSound(mo, mo->info->seesound);
   1445 }
   1446 
   1447 /*
   1448 ==============
   1449 =
   1450 = A_RectMissile
   1451 =
   1452 ==============
   1453 */
   1454 
   1455 void A_RectMissile(mobj_t* actor) // 80012B1C
   1456 {
   1457     mobj_t* mo;
   1458     int count;
   1459     angle_t an;
   1460     fixed_t x;
   1461     fixed_t y;
   1462     fixed_t speed;
   1463 
   1464     if(!actor->target)
   1465         return;
   1466 
   1467     A_FaceTarget(actor);
   1468     for(mo = mobjhead.next; mo != &mobjhead; mo = mo->next)
   1469     {
   1470         // not a rect projectile
   1471         if(mo->type == MT_PROJ_RECT)
   1472         {
   1473             if((++count >= 9))
   1474                 return;
   1475         }
   1476     }
   1477 
   1478     // Arm 1
   1479 
   1480     an = (actor->angle/*-ANG90*/) >> ANGLETOFINESHIFT;
   1481     x = (finesine[an] * 68);
   1482     y = (finecosine[an] * 68);
   1483     mo = P_SpawnMobj(actor->x + x, actor->y - y, actor->z + (68*FRACUNIT), MT_PROJ_RECT);
   1484     mo->target = actor;
   1485     mo->tracer = actor->target;
   1486     mo->threshold = 5;
   1487     an = (actor->angle + ANG270);
   1488     mo->angle = an;
   1489     an >>= ANGLETOFINESHIFT;
   1490     speed = mo->info->speed >> 1;
   1491     if(!(speed >= 0))
   1492     {
   1493         speed = (mo->info->speed + 1) >> 1;
   1494     }
   1495     mo->momx = (finecosine[an] * speed);
   1496     mo->momy = (finesine[an] * speed);
   1497 
   1498     // Arm2
   1499 
   1500     an = (actor->angle/*-ANG90*/) >> ANGLETOFINESHIFT;
   1501     x = (finesine[an] * 50);
   1502     y = (finecosine[an] * 50);
   1503     mo = P_SpawnMobj(actor->x + x, actor->y - y, actor->z + (139*FRACUNIT), MT_PROJ_RECT);
   1504     mo->target = actor;
   1505     mo->tracer = actor->target;
   1506     mo->threshold = 1;
   1507     an = (actor->angle + ANG270);
   1508     mo->angle = an;
   1509     an >>= ANGLETOFINESHIFT;
   1510     speed = mo->info->speed >> 1;
   1511     if(!(speed >= 0))
   1512     {
   1513         speed = (mo->info->speed + 1) >> 1;
   1514     }
   1515     mo->momx = (finecosine[an] * speed);
   1516     mo->momy = (finesine[an] * speed);
   1517 
   1518     // Arm3
   1519 
   1520     an = (actor->angle/*+ANG90*/) >> ANGLETOFINESHIFT;
   1521     x = (finesine[an] * 68);
   1522     y = (finecosine[an] * 68);
   1523     mo = P_SpawnMobj(actor->x - x, actor->y + y, actor->z + (68*FRACUNIT), MT_PROJ_RECT);
   1524     mo->target = actor;
   1525     mo->tracer = actor->target;
   1526     mo->threshold = 5;
   1527     an = (actor->angle - ANG270);
   1528     mo->angle = an;
   1529     an >>= ANGLETOFINESHIFT;
   1530     speed = mo->info->speed >> 1;
   1531     if(!(speed >= 0))
   1532     {
   1533         speed = (mo->info->speed + 1) >> 1;
   1534     }
   1535     mo->momx = (finecosine[an] * speed);
   1536     mo->momy = (finesine[an] * speed);
   1537 
   1538     // Arm4
   1539 
   1540     an = (actor->angle/*+ANG90*/) >> ANGLETOFINESHIFT;
   1541     x = (finesine[an] * 50);
   1542     y = (finecosine[an] * 50);
   1543     mo = P_SpawnMobj(actor->x - x, actor->y + y, actor->z + (139*FRACUNIT), MT_PROJ_RECT);
   1544     mo->target = actor;
   1545     mo->tracer = actor->target;
   1546     mo->threshold = 1;
   1547     an = (actor->angle - ANG270);
   1548     mo->angle = an;
   1549     an >>= ANGLETOFINESHIFT;
   1550     speed = mo->info->speed >> 1;
   1551     if(!(speed >= 0))
   1552     {
   1553         speed = (mo->info->speed + 1) >> 1;
   1554     }
   1555     mo->momx = (finecosine[an] * speed);
   1556     mo->momy = (finesine[an] * speed);
   1557 }
   1558 
   1559 /*
   1560 ==============
   1561 =
   1562 = A_MoveGroundFire
   1563 =
   1564 ==============
   1565 */
   1566 
   1567 void A_MoveGroundFire(mobj_t* fire) // 80012EA4
   1568 {
   1569     mobj_t* mo;
   1570     fade_t *fade;
   1571 
   1572     mo = P_SpawnMobj(fire->x, fire->y, fire->floorz, MT_PROP_FIRE);
   1573 
   1574     //P_FadeMobj(mo, -8, 0, mobjflag_t::MF_NONE);
   1575     fade = Z_Malloc (sizeof(*fade), PU_LEVSPEC, 0);
   1576     P_AddThinker (&fade->thinker);
   1577     fade->thinker.function = T_FadeThinker;
   1578     fade->amount = -8;
   1579     fade->destAlpha = 0;
   1580     fade->flagReserve = 0;
   1581     fade->mobj = mo;
   1582 }
   1583 
   1584 /*
   1585 ==============
   1586 =
   1587 = A_RectTracer
   1588 =
   1589 ==============
   1590 */
   1591 
   1592 void A_RectTracer(mobj_t* actor) // 80012F34
   1593 {
   1594     if(actor->threshold < 0)
   1595         A_Tracer(actor);
   1596     else
   1597         actor->threshold--;
   1598 }
   1599 
   1600 
   1601 /*
   1602 ==============
   1603 =
   1604 = A_RectDeathEvent
   1605 =
   1606 ==============
   1607 */
   1608 
   1609 void A_RectDeathEvent(mobj_t* actor) // 80012F6C
   1610 {
   1611     mobjexp_t *exp;
   1612 
   1613     //P_BossExplode(actor, 3, 32);
   1614     exp = Z_Malloc (sizeof(*exp), PU_LEVSPEC, 0);
   1615     P_AddThinker (&exp->thinker);
   1616     exp->thinker.function = T_MobjExplode;
   1617     exp->mobj = actor;
   1618     exp->delay = 0;
   1619     exp->delaydefault = 3;
   1620     exp->lifetime = 32;
   1621     S_StartSound(NULL, actor->info->deathsound);
   1622 }
   1623 
   1624 
   1625 /*
   1626 ==================
   1627 =
   1628 = A_TargetCamera
   1629 =
   1630 ==================
   1631 */
   1632 
   1633 void A_TargetCamera(mobj_t* actor) // 80012FEC
   1634 {
   1635     mobj_t* mo;
   1636 
   1637     actor->threshold = MAXINT;
   1638 
   1639     for(mo = mobjhead.next; mo != &mobjhead; mo = mo->next)
   1640     {
   1641         if(actor->tid+1 == mo->tid)
   1642         {
   1643             actor->target = mo;
   1644             P_SetMobjState(actor, actor->info->missilestate);
   1645             return;
   1646         }
   1647     }
   1648 }
   1649 
   1650 /*
   1651 ==================
   1652 =
   1653 = A_BarrelExplode
   1654 =
   1655 ==================
   1656 */
   1657 
   1658 void A_BarrelExplode(mobj_t* actor) // 80013070
   1659 {
   1660 
   1661     S_StartSound(actor, actor->info->deathsound);
   1662     P_SpawnMobj(actor->x, actor->y, actor->z + (actor->info->height >> 1), MT_EXPLOSION1);
   1663     P_RadiusAttack(actor, actor->target, 128);//A_Explode(actor);
   1664 
   1665     A_OnDeathTrigger(actor);
   1666 }
   1667 
   1668 
   1669 /*
   1670 ================
   1671 =
   1672 = A_Hoof
   1673 =
   1674 ================
   1675 */
   1676 
   1677 void A_Hoof (mobj_t *mo) // 800130E0
   1678 {
   1679 	S_StartSound(mo, sfx_cybhoof);
   1680 	A_Chase(mo);
   1681 }
   1682 
   1683 /*
   1684 ================
   1685 =
   1686 = A_Metal
   1687 =
   1688 ================
   1689 */
   1690 
   1691 void A_Metal (mobj_t *mo) // 80013110
   1692 {
   1693 	S_StartSound(mo, sfx_metal);
   1694 	A_Chase(mo);
   1695 }
   1696 
   1697 /*
   1698 ================
   1699 =
   1700 = A_BabyMetal
   1701 =
   1702 ================
   1703 */
   1704 
   1705 void A_BabyMetal(mobj_t* mo) // 80013140
   1706 {
   1707 	S_StartSound(mo, sfx_bspistomp);
   1708 	A_Chase(mo);
   1709 }
   1710 
   1711 /*============================================================================= */
   1712 
   1713 /* a move in p_base.c crossed a special line */
   1714 #if 0
   1715 void L_CrossSpecial (mobj_t *mo)
   1716 {
   1717 	line_t	*line;
   1718 
   1719 	line = (line_t *)(mo->extradata & ~1);
   1720 
   1721 	P_CrossSpecialLine (line, mo);
   1722 }
   1723 #endif
   1724 
   1725 /*
   1726 ================
   1727 =
   1728 = L_MissileHit
   1729 =
   1730 ================
   1731 */
   1732 
   1733 /* a move in p_base.c caused a missile to hit another thing or wall */
   1734 void L_MissileHit (mobj_t *mo) // 80013170
   1735 {
   1736 	int	damage;
   1737 	mobj_t	*missilething;
   1738 
   1739 	missilething = (mobj_t *)mo->extradata;
   1740 	damage = 0;
   1741 
   1742 	if (missilething)
   1743 	{
   1744 		damage = ((P_Random()&7)+1)*mo->info->damage;
   1745 		P_DamageMobj (missilething, mo, mo->target, damage);
   1746 
   1747         if ((mo->type == MT_PROJ_RECTFIRE) && (missilething->player))
   1748         {
   1749             missilething->momz = (1500*FRACUNIT) / missilething->info->mass;
   1750         }
   1751 	}
   1752 
   1753     if (mo->type == MT_PROJ_DART)
   1754     {
   1755         if (missilething && !(missilething->flags & MF_NOBLOOD))
   1756         {
   1757             P_SpawnBlood(mo->x, mo->y, mo->z, damage);
   1758         }
   1759         else
   1760         {
   1761             S_StartSound(mo, sfx_darthit);
   1762             P_SpawnPuff(mo->x, mo->y, mo->z);
   1763         }
   1764     }
   1765 	P_ExplodeMissile (mo);
   1766 }
   1767 
   1768 /*
   1769 ================
   1770 =
   1771 = L_SkullBash
   1772 =
   1773 ================
   1774 */
   1775 
   1776 /* a move in p_base.c caused a flying skull to hit another thing or a wall */
   1777 void L_SkullBash (mobj_t *mo) // 800132AC
   1778 {
   1779 	int	damage;
   1780 	mobj_t	*skullthing;
   1781 
   1782 	skullthing = (mobj_t *)mo->extradata;
   1783 
   1784 	if (skullthing)
   1785 	{
   1786 		damage = ((P_Random()&7)+1)*mo->info->damage;
   1787 		P_DamageMobj (skullthing, mo, mo, damage);
   1788 	}
   1789 
   1790 	mo->flags &= ~MF_SKULLFLY;
   1791 	mo->momx = mo->momy = mo->momz = 0;
   1792 	P_SetMobjState (mo, mo->info->spawnstate);
   1793 }
   1794 
   1795 /*
   1796 ==================
   1797 =
   1798 = A_FadeAlpha
   1799 =
   1800 ==================
   1801 */
   1802 
   1803 void A_FadeAlpha(mobj_t *mobj) // 8001333C
   1804 {
   1805     int fade;
   1806 
   1807     fade = mobj->alpha * 3;
   1808     if(!(fade >= 0))
   1809     {
   1810         fade = fade + 3;
   1811     }
   1812 
   1813     mobj->alpha = (fade >> 2);
   1814 }
   1815 
   1816 /*
   1817 ==================
   1818 =
   1819 = A_PainDeathEvent
   1820 =
   1821 ==================
   1822 */
   1823 
   1824 void A_PainDeathEvent(mobj_t* actor) // 80013364
   1825 {
   1826     actor->alpha -= 0x40;
   1827 }
   1828 
   1829 /*
   1830 ==================
   1831 =
   1832 = A_SkullSetAlpha
   1833 =
   1834 ==================
   1835 */
   1836 
   1837 void A_SkullSetAlpha(mobj_t* actor) // 80013378
   1838 {
   1839     actor->alpha >>= 2;
   1840 }
   1841 
   1842 /*
   1843 ==================
   1844 =
   1845 = A_MissileSetAlpha
   1846 =
   1847 ==================
   1848 */
   1849 
   1850 void A_MissileSetAlpha(mobj_t* actor) // 8001338C
   1851 {
   1852     actor->alpha >>= 1;
   1853 }
   1854 
   1855 
   1856 /*
   1857 ==================
   1858 =
   1859 = A_FadeOut
   1860 =
   1861 ==================
   1862 */
   1863 
   1864 void A_FadeOut(mobj_t* actor) // 800133A0
   1865 {
   1866     fade_t *fade;
   1867 
   1868     if (actor->alpha >= 0xff)
   1869     {
   1870         actor->flags |= MF_SHADOW;
   1871         //P_FadeMobj(actor, -8, 0x30, mobjflag_t::MF_NONE);
   1872         fade = Z_Malloc (sizeof(*fade), PU_LEVSPEC, 0);
   1873         P_AddThinker (&fade->thinker);
   1874         fade->thinker.function = T_FadeThinker;
   1875         fade->amount = -8;
   1876         fade->destAlpha = 0x30;
   1877         fade->flagReserve = 0;
   1878         fade->mobj = actor;
   1879     }
   1880 }
   1881 
   1882 
   1883 /*
   1884 ==================
   1885 =
   1886 = A_FadeIn
   1887 =
   1888 ==================
   1889 */
   1890 
   1891 void A_FadeIn(mobj_t* actor) // 80013428
   1892 {
   1893     fade_t *fade;
   1894 
   1895     if (actor->alpha < 0xff)
   1896     {
   1897         actor->alpha = 0x30;
   1898         actor->flags &= ~MF_SHADOW;
   1899 
   1900         //P_FadeMobj(actor, 8, 0xff, mobjflag_t::MF_NONE);
   1901         fade = Z_Malloc (sizeof(*fade), PU_LEVSPEC, 0);
   1902         P_AddThinker (&fade->thinker);
   1903         fade->thinker.function = T_FadeThinker;
   1904         fade->mobj = actor;
   1905         fade->amount = 8;
   1906         fade->destAlpha = 0xff;
   1907         fade->flagReserve = 0;
   1908     }
   1909 }
   1910 
   1911 
   1912 /*
   1913 ================
   1914 =
   1915 P_MissileAttack
   1916 =
   1917 ================
   1918 */
   1919 
   1920 mobj_t* P_MissileAttack(mobj_t *actor, dirproj_e direction) // 800134BC
   1921 {
   1922     angle_t angle;
   1923     fixed_t deltax, deltay, deltaz;
   1924     fixed_t x, y;
   1925     mobjtype_t type;
   1926     mobj_t *mo;
   1927 
   1928     if(direction == DP_LEFT)
   1929     {
   1930         angle = actor->angle + ANG45;
   1931     }
   1932     else if(direction == DP_RIGHT)
   1933     {
   1934         angle = actor->angle - ANG45;
   1935     }
   1936     else
   1937     {
   1938         angle = actor->angle;
   1939     }
   1940 
   1941     angle >>= ANGLETOFINESHIFT;
   1942     x = finecosine[angle];
   1943     y = finesine[angle];
   1944 
   1945     switch(actor->type)
   1946     {
   1947     case MT_MANCUBUS:
   1948         deltay = (y * 50);
   1949         deltax = (x * 50);
   1950         deltaz = (69*FRACUNIT);
   1951         type = MT_PROJ_FATSO;
   1952         break;
   1953     case MT_IMP1:
   1954         deltay = 0;
   1955         deltax = 0;
   1956         deltaz = (64*FRACUNIT);
   1957         type = MT_PROJ_IMP1;
   1958         break;
   1959     case MT_IMP2:
   1960         deltay = 0;
   1961         deltax = 0;
   1962         deltaz = (64*FRACUNIT);
   1963         type = MT_PROJ_IMP2;
   1964         break;
   1965     case MT_CACODEMON:
   1966         deltay = 0;
   1967         deltax = 0;
   1968         deltaz = (46*FRACUNIT);
   1969         type = MT_PROJ_HEAD;
   1970         break;
   1971     case MT_BRUISER1:
   1972         deltay = 0;
   1973         deltax = 0;
   1974         deltaz = (48*FRACUNIT);
   1975         type = MT_PROJ_BRUISER2;
   1976         break;
   1977     case MT_BRUISER2:
   1978         deltay = 0;
   1979         deltax = 0;
   1980         deltaz = (48*FRACUNIT);
   1981         type = MT_PROJ_BRUISER1;
   1982         break;
   1983     case MT_BABY:
   1984         deltay = (y * 20);
   1985         deltax = (x * 20);
   1986         deltaz = (28*FRACUNIT);
   1987         type = MT_PROJ_BABY;
   1988         break;
   1989     case MT_CYBORG:
   1990     case MT_CYBORG_TITLE:
   1991         deltay = (y * 45);
   1992         deltax = (x * 45);
   1993         deltaz = (88*FRACUNIT);
   1994         type = MT_PROJ_ROCKET;
   1995         break;
   1996 
   1997     default:
   1998         break;
   1999     }
   2000 
   2001     mo = P_SpawnMissile(actor, actor->target, deltax, deltay, deltaz, type);
   2002     return mo;
   2003 }