1 /* Emacs style mode select   -*- C++ -*-
2  *-----------------------------------------------------------------------------
3  *
4  *
5  *  PrBoom: a Doom port merged with LxDoom and LSDLDoom
6  *  based on BOOM, a modified and improved DOOM engine
7  *  Copyright (C) 1999 by
8  *  id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9  *  Copyright (C) 1999-2000,2002 by
10  *  Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11  *  Copyright 2005, 2006 by
12  *  Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License
16  *  as published by the Free Software Foundation; either version 2
17  *  of the License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27  *  02111-1307, USA.
28  *
29  * DESCRIPTION:
30  *      Enemy thinking, AI.
31  *      Action Pointer Functions
32  *      that are associated with states/frames.
33  *
34  *-----------------------------------------------------------------------------*/
35 
36 #include "doomstat.h"
37 #include "m_random.h"
38 #include "r_main.h"
39 #include "p_maputl.h"
40 #include "p_map.h"
41 #include "p_setup.h"
42 #include "p_spec.h"
43 #include "s_sound.h"
44 #include "sounds.h"
45 #include "p_inter.h"
46 #include "g_game.h"
47 #include "p_enemy.h"
48 #include "p_tick.h"
49 #include "m_bbox.h"
50 #include "lprintf.h"
51 
52 static mobj_t *current_actor;
53 
54 typedef enum
55 {
56   DI_EAST,
57   DI_NORTHEAST,
58   DI_NORTH,
59   DI_NORTHWEST,
60   DI_WEST,
61   DI_SOUTHWEST,
62   DI_SOUTH,
63   DI_SOUTHEAST,
64   DI_NODIR,
65   NUMDIRS
66 } dirtype_t;
67 
68 static void P_NewChaseDir(mobj_t *actor);
69 void P_ZBumpCheck(mobj_t *);                                        // phares
70 
71 extern void retro_set_rumble_damage(int damage, float duration);
72 
73 //
74 // ENEMY THINKING
75 // Enemies are allways spawned
76 // with targetplayer = -1, threshold = 0
77 // Most monsters are spawned unaware of all players,
78 // but some can be made preaware
79 //
80 
81 //
82 // Called by P_NoiseAlert.
83 // Recursively traverse adjacent sectors,
84 // sound blocking lines cut off traversal.
85 //
86 // killough 5/5/98: reformatted, cleaned up
87 
P_RecursiveSound(sector_t * sec,int soundblocks,mobj_t * soundtarget)88 static void P_RecursiveSound(sector_t *sec, int soundblocks,
89            mobj_t *soundtarget)
90 {
91   int i;
92 
93   // wake up all monsters in this sector
94   if (sec->validcount == validcount && sec->soundtraversed <= soundblocks+1)
95     return;             // already flooded
96 
97   sec->validcount = validcount;
98   sec->soundtraversed = soundblocks+1;
99   P_SetTarget(&sec->soundtarget, soundtarget);
100 
101   for (i=0; i<sec->linecount; i++)
102     {
103       sector_t *other;
104       line_t *check = sec->lines[i];
105 
106       if (!(check->flags & ML_TWOSIDED))
107         continue;
108 
109       P_LineOpening(check);
110 
111       if (openrange <= 0)
112         continue;       // closed door
113 
114       other=sides[check->sidenum[sides[check->sidenum[0]].sector==sec]].sector;
115 
116       if (!(check->flags & ML_SOUNDBLOCK))
117         P_RecursiveSound(other, soundblocks, soundtarget);
118       else
119         if (!soundblocks)
120           P_RecursiveSound(other, 1, soundtarget);
121     }
122 }
123 
124 //
125 // P_NoiseAlert
126 // If a monster yells at a player,
127 // it will alert other monsters to the player.
128 //
P_NoiseAlert(mobj_t * target,mobj_t * emitter)129 void P_NoiseAlert(mobj_t *target, mobj_t *emitter)
130 {
131   validcount++;
132   P_RecursiveSound(emitter->subsector->sector, 0, target);
133 }
134 
135 //
136 // P_CheckMeleeRange
137 //
138 
P_CheckMeleeRange(mobj_t * actor)139 static dbool   P_CheckMeleeRange(mobj_t *actor)
140 {
141   mobj_t *pl = actor->target;
142 
143   return  // killough 7/18/98: friendly monsters don't attack other friends
144     pl && !(actor->flags & pl->flags & MF_FRIEND) &&
145     (P_AproxDistance(pl->x-actor->x, pl->y-actor->y) <
146      MELEERANGE - 20*FRACUNIT + pl->info->radius) &&
147     P_CheckSight(actor, actor->target);
148 }
149 
150 //
151 // P_HitFriend()
152 //
153 // killough 12/98
154 // This function tries to prevent shooting at friends
155 
P_HitFriend(mobj_t * actor)156 static dbool   P_HitFriend(mobj_t *actor)
157 {
158   return actor->flags & MF_FRIEND && actor->target &&
159     (P_AimLineAttack(actor,
160          R_PointToAngle2(actor->x, actor->y,
161              actor->target->x, actor->target->y),
162          P_AproxDistance(actor->x-actor->target->x,
163              actor->y-actor->target->y), 0),
164      linetarget) && linetarget != actor->target &&
165     !((linetarget->flags ^ actor->flags) & MF_FRIEND);
166 }
167 
168 //
169 // P_CheckMissileRange
170 //
P_CheckMissileRange(mobj_t * actor)171 static dbool   P_CheckMissileRange(mobj_t *actor)
172 {
173   fixed_t dist;
174 
175   if (!P_CheckSight(actor, actor->target))
176     return FALSE;
177 
178   if (actor->flags & MF_JUSTHIT)
179     {      // the target just hit the enemy, so fight back!
180       actor->flags &= ~MF_JUSTHIT;
181 
182       /* killough 7/18/98: no friendly fire at corpses
183        * killough 11/98: prevent too much infighting among friends
184        * cph - yikes, talk about fitting everything on one line... */
185 
186       return
187   !(actor->flags & MF_FRIEND) ||
188   (actor->target->health > 0 &&
189    (!(actor->target->flags & MF_FRIEND) ||
190     (actor->target->player ?
191      monster_infighting || P_Random(pr_defect) >128 :
192      !(actor->target->flags & MF_JUSTHIT) && P_Random(pr_defect) >128)));
193     }
194 
195   /* killough 7/18/98: friendly monsters don't attack other friendly
196    * monsters or players (except when attacked, and then only once)
197    */
198   if (actor->flags & actor->target->flags & MF_FRIEND)
199     return FALSE;
200 
201   if (actor->reactiontime)
202     return FALSE;       // do not attack yet
203 
204   // OPTIMIZE: get this from a global checksight
205   dist = P_AproxDistance ( actor->x-actor->target->x,
206                            actor->y-actor->target->y) - 64*FRACUNIT;
207 
208   if (!actor->info->meleestate)
209     dist -= 128*FRACUNIT;       // no melee attack, so fire more
210 
211   dist >>= FRACBITS;
212 
213   if (actor->info->maxattackrange > 0 && dist > actor->info->maxattackrange)
214     return FALSE;     // too far away
215 
216   if (actor->info->meleestate != S_NULL && dist < actor->info->meleethreshold)
217     return false;     // close enough for melee attack, don't fire
218 
219   // higher attack probability like Cyberdemon, Spiderboss, Revenant and Lost Soul
220   if (actor->flags & MF_MISSILEMORE)
221     dist >>= 1;
222 
223   // Some mobs (eg. Cyberdemon) have a minimum attack chance
224   if (dist > actor->info->minmissilechance)
225     dist = actor->info->minmissilechance;
226 
227   if (P_Random(pr_missrange) < dist)
228     return FALSE;
229 
230   if (P_HitFriend(actor))
231     return FALSE;
232 
233   return TRUE;
234 }
235 
236 /*
237  * P_IsOnLift
238  *
239  * killough 9/9/98:
240  *
241  * Returns TRUE if the object is on a lift. Used for AI,
242  * since it may indicate the need for crowded conditions,
243  * or that a monster should stay on the lift for a while
244  * while it goes up or down.
245  */
246 
P_IsOnLift(const mobj_t * actor)247 static dbool   P_IsOnLift(const mobj_t *actor)
248 {
249   const sector_t *sec = actor->subsector->sector;
250   line_t line;
251   int l;
252 
253   memset(&line, 0, sizeof(line));
254 
255   // Short-circuit: it's on a lift which is active.
256   if (sec->floordata && ((thinker_t *) sec->floordata)->function==T_PlatRaise)
257     return TRUE;
258 
259   // Check to see if it's in a sector which can be activated as a lift.
260   if ((line.tag = sec->tag))
261     for (l = -1; (l = P_FindLineFromLineTag(&line, l)) >= 0;)
262       switch (lines[l].special)
263   {
264   case  10: case  14: case  15: case  20: case  21: case  22:
265   case  47: case  53: case  62: case  66: case  67: case  68:
266   case  87: case  88: case  95: case 120: case 121: case 122:
267   case 123: case 143: case 162: case 163: case 181: case 182:
268   case 144: case 148: case 149: case 211: case 227: case 228:
269   case 231: case 232: case 235: case 236:
270     return TRUE;
271   }
272 
273   return FALSE;
274 }
275 
276 /*
277  * P_IsUnderDamage
278  *
279  * killough 9/9/98:
280  *
281  * Returns nonzero if the object is under damage based on
282  * their current position. Returns 1 if the damage is moderate,
283  * -1 if it is serious. Used for AI.
284  */
285 
P_IsUnderDamage(mobj_t * actor)286 static int P_IsUnderDamage(mobj_t *actor)
287 {
288   const struct msecnode_s *seclist;
289   const ceiling_t *cl;             // Crushing ceiling
290   int dir = 0;
291   for (seclist=actor->touching_sectorlist; seclist; seclist=seclist->m_tnext)
292     if ((cl = seclist->m_sector->ceilingdata) &&
293   cl->thinker.function == T_MoveCeiling)
294       dir |= cl->direction;
295   return dir;
296 }
297 
298 //
299 // P_Move
300 // Move in the current direction,
301 // returns FALSE if the move is blocked.
302 //
303 
304 static fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
305 static fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
306 
307 // 1/11/98 killough: Limit removed on special lines crossed
308 extern  line_t **spechit;          // New code -- killough
309 extern  int    numspechit;
310 
P_Move(mobj_t * actor,dbool dropoff)311 static dbool   P_Move(mobj_t *actor, dbool   dropoff) /* killough 9/12/98 */
312 {
313   fixed_t tryx, tryy, deltax, deltay, origx, origy;
314   dbool   try_ok;
315   int movefactor = ORIG_FRICTION_FACTOR;    // killough 10/98
316   int friction = ORIG_FRICTION;
317   int speed;
318 
319   if (actor->movedir == DI_NODIR)
320     return FALSE;
321 
322   // killough 10/98: make monsters get affected by ice and sludge too:
323 
324   if (monster_friction)
325     movefactor = P_GetMoveFactor(actor, &friction);
326 
327   speed = actor->info->speed;
328 
329   if (friction < ORIG_FRICTION &&     // sludge
330       !(speed = ((ORIG_FRICTION_FACTOR - (ORIG_FRICTION_FACTOR-movefactor)/2)
331      * speed) / ORIG_FRICTION_FACTOR))
332     speed = 1;      // always give the monster a little bit of speed
333 
334   tryx = (origx = actor->x) + (deltax = speed * xspeed[actor->movedir]);
335   tryy = (origy = actor->y) + (deltay = speed * yspeed[actor->movedir]);
336 
337   try_ok = P_TryMove(actor, tryx, tryy, dropoff);
338 
339   // killough 10/98:
340   // Let normal momentum carry them, instead of steptoeing them across ice.
341 
342   if (try_ok && friction > ORIG_FRICTION)
343     {
344       actor->x = origx;
345       actor->y = origy;
346       movefactor *= FRACUNIT / ORIG_FRICTION_FACTOR / 4;
347       actor->momx += FixedMul(deltax, movefactor);
348       actor->momy += FixedMul(deltay, movefactor);
349     }
350 
351   if (!try_ok)
352     {      // open any specials
353       int good;
354 
355       if (actor->flags & MF_FLOAT && floatok)
356         {
357           if (actor->z < tmfloorz)          // must adjust height
358             actor->z += FLOATSPEED;
359           else
360             actor->z -= FLOATSPEED;
361 
362           actor->flags |= MF_INFLOAT;
363 
364     return TRUE;
365         }
366 
367       if (!numspechit)
368         return FALSE;
369 
370       actor->movedir = DI_NODIR;
371 
372       /* if the special is not a door that can be opened, return FALSE
373        *
374        * killough 8/9/98: this is what caused monsters to get stuck in
375        * doortracks, because it thought that the monster freed itself
376        * by opening a door, even if it was moving towards the doortrack,
377        * and not the door itself.
378        *
379        * killough 9/9/98: If a line blocking the monster is activated,
380        * return TRUE 90% of the time. If a line blocking the monster is
381        * not activated, but some other line is, return FALSE 90% of the
382        * time. A bit of randomness is needed to ensure it's free from
383        * lockups, but for most cases, it returns the correct result.
384        *
385        * Do NOT simply return FALSE 1/4th of the time (causes monsters to
386        * back out when they shouldn't, and creates secondary stickiness).
387        */
388 
389       for (good = FALSE; numspechit--; )
390         if (P_UseSpecialLine(actor, spechit[numspechit], 0))
391     good |= spechit[numspechit] == blockline ? 1 : 2;
392 
393       /* cph - compatibility maze here
394        * Boom v2.01 and orig. Doom return "good"
395        * Boom v2.02 and LxDoom return good && (P_Random(pr_trywalk)&3)
396        * MBF plays even more games
397        */
398       if (!good || comp[comp_doorstuck]) return good;
399       if (!mbf_features)
400   return (P_Random(pr_trywalk)&3); /* jff 8/13/98 */
401       else /* finally, MBF code */
402   return ((P_Random(pr_opendoor) >= 230) ^ (good & 1));
403     }
404   else
405     actor->flags &= ~MF_INFLOAT;
406 
407   /* killough 11/98: fall more slowly, under gravity, if felldown==TRUE */
408   if (!(actor->flags & MF_FLOAT) &&
409       (!felldown || !mbf_features))
410     actor->z = actor->floorz;
411 
412   return TRUE;
413 }
414 
415 /*
416  * P_SmartMove
417  *
418  * killough 9/12/98: Same as P_Move, except smarter
419  */
420 
P_SmartMove(mobj_t * actor)421 static dbool   P_SmartMove(mobj_t *actor)
422 {
423   mobj_t *target = actor->target;
424   int on_lift, dropoff = FALSE, under_damage;
425 
426   /* killough 9/12/98: Stay on a lift if target is on one */
427   on_lift = !comp[comp_staylift]
428     && target && target->health > 0
429     && target->subsector->sector->tag==actor->subsector->sector->tag &&
430     P_IsOnLift(actor);
431 
432   under_damage = monster_avoid_hazards && P_IsUnderDamage(actor);
433 
434   // killough 10/98: allow dogs to drop off of taller ledges sometimes.
435   // dropoff==1 means always allow it, dropoff==2 means only up to 128 high,
436   // and only if the target is immediately on the other side of the line.
437 
438   if (!P_Move(actor, dropoff))
439     return FALSE;
440 
441   // killough 9/9/98: avoid crushing ceilings or other damaging areas
442   if (
443       (on_lift && P_Random(pr_stayonlift) < 230 &&      // Stay on lift
444        !P_IsOnLift(actor))
445       ||
446       (monster_avoid_hazards && !under_damage &&  // Get away from damage
447        (under_damage = P_IsUnderDamage(actor)) &&
448        (under_damage < 0 || P_Random(pr_avoidcrush) < 200))
449       )
450     actor->movedir = DI_NODIR;    // avoid the area (most of the time anyway)
451 
452   return TRUE;
453 }
454 
455 //
456 // TryWalk
457 // Attempts to move actor on
458 // in its current (ob->moveangle) direction.
459 // If blocked by either a wall or an actor
460 // returns FALSE
461 // If move is either clear or blocked only by a door,
462 // returns TRUE and sets...
463 // If a door is in the way,
464 // an OpenDoor call is made to start it opening.
465 //
466 
P_TryWalk(mobj_t * actor)467 static dbool   P_TryWalk(mobj_t *actor)
468 {
469   if (!P_SmartMove(actor))
470     return FALSE;
471   actor->movecount = P_Random(pr_trywalk)&15;
472   return TRUE;
473 }
474 
475 //
476 // P_DoNewChaseDir
477 //
478 // killough 9/8/98:
479 //
480 // Most of P_NewChaseDir(), except for what
481 // determines the new direction to take
482 //
483 
P_DoNewChaseDir(mobj_t * actor,fixed_t deltax,fixed_t deltay)484 static void P_DoNewChaseDir(mobj_t *actor, fixed_t deltax, fixed_t deltay)
485 {
486   dirtype_t xdir, ydir, tdir;
487   dirtype_t olddir = actor->movedir;
488   dirtype_t turnaround = olddir;
489 
490   if (turnaround != DI_NODIR)         // find reverse direction
491     turnaround ^= 4;
492 
493   xdir =
494     deltax >  10*FRACUNIT ? DI_EAST :
495     deltax < -10*FRACUNIT ? DI_WEST : DI_NODIR;
496 
497   ydir =
498     deltay < -10*FRACUNIT ? DI_SOUTH :
499     deltay >  10*FRACUNIT ? DI_NORTH : DI_NODIR;
500 
501   // try direct route
502   if (xdir != DI_NODIR && ydir != DI_NODIR && turnaround !=
503       (actor->movedir = deltay < 0 ? deltax > 0 ? DI_SOUTHEAST : DI_SOUTHWEST :
504        deltax > 0 ? DI_NORTHEAST : DI_NORTHWEST) && P_TryWalk(actor))
505     return;
506 
507   // try other directions
508   if (P_Random(pr_newchase) > 200 || D_abs(deltay)>D_abs(deltax))
509     tdir = xdir, xdir = ydir, ydir = tdir;
510 
511   if ((xdir == turnaround ? xdir = DI_NODIR : xdir) != DI_NODIR &&
512       (actor->movedir = xdir, P_TryWalk(actor)))
513     return;         // either moved forward or attacked
514 
515   if ((ydir == turnaround ? ydir = DI_NODIR : ydir) != DI_NODIR &&
516       (actor->movedir = ydir, P_TryWalk(actor)))
517     return;
518 
519   // there is no direct path to the player, so pick another direction.
520   if (olddir != DI_NODIR && (actor->movedir = olddir, P_TryWalk(actor)))
521     return;
522 
523   // randomly determine direction of search
524   if (P_Random(pr_newchasedir) & 1)
525     {
526       for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++)
527         if (tdir != turnaround && (actor->movedir = tdir, P_TryWalk(actor)))
528     return;
529     }
530   else
531     for (tdir = DI_SOUTHEAST; tdir != (dirtype_t)(DI_EAST-1); tdir--)
532       if (tdir != turnaround && (actor->movedir = tdir, P_TryWalk(actor)))
533   return;
534 
535   if ((actor->movedir = turnaround) != DI_NODIR && !P_TryWalk(actor))
536     actor->movedir = DI_NODIR;
537 }
538 
539 //
540 // killough 11/98:
541 //
542 // Monsters try to move away from tall dropoffs.
543 //
544 // In Doom, they were never allowed to hang over dropoffs,
545 // and would remain stuck if involuntarily forced over one.
546 // This logic, combined with p_map.c (P_TryMove), allows
547 // monsters to free themselves without making them tend to
548 // hang over dropoffs.
549 
550 static fixed_t dropoff_deltax, dropoff_deltay, floorz;
551 
PIT_AvoidDropoff(line_t * line)552 static dbool   PIT_AvoidDropoff(line_t *line)
553 {
554   if (line->backsector                          && // Ignore one-sided linedefs
555       tmbbox[BOXRIGHT]  > line->bbox[BOXLEFT]   &&
556       tmbbox[BOXLEFT]   < line->bbox[BOXRIGHT]  &&
557       tmbbox[BOXTOP]    > line->bbox[BOXBOTTOM] && // Linedef must be contacted
558       tmbbox[BOXBOTTOM] < line->bbox[BOXTOP]    &&
559       P_BoxOnLineSide(tmbbox, line) == -1)
560     {
561       fixed_t front = line->frontsector->floorheight;
562       fixed_t back  = line->backsector->floorheight;
563       angle_t angle;
564 
565       // The monster must contact one of the two floors,
566       // and the other must be a tall dropoff (more than 24).
567 
568       if (back == floorz && front < floorz - STEPSIZE)
569   angle = R_PointToAngle2(0,0,line->dx,line->dy);   // front side dropoff
570       else
571   if (front == floorz && back < floorz - STEPSIZE)
572     angle = R_PointToAngle2(line->dx,line->dy,0,0); // back side dropoff
573   else
574     return TRUE;
575 
576       // Move away from dropoff at a standard speed.
577       // Multiple contacted linedefs are cumulative (e.g. hanging over corner)
578       dropoff_deltax -= finesine[angle >> ANGLETOFINESHIFT]*32;
579       dropoff_deltay += finecosine[angle >> ANGLETOFINESHIFT]*32;
580     }
581   return TRUE;
582 }
583 
584 //
585 // Driver for above
586 //
587 
P_AvoidDropoff(mobj_t * actor)588 static fixed_t P_AvoidDropoff(mobj_t *actor)
589 {
590   int yh=((tmbbox[BOXTOP]   = actor->y+actor->radius)-bmaporgy)>>MAPBLOCKSHIFT;
591   int yl=((tmbbox[BOXBOTTOM]= actor->y-actor->radius)-bmaporgy)>>MAPBLOCKSHIFT;
592   int xh=((tmbbox[BOXRIGHT] = actor->x+actor->radius)-bmaporgx)>>MAPBLOCKSHIFT;
593   int xl=((tmbbox[BOXLEFT]  = actor->x-actor->radius)-bmaporgx)>>MAPBLOCKSHIFT;
594   int bx, by;
595 
596   floorz = actor->z;            // remember floor height
597 
598   dropoff_deltax = dropoff_deltay = 0;
599 
600   // check lines
601 
602   validcount++;
603   for (bx=xl ; bx<=xh ; bx++)
604     for (by=yl ; by<=yh ; by++)
605       P_BlockLinesIterator(bx, by, PIT_AvoidDropoff);  // all contacted lines
606 
607   return dropoff_deltax | dropoff_deltay;   // Non-zero if movement prescribed
608 }
609 
610 //
611 // P_NewChaseDir
612 //
613 // killough 9/8/98: Split into two functions
614 //
615 
P_NewChaseDir(mobj_t * actor)616 static void P_NewChaseDir(mobj_t *actor)
617 {
618   mobj_t *target = actor->target;
619   fixed_t deltax = target->x - actor->x;
620   fixed_t deltay = target->y - actor->y;
621 
622   // killough 8/8/98: sometimes move away from target, keeping distance
623   //
624   // 1) Stay a certain distance away from a friend, to avoid being in their way
625   // 2) Take advantage over an enemy without missiles, by keeping distance
626 
627   actor->strafecount = 0;
628 
629   if (mbf_features) {
630     if (actor->floorz - actor->dropoffz > STEPSIZE &&
631   actor->z <= actor->floorz &&
632   !(actor->flags & (MF_DROPOFF|MF_FLOAT)) &&
633   !comp[comp_dropoff] &&
634   P_AvoidDropoff(actor)) /* Move away from dropoff */
635       {
636   P_DoNewChaseDir(actor, dropoff_deltax, dropoff_deltay);
637 
638   // If moving away from dropoff, set movecount to 1 so that
639   // small steps are taken to get monster away from dropoff.
640 
641   actor->movecount = 1;
642   return;
643       }
644     else
645       {
646   fixed_t dist = P_AproxDistance(deltax, deltay);
647 
648   // Move away from friends when too close, except
649   // in certain situations (e.g. a crowded lift)
650 
651   if (actor->flags & target->flags & MF_FRIEND &&
652       distfriend << FRACBITS > dist &&
653       !P_IsOnLift(target) && !P_IsUnderDamage(actor))
654   {
655     deltax = -deltax, deltay = -deltay;
656   } else
657     if (target->health > 0 && (actor->flags ^ target->flags) & MF_FRIEND)
658       {   // Live enemy target
659         if (monster_backing &&
660       actor->info->missilestate && actor->type != MT_SKULL &&
661       ((!target->info->missilestate && dist < MELEERANGE*2) ||
662        (target->player && dist < MELEERANGE*3 &&
663         (target->player->readyweapon == WP_FIST ||
664          target->player->readyweapon == WP_CHAINSAW))))
665     {       // Back away from melee attacker
666       actor->strafecount = P_Random(pr_enemystrafe) & 15;
667       deltax = -deltax, deltay = -deltay;
668     }
669       }
670       }
671   }
672 
673   P_DoNewChaseDir(actor, deltax, deltay);
674 
675   // If strafing, set movecount to strafecount so that old Doom
676   // logic still works the same, except in the strafing part
677 
678   if (actor->strafecount)
679     actor->movecount = actor->strafecount;
680 }
681 
682 //
683 // P_IsVisible
684 //
685 // killough 9/9/98: whether a target is visible to a monster
686 //
687 
P_IsVisible(mobj_t * actor,mobj_t * mo,dbool allaround)688 static dbool   P_IsVisible(mobj_t *actor, mobj_t *mo, dbool   allaround)
689 {
690   if (!allaround)
691     {
692       angle_t an = R_PointToAngle2(actor->x, actor->y,
693            mo->x, mo->y) - actor->angle;
694       if (an > ANG90 && an < ANG270 &&
695     P_AproxDistance(mo->x-actor->x, mo->y-actor->y) > MELEERANGE)
696   return FALSE;
697     }
698   return P_CheckSight(actor, mo);
699 }
700 
701 //
702 // PIT_FindTarget
703 //
704 // killough 9/5/98
705 //
706 // Finds monster targets for other monsters
707 //
708 
709 static int current_allaround;
710 
PIT_FindTarget(mobj_t * mo)711 static dbool   PIT_FindTarget(mobj_t *mo)
712 {
713   mobj_t *actor = current_actor;
714 
715   if (!((mo->flags ^ actor->flags) & MF_FRIEND &&        // Invalid target
716   mo->health > 0 && (mo->flags & MF_ISMONSTER)))
717     return TRUE;
718 
719   // If the monster is already engaged in a one-on-one attack
720   // with a healthy friend, don't attack around 60% the time
721   {
722     const mobj_t *targ = mo->target;
723     if (targ && targ->target == mo &&
724   P_Random(pr_skiptarget) > 100 &&
725   (targ->flags ^ mo->flags) & MF_FRIEND &&
726   targ->health*2 >= targ->info->spawnhealth)
727       return TRUE;
728   }
729 
730   if (!P_IsVisible(actor, mo, current_allaround))
731     return TRUE;
732 
733   P_SetTarget(&actor->lastenemy, actor->target);  // Remember previous target
734   P_SetTarget(&actor->target, mo);                // Found target
735 
736   // Move the selected monster to the end of its associated
737   // list, so that it gets searched last next time.
738 
739   {
740     thinker_t *cap = &thinkerclasscap[mo->flags & MF_FRIEND ?
741              th_friends : th_enemies];
742     (mo->thinker.cprev->cnext = mo->thinker.cnext)->cprev = mo->thinker.cprev;
743     (mo->thinker.cprev = cap->cprev)->cnext = &mo->thinker;
744     (mo->thinker.cnext = cap)->cprev = &mo->thinker;
745   }
746 
747   return FALSE;
748 }
749 
750 //
751 // P_LookForPlayers
752 // If allaround is FALSE, only look 180 degrees in front.
753 // Returns TRUE if a player is targeted.
754 //
755 
P_LookForPlayers(mobj_t * actor,dbool allaround)756 static dbool   P_LookForPlayers(mobj_t *actor, dbool   allaround)
757 {
758   player_t *player;
759   int stop, stopc, c;
760 
761   if (actor->flags & MF_FRIEND)
762     {  // killough 9/9/98: friendly monsters go about players differently
763       int anyone;
764 
765 #if 0
766       if (!allaround) // If you want friendly monsters not to awaken unprovoked
767   return FALSE;
768 #endif
769 
770       // Go back to a player, no matter whether it's visible or not
771       for (anyone=0; anyone<=1; anyone++)
772   for (c=0; c<MAXPLAYERS; c++)
773     if (playeringame[c] && players[c].playerstate==PST_LIVE &&
774         (anyone || P_IsVisible(actor, players[c].mo, allaround)))
775       {
776         P_SetTarget(&actor->target, players[c].mo);
777 
778         // killough 12/98:
779         // get out of refiring loop, to avoid hitting player accidentally
780 
781         if (actor->info->missilestate)
782     {
783       P_SetMobjState(actor, actor->info->seestate);
784       actor->flags &= ~MF_JUSTHIT;
785     }
786 
787         return TRUE;
788       }
789 
790       return FALSE;
791     }
792 
793   // Change mask of 3 to (MAXPLAYERS-1) -- killough 2/15/98:
794   stop = (actor->lastlook-1)&(MAXPLAYERS-1);
795 
796   c = 0;
797 
798   stopc = !mbf_features &&
799     !demo_compatibility && monsters_remember ?
800     MAXPLAYERS : 2;       // killough 9/9/98
801 
802   for (;; actor->lastlook = (actor->lastlook+1)&(MAXPLAYERS-1))
803     {
804       if (!playeringame[actor->lastlook])
805   continue;
806 
807       // killough 2/15/98, 9/9/98:
808       if (c++ == stopc || actor->lastlook == stop)  // done looking
809       {
810         // e6y
811         // Fixed Boom incompatibilities. The following code was missed.
812         // There are no more desyncs on Donce's demos on horror.wad
813 
814         // Use last known enemy if no players sighted -- killough 2/15/98:
815         if (!mbf_features && !demo_compatibility && monsters_remember)
816         {
817           if (actor->lastenemy && actor->lastenemy->health > 0)
818           {
819             actor->target = actor->lastenemy;
820             actor->lastenemy = NULL;
821             return TRUE;
822           }
823         }
824 
825         return FALSE;
826       }
827 
828       player = &players[actor->lastlook];
829 
830       if (player->health <= 0)
831   continue;               // dead
832 
833       if (!P_IsVisible(actor, player->mo, allaround))
834   continue;
835 
836       P_SetTarget(&actor->target, player->mo);
837 
838       /* killough 9/9/98: give monsters a threshold towards getting players
839        * (we don't want it to be too easy for a player with dogs :)
840        */
841       if (!comp[comp_pursuit])
842   actor->threshold = 60;
843 
844       return TRUE;
845     }
846 }
847 
848 //
849 // Friendly monsters, by Lee Killough 7/18/98
850 //
851 // Friendly monsters go after other monsters first, but
852 // also return to owner if they cannot find any targets.
853 // A marine's best friend :)  killough 7/18/98, 9/98
854 //
855 
P_LookForMonsters(mobj_t * actor,dbool allaround)856 static dbool   P_LookForMonsters(mobj_t *actor, dbool   allaround)
857 {
858   thinker_t *cap, *th;
859 
860   if (demo_compatibility)
861     return FALSE;
862 
863   if (actor->lastenemy && actor->lastenemy->health > 0 && monsters_remember &&
864       !(actor->lastenemy->flags & actor->flags & MF_FRIEND)) // not friends
865     {
866       P_SetTarget(&actor->target, actor->lastenemy);
867       P_SetTarget(&actor->lastenemy, NULL);
868       return TRUE;
869     }
870 
871   /* Old demos do not support monster-seeking bots */
872   if (!mbf_features)
873     return FALSE;
874 
875   // Search the threaded list corresponding to this object's potential targets
876   cap = &thinkerclasscap[actor->flags & MF_FRIEND ? th_enemies : th_friends];
877 
878   // Search for new enemy
879 
880   if (cap->cnext != cap)        // Empty list? bail out early
881     {
882       int x = (actor->x - bmaporgx)>>MAPBLOCKSHIFT;
883       int y = (actor->y - bmaporgy)>>MAPBLOCKSHIFT;
884       int d;
885 
886       current_actor = actor;
887       current_allaround = allaround;
888 
889       // Search first in the immediate vicinity.
890 
891       if (!P_BlockThingsIterator(x, y, PIT_FindTarget))
892   return TRUE;
893 
894       for (d=1; d<5; d++)
895   {
896     int i = 1 - d;
897     do
898       if (!P_BlockThingsIterator(x+i, y-d, PIT_FindTarget) ||
899     !P_BlockThingsIterator(x+i, y+d, PIT_FindTarget))
900         return TRUE;
901     while (++i < d);
902     do
903       if (!P_BlockThingsIterator(x-d, y+i, PIT_FindTarget) ||
904     !P_BlockThingsIterator(x+d, y+i, PIT_FindTarget))
905         return TRUE;
906     while (--i + d >= 0);
907   }
908 
909       {   // Random number of monsters, to prevent patterns from forming
910   int n = (P_Random(pr_friends) & 31) + 15;
911 
912   for (th = cap->cnext; th != cap; th = th->cnext)
913     if (--n < 0)
914       {
915         // Only a subset of the monsters were searched. Move all of
916         // the ones which were searched so far, to the end of the list.
917 
918         (cap->cnext->cprev = cap->cprev)->cnext = cap->cnext;
919         (cap->cprev = th->cprev)->cnext = cap;
920         (th->cprev = cap)->cnext = th;
921         break;
922      }
923     else
924       if (!PIT_FindTarget((mobj_t *) th))   // If target sighted
925         return TRUE;
926       }
927     }
928 
929   return FALSE;  // No monster found
930 }
931 
932 //
933 // P_LookForTargets
934 //
935 // killough 9/5/98: look for targets to go after, depending on kind of monster
936 //
937 
P_LookForTargets(mobj_t * actor,int allaround)938 static dbool   P_LookForTargets(mobj_t *actor, int allaround)
939 {
940   return actor->flags & MF_FRIEND ?
941     P_LookForMonsters(actor, allaround) || P_LookForPlayers (actor, allaround):
942     P_LookForPlayers (actor, allaround) || P_LookForMonsters(actor, allaround);
943 }
944 
945 //
946 // P_HelpFriend
947 //
948 // killough 9/8/98: Help friends in danger of dying
949 //
950 
P_HelpFriend(mobj_t * actor)951 static dbool   P_HelpFriend(mobj_t *actor)
952 {
953   thinker_t *cap, *th;
954 
955   // If less than 33% health, self-preservation rules
956   if (actor->health*3 < actor->info->spawnhealth)
957     return FALSE;
958 
959   current_actor = actor;
960   current_allaround = TRUE;
961 
962   // Possibly help a friend under 50% health
963   cap = &thinkerclasscap[actor->flags & MF_FRIEND ? th_friends : th_enemies];
964 
965   for (th = cap->cnext; th != cap; th = th->cnext)
966     if (((mobj_t *) th)->health*2 >= ((mobj_t *) th)->info->spawnhealth)
967       {
968   if (P_Random(pr_helpfriend) < 180)
969     break;
970       }
971     else
972       if (((mobj_t *) th)->flags & MF_JUSTHIT &&
973     ((mobj_t *) th)->target &&
974     ((mobj_t *) th)->target != actor->target &&
975     !PIT_FindTarget(((mobj_t *) th)->target))
976   {
977     // Ignore any attacking monsters, while searching for friend
978     actor->threshold = BASETHRESHOLD;
979     return TRUE;
980   }
981 
982   return FALSE;
983 }
984 
985 //
986 // A_KeenDie
987 // DOOM II special, map 32.
988 // Uses special tag 666.
989 //
A_KeenDie(mobj_t * mo)990 void A_KeenDie(mobj_t* mo)
991 {
992   thinker_t *th;
993   line_t   junk;
994 
995   A_Fall(mo);
996 
997   // scan the remaining thinkers to see if all Keens are dead
998 
999   for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
1000     if (th->function == P_MobjThinker)
1001       {
1002         mobj_t *mo2 = (mobj_t *) th;
1003         if (mo2 != mo && mo2->type == mo->type && mo2->health > 0)
1004           return;                           // other Keen not dead
1005       }
1006 
1007   junk.tag = 666;
1008   EV_DoDoor(&junk,open);
1009 }
1010 
1011 
1012 //
1013 // ACTION ROUTINES
1014 //
1015 
1016 //
1017 // A_Look
1018 // Stay in state until a player is sighted.
1019 //
1020 
A_Look(mobj_t * actor)1021 void A_Look(mobj_t *actor)
1022 {
1023   mobj_t *targ = actor->subsector->sector->soundtarget;
1024   actor->threshold = 0; // any shot will wake up
1025 
1026   /* killough 7/18/98:
1027    * Friendly monsters go after other monsters first, but
1028    * also return to player, without attacking them, if they
1029    * cannot find any targets. A marine's best friend :)
1030    */
1031   actor->pursuecount = 0;
1032 
1033   if (!(actor->flags & MF_FRIEND && P_LookForTargets(actor, FALSE)) &&
1034       !((targ = actor->subsector->sector->soundtarget) &&
1035   targ->flags & MF_SHOOTABLE &&
1036   (P_SetTarget(&actor->target, targ),
1037    !(actor->flags & MF_AMBUSH) || P_CheckSight(actor, targ))) &&
1038       (actor->flags & MF_FRIEND || !P_LookForTargets(actor, FALSE)))
1039     return;
1040 
1041   // go into chase state
1042 
1043   if (actor->info->seesound)
1044     {
1045       int sound;
1046       switch (actor->info->seesound)
1047         {
1048         case sfx_posit1:
1049         case sfx_posit2:
1050         case sfx_posit3:
1051           sound = sfx_posit1+P_Random(pr_see)%3;
1052           break;
1053 
1054         case sfx_bgsit1:
1055         case sfx_bgsit2:
1056           sound = sfx_bgsit1+P_Random(pr_see)%2;
1057           break;
1058 
1059         default:
1060           sound = actor->info->seesound;
1061           break;
1062         }
1063       if (actor->flags & MF_FULLVOLSIGHT)
1064         S_StartSound(NULL, sound);          // full volume
1065       else
1066         S_StartSound(actor, sound);
1067     }
1068   P_SetMobjState(actor, actor->info->seestate);
1069 }
1070 
1071 //
1072 // A_KeepChasing
1073 //
1074 // killough 10/98:
1075 // Allows monsters to continue movement while attacking
1076 //
1077 
1078 #if 0
1079 static void A_KeepChasing(mobj_t *actor)
1080 {
1081   if (actor->movecount)
1082     {
1083       actor->movecount--;
1084       if (actor->strafecount)
1085         actor->strafecount--;
1086       P_SmartMove(actor);
1087     }
1088 }
1089 #endif
1090 
1091 //
1092 // A_Chase
1093 // Actor has a melee attack,
1094 // so it tries to close as fast as possible
1095 //
1096 
A_Chase(mobj_t * actor)1097 void A_Chase(mobj_t *actor)
1098 {
1099   if (actor->reactiontime)
1100     actor->reactiontime--;
1101 
1102   if (actor->threshold) { /* modify target threshold */
1103     if (!actor->target || actor->target->health <= 0)
1104       actor->threshold = 0;
1105     else
1106       actor->threshold--;
1107   }
1108 
1109   /* turn towards movement direction if not there yet
1110    * killough 9/7/98: keep facing towards target if strafing or backing out
1111    */
1112 
1113   if (actor->strafecount)
1114     A_FaceTarget(actor);
1115   else if (actor->movedir < 8)
1116     {
1117       int delta = (actor->angle &= (7<<29)) - (actor->movedir << 29);
1118       if (delta > 0)
1119         actor->angle -= ANG90/2;
1120       else
1121         if (delta < 0)
1122           actor->angle += ANG90/2;
1123     }
1124 
1125   if (!actor->target || !(actor->target->flags&MF_SHOOTABLE))
1126     {
1127       if (!P_LookForTargets(actor,TRUE)) // look for a new target
1128   P_SetMobjState(actor, actor->info->spawnstate); // no new target
1129       return;
1130     }
1131 
1132   // do not attack twice in a row
1133   if (actor->flags & MF_JUSTATTACKED)
1134     {
1135       actor->flags &= ~MF_JUSTATTACKED;
1136       if (gameskill != sk_nightmare && !fastparm)
1137         P_NewChaseDir(actor);
1138       return;
1139     }
1140 
1141   // check for melee attack
1142   if (actor->info->meleestate && P_CheckMeleeRange(actor))
1143     {
1144       if (actor->info->attacksound)
1145         S_StartSound(actor, actor->info->attacksound);
1146       P_SetMobjState(actor, actor->info->meleestate);
1147       /* killough 8/98: remember an attack
1148       * cph - DEMOSYNC? */
1149       if (!actor->info->missilestate)
1150   actor->flags |= MF_JUSTHIT;
1151       return;
1152     }
1153 
1154   // check for missile attack
1155   if (actor->info->missilestate)
1156     if (!(gameskill < sk_nightmare && !fastparm && actor->movecount))
1157       if (P_CheckMissileRange(actor))
1158         {
1159           P_SetMobjState(actor, actor->info->missilestate);
1160           actor->flags |= MF_JUSTATTACKED;
1161           return;
1162         }
1163 
1164   if (!actor->threshold) {
1165     if (!mbf_features)
1166       {   /* killough 9/9/98: for backward demo compatibility */
1167   if (netgame && !P_CheckSight(actor, actor->target) &&
1168       P_LookForPlayers(actor, TRUE))
1169     return;
1170       }
1171     /* killough 7/18/98, 9/9/98: new monster AI */
1172     else if (help_friends && P_HelpFriend(actor))
1173       return;      /* killough 9/8/98: Help friends in need */
1174     /* Look for new targets if current one is bad or is out of view */
1175     else if (actor->pursuecount)
1176       actor->pursuecount--;
1177     else {
1178   /* Our pursuit time has expired. We're going to think about
1179    * changing targets */
1180   actor->pursuecount = BASETHRESHOLD;
1181 
1182   /* Unless (we have a live target
1183    *         and it's not friendly
1184    *         and we can see it)
1185    *  try to find a new one; return if sucessful */
1186 
1187   if (!(actor->target && actor->target->health > 0 &&
1188         ((comp[comp_pursuit] && !netgame) ||
1189          (((actor->target->flags ^ actor->flags) & MF_FRIEND ||
1190      (!(actor->flags & MF_FRIEND) && monster_infighting)) &&
1191     P_CheckSight(actor, actor->target))))
1192       && P_LookForTargets(actor, TRUE))
1193         return;
1194 
1195   /* (Current target was good, or no new target was found.)
1196    *
1197    * If monster is a missile-less friend, give up pursuit and
1198    * return to player, if no attacks have occurred recently.
1199    */
1200 
1201   if (!actor->info->missilestate && actor->flags & MF_FRIEND) {
1202     if (actor->flags & MF_JUSTHIT)          /* if recent action, */
1203       actor->flags &= ~MF_JUSTHIT;          /* keep fighting */
1204     else if (P_LookForPlayers(actor, TRUE)) /* else return to player */
1205       return;
1206   }
1207     }
1208   }
1209 
1210   if (actor->strafecount)
1211     actor->strafecount--;
1212 
1213   // chase towards player
1214   if (--actor->movecount<0 || !P_SmartMove(actor))
1215     P_NewChaseDir(actor);
1216 
1217   // make active sound
1218   if (actor->info->activesound && P_Random(pr_see)<3)
1219     S_StartSound(actor, actor->info->activesound);
1220 }
1221 
1222 //
1223 // A_FaceTarget
1224 //
A_FaceTarget(mobj_t * actor)1225 void A_FaceTarget(mobj_t *actor)
1226 {
1227   if (!actor->target)
1228     return;
1229   actor->flags &= ~MF_AMBUSH;
1230   actor->angle = R_PointToAngle2(actor->x, actor->y,
1231                                  actor->target->x, actor->target->y);
1232   if (actor->target->flags & MF_SHADOW)
1233     { // killough 5/5/98: remove dependence on order of evaluation:
1234       int t = P_Random(pr_facetarget);
1235       actor->angle += (t-P_Random(pr_facetarget))<<21;
1236     }
1237 }
1238 
1239 //
1240 // A_PosAttack
1241 //
1242 
A_PosAttack(mobj_t * actor)1243 void A_PosAttack(mobj_t *actor)
1244 {
1245   int angle, damage, slope, t;
1246 
1247   if (!actor->target)
1248     return;
1249   A_FaceTarget(actor);
1250   angle = actor->angle;
1251   slope = P_AimLineAttack(actor, angle, MISSILERANGE, 0); /* killough 8/2/98 */
1252   S_StartSound(actor, sfx_pistol);
1253 
1254   // killough 5/5/98: remove dependence on order of evaluation:
1255   t = P_Random(pr_posattack);
1256   angle += (t - P_Random(pr_posattack))<<20;
1257   damage = (P_Random(pr_posattack)%5 + 1)*3;
1258   P_LineAttack(actor, angle, MISSILERANGE, slope, damage);
1259 }
1260 
A_SPosAttack(mobj_t * actor)1261 void A_SPosAttack(mobj_t* actor)
1262 {
1263   int i, bangle, slope;
1264 
1265   if (!actor->target)
1266     return;
1267   S_StartSound(actor, sfx_shotgn);
1268   A_FaceTarget(actor);
1269   bangle = actor->angle;
1270   slope = P_AimLineAttack(actor, bangle, MISSILERANGE, 0); /* killough 8/2/98 */
1271   for (i=0; i<3; i++)
1272     {  // killough 5/5/98: remove dependence on order of evaluation:
1273       int t = P_Random(pr_sposattack);
1274       int angle = bangle + ((t - P_Random(pr_sposattack))<<20);
1275       int damage = ((P_Random(pr_sposattack)%5)+1)*3;
1276       P_LineAttack(actor, angle, MISSILERANGE, slope, damage);
1277     }
1278 }
1279 
A_CPosAttack(mobj_t * actor)1280 void A_CPosAttack(mobj_t *actor)
1281 {
1282   int angle, bangle, damage, slope, t;
1283 
1284   if (!actor->target)
1285     return;
1286   S_StartSound(actor, sfx_shotgn);
1287   A_FaceTarget(actor);
1288   bangle = actor->angle;
1289   slope = P_AimLineAttack(actor, bangle, MISSILERANGE, 0); /* killough 8/2/98 */
1290 
1291   // killough 5/5/98: remove dependence on order of evaluation:
1292   t = P_Random(pr_cposattack);
1293   angle = bangle + ((t - P_Random(pr_cposattack))<<20);
1294   damage = ((P_Random(pr_cposattack)%5)+1)*3;
1295   P_LineAttack(actor, angle, MISSILERANGE, slope, damage);
1296 }
1297 
A_CPosRefire(mobj_t * actor)1298 void A_CPosRefire(mobj_t *actor)
1299 {
1300   // keep firing unless target got out of sight
1301   A_FaceTarget(actor);
1302 
1303   /* killough 12/98: Stop firing if a friend has gotten in the way */
1304   if (P_HitFriend(actor))
1305     goto stop;
1306 
1307   /* killough 11/98: prevent refiring on friends continuously */
1308   if (P_Random(pr_cposrefire) < 40) {
1309     if (actor->target && actor->flags & actor->target->flags & MF_FRIEND)
1310       goto stop;
1311     else
1312       return;
1313   }
1314 
1315   if (!actor->target || actor->target->health <= 0
1316       || !P_CheckSight(actor, actor->target))
1317 stop:  P_SetMobjState(actor, actor->info->seestate);
1318 }
1319 
A_SpidRefire(mobj_t * actor)1320 void A_SpidRefire(mobj_t* actor)
1321 {
1322   // keep firing unless target got out of sight
1323   A_FaceTarget(actor);
1324 
1325   /* killough 12/98: Stop firing if a friend has gotten in the way */
1326   if (P_HitFriend(actor))
1327     goto stop;
1328 
1329   if (P_Random(pr_spidrefire) < 10)
1330     return;
1331 
1332   // killough 11/98: prevent refiring on friends continuously
1333   if (!actor->target || actor->target->health <= 0
1334       || actor->flags & actor->target->flags & MF_FRIEND
1335       || !P_CheckSight(actor, actor->target))
1336     stop: P_SetMobjState(actor, actor->info->seestate);
1337 }
1338 
A_BspiAttack(mobj_t * actor)1339 void A_BspiAttack(mobj_t *actor)
1340 {
1341   if (!actor->target)
1342     return;
1343   A_FaceTarget(actor);
1344   P_SpawnMissile(actor, actor->target, MT_ARACHPLAZ);  // launch a missile
1345 }
1346 
1347 //
1348 // A_TroopAttack
1349 //
1350 
A_TroopAttack(mobj_t * actor)1351 void A_TroopAttack(mobj_t *actor)
1352 {
1353   if (!actor->target)
1354     return;
1355   A_FaceTarget(actor);
1356   if (P_CheckMeleeRange(actor))
1357     {
1358       int damage;
1359       S_StartSound(actor, sfx_claw);
1360       damage = (P_Random(pr_troopattack)%8+1)*3;
1361       P_DamageMobj(actor->target, actor, actor, damage);
1362       return;
1363     }
1364   P_SpawnMissile(actor, actor->target, MT_TROOPSHOT);  // launch a missile
1365 }
1366 
A_SargAttack(mobj_t * actor)1367 void A_SargAttack(mobj_t *actor)
1368 {
1369   if (!actor->target)
1370     return;
1371   A_FaceTarget(actor);
1372   if (P_CheckMeleeRange(actor))
1373     {
1374       int damage = ((P_Random(pr_sargattack)%10)+1)*4;
1375       P_DamageMobj(actor->target, actor, actor, damage);
1376     }
1377 }
1378 
A_HeadAttack(mobj_t * actor)1379 void A_HeadAttack(mobj_t *actor)
1380 {
1381   if (!actor->target)
1382     return;
1383   A_FaceTarget (actor);
1384   if (P_CheckMeleeRange(actor))
1385     {
1386       int damage = (P_Random(pr_headattack)%6+1)*10;
1387       P_DamageMobj(actor->target, actor, actor, damage);
1388       return;
1389     }
1390   P_SpawnMissile(actor, actor->target, MT_HEADSHOT);  // launch a missile
1391 }
1392 
A_CyberAttack(mobj_t * actor)1393 void A_CyberAttack(mobj_t *actor)
1394 {
1395   if (!actor->target)
1396     return;
1397   A_FaceTarget(actor);
1398   P_SpawnMissile(actor, actor->target, MT_ROCKET);
1399 }
1400 
A_BruisAttack(mobj_t * actor)1401 void A_BruisAttack(mobj_t *actor)
1402 {
1403   if (!actor->target)
1404     return;
1405   if (P_CheckMeleeRange(actor))
1406     {
1407       int damage;
1408       S_StartSound(actor, sfx_claw);
1409       damage = (P_Random(pr_bruisattack)%8+1)*10;
1410       P_DamageMobj(actor->target, actor, actor, damage);
1411       return;
1412     }
1413   P_SpawnMissile(actor, actor->target, MT_BRUISERSHOT);  // launch a missile
1414 }
1415 
1416 //
1417 // A_SkelMissile
1418 //
1419 
A_SkelMissile(mobj_t * actor)1420 void A_SkelMissile(mobj_t *actor)
1421 {
1422   mobj_t *mo;
1423 
1424   if (!actor->target)
1425     return;
1426 
1427   A_FaceTarget (actor);
1428   actor->z += 16*FRACUNIT;      // so missile spawns higher
1429   mo = P_SpawnMissile (actor, actor->target, MT_TRACER);
1430   actor->z -= 16*FRACUNIT;      // back to normal
1431 
1432   mo->x += mo->momx;
1433   mo->y += mo->momy;
1434   P_SetTarget(&mo->tracer, actor->target);
1435 }
1436 
1437 int     TRACEANGLE = 0xc000000;
1438 
A_Tracer(mobj_t * actor)1439 void A_Tracer(mobj_t *actor)
1440 {
1441   angle_t       exact;
1442   fixed_t       dist;
1443   fixed_t       slope;
1444   mobj_t        *dest;
1445   mobj_t        *th;
1446 
1447   /* killough 1/18/98: this is why some missiles do not have smoke
1448    * and some do. Also, internal demos start at random gametics, thus
1449    * the bug in which revenants cause internal demos to go out of sync.
1450    *
1451    * killough 3/6/98: fix revenant internal demo bug by subtracting
1452    * levelstarttic from gametic.
1453    *
1454    * killough 9/29/98: use new "basetic" so that demos stay in sync
1455    * during pauses and menu activations, while retaining old demo sync.
1456    *
1457    * leveltime would have been better to use to start with in Doom, but
1458    * since old demos were recorded using gametic, we must stick with it,
1459    * and improvise around it (using leveltime causes desync across levels).
1460    */
1461 
1462   if ((gametic-basetic) & 3)
1463     return;
1464 
1465   // spawn a puff of smoke behind the rocket
1466   P_SpawnPuff(actor->x, actor->y, actor->z);
1467 
1468   th = P_SpawnMobj (actor->x-actor->momx,
1469                     actor->y-actor->momy,
1470                     actor->z, MT_SMOKE);
1471 
1472   th->momz = FRACUNIT;
1473   th->tics -= P_Random(pr_tracer) & 3;
1474   if (th->tics < 1)
1475     th->tics = 1;
1476 
1477   // adjust direction
1478   dest = actor->tracer;
1479 
1480   if (!dest || dest->health <= 0)
1481     return;
1482 
1483   // change angle
1484   exact = R_PointToAngle2(actor->x, actor->y, dest->x, dest->y);
1485 
1486   if (exact != actor->angle) {
1487     if (exact - actor->angle > 0x80000000)
1488       {
1489         actor->angle -= TRACEANGLE;
1490         if (exact - actor->angle < 0x80000000)
1491           actor->angle = exact;
1492       }
1493     else
1494       {
1495         actor->angle += TRACEANGLE;
1496         if (exact - actor->angle > 0x80000000)
1497           actor->angle = exact;
1498       }
1499   }
1500 
1501   exact = actor->angle>>ANGLETOFINESHIFT;
1502   actor->momx = FixedMul(actor->info->speed, finecosine[exact]);
1503   actor->momy = FixedMul(actor->info->speed, finesine[exact]);
1504 
1505   // change slope
1506   dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y);
1507 
1508   dist = dist / actor->info->speed;
1509 
1510   if (dist < 1)
1511     dist = 1;
1512 
1513   slope = (dest->z+40*FRACUNIT - actor->z) / dist;
1514 
1515   if (slope < actor->momz)
1516     actor->momz -= FRACUNIT/8;
1517   else
1518     actor->momz += FRACUNIT/8;
1519 }
1520 
A_SkelWhoosh(mobj_t * actor)1521 void A_SkelWhoosh(mobj_t *actor)
1522 {
1523   if (!actor->target)
1524     return;
1525   A_FaceTarget(actor);
1526   S_StartSound(actor,sfx_skeswg);
1527 }
1528 
A_SkelFist(mobj_t * actor)1529 void A_SkelFist(mobj_t *actor)
1530 {
1531   if (!actor->target)
1532     return;
1533   A_FaceTarget(actor);
1534   if (P_CheckMeleeRange(actor))
1535     {
1536       int damage = ((P_Random(pr_skelfist)%10)+1)*6;
1537       S_StartSound(actor, sfx_skepch);
1538       P_DamageMobj(actor->target, actor, actor, damage);
1539     }
1540 }
1541 
1542 //
1543 // PIT_VileCheck
1544 // Detect a corpse that could be raised.
1545 //
1546 
1547 mobj_t* corpsehit;
1548 mobj_t* vileobj;
1549 fixed_t viletryx;
1550 fixed_t viletryy;
1551 
PIT_VileCheck(mobj_t * thing)1552 static dbool   PIT_VileCheck(mobj_t *thing)
1553 {
1554   int     maxdist;
1555   dbool   check;
1556 
1557   if (!(thing->flags & MF_CORPSE) )
1558     return TRUE;        // not a monster
1559 
1560   if (thing->tics != -1)
1561     return TRUE;        // not lying still yet
1562 
1563   if (thing->info->raisestate == S_NULL)
1564     return TRUE;        // monster doesn't have a raise state
1565 
1566   maxdist = thing->info->radius + mobjinfo[MT_VILE].radius;
1567 
1568   if (D_abs(thing->x-viletryx) > maxdist || D_abs(thing->y-viletryy) > maxdist)
1569     return TRUE;                // not actually touching
1570 
1571 // Check to see if the radius and height are zero. If they are      // phares
1572 // then this is a crushed monster that has been turned into a       //   |
1573 // gib. One of the options may be to ignore this guy.               //   V
1574 
1575 // Option 1: the original, buggy method, -> ghost (compatibility)
1576 // Option 2: ressurect the monster, but not as a ghost
1577 // Option 3: ignore the gib
1578 
1579 //    if (Option3)                                                  //   ^
1580 //        if ((thing->height == 0) && (thing->radius == 0))         //   |
1581 //            return TRUE;                                          // phares
1582 
1583     corpsehit = thing;
1584     corpsehit->momx = corpsehit->momy = 0;
1585     if (comp[comp_vile])                                            // phares
1586       {                                                             //   |
1587         corpsehit->height <<= 2;                                    //   V
1588         check = P_CheckPosition(corpsehit,corpsehit->x,corpsehit->y);
1589         corpsehit->height >>= 2;
1590       }
1591     else
1592       {
1593         int height,radius;
1594 
1595         height = corpsehit->height; // save temporarily
1596         radius = corpsehit->radius; // save temporarily
1597         corpsehit->height = corpsehit->info->height;
1598         corpsehit->radius = corpsehit->info->radius;
1599         corpsehit->flags |= MF_SOLID;
1600         check = P_CheckPosition(corpsehit,corpsehit->x,corpsehit->y);
1601         corpsehit->height = height; // restore
1602         corpsehit->radius = radius; // restore                      //   ^
1603         corpsehit->flags &= ~MF_SOLID;
1604       }                                                             //   |
1605                                                                     // phares
1606     if (!check)
1607       return TRUE;              // doesn't fit here
1608     return FALSE;               // got one, so stop checking
1609 }
1610 
1611 //
1612 // A_VileChase
1613 // Check for ressurecting a body
1614 //
1615 
A_VileChase(mobj_t * actor)1616 void A_VileChase(mobj_t* actor)
1617 {
1618   int xl, xh;
1619   int yl, yh;
1620   int bx, by;
1621 
1622   if (actor->movedir != DI_NODIR)
1623     {
1624       // check for corpses to raise
1625       viletryx =
1626         actor->x + actor->info->speed*xspeed[actor->movedir];
1627       viletryy =
1628         actor->y + actor->info->speed*yspeed[actor->movedir];
1629 
1630       xl = (viletryx - bmaporgx - MAXRADIUS*2)>>MAPBLOCKSHIFT;
1631       xh = (viletryx - bmaporgx + MAXRADIUS*2)>>MAPBLOCKSHIFT;
1632       yl = (viletryy - bmaporgy - MAXRADIUS*2)>>MAPBLOCKSHIFT;
1633       yh = (viletryy - bmaporgy + MAXRADIUS*2)>>MAPBLOCKSHIFT;
1634 
1635       vileobj = actor;
1636       for (bx=xl ; bx<=xh ; bx++)
1637         {
1638           for (by=yl ; by<=yh ; by++)
1639             {
1640               // Call PIT_VileCheck to check
1641               // whether object is a corpse
1642               // that canbe raised.
1643               if (!P_BlockThingsIterator(bx,by,PIT_VileCheck))
1644                 {
1645       mobjinfo_t *info;
1646 
1647                   // got one!
1648                   mobj_t* temp = actor->target;
1649                   actor->target = corpsehit;
1650                   A_FaceTarget(actor);
1651                   actor->target = temp;
1652 
1653                   P_SetMobjState(actor, S_VILE_HEAL1);
1654                   S_StartSound(corpsehit, sfx_slop);
1655                   info = corpsehit->info;
1656 
1657                   P_SetMobjState(corpsehit,info->raisestate);
1658 
1659                   if (comp[comp_vile])                              // phares
1660                     corpsehit->height <<= 2;                        //   |
1661                   else                                              //   V
1662                     {
1663                       corpsehit->height = info->height; // fix Ghost bug
1664                       corpsehit->radius = info->radius; // fix Ghost bug
1665                     }                                               // phares
1666 
1667       /* killough 7/18/98:
1668        * friendliness is transferred from AV to raised corpse
1669        */
1670       corpsehit->flags =
1671         (info->flags & ~MF_FRIEND) | (actor->flags & MF_FRIEND);
1672 
1673       corpsehit->intflags = corpsehit->intflags | MIF_RESURRECTED;//mark as resurrected
1674 
1675       if (!((corpsehit->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL)))
1676           totallive++;
1677 
1678       corpsehit->health = info->spawnhealth;
1679       P_SetTarget(&corpsehit->target, NULL);  // killough 11/98
1680 
1681       if (mbf_features)
1682         {         /* kilough 9/9/98 */
1683           P_SetTarget(&corpsehit->lastenemy, NULL);
1684           corpsehit->flags &= ~MF_JUSTHIT;
1685         }
1686 
1687       /* killough 8/29/98: add to appropriate thread */
1688       P_UpdateThinker(&corpsehit->thinker);
1689 
1690                   return;
1691                 }
1692             }
1693         }
1694     }
1695   A_Chase(actor);  // Return to normal attack.
1696 }
1697 
1698 //
1699 // A_VileStart
1700 //
1701 
A_VileStart(mobj_t * actor)1702 void A_VileStart(mobj_t *actor)
1703 {
1704   S_StartSound(actor, sfx_vilatk);
1705 }
1706 
1707 //
1708 // A_Fire
1709 // Keep fire in front of player unless out of sight
1710 //
1711 
A_StartFire(mobj_t * actor)1712 void A_StartFire(mobj_t *actor)
1713 {
1714   S_StartSound(actor,sfx_flamst);
1715   A_Fire(actor);
1716 }
1717 
A_FireCrackle(mobj_t * actor)1718 void A_FireCrackle(mobj_t* actor)
1719 {
1720   S_StartSound(actor,sfx_flame);
1721   A_Fire(actor);
1722 }
1723 
A_Fire(mobj_t * actor)1724 void A_Fire(mobj_t *actor)
1725 {
1726   unsigned an;
1727   mobj_t *dest = actor->tracer;
1728 
1729   if (!dest)
1730     return;
1731 
1732   // don't move it if the vile lost sight
1733   if (!P_CheckSight(actor->target, dest) )
1734     return;
1735 
1736   an = dest->angle >> ANGLETOFINESHIFT;
1737 
1738   P_UnsetThingPosition(actor);
1739   actor->x = dest->x + FixedMul(STEPSIZE, finecosine[an]);
1740   actor->y = dest->y + FixedMul(STEPSIZE, finesine[an]);
1741   actor->z = dest->z;
1742   P_SetThingPosition(actor);
1743 }
1744 
1745 //
1746 // A_VileTarget
1747 // Spawn the hellfire
1748 //
1749 
A_VileTarget(mobj_t * actor)1750 void A_VileTarget(mobj_t *actor)
1751 {
1752   mobj_t *fog;
1753 
1754   if (!actor->target)
1755     return;
1756 
1757   A_FaceTarget(actor);
1758 
1759   // killough 12/98: fix Vile fog coordinates // CPhipps - compatibility optioned
1760   fog = P_SpawnMobj(actor->target->x,
1761     (compatibility_level < lxdoom_1_compatibility) ? actor->target->x : actor->target->y,
1762                     actor->target->z,MT_FIRE);
1763 
1764   P_SetTarget(&actor->tracer, fog);
1765   P_SetTarget(&fog->target, actor);
1766   P_SetTarget(&fog->tracer, actor->target);
1767   A_Fire(fog);
1768 }
1769 
1770 //
1771 // A_VileAttack
1772 //
1773 
A_VileAttack(mobj_t * actor)1774 void A_VileAttack(mobj_t *actor)
1775 {
1776   mobj_t *fire;
1777   int    an;
1778 
1779   if (!actor->target)
1780     return;
1781 
1782   A_FaceTarget(actor);
1783 
1784   if (!P_CheckSight(actor, actor->target))
1785     return;
1786 
1787   S_StartSound(actor, sfx_barexp);
1788   P_DamageMobj(actor->target, actor, actor, 20);
1789   actor->target->momz = 1000*FRACUNIT/actor->target->info->mass;
1790 
1791   an = actor->angle >> ANGLETOFINESHIFT;
1792 
1793   fire = actor->tracer;
1794 
1795   if (!fire)
1796     return;
1797 
1798   // move the fire between the vile and the player
1799   fire->x = actor->target->x - FixedMul (STEPSIZE, finecosine[an]);
1800   fire->y = actor->target->y - FixedMul (STEPSIZE, finesine[an]);
1801   P_RadiusAttack(fire, actor, 70);
1802 }
1803 
1804 //
1805 // Mancubus attack,
1806 // firing three missiles (bruisers)
1807 // in three different directions?
1808 // Doesn't look like it.
1809 //
1810 
1811 #define FATSPREAD       (ANG90/8)
1812 
A_FatRaise(mobj_t * actor)1813 void A_FatRaise(mobj_t *actor)
1814 {
1815   A_FaceTarget(actor);
1816   S_StartSound(actor, sfx_manatk);
1817 }
1818 
A_FatAttack1(mobj_t * actor)1819 void A_FatAttack1(mobj_t *actor)
1820 {
1821   mobj_t *mo;
1822   int    an;
1823 
1824   if (!actor->target)
1825     return;
1826 
1827   A_FaceTarget(actor);
1828 
1829   // Change direction  to ...
1830   actor->angle += FATSPREAD;
1831 
1832   P_SpawnMissile(actor, actor->target, MT_FATSHOT);
1833 
1834   mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1835   mo->angle += FATSPREAD;
1836   an = mo->angle >> ANGLETOFINESHIFT;
1837   mo->momx = FixedMul(mo->info->speed, finecosine[an]);
1838   mo->momy = FixedMul(mo->info->speed, finesine[an]);
1839 }
1840 
A_FatAttack2(mobj_t * actor)1841 void A_FatAttack2(mobj_t *actor)
1842 {
1843   mobj_t *mo;
1844   int    an;
1845 
1846   if (!actor->target)
1847     return;
1848 
1849   A_FaceTarget(actor);
1850   // Now here choose opposite deviation.
1851   actor->angle -= FATSPREAD;
1852   P_SpawnMissile(actor, actor->target, MT_FATSHOT);
1853 
1854   mo = P_SpawnMissile(actor, actor->target, MT_FATSHOT);
1855   mo->angle -= FATSPREAD*2;
1856   an = mo->angle >> ANGLETOFINESHIFT;
1857   mo->momx = FixedMul(mo->info->speed, finecosine[an]);
1858   mo->momy = FixedMul(mo->info->speed, finesine[an]);
1859 }
1860 
A_FatAttack3(mobj_t * actor)1861 void A_FatAttack3(mobj_t *actor)
1862 {
1863   mobj_t *mo;
1864   int    an;
1865 
1866   if (!actor->target)
1867     return;
1868 
1869   A_FaceTarget(actor);
1870 
1871   mo = P_SpawnMissile(actor, actor->target, MT_FATSHOT);
1872   mo->angle -= FATSPREAD/2;
1873   an = mo->angle >> ANGLETOFINESHIFT;
1874   mo->momx = FixedMul(mo->info->speed, finecosine[an]);
1875   mo->momy = FixedMul(mo->info->speed, finesine[an]);
1876 
1877   mo = P_SpawnMissile(actor, actor->target, MT_FATSHOT);
1878   mo->angle += FATSPREAD/2;
1879   an = mo->angle >> ANGLETOFINESHIFT;
1880   mo->momx = FixedMul(mo->info->speed, finecosine[an]);
1881   mo->momy = FixedMul(mo->info->speed, finesine[an]);
1882 }
1883 
1884 
1885 //
1886 // SkullAttack
1887 // Fly at the player like a missile.
1888 //
1889 #define SKULLSPEED              (20*FRACUNIT)
1890 
A_SkullAttack(mobj_t * actor)1891 void A_SkullAttack(mobj_t *actor)
1892 {
1893   mobj_t  *dest;
1894   angle_t an;
1895   int     dist;
1896 
1897   if (!actor->target)
1898     return;
1899 
1900   dest = actor->target;
1901   actor->flags |= MF_SKULLFLY;
1902 
1903   S_StartSound(actor, actor->info->attacksound);
1904   A_FaceTarget(actor);
1905   an = actor->angle >> ANGLETOFINESHIFT;
1906   actor->momx = FixedMul(SKULLSPEED, finecosine[an]);
1907   actor->momy = FixedMul(SKULLSPEED, finesine[an]);
1908   dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y);
1909   dist = dist / SKULLSPEED;
1910 
1911   if (dist < 1)
1912     dist = 1;
1913   actor->momz = (dest->z+(dest->height>>1) - actor->z) / dist;
1914 }
1915 
1916 //
1917 // A_BetaSkullAttack
1918 // The flying skull had different behavior on Beta Doom
1919 //
1920 
A_BetaSkullAttack(mobj_t * actor)1921 void A_BetaSkullAttack(mobj_t *actor)
1922 {
1923   int damage;
1924 
1925   if (compatibility_level < mbf_compatibility)
1926     return;
1927 
1928   if (!actor->target || actor->target->type == MT_SKULL)
1929     return;
1930 
1931   S_StartSound(actor, actor->info->attacksound);
1932   A_FaceTarget(actor);
1933   damage = (P_Random(pr_skullfly)%8+1)*actor->info->damage;
1934   P_DamageMobj(actor->target, actor, actor, damage);
1935 }
1936 
1937 //
1938 // A_Stop
1939 // The flying skull had different behavior on Beta Doom
1940 //
1941 
A_Stop(mobj_t * actor)1942 void A_Stop(mobj_t *actor)
1943 {
1944   if (compatibility_level < mbf_compatibility)
1945     return;
1946 
1947   actor->momx = actor->momy = actor->momz = 0;
1948 }
1949 
1950 //
1951 // A_PainShootSkull
1952 // Spawn a lost soul and launch it at the target
1953 //
1954 
A_PainShootSkull(mobj_t * actor,angle_t angle)1955 static void A_PainShootSkull(mobj_t *actor, angle_t angle)
1956 {
1957   fixed_t       x,y,z;
1958   mobj_t        *newmobj;
1959   angle_t       an;
1960   int           prestep;
1961 
1962 // The original code checked for 20 skulls on the level,            // phares
1963 // and wouldn't spit another one if there were. If not in           // phares
1964 // compatibility mode, we remove the limit.                         // phares
1965                                                                     // phares
1966   if (comp[comp_pain]) /* killough 10/98: compatibility-optioned */
1967     {
1968       // count total number of skulls currently on the level
1969       int count = 0;
1970       thinker_t *currentthinker = NULL;
1971       while ((currentthinker = P_NextThinker(currentthinker,th_all)) != NULL)
1972         if ((currentthinker->function == P_MobjThinker)
1973             && ((mobj_t *)currentthinker)->type == MT_SKULL)
1974           count++;
1975       if (count > 20)                                               // phares
1976         return;                                                     // phares
1977     }
1978 
1979   // okay, there's room for another one
1980 
1981   an = angle >> ANGLETOFINESHIFT;
1982 
1983   prestep = 4*FRACUNIT + 3*(actor->info->radius + mobjinfo[MT_SKULL].radius)/2;
1984 
1985   x = actor->x + FixedMul(prestep, finecosine[an]);
1986   y = actor->y + FixedMul(prestep, finesine[an]);
1987   z = actor->z + 8*FRACUNIT;
1988 
1989   if (comp[comp_skull])   /* killough 10/98: compatibility-optioned */
1990     newmobj = P_SpawnMobj(x, y, z, MT_SKULL);                     // phares
1991   else                                                            //   V
1992     {
1993       // Check whether the Lost Soul is being fired through a 1-sided
1994       // wall or an impassible line, or a "monsters can't cross" line.
1995       // If it is, then we don't allow the spawn. This is a bug fix, but
1996       // it should be considered an enhancement, since it may disturb
1997       // existing demos, so don't do it in compatibility mode.
1998 
1999       if (Check_Sides(actor,x,y))
2000         return;
2001 
2002       newmobj = P_SpawnMobj(x, y, z, MT_SKULL);
2003 
2004       // Check to see if the new Lost Soul's z value is above the
2005       // ceiling of its new sector, or below the floor. If so, kill it.
2006 
2007       if ((newmobj->z >
2008            (newmobj->subsector->sector->ceilingheight - newmobj->height)) ||
2009           (newmobj->z < newmobj->subsector->sector->floorheight))
2010         {
2011           // kill it immediately
2012           P_DamageMobj(newmobj,actor,actor,10000);
2013           return;                                                 //   ^
2014         }                                                         //   |
2015      }                                                            // phares
2016 
2017   /* killough 7/20/98: PEs shoot lost souls with the same friendliness */
2018   newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (actor->flags & MF_FRIEND);
2019 
2020   /* killough 8/29/98: add to appropriate thread */
2021   P_UpdateThinker(&newmobj->thinker);
2022 
2023   // Check for movements.
2024   // killough 3/15/98: don't jump over dropoffs:
2025 
2026   if (!P_TryMove(newmobj, newmobj->x, newmobj->y, FALSE))
2027     {
2028       // kill it immediately
2029       P_DamageMobj(newmobj, actor, actor, 10000);
2030       return;
2031     }
2032 
2033   P_SetTarget(&newmobj->target, actor->target);
2034   A_SkullAttack(newmobj);
2035 }
2036 
2037 //
2038 // A_PainAttack
2039 // Spawn a lost soul and launch it at the target
2040 //
2041 
A_PainAttack(mobj_t * actor)2042 void A_PainAttack(mobj_t *actor)
2043 {
2044   if (!actor->target)
2045     return;
2046   A_FaceTarget(actor);
2047   A_PainShootSkull(actor, actor->angle);
2048 }
2049 
A_PainDie(mobj_t * actor)2050 void A_PainDie(mobj_t *actor)
2051 {
2052   A_Fall(actor);
2053   A_PainShootSkull(actor, actor->angle+ANG90);
2054   A_PainShootSkull(actor, actor->angle+ANG180);
2055   A_PainShootSkull(actor, actor->angle+ANG270);
2056 }
2057 
A_Scream(mobj_t * actor)2058 void A_Scream(mobj_t *actor)
2059 {
2060   int sound;
2061 
2062   switch (actor->info->deathsound)
2063     {
2064     case 0:
2065       return;
2066 
2067     case sfx_podth1:
2068     case sfx_podth2:
2069     case sfx_podth3:
2070       sound = sfx_podth1 + P_Random(pr_scream)%3;
2071       break;
2072 
2073     case sfx_bgdth1:
2074     case sfx_bgdth2:
2075       sound = sfx_bgdth1 + P_Random(pr_scream)%2;
2076       break;
2077 
2078     default:
2079       sound = actor->info->deathsound;
2080       break;
2081     }
2082 
2083   // Check for bosses.
2084   if (actor->flags & MF_FULLVOLDEATH)
2085     S_StartSound(NULL, sound); // full volume
2086   else
2087     S_StartSound(actor, sound);
2088 }
2089 
A_XScream(mobj_t * actor)2090 void A_XScream(mobj_t *actor)
2091 {
2092   S_StartSound(actor, sfx_slop);
2093 }
2094 
A_Pain(mobj_t * actor)2095 void A_Pain(mobj_t *actor)
2096 {
2097   if (actor->info->painsound)
2098     S_StartSound(actor, actor->info->painsound);
2099 }
2100 
A_Fall(mobj_t * actor)2101 void A_Fall(mobj_t *actor)
2102 {
2103   // actor is on ground, it can be walked over
2104   actor->flags &= ~MF_SOLID;
2105 }
2106 
2107 //
2108 // A_Explode
2109 //
A_Explode(mobj_t * thingy)2110 void A_Explode(mobj_t *thingy)
2111 {
2112   P_RadiusAttack( thingy, thingy->target, 128 );
2113   retro_set_rumble_damage(60, 500.f);
2114 }
2115 
2116 //
2117 // A_BossDeath
2118 // Possibly trigger special effects
2119 // if on first boss level
2120 //
2121 
A_BossDeath(mobj_t * mo)2122 void A_BossDeath(mobj_t *mo)
2123 {
2124   thinker_t *th;
2125   line_t    junk;
2126   int       i;
2127 
2128   // numbossactions == 0 means to use the defaults.
2129   // numbossactions == -1 means to do nothing.
2130   // positive values mean to check the list of boss actions and run all that apply.
2131   if (gamemapinfo && gamemapinfo->numbossactions != 0)
2132   {
2133     if (gamemapinfo->numbossactions < 0) return; // -1 clears all bossaction
2134 
2135     for (i = 0; i < gamemapinfo->numbossactions; i++)
2136     {
2137       if (gamemapinfo->bossactions[i].type == mo->type)
2138         break;
2139     }
2140     if (i >= gamemapinfo->numbossactions)
2141       return;	// no matches found
2142   }
2143   else if (gamemode == commercial)
2144     {
2145       if (gamemap != 7)
2146         return;
2147 
2148       if ((mo->type != MT_FATSO)
2149           && (mo->type != MT_BABY))
2150         return;
2151     }
2152   else
2153     {
2154       // e6y
2155       // Additional check of gameepisode is necessary, because
2156       // there is no right or wrong solution for E4M6 in original EXEs,
2157       // there's nothing to emulate.
2158       if (comp[comp_666] && gameepisode < 4)
2159       {
2160         // e6y
2161         // Only following checks are present in doom2.exe ver. 1.666 and 1.9
2162         // instead of separate checks for each episode in doomult.exe, plutonia.exe and tnt.exe
2163         // There is no more desync on doom.wad\episode3.lmp
2164         // http://www.doomworld.com/idgames/index.php?id=6909
2165         if (gamemap != 8)
2166           return;
2167         if (mo->type == MT_BRUISER && gameepisode != 1)
2168           return;
2169       }
2170       else
2171       {
2172       switch(gameepisode)
2173         {
2174         case 1:
2175           if (gamemap != 8)
2176             return;
2177 
2178           if (mo->type != MT_BRUISER)
2179             return;
2180           break;
2181 
2182         case 2:
2183           if (gamemap != 8)
2184             return;
2185 
2186           if (mo->type != MT_CYBORG)
2187             return;
2188           break;
2189 
2190         case 3:
2191           if (gamemap != 8)
2192             return;
2193 
2194           if (mo->type != MT_SPIDER)
2195             return;
2196 
2197           break;
2198 
2199         case 4:
2200           switch(gamemap)
2201             {
2202             case 6:
2203               if (mo->type != MT_CYBORG)
2204                 return;
2205               break;
2206 
2207             case 8:
2208               if (mo->type != MT_SPIDER)
2209                 return;
2210               break;
2211 
2212             default:
2213               return;
2214               break;
2215             }
2216           break;
2217 
2218         case 5: // sigil
2219           return;
2220 
2221         default:
2222           if (gamemap != 8)
2223             return;
2224           break;
2225         }
2226       }
2227 
2228     }
2229 
2230   // make sure there is a player alive for victory
2231   for (i=0; i<MAXPLAYERS; i++)
2232     if (playeringame[i] && players[i].health > 0)
2233       break;
2234 
2235   if (i==MAXPLAYERS)
2236     return;     // no one left alive, so do not end game
2237 
2238     // scan the remaining thinkers to see
2239     // if all bosses are dead
2240   for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
2241     if (th->function == P_MobjThinker)
2242       {
2243         mobj_t *mo2 = (mobj_t *) th;
2244         if (mo2 != mo && mo2->type == mo->type && mo2->health > 0)
2245           return;         // other boss not dead
2246       }
2247 
2248   // victory! apply BossDeath effect
2249   if (gamemapinfo && gamemapinfo->numbossactions != 0)
2250   {
2251     for (i = 0; i < gamemapinfo->numbossactions; i++)
2252       if (gamemapinfo->bossactions[i].type == mo->type)
2253       {
2254         player_t fakeplayer = {0};
2255         fakeplayer.health = 1; // non-zombie fake player
2256         fakeplayer.mo = NULL;  // don't play sounds, teleport, etc
2257         junk = *lines;
2258         junk.special = (short)gamemapinfo->bossactions[i].special;
2259         junk.tag = (short)gamemapinfo->bossactions[i].tag;
2260         // Treat the boss as a temporary fake player to activate the special
2261         // it'll be excluded from teleportation since fakeplayer->mo == NULL
2262         mo->player = &fakeplayer;
2263         if (!P_UseSpecialLine(mo, &junk, 0))
2264           P_CrossSpecialLine(&junk, 0, mo);
2265         mo->player = NULL;
2266       }
2267   }
2268   else if ( gamemode == commercial)
2269     {
2270       if (gamemap == 7)
2271         {
2272           if (mo->type == MT_FATSO)
2273             {
2274               junk.tag = 666;
2275               EV_DoFloor(&junk,FLEV_LOWERFLOORTOLOWEST);
2276               return;
2277             }
2278 
2279           if (mo->type == MT_BABY)
2280             {
2281               junk.tag = 667;
2282               EV_DoFloor(&junk, FLEV_RAISETOTEXTURE);
2283               return;
2284             }
2285         }
2286     }
2287   else
2288     {
2289       switch(gameepisode)
2290         {
2291         case 1:
2292           junk.tag = 666;
2293           EV_DoFloor(&junk, FLEV_LOWERFLOORTOLOWEST);
2294           return;
2295         case 4:
2296           switch(gamemap)
2297             {
2298             case 6:
2299               junk.tag = 666;
2300               EV_DoDoor(&junk, blazeOpen);
2301               return;
2302             case 8:
2303               junk.tag = 666;
2304               EV_DoFloor(&junk, FLEV_LOWERFLOORTOLOWEST);
2305               return;
2306             }
2307         }
2308     }
2309   G_ExitLevel();
2310 }
2311 
2312 
A_Hoof(mobj_t * mo)2313 void A_Hoof (mobj_t* mo)
2314 {
2315     S_StartSound(mo, sfx_hoof);
2316     A_Chase(mo);
2317 }
2318 
A_Metal(mobj_t * mo)2319 void A_Metal(mobj_t *mo)
2320 {
2321   S_StartSound(mo, sfx_metal);
2322   A_Chase(mo);
2323 }
2324 
A_BabyMetal(mobj_t * mo)2325 void A_BabyMetal(mobj_t *mo)
2326 {
2327   S_StartSound(mo, sfx_bspwlk);
2328   A_Chase(mo);
2329 }
2330 
A_OpenShotgun2(player_t * player,pspdef_t * psp)2331 void A_OpenShotgun2(player_t *player, pspdef_t *psp)
2332 {
2333   S_StartSound(player->mo, sfx_dbopn);
2334 }
2335 
A_LoadShotgun2(player_t * player,pspdef_t * psp)2336 void A_LoadShotgun2(player_t *player, pspdef_t *psp)
2337 {
2338   S_StartSound(player->mo, sfx_dbload);
2339 }
2340 
A_CloseShotgun2(player_t * player,pspdef_t * psp)2341 void A_CloseShotgun2(player_t *player, pspdef_t *psp)
2342 {
2343   S_StartSound(player->mo, sfx_dbcls);
2344   A_ReFire(player,psp);
2345 }
2346 
2347 // killough 2/7/98: Remove limit on icon landings:
2348 mobj_t **braintargets;
2349 int    numbraintargets_alloc;
2350 int    numbraintargets;
2351 
2352 struct brain_s brain;   // killough 3/26/98: global state of boss brain
2353 
2354 // killough 3/26/98: initialize icon landings at level startup,
2355 // rather than at boss wakeup, to prevent savegame-related crashes
2356 
P_SpawnBrainTargets(void)2357 void P_SpawnBrainTargets(void)  // killough 3/26/98: renamed old function
2358 {
2359   thinker_t *thinker;
2360 
2361   // find all the target spots
2362   numbraintargets = 0;
2363   brain.targeton = 0;
2364   brain.easy = 0;           // killough 3/26/98: always init easy to 0
2365 
2366   for (thinker = thinkercap.next ;
2367        thinker != &thinkercap ;
2368        thinker = thinker->next)
2369     if (thinker->function == P_MobjThinker)
2370       {
2371         mobj_t *m = (mobj_t *) thinker;
2372 
2373         if (m->type == MT_BOSSTARGET )
2374           {   // killough 2/7/98: remove limit on icon landings:
2375             if (numbraintargets >= numbraintargets_alloc)
2376               braintargets = realloc(braintargets,
2377                       (numbraintargets_alloc = numbraintargets_alloc ?
2378                        numbraintargets_alloc*2 : 32) *sizeof *braintargets);
2379             braintargets[numbraintargets++] = m;
2380           }
2381       }
2382 }
2383 
A_BrainAwake(mobj_t * mo)2384 void A_BrainAwake(mobj_t *mo)
2385 {
2386   S_StartSound(NULL,sfx_bossit); // killough 3/26/98: only generates sound now
2387 }
2388 
A_BrainPain(mobj_t * mo)2389 void A_BrainPain(mobj_t *mo)
2390 {
2391   S_StartSound(NULL,sfx_bospn);
2392 }
2393 
A_BrainScream(mobj_t * mo)2394 void A_BrainScream(mobj_t *mo)
2395 {
2396   int x;
2397   for (x=mo->x - 196*FRACUNIT ; x< mo->x + 320*FRACUNIT ; x+= FRACUNIT*8)
2398     {
2399       int y = mo->y - 320*FRACUNIT;
2400       int z = 128 + P_Random(pr_brainscream)*2*FRACUNIT;
2401       mobj_t *th = P_SpawnMobj (x,y,z, MT_ROCKET);
2402       th->momz = P_Random(pr_brainscream)*512;
2403       P_SetMobjState(th, S_BRAINEXPLODE1);
2404       th->tics -= P_Random(pr_brainscream)&7;
2405       if (th->tics < 1)
2406         th->tics = 1;
2407     }
2408   S_StartSound(NULL,sfx_bosdth);
2409 }
2410 
A_BrainExplode(mobj_t * mo)2411 void A_BrainExplode(mobj_t *mo)
2412 {  // killough 5/5/98: remove dependence on order of evaluation:
2413   int t = P_Random(pr_brainexp);
2414   int x = mo->x + (t - P_Random(pr_brainexp))*2048;
2415   int y = mo->y;
2416   int z = 128 + P_Random(pr_brainexp)*2*FRACUNIT;
2417   mobj_t *th = P_SpawnMobj(x,y,z, MT_ROCKET);
2418   th->momz = P_Random(pr_brainexp)*512;
2419   P_SetMobjState(th, S_BRAINEXPLODE1);
2420   th->tics -= P_Random(pr_brainexp)&7;
2421   if (th->tics < 1)
2422     th->tics = 1;
2423 }
2424 
A_BrainDie(mobj_t * mo)2425 void A_BrainDie(mobj_t *mo)
2426 {
2427   G_ExitLevel();
2428 }
2429 
A_BrainSpit(mobj_t * mo)2430 void A_BrainSpit(mobj_t *mo)
2431 {
2432   mobj_t *targ, *newmobj;
2433 
2434   if (!numbraintargets)     // killough 4/1/98: ignore if no targets
2435     return;
2436 
2437   brain.easy ^= 1;          // killough 3/26/98: use brain struct
2438   if (gameskill <= sk_easy && !brain.easy)
2439     return;
2440 
2441   // shoot a cube at current target
2442   targ = braintargets[brain.targeton++]; // killough 3/26/98:
2443   brain.targeton %= numbraintargets;     // Use brain struct for targets
2444 
2445   // spawn brain missile
2446   newmobj = P_SpawnMissile(mo, targ, MT_SPAWNSHOT);
2447   P_SetTarget(&newmobj->target, targ);
2448   newmobj->reactiontime = (short)(((targ->y-mo->y)/newmobj->momy)/newmobj->state->tics);
2449 
2450   // killough 7/18/98: brain friendliness is transferred
2451   newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND);
2452 
2453   // killough 8/29/98: add to appropriate thread
2454   P_UpdateThinker(&newmobj->thinker);
2455 
2456   S_StartSound(NULL, sfx_bospit);
2457 }
2458 
2459 // travelling cube sound
A_SpawnSound(mobj_t * mo)2460 void A_SpawnSound(mobj_t *mo)
2461 {
2462   S_StartSound(mo,sfx_boscub);
2463   A_SpawnFly(mo);
2464 }
2465 
A_SpawnFly(mobj_t * mo)2466 void A_SpawnFly(mobj_t *mo)
2467 {
2468   mobj_t *newmobj;
2469   mobj_t *fog;
2470   mobj_t *targ;
2471   int    r;
2472   mobjtype_t type;
2473 
2474   if (--mo->reactiontime)
2475     return;     // still flying
2476 
2477   targ = mo->target;
2478 
2479   // First spawn teleport fog.
2480   fog = P_SpawnMobj(targ->x, targ->y, targ->z, MT_SPAWNFIRE);
2481   S_StartSound(fog, sfx_telept);
2482 
2483   // Randomly select monster to spawn.
2484   r = P_Random(pr_spawnfly);
2485 
2486   // Probability distribution (kind of :), decreasing likelihood.
2487   if ( r<50 )
2488     type = MT_TROOP;
2489   else if (r<90)
2490     type = MT_SERGEANT;
2491   else if (r<120)
2492     type = MT_SHADOWS;
2493   else if (r<130)
2494     type = MT_PAIN;
2495   else if (r<160)
2496     type = MT_HEAD;
2497   else if (r<162)
2498     type = MT_VILE;
2499   else if (r<172)
2500     type = MT_UNDEAD;
2501   else if (r<192)
2502     type = MT_BABY;
2503   else if (r<222)
2504     type = MT_FATSO;
2505   else if (r<246)
2506     type = MT_KNIGHT;
2507   else
2508     type = MT_BRUISER;
2509 
2510   newmobj = P_SpawnMobj(targ->x, targ->y, targ->z, type);
2511 
2512   /* killough 7/18/98: brain friendliness is transferred */
2513   newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND);
2514 
2515   /* killough 8/29/98: add to appropriate thread */
2516   P_UpdateThinker(&newmobj->thinker);
2517 
2518   if (P_LookForTargets(newmobj,TRUE))      /* killough 9/4/98 */
2519     P_SetMobjState(newmobj, newmobj->info->seestate);
2520 
2521     // telefrag anything in this spot
2522   P_TeleportMove(newmobj, newmobj->x, newmobj->y, TRUE); /* killough 8/9/98 */
2523 
2524   // remove self (i.e., cube).
2525   P_RemoveMobj(mo);
2526 }
2527 
A_PlayerScream(mobj_t * mo)2528 void A_PlayerScream(mobj_t *mo)
2529 {
2530   int sound = sfx_pldeth;  // Default death sound.
2531   if (gamemode != shareware && mo->health < -50)
2532     sound = sfx_pdiehi;   // IF THE PLAYER DIES LESS THAN -50% WITHOUT GIBBING
2533   S_StartSound(mo, sound);
2534 }
2535 
2536 /* cph - MBF-added codepointer functions */
2537 
2538 // killough 11/98: kill an object
A_Die(mobj_t * actor)2539 void A_Die(mobj_t *actor)
2540 {
2541   P_DamageMobj(actor, NULL, NULL, actor->health);
2542 }
2543 
2544 //
2545 // A_Detonate
2546 // killough 8/9/98: same as A_Explode, except that the damage is variable
2547 //
2548 
A_Detonate(mobj_t * mo)2549 void A_Detonate(mobj_t *mo)
2550 {
2551   P_RadiusAttack(mo, mo->target, mo->info->damage);
2552   retro_set_rumble_damage(60, 500.f);
2553 }
2554 
2555 //
2556 // killough 9/98: a mushroom explosion effect, sorta :)
2557 // Original idea: Linguica
2558 //
2559 
A_Mushroom(mobj_t * actor)2560 void A_Mushroom(mobj_t *actor)
2561 {
2562   int i, j, n = actor->info->damage;
2563 
2564   A_Explode(actor);  // First make normal explosion
2565 
2566   // Now launch mushroom cloud
2567   for (i = -n; i <= n; i += 8)
2568     for (j = -n; j <= n; j += 8)
2569       {
2570   mobj_t target = *actor, *mo;
2571   target.x += i << FRACBITS;    // Aim in many directions from source
2572   target.y += j << FRACBITS;
2573   target.z += P_AproxDistance(i,j) << (FRACBITS+2); // Aim up fairly high
2574   mo = P_SpawnMissile(actor, &target, MT_FATSHOT);  // Launch fireball
2575   mo->momx >>= 1;
2576   mo->momy >>= 1;                                   // Slow it down a bit
2577   mo->momz >>= 1;
2578   mo->flags &= ~MF_NOGRAVITY;   // Make debris fall under gravity
2579       }
2580 }
2581 
2582 //
2583 // killough 11/98
2584 //
2585 // The following were inspired by Len Pitre
2586 //
2587 // A small set of highly-sought-after code pointers
2588 //
2589 
A_Spawn(mobj_t * mo)2590 void A_Spawn(mobj_t *mo)
2591 {
2592   if (mo->state->misc1)
2593     {
2594       /* mobj_t *newmobj = */
2595       P_SpawnMobj(mo->x, mo->y, (mo->state->misc2 << FRACBITS) + mo->z,
2596       mo->state->misc1 - 1);
2597       /* CPhipps - no friendlyness (yet)
2598    newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND);
2599       */
2600     }
2601 }
2602 
A_Turn(mobj_t * mo)2603 void A_Turn(mobj_t *mo)
2604 {
2605   mo->angle += (unsigned int)(((uint64_t) mo->state->misc1 << 32) / 360);
2606 }
2607 
A_Face(mobj_t * mo)2608 void A_Face(mobj_t *mo)
2609 {
2610   mo->angle = (unsigned int)(((uint64_t) mo->state->misc1 << 32) / 360);
2611 }
2612 
A_Scratch(mobj_t * mo)2613 void A_Scratch(mobj_t *mo)
2614 {
2615   mo->target && (A_FaceTarget(mo), P_CheckMeleeRange(mo)) ?
2616     mo->state->misc2 ? S_StartSound(mo, mo->state->misc2) : (void) 0,
2617     P_DamageMobj(mo->target, mo, mo, mo->state->misc1) : (void) 0;
2618 }
2619 
A_PlaySound(mobj_t * mo)2620 void A_PlaySound(mobj_t *mo)
2621 {
2622   S_StartSound(mo->state->misc2 ? NULL : mo, mo->state->misc1);
2623 }
2624 
A_RandomJump(mobj_t * mo)2625 void A_RandomJump(mobj_t *mo)
2626 {
2627   if (P_Random(pr_randomjump) < mo->state->misc2)
2628     P_SetMobjState(mo, mo->state->misc1);
2629 }
2630 
2631 //
2632 // This allows linedef effects to be activated inside deh frames.
2633 //
2634 
A_LineEffect(mobj_t * mo)2635 void A_LineEffect(mobj_t *mo)
2636 {
2637   static line_t junk;
2638   player_t player;
2639   player_t *oldplayer;
2640   junk = *lines;
2641   oldplayer = mo->player;
2642   mo->player = &player;
2643   player.health = 100;
2644   junk.special = (short)mo->state->misc1;
2645   if (!junk.special)
2646     return;
2647   junk.tag = (short)mo->state->misc2;
2648   if (!P_UseSpecialLine(mo, &junk, 0))
2649     P_CrossSpecialLine(&junk, 0, mo);
2650   mo->state->misc1 = junk.special;
2651   mo->player = oldplayer;
2652 }
2653