1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 2005-2014 Simon Howard
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // DESCRIPTION:
16 //	Enemy thinking, AI.
17 //	Action Pointer Functions
18 //	that are associated with states/frames.
19 //
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 
24 #include "m_random.h"
25 #include "i_system.h"
26 
27 #include "doomdef.h"
28 #include "p_local.h"
29 
30 #include "s_sound.h"
31 
32 #include "g_game.h"
33 
34 // State.
35 #include "doomstat.h"
36 #include "r_state.h"
37 
38 // Data.
39 #include "sounds.h"
40 
41 
42 
43 
44 typedef enum
45 {
46     DI_EAST,
47     DI_NORTHEAST,
48     DI_NORTH,
49     DI_NORTHWEST,
50     DI_WEST,
51     DI_SOUTHWEST,
52     DI_SOUTH,
53     DI_SOUTHEAST,
54     DI_NODIR,
55     NUMDIRS
56 
57 } dirtype_t;
58 
59 
60 //
61 // P_NewChaseDir related LUT.
62 //
63 dirtype_t opposite[] =
64 {
65   DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST,
66   DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR
67 };
68 
69 dirtype_t diags[] =
70 {
71     DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST
72 };
73 
74 
75 
76 
77 
78 void A_Fall (mobj_t *actor);
79 
80 
81 //
82 // ENEMY THINKING
83 // Enemies are allways spawned
84 // with targetplayer = -1, threshold = 0
85 // Most monsters are spawned unaware of all players,
86 // but some can be made preaware
87 //
88 
89 
90 //
91 // Called by P_NoiseAlert.
92 // Recursively traverse adjacent sectors,
93 // sound blocking lines cut off traversal.
94 //
95 
96 mobj_t*		soundtarget;
97 
98 void
P_RecursiveSound(sector_t * sec,int soundblocks)99 P_RecursiveSound
100 ( sector_t*	sec,
101   int		soundblocks )
102 {
103     int		i;
104     line_t*	check;
105     sector_t*	other;
106 
107     // wake up all monsters in this sector
108     if (sec->validcount == validcount
109 	&& sec->soundtraversed <= soundblocks+1)
110     {
111 	return;		// already flooded
112     }
113 
114     sec->validcount = validcount;
115     sec->soundtraversed = soundblocks+1;
116     sec->soundtarget = soundtarget;
117 
118     for (i=0 ;i<sec->linecount ; i++)
119     {
120 	check = sec->lines[i];
121 	if (! (check->flags & ML_TWOSIDED) )
122 	    continue;
123 
124 	P_LineOpening (check);
125 
126 	if (openrange <= 0)
127 	    continue;	// closed door
128 
129 	if ( sides[ check->sidenum[0] ].sector == sec)
130 	    other = sides[ check->sidenum[1] ] .sector;
131 	else
132 	    other = sides[ check->sidenum[0] ].sector;
133 
134 	if (check->flags & ML_SOUNDBLOCK)
135 	{
136 	    if (!soundblocks)
137 		P_RecursiveSound (other, 1);
138 	}
139 	else
140 	    P_RecursiveSound (other, soundblocks);
141     }
142 }
143 
144 
145 
146 //
147 // P_NoiseAlert
148 // If a monster yells at a player,
149 // it will alert other monsters to the player.
150 //
151 void
P_NoiseAlert(mobj_t * target,mobj_t * emmiter)152 P_NoiseAlert
153 ( mobj_t*	target,
154   mobj_t*	emmiter )
155 {
156     soundtarget = target;
157     validcount++;
158     P_RecursiveSound (emmiter->subsector->sector, 0);
159 }
160 
161 
162 
163 
164 //
165 // P_CheckMeleeRange
166 //
P_CheckMeleeRange(mobj_t * actor)167 boolean P_CheckMeleeRange (mobj_t*	actor)
168 {
169     mobj_t*	pl;
170     fixed_t	dist;
171 
172     if (!actor->target)
173 	return false;
174 
175     pl = actor->target;
176     dist = P_AproxDistance (pl->x-actor->x, pl->y-actor->y);
177 
178     if (dist >= MELEERANGE-20*FRACUNIT+pl->info->radius)
179 	return false;
180 
181     if (! P_CheckSight (actor, actor->target) )
182 	return false;
183 
184     return true;
185 }
186 
187 //
188 // P_CheckMissileRange
189 //
P_CheckMissileRange(mobj_t * actor)190 boolean P_CheckMissileRange (mobj_t* actor)
191 {
192     fixed_t	dist;
193 
194     if (! P_CheckSight (actor, actor->target) )
195 	return false;
196 
197     if ( actor->flags & MF_JUSTHIT )
198     {
199 	// the target just hit the enemy,
200 	// so fight back!
201 	actor->flags &= ~MF_JUSTHIT;
202 	return true;
203     }
204 
205     if (actor->reactiontime)
206 	return false;	// do not attack yet
207 
208     // OPTIMIZE: get this from a global checksight
209     dist = P_AproxDistance ( actor->x-actor->target->x,
210 			     actor->y-actor->target->y) - 64*FRACUNIT;
211 
212     if (!actor->info->meleestate)
213 	dist -= 128*FRACUNIT;	// no melee attack, so fire more
214 
215     dist >>= FRACBITS;
216 
217     if (actor->type == MT_VILE)
218     {
219 	if (dist > 14*64)
220 	    return false;	// too far away
221     }
222 
223 
224     if (actor->type == MT_UNDEAD)
225     {
226 	if (dist < 196)
227 	    return false;	// close for fist attack
228 	dist >>= 1;
229     }
230 
231 
232     if (actor->type == MT_CYBORG
233 	|| actor->type == MT_SPIDER
234 	|| actor->type == MT_SKULL)
235     {
236 	dist >>= 1;
237     }
238 
239     if (dist > 200)
240 	dist = 200;
241 
242     if (actor->type == MT_CYBORG && dist > 160)
243 	dist = 160;
244 
245     if (P_Random () < dist)
246 	return false;
247 
248     return true;
249 }
250 
251 
252 //
253 // P_Move
254 // Move in the current direction,
255 // returns false if the move is blocked.
256 //
257 fixed_t	xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
258 fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
259 
P_Move(mobj_t * actor)260 boolean P_Move (mobj_t*	actor)
261 {
262     fixed_t	tryx;
263     fixed_t	tryy;
264 
265     line_t*	ld;
266 
267     // warning: 'catch', 'throw', and 'try'
268     // are all C++ reserved words
269     boolean	try_ok;
270     boolean	good;
271 
272     if (actor->movedir == DI_NODIR)
273 	return false;
274 
275     if ((unsigned)actor->movedir >= 8)
276 	I_Error ("Weird actor->movedir!");
277 
278     tryx = actor->x + actor->info->speed*xspeed[actor->movedir];
279     tryy = actor->y + actor->info->speed*yspeed[actor->movedir];
280 
281     try_ok = P_TryMove (actor, tryx, tryy);
282 
283     if (!try_ok)
284     {
285 	// open any specials
286 	if (actor->flags & MF_FLOAT && floatok)
287 	{
288 	    // must adjust height
289 	    if (actor->z < tmfloorz)
290 		actor->z += FLOATSPEED;
291 	    else
292 		actor->z -= FLOATSPEED;
293 
294 	    actor->flags |= MF_INFLOAT;
295 	    return true;
296 	}
297 
298 	if (!numspechit)
299 	    return false;
300 
301 	actor->movedir = DI_NODIR;
302 	good = false;
303 	while (numspechit--)
304 	{
305 	    ld = spechit[numspechit];
306 	    // if the special is not a door
307 	    // that can be opened,
308 	    // return false
309 	    if (P_UseSpecialLine (actor, ld,0))
310 		good = true;
311 	}
312 	return good;
313     }
314     else
315     {
316 	actor->flags &= ~MF_INFLOAT;
317     }
318 
319 
320     if (! (actor->flags & MF_FLOAT) )
321 	actor->z = actor->floorz;
322     return true;
323 }
324 
325 
326 //
327 // TryWalk
328 // Attempts to move actor on
329 // in its current (ob->moveangle) direction.
330 // If blocked by either a wall or an actor
331 // returns FALSE
332 // If move is either clear or blocked only by a door,
333 // returns TRUE and sets...
334 // If a door is in the way,
335 // an OpenDoor call is made to start it opening.
336 //
P_TryWalk(mobj_t * actor)337 boolean P_TryWalk (mobj_t* actor)
338 {
339     if (!P_Move (actor))
340     {
341 	return false;
342     }
343 
344     actor->movecount = P_Random()&15;
345     return true;
346 }
347 
348 
349 
350 
P_NewChaseDir(mobj_t * actor)351 void P_NewChaseDir (mobj_t*	actor)
352 {
353     fixed_t	deltax;
354     fixed_t	deltay;
355 
356     dirtype_t	d[3];
357 
358     int		tdir;
359     dirtype_t	olddir;
360 
361     dirtype_t	turnaround;
362 
363     if (!actor->target)
364 	I_Error ("P_NewChaseDir: called with no target");
365 
366     olddir = actor->movedir;
367     turnaround=opposite[olddir];
368 
369     deltax = actor->target->x - actor->x;
370     deltay = actor->target->y - actor->y;
371 
372     if (deltax>10*FRACUNIT)
373 	d[1]= DI_EAST;
374     else if (deltax<-10*FRACUNIT)
375 	d[1]= DI_WEST;
376     else
377 	d[1]=DI_NODIR;
378 
379     if (deltay<-10*FRACUNIT)
380 	d[2]= DI_SOUTH;
381     else if (deltay>10*FRACUNIT)
382 	d[2]= DI_NORTH;
383     else
384 	d[2]=DI_NODIR;
385 
386     // try direct route
387     if (d[1] != DI_NODIR
388 	&& d[2] != DI_NODIR)
389     {
390 	actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
391 	if (actor->movedir != (int) turnaround && P_TryWalk(actor))
392 	    return;
393     }
394 
395     // try other directions
396     if (P_Random() > 200
397 	||  abs(deltay)>abs(deltax))
398     {
399 	tdir=d[1];
400 	d[1]=d[2];
401 	d[2]=tdir;
402     }
403 
404     if (d[1]==turnaround)
405 	d[1]=DI_NODIR;
406     if (d[2]==turnaround)
407 	d[2]=DI_NODIR;
408 
409     if (d[1]!=DI_NODIR)
410     {
411 	actor->movedir = d[1];
412 	if (P_TryWalk(actor))
413 	{
414 	    // either moved forward or attacked
415 	    return;
416 	}
417     }
418 
419     if (d[2]!=DI_NODIR)
420     {
421 	actor->movedir =d[2];
422 
423 	if (P_TryWalk(actor))
424 	    return;
425     }
426 
427     // there is no direct path to the player,
428     // so pick another direction.
429     if (olddir!=DI_NODIR)
430     {
431 	actor->movedir =olddir;
432 
433 	if (P_TryWalk(actor))
434 	    return;
435     }
436 
437     // randomly determine direction of search
438     if (P_Random()&1)
439     {
440 	for ( tdir=DI_EAST;
441 	      tdir<=DI_SOUTHEAST;
442 	      tdir++ )
443 	{
444 	    if (tdir != (int) turnaround)
445 	    {
446 		actor->movedir =tdir;
447 
448 		if ( P_TryWalk(actor) )
449 		    return;
450 	    }
451 	}
452     }
453     else
454     {
455 	for ( tdir=DI_SOUTHEAST;
456 	      tdir != (DI_EAST-1);
457 	      tdir-- )
458 	{
459 	    if (tdir != (int) turnaround)
460 	    {
461 		actor->movedir = tdir;
462 
463 		if ( P_TryWalk(actor) )
464 		    return;
465 	    }
466 	}
467     }
468 
469     if (turnaround !=  DI_NODIR)
470     {
471 	actor->movedir =turnaround;
472 	if ( P_TryWalk(actor) )
473 	    return;
474     }
475 
476     actor->movedir = DI_NODIR;	// can not move
477 }
478 
479 
480 
481 //
482 // P_LookForPlayers
483 // If allaround is false, only look 180 degrees in front.
484 // Returns true if a player is targeted.
485 //
486 boolean
P_LookForPlayers(mobj_t * actor,boolean allaround)487 P_LookForPlayers
488 ( mobj_t*	actor,
489   boolean	allaround )
490 {
491     int		c;
492     int		stop;
493     player_t*	player;
494     angle_t	an;
495     fixed_t	dist;
496 
497     c = 0;
498     stop = (actor->lastlook-1)&3;
499 
500     for ( ; ; actor->lastlook = (actor->lastlook+1)&3 )
501     {
502 	if (!playeringame[actor->lastlook])
503 	    continue;
504 
505 	if (c++ == 2
506 	    || actor->lastlook == stop)
507 	{
508 	    // done looking
509 	    return false;
510 	}
511 
512 	player = &players[actor->lastlook];
513 
514 	if (player->health <= 0)
515 	    continue;		// dead
516 
517 	if (!P_CheckSight (actor, player->mo))
518 	    continue;		// out of sight
519 
520 	if (!allaround)
521 	{
522 	    an = R_PointToAngle2 (actor->x,
523 				  actor->y,
524 				  player->mo->x,
525 				  player->mo->y)
526 		- actor->angle;
527 
528 	    if (an > ANG90 && an < ANG270)
529 	    {
530 		dist = P_AproxDistance (player->mo->x - actor->x,
531 					player->mo->y - actor->y);
532 		// if real close, react anyway
533 		if (dist > MELEERANGE)
534 		    continue;	// behind back
535 	    }
536 	}
537 
538 	actor->target = player->mo;
539 	return true;
540     }
541 
542     return false;
543 }
544 
545 
546 //
547 // A_KeenDie
548 // DOOM II special, map 32.
549 // Uses special tag 666.
550 //
A_KeenDie(mobj_t * mo)551 void A_KeenDie (mobj_t* mo)
552 {
553     thinker_t*	th;
554     mobj_t*	mo2;
555     line_t	junk;
556 
557     A_Fall (mo);
558 
559     // scan the remaining thinkers
560     // to see if all Keens are dead
561     for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
562     {
563 	if (th->function.acp1 != (actionf_p1)P_MobjThinker)
564 	    continue;
565 
566 	mo2 = (mobj_t *)th;
567 	if (mo2 != mo
568 	    && mo2->type == mo->type
569 	    && mo2->health > 0)
570 	{
571 	    // other Keen not dead
572 	    return;
573 	}
574     }
575 
576     junk.tag = 666;
577     EV_DoDoor(&junk, vld_open);
578 }
579 
580 
581 //
582 // ACTION ROUTINES
583 //
584 
585 //
586 // A_Look
587 // Stay in state until a player is sighted.
588 //
A_Look(mobj_t * actor)589 void A_Look (mobj_t* actor)
590 {
591     mobj_t*	targ;
592 
593     actor->threshold = 0;	// any shot will wake up
594     targ = actor->subsector->sector->soundtarget;
595 
596     if (targ
597 	&& (targ->flags & MF_SHOOTABLE) )
598     {
599 	actor->target = targ;
600 
601 	if ( actor->flags & MF_AMBUSH )
602 	{
603 	    if (P_CheckSight (actor, actor->target))
604 		goto seeyou;
605 	}
606 	else
607 	    goto seeyou;
608     }
609 
610 
611     if (!P_LookForPlayers (actor, false) )
612 	return;
613 
614     // go into chase state
615   seeyou:
616     if (actor->info->seesound)
617     {
618 	int		sound;
619 
620 	switch (actor->info->seesound)
621 	{
622 	  case sfx_posit1:
623 	  case sfx_posit2:
624 	  case sfx_posit3:
625 	    sound = sfx_posit1+P_Random()%3;
626 	    break;
627 
628 	  case sfx_bgsit1:
629 	  case sfx_bgsit2:
630 	    sound = sfx_bgsit1+P_Random()%2;
631 	    break;
632 
633 	  default:
634 	    sound = actor->info->seesound;
635 	    break;
636 	}
637 
638 	if (actor->type==MT_SPIDER
639 	    || actor->type == MT_CYBORG)
640 	{
641 	    // full volume
642 	    S_StartSound (NULL, sound);
643 	}
644 	else
645 	    S_StartSound (actor, sound);
646     }
647 
648     P_SetMobjState (actor, actor->info->seestate);
649 }
650 
651 
652 //
653 // A_Chase
654 // Actor has a melee attack,
655 // so it tries to close as fast as possible
656 //
A_Chase(mobj_t * actor)657 void A_Chase (mobj_t*	actor)
658 {
659     int		delta;
660 
661     if (actor->reactiontime)
662 	actor->reactiontime--;
663 
664 
665     // modify target threshold
666     if  (actor->threshold)
667     {
668 	if (!actor->target
669 	    || actor->target->health <= 0)
670 	{
671 	    actor->threshold = 0;
672 	}
673 	else
674 	    actor->threshold--;
675     }
676 
677     // turn towards movement direction if not there yet
678     if (actor->movedir < 8)
679     {
680 	actor->angle &= (7<<29);
681 	delta = actor->angle - (actor->movedir << 29);
682 
683 	if (delta > 0)
684 	    actor->angle -= ANG90/2;
685 	else if (delta < 0)
686 	    actor->angle += ANG90/2;
687     }
688 
689     if (!actor->target
690 	|| !(actor->target->flags&MF_SHOOTABLE))
691     {
692 	// look for a new target
693 	if (P_LookForPlayers(actor,true))
694 	    return; 	// got a new target
695 
696 	P_SetMobjState (actor, actor->info->spawnstate);
697 	return;
698     }
699 
700     // do not attack twice in a row
701     if (actor->flags & MF_JUSTATTACKED)
702     {
703 	actor->flags &= ~MF_JUSTATTACKED;
704 	if (gameskill != sk_nightmare && !fastparm)
705 	    P_NewChaseDir (actor);
706 	return;
707     }
708 
709     // check for melee attack
710     if (actor->info->meleestate
711 	&& P_CheckMeleeRange (actor))
712     {
713 	if (actor->info->attacksound)
714 	    S_StartSound (actor, actor->info->attacksound);
715 
716 	P_SetMobjState (actor, actor->info->meleestate);
717 	return;
718     }
719 
720     // check for missile attack
721     if (actor->info->missilestate)
722     {
723 	if (gameskill < sk_nightmare
724 	    && !fastparm && actor->movecount)
725 	{
726 	    goto nomissile;
727 	}
728 
729 	if (!P_CheckMissileRange (actor))
730 	    goto nomissile;
731 
732 	P_SetMobjState (actor, actor->info->missilestate);
733 	actor->flags |= MF_JUSTATTACKED;
734 	return;
735     }
736 
737     // ?
738   nomissile:
739     // possibly choose another target
740     if (netgame
741 	&& !actor->threshold
742 	&& !P_CheckSight (actor, actor->target) )
743     {
744 	if (P_LookForPlayers(actor,true))
745 	    return;	// got a new target
746     }
747 
748     // chase towards player
749     if (--actor->movecount<0
750 	|| !P_Move (actor))
751     {
752 	P_NewChaseDir (actor);
753     }
754 
755     // make active sound
756     if (actor->info->activesound
757 	&& P_Random () < 3)
758     {
759 	S_StartSound (actor, actor->info->activesound);
760     }
761 }
762 
763 
764 //
765 // A_FaceTarget
766 //
A_FaceTarget(mobj_t * actor)767 void A_FaceTarget (mobj_t* actor)
768 {
769     if (!actor->target)
770 	return;
771 
772     actor->flags &= ~MF_AMBUSH;
773 
774     actor->angle = R_PointToAngle2 (actor->x,
775 				    actor->y,
776 				    actor->target->x,
777 				    actor->target->y);
778 
779     if (actor->target->flags & MF_SHADOW)
780 	actor->angle += P_SubRandom() << 21;
781 }
782 
783 
784 //
785 // A_PosAttack
786 //
A_PosAttack(mobj_t * actor)787 void A_PosAttack (mobj_t* actor)
788 {
789     int		angle;
790     int		damage;
791     int		slope;
792 
793     if (!actor->target)
794 	return;
795 
796     A_FaceTarget (actor);
797     angle = actor->angle;
798     slope = P_AimLineAttack (actor, angle, MISSILERANGE);
799 
800     S_StartSound (actor, sfx_pistol);
801     angle += P_SubRandom() << 20;
802     damage = ((P_Random()%5)+1)*3;
803     P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
804 }
805 
A_SPosAttack(mobj_t * actor)806 void A_SPosAttack (mobj_t* actor)
807 {
808     int		i;
809     int		angle;
810     int		bangle;
811     int		damage;
812     int		slope;
813 
814     if (!actor->target)
815 	return;
816 
817     S_StartSound (actor, sfx_shotgn);
818     A_FaceTarget (actor);
819     bangle = actor->angle;
820     slope = P_AimLineAttack (actor, bangle, MISSILERANGE);
821 
822     for (i=0 ; i<3 ; i++)
823     {
824 	angle = bangle + (P_SubRandom() << 20);
825 	damage = ((P_Random()%5)+1)*3;
826 	P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
827     }
828 }
829 
A_CPosAttack(mobj_t * actor)830 void A_CPosAttack (mobj_t* actor)
831 {
832     int		angle;
833     int		bangle;
834     int		damage;
835     int		slope;
836 
837     if (!actor->target)
838 	return;
839 
840     S_StartSound (actor, sfx_shotgn);
841     A_FaceTarget (actor);
842     bangle = actor->angle;
843     slope = P_AimLineAttack (actor, bangle, MISSILERANGE);
844 
845     angle = bangle + (P_SubRandom() << 20);
846     damage = ((P_Random()%5)+1)*3;
847     P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
848 }
849 
A_CPosRefire(mobj_t * actor)850 void A_CPosRefire (mobj_t* actor)
851 {
852     // keep firing unless target got out of sight
853     A_FaceTarget (actor);
854 
855     if (P_Random () < 40)
856 	return;
857 
858     if (!actor->target
859 	|| actor->target->health <= 0
860 	|| !P_CheckSight (actor, actor->target) )
861     {
862 	P_SetMobjState (actor, actor->info->seestate);
863     }
864 }
865 
866 
A_SpidRefire(mobj_t * actor)867 void A_SpidRefire (mobj_t* actor)
868 {
869     // keep firing unless target got out of sight
870     A_FaceTarget (actor);
871 
872     if (P_Random () < 10)
873 	return;
874 
875     if (!actor->target
876 	|| actor->target->health <= 0
877 	|| !P_CheckSight (actor, actor->target) )
878     {
879 	P_SetMobjState (actor, actor->info->seestate);
880     }
881 }
882 
A_BspiAttack(mobj_t * actor)883 void A_BspiAttack (mobj_t *actor)
884 {
885     if (!actor->target)
886 	return;
887 
888     A_FaceTarget (actor);
889 
890     // launch a missile
891     P_SpawnMissile (actor, actor->target, MT_ARACHPLAZ);
892 }
893 
894 
895 //
896 // A_TroopAttack
897 //
A_TroopAttack(mobj_t * actor)898 void A_TroopAttack (mobj_t* actor)
899 {
900     int		damage;
901 
902     if (!actor->target)
903 	return;
904 
905     A_FaceTarget (actor);
906     if (P_CheckMeleeRange (actor))
907     {
908 	S_StartSound (actor, sfx_claw);
909 	damage = (P_Random()%8+1)*3;
910 	P_DamageMobj (actor->target, actor, actor, damage);
911 	return;
912     }
913 
914 
915     // launch a missile
916     P_SpawnMissile (actor, actor->target, MT_TROOPSHOT);
917 }
918 
919 
A_SargAttack(mobj_t * actor)920 void A_SargAttack (mobj_t* actor)
921 {
922     int		damage;
923 
924     if (!actor->target)
925 	return;
926 
927     A_FaceTarget (actor);
928     if (P_CheckMeleeRange (actor))
929     {
930 	damage = ((P_Random()%10)+1)*4;
931 	P_DamageMobj (actor->target, actor, actor, damage);
932     }
933 }
934 
A_HeadAttack(mobj_t * actor)935 void A_HeadAttack (mobj_t* actor)
936 {
937     int		damage;
938 
939     if (!actor->target)
940 	return;
941 
942     A_FaceTarget (actor);
943     if (P_CheckMeleeRange (actor))
944     {
945 	damage = (P_Random()%6+1)*10;
946 	P_DamageMobj (actor->target, actor, actor, damage);
947 	return;
948     }
949 
950     // launch a missile
951     P_SpawnMissile (actor, actor->target, MT_HEADSHOT);
952 }
953 
A_CyberAttack(mobj_t * actor)954 void A_CyberAttack (mobj_t* actor)
955 {
956     if (!actor->target)
957 	return;
958 
959     A_FaceTarget (actor);
960     P_SpawnMissile (actor, actor->target, MT_ROCKET);
961 }
962 
963 
A_BruisAttack(mobj_t * actor)964 void A_BruisAttack (mobj_t* actor)
965 {
966     int		damage;
967 
968     if (!actor->target)
969 	return;
970 
971     if (P_CheckMeleeRange (actor))
972     {
973 	S_StartSound (actor, sfx_claw);
974 	damage = (P_Random()%8+1)*10;
975 	P_DamageMobj (actor->target, actor, actor, damage);
976 	return;
977     }
978 
979     // launch a missile
980     P_SpawnMissile (actor, actor->target, MT_BRUISERSHOT);
981 }
982 
983 
984 //
985 // A_SkelMissile
986 //
A_SkelMissile(mobj_t * actor)987 void A_SkelMissile (mobj_t* actor)
988 {
989     mobj_t*	mo;
990 
991     if (!actor->target)
992 	return;
993 
994     A_FaceTarget (actor);
995     actor->z += 16*FRACUNIT;	// so missile spawns higher
996     mo = P_SpawnMissile (actor, actor->target, MT_TRACER);
997     actor->z -= 16*FRACUNIT;	// back to normal
998 
999     mo->x += mo->momx;
1000     mo->y += mo->momy;
1001     mo->tracer = actor->target;
1002 }
1003 
1004 int	TRACEANGLE = 0xc000000;
1005 
A_Tracer(mobj_t * actor)1006 void A_Tracer (mobj_t* actor)
1007 {
1008     angle_t	exact;
1009     fixed_t	dist;
1010     fixed_t	slope;
1011     mobj_t*	dest;
1012     mobj_t*	th;
1013 
1014     if (gametic & 3)
1015 	return;
1016 
1017     // spawn a puff of smoke behind the rocket
1018     P_SpawnPuff (actor->x, actor->y, actor->z);
1019 
1020     th = P_SpawnMobj (actor->x-actor->momx,
1021 		      actor->y-actor->momy,
1022 		      actor->z, MT_SMOKE);
1023 
1024     th->momz = FRACUNIT;
1025     th->tics -= P_Random()&3;
1026     if (th->tics < 1)
1027 	th->tics = 1;
1028 
1029     // adjust direction
1030     dest = actor->tracer;
1031 
1032     if (!dest || dest->health <= 0)
1033 	return;
1034 
1035     // change angle
1036     exact = R_PointToAngle2 (actor->x,
1037 			     actor->y,
1038 			     dest->x,
1039 			     dest->y);
1040 
1041     if (exact != actor->angle)
1042     {
1043 	if (exact - actor->angle > 0x80000000)
1044 	{
1045 	    actor->angle -= TRACEANGLE;
1046 	    if (exact - actor->angle < 0x80000000)
1047 		actor->angle = exact;
1048 	}
1049 	else
1050 	{
1051 	    actor->angle += TRACEANGLE;
1052 	    if (exact - actor->angle > 0x80000000)
1053 		actor->angle = exact;
1054 	}
1055     }
1056 
1057     exact = actor->angle>>ANGLETOFINESHIFT;
1058     actor->momx = FixedMul (actor->info->speed, finecosine[exact]);
1059     actor->momy = FixedMul (actor->info->speed, finesine[exact]);
1060 
1061     // change slope
1062     dist = P_AproxDistance (dest->x - actor->x,
1063 			    dest->y - actor->y);
1064 
1065     dist = dist / actor->info->speed;
1066 
1067     if (dist < 1)
1068 	dist = 1;
1069     slope = (dest->z+40*FRACUNIT - actor->z) / dist;
1070 
1071     if (slope < actor->momz)
1072 	actor->momz -= FRACUNIT/8;
1073     else
1074 	actor->momz += FRACUNIT/8;
1075 }
1076 
1077 
A_SkelWhoosh(mobj_t * actor)1078 void A_SkelWhoosh (mobj_t*	actor)
1079 {
1080     if (!actor->target)
1081 	return;
1082     A_FaceTarget (actor);
1083     S_StartSound (actor,sfx_skeswg);
1084 }
1085 
A_SkelFist(mobj_t * actor)1086 void A_SkelFist (mobj_t*	actor)
1087 {
1088     int		damage;
1089 
1090     if (!actor->target)
1091 	return;
1092 
1093     A_FaceTarget (actor);
1094 
1095     if (P_CheckMeleeRange (actor))
1096     {
1097 	damage = ((P_Random()%10)+1)*6;
1098 	S_StartSound (actor, sfx_skepch);
1099 	P_DamageMobj (actor->target, actor, actor, damage);
1100     }
1101 }
1102 
1103 
1104 
1105 //
1106 // PIT_VileCheck
1107 // Detect a corpse that could be raised.
1108 //
1109 mobj_t*		corpsehit;
1110 mobj_t*		vileobj;
1111 fixed_t		viletryx;
1112 fixed_t		viletryy;
1113 
PIT_VileCheck(mobj_t * thing)1114 boolean PIT_VileCheck (mobj_t*	thing)
1115 {
1116     int		maxdist;
1117     boolean	check;
1118 
1119     if (!(thing->flags & MF_CORPSE) )
1120 	return true;	// not a monster
1121 
1122     if (thing->tics != -1)
1123 	return true;	// not lying still yet
1124 
1125     if (thing->info->raisestate == S_NULL)
1126 	return true;	// monster doesn't have a raise state
1127 
1128     maxdist = thing->info->radius + mobjinfo[MT_VILE].radius;
1129 
1130     if ( abs(thing->x - viletryx) > maxdist
1131 	 || abs(thing->y - viletryy) > maxdist )
1132 	return true;		// not actually touching
1133 
1134     corpsehit = thing;
1135     corpsehit->momx = corpsehit->momy = 0;
1136     corpsehit->height <<= 2;
1137     check = P_CheckPosition (corpsehit, corpsehit->x, corpsehit->y);
1138     corpsehit->height >>= 2;
1139 
1140     if (!check)
1141 	return true;		// doesn't fit here
1142 
1143     return false;		// got one, so stop checking
1144 }
1145 
1146 
1147 
1148 //
1149 // A_VileChase
1150 // Check for ressurecting a body
1151 //
A_VileChase(mobj_t * actor)1152 void A_VileChase (mobj_t* actor)
1153 {
1154     int			xl;
1155     int			xh;
1156     int			yl;
1157     int			yh;
1158 
1159     int			bx;
1160     int			by;
1161 
1162     mobjinfo_t*		info;
1163     mobj_t*		temp;
1164 
1165     if (actor->movedir != DI_NODIR)
1166     {
1167 	// check for corpses to raise
1168 	viletryx =
1169 	    actor->x + actor->info->speed*xspeed[actor->movedir];
1170 	viletryy =
1171 	    actor->y + actor->info->speed*yspeed[actor->movedir];
1172 
1173 	xl = (viletryx - bmaporgx - MAXRADIUS*2)>>MAPBLOCKSHIFT;
1174 	xh = (viletryx - bmaporgx + MAXRADIUS*2)>>MAPBLOCKSHIFT;
1175 	yl = (viletryy - bmaporgy - MAXRADIUS*2)>>MAPBLOCKSHIFT;
1176 	yh = (viletryy - bmaporgy + MAXRADIUS*2)>>MAPBLOCKSHIFT;
1177 
1178 	vileobj = actor;
1179 	for (bx=xl ; bx<=xh ; bx++)
1180 	{
1181 	    for (by=yl ; by<=yh ; by++)
1182 	    {
1183 		// Call PIT_VileCheck to check
1184 		// whether object is a corpse
1185 		// that canbe raised.
1186 		if (!P_BlockThingsIterator(bx,by,PIT_VileCheck))
1187 		{
1188 		    // got one!
1189 		    temp = actor->target;
1190 		    actor->target = corpsehit;
1191 		    A_FaceTarget (actor);
1192 		    actor->target = temp;
1193 
1194 		    P_SetMobjState (actor, S_VILE_HEAL1);
1195 		    S_StartSound (corpsehit, sfx_slop);
1196 		    info = corpsehit->info;
1197 
1198 		    P_SetMobjState (corpsehit,info->raisestate);
1199 		    corpsehit->height <<= 2;
1200 		    corpsehit->flags = info->flags;
1201 		    corpsehit->health = info->spawnhealth;
1202 		    corpsehit->target = NULL;
1203 
1204 		    return;
1205 		}
1206 	    }
1207 	}
1208     }
1209 
1210     // Return to normal attack.
1211     A_Chase (actor);
1212 }
1213 
1214 
1215 //
1216 // A_VileStart
1217 //
A_VileStart(mobj_t * actor)1218 void A_VileStart (mobj_t* actor)
1219 {
1220     S_StartSound (actor, sfx_vilatk);
1221 }
1222 
1223 
1224 //
1225 // A_Fire
1226 // Keep fire in front of player unless out of sight
1227 //
1228 void A_Fire (mobj_t* actor);
1229 
A_StartFire(mobj_t * actor)1230 void A_StartFire (mobj_t* actor)
1231 {
1232     S_StartSound(actor,sfx_flamst);
1233     A_Fire(actor);
1234 }
1235 
A_FireCrackle(mobj_t * actor)1236 void A_FireCrackle (mobj_t* actor)
1237 {
1238     S_StartSound(actor,sfx_flame);
1239     A_Fire(actor);
1240 }
1241 
A_Fire(mobj_t * actor)1242 void A_Fire (mobj_t* actor)
1243 {
1244     mobj_t*	dest;
1245     mobj_t*     target;
1246     unsigned	an;
1247 
1248     dest = actor->tracer;
1249     if (!dest)
1250 	return;
1251 
1252     target = P_SubstNullMobj(actor->target);
1253 
1254     // don't move it if the vile lost sight
1255     if (!P_CheckSight (target, dest) )
1256 	return;
1257 
1258     an = dest->angle >> ANGLETOFINESHIFT;
1259 
1260     P_UnsetThingPosition (actor);
1261     actor->x = dest->x + FixedMul (24*FRACUNIT, finecosine[an]);
1262     actor->y = dest->y + FixedMul (24*FRACUNIT, finesine[an]);
1263     actor->z = dest->z;
1264     P_SetThingPosition (actor);
1265 }
1266 
1267 
1268 
1269 //
1270 // A_VileTarget
1271 // Spawn the hellfire
1272 //
A_VileTarget(mobj_t * actor)1273 void A_VileTarget (mobj_t*	actor)
1274 {
1275     mobj_t*	fog;
1276 
1277     if (!actor->target)
1278 	return;
1279 
1280     A_FaceTarget (actor);
1281 
1282     fog = P_SpawnMobj (actor->target->x,
1283 		       actor->target->x,
1284 		       actor->target->z, MT_FIRE);
1285 
1286     actor->tracer = fog;
1287     fog->target = actor;
1288     fog->tracer = actor->target;
1289     A_Fire (fog);
1290 }
1291 
1292 
1293 
1294 
1295 //
1296 // A_VileAttack
1297 //
A_VileAttack(mobj_t * actor)1298 void A_VileAttack (mobj_t* actor)
1299 {
1300     mobj_t*	fire;
1301     int		an;
1302 
1303     if (!actor->target)
1304 	return;
1305 
1306     A_FaceTarget (actor);
1307 
1308     if (!P_CheckSight (actor, actor->target) )
1309 	return;
1310 
1311     S_StartSound (actor, sfx_barexp);
1312     P_DamageMobj (actor->target, actor, actor, 20);
1313     actor->target->momz = 1000*FRACUNIT/actor->target->info->mass;
1314 
1315     an = actor->angle >> ANGLETOFINESHIFT;
1316 
1317     fire = actor->tracer;
1318 
1319     if (!fire)
1320 	return;
1321 
1322     // move the fire between the vile and the player
1323     fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]);
1324     fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]);
1325     P_RadiusAttack (fire, actor, 70 );
1326 }
1327 
1328 
1329 
1330 
1331 //
1332 // Mancubus attack,
1333 // firing three missiles (bruisers)
1334 // in three different directions?
1335 // Doesn't look like it.
1336 //
1337 #define	FATSPREAD	(ANG90/8)
1338 
A_FatRaise(mobj_t * actor)1339 void A_FatRaise (mobj_t *actor)
1340 {
1341     A_FaceTarget (actor);
1342     S_StartSound (actor, sfx_manatk);
1343 }
1344 
1345 
A_FatAttack1(mobj_t * actor)1346 void A_FatAttack1 (mobj_t* actor)
1347 {
1348     mobj_t*	mo;
1349     mobj_t*     target;
1350     int		an;
1351 
1352     A_FaceTarget (actor);
1353 
1354     // Change direction  to ...
1355     actor->angle += FATSPREAD;
1356     target = P_SubstNullMobj(actor->target);
1357     P_SpawnMissile (actor, target, MT_FATSHOT);
1358 
1359     mo = P_SpawnMissile (actor, target, MT_FATSHOT);
1360     mo->angle += FATSPREAD;
1361     an = mo->angle >> ANGLETOFINESHIFT;
1362     mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1363     mo->momy = FixedMul (mo->info->speed, finesine[an]);
1364 }
1365 
A_FatAttack2(mobj_t * actor)1366 void A_FatAttack2 (mobj_t* actor)
1367 {
1368     mobj_t*	mo;
1369     mobj_t*     target;
1370     int		an;
1371 
1372     A_FaceTarget (actor);
1373     // Now here choose opposite deviation.
1374     actor->angle -= FATSPREAD;
1375     target = P_SubstNullMobj(actor->target);
1376     P_SpawnMissile (actor, target, MT_FATSHOT);
1377 
1378     mo = P_SpawnMissile (actor, target, MT_FATSHOT);
1379     mo->angle -= FATSPREAD*2;
1380     an = mo->angle >> ANGLETOFINESHIFT;
1381     mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1382     mo->momy = FixedMul (mo->info->speed, finesine[an]);
1383 }
1384 
A_FatAttack3(mobj_t * actor)1385 void A_FatAttack3 (mobj_t*	actor)
1386 {
1387     mobj_t*	mo;
1388     mobj_t*     target;
1389     int		an;
1390 
1391     A_FaceTarget (actor);
1392 
1393     target = P_SubstNullMobj(actor->target);
1394 
1395     mo = P_SpawnMissile (actor, target, MT_FATSHOT);
1396     mo->angle -= FATSPREAD/2;
1397     an = mo->angle >> ANGLETOFINESHIFT;
1398     mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1399     mo->momy = FixedMul (mo->info->speed, finesine[an]);
1400 
1401     mo = P_SpawnMissile (actor, target, MT_FATSHOT);
1402     mo->angle += FATSPREAD/2;
1403     an = mo->angle >> ANGLETOFINESHIFT;
1404     mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1405     mo->momy = FixedMul (mo->info->speed, finesine[an]);
1406 }
1407 
1408 
1409 //
1410 // SkullAttack
1411 // Fly at the player like a missile.
1412 //
1413 #define	SKULLSPEED		(20*FRACUNIT)
1414 
A_SkullAttack(mobj_t * actor)1415 void A_SkullAttack (mobj_t* actor)
1416 {
1417     mobj_t*		dest;
1418     angle_t		an;
1419     int			dist;
1420 
1421     if (!actor->target)
1422 	return;
1423 
1424     dest = actor->target;
1425     actor->flags |= MF_SKULLFLY;
1426 
1427     S_StartSound (actor, actor->info->attacksound);
1428     A_FaceTarget (actor);
1429     an = actor->angle >> ANGLETOFINESHIFT;
1430     actor->momx = FixedMul (SKULLSPEED, finecosine[an]);
1431     actor->momy = FixedMul (SKULLSPEED, finesine[an]);
1432     dist = P_AproxDistance (dest->x - actor->x, dest->y - actor->y);
1433     dist = dist / SKULLSPEED;
1434 
1435     if (dist < 1)
1436 	dist = 1;
1437     actor->momz = (dest->z+(dest->height>>1) - actor->z) / dist;
1438 }
1439 
1440 
1441 //
1442 // A_PainShootSkull
1443 // Spawn a lost soul and launch it at the target
1444 //
1445 void
A_PainShootSkull(mobj_t * actor,angle_t angle)1446 A_PainShootSkull
1447 ( mobj_t*	actor,
1448   angle_t	angle )
1449 {
1450     fixed_t	x;
1451     fixed_t	y;
1452     fixed_t	z;
1453 
1454     mobj_t*	newmobj;
1455     angle_t	an;
1456     int		prestep;
1457     int		count;
1458     thinker_t*	currentthinker;
1459 
1460     // count total number of skull currently on the level
1461     count = 0;
1462 
1463     currentthinker = thinkercap.next;
1464     while (currentthinker != &thinkercap)
1465     {
1466 	if (   (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
1467 	    && ((mobj_t *)currentthinker)->type == MT_SKULL)
1468 	    count++;
1469 	currentthinker = currentthinker->next;
1470     }
1471 
1472     // if there are allready 20 skulls on the level,
1473     // don't spit another one
1474     if (count > 20)
1475 	return;
1476 
1477 
1478     // okay, there's playe for another one
1479     an = angle >> ANGLETOFINESHIFT;
1480 
1481     prestep =
1482 	4*FRACUNIT
1483 	+ 3*(actor->info->radius + mobjinfo[MT_SKULL].radius)/2;
1484 
1485     x = actor->x + FixedMul (prestep, finecosine[an]);
1486     y = actor->y + FixedMul (prestep, finesine[an]);
1487     z = actor->z + 8*FRACUNIT;
1488 
1489     newmobj = P_SpawnMobj (x , y, z, MT_SKULL);
1490 
1491     // Check for movements.
1492     if (!P_TryMove (newmobj, newmobj->x, newmobj->y))
1493     {
1494 	// kill it immediately
1495 	P_DamageMobj (newmobj,actor,actor,10000);
1496 	return;
1497     }
1498 
1499     newmobj->target = actor->target;
1500     A_SkullAttack (newmobj);
1501 }
1502 
1503 
1504 //
1505 // A_PainAttack
1506 // Spawn a lost soul and launch it at the target
1507 //
A_PainAttack(mobj_t * actor)1508 void A_PainAttack (mobj_t* actor)
1509 {
1510     if (!actor->target)
1511 	return;
1512 
1513     A_FaceTarget (actor);
1514     A_PainShootSkull (actor, actor->angle);
1515 }
1516 
1517 
A_PainDie(mobj_t * actor)1518 void A_PainDie (mobj_t* actor)
1519 {
1520     A_Fall (actor);
1521     A_PainShootSkull (actor, actor->angle+ANG90);
1522     A_PainShootSkull (actor, actor->angle+ANG180);
1523     A_PainShootSkull (actor, actor->angle+ANG270);
1524 }
1525 
1526 
1527 
1528 
1529 
1530 
A_Scream(mobj_t * actor)1531 void A_Scream (mobj_t* actor)
1532 {
1533     int		sound;
1534 
1535     switch (actor->info->deathsound)
1536     {
1537       case 0:
1538 	return;
1539 
1540       case sfx_podth1:
1541       case sfx_podth2:
1542       case sfx_podth3:
1543 	sound = sfx_podth1 + P_Random ()%3;
1544 	break;
1545 
1546       case sfx_bgdth1:
1547       case sfx_bgdth2:
1548 	sound = sfx_bgdth1 + P_Random ()%2;
1549 	break;
1550 
1551       default:
1552 	sound = actor->info->deathsound;
1553 	break;
1554     }
1555 
1556     // Check for bosses.
1557     if (actor->type==MT_SPIDER
1558 	|| actor->type == MT_CYBORG)
1559     {
1560 	// full volume
1561 	S_StartSound (NULL, sound);
1562     }
1563     else
1564 	S_StartSound (actor, sound);
1565 }
1566 
1567 
A_XScream(mobj_t * actor)1568 void A_XScream (mobj_t* actor)
1569 {
1570     S_StartSound (actor, sfx_slop);
1571 }
1572 
A_Pain(mobj_t * actor)1573 void A_Pain (mobj_t* actor)
1574 {
1575     if (actor->info->painsound)
1576 	S_StartSound (actor, actor->info->painsound);
1577 }
1578 
1579 
1580 
A_Fall(mobj_t * actor)1581 void A_Fall (mobj_t *actor)
1582 {
1583     // actor is on ground, it can be walked over
1584     actor->flags &= ~MF_SOLID;
1585 
1586     // So change this if corpse objects
1587     // are meant to be obstacles.
1588 }
1589 
1590 
1591 //
1592 // A_Explode
1593 //
A_Explode(mobj_t * thingy)1594 void A_Explode (mobj_t* thingy)
1595 {
1596     P_RadiusAttack(thingy, thingy->target, 128);
1597 }
1598 
1599 // Check whether the death of the specified monster type is allowed
1600 // to trigger the end of episode special action.
1601 //
1602 // This behavior changed in v1.9, the most notable effect of which
1603 // was to break uac_dead.wad
1604 
CheckBossEnd(mobjtype_t motype)1605 static boolean CheckBossEnd(mobjtype_t motype)
1606 {
1607     if (gameversion < exe_ultimate)
1608     {
1609         if (gamemap != 8)
1610         {
1611             return false;
1612         }
1613 
1614         // Baron death on later episodes is nothing special.
1615 
1616         if (motype == MT_BRUISER && gameepisode != 1)
1617         {
1618             return false;
1619         }
1620 
1621         return true;
1622     }
1623     else
1624     {
1625         // New logic that appeared in Ultimate Doom.
1626         // Looks like the logic was overhauled while adding in the
1627         // episode 4 support.  Now bosses only trigger on their
1628         // specific episode.
1629 
1630 	switch(gameepisode)
1631 	{
1632             case 1:
1633                 return gamemap == 8 && motype == MT_BRUISER;
1634 
1635             case 2:
1636                 return gamemap == 8 && motype == MT_CYBORG;
1637 
1638             case 3:
1639                 return gamemap == 8 && motype == MT_SPIDER;
1640 
1641 	    case 4:
1642                 return (gamemap == 6 && motype == MT_CYBORG)
1643                     || (gamemap == 8 && motype == MT_SPIDER);
1644 
1645             default:
1646                 return gamemap == 8;
1647 	}
1648     }
1649 }
1650 
1651 //
1652 // A_BossDeath
1653 // Possibly trigger special effects
1654 // if on first boss level
1655 //
A_BossDeath(mobj_t * mo)1656 void A_BossDeath (mobj_t* mo)
1657 {
1658     thinker_t*	th;
1659     mobj_t*	mo2;
1660     line_t	junk;
1661     int		i;
1662 
1663     if ( gamemode == commercial)
1664     {
1665 	if (gamemap != 7)
1666 	    return;
1667 
1668 	if ((mo->type != MT_FATSO)
1669 	    && (mo->type != MT_BABY))
1670 	    return;
1671     }
1672     else
1673     {
1674         if (!CheckBossEnd(mo->type))
1675         {
1676             return;
1677         }
1678     }
1679 
1680     // make sure there is a player alive for victory
1681     for (i=0 ; i<MAXPLAYERS ; i++)
1682 	if (playeringame[i] && players[i].health > 0)
1683 	    break;
1684 
1685     if (i==MAXPLAYERS)
1686 	return;	// no one left alive, so do not end game
1687 
1688     // scan the remaining thinkers to see
1689     // if all bosses are dead
1690     for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
1691     {
1692 	if (th->function.acp1 != (actionf_p1)P_MobjThinker)
1693 	    continue;
1694 
1695 	mo2 = (mobj_t *)th;
1696 	if (mo2 != mo
1697 	    && mo2->type == mo->type
1698 	    && mo2->health > 0)
1699 	{
1700 	    // other boss not dead
1701 	    return;
1702 	}
1703     }
1704 
1705     // victory!
1706     if ( gamemode == commercial)
1707     {
1708 	if (gamemap == 7)
1709 	{
1710 	    if (mo->type == MT_FATSO)
1711 	    {
1712 		junk.tag = 666;
1713 		EV_DoFloor(&junk,lowerFloorToLowest);
1714 		return;
1715 	    }
1716 
1717 	    if (mo->type == MT_BABY)
1718 	    {
1719 		junk.tag = 667;
1720 		EV_DoFloor(&junk,raiseToTexture);
1721 		return;
1722 	    }
1723 	}
1724     }
1725     else
1726     {
1727 	switch(gameepisode)
1728 	{
1729 	  case 1:
1730 	    junk.tag = 666;
1731 	    EV_DoFloor (&junk, lowerFloorToLowest);
1732 	    return;
1733 	    break;
1734 
1735 	  case 4:
1736 	    switch(gamemap)
1737 	    {
1738 	      case 6:
1739 		junk.tag = 666;
1740 		EV_DoDoor (&junk, vld_blazeOpen);
1741 		return;
1742 		break;
1743 
1744 	      case 8:
1745 		junk.tag = 666;
1746 		EV_DoFloor (&junk, lowerFloorToLowest);
1747 		return;
1748 		break;
1749 	    }
1750 	}
1751     }
1752 
1753     G_ExitLevel ();
1754 }
1755 
1756 
A_Hoof(mobj_t * mo)1757 void A_Hoof (mobj_t* mo)
1758 {
1759     S_StartSound (mo, sfx_hoof);
1760     A_Chase (mo);
1761 }
1762 
A_Metal(mobj_t * mo)1763 void A_Metal (mobj_t* mo)
1764 {
1765     S_StartSound (mo, sfx_metal);
1766     A_Chase (mo);
1767 }
1768 
A_BabyMetal(mobj_t * mo)1769 void A_BabyMetal (mobj_t* mo)
1770 {
1771     S_StartSound (mo, sfx_bspwlk);
1772     A_Chase (mo);
1773 }
1774 
1775 void
A_OpenShotgun2(player_t * player,pspdef_t * psp)1776 A_OpenShotgun2
1777 ( player_t*	player,
1778   pspdef_t*	psp )
1779 {
1780     S_StartSound (player->mo, sfx_dbopn);
1781 }
1782 
1783 void
A_LoadShotgun2(player_t * player,pspdef_t * psp)1784 A_LoadShotgun2
1785 ( player_t*	player,
1786   pspdef_t*	psp )
1787 {
1788     S_StartSound (player->mo, sfx_dbload);
1789 }
1790 
1791 void
1792 A_ReFire
1793 ( player_t*	player,
1794   pspdef_t*	psp );
1795 
1796 void
A_CloseShotgun2(player_t * player,pspdef_t * psp)1797 A_CloseShotgun2
1798 ( player_t*	player,
1799   pspdef_t*	psp )
1800 {
1801     S_StartSound (player->mo, sfx_dbcls);
1802     A_ReFire(player,psp);
1803 }
1804 
1805 
1806 
1807 mobj_t*		braintargets[32];
1808 int		numbraintargets;
1809 int		braintargeton = 0;
1810 
A_BrainAwake(mobj_t * mo)1811 void A_BrainAwake (mobj_t* mo)
1812 {
1813     thinker_t*	thinker;
1814     mobj_t*	m;
1815 
1816     // find all the target spots
1817     numbraintargets = 0;
1818     braintargeton = 0;
1819 
1820     thinker = thinkercap.next;
1821     for (thinker = thinkercap.next ;
1822 	 thinker != &thinkercap ;
1823 	 thinker = thinker->next)
1824     {
1825 	if (thinker->function.acp1 != (actionf_p1)P_MobjThinker)
1826 	    continue;	// not a mobj
1827 
1828 	m = (mobj_t *)thinker;
1829 
1830 	if (m->type == MT_BOSSTARGET )
1831 	{
1832 	    braintargets[numbraintargets] = m;
1833 	    numbraintargets++;
1834 	}
1835     }
1836 
1837     S_StartSound (NULL,sfx_bossit);
1838 }
1839 
1840 
A_BrainPain(mobj_t * mo)1841 void A_BrainPain (mobj_t*	mo)
1842 {
1843     S_StartSound (NULL,sfx_bospn);
1844 }
1845 
1846 
A_BrainScream(mobj_t * mo)1847 void A_BrainScream (mobj_t*	mo)
1848 {
1849     int		x;
1850     int		y;
1851     int		z;
1852     mobj_t*	th;
1853 
1854     for (x=mo->x - 196*FRACUNIT ; x< mo->x + 320*FRACUNIT ; x+= FRACUNIT*8)
1855     {
1856 	y = mo->y - 320*FRACUNIT;
1857 	z = 128 + P_Random()*2*FRACUNIT;
1858 	th = P_SpawnMobj (x,y,z, MT_ROCKET);
1859 	th->momz = P_Random()*512;
1860 
1861 	P_SetMobjState (th, S_BRAINEXPLODE1);
1862 
1863 	th->tics -= P_Random()&7;
1864 	if (th->tics < 1)
1865 	    th->tics = 1;
1866     }
1867 
1868     S_StartSound (NULL,sfx_bosdth);
1869 }
1870 
1871 
1872 
A_BrainExplode(mobj_t * mo)1873 void A_BrainExplode (mobj_t* mo)
1874 {
1875     int		x;
1876     int		y;
1877     int		z;
1878     mobj_t*	th;
1879 
1880     x = mo->x +  P_SubRandom() * 2048;
1881     y = mo->y;
1882     z = 128 + P_Random()*2*FRACUNIT;
1883     th = P_SpawnMobj (x,y,z, MT_ROCKET);
1884     th->momz = P_Random()*512;
1885 
1886     P_SetMobjState (th, S_BRAINEXPLODE1);
1887 
1888     th->tics -= P_Random()&7;
1889     if (th->tics < 1)
1890 	th->tics = 1;
1891 }
1892 
1893 
A_BrainDie(mobj_t * mo)1894 void A_BrainDie (mobj_t*	mo)
1895 {
1896     G_ExitLevel ();
1897 }
1898 
A_BrainSpit(mobj_t * mo)1899 void A_BrainSpit (mobj_t*	mo)
1900 {
1901     mobj_t*	targ;
1902     mobj_t*	newmobj;
1903 
1904     static int	easy = 0;
1905 
1906     easy ^= 1;
1907     if (gameskill <= sk_easy && (!easy))
1908 	return;
1909 
1910     // shoot a cube at current target
1911     targ = braintargets[braintargeton];
1912     braintargeton = (braintargeton+1)%numbraintargets;
1913 
1914     // spawn brain missile
1915     newmobj = P_SpawnMissile (mo, targ, MT_SPAWNSHOT);
1916     newmobj->target = targ;
1917     newmobj->reactiontime =
1918 	((targ->y - mo->y)/newmobj->momy) / newmobj->state->tics;
1919 
1920     S_StartSound(NULL, sfx_bospit);
1921 }
1922 
1923 
1924 
1925 void A_SpawnFly (mobj_t* mo);
1926 
1927 // travelling cube sound
A_SpawnSound(mobj_t * mo)1928 void A_SpawnSound (mobj_t* mo)
1929 {
1930     S_StartSound (mo,sfx_boscub);
1931     A_SpawnFly(mo);
1932 }
1933 
A_SpawnFly(mobj_t * mo)1934 void A_SpawnFly (mobj_t* mo)
1935 {
1936     mobj_t*	newmobj;
1937     mobj_t*	fog;
1938     mobj_t*	targ;
1939     int		r;
1940     mobjtype_t	type;
1941 
1942     if (--mo->reactiontime)
1943 	return;	// still flying
1944 
1945     targ = P_SubstNullMobj(mo->target);
1946 
1947     // First spawn teleport fog.
1948     fog = P_SpawnMobj (targ->x, targ->y, targ->z, MT_SPAWNFIRE);
1949     S_StartSound (fog, sfx_telept);
1950 
1951     // Randomly select monster to spawn.
1952     r = P_Random ();
1953 
1954     // Probability distribution (kind of :),
1955     // decreasing likelihood.
1956     if ( r<50 )
1957 	type = MT_TROOP;
1958     else if (r<90)
1959 	type = MT_SERGEANT;
1960     else if (r<120)
1961 	type = MT_SHADOWS;
1962     else if (r<130)
1963 	type = MT_PAIN;
1964     else if (r<160)
1965 	type = MT_HEAD;
1966     else if (r<162)
1967 	type = MT_VILE;
1968     else if (r<172)
1969 	type = MT_UNDEAD;
1970     else if (r<192)
1971 	type = MT_BABY;
1972     else if (r<222)
1973 	type = MT_FATSO;
1974     else if (r<246)
1975 	type = MT_KNIGHT;
1976     else
1977 	type = MT_BRUISER;
1978 
1979     newmobj	= P_SpawnMobj (targ->x, targ->y, targ->z, type);
1980     if (P_LookForPlayers (newmobj, true) )
1981 	P_SetMobjState (newmobj, newmobj->info->seestate);
1982 
1983     // telefrag anything in this spot
1984     P_TeleportMove (newmobj, newmobj->x, newmobj->y);
1985 
1986     // remove self (i.e., cube).
1987     P_RemoveMobj (mo);
1988 }
1989 
1990 
1991 
A_PlayerScream(mobj_t * mo)1992 void A_PlayerScream (mobj_t* mo)
1993 {
1994     // Default death sound.
1995     int		sound = sfx_pldeth;
1996 
1997     if ( (gamemode == commercial)
1998 	&& 	(mo->health < -50))
1999     {
2000 	// IF THE PLAYER DIES
2001 	// LESS THAN -50% WITHOUT GIBBING
2002 	sound = sfx_pdiehi;
2003     }
2004 
2005     S_StartSound (mo, sound);
2006 }
2007