1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: p_enemy.cpp 4542 2014-02-09 17:39:42Z dr_sean $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Copyright (C) 2006-2014 by The Odamex Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // DESCRIPTION:
20 //	Enemy thinking, AI.
21 //	Action Pointer Functions
22 //	that are associated with states/frames.
23 //
24 //-----------------------------------------------------------------------------
25 
26 #include <math.h>
27 #include "m_random.h"
28 #include "m_alloc.h"
29 #include "i_system.h"
30 #include "doomdef.h"
31 #include "p_local.h"
32 #include "p_lnspec.h"
33 #include "s_sound.h"
34 #include "g_game.h"
35 #include "doomstat.h"
36 #include "r_state.h"
37 #include "c_cvars.h"
38 #include "gi.h"
39 #include "p_mobj.h"
40 
41 #include "d_player.h"
42 
43 extern bool HasBehavior;
44 
45 EXTERN_CVAR (sv_allowexit)
46 EXTERN_CVAR (sv_fastmonsters)
47 EXTERN_CVAR (co_realactorheight)
48 EXTERN_CVAR (co_zdoomphys)
49 
50 enum dirtype_t
51 {
52 	DI_EAST,
53 	DI_NORTHEAST,
54 	DI_NORTH,
55 	DI_NORTHWEST,
56 	DI_WEST,
57 	DI_SOUTHWEST,
58 	DI_SOUTH,
59 	DI_SOUTHEAST,
60 	DI_NODIR,
61 	NUMDIRS
62 };
63 
64 //
65 // P_NewChaseDir related LUT.
66 //
67 
68 dirtype_t opposite[9] =
69 {
70 	DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST,
71 	DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR
72 };
73 
74 dirtype_t diags[4] =
75 {
76 	DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST
77 };
78 
79 fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
80 fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
81 
82 
83 void A_Die (AActor *actor);
84 void A_Detonate (AActor *mo);
85 void A_Explode (AActor *thing);
86 void A_Mushroom (AActor *actor);
87 void A_Fall (AActor *actor);
88 
89 
90 //
91 // ENEMY THINKING
92 // Enemies are always spawned
93 // with targetplayer = -1, threshold = 0
94 // Most monsters are spawned unaware of all players,
95 // but some can be made preaware
96 //
97 
98 
99 //
100 // Called by P_NoiseAlert.
101 // Recursively traverse adjacent sectors,
102 // sound blocking lines cut off traversal.
103 //
104 
P_RecursiveSound(sector_t * sec,int soundblocks,AActor * soundtarget)105 void P_RecursiveSound (sector_t *sec, int soundblocks, AActor *soundtarget)
106 {
107 	int 		i;
108 	line_t* 	check;
109 	sector_t*	other;
110 
111 	// wake up all monsters in this sector
112 	if (sec->validcount == validcount
113 		&& sec->soundtraversed <= soundblocks+1)
114 	{
115 		return; 		// already flooded
116 	}
117 
118 	sec->validcount = validcount;
119 	sec->soundtraversed = soundblocks+1;
120 	sec->soundtarget = soundtarget->ptr();
121 
122 	for (i=0 ;i<sec->linecount ; i++)
123 	{
124 		check = sec->lines[i];
125 		if (! (check->flags & ML_TWOSIDED) )
126 			continue;
127 
128 		if ( sides[ check->sidenum[0] ].sector == sec)
129 			other = sides[ check->sidenum[1] ] .sector;
130 		else
131 			other = sides[ check->sidenum[0] ].sector;
132 
133 		// [SL] 2012-02-08 - FIXME: Currently only checks for a line opening at
134 		// midpoint of a sloped linedef.  P_RecursiveSound() in ZDoom 1.23 causes
135 		// demo desyncs.
136 		P_LineOpening(check, (check->v1->x >> 1) + (check->v2->x >> 1),
137 							 (check->v1->y >> 1) + (check->v2->y >> 1));
138 
139 		if (openrange <= 0)
140 			continue;	// closed door
141 
142 		if (check->flags & ML_SOUNDBLOCK)
143 		{
144 			if (!soundblocks)
145 				P_RecursiveSound (other, 1, soundtarget);
146 		}
147 		else
148 			P_RecursiveSound (other, soundblocks, soundtarget);
149 	}
150 }
151 
152 
153 
154 //
155 // P_NoiseAlert
156 // If a monster yells at a player,
157 // it will alert other monsters to the player.
158 //
P_NoiseAlert(AActor * target,AActor * emmiter)159 void P_NoiseAlert (AActor *target, AActor *emmiter)
160 {
161 	if (target->player && (!multiplayer && (target->player->cheats & CF_NOTARGET)))
162 		return;
163 
164 	validcount++;
165 	P_RecursiveSound (emmiter->subsector->sector, 0, target);
166 }
167 
168 
169 
170 
171 //
172 // P_CheckMeleeRange
173 //
P_CheckMeleeRange(AActor * actor)174 BOOL P_CheckMeleeRange (AActor *actor)
175 {
176 	AActor *pl;
177 	fixed_t dist;
178 
179 	if (!actor->target)
180 		return false;
181 
182 	pl = actor->target;
183 	dist = P_AproxDistance (pl->x-actor->x, pl->y-actor->y);
184 
185 	if (dist >= MELEERANGE-20*FRACUNIT+pl->info->radius)
186 		return false;
187 
188 	// [RH] If moving toward goal, then we've reached it.
189 	if (actor->target == actor->goal)
190 		return true;
191 
192 	// [RH] Don't melee things too far above or below actor.
193 	if (co_realactorheight)
194 	{
195 		if (pl->z > actor->z + actor->height)
196 			return false;
197 		if (pl->z + pl->height < actor->z)
198 			return false;
199 	}
200 
201 	if (!P_CheckSight(actor, pl))
202 		return false;
203 
204 	return true;
205 }
206 
207 //
208 // P_CheckMissileRange
209 //
P_CheckMissileRange(AActor * actor)210 BOOL P_CheckMissileRange (AActor *actor)
211 {
212 	fixed_t dist;
213 
214 	if (!P_CheckSight (actor, actor->target))
215 		return false;
216 
217 	if (actor->flags & MF_JUSTHIT)
218 	{
219 		// the target just hit the enemy,
220 		// so fight back!
221 		actor->flags &= ~MF_JUSTHIT;
222 		return true;
223 	}
224 
225 	if (actor->reactiontime)
226 		return false;	// do not attack yet
227 
228 	// OPTIMIZE: get this from a global checksight
229 	dist = P_AproxDistance ( actor->x-actor->target->x,
230 							 actor->y-actor->target->y) - 64*FRACUNIT;
231 
232 	if (!actor->info->meleestate)
233 		dist -= 128*FRACUNIT;	// no melee attack, so fire more
234 
235 	dist >>= 16;
236 
237 	if (actor->type == MT_VILE)
238 	{
239 		if (dist > 14*64)
240 			return false;		// too far away
241 	}
242 
243 
244 	if (actor->type == MT_UNDEAD)
245 	{
246 		if (dist < 196)
247 			return false;		// close for fist attack
248 		dist >>= 1;
249 	}
250 
251 
252 	if (actor->type == MT_CYBORG
253 		|| actor->type == MT_SPIDER
254 		|| actor->type == MT_SKULL)
255 	{
256 		dist >>= 1;
257 	}
258 
259 	if (dist > 200)
260 		dist = 200;
261 
262 	if (actor->type == MT_CYBORG && dist > 160)
263 		dist = 160;
264 
265 	if (P_Random (actor) < dist)
266 		return false;
267 
268 	return true;
269 }
270 
271 
272 //
273 // P_Move
274 // Move in the current direction,
275 // returns false if the move is blocked.
276 //
277 extern	std::vector<line_t*> spechit;
278 
P_Move(AActor * actor)279 BOOL P_Move (AActor *actor)
280 {
281 	fixed_t tryx, tryy, deltax, deltay, origx, origy;
282 	BOOL try_ok;
283 	int good;
284 	int speed;
285 	int movefactor = ORIG_FRICTION_FACTOR;
286 	int friction = ORIG_FRICTION;
287 
288 	if (!actor->subsector)
289 		return false;
290 
291 	if (actor->flags2 & MF2_BLASTED)
292 		return true;
293 
294 	if (actor->movedir == DI_NODIR)
295 		return false;
296 
297 	// [RH] Instead of yanking non-floating monsters to the ground,
298 	// let gravity drop them down, unless they're moving down a step.
299 	if (co_zdoomphys && !(actor->flags & MF_NOGRAVITY) && actor->z > actor->floorz
300 		&& !(actor->flags2 & MF2_ONMOBJ))
301 	{
302 		if (actor->z > actor->floorz + 24*FRACUNIT)
303 		{
304 			return false;
305 		}
306 		else
307 		{
308 			actor->z = actor->floorz;
309 		}
310 	}
311 
312 	if ((unsigned)actor->movedir >= 8)
313 		I_Error ("Weird actor->movedir!");
314 
315 	speed = actor->info->speed;
316 
317 #if 0	// [RH] I'm not so sure this is such a good idea
318 	// killough 10/98: make monsters get affected by ice and sludge too:
319 	movefactor = P_GetMoveFactor (actor, &friction);
320 
321 	if (friction < ORIG_FRICTION &&		// sludge
322 		!(speed = ((ORIG_FRICTION_FACTOR - (ORIG_FRICTION_FACTOR-movefactor)/2)
323 		   * speed) / ORIG_FRICTION_FACTOR))
324 		speed = 1;	// always give the monster a little bit of speed
325 #endif
326 
327 	tryx = (origx = actor->x) + (deltax = speed * xspeed[actor->movedir]);
328 	tryy = (origy = actor->y) + (deltay = speed * yspeed[actor->movedir]);
329 
330 	// killough 3/15/98: don't jump over dropoffs:
331 	try_ok = P_TryMove (actor, tryx, tryy, false);
332 
333 	if (try_ok && friction > ORIG_FRICTION)
334 	{
335 		actor->x = origx;
336 		actor->y = origy;
337 		movefactor *= FRACUNIT / ORIG_FRICTION_FACTOR / 4;
338 		actor->momx += FixedMul (deltax, movefactor);
339 		actor->momy += FixedMul (deltay, movefactor);
340 	}
341 
342 	if (!try_ok)
343 	{
344 		// open any specials
345 		if (actor->flags & MF_FLOAT && floatok)
346 		{
347 			// must adjust height
348 			if (actor->z < tmfloorz)
349 				actor->z += FLOATSPEED;
350 			else
351 				actor->z -= FLOATSPEED;
352 
353 			actor->flags |= MF_INFLOAT;
354 			return true;
355 		}
356 
357 		if (spechit.empty())
358 			return false;
359 
360 		actor->movedir = DI_NODIR;
361 		good = false;
362 		while (!spechit.empty())
363 		{
364 			line_t *ld = spechit.back();
365 			spechit.pop_back();
366 
367 			// if the special is not a door
368 			// that can be opened,
369 			// return false
370 			if (P_UseSpecialLine (actor, ld, 0) ||
371 				P_PushSpecialLine (actor, ld, 0))
372 				good = true;
373 		}
374 		return good;
375 	}
376 	else
377 	{
378 		actor->flags &= ~MF_INFLOAT;
379 	}
380 
381 	if (!co_zdoomphys && !(actor->flags & MF_FLOAT))
382 		actor->z = actor->floorz;
383 
384 	return true;
385 }
386 
387 
388 //
389 // TryWalk
390 // Attempts to move actor on
391 // in its current (ob->moveangle) direction.
392 // If blocked by either a wall or an actor
393 // returns FALSE
394 // If move is either clear or blocked only by a door,
395 // returns TRUE and sets...
396 // If a door is in the way,
397 // an OpenDoor call is made to start it opening.
398 //
P_TryWalk(AActor * actor)399 BOOL P_TryWalk (AActor *actor)
400 {
401 	if (!P_Move (actor))
402 	{
403 		return false;
404 	}
405 
406 	actor->movecount = P_Random (actor) & 15;
407 	return true;
408 }
409 
410 
411 
412 
P_NewChaseDir(AActor * actor)413 void P_NewChaseDir (AActor *actor)
414 {
415 	fixed_t 	deltax;
416 	fixed_t 	deltay;
417 
418 	dirtype_t	d[3];
419 
420 	int			tdir;
421 	dirtype_t	olddir;
422 
423 	dirtype_t	turnaround;
424 
425 	if (!actor->target)
426 		I_Error ("P_NewChaseDir: called with no target");
427 
428 	olddir = (dirtype_t)actor->movedir;
429 	turnaround = opposite[olddir];
430 
431 	deltax = actor->target->x - actor->x;
432 	deltay = actor->target->y - actor->y;
433 
434 	if (deltax>10*FRACUNIT)
435 		d[1]= DI_EAST;
436 	else if (deltax<-10*FRACUNIT)
437 		d[1]= DI_WEST;
438 	else
439 		d[1]=DI_NODIR;
440 
441 	if (deltay<-10*FRACUNIT)
442 		d[2]= DI_SOUTH;
443 	else if (deltay>10*FRACUNIT)
444 		d[2] = DI_NORTH;
445 	else
446 		d[2] = DI_NODIR;
447 
448 	// try direct route
449 	if (d[1] != DI_NODIR && d[2] != DI_NODIR)
450 	{
451 		actor->movedir = diags[((deltay<0)<<1) + (deltax>0)];
452 		if (actor->movedir != turnaround && P_TryWalk(actor))
453 			return;
454 	}
455 
456 	// try other directions
457 	if (P_Random (actor) > 200 || abs(deltay) > abs(deltax))
458 	{
459 		tdir = d[1];
460 		d[1] = d[2];
461 		d[2] = (dirtype_t)tdir;
462 	}
463 
464 	if (d[1] == turnaround)
465 		d[1] = DI_NODIR;
466 	if (d[2] == turnaround)
467 		d[2] = DI_NODIR;
468 
469 	if (d[1] != DI_NODIR)
470 	{
471 		actor->movedir = d[1];
472 		if (P_TryWalk (actor))
473 		{
474 			// either moved forward or attacked
475 			return;
476 		}
477 	}
478 
479 	if (d[2] != DI_NODIR)
480 	{
481 		actor->movedir = d[2];
482 
483 		if (P_TryWalk (actor))
484 			return;
485 	}
486 
487 	// there is no direct path to the player,
488 	// so pick another direction.
489 	if (olddir != DI_NODIR)
490 	{
491 		actor->movedir = olddir;
492 
493 		if (P_TryWalk (actor))
494 			return;
495 	}
496 
497 	// randomly determine direction of search
498 	if (P_Random (actor) & 1)
499 	{
500 		for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++)
501 		{
502 			if (tdir != turnaround)
503 			{
504 				actor->movedir = tdir;
505 
506 				if ( P_TryWalk(actor) )
507 					return;
508 			}
509 		}
510 	}
511 	else
512 	{
513 		for (tdir = DI_SOUTHEAST; tdir != (DI_EAST-1); tdir--)
514 		{
515 			if (tdir != turnaround)
516 			{
517 				actor->movedir = tdir;
518 
519 				if ( P_TryWalk(actor) )
520 					return;
521 			}
522 		}
523 	}
524 
525 	if (turnaround != DI_NODIR)
526 	{
527 		actor->movedir =turnaround;
528 		if ( P_TryWalk(actor) )
529 			return;
530 	}
531 
532 	actor->movedir = DI_NODIR;	// can not move
533 }
534 
535 
536 
537 //
538 // P_LookForPlayers
539 // If allaround is false, only look 180 degrees in front.
540 // Returns true if a player is targeted.
541 //
542 // This function can trip you up if you're not careful.  The piece of
543 // functionality that is critical to vanilla compatibility is actor->lastlook.
544 // In vanilla, it was randomly set to a number between 0 and 3 on mobj
545 // creation, and this function is SUPPOSED to loop through all player numbers,
546 // set the mobj target and leave lastlook at the last-looked at player, in
547 // the hopes that not all monsters will immediately target the same player.
548 //
549 // However, the looping logic is _very_ tricky to get your head around, as
550 // the function was written with a fixed array of players in mind and makes
551 // some bad assumptions.  The ending sentinal (stop) can refer to a player
552 // index that doesn't exist.  The hard-limit counter (c) is post-incremented,
553 // so the loop will do at most two sight-checks, but lastlook is actually
554 // incremented one more time than that.
555 //
P_LookForPlayers(AActor * actor,bool allaround)556 bool P_LookForPlayers(AActor *actor, bool allaround)
557 {
558 	sector_t* sector = actor->subsector->sector;
559 
560 	if (!sector)
561 		return false;
562 
563 	// Construct our table of ingame players
564 	// [AM] TODO: Have the Players container handle this instead of having to
565 	//            check every single tic.
566 	static player_t* playeringame[MAXPLAYERS];
567 	memset(playeringame, 0, sizeof(player_t*) * MAXPLAYERS);
568 
569 	short maxid = 0;
570 	for (Players::iterator it = players.begin();it != players.end();++it)
571 	{
572 		if (it->ingame() && !(it->spectator))
573 		{
574 			playeringame[(it->id) - 1] = &*it;
575 			maxid = it->id;
576 		}
577 	}
578 
579 	// If there are no ingame players, we need to bug out now because
580 	// otherwise we're going to cause an infinite loop.
581 	if (maxid == 0)
582 		return false;
583 
584 	// denis - vanilla sync, original code always looped over size-4 array.
585 	if (maxid < MAXPLAYERS_VANILLA)
586 		maxid = MAXPLAYERS_VANILLA;
587 
588 	// denis - prevents calling P_CheckSight twice on the same player
589 	static bool sightcheckfailed[MAXPLAYERS];
590 	memset(sightcheckfailed, 0, sizeof(bool) * maxid);
591 
592 	int counter = 0;
593 
594 	// [AM] Vanilla braindamage, "fixing" will lead to vanilla desyncs
595 	unsigned int stop;
596 	if (actor->lastlook > 0)
597 		stop = actor->lastlook - 1;
598 	else
599 		stop = maxid - 1;
600 
601 	for ( ; ; actor->lastlook = (actor->lastlook + 1) % maxid)
602 	{
603 		if (playeringame[actor->lastlook] == NULL)
604 			continue;
605 
606 		if (++counter == 3 || actor->lastlook == stop)
607 		{
608 			// done looking
609 			// [RH] Use goal as a last resort
610 			if (!actor->target && actor->goal)
611 			{
612 				actor->target = actor->goal;
613 				return true;
614 			}
615 			return false;
616 		}
617 
618 		if (sightcheckfailed[actor->lastlook])
619 			continue;
620 
621 		player_t* player = playeringame[actor->lastlook];
622 
623 		if (player->cheats & CF_NOTARGET)
624 			continue; // no target
625 
626 		if (player->health <= 0)
627 			continue; // dead
628 
629 		if (!player->mo)
630 			continue; // out of game
631 
632 		if (!P_CheckSight(actor, player->mo))
633 		{
634 			sightcheckfailed[actor->lastlook] = true;
635 			continue; // out of sight
636 		}
637 
638 		if (!allaround)
639 		{
640 			angle_t an = P_PointToAngle(actor->x, actor->y,
641 			                            player->mo->x, player->mo->y) - actor->angle;
642 			if (an > ANG90 && an < ANG270)
643 			{
644 				fixed_t dist = P_AproxDistance(player->mo->x - actor->x,
645 				                               player->mo->y - actor->y);
646 				// if real close, react anyway
647 				if (dist > MELEERANGE)
648 					continue; // behind back
649 			}
650 		}
651 
652 		// [RH] Need to be sure the reactiontime is 0 if the monster is
653 		//		leaving its goal to go after a player.
654 		if (actor->goal && actor->target == actor->goal)
655 			actor->reactiontime = 0;
656 
657 		actor->target = player->mo->ptr();
658 		return true;
659 	}
660 
661 	return false;
662 }
663 
664 
665 //
666 // A_KeenDie
667 // DOOM II special, map 32.
668 // Uses special tag 666.
669 //
A_KeenDie(AActor * actor)670 void A_KeenDie (AActor *actor)
671 {
672 	A_Fall (actor);
673 
674 	// scan the remaining thinkers
675 	// to see if all Keens are dead
676 	AActor *other;
677 	TThinkerIterator<AActor> iterator;
678 
679 	while ( (other = iterator.Next ()) )
680 	{
681 		if (other != actor && other->type == actor->type && other->health > 0)
682 		{
683 			// other Keen not dead
684 			return;
685 		}
686 	}
687 
688 	EV_DoDoor (DDoor::doorOpen, NULL, NULL, 666, 2*FRACUNIT, 0, NoKey);
689 }
690 
691 
692 //
693 // ACTION ROUTINES
694 //
695 
696 //
697 // A_Look
698 // Stay in state until a player is sighted.
699 // [RH] Will also leave state to move to goal.
700 //
A_Look(AActor * actor)701 void A_Look (AActor *actor)
702 {
703 	AActor *targ;
704 	AActor *newgoal;
705 
706 	if(!actor->subsector)
707 		return;
708 
709 	// [RH] Set goal now if appropriate
710 	if (actor->special == Thing_SetGoal && actor->args[0] == 0)
711 	{
712 		actor->special = 0;
713 		newgoal = AActor::FindGoal (NULL, actor->args[1], MT_PATHNODE);
714 		actor->goal = newgoal->ptr();
715 		actor->reactiontime = actor->args[2] * TICRATE + level.time;
716 	}
717 
718 	actor->threshold = 0;		// any shot will wake up
719 	targ = actor->subsector->sector->soundtarget;
720 
721 	if (targ && targ->player && (targ->player->cheats & CF_NOTARGET))
722 		return;
723 
724 	// GhostlyDeath -- can't hear spectators
725 	if (targ && targ->player && targ->player->spectator)
726 		return;
727 
728 	if (targ && (targ->flags & MF_SHOOTABLE))
729 	{
730 		actor->target = targ->ptr();
731 
732 		if (actor->flags & MF_AMBUSH)
733 		{
734 			if (P_CheckSight(actor, actor->target))
735 				goto seeyou;
736 		}
737 		else
738 			goto seeyou;
739 	}
740 
741 
742 	if (!P_LookForPlayers (actor, false))
743 		return;
744 
745 	// go into chase state
746   seeyou:
747 
748   	// GhostlyDeath -- Can't see spectators
749   	if (actor->target->player && actor->target->player->spectator)
750   		return;
751 
752 	// [RH] Don't start chasing after a goal if it isn't time yet.
753 	if (actor->target == actor->goal)
754 	{
755 		if (actor->reactiontime > level.time)
756 			actor->target = AActor::AActorPtr();
757 	}
758 	else if (actor->info->seesound)
759 	{
760 		char sound[MAX_SNDNAME];
761 
762 		strcpy (sound, actor->info->seesound);
763 
764 		if (sound[strlen(sound)-1] == '1')
765 		{
766 			sound[strlen(sound)-1] = P_Random(actor)%3 + '1';
767 			if (S_FindSound (sound) == -1)
768 				sound[strlen(sound)-1] = '1';
769 		}
770 
771 		S_Sound (actor, CHAN_VOICE, sound, 1, ATTN_NORM);
772 	}
773 
774 	if (actor->target)
775 		P_SetMobjState (actor, actor->info->seestate, true);
776 }
777 #include "m_vectors.h"
778 
779 //
780 // A_Chase
781 // Actor has a melee attack,
782 // so it tries to close as fast as possible
783 //
A_Chase(AActor * actor)784 void A_Chase (AActor *actor)
785 {
786 	int delta;
787 	AActor *ngoal;
788 
789 	// GhostlyDeath -- Don't chase spectators at all
790 	if (actor->target && actor->target->player && actor->target->player->spectator)
791 		return;
792 
793 	if (actor->reactiontime)
794 		actor->reactiontime--;
795 
796 	// modify target threshold
797 	if (actor->threshold)
798 	{
799 		if (!actor->target || actor->target->health <= 0)
800 		{
801 			actor->threshold = 0;
802 		}
803 		else
804 			actor->threshold--;
805 	}
806 
807 	// turn towards movement direction if not there yet
808 	if (actor->movedir < 8)
809 	{
810 		actor->angle &= (angle_t)(7<<29);
811 		delta = actor->angle - (actor->movedir << 29);
812 
813 		if (delta > 0)
814 			actor->angle -= ANG90/2;
815 		else if (delta < 0)
816 			actor->angle += ANG90/2;
817 	}
818 
819 	// [RH] If the target is dead (and not a goal), stop chasing it.
820 	if (actor->target && actor->target != actor->goal && actor->target->health <= 0)
821 		actor->target = AActor::AActorPtr();
822 
823 	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
824 	{
825 		// look for a new target
826 		if (P_LookForPlayers (actor, true) && actor->target != actor->goal)
827 			return; 	// got a new target
828 
829 		if (!actor->target)
830 		{
831 			P_SetMobjState (actor, actor->info->spawnstate, true); // denis - todo - this sometimes leads to a stack overflow due to infinite recursion: A_Chase->SetMobjState->A_Look->SetMobjState
832 			return;
833 		}
834 	}
835 
836 	// do not attack twice in a row
837 	if (actor->flags & MF_JUSTATTACKED)
838 	{
839 		actor->flags &= ~MF_JUSTATTACKED;
840 		if ((sv_skill != sk_nightmare) && !sv_fastmonsters)
841 			P_NewChaseDir (actor);
842 		return;
843 	}
844 
845 	// [RH] Don't attack if just moving toward goal
846 	if (actor->target == actor->goal)
847 	{
848 		if (P_CheckMeleeRange (actor))
849 		{
850 			// reached the goal
851 			actor->reactiontime = actor->goal->args[1] * TICRATE + level.time;
852 			ngoal = AActor::FindGoal (NULL, actor->goal->args[0], MT_PATHNODE);
853 			if (ngoal)
854 				actor->goal = ngoal->ptr();
855 			else
856 				actor->goal = AActor::AActorPtr();
857 
858 			actor->target = AActor::AActorPtr();
859 			P_SetMobjState (actor, actor->info->spawnstate, true);
860 			return;
861 		}
862 		goto nomissile;
863 	}
864 
865 	// check for melee attack
866 	if (actor->info->meleestate && P_CheckMeleeRange (actor))
867 	{
868 		if (actor->info->attacksound)
869 			S_Sound (actor, CHAN_WEAPON, actor->info->attacksound, 1, ATTN_NORM);
870 
871 		P_SetMobjState (actor, actor->info->meleestate, true);
872 		return;
873 	}
874 
875 	// check for missile attack
876 	if (actor->info->missilestate)
877 	{
878 		if (sv_skill < sk_nightmare
879 			&& actor->movecount && !sv_fastmonsters)
880 		{
881 			goto nomissile;
882 		}
883 
884 		if (!P_CheckMissileRange (actor))
885 			goto nomissile;
886 
887 		P_SetMobjState (actor, actor->info->missilestate, true);
888 		actor->flags |= MF_JUSTATTACKED;
889 		return;
890 	}
891 
892 	// ?
893   nomissile:
894 	// possibly choose another target
895 	if (multiplayer
896 		&& !actor->threshold
897 		&& !P_CheckSight(actor, actor->target))
898 	{
899 		if (P_LookForPlayers(actor,true))
900 			return; 	// got a new target
901 	}
902 
903 	// chase towards player
904 	if (--actor->movecount < 0 || !P_Move (actor))
905 	{
906 		P_NewChaseDir (actor);
907 	}
908 
909 	// make active sound
910 	if (actor->info->activesound && P_Random (actor) < 3)
911 	{
912 		S_Sound (actor, CHAN_VOICE, actor->info->activesound, 1, ATTN_IDLE);
913 	}
914 }
915 
916 
917 //
918 // A_FaceTarget
919 //
A_FaceTarget(AActor * actor)920 void A_FaceTarget (AActor *actor)
921 {
922 	if (!actor->target)
923 		return;
924 
925 	actor->flags &= ~MF_AMBUSH;
926 
927 	actor->angle = P_PointToAngle (actor->x,
928 									actor->y,
929 									actor->target->x,
930 									actor->target->y);
931 
932 	if (actor->target->flags & MF_SHADOW)
933 		actor->angle += P_RandomDiff(actor)<<21;
934 }
935 
936 //
937 // [RH] A_MonsterRail
938 //
939 // New function to let monsters shoot a railgun
940 //
A_MonsterRail(AActor * actor)941 void A_MonsterRail (AActor *actor)
942 {
943 	if (!actor->target)
944 		return;
945 
946 	actor->flags &= ~MF_AMBUSH;
947 
948 	actor->angle = R_PointToAngle2 (actor->x,
949 									actor->y,
950 									actor->target->x,
951 									actor->target->y);
952 
953 	//actor->pitch = tantoangle[P_AimLineAttack (actor, actor->angle, MISSILERANGE) >> DBITS];
954 	actor->pitch = -(int)(tan ((float)P_AimLineAttack (actor, actor->angle, MISSILERANGE)/65536.0f)*ANG180/PI);
955 
956 	// Let the aim trail behind the player
957 	actor->angle = R_PointToAngle2 (actor->x,
958 									actor->y,
959 									actor->target->x - actor->target->momx * 3,
960 									actor->target->y - actor->target->momy * 3);
961 
962 	if (actor->target->flags & MF_SHADOW)
963     {
964 		int t = P_Random(actor);
965 		actor->angle += (t-P_Random(actor))<<21;
966     }
967 
968 	P_RailAttack (actor, actor->info->damage, 0);
969 }
970 
971 //
972 //
973 // A_PosAttack
974 //
A_PosAttack(AActor * actor)975 void A_PosAttack (AActor *actor)
976 {
977 	int angle;
978 	int damage;
979 	int slope;
980 
981 	if (!actor->target)
982 		return;
983 
984 	A_FaceTarget (actor);
985 	angle = actor->angle;
986 	slope = P_AimLineAttack (actor, angle, MISSILERANGE);
987 
988 	S_Sound (actor, CHAN_WEAPON, "grunt/attack", 1, ATTN_NORM);
989 	angle += P_RandomDiff (actor)<<20;
990 	damage = ((P_Random (actor)%5)+1)*3;
991 	P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
992 }
993 
A_SPosAttack(AActor * actor)994 void A_SPosAttack (AActor *actor)
995 {
996 	int i;
997 	int bangle;
998 	int slope;
999 
1000 	if (!actor->target)
1001 		return;
1002 
1003 	S_Sound (actor, CHAN_WEAPON, "shotguy/attack", 1, ATTN_NORM);
1004 	A_FaceTarget (actor);
1005 	bangle = actor->angle;
1006 	slope = P_AimLineAttack (actor, bangle, MISSILERANGE);
1007 
1008 	for (i=0 ; i<3 ; i++)
1009     {
1010 		int angle = bangle + (P_RandomDiff (actor)<<20);
1011 		int damage = ((P_Random (actor)%5)+1)*3;
1012 		P_LineAttack(actor, angle, MISSILERANGE, slope, damage);
1013     }
1014 }
1015 
A_CPosAttack(AActor * actor)1016 void A_CPosAttack (AActor *actor)
1017 {
1018 	int angle;
1019 	int bangle;
1020 	int damage;
1021 	int slope;
1022 
1023 	if (!actor->target)
1024 		return;
1025 
1026 	S_Sound (actor, CHAN_WEAPON, "chainguy/attack", 1, ATTN_NORM);
1027 	A_FaceTarget (actor);
1028 	bangle = actor->angle;
1029 	slope = P_AimLineAttack (actor, bangle, MISSILERANGE);
1030 
1031 	angle = bangle + (P_RandomDiff (actor)<<20);
1032 	damage = ((P_Random (actor)%5)+1)*3;
1033 	P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
1034 }
1035 
A_CPosRefire(AActor * actor)1036 void A_CPosRefire (AActor *actor)
1037 {
1038 	// keep firing unless target got out of sight
1039 	A_FaceTarget (actor);
1040 
1041 	if (P_Random (actor) < 40)
1042 		return;
1043 
1044 	if (!actor->target
1045 		|| actor->target->health <= 0
1046 		|| !P_CheckSight(actor, actor->target)
1047         )
1048 	{
1049 		P_SetMobjState (actor, actor->info->seestate, true);
1050 	}
1051 }
1052 
1053 
A_SpidRefire(AActor * actor)1054 void A_SpidRefire (AActor *actor)
1055 {
1056 	// keep firing unless target got out of sight
1057 	A_FaceTarget (actor);
1058 
1059 	if (P_Random (actor) < 10)
1060 		return;
1061 
1062 	if (!actor->target
1063 		|| actor->target->health <= 0
1064 		|| !P_CheckSight(actor, actor->target)
1065         )
1066 	{
1067 		P_SetMobjState (actor, actor->info->seestate, true);
1068 	}
1069 }
1070 
A_BspiAttack(AActor * actor)1071 void A_BspiAttack (AActor *actor)
1072 {
1073 	if (!actor->target)
1074 		return;
1075 
1076 	A_FaceTarget (actor);
1077 
1078 	// launch a missile
1079 	if(serverside)
1080 		P_SpawnMissile (actor, actor->target, MT_ARACHPLAZ);
1081 }
1082 
1083 
1084 //
1085 // A_TroopAttack
1086 //
A_TroopAttack(AActor * actor)1087 void A_TroopAttack (AActor *actor)
1088 {
1089 	if (!actor->target)
1090 		return;
1091 
1092 	A_FaceTarget (actor);
1093 	if (P_CheckMeleeRange (actor))
1094 	{
1095 		S_Sound (actor, CHAN_WEAPON, "imp/melee", 1, ATTN_NORM);
1096 		int damage = (P_Random (actor)%8+1)*3;
1097 		P_DamageMobj (actor->target, actor, actor, damage, MOD_HIT);
1098 		return;
1099 	}
1100 
1101 	// launch a missile
1102 	if(serverside)
1103 		P_SpawnMissile (actor, actor->target, MT_TROOPSHOT);
1104 }
1105 
1106 
A_SargAttack(AActor * actor)1107 void A_SargAttack (AActor *actor)
1108 {
1109 	if (!actor->target)
1110 		return;
1111 
1112 	A_FaceTarget (actor);
1113 	if (P_CheckMeleeRange (actor))
1114 	{
1115 		int damage = ((P_Random (actor)%10)+1)*4;
1116 		P_DamageMobj (actor->target, actor, actor, damage, MOD_HIT);
1117 	}
1118 }
1119 
A_HeadAttack(AActor * actor)1120 void A_HeadAttack (AActor *actor)
1121 {
1122 	if (!actor->target)
1123 		return;
1124 
1125 	A_FaceTarget (actor);
1126 	if (P_CheckMeleeRange (actor))
1127 	{
1128 		int damage = (P_Random (actor)%6+1)*10;
1129 		P_DamageMobj (actor->target, actor, actor, damage, MOD_HIT);
1130 		return;
1131 	}
1132 
1133 	// launch a missile
1134 	if(serverside)
1135 		P_SpawnMissile (actor, actor->target, MT_HEADSHOT);
1136 }
1137 
A_CyberAttack(AActor * actor)1138 void A_CyberAttack (AActor *actor)
1139 {
1140 	if (!actor->target)
1141 		return;
1142 
1143 	A_FaceTarget (actor);
1144 
1145 	if(serverside)
1146 	{
1147 		P_SpawnMissile (actor, actor->target, MT_ROCKET);
1148 	}
1149 }
1150 
1151 
A_BruisAttack(AActor * actor)1152 void A_BruisAttack (AActor *actor)
1153 {
1154 	if (!actor->target)
1155 		return;
1156 
1157 	if (P_CheckMeleeRange (actor))
1158 	{
1159 		int damage = (P_Random (actor)%8+1)*10;
1160 		S_Sound (actor, CHAN_WEAPON, "baron/melee", 1, ATTN_NORM);
1161 		P_DamageMobj (actor->target, actor, actor, damage, MOD_HIT);
1162 		return;
1163 	}
1164 
1165 	// launch a missile
1166 	if(serverside)
1167 		P_SpawnMissile (actor, actor->target, MT_BRUISERSHOT);
1168 }
1169 
1170 
1171 //
1172 // A_SkelMissile
1173 //
A_SkelMissile(AActor * actor)1174 void A_SkelMissile (AActor *actor)
1175 {
1176 	if (!actor->target)
1177 		return;
1178 
1179 	A_FaceTarget (actor);
1180 
1181 	if(serverside)
1182 	{
1183 		actor->z += 16*FRACUNIT;	// so missile spawns higher
1184 		AActor *mo = P_SpawnMissile (actor, actor->target, MT_TRACER);
1185 		actor->z -= 16*FRACUNIT;	// back to normal
1186 
1187 		mo->x += mo->momx;
1188 		mo->y += mo->momy;
1189 		mo->tracer = actor->target;
1190 	}
1191 }
1192 
1193 #define TRACEANGLE (0xc000000)
1194 
A_Tracer(AActor * actor)1195 void A_Tracer (AActor *actor)
1196 {
1197 	// killough 1/18/98: this is why some missiles do not have smoke
1198 	// and some do. Also, internal demos start at random gametics, thus
1199 	// the bug in which revenants cause internal demos to go out of sync.
1200 	//
1201 	// killough 3/6/98: fix revenant internal demo bug by subtracting
1202 	// levelstarttic from gametic:
1203 	//
1204 	// [RH] level.time is always 0-based, so nothing special to do here.
1205 
1206 	// denis - demogametic must be 0-based, but from start of entire demo,
1207 	// not just this level!
1208 	extern int demostartgametic;
1209 	int demogametic = gametic - demostartgametic;
1210 	if (demogametic & 3)
1211 		return;
1212 
1213 	// spawn a puff of smoke behind the rocket
1214 	if(serverside)
1215 	{
1216 		P_SpawnPuff(actor->x, actor->y, actor->z);
1217 
1218 		AActor* th = new AActor (actor->x - actor->momx,
1219 						 actor->y - actor->momy,
1220 						 actor->z, MT_SMOKE);
1221 
1222 		th->momz = FRACUNIT;
1223 		th->tics -= P_Random (th)&3;
1224 		if (th->tics < 1)
1225 			th->tics = 1;
1226 	}
1227 
1228 	// adjust direction
1229 	AActor *dest = actor->tracer;
1230 
1231 	if (!dest || dest->health <= 0)
1232 		return;
1233 
1234 	// change angle
1235 	angle_t exact = P_PointToAngle (actor->x,
1236 							 actor->y,
1237 							 dest->x,
1238 							 dest->y);
1239 
1240 	if (exact != actor->angle)
1241 	{
1242 		if (exact - actor->angle > ANG180)
1243 		{
1244 			actor->angle -= TRACEANGLE;
1245 			if (exact - actor->angle < ANG180)
1246 				actor->angle = exact;
1247 		}
1248 		else
1249 		{
1250 			actor->angle += TRACEANGLE;
1251 			if (exact - actor->angle > ANG180)
1252 				actor->angle = exact;
1253 		}
1254 	}
1255 
1256 	exact = actor->angle>>ANGLETOFINESHIFT;
1257 	actor->momx = FixedMul (actor->info->speed, finecosine[exact]);
1258 	actor->momy = FixedMul (actor->info->speed, finesine[exact]);
1259 
1260 	// change slope
1261 	fixed_t dist = P_AproxDistance (dest->x - actor->x,
1262 							dest->y - actor->y);
1263 
1264 	dist = dist / actor->info->speed;
1265 
1266 	if (dist < 1)
1267 		dist = 1;
1268 	fixed_t slope = (dest->z+40*FRACUNIT - actor->z) / dist;
1269 
1270 	if (slope < actor->momz)
1271 		actor->momz -= FRACUNIT/8;
1272 	else
1273 		actor->momz += FRACUNIT/8;
1274 }
1275 
1276 
A_SkelWhoosh(AActor * actor)1277 void A_SkelWhoosh (AActor *actor)
1278 {
1279 	if (!actor->target)
1280 		return;
1281 	A_FaceTarget (actor);
1282 	S_Sound (actor, CHAN_WEAPON, "skeleton/swing", 1, ATTN_NORM);
1283 }
1284 
A_SkelFist(AActor * actor)1285 void A_SkelFist (AActor *actor)
1286 {
1287 	if (!actor->target)
1288 		return;
1289 
1290 	A_FaceTarget (actor);
1291 
1292 	if (P_CheckMeleeRange (actor))
1293 	{
1294 		int damage = ((P_Random (actor)%10)+1)*6;
1295 		S_Sound (actor, CHAN_WEAPON, "skeleton/melee", 1, ATTN_NORM);
1296 		P_DamageMobj (actor->target, actor, actor, damage, MOD_HIT);
1297 	}
1298 }
1299 
1300 
1301 
1302 //
1303 // PIT_VileCheck
1304 // Detect a corpse that could be raised.
1305 //
1306 AActor* 		corpsehit;
1307 AActor* 		vileobj;
1308 fixed_t 		viletryx;
1309 fixed_t 		viletryy;
1310 
PIT_VileCheck(AActor * thing)1311 BOOL PIT_VileCheck (AActor *thing)
1312 {
1313 	int 	maxdist;
1314 	BOOL 	check;
1315 
1316 	if (!(thing->flags & MF_CORPSE) )
1317 		return true;	// not a monster
1318 
1319 	if (thing->tics != -1)
1320 		return true;	// not lying still yet
1321 
1322 	if (thing->info->raisestate == S_NULL)
1323 		return true;	// monster doesn't have a raise state
1324 
1325 	maxdist = thing->info->radius + mobjinfo[MT_VILE].radius;
1326 
1327 	if ( abs(thing->x - viletryx) > maxdist
1328 		 || abs(thing->y - viletryy) > maxdist )
1329 		return true;			// not actually touching
1330 
1331 	corpsehit = thing;
1332 	corpsehit->momx = corpsehit->momy = 0;
1333 	corpsehit->height <<= 2;
1334 	check = P_CheckPosition (corpsehit, corpsehit->x, corpsehit->y);
1335 	corpsehit->height >>= 2;
1336 
1337 	return !check;
1338 }
1339 
1340 
1341 
1342 //
1343 // A_VileChase
1344 // Check for ressurecting a body
1345 //
A_VileChase(AActor * actor)1346 void A_VileChase (AActor *actor)
1347 {
1348 	if(!serverside)
1349 	{
1350 		// Return to normal attack.
1351 		A_Chase (actor);
1352 		return;
1353 	}
1354 
1355 	int 				xl;
1356 	int 				xh;
1357 	int 				yl;
1358 	int 				yh;
1359 
1360 	int 				bx;
1361 	int 				by;
1362 
1363 	mobjinfo_t* 		info;
1364 	AActor::AActorPtr 	temp;
1365 
1366 	if (actor->movedir != DI_NODIR)
1367 	{
1368 		// check for corpses to raise
1369 		viletryx =
1370 			actor->x + actor->info->speed*xspeed[actor->movedir];
1371 		viletryy =
1372 			actor->y + actor->info->speed*yspeed[actor->movedir];
1373 
1374 		xl = (viletryx - bmaporgx - MAXRADIUS*2)>>MAPBLOCKSHIFT;
1375 		xh = (viletryx - bmaporgx + MAXRADIUS*2)>>MAPBLOCKSHIFT;
1376 		yl = (viletryy - bmaporgy - MAXRADIUS*2)>>MAPBLOCKSHIFT;
1377 		yh = (viletryy - bmaporgy + MAXRADIUS*2)>>MAPBLOCKSHIFT;
1378 
1379 		vileobj = actor;
1380 		for (bx=xl ; bx<=xh ; bx++)
1381 		{
1382 			for (by=yl ; by<=yh ; by++)
1383 			{
1384 				// Call PIT_VileCheck to check
1385 				// whether object is a corpse
1386 				// that canbe raised.
1387 				if (!P_BlockThingsIterator(bx,by,PIT_VileCheck))
1388 				{
1389 					// got one!
1390 					temp = actor->target;
1391 					actor->target = corpsehit->ptr();
1392 					A_FaceTarget (actor);
1393 					actor->target = temp;
1394 
1395 					P_SetMobjState (actor, S_VILE_HEAL1, true);
1396 					S_Sound (corpsehit, CHAN_BODY, "vile/raise", 1, ATTN_IDLE);
1397 					info = corpsehit->info;
1398 
1399 					P_SetMobjState (corpsehit,info->raisestate, true);
1400 
1401 					// [Nes] - Classic demo compatability: Ghost monster bug.
1402 					if ((demoplayback || demorecording) && democlassic) {
1403 						corpsehit->height <<= 2;
1404 					} else {
1405 						corpsehit->height = P_ThingInfoHeight(info);	// [RH] Use real mobj height
1406 						corpsehit->radius = info->radius;	// [RH] Use real radius
1407 					}
1408 
1409 					corpsehit->flags = info->flags;
1410 					corpsehit->health = info->spawnhealth;
1411 					corpsehit->target = AActor::AActorPtr();
1412 
1413 					return;
1414 				}
1415 			}
1416 		}
1417 	}
1418 
1419 	// Return to normal attack.
1420 	A_Chase (actor);
1421 }
1422 
1423 
1424 //
1425 // A_VileStart
1426 //
A_VileStart(AActor * actor)1427 void A_VileStart (AActor *actor)
1428 {
1429 	S_Sound (actor, CHAN_VOICE, "vile/start", 1, ATTN_NORM);
1430 }
1431 
1432 
1433 //
1434 // A_Fire
1435 // Keep fire in front of player unless out of sight
1436 //
1437 void A_Fire (AActor *actor);
1438 
A_StartFire(AActor * actor)1439 void A_StartFire (AActor *actor)
1440 {
1441 	S_Sound(actor, CHAN_BODY, "vile/firestrt", 1, ATTN_NORM);
1442 	A_Fire(actor);
1443 }
1444 
A_FireCrackle(AActor * actor)1445 void A_FireCrackle (AActor *actor)
1446 {
1447 	S_Sound(actor, CHAN_BODY, "vile/firecrkl", 1, ATTN_NORM);
1448 	A_Fire(actor);
1449 }
1450 
A_Fire(AActor * actor)1451 void A_Fire (AActor *actor)
1452 {
1453 	AActor* 	dest;
1454 	unsigned	an;
1455 
1456 	dest = actor->tracer;
1457 	if (!dest)
1458 		return;
1459 
1460 	// don't move it if the vile lost sight
1461 	if (!P_CheckSight(actor->target, dest))
1462 		return;
1463 
1464 	an = dest->angle >> ANGLETOFINESHIFT;
1465 
1466 	actor->SetOrigin (dest->x + FixedMul (24*FRACUNIT, finecosine[an]),
1467 					  dest->y + FixedMul (24*FRACUNIT, finesine[an]),
1468 					  dest->z);
1469 }
1470 
1471 
1472 
1473 //
1474 // A_VileTarget
1475 // Spawn the hellfire
1476 //
A_VileTarget(AActor * actor)1477 void A_VileTarget (AActor *actor)
1478 {
1479 	AActor *fog;
1480 
1481 	if (!actor->target)
1482 		return;
1483 
1484 	A_FaceTarget (actor);
1485 
1486 	fog = new AActor (actor->target->x,
1487 					  actor->target->x,
1488 					  actor->target->z, MT_FIRE);
1489 
1490 	actor->tracer = fog->ptr();
1491 	fog->target = actor->ptr();
1492 	fog->tracer = actor->target;
1493 	A_Fire (fog);
1494 }
1495 
1496 
1497 
1498 
1499 //
1500 // A_VileAttack
1501 //
A_VileAttack(AActor * actor)1502 void A_VileAttack (AActor *actor)
1503 {
1504 	AActor *fire;
1505 	int an;
1506 
1507 	if (!actor->target)
1508 		return;
1509 
1510 	A_FaceTarget (actor);
1511 
1512 	if (!P_CheckSight(actor, actor->target))
1513 		return;
1514 
1515 	S_Sound (actor, CHAN_WEAPON, "vile/stop", 1, ATTN_NORM);
1516 	P_DamageMobj (actor->target, actor, actor, 20, MOD_UNKNOWN);
1517 	actor->target->momz = 1000*FRACUNIT/actor->target->info->mass;
1518 
1519 	an = actor->angle >> ANGLETOFINESHIFT;
1520 
1521 	fire = actor->tracer;
1522 
1523 	if (!fire)
1524 		return;
1525 
1526 	// move the fire between the vile and the player
1527 	fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]);
1528 	fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]);
1529 	P_RadiusAttack (fire, actor, 70, 70, true, MOD_UNKNOWN);
1530 }
1531 
1532 
1533 
1534 
1535 //
1536 // Mancubus attack,
1537 // firing three missiles (bruisers) in three different directions?
1538 // Doesn't look like it.
1539 //
1540 #define FATSPREAD		(ANG90/8)
1541 
A_FatRaise(AActor * actor)1542 void A_FatRaise (AActor *actor)
1543 {
1544 	A_FaceTarget (actor);
1545 	S_Sound (actor, CHAN_WEAPON, "fatso/raiseguns", 1, ATTN_NORM);
1546 }
1547 
1548 
A_FatAttack1(AActor * actor)1549 void A_FatAttack1 (AActor *actor)
1550 {
1551 	if(!actor->target)
1552 		return;
1553 
1554 	A_FaceTarget (actor);
1555 
1556 	if(serverside)
1557 	{
1558 		// Change direction  to ...
1559 		actor->angle += FATSPREAD;
1560 		P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1561 
1562 		AActor *mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1563 		mo->angle += FATSPREAD;
1564 		int an = mo->angle >> ANGLETOFINESHIFT;
1565 		mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1566 		mo->momy = FixedMul (mo->info->speed, finesine[an]);
1567 	}
1568 }
1569 
A_FatAttack2(AActor * actor)1570 void A_FatAttack2 (AActor *actor)
1571 {
1572 	if(!actor->target)
1573 		return;
1574 
1575 	A_FaceTarget (actor);
1576 
1577 	if(serverside)
1578 	{
1579 		// Now here choose opposite deviation.
1580 		actor->angle -= FATSPREAD;
1581 		P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1582 
1583 		AActor *mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1584 		mo->angle -= FATSPREAD*2;
1585 		int an = mo->angle >> ANGLETOFINESHIFT;
1586 		mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1587 		mo->momy = FixedMul (mo->info->speed, finesine[an]);
1588 	}
1589 }
1590 
A_FatAttack3(AActor * actor)1591 void A_FatAttack3 (AActor *actor)
1592 {
1593 	if(!actor->target)
1594 		return;
1595 
1596 	A_FaceTarget (actor);
1597 
1598 	if(serverside)
1599 	{
1600 		AActor *mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1601 		mo->angle -= FATSPREAD/2;
1602 		int an = mo->angle >> ANGLETOFINESHIFT;
1603 		mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1604 		mo->momy = FixedMul (mo->info->speed, finesine[an]);
1605 
1606 		mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1607 		mo->angle += FATSPREAD/2;
1608 		an = mo->angle >> ANGLETOFINESHIFT;
1609 		mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1610 		mo->momy = FixedMul (mo->info->speed, finesine[an]);
1611 	}
1612 }
1613 
1614 
1615 //
1616 // killough 9/98: a mushroom explosion effect, sorta :)
1617 // Original idea: Linguica
1618 //
1619 
A_Mushroom(AActor * actor)1620 void A_Mushroom (AActor *actor)
1621 {
1622 	int i, j, n = actor->damage;
1623 
1624 	A_Explode (actor);	// First make normal explosion
1625 
1626 	if(serverside)
1627 	{
1628         // Now launch mushroom cloud
1629         for (i = -n; i <= n; i += 8)
1630         {
1631             for (j = -n; j <= n; j += 8)
1632             {
1633                 AActor target = *actor, *mo;
1634                 target.x += i << FRACBITS; // Aim in many directions from source
1635                 target.y += j << FRACBITS;
1636                 target.z += P_AproxDistance(i,j) << (FRACBITS+2); // Aim up fairly high
1637                 mo = P_SpawnMissile (actor, &target, MT_FATSHOT); // Launch fireball
1638                 if (mo != NULL)
1639                 {
1640                     mo->momx >>= 1;
1641                     mo->momy >>= 1;				  // Slow it down a bit
1642                     mo->momz >>= 1;
1643                     mo->flags &= ~MF_NOGRAVITY;   // Make debris fall under gravity
1644                 }
1645             }
1646         }
1647 	}
1648 }
1649 
1650 
1651 
1652 //
1653 // SkullAttack
1654 // Fly at the player like a missile.
1655 //
1656 #define SKULLSPEED (20*FRACUNIT)
1657 
A_SkullAttack(AActor * actor)1658 void A_SkullAttack (AActor *actor)
1659 {
1660 	AActor* 			dest;
1661 	angle_t 			an;
1662 	int 				dist;
1663 
1664 	if (!actor->target)
1665 		return;
1666 
1667 	dest = actor->target;
1668 	actor->flags |= MF_SKULLFLY;
1669 
1670 	S_Sound (actor, CHAN_VOICE, actor->info->attacksound, 1, ATTN_NORM);
1671 	A_FaceTarget (actor);
1672 	an = actor->angle >> ANGLETOFINESHIFT;
1673 	actor->momx = FixedMul (SKULLSPEED, finecosine[an]);
1674 	actor->momy = FixedMul (SKULLSPEED, finesine[an]);
1675 	dist = P_AproxDistance (dest->x - actor->x, dest->y - actor->y);
1676 	dist = dist / SKULLSPEED;
1677 
1678 	if (dist < 1)
1679 		dist = 1;
1680 	actor->momz = (dest->z+(dest->height>>1) - actor->z) / dist;
1681 }
1682 
1683 
1684 //
1685 // A_PainShootSkull
1686 // Spawn a lost soul and launch it at the target
1687 //
A_PainShootSkull(AActor * actor,angle_t angle)1688 void A_PainShootSkull (AActor *actor, angle_t angle)
1689 {
1690 	fixed_t 	x;
1691 	fixed_t 	y;
1692 	fixed_t 	z;
1693 
1694 	AActor* 	other;
1695 	angle_t 	an;
1696 	int 		prestep;
1697 	int 		count;
1698 
1699 	if(!serverside)
1700 		return;
1701 
1702 	// count total number of skull currently on the level
1703 	count = 0;
1704 
1705 	TThinkerIterator<AActor> iterator;
1706 
1707 	while ( (other = iterator.Next ()) )
1708 	{
1709 		if (other->type == MT_SKULL)
1710 			count++;
1711 	}
1712 
1713 	// if there are already 20 skulls on the level,
1714 	// don't spit another one
1715 	if (count > 20)
1716 		return;
1717 
1718 	// okay, there's room for another one
1719 	an = angle >> ANGLETOFINESHIFT;
1720 
1721 	prestep = 4*FRACUNIT + 3*(actor->info->radius + mobjinfo[MT_SKULL].radius)/2;
1722 
1723 	x = actor->x + FixedMul (prestep, finecosine[an]);
1724 	y = actor->y + FixedMul (prestep, finesine[an]);
1725 	z = actor->z + 8*FRACUNIT;
1726 
1727 	// Check whether the Lost Soul is being fired through a 1-sided	// phares
1728 	// wall or an impassible line, or a "monsters can't cross" line.//   |
1729 	// If it is, then we don't allow the spawn.						//   V
1730 	// denis - vanilla desync
1731 	/*
1732 	if (Check_Sides(actor,x,y))
1733 		return;*/
1734 
1735 	other = new AActor (x, y, z, MT_SKULL);
1736 
1737 	// Check to see if the new Lost Soul's z value is above the
1738 	// ceiling of its new sector, or below the floor. If so, kill it.
1739 	// denis - vanilla desync
1740 	/*
1741 	if ((other->z >
1742          (other->subsector->sector->ceilingheight - other->height)) ||
1743         (other->z < other->subsector->sector->floorheight))
1744 	{
1745 		// kill it immediately
1746 		P_DamageMobj (other, actor, actor, 10000, MOD_UNKNOWN);		//   ^
1747 		return;														//   |
1748 	}																// phares
1749 	 */
1750 	// Check for movements.
1751 	if (!P_TryMove(other, x, y, false))
1752 	{
1753 		// kill it immediately
1754 		P_DamageMobj (other, actor, actor, 10000, MOD_UNKNOWN);
1755 		return;
1756 	}
1757 
1758 	other->target = actor->target;
1759 	A_SkullAttack (other);
1760 }
1761 
1762 
1763 //
1764 // A_PainAttack
1765 // Spawn a lost soul and launch it at the target
1766 //
A_PainAttack(AActor * actor)1767 void A_PainAttack (AActor *actor)
1768 {
1769 	if (!actor->target)
1770 		return;
1771 
1772 	A_FaceTarget (actor);
1773 
1774 	if(!serverside)
1775 		return;
1776 
1777 	A_PainShootSkull (actor, actor->angle);
1778 }
1779 
A_PainDie(AActor * actor)1780 void A_PainDie (AActor *actor)
1781 {
1782 	A_Fall (actor);
1783 
1784 	if(!serverside)
1785 		return;
1786 
1787 	A_PainShootSkull (actor, actor->angle+ANG90);
1788 	A_PainShootSkull (actor, actor->angle+ANG180);
1789 	A_PainShootSkull (actor, actor->angle+ANG270);
1790 }
1791 
1792 
A_Scream(AActor * actor)1793 void A_Scream (AActor *actor)
1794 {
1795     char sound[MAX_SNDNAME];
1796 
1797 	if (actor->info->deathsound == NULL)
1798         return;
1799 
1800 
1801 	strcpy (sound, actor->info->deathsound);
1802 
1803     if (stricmp(sound, "grunt/death1") == 0 ||
1804         stricmp(sound, "shotguy/death1") == 0 ||
1805         stricmp(sound, "chainguy/death1") == 0)
1806     {
1807         sound[strlen(sound)-1] = P_Random(actor) % 3 + '1';
1808     }
1809 
1810     if (stricmp(sound, "imp/death1") == 0 ||
1811         stricmp(sound, "imp/death2") == 0)
1812     {
1813         sound[strlen(sound)-1] = P_Random(actor) % 2 + '1';
1814     }
1815 
1816 
1817     S_Sound (actor, CHAN_VOICE, sound, 1, ATTN_NORM);
1818 }
1819 
1820 
A_XScream(AActor * actor)1821 void A_XScream (AActor *actor)
1822 {
1823 	if (actor->player)
1824 		S_Sound (actor, CHAN_VOICE, "*gibbed", 1, ATTN_NORM);
1825 	else
1826 		S_Sound (actor, CHAN_VOICE, "misc/gibbed", 1, ATTN_NORM);
1827 }
1828 
A_Pain(AActor * actor)1829 void A_Pain (AActor *actor)
1830 {
1831 	if (actor->info->painsound)
1832 		S_Sound (actor, CHAN_VOICE, actor->info->painsound, 1, ATTN_NORM);
1833 }
1834 
1835 
1836 
A_Fall(AActor * actor)1837 void A_Fall (AActor *actor)
1838 {
1839 	// actor is on ground, it can be walked over
1840 	actor->flags &= ~MF_SOLID;
1841 
1842 	// So change this if corpse objects
1843 	// are meant to be obstacles.
1844 }
1845 
1846 
1847 // killough 11/98: kill an object
A_Die(AActor * actor)1848 void A_Die (AActor *actor)
1849 {
1850 	P_DamageMobj (actor, NULL, NULL, actor->health, MOD_UNKNOWN);
1851 }
1852 
1853 //
1854 // A_Detonate
1855 // killough 8/9/98: same as A_Explode, except that the damage is variable
1856 //
1857 
A_Detonate(AActor * mo)1858 void A_Detonate (AActor *mo)
1859 {
1860 	P_RadiusAttack (mo, mo->target, mo->damage, mo->damage, true, MOD_UNKNOWN);
1861 	if (mo->z <= mo->floorz + (mo->damage<<FRACBITS))
1862 	{
1863 		P_HitFloor (mo);
1864 	}
1865 }
1866 
1867 
1868 //
1869 // A_Explode
1870 //
A_Explode(AActor * thing)1871 void A_Explode (AActor *thing)
1872 {
1873 	// [RH] figure out means of death;
1874 	int mod;
1875 	int damage = 128;
1876 	int distance = 128;
1877 	bool hurtSource = true;
1878 
1879 	switch (thing->type) {
1880 		case MT_BARREL:
1881 			mod = MOD_BARREL;
1882 			break;
1883 		case MT_ROCKET:
1884 			mod = MOD_R_SPLASH;
1885 			break;
1886 		default:
1887 			mod = MOD_UNKNOWN;
1888 			break;
1889 	}
1890 
1891 	P_RadiusAttack (thing, thing->target, damage, distance, hurtSource, mod);
1892 }
1893 
1894 #define SPEED(a)		((a)*(FRACUNIT/8))
1895 
1896 //
1897 // A_BossDeath
1898 // Possibly trigger special effects if on a boss level
1899 //
A_BossDeath(AActor * actor)1900 void A_BossDeath (AActor *actor)
1901 {
1902 	// [RH] These all depend on the presence of level flags now
1903 	//		rather than being hard-coded to specific levels.
1904 
1905 	if ((level.flags & (LEVEL_MAP07SPECIAL|
1906 						LEVEL_BRUISERSPECIAL|
1907 						LEVEL_CYBORGSPECIAL|
1908 						LEVEL_SPIDERSPECIAL)) == 0)
1909 		return;
1910 
1911 	if (
1912 		((level.flags & LEVEL_MAP07SPECIAL) && (actor->type == MT_FATSO || actor->type == MT_BABY)) ||
1913 		((level.flags & LEVEL_BRUISERSPECIAL) && (actor->type == MT_BRUISER)) ||
1914 		((level.flags & LEVEL_CYBORGSPECIAL) && (actor->type == MT_CYBORG)) ||
1915 		((level.flags & LEVEL_SPIDERSPECIAL) && (actor->type == MT_SPIDER))
1916 	   )
1917 		;
1918 	else return;
1919 
1920 	// make sure there is a player alive for victory
1921 	Players::const_iterator it = players.begin();
1922 	for (;it != players.end();++it)
1923 	{
1924 		if (it->ingame() && it->health > 0)
1925 			break;
1926 	}
1927 
1928 	if (it == players.end())
1929 		return; // no one left alive, so do not end game
1930 
1931 	// scan the remaining thinkers to see if all bosses are dead
1932 	TThinkerIterator<AActor> iterator;
1933 	AActor *other;
1934 
1935 	while ( (other = iterator.Next ()) )
1936 	{
1937 		if (other != actor && other->type == actor->type && other->health > 0)
1938 		{
1939 			// other boss not dead
1940 			return;
1941 		}
1942 	}
1943 
1944 	// victory!
1945 	if (level.flags & LEVEL_MAP07SPECIAL)
1946 	{
1947 		if (actor->type == MT_FATSO)
1948 		{
1949 			EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, FRACUNIT, 0, 0, 0);
1950 			return;
1951 		}
1952 
1953 		if (actor->type == MT_BABY)
1954 		{
1955 			EV_DoFloor (DFloor::floorRaiseByTexture, NULL, 667, FRACUNIT, 0, 0, 0);
1956 			return;
1957 		}
1958 	}
1959 	else
1960 	{
1961 		switch (level.flags & LEVEL_SPECACTIONSMASK)
1962 		{
1963 			case LEVEL_SPECLOWERFLOOR:
1964 				EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, FRACUNIT, 0, 0, 0);
1965 				return;
1966 
1967 			case LEVEL_SPECOPENDOOR:
1968 				EV_DoDoor (DDoor::doorOpen, NULL, NULL, 666, SPEED(64), 0, NoKey);
1969 				return;
1970 		}
1971 	}
1972 
1973 	// [RH] If noexit, then don't end the level.
1974 	if (sv_gametype != GM_COOP && !sv_allowexit)
1975 		return;
1976 
1977 	G_ExitLevel (0, 1);
1978 }
1979 
1980 
A_Hoof(AActor * mo)1981 void A_Hoof (AActor *mo)
1982 {
1983 	S_Sound (mo, CHAN_BODY, "cyber/hoof", 1, ATTN_IDLE);
1984 	A_Chase (mo);
1985 }
1986 
A_Metal(AActor * mo)1987 void A_Metal (AActor *mo)
1988 {
1989 	S_Sound (mo, CHAN_BODY, "spider/walk", 1, ATTN_IDLE);
1990 	A_Chase (mo);
1991 }
1992 
A_BabyMetal(AActor * mo)1993 void A_BabyMetal (AActor *mo)
1994 {
1995 	S_Sound (mo, CHAN_BODY, "baby/walk", 1, ATTN_IDLE);
1996 	A_Chase (mo);
1997 }
1998 
1999 // killough 2/7/98: Remove limit on icon landings:
2000 AActor **braintargets;
2001 int    numbraintargets_alloc;
2002 int    numbraintargets;
2003 
2004 struct brain_s brain;   // killough 3/26/98: global state of boss brain
2005 
2006 // killough 3/26/98: initialize icon landings at level startup,
2007 // rather than at boss wakeup, to prevent savegame-related crashes
2008 
P_SpawnBrainTargets(void)2009 void P_SpawnBrainTargets (void)	// killough 3/26/98: renamed old function
2010 {
2011 	AActor *other;
2012 	TThinkerIterator<AActor> iterator;
2013 
2014 	// find all the target spots
2015 	numbraintargets = 0;
2016 	brain.targeton = 0;
2017 	brain.easy = 0;				// killough 3/26/98: always init easy to 0
2018 
2019 	while ( (other = iterator.Next ()) )
2020 	{
2021 		if (other->type == MT_BOSSTARGET)
2022 		{	// killough 2/7/98: remove limit on icon landings:
2023 			if (numbraintargets >= numbraintargets_alloc)
2024 			{
2025 				braintargets = (AActor **)Realloc (braintargets,
2026 					(numbraintargets_alloc = numbraintargets_alloc ?
2027 					 numbraintargets_alloc*2 : 32) *sizeof *braintargets);
2028 			}
2029 			braintargets[numbraintargets++] = other;
2030 		}
2031 	}
2032 }
2033 
A_BrainAwake(AActor * mo)2034 void A_BrainAwake (AActor *mo)
2035 {
2036 	// killough 3/26/98: only generates sound now
2037 	S_Sound (mo, CHAN_VOICE, "brain/sight", 1, ATTN_NONE);
2038 }
2039 
2040 
A_BrainPain(AActor * mo)2041 void A_BrainPain (AActor *mo)
2042 {
2043 	S_Sound (mo, CHAN_VOICE, "brain/pain", 1, ATTN_NONE);
2044 }
2045 
2046 
A_BrainScream(AActor * mo)2047 void A_BrainScream (AActor *mo)
2048 {
2049 	if(!clientside)
2050 		return;
2051 
2052 	int 		x;
2053 	int 		y;
2054 	int 		z;
2055 	AActor* 	th;
2056 
2057 	for (x=mo->x - 196*FRACUNIT ; x< mo->x + 320*FRACUNIT ; x+= FRACUNIT*8)
2058 	{
2059 		y = mo->y - 320*FRACUNIT;
2060 		z = 128 + (P_Random (mo) << (FRACBITS + 1));
2061 		th = new AActor (x,y,z, MT_ROCKET);
2062 		th->momz = P_Random (mo) << 9;
2063 
2064 		P_SetMobjState (th, S_BRAINEXPLODE1, true);
2065 
2066 		th->tics -= P_Random (mo) & 7;
2067 		if (th->tics < 1)
2068 			th->tics = 1;
2069 	}
2070 
2071 	S_Sound (mo, CHAN_VOICE, "brain/death", 1, ATTN_NONE);
2072 }
2073 
2074 
2075 
A_BrainExplode(AActor * mo)2076 void A_BrainExplode (AActor *mo)
2077 {
2078 	if(!clientside)
2079 		return;
2080 
2081 	int x = mo->x + P_RandomDiff (mo)*2048;
2082 	int y = mo->y;
2083 	int z = 128 + P_Random (mo)*2*FRACUNIT;
2084 	AActor *th = new AActor (x,y,z, MT_ROCKET);
2085 	th->momz = P_Random (mo) << 9;
2086 
2087 	P_SetMobjState (th, S_BRAINEXPLODE1, true);
2088 
2089 	th->tics -= P_Random (mo) & 7;
2090 	if (th->tics < 1)
2091 		th->tics = 1;
2092 }
2093 
2094 
A_BrainDie(AActor * mo)2095 void A_BrainDie (AActor *mo)
2096 {
2097 	// [RH] If noexit, then don't end the level.
2098 	if (sv_gametype != GM_COOP && !sv_allowexit)
2099 		return;
2100 
2101 	G_ExitLevel (0, 1);
2102 }
2103 
A_BrainSpit(AActor * mo)2104 void A_BrainSpit (AActor *mo)
2105 {
2106 	if(!serverside)
2107 		return;
2108 
2109 	AActor* 	targ;
2110 	AActor* 	newmobj;
2111 
2112 	// [RH] Do nothing if there are no brain targets.
2113 	if (numbraintargets == 0)
2114 		return;
2115 
2116 	brain.easy ^= 1;		// killough 3/26/98: use brain struct
2117 	if (sv_skill <= sk_easy && (!brain.easy))
2118 		return;
2119 
2120 	// shoot a cube at current target
2121 	targ = braintargets[brain.targeton++];	// killough 3/26/98:
2122 	brain.targeton %= numbraintargets;		// Use brain struct for targets
2123 
2124 	// spawn brain missile
2125 	newmobj = P_SpawnMissile (mo, targ, MT_SPAWNSHOT);
2126 
2127 	if(newmobj)
2128 	{
2129 		newmobj->target = targ->ptr();
2130 		newmobj->reactiontime =
2131 			((targ->y - mo->y)/newmobj->momy) / newmobj->state->tics;
2132 	}
2133 
2134 	S_Sound (mo, CHAN_WEAPON, "brain/spit", 1, ATTN_NONE);
2135 }
2136 
2137 
2138 
2139 void A_SpawnFly (AActor *mo);
2140 
2141 // travelling cube sound
A_SpawnSound(AActor * mo)2142 void A_SpawnSound (AActor *mo)
2143 {
2144 	S_Sound (mo, CHAN_BODY, "brain/cube", 1, ATTN_IDLE);
2145 	A_SpawnFly(mo);
2146 }
2147 
A_SpawnFly(AActor * mo)2148 void A_SpawnFly (AActor *mo)
2149 {
2150 	AActor* 	newmobj;
2151 	AActor* 	fog;
2152 	AActor* 	targ;
2153 	int 		r;
2154 	mobjtype_t	type;
2155 
2156 	if (--mo->reactiontime)
2157 		return; // still flying
2158 
2159 	if(!serverside)
2160 		return;
2161 
2162 	targ = mo->target;
2163 
2164 	// First spawn teleport fog.
2165 	fog = new AActor (targ->x, targ->y, targ->z, MT_SPAWNFIRE);
2166 	S_Sound (fog, CHAN_BODY, "misc/teleport", 1, ATTN_NORM);
2167 
2168 	// Randomly select monster to spawn.
2169 	r = P_Random (mo);
2170 
2171 	// Probability distribution (kind of :),
2172 	// decreasing likelihood.
2173 	if ( r<50 )
2174 		type = MT_TROOP;
2175 	else if (r<90)
2176 		type = MT_SERGEANT;
2177 	else if (r<120)
2178 		type = MT_SHADOWS;
2179 	else if (r<130)
2180 		type = MT_PAIN;
2181 	else if (r<160)
2182 		type = MT_HEAD;
2183 	else if (r<162)
2184 		type = MT_VILE;
2185 	else if (r<172)
2186 		type = MT_UNDEAD;
2187 	else if (r<192)
2188 		type = MT_BABY;
2189 	else if (r<222)
2190 		type = MT_FATSO;
2191 	else if (r<246)
2192 		type = MT_KNIGHT;
2193 	else
2194 		type = MT_BRUISER;
2195 
2196 	newmobj = new AActor (targ->x, targ->y, targ->z, type);
2197 	if (P_LookForPlayers (newmobj, true))
2198 		P_SetMobjState (newmobj, newmobj->info->seestate, true);
2199 
2200 	// telefrag anything in this spot
2201 	P_TeleportMove (newmobj, newmobj->x, newmobj->y, newmobj->z, true);
2202 
2203 	// remove self (i.e., cube).
2204 	mo->Destroy ();
2205 
2206 	// [SL] 2011-06-19 - Emulate vanilla doom bug where monsters spawned after
2207 	// the start of the level (eg, spawned from a cube) are respawned at map
2208 	// location (0, 0).
2209 	memset(&newmobj->spawnpoint, 0, sizeof(newmobj->spawnpoint));
2210 }
2211 
2212 
2213 
A_PlayerScream(AActor * mo)2214 void A_PlayerScream (AActor *mo)
2215 {
2216 	if (!mo)
2217 		return;
2218 
2219 	char nametemp[128];
2220 	const char *sound;
2221 
2222 	// [SL] 2011-06-15 - Spectators shouldn't make any noises
2223 	if (mo->player && mo->player->spectator)
2224 		return;
2225 
2226 	// [Fly] added for csDoom
2227 	if (mo->health < -mo->info->spawnhealth)
2228 	{
2229 		A_XScream (mo);
2230 		return;
2231 	}
2232 
2233 	if (!(gameinfo.flags & GI_NOCRAZYDEATH) && (mo->health < -50))
2234 	{
2235 		// IF THE PLAYER DIES LESS THAN -50% WITHOUT GIBBING
2236 		sound = "*xdeath1";
2237 	} else {
2238 		// [RH] More variety in death sounds
2239 		//sprintf (nametemp, "*death%d", (M_Random ()&3) + 1); // denis - do not use randomness source!
2240 		sprintf (nametemp, "*death1");
2241 		sound = nametemp;
2242 	}
2243 
2244 	S_Sound (mo, CHAN_VOICE, sound, 1, ATTN_NORM);
2245 }
2246 
A_Gibify(AActor * mo)2247 void A_Gibify(AActor *mo) // denis - squash thing
2248 {
2249 	mo->flags &= ~MF_SOLID;
2250 	mo->height = 0;
2251 	mo->radius = 0;
2252 }
2253 
2254 VERSION_CONTROL (p_enemy_cpp, "$Id: p_enemy.cpp 4542 2014-02-09 17:39:42Z dr_sean $")
2255 
2256