1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
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 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
29 * Action Pointer Functions
30 * that are associated with states/frames.
32 *-----------------------------------------------------------------------------*/
49 #include "rockmacros.h"
51 static mobj_t
*current_actor
;
65 typedef unsigned dirtype_t
;
67 void A_Fall(mobj_t
*actor
);
68 void A_FaceTarget(mobj_t
*actor
);
69 static void P_NewChaseDir(mobj_t
*actor
);
70 void P_ZBumpCheck(mobj_t
*); // phares
74 // Enemies are allways spawned
75 // with targetplayer = -1, threshold = 0
76 // Most monsters are spawned unaware of all players,
77 // but some can be made preaware
81 // Called by P_NoiseAlert.
82 // Recursively traverse adjacent sectors,
83 // sound blocking lines cut off traversal.
85 // killough 5/5/98: reformatted, cleaned up
87 static void P_RecursiveSound(sector_t
*sec
, int soundblocks
,
92 // wake up all monsters in this sector
93 if (sec
->validcount
== validcount
&& sec
->soundtraversed
<= soundblocks
+1)
94 return; // already flooded
96 sec
->validcount
= validcount
;
97 sec
->soundtraversed
= soundblocks
+1;
98 P_SetTarget(&sec
->soundtarget
, soundtarget
);
100 for (i
=0; i
<sec
->linecount
; i
++)
103 line_t
*check
= sec
->lines
[i
];
105 if (!(check
->flags
& ML_TWOSIDED
))
108 P_LineOpening(check
);
111 continue; // closed door
113 other
=sides
[check
->sidenum
[sides
[check
->sidenum
[0]].sector
==sec
]].sector
;
115 if (!(check
->flags
& ML_SOUNDBLOCK
))
116 P_RecursiveSound(other
, soundblocks
, soundtarget
);
119 P_RecursiveSound(other
, 1, soundtarget
);
125 // If a monster yells at a player,
126 // it will alert other monsters to the player.
128 void P_NoiseAlert(mobj_t
*target
, mobj_t
*emitter
)
131 P_RecursiveSound(emitter
->subsector
->sector
, 0, target
);
138 static boolean
P_CheckMeleeRange(mobj_t
*actor
)
140 mobj_t
*pl
= actor
->target
;
142 return // killough 7/18/98: friendly monsters don't attack other friends
143 pl
&& !(actor
->flags
& pl
->flags
& MF_FRIEND
) &&
144 (P_AproxDistance(pl
->x
-actor
->x
, pl
->y
-actor
->y
) <
145 MELEERANGE
- 20*FRACUNIT
+ pl
->info
->radius
) &&
146 P_CheckSight(actor
, actor
->target
);
153 // This function tries to prevent shooting at friends
155 static boolean
P_HitFriend(mobj_t
*actor
)
157 return actor
->flags
& MF_FRIEND
&& actor
->target
&&
158 (P_AimLineAttack(actor
,
159 R_PointToAngle2(actor
->x
, actor
->y
,
160 actor
->target
->x
, actor
->target
->y
),
161 P_AproxDistance(actor
->x
-actor
->target
->x
,
162 actor
->y
-actor
->target
->y
), 0),
163 linetarget
) && linetarget
!= actor
->target
&&
164 !((linetarget
->flags
^ actor
->flags
) & MF_FRIEND
);
168 // P_CheckMissileRange
170 boolean
P_CheckMissileRange(mobj_t
*actor
)
174 if (!P_CheckSight(actor
, actor
->target
))
177 if (actor
->flags
& MF_JUSTHIT
)
178 { // the target just hit the enemy, so fight back!
179 actor
->flags
&= ~MF_JUSTHIT
;
181 /* killough 7/18/98: no friendly fire at corpses
182 * killough 11/98: prevent too much infighting among friends
183 * cph - yikes, talk about fitting everything on one line... */
186 !(actor
->flags
& MF_FRIEND
) ||
187 (actor
->target
->health
> 0 &&
188 (!(actor
->target
->flags
& MF_FRIEND
) ||
189 (actor
->target
->player
?
190 monster_infighting
|| P_Random(pr_defect
) >128 :
191 !(actor
->target
->flags
& MF_JUSTHIT
) && P_Random(pr_defect
) >128)));
194 /* killough 7/18/98: friendly monsters don't attack other friendly
195 * monsters or players (except when attacked, and then only once)
197 if (actor
->flags
& actor
->target
->flags
& MF_FRIEND
)
200 if (actor
->reactiontime
)
201 return false; // do not attack yet
203 // OPTIMIZE: get this from a global checksight
204 dist
= P_AproxDistance ( actor
->x
-actor
->target
->x
,
205 actor
->y
-actor
->target
->y
) - 64*FRACUNIT
;
207 if (!actor
->info
->meleestate
)
208 dist
-= 128*FRACUNIT
; // no melee attack, so fire more
212 if (actor
->type
== MT_VILE
)
214 return false; // too far away
217 if (actor
->type
== MT_UNDEAD
)
220 return false; // close for fist attack
224 if (actor
->type
== MT_CYBORG
||
225 actor
->type
== MT_SPIDER
||
226 actor
->type
== MT_SKULL
)
232 if (actor
->type
== MT_CYBORG
&& dist
> 160)
235 if (P_Random(pr_missrange
) < dist
)
238 if (P_HitFriend(actor
))
249 * Returns true if the object is on a lift. Used for AI,
250 * since it may indicate the need for crowded conditions,
251 * or that a monster should stay on the lift for a while
252 * while it goes up or down.
255 static boolean
P_IsOnLift(const mobj_t
*actor
)
257 const sector_t
*sec
= actor
->subsector
->sector
;
261 // Short-circuit: it's on a lift which is active.
262 if (sec
->floordata
&& ((thinker_t
*) sec
->floordata
)->function
==T_PlatRaise
)
265 // Check to see if it's in a sector which can be activated as a lift.
266 if ((line
.tag
= sec
->tag
))
267 for (l
= -1; (l
= P_FindLineFromLineTag(&line
, l
)) >= 0;)
268 switch (lines
[l
].special
)
270 case 10: case 14: case 15: case 20: case 21: case 22:
271 case 47: case 53: case 62: case 66: case 67: case 68:
272 case 87: case 88: case 95: case 120: case 121: case 122:
273 case 123: case 143: case 162: case 163: case 181: case 182:
274 case 144: case 148: case 149: case 211: case 227: case 228:
275 case 231: case 232: case 235: case 236:
287 * Returns nonzero if the object is under damage based on
288 * their current position. Returns 1 if the damage is moderate,
289 * -1 if it is serious. Used for AI.
292 static int P_IsUnderDamage(mobj_t
*actor
)
294 const struct msecnode_s
*seclist
;
295 const ceiling_t
*cl
; // Crushing ceiling
297 for (seclist
=actor
->touching_sectorlist
; seclist
; seclist
=seclist
->m_tnext
)
298 if ((cl
= seclist
->m_sector
->ceilingdata
) &&
299 cl
->thinker
.function
== T_MoveCeiling
)
300 dir
|= cl
->direction
;
306 // Move in the current direction,
307 // returns false if the move is blocked.
310 static fixed_t xspeed
[8] = {FRACUNIT
,47000,0,-47000,-FRACUNIT
,-47000,0,47000};
311 static fixed_t yspeed
[8] = {0,47000,FRACUNIT
,47000,0,-47000,-FRACUNIT
,-47000};
313 // 1/11/98 killough: Limit removed on special lines crossed
314 extern line_t
**spechit
; // New code -- killough
315 extern int numspechit
;
317 static boolean
P_Move(mobj_t
*actor
, boolean dropoff
) /* killough 9/12/98 */
319 fixed_t tryx
, tryy
, deltax
, deltay
, origx
, origy
;
321 int movefactor
= ORIG_FRICTION_FACTOR
; // killough 10/98
322 int friction
= ORIG_FRICTION
;
325 if (actor
->movedir
== DI_NODIR
)
329 if ((unsigned)actor
->movedir
>= 8)
330 I_Error ("P_Move: Weird actor->movedir!");
333 // killough 10/98: make monsters get affected by ice and sludge too:
335 if (monster_friction
)
336 movefactor
= P_GetMoveFactor(actor
, &friction
);
338 speed
= actor
->info
->speed
;
340 if (friction
< ORIG_FRICTION
&& // sludge
341 !(speed
= ((ORIG_FRICTION_FACTOR
- (ORIG_FRICTION_FACTOR
-movefactor
)/2)
342 * speed
) / ORIG_FRICTION_FACTOR
))
343 speed
= 1; // always give the monster a little bit of speed
345 tryx
= (origx
= actor
->x
) + (deltax
= speed
* xspeed
[actor
->movedir
]);
346 tryy
= (origy
= actor
->y
) + (deltay
= speed
* yspeed
[actor
->movedir
]);
348 try_ok
= P_TryMove(actor
, tryx
, tryy
, dropoff
);
351 // Let normal momentum carry them, instead of steptoeing them across ice.
353 if (try_ok
&& friction
> ORIG_FRICTION
)
357 movefactor
*= FRACUNIT
/ ORIG_FRICTION_FACTOR
/ 4;
358 actor
->momx
+= FixedMul(deltax
, movefactor
);
359 actor
->momy
+= FixedMul(deltay
, movefactor
);
363 { // open any specials
366 if (actor
->flags
& MF_FLOAT
&& floatok
)
368 if (actor
->z
< tmfloorz
) // must adjust height
369 actor
->z
+= FLOATSPEED
;
371 actor
->z
-= FLOATSPEED
;
373 actor
->flags
|= MF_INFLOAT
;
381 actor
->movedir
= DI_NODIR
;
383 /* if the special is not a door that can be opened, return false
385 * killough 8/9/98: this is what caused monsters to get stuck in
386 * doortracks, because it thought that the monster freed itself
387 * by opening a door, even if it was moving towards the doortrack,
388 * and not the door itself.
390 * killough 9/9/98: If a line blocking the monster is activated,
391 * return true 90% of the time. If a line blocking the monster is
392 * not activated, but some other line is, return false 90% of the
393 * time. A bit of randomness is needed to ensure it's free from
394 * lockups, but for most cases, it returns the correct result.
396 * Do NOT simply return false 1/4th of the time (causes monsters to
397 * back out when they shouldn't, and creates secondary stickiness).
400 for (good
= false; numspechit
--; )
401 if (P_UseSpecialLine(actor
, spechit
[numspechit
], 0))
402 good
|= spechit
[numspechit
] == blockline
? 1 : 2;
404 /* cph - compatibility maze here
405 * Boom v2.01 and orig. Doom return "good"
406 * Boom v2.02 and LxDoom return good && (P_Random(pr_trywalk)&3)
407 * MBF plays even more games
409 if (!good
|| comp
[comp_doorstuck
]) return good
;
411 return (P_Random(pr_trywalk
)&3); /* jff 8/13/98 */
412 else /* finally, MBF code */
413 return ((P_Random(pr_opendoor
) >= 230) ^ (good
& 1));
416 actor
->flags
&= ~MF_INFLOAT
;
418 /* killough 11/98: fall more slowly, under gravity, if felldown==true */
419 if (!(actor
->flags
& MF_FLOAT
) &&
420 (!felldown
|| !mbf_features
))
421 actor
->z
= actor
->floorz
;
429 * killough 9/12/98: Same as P_Move, except smarter
432 static boolean
P_SmartMove(mobj_t
*actor
)
434 mobj_t
*target
= actor
->target
;
435 int on_lift
, dropoff
= false, under_damage
;
437 /* killough 9/12/98: Stay on a lift if target is on one */
438 on_lift
= !comp
[comp_staylift
]
439 && target
&& target
->health
> 0
440 && target
->subsector
->sector
->tag
==actor
->subsector
->sector
->tag
&&
443 under_damage
= monster_avoid_hazards
&& P_IsUnderDamage(actor
);
445 // killough 10/98: allow dogs to drop off of taller ledges sometimes.
446 // dropoff==1 means always allow it, dropoff==2 means only up to 128 high,
447 // and only if the target is immediately on the other side of the line.
450 if (actor
->type
== MT_DOGS
&& target
&& dog_jumping
&&
451 !((target
->flags
^ actor
->flags
) & MF_FRIEND
) &&
452 P_AproxDistance(actor
->x
- target
->x
,
453 actor
->y
- target
->y
) < FRACUNIT
*144 &&
454 P_Random(pr_dropoff
) < 235)
458 if (!P_Move(actor
, dropoff
))
461 // killough 9/9/98: avoid crushing ceilings or other damaging areas
463 (on_lift
&& P_Random(pr_stayonlift
) < 230 && // Stay on lift
466 (monster_avoid_hazards
&& !under_damage
&& // Get away from damage
467 (under_damage
= P_IsUnderDamage(actor
)) &&
468 (under_damage
< 0 || P_Random(pr_avoidcrush
) < 200))
470 actor
->movedir
= DI_NODIR
; // avoid the area (most of the time anyway)
477 // Attempts to move actor on
478 // in its current (ob->moveangle) direction.
479 // If blocked by either a wall or an actor
481 // If move is either clear or blocked only by a door,
482 // returns TRUE and sets...
483 // If a door is in the way,
484 // an OpenDoor call is made to start it opening.
487 boolean
P_TryWalk(mobj_t
*actor
)
489 if (!P_SmartMove(actor
))
491 actor
->movecount
= P_Random(pr_trywalk
)&15;
500 // Most of P_NewChaseDir(), except for what
501 // determines the new direction to take
504 static void P_DoNewChaseDir(mobj_t
*actor
, fixed_t deltax
, fixed_t deltay
)
506 dirtype_t xdir
, ydir
, tdir
;
507 dirtype_t olddir
= actor
->movedir
;
508 dirtype_t turnaround
= olddir
;
510 if (turnaround
!= DI_NODIR
) // find reverse direction
514 deltax
> 10*FRACUNIT
? DI_EAST
:
515 deltax
< -10*FRACUNIT
? DI_WEST
: DI_NODIR
;
518 deltay
< -10*FRACUNIT
? DI_SOUTH
:
519 deltay
> 10*FRACUNIT
? DI_NORTH
: DI_NODIR
;
522 if (xdir
!= DI_NODIR
&& ydir
!= DI_NODIR
&& turnaround
!=
523 (actor
->movedir
= deltay
< 0 ? deltax
> 0 ? DI_SOUTHEAST
: DI_SOUTHWEST
:
524 deltax
> 0 ? DI_NORTHEAST
: DI_NORTHWEST
) && P_TryWalk(actor
))
527 // try other directions
528 if (P_Random(pr_newchase
) > 200 || abs(deltay
)>abs(deltax
))
529 tdir
= xdir
, xdir
= ydir
, ydir
= tdir
;
531 if ((xdir
== turnaround
? xdir
= DI_NODIR
: xdir
) != DI_NODIR
&&
532 (actor
->movedir
= xdir
, P_TryWalk(actor
)))
533 return; // either moved forward or attacked
535 if ((ydir
== turnaround
? ydir
= DI_NODIR
: ydir
) != DI_NODIR
&&
536 (actor
->movedir
= ydir
, P_TryWalk(actor
)))
539 // there is no direct path to the player, so pick another direction.
540 if (olddir
!= DI_NODIR
&& (actor
->movedir
= olddir
, P_TryWalk(actor
)))
543 // randomly determine direction of search
544 if (P_Random(pr_newchasedir
) & 1)
546 for (tdir
= DI_EAST
; tdir
<= DI_SOUTHEAST
; tdir
++)
547 if (tdir
!= turnaround
&& (actor
->movedir
= tdir
, P_TryWalk(actor
)))
551 for (tdir
= DI_SOUTHEAST
; tdir
!= (dirtype_t
)(DI_EAST
-1); tdir
--)
552 if (tdir
!= turnaround
&& (actor
->movedir
= tdir
, P_TryWalk(actor
)))
555 if ((actor
->movedir
= turnaround
) != DI_NODIR
&& !P_TryWalk(actor
))
556 actor
->movedir
= DI_NODIR
;
562 // Monsters try to move away from tall dropoffs.
564 // In Doom, they were never allowed to hang over dropoffs,
565 // and would remain stuck if involuntarily forced over one.
566 // This logic, combined with p_map.c (P_TryMove), allows
567 // monsters to free themselves without making them tend to
568 // hang over dropoffs.
570 static fixed_t dropoff_deltax
, dropoff_deltay
, floorz
;
572 static boolean
PIT_AvoidDropoff(line_t
*line
)
574 if (line
->backsector
&& // Ignore one-sided linedefs
575 tmbbox
[BOXRIGHT
] > line
->bbox
[BOXLEFT
] &&
576 tmbbox
[BOXLEFT
] < line
->bbox
[BOXRIGHT
] &&
577 tmbbox
[BOXTOP
] > line
->bbox
[BOXBOTTOM
] && // Linedef must be contacted
578 tmbbox
[BOXBOTTOM
] < line
->bbox
[BOXTOP
] &&
579 P_BoxOnLineSide(tmbbox
, line
) == -1)
581 fixed_t front
= line
->frontsector
->floorheight
;
582 fixed_t back
= line
->backsector
->floorheight
;
585 // The monster must contact one of the two floors,
586 // and the other must be a tall dropoff (more than 24).
588 if (back
== floorz
&& front
< floorz
- FRACUNIT
*24)
589 angle
= R_PointToAngle2(0,0,line
->dx
,line
->dy
); // front side dropoff
591 if (front
== floorz
&& back
< floorz
- FRACUNIT
*24)
592 angle
= R_PointToAngle2(line
->dx
,line
->dy
,0,0); // back side dropoff
596 // Move away from dropoff at a standard speed.
597 // Multiple contacted linedefs are cumulative (e.g. hanging over corner)
598 dropoff_deltax
-= finesine
[angle
>> ANGLETOFINESHIFT
]*32;
599 dropoff_deltay
+= finecosine
[angle
>> ANGLETOFINESHIFT
]*32;
608 static fixed_t
P_AvoidDropoff(mobj_t
*actor
)
610 int yh
=((tmbbox
[BOXTOP
] = actor
->y
+actor
->radius
)-bmaporgy
)>>MAPBLOCKSHIFT
;
611 int yl
=((tmbbox
[BOXBOTTOM
]= actor
->y
-actor
->radius
)-bmaporgy
)>>MAPBLOCKSHIFT
;
612 int xh
=((tmbbox
[BOXRIGHT
] = actor
->x
+actor
->radius
)-bmaporgx
)>>MAPBLOCKSHIFT
;
613 int xl
=((tmbbox
[BOXLEFT
] = actor
->x
-actor
->radius
)-bmaporgx
)>>MAPBLOCKSHIFT
;
616 floorz
= actor
->z
; // remember floor height
618 dropoff_deltax
= dropoff_deltay
= 0;
623 for (bx
=xl
; bx
<=xh
; bx
++)
624 for (by
=yl
; by
<=yh
; by
++)
625 P_BlockLinesIterator(bx
, by
, PIT_AvoidDropoff
); // all contacted lines
627 return dropoff_deltax
| dropoff_deltay
; // Non-zero if movement prescribed
633 // killough 9/8/98: Split into two functions
636 static void P_NewChaseDir(mobj_t
*actor
)
638 mobj_t
*target
= actor
->target
;
639 fixed_t deltax
= target
->x
- actor
->x
;
640 fixed_t deltay
= target
->y
- actor
->y
;
642 // killough 8/8/98: sometimes move away from target, keeping distance
644 // 1) Stay a certain distance away from a friend, to avoid being in their way
645 // 2) Take advantage over an enemy without missiles, by keeping distance
647 actor
->strafecount
= 0;
650 if (actor
->floorz
- actor
->dropoffz
> FRACUNIT
*24 &&
651 actor
->z
<= actor
->floorz
&&
652 !(actor
->flags
& (MF_DROPOFF
|MF_FLOAT
)) &&
653 !comp
[comp_dropoff
] &&
654 P_AvoidDropoff(actor
)) /* Move away from dropoff */
656 P_DoNewChaseDir(actor
, dropoff_deltax
, dropoff_deltay
);
658 // If moving away from dropoff, set movecount to 1 so that
659 // small steps are taken to get monster away from dropoff.
661 actor
->movecount
= 1;
666 fixed_t dist
= P_AproxDistance(deltax
, deltay
);
668 // Move away from friends when too close, except
669 // in certain situations (e.g. a crowded lift)
671 if (actor
->flags
& target
->flags
& MF_FRIEND
&&
672 distfriend
<< FRACBITS
> dist
&&
673 !P_IsOnLift(target
) && !P_IsUnderDamage(actor
))
675 deltax
= -deltax
, deltay
= -deltay
;
677 if (target
->health
> 0 && (actor
->flags
^ target
->flags
) & MF_FRIEND
)
678 { // Live enemy target
679 if (monster_backing
&&
680 actor
->info
->missilestate
&& actor
->type
!= MT_SKULL
&&
681 ((!target
->info
->missilestate
&& dist
< MELEERANGE
*2) ||
682 (target
->player
&& dist
< MELEERANGE
*3 &&
683 (target
->player
->readyweapon
== wp_fist
||
684 target
->player
->readyweapon
== wp_chainsaw
))))
685 { // Back away from melee attacker
686 actor
->strafecount
= P_Random(pr_enemystrafe
) & 15;
687 deltax
= -deltax
, deltay
= -deltay
;
693 P_DoNewChaseDir(actor
, deltax
, deltay
);
695 // If strafing, set movecount to strafecount so that old Doom
696 // logic still works the same, except in the strafing part
698 if (actor
->strafecount
)
699 actor
->movecount
= actor
->strafecount
;
705 // killough 9/9/98: whether a target is visible to a monster
708 static boolean
P_IsVisible(mobj_t
*actor
, mobj_t
*mo
, boolean allaround
)
712 angle_t an
= R_PointToAngle2(actor
->x
, actor
->y
,
713 mo
->x
, mo
->y
) - actor
->angle
;
714 if (an
> ANG90
&& an
< ANG270
&&
715 P_AproxDistance(mo
->x
-actor
->x
, mo
->y
-actor
->y
) > MELEERANGE
)
718 return P_CheckSight(actor
, mo
);
726 // Finds monster targets for other monsters
729 static int current_allaround
;
731 static boolean
PIT_FindTarget(mobj_t
*mo
)
733 mobj_t
*actor
= current_actor
;
735 if (!((mo
->flags
^ actor
->flags
) & MF_FRIEND
&& // Invalid target
736 mo
->health
> 0 && (mo
->flags
& MF_COUNTKILL
|| mo
->type
== MT_SKULL
)))
739 // If the monster is already engaged in a one-on-one attack
740 // with a healthy friend, don't attack around 60% the time
742 const mobj_t
*targ
= mo
->target
;
743 if (targ
&& targ
->target
== mo
&&
744 P_Random(pr_skiptarget
) > 100 &&
745 (targ
->flags
^ mo
->flags
) & MF_FRIEND
&&
746 targ
->health
*2 >= targ
->info
->spawnhealth
)
750 if (!P_IsVisible(actor
, mo
, current_allaround
))
753 P_SetTarget(&actor
->lastenemy
, actor
->target
); // Remember previous target
754 P_SetTarget(&actor
->target
, mo
); // Found target
756 // Move the selected monster to the end of its associated
757 // list, so that it gets searched last next time.
760 thinker_t
*cap
= &thinkerclasscap
[mo
->flags
& MF_FRIEND
?
761 th_friends
: th_enemies
];
762 (mo
->thinker
.cprev
->cnext
= mo
->thinker
.cnext
)->cprev
= mo
->thinker
.cprev
;
763 (mo
->thinker
.cprev
= cap
->cprev
)->cnext
= &mo
->thinker
;
764 (mo
->thinker
.cnext
= cap
)->cprev
= &mo
->thinker
;
772 // If allaround is false, only look 180 degrees in front.
773 // Returns true if a player is targeted.
776 static boolean
P_LookForPlayers(mobj_t
*actor
, boolean allaround
)
781 if (actor
->flags
& MF_FRIEND
)
782 { // killough 9/9/98: friendly monsters go about players differently
786 if (!allaround
) // If you want friendly monsters not to awaken unprovoked
790 // Go back to a player, no matter whether it's visible or not
791 for (anyone
=0; anyone
<=1; anyone
++)
792 for (c
=0; c
<MAXPLAYERS
; c
++)
793 if (playeringame
[c
] && players
[c
].playerstate
==PST_LIVE
&&
794 (anyone
|| P_IsVisible(actor
, players
[c
].mo
, allaround
)))
796 P_SetTarget(&actor
->target
, players
[c
].mo
);
799 // get out of refiring loop, to avoid hitting player accidentally
801 if (actor
->info
->missilestate
)
803 P_SetMobjState(actor
, actor
->info
->seestate
);
804 actor
->flags
&= ~MF_JUSTHIT
;
813 // Change mask of 3 to (MAXPLAYERS-1) -- killough 2/15/98:
814 stop
= (actor
->lastlook
-1)&(MAXPLAYERS
-1);
818 stopc
= !mbf_features
&&
819 !demo_compatibility
&& monsters_remember
?
820 MAXPLAYERS
: 2; // killough 9/9/98
822 for (;; actor
->lastlook
= (actor
->lastlook
+1)&(MAXPLAYERS
-1))
824 if (!playeringame
[actor
->lastlook
])
827 // killough 2/15/98, 9/9/98:
828 if (c
++ == stopc
|| actor
->lastlook
== stop
) // done looking
831 player
= &players
[actor
->lastlook
];
833 if (player
->health
<= 0)
836 if (!P_IsVisible(actor
, player
->mo
, allaround
))
839 P_SetTarget(&actor
->target
, player
->mo
);
841 /* killough 9/9/98: give monsters a threshold towards getting players
842 * (we don't want it to be too easy for a player with dogs :)
844 if (!comp
[comp_pursuit
])
845 actor
->threshold
= 60;
852 // Friendly monsters, by Lee Killough 7/18/98
854 // Friendly monsters go after other monsters first, but
855 // also return to owner if they cannot find any targets.
856 // A marine's best friend :) killough 7/18/98, 9/98
859 static boolean
P_LookForMonsters(mobj_t
*actor
, boolean allaround
)
863 if (demo_compatibility
)
866 if (actor
->lastenemy
&& actor
->lastenemy
->health
> 0 && monsters_remember
&&
867 !(actor
->lastenemy
->flags
& actor
->flags
& MF_FRIEND
)) // not friends
869 P_SetTarget(&actor
->target
, actor
->lastenemy
);
870 P_SetTarget(&actor
->lastenemy
, NULL
);
874 /* Old demos do not support monster-seeking bots */
878 // Search the threaded list corresponding to this object's potential targets
879 cap
= &thinkerclasscap
[actor
->flags
& MF_FRIEND
? th_enemies
: th_friends
];
881 // Search for new enemy
883 if (cap
->cnext
!= cap
) // Empty list? bail out early
885 int x
= (actor
->x
- bmaporgx
)>>MAPBLOCKSHIFT
;
886 int y
= (actor
->y
- bmaporgy
)>>MAPBLOCKSHIFT
;
889 current_actor
= actor
;
890 current_allaround
= allaround
;
892 // Search first in the immediate vicinity.
894 if (!P_BlockThingsIterator(x
, y
, PIT_FindTarget
))
901 if (!P_BlockThingsIterator(x
+i
, y
-d
, PIT_FindTarget
) ||
902 !P_BlockThingsIterator(x
+i
, y
+d
, PIT_FindTarget
))
906 if (!P_BlockThingsIterator(x
-d
, y
+i
, PIT_FindTarget
) ||
907 !P_BlockThingsIterator(x
+d
, y
+i
, PIT_FindTarget
))
909 while (--i
+ d
>= 0);
912 { // Random number of monsters, to prevent patterns from forming
913 int n
= (P_Random(pr_friends
) & 31) + 15;
915 for (th
= cap
->cnext
; th
!= cap
; th
= th
->cnext
)
918 // Only a subset of the monsters were searched. Move all of
919 // the ones which were searched so far, to the end of the list.
921 (cap
->cnext
->cprev
= cap
->cprev
)->cnext
= cap
->cnext
;
922 (cap
->cprev
= th
->cprev
)->cnext
= cap
;
923 (th
->cprev
= cap
)->cnext
= th
;
927 if (!PIT_FindTarget((mobj_t
*) th
)) // If target sighted
932 return false; // No monster found
938 // killough 9/5/98: look for targets to go after, depending on kind of monster
941 static boolean
P_LookForTargets(mobj_t
*actor
, int allaround
)
943 return actor
->flags
& MF_FRIEND
?
944 P_LookForMonsters(actor
, allaround
) || P_LookForPlayers (actor
, allaround
):
945 P_LookForPlayers (actor
, allaround
) || P_LookForMonsters(actor
, allaround
);
951 // killough 9/8/98: Help friends in danger of dying
954 static boolean
P_HelpFriend(mobj_t
*actor
)
958 // If less than 33% health, self-preservation rules
959 if (actor
->health
*3 < actor
->info
->spawnhealth
)
962 current_actor
= actor
;
963 current_allaround
= true;
965 // Possibly help a friend under 50% health
966 cap
= &thinkerclasscap
[actor
->flags
& MF_FRIEND
? th_friends
: th_enemies
];
968 for (th
= cap
->cnext
; th
!= cap
; th
= th
->cnext
)
969 if (((mobj_t
*) th
)->health
*2 >= ((mobj_t
*) th
)->info
->spawnhealth
)
971 if (P_Random(pr_helpfriend
) < 180)
975 if (((mobj_t
*) th
)->flags
& MF_JUSTHIT
&&
976 ((mobj_t
*) th
)->target
&&
977 ((mobj_t
*) th
)->target
!= actor
->target
&&
978 !PIT_FindTarget(((mobj_t
*) th
)->target
))
980 // Ignore any attacking monsters, while searching for friend
981 actor
->threshold
= BASETHRESHOLD
;
990 // DOOM II special, map 32.
991 // Uses special tag 666.
993 void A_KeenDie(mobj_t
* mo
)
1000 // scan the remaining thinkers to see if all Keens are dead
1002 for (th
= thinkercap
.next
; th
!= &thinkercap
; th
=th
->next
)
1003 if (th
->function
== P_MobjThinker
)
1005 mobj_t
*mo2
= (mobj_t
*) th
;
1006 if (mo2
!= mo
&& mo2
->type
== mo
->type
&& mo2
->health
> 0)
1007 return; // other Keen not dead
1011 EV_DoDoor(&junk
,p_open
);
1021 // Stay in state until a player is sighted.
1024 void A_Look(mobj_t
*actor
)
1026 mobj_t
*targ
= actor
->subsector
->sector
->soundtarget
;
1027 actor
->threshold
= 0; // any shot will wake up
1029 /* killough 7/18/98:
1030 * Friendly monsters go after other monsters first, but
1031 * also return to player, without attacking them, if they
1032 * cannot find any targets. A marine's best friend :)
1034 actor
->pursuecount
= 0;
1036 if (!(actor
->flags
& MF_FRIEND
&& P_LookForTargets(actor
, false)) &&
1037 !((targ
= actor
->subsector
->sector
->soundtarget
) &&
1038 targ
->flags
& MF_SHOOTABLE
&&
1039 (P_SetTarget(&actor
->target
, targ
),
1040 !(actor
->flags
& MF_AMBUSH
) || P_CheckSight(actor
, targ
))) &&
1041 (actor
->flags
& MF_FRIEND
|| !P_LookForTargets(actor
, false)))
1044 // go into chase state
1046 if (actor
->info
->seesound
)
1049 switch (actor
->info
->seesound
)
1054 sound
= sfx_posit1
+P_Random(pr_see
)%3;
1059 sound
= sfx_bgsit1
+P_Random(pr_see
)%2;
1063 sound
= actor
->info
->seesound
;
1066 if (actor
->type
==MT_SPIDER
|| actor
->type
== MT_CYBORG
)
1067 S_StartSound(NULL
, sound
); // full volume
1069 S_StartSound(actor
, sound
);
1071 P_SetMobjState(actor
, actor
->info
->seestate
);
1078 // Allows monsters to continue movement while attacking
1081 void A_KeepChasing(mobj_t
*actor
)
1083 if (actor
->movecount
)
1086 if (actor
->strafecount
)
1087 actor
->strafecount
--;
1094 // Actor has a melee attack,
1095 // so it tries to close as fast as possible
1098 void A_Chase(mobj_t
*actor
)
1100 if (actor
->reactiontime
)
1101 actor
->reactiontime
--;
1103 if (actor
->threshold
) { /* modify target threshold */
1104 if (!actor
->target
|| actor
->target
->health
<= 0)
1105 actor
->threshold
= 0;
1110 /* turn towards movement direction if not there yet
1111 * killough 9/7/98: keep facing towards target if strafing or backing out
1114 if (actor
->strafecount
)
1115 A_FaceTarget(actor
);
1116 else if (actor
->movedir
< 8)
1118 int delta
= (actor
->angle
&= (7<<29)) - (actor
->movedir
<< 29);
1120 actor
->angle
-= ANG90
/2;
1123 actor
->angle
+= ANG90
/2;
1126 if (!actor
->target
|| !(actor
->target
->flags
&MF_SHOOTABLE
))
1128 if (!P_LookForTargets(actor
,true)) // look for a new target
1129 P_SetMobjState(actor
, actor
->info
->spawnstate
); // no new target
1133 // do not attack twice in a row
1134 if (actor
->flags
& MF_JUSTATTACKED
)
1136 actor
->flags
&= ~MF_JUSTATTACKED
;
1137 if (gameskill
!= sk_nightmare
&& !fastparm
)
1138 P_NewChaseDir(actor
);
1142 // check for melee attack
1143 if (actor
->info
->meleestate
&& P_CheckMeleeRange(actor
))
1145 if (actor
->info
->attacksound
)
1146 S_StartSound(actor
, actor
->info
->attacksound
);
1147 P_SetMobjState(actor
, actor
->info
->meleestate
);
1148 /* killough 8/98: remember an attack
1149 * cph - DEMOSYNC? */
1150 if (!actor
->info
->missilestate
)
1151 actor
->flags
|= MF_JUSTHIT
;
1155 // check for missile attack
1156 if (actor
->info
->missilestate
)
1157 if (!(gameskill
< sk_nightmare
&& !fastparm
&& actor
->movecount
))
1158 if (P_CheckMissileRange(actor
))
1160 P_SetMobjState(actor
, actor
->info
->missilestate
);
1161 actor
->flags
|= MF_JUSTATTACKED
;
1165 if (!actor
->threshold
) {
1167 { /* killough 9/9/98: for backward demo compatibility */
1168 if (netgame
&& !P_CheckSight(actor
, actor
->target
) &&
1169 P_LookForPlayers(actor
, true))
1172 /* killough 7/18/98, 9/9/98: new monster AI */
1173 else if (help_friends
&& P_HelpFriend(actor
))
1174 return; /* killough 9/8/98: Help friends in need */
1175 /* Look for new targets if current one is bad or is out of view */
1176 else if (actor
->pursuecount
)
1177 actor
->pursuecount
--;
1179 /* Our pursuit time has expired. We're going to think about
1180 * changing targets */
1181 actor
->pursuecount
= BASETHRESHOLD
;
1183 /* Unless (we have a live target
1184 * and it's not friendly
1185 * and we can see it)
1186 * try to find a new one; return if sucessful */
1188 if (!(actor
->target
&& actor
->target
->health
> 0 &&
1189 ((comp
[comp_pursuit
] && !netgame
) ||
1190 (((actor
->target
->flags
^ actor
->flags
) & MF_FRIEND
||
1191 (!(actor
->flags
& MF_FRIEND
) && monster_infighting
)) &&
1192 P_CheckSight(actor
, actor
->target
))))
1193 && P_LookForTargets(actor
, true))
1196 /* (Current target was good, or no new target was found.)
1198 * If monster is a missile-less friend, give up pursuit and
1199 * return to player, if no attacks have occurred recently.
1202 if (!actor
->info
->missilestate
&& actor
->flags
& MF_FRIEND
) {
1203 if (actor
->flags
& MF_JUSTHIT
) /* if recent action, */
1204 actor
->flags
&= ~MF_JUSTHIT
; /* keep fighting */
1205 else if (P_LookForPlayers(actor
, true)) /* else return to player */
1211 if (actor
->strafecount
)
1212 actor
->strafecount
--;
1214 // chase towards player
1215 if (--actor
->movecount
<0 || !P_SmartMove(actor
))
1216 P_NewChaseDir(actor
);
1218 // make active sound
1219 if (actor
->info
->activesound
&& P_Random(pr_see
)<3)
1220 S_StartSound(actor
, actor
->info
->activesound
);
1226 void A_FaceTarget(mobj_t
*actor
)
1230 actor
->flags
&= ~MF_AMBUSH
;
1231 actor
->angle
= R_PointToAngle2(actor
->x
, actor
->y
,
1232 actor
->target
->x
, actor
->target
->y
);
1233 if (actor
->target
->flags
& MF_SHADOW
)
1234 { // killough 5/5/98: remove dependence on order of evaluation:
1235 int t
= P_Random(pr_facetarget
);
1236 actor
->angle
+= (t
-P_Random(pr_facetarget
))<<21;
1244 void A_PosAttack(mobj_t
*actor
)
1246 int angle
, damage
, slope
, t
;
1250 A_FaceTarget(actor
);
1251 angle
= actor
->angle
;
1252 slope
= P_AimLineAttack(actor
, angle
, MISSILERANGE
, 0); /* killough 8/2/98 */
1253 S_StartSound(actor
, sfx_pistol
);
1255 // killough 5/5/98: remove dependence on order of evaluation:
1256 t
= P_Random(pr_posattack
);
1257 angle
+= (t
- P_Random(pr_posattack
))<<20;
1258 damage
= (P_Random(pr_posattack
)%5 + 1)*3;
1259 P_LineAttack(actor
, angle
, MISSILERANGE
, slope
, damage
);
1262 void A_SPosAttack(mobj_t
* actor
)
1264 int i
, bangle
, slope
;
1268 S_StartSound(actor
, sfx_shotgn
);
1269 A_FaceTarget(actor
);
1270 bangle
= actor
->angle
;
1271 slope
= P_AimLineAttack(actor
, bangle
, MISSILERANGE
, 0); /* killough 8/2/98 */
1273 { // killough 5/5/98: remove dependence on order of evaluation:
1274 int t
= P_Random(pr_sposattack
);
1275 int angle
= bangle
+ ((t
- P_Random(pr_sposattack
))<<20);
1276 int damage
= ((P_Random(pr_sposattack
)%5)+1)*3;
1277 P_LineAttack(actor
, angle
, MISSILERANGE
, slope
, damage
);
1281 void A_CPosAttack(mobj_t
*actor
)
1283 int angle
, bangle
, damage
, slope
, t
;
1287 S_StartSound(actor
, sfx_shotgn
);
1288 A_FaceTarget(actor
);
1289 bangle
= actor
->angle
;
1290 slope
= P_AimLineAttack(actor
, bangle
, MISSILERANGE
, 0); /* killough 8/2/98 */
1292 // killough 5/5/98: remove dependence on order of evaluation:
1293 t
= P_Random(pr_cposattack
);
1294 angle
= bangle
+ ((t
- P_Random(pr_cposattack
))<<20);
1295 damage
= ((P_Random(pr_cposattack
)%5)+1)*3;
1296 P_LineAttack(actor
, angle
, MISSILERANGE
, slope
, damage
);
1299 void A_CPosRefire(mobj_t
*actor
)
1301 // keep firing unless target got out of sight
1302 A_FaceTarget(actor
);
1304 /* killough 12/98: Stop firing if a friend has gotten in the way */
1305 if (P_HitFriend(actor
))
1308 /* killough 11/98: prevent refiring on friends continuously */
1309 if (P_Random(pr_cposrefire
) < 40) {
1310 if (actor
->target
&& actor
->flags
& actor
->target
->flags
& MF_FRIEND
)
1316 if (!actor
->target
|| actor
->target
->health
<= 0
1317 || !P_CheckSight(actor
, actor
->target
))
1318 stop
: P_SetMobjState(actor
, actor
->info
->seestate
);
1321 void A_SpidRefire(mobj_t
* actor
)
1323 // keep firing unless target got out of sight
1324 A_FaceTarget(actor
);
1326 /* killough 12/98: Stop firing if a friend has gotten in the way */
1327 if (P_HitFriend(actor
))
1330 if (P_Random(pr_spidrefire
) < 10)
1333 // killough 11/98: prevent refiring on friends continuously
1334 if (!actor
->target
|| actor
->target
->health
<= 0
1335 || actor
->flags
& actor
->target
->flags
& MF_FRIEND
1336 || !P_CheckSight(actor
, actor
->target
))
1337 stop
: P_SetMobjState(actor
, actor
->info
->seestate
);
1340 void A_BspiAttack(mobj_t
*actor
)
1344 A_FaceTarget(actor
);
1345 P_SpawnMissile(actor
, actor
->target
, MT_ARACHPLAZ
); // launch a missile
1352 void A_TroopAttack(mobj_t
*actor
)
1356 A_FaceTarget(actor
);
1357 if (P_CheckMeleeRange(actor
))
1360 S_StartSound(actor
, sfx_claw
);
1361 damage
= (P_Random(pr_troopattack
)%8+1)*3;
1362 P_DamageMobj(actor
->target
, actor
, actor
, damage
);
1365 P_SpawnMissile(actor
, actor
->target
, MT_TROOPSHOT
); // launch a missile
1368 void A_SargAttack(mobj_t
*actor
)
1372 A_FaceTarget(actor
);
1373 if (P_CheckMeleeRange(actor
))
1375 int damage
= ((P_Random(pr_sargattack
)%10)+1)*4;
1376 P_DamageMobj(actor
->target
, actor
, actor
, damage
);
1380 void A_HeadAttack(mobj_t
*actor
)
1384 A_FaceTarget (actor
);
1385 if (P_CheckMeleeRange(actor
))
1387 int damage
= (P_Random(pr_headattack
)%6+1)*10;
1388 P_DamageMobj(actor
->target
, actor
, actor
, damage
);
1391 P_SpawnMissile(actor
, actor
->target
, MT_HEADSHOT
); // launch a missile
1394 void A_CyberAttack(mobj_t
*actor
)
1398 A_FaceTarget(actor
);
1399 P_SpawnMissile(actor
, actor
->target
, MT_ROCKET
);
1402 void A_BruisAttack(mobj_t
*actor
)
1406 if (P_CheckMeleeRange(actor
))
1409 S_StartSound(actor
, sfx_claw
);
1410 damage
= (P_Random(pr_bruisattack
)%8+1)*10;
1411 P_DamageMobj(actor
->target
, actor
, actor
, damage
);
1414 P_SpawnMissile(actor
, actor
->target
, MT_BRUISERSHOT
); // launch a missile
1421 void A_SkelMissile(mobj_t
*actor
)
1428 A_FaceTarget (actor
);
1429 actor
->z
+= 16*FRACUNIT
; // so missile spawns higher
1430 mo
= P_SpawnMissile (actor
, actor
->target
, MT_TRACER
);
1431 actor
->z
-= 16*FRACUNIT
; // back to normal
1435 P_SetTarget(&mo
->tracer
, actor
->target
);
1438 int TRACEANGLE
= 0xc000000;
1440 void A_Tracer(mobj_t
*actor
)
1448 /* killough 1/18/98: this is why some missiles do not have smoke
1449 * and some do. Also, internal demos start at random gametics, thus
1450 * the bug in which revenants cause internal demos to go out of sync.
1452 * killough 3/6/98: fix revenant internal demo bug by subtracting
1453 * levelstarttic from gametic.
1455 * killough 9/29/98: use new "basetic" so that demos stay in sync
1456 * during pauses and menu activations, while retaining old demo sync.
1458 * leveltime would have been better to use to start with in Doom, but
1459 * since old demos were recorded using gametic, we must stick with it,
1460 * and improvise around it (using leveltime causes desync across levels).
1463 if ((gametic
-basetic
) & 3)
1466 // spawn a puff of smoke behind the rocket
1467 P_SpawnPuff(actor
->x
, actor
->y
, actor
->z
);
1469 th
= P_SpawnMobj (actor
->x
-actor
->momx
,
1470 actor
->y
-actor
->momy
,
1471 actor
->z
, MT_SMOKE
);
1473 th
->momz
= FRACUNIT
;
1474 th
->tics
-= P_Random(pr_tracer
) & 3;
1479 dest
= actor
->tracer
;
1481 if (!dest
|| dest
->health
<= 0)
1485 exact
= R_PointToAngle2(actor
->x
, actor
->y
, dest
->x
, dest
->y
);
1487 if (exact
!= actor
->angle
) {
1488 if (exact
- actor
->angle
> 0x80000000)
1490 actor
->angle
-= TRACEANGLE
;
1491 if (exact
- actor
->angle
< 0x80000000)
1492 actor
->angle
= exact
;
1496 actor
->angle
+= TRACEANGLE
;
1497 if (exact
- actor
->angle
> 0x80000000)
1498 actor
->angle
= exact
;
1502 exact
= actor
->angle
>>ANGLETOFINESHIFT
;
1503 actor
->momx
= FixedMul(actor
->info
->speed
, finecosine
[exact
]);
1504 actor
->momy
= FixedMul(actor
->info
->speed
, finesine
[exact
]);
1507 dist
= P_AproxDistance(dest
->x
- actor
->x
, dest
->y
- actor
->y
);
1509 dist
= dist
/ actor
->info
->speed
;
1514 slope
= (dest
->z
+40*FRACUNIT
- actor
->z
) / dist
;
1516 if (slope
< actor
->momz
)
1517 actor
->momz
-= FRACUNIT
/8;
1519 actor
->momz
+= FRACUNIT
/8;
1522 void A_SkelWhoosh(mobj_t
*actor
)
1526 A_FaceTarget(actor
);
1527 S_StartSound(actor
,sfx_skeswg
);
1530 void A_SkelFist(mobj_t
*actor
)
1534 A_FaceTarget(actor
);
1535 if (P_CheckMeleeRange(actor
))
1537 int damage
= ((P_Random(pr_skelfist
)%10)+1)*6;
1538 S_StartSound(actor
, sfx_skepch
);
1539 P_DamageMobj(actor
->target
, actor
, actor
, damage
);
1545 // Detect a corpse that could be raised.
1553 boolean
PIT_VileCheck(mobj_t
*thing
)
1558 if (!(thing
->flags
& MF_CORPSE
) )
1559 return true; // not a monster
1561 if (thing
->tics
!= -1)
1562 return true; // not lying still yet
1564 if (thing
->info
->raisestate
== S_NULL
)
1565 return true; // monster doesn't have a raise state
1567 maxdist
= thing
->info
->radius
+ mobjinfo
[MT_VILE
].radius
;
1569 if (D_abs(thing
->x
-viletryx
) > maxdist
|| D_abs(thing
->y
-viletryy
) > maxdist
)
1570 return true; // not actually touching
1572 // Check to see if the radius and height are zero. If they are // phares
1573 // then this is a crushed monster that has been turned into a // |
1574 // gib. One of the options may be to ignore this guy. // V
1576 // Option 1: the original, buggy method, -> ghost (compatibility)
1577 // Option 2: ressurect the monster, but not as a ghost
1578 // Option 3: ignore the gib
1580 // if (Option3) // ^
1581 // if ((thing->height == 0) && (thing->radius == 0)) // |
1582 // return true; // phares
1585 corpsehit
->momx
= corpsehit
->momy
= 0;
1586 if (comp
[comp_vile
]) // phares
1588 corpsehit
->height
<<= 2; // V
1589 check
= P_CheckPosition(corpsehit
,corpsehit
->x
,corpsehit
->y
);
1590 corpsehit
->height
>>= 2;
1596 height
= corpsehit
->height
; // save temporarily
1597 radius
= corpsehit
->radius
; // save temporarily
1598 corpsehit
->height
= corpsehit
->info
->height
;
1599 corpsehit
->radius
= corpsehit
->info
->radius
;
1600 corpsehit
->flags
|= MF_SOLID
;
1601 check
= P_CheckPosition(corpsehit
,corpsehit
->x
,corpsehit
->y
);
1602 corpsehit
->height
= height
; // restore
1603 corpsehit
->radius
= radius
; // restore // ^
1604 corpsehit
->flags
&= ~MF_SOLID
;
1608 return true; // doesn't fit here
1609 return false; // got one, so stop checking
1614 // Check for ressurecting a body
1617 void A_VileChase(mobj_t
* actor
)
1623 if (actor
->movedir
!= DI_NODIR
)
1625 // check for corpses to raise
1627 actor
->x
+ actor
->info
->speed
*xspeed
[actor
->movedir
];
1629 actor
->y
+ actor
->info
->speed
*yspeed
[actor
->movedir
];
1631 xl
= (viletryx
- bmaporgx
- MAXRADIUS
*2)>>MAPBLOCKSHIFT
;
1632 xh
= (viletryx
- bmaporgx
+ MAXRADIUS
*2)>>MAPBLOCKSHIFT
;
1633 yl
= (viletryy
- bmaporgy
- MAXRADIUS
*2)>>MAPBLOCKSHIFT
;
1634 yh
= (viletryy
- bmaporgy
+ MAXRADIUS
*2)>>MAPBLOCKSHIFT
;
1637 for (bx
=xl
; bx
<=xh
; bx
++)
1639 for (by
=yl
; by
<=yh
; by
++)
1641 // Call PIT_VileCheck to check
1642 // whether object is a corpse
1643 // that canbe raised.
1644 if (!P_BlockThingsIterator(bx
,by
,PIT_VileCheck
))
1649 mobj_t
* temp
= actor
->target
;
1650 actor
->target
= corpsehit
;
1651 A_FaceTarget(actor
);
1652 actor
->target
= temp
;
1654 P_SetMobjState(actor
, S_VILE_HEAL1
);
1655 S_StartSound(corpsehit
, sfx_slop
);
1656 info
= corpsehit
->info
;
1658 P_SetMobjState(corpsehit
,info
->raisestate
);
1660 if (comp
[comp_vile
]) // phares
1661 corpsehit
->height
<<= 2; // |
1664 corpsehit
->height
= info
->height
; // fix Ghost bug
1665 corpsehit
->radius
= info
->radius
; // fix Ghost bug
1668 /* killough 7/18/98:
1669 * friendliness is transferred from AV to raised corpse
1672 (info
->flags
& ~MF_FRIEND
) | (actor
->flags
& MF_FRIEND
);
1674 if (!((corpsehit
->flags
^ MF_COUNTKILL
) & (MF_FRIEND
| MF_COUNTKILL
)))
1677 corpsehit
->health
= info
->spawnhealth
;
1678 P_SetTarget(&corpsehit
->target
, NULL
); // killough 11/98
1681 { /* kilough 9/9/98 */
1682 P_SetTarget(&corpsehit
->lastenemy
, NULL
);
1683 corpsehit
->flags
&= ~MF_JUSTHIT
;
1686 /* killough 8/29/98: add to appropriate thread */
1687 P_UpdateThinker(&corpsehit
->thinker
);
1694 A_Chase(actor
); // Return to normal attack.
1701 void A_VileStart(mobj_t
*actor
)
1703 S_StartSound(actor
, sfx_vilatk
);
1708 // Keep fire in front of player unless out of sight
1711 void A_Fire(mobj_t
*actor
);
1713 void A_StartFire(mobj_t
*actor
)
1715 S_StartSound(actor
,sfx_flamst
);
1719 void A_FireCrackle(mobj_t
* actor
)
1721 S_StartSound(actor
,sfx_flame
);
1725 void A_Fire(mobj_t
*actor
)
1728 mobj_t
*dest
= actor
->tracer
;
1733 // don't move it if the vile lost sight
1734 if (!P_CheckSight(actor
->target
, dest
) )
1737 an
= dest
->angle
>> ANGLETOFINESHIFT
;
1739 P_UnsetThingPosition(actor
);
1740 actor
->x
= dest
->x
+ FixedMul(24*FRACUNIT
, finecosine
[an
]);
1741 actor
->y
= dest
->y
+ FixedMul(24*FRACUNIT
, finesine
[an
]);
1743 P_SetThingPosition(actor
);
1748 // Spawn the hellfire
1751 void A_VileTarget(mobj_t
*actor
)
1758 A_FaceTarget(actor
);
1760 // killough 12/98: fix Vile fog coordinates // CPhipps - compatibility optioned
1761 fog
= P_SpawnMobj(actor
->target
->x
,
1762 (compatibility_level
< lxdoom_1_compatibility
) ? actor
->target
->x
: actor
->target
->y
,
1763 actor
->target
->z
,MT_FIRE
);
1765 P_SetTarget(&actor
->tracer
, fog
);
1766 P_SetTarget(&fog
->target
, actor
);
1767 P_SetTarget(&fog
->tracer
, actor
->target
);
1775 void A_VileAttack(mobj_t
*actor
)
1783 A_FaceTarget(actor
);
1785 if (!P_CheckSight(actor
, actor
->target
))
1788 S_StartSound(actor
, sfx_barexp
);
1789 P_DamageMobj(actor
->target
, actor
, actor
, 20);
1790 actor
->target
->momz
= 1000*FRACUNIT
/actor
->target
->info
->mass
;
1792 an
= actor
->angle
>> ANGLETOFINESHIFT
;
1794 fire
= actor
->tracer
;
1799 // move the fire between the vile and the player
1800 fire
->x
= actor
->target
->x
- FixedMul (24*FRACUNIT
, finecosine
[an
]);
1801 fire
->y
= actor
->target
->y
- FixedMul (24*FRACUNIT
, finesine
[an
]);
1802 P_RadiusAttack(fire
, actor
, 70);
1807 // firing three missiles (bruisers)
1808 // in three different directions?
1809 // Doesn't look like it.
1812 #define FATSPREAD (ANG90/8)
1814 void A_FatRaise(mobj_t
*actor
)
1816 A_FaceTarget(actor
);
1817 S_StartSound(actor
, sfx_manatk
);
1820 void A_FatAttack1(mobj_t
*actor
)
1825 A_FaceTarget(actor
);
1827 // Change direction to ...
1828 actor
->angle
+= FATSPREAD
;
1830 P_SpawnMissile(actor
, actor
->target
, MT_FATSHOT
);
1832 mo
= P_SpawnMissile (actor
, actor
->target
, MT_FATSHOT
);
1833 mo
->angle
+= FATSPREAD
;
1834 an
= mo
->angle
>> ANGLETOFINESHIFT
;
1835 mo
->momx
= FixedMul(mo
->info
->speed
, finecosine
[an
]);
1836 mo
->momy
= FixedMul(mo
->info
->speed
, finesine
[an
]);
1839 void A_FatAttack2(mobj_t
*actor
)
1844 A_FaceTarget(actor
);
1845 // Now here choose opposite deviation.
1846 actor
->angle
-= FATSPREAD
;
1847 P_SpawnMissile(actor
, actor
->target
, MT_FATSHOT
);
1849 mo
= P_SpawnMissile(actor
, actor
->target
, MT_FATSHOT
);
1850 mo
->angle
-= FATSPREAD
*2;
1851 an
= mo
->angle
>> ANGLETOFINESHIFT
;
1852 mo
->momx
= FixedMul(mo
->info
->speed
, finecosine
[an
]);
1853 mo
->momy
= FixedMul(mo
->info
->speed
, finesine
[an
]);
1856 void A_FatAttack3(mobj_t
*actor
)
1861 A_FaceTarget(actor
);
1863 mo
= P_SpawnMissile(actor
, actor
->target
, MT_FATSHOT
);
1864 mo
->angle
-= FATSPREAD
/2;
1865 an
= mo
->angle
>> ANGLETOFINESHIFT
;
1866 mo
->momx
= FixedMul(mo
->info
->speed
, finecosine
[an
]);
1867 mo
->momy
= FixedMul(mo
->info
->speed
, finesine
[an
]);
1869 mo
= P_SpawnMissile(actor
, actor
->target
, MT_FATSHOT
);
1870 mo
->angle
+= FATSPREAD
/2;
1871 an
= mo
->angle
>> ANGLETOFINESHIFT
;
1872 mo
->momx
= FixedMul(mo
->info
->speed
, finecosine
[an
]);
1873 mo
->momy
= FixedMul(mo
->info
->speed
, finesine
[an
]);
1879 // Fly at the player like a missile.
1881 #define SKULLSPEED (20*FRACUNIT)
1883 void A_SkullAttack(mobj_t
*actor
)
1892 dest
= actor
->target
;
1893 actor
->flags
|= MF_SKULLFLY
;
1895 S_StartSound(actor
, actor
->info
->attacksound
);
1896 A_FaceTarget(actor
);
1897 an
= actor
->angle
>> ANGLETOFINESHIFT
;
1898 actor
->momx
= FixedMul(SKULLSPEED
, finecosine
[an
]);
1899 actor
->momy
= FixedMul(SKULLSPEED
, finesine
[an
]);
1900 dist
= P_AproxDistance(dest
->x
- actor
->x
, dest
->y
- actor
->y
);
1901 dist
= dist
/ SKULLSPEED
;
1905 actor
->momz
= (dest
->z
+(dest
->height
>>1) - actor
->z
) / dist
;
1910 // Spawn a lost soul and launch it at the target
1913 void A_PainShootSkull(mobj_t
*actor
, angle_t angle
)
1920 // The original code checked for 20 skulls on the level, // phares
1921 // and wouldn't spit another one if there were. If not in // phares
1922 // compatibility mode, we remove the limit. // phares
1924 if (comp
[comp_pain
]) /* killough 10/98: compatibility-optioned */
1926 // count total number of skulls currently on the level
1928 thinker_t
*currentthinker
;
1929 for (currentthinker
= thinkercap
.next
;
1930 currentthinker
!= &thinkercap
;
1931 currentthinker
= currentthinker
->next
)
1932 if ((currentthinker
->function
== P_MobjThinker
)
1933 && ((mobj_t
*)currentthinker
)->type
== MT_SKULL
)
1935 if (count
> 20) // phares
1939 // okay, there's room for another one
1941 an
= angle
>> ANGLETOFINESHIFT
;
1943 prestep
= 4*FRACUNIT
+ 3*(actor
->info
->radius
+ mobjinfo
[MT_SKULL
].radius
)/2;
1945 x
= actor
->x
+ FixedMul(prestep
, finecosine
[an
]);
1946 y
= actor
->y
+ FixedMul(prestep
, finesine
[an
]);
1947 z
= actor
->z
+ 8*FRACUNIT
;
1949 if (comp
[comp_skull
]) /* killough 10/98: compatibility-optioned */
1950 newmobj
= P_SpawnMobj(x
, y
, z
, MT_SKULL
); // phares
1953 // Check whether the Lost Soul is being fired through a 1-sided
1954 // wall or an impassible line, or a "monsters can't cross" line.
1955 // If it is, then we don't allow the spawn. This is a bug fix, but
1956 // it should be considered an enhancement, since it may disturb
1957 // existing demos, so don't do it in compatibility mode.
1959 if (Check_Sides(actor
,x
,y
))
1962 newmobj
= P_SpawnMobj(x
, y
, z
, MT_SKULL
);
1964 // Check to see if the new Lost Soul's z value is above the
1965 // ceiling of its new sector, or below the floor. If so, kill it.
1968 (newmobj
->subsector
->sector
->ceilingheight
- newmobj
->height
)) ||
1969 (newmobj
->z
< newmobj
->subsector
->sector
->floorheight
))
1971 // kill it immediately
1972 P_DamageMobj(newmobj
,actor
,actor
,10000);
1977 /* killough 7/20/98: PEs shoot lost souls with the same friendliness */
1978 newmobj
->flags
= (newmobj
->flags
& ~MF_FRIEND
) | (actor
->flags
& MF_FRIEND
);
1980 /* killough 8/29/98: add to appropriate thread */
1981 P_UpdateThinker(&newmobj
->thinker
);
1983 // Check for movements.
1984 // killough 3/15/98: don't jump over dropoffs:
1986 if (!P_TryMove(newmobj
, newmobj
->x
, newmobj
->y
, false))
1988 // kill it immediately
1989 P_DamageMobj(newmobj
, actor
, actor
, 10000);
1993 P_SetTarget(&newmobj
->target
, actor
->target
);
1994 A_SkullAttack(newmobj
);
1999 // Spawn a lost soul and launch it at the target
2002 void A_PainAttack(mobj_t
*actor
)
2006 A_FaceTarget(actor
);
2007 A_PainShootSkull(actor
, actor
->angle
);
2010 void A_PainDie(mobj_t
*actor
)
2013 A_PainShootSkull(actor
, actor
->angle
+ANG90
);
2014 A_PainShootSkull(actor
, actor
->angle
+ANG180
);
2015 A_PainShootSkull(actor
, actor
->angle
+ANG270
);
2018 void A_Scream(mobj_t
*actor
)
2022 switch (actor
->info
->deathsound
)
2030 sound
= sfx_podth1
+ P_Random(pr_scream
)%3;
2035 sound
= sfx_bgdth1
+ P_Random(pr_scream
)%2;
2039 sound
= actor
->info
->deathsound
;
2043 // Check for bosses.
2044 if (actor
->type
==MT_SPIDER
|| actor
->type
== MT_CYBORG
)
2045 S_StartSound(NULL
, sound
); // full volume
2047 S_StartSound(actor
, sound
);
2050 void A_XScream(mobj_t
*actor
)
2052 S_StartSound(actor
, sfx_slop
);
2055 void A_Pain(mobj_t
*actor
)
2057 if (actor
->info
->painsound
)
2058 S_StartSound(actor
, actor
->info
->painsound
);
2061 void A_Fall(mobj_t
*actor
)
2063 // actor is on ground, it can be walked over
2064 actor
->flags
&= ~MF_SOLID
;
2070 void A_Explode(mobj_t
*thingy
)
2072 P_RadiusAttack( thingy
, thingy
->target
, 128 );
2077 // Possibly trigger special effects
2078 // if on first boss level
2081 void A_BossDeath(mobj_t
*mo
)
2087 if (gamemode
== commercial
)
2092 if ((mo
->type
!= MT_FATSO
)
2093 && (mo
->type
!= MT_BABY
))
2104 if (mo
->type
!= MT_BRUISER
)
2112 if (mo
->type
!= MT_CYBORG
)
2120 if (mo
->type
!= MT_SPIDER
)
2129 if (mo
->type
!= MT_CYBORG
)
2134 if (mo
->type
!= MT_SPIDER
)
2152 // make sure there is a player alive for victory
2153 for (i
=0; i
<MAXPLAYERS
; i
++)
2154 if (playeringame
[i
] && players
[i
].health
> 0)
2158 return; // no one left alive, so do not end game
2160 // scan the remaining thinkers to see
2161 // if all bosses are dead
2162 for (th
= thinkercap
.next
; th
!= &thinkercap
; th
=th
->next
)
2163 if (th
->function
== P_MobjThinker
)
2165 mobj_t
*mo2
= (mobj_t
*) th
;
2166 if (mo2
!= mo
&& mo2
->type
== mo
->type
&& mo2
->health
> 0)
2167 return; // other boss not dead
2171 if ( gamemode
== commercial
)
2175 if (mo
->type
== MT_FATSO
)
2178 EV_DoFloor(&junk
,lowerFloorToLowest
);
2182 if (mo
->type
== MT_BABY
)
2185 EV_DoFloor(&junk
,raiseToTexture
);
2196 EV_DoFloor(&junk
, lowerFloorToLowest
);
2205 EV_DoDoor(&junk
, blazeOpen
);
2211 EV_DoFloor(&junk
, lowerFloorToLowest
);
2221 void A_Hoof (mobj_t
* mo
)
2223 S_StartSound(mo
, sfx_hoof
);
2227 void A_Metal(mobj_t
*mo
)
2229 S_StartSound(mo
, sfx_metal
);
2233 void A_BabyMetal(mobj_t
*mo
)
2235 S_StartSound(mo
, sfx_bspwlk
);
2239 void A_OpenShotgun2(player_t
*player
, pspdef_t
*psp
)
2242 S_StartSound(player
->mo
, sfx_dbopn
);
2245 void A_LoadShotgun2(player_t
*player
, pspdef_t
*psp
)
2248 S_StartSound(player
->mo
, sfx_dbload
);
2251 void A_ReFire(player_t
*player
, pspdef_t
*psp
);
2253 void A_CloseShotgun2(player_t
*player
, pspdef_t
*psp
)
2255 S_StartSound(player
->mo
, sfx_dbcls
);
2256 A_ReFire(player
,psp
);
2259 // killough 2/7/98: Remove limit on icon landings:
2260 mobj_t
**braintargets
;
2261 int numbraintargets_alloc
;
2262 int numbraintargets
;
2264 struct brain_s brain
; // killough 3/26/98: global state of boss brain
2266 // killough 3/26/98: initialize icon landings at level startup,
2267 // rather than at boss wakeup, to prevent savegame-related crashes
2269 void P_SpawnBrainTargets(void) // killough 3/26/98: renamed old function
2273 // find all the target spots
2274 numbraintargets
= 0;
2276 brain
.easy
= 0; // killough 3/26/98: always init easy to 0
2278 for (thinker
= thinkercap
.next
;
2279 thinker
!= &thinkercap
;
2280 thinker
= thinker
->next
)
2281 if (thinker
->function
== P_MobjThinker
)
2283 mobj_t
*m
= (mobj_t
*) thinker
;
2285 if (m
->type
== MT_BOSSTARGET
)
2286 { // killough 2/7/98: remove limit on icon landings:
2287 if (numbraintargets
>= numbraintargets_alloc
)
2288 braintargets
= realloc(braintargets
,
2289 (numbraintargets_alloc
= numbraintargets_alloc
?
2290 numbraintargets_alloc
*2 : 32) *sizeof *braintargets
);
2291 braintargets
[numbraintargets
++] = m
;
2296 void A_BrainAwake(mobj_t
*mo
)
2299 S_StartSound(NULL
,sfx_bossit
); // killough 3/26/98: only generates sound now
2302 void A_BrainPain(mobj_t
*mo
)
2305 S_StartSound(NULL
,sfx_bospn
);
2308 void A_BrainScream(mobj_t
*mo
)
2311 for (x
=mo
->x
- 196*FRACUNIT
; x
< mo
->x
+ 320*FRACUNIT
; x
+= FRACUNIT
*8)
2313 int y
= mo
->y
- 320*FRACUNIT
;
2314 int z
= 128 + P_Random(pr_brainscream
)*2*FRACUNIT
;
2315 mobj_t
*th
= P_SpawnMobj (x
,y
,z
, MT_ROCKET
);
2316 th
->momz
= P_Random(pr_brainscream
)*512;
2317 P_SetMobjState(th
, S_BRAINEXPLODE1
);
2318 th
->tics
-= P_Random(pr_brainscream
)&7;
2322 S_StartSound(NULL
,sfx_bosdth
);
2325 void A_BrainExplode(mobj_t
*mo
)
2326 { // killough 5/5/98: remove dependence on order of evaluation:
2328 int t
= P_Random(pr_brainexp
);
2329 int x
= mo
->x
+ (t
- P_Random(pr_brainexp
))*2048;
2331 int z
= 128 + P_Random(pr_brainexp
)*2*FRACUNIT
;
2332 mobj_t
*th
= P_SpawnMobj(x
,y
,z
, MT_ROCKET
);
2333 th
->momz
= P_Random(pr_brainexp
)*512;
2334 P_SetMobjState(th
, S_BRAINEXPLODE1
);
2335 th
->tics
-= P_Random(pr_brainexp
)&7;
2340 void A_BrainDie(mobj_t
*mo
)
2346 void A_BrainSpit(mobj_t
*mo
)
2348 mobj_t
*targ
, *newmobj
;
2350 if (!numbraintargets
) // killough 4/1/98: ignore if no targets
2353 brain
.easy
^= 1; // killough 3/26/98: use brain struct
2354 if (gameskill
<= sk_easy
&& !brain
.easy
)
2357 // shoot a cube at current target
2358 targ
= braintargets
[brain
.targeton
++]; // killough 3/26/98:
2359 brain
.targeton
%= numbraintargets
; // Use brain struct for targets
2361 // spawn brain missile
2362 newmobj
= P_SpawnMissile(mo
, targ
, MT_SPAWNSHOT
);
2363 P_SetTarget(&newmobj
->target
, targ
);
2364 newmobj
->reactiontime
= (short)(((targ
->y
-mo
->y
)/newmobj
->momy
)/newmobj
->state
->tics
);
2366 // killough 7/18/98: brain friendliness is transferred
2367 newmobj
->flags
= (newmobj
->flags
& ~MF_FRIEND
) | (mo
->flags
& MF_FRIEND
);
2369 // killough 8/29/98: add to appropriate thread
2370 P_UpdateThinker(&newmobj
->thinker
);
2372 S_StartSound(NULL
, sfx_bospit
);
2375 void A_SpawnFly(mobj_t
*mo
);
2377 // travelling cube sound
2378 void A_SpawnSound(mobj_t
*mo
)
2380 S_StartSound(mo
,sfx_boscub
);
2384 void A_SpawnFly(mobj_t
*mo
)
2392 if (--mo
->reactiontime
)
2393 return; // still flying
2397 // First spawn teleport fog.
2398 fog
= P_SpawnMobj(targ
->x
, targ
->y
, targ
->z
, MT_SPAWNFIRE
);
2399 S_StartSound(fog
, sfx_telept
);
2401 // Randomly select monster to spawn.
2402 r
= P_Random(pr_spawnfly
);
2404 // Probability distribution (kind of :), decreasing likelihood.
2428 newmobj
= P_SpawnMobj(targ
->x
, targ
->y
, targ
->z
, type
);
2430 /* killough 7/18/98: brain friendliness is transferred */
2431 newmobj
->flags
= (newmobj
->flags
& ~MF_FRIEND
) | (mo
->flags
& MF_FRIEND
);
2433 /* killough 8/29/98: add to appropriate thread */
2434 P_UpdateThinker(&newmobj
->thinker
);
2436 if (P_LookForTargets(newmobj
,true)) /* killough 9/4/98 */
2437 P_SetMobjState(newmobj
, newmobj
->info
->seestate
);
2439 // telefrag anything in this spot
2440 P_TeleportMove(newmobj
, newmobj
->x
, newmobj
->y
, true); /* killough 8/9/98 */
2442 // remove self (i.e., cube).
2446 void A_PlayerScream(mobj_t
*mo
)
2448 int sound
= sfx_pldeth
; // Default death sound.
2449 if (gamemode
!= shareware
&& mo
->health
< -50)
2450 sound
= sfx_pdiehi
; // IF THE PLAYER DIES LESS THAN -50% WITHOUT GIBBING
2451 S_StartSound(mo
, sound
);
2454 /* cph - MBF-added codepointer functions */
2456 // killough 11/98: kill an object
2457 void A_Die(mobj_t
*actor
)
2459 P_DamageMobj(actor
, NULL
, NULL
, actor
->health
);
2464 // killough 8/9/98: same as A_Explode, except that the damage is variable
2467 void A_Detonate(mobj_t
*mo
)
2469 P_RadiusAttack(mo
, mo
->target
, mo
->info
->damage
);
2473 // killough 9/98: a mushroom explosion effect, sorta :)
2474 // Original idea: Linguica
2477 void A_Mushroom(mobj_t
*actor
)
2479 int i
, j
, n
= actor
->info
->damage
;
2481 A_Explode(actor
); // First make normal explosion
2483 // Now launch mushroom cloud
2484 for (i
= -n
; i
<= n
; i
+= 8)
2485 for (j
= -n
; j
<= n
; j
+= 8)
2487 mobj_t target
= *actor
, *mo
;
2488 target
.x
+= i
<< FRACBITS
; // Aim in many directions from source
2489 target
.y
+= j
<< FRACBITS
;
2490 target
.z
+= P_AproxDistance(i
,j
) << (FRACBITS
+2); // Aim up fairly high
2491 mo
= P_SpawnMissile(actor
, &target
, MT_FATSHOT
); // Launch fireball
2493 mo
->momy
>>= 1; // Slow it down a bit
2495 mo
->flags
&= ~MF_NOGRAVITY
; // Make debris fall under gravity
2502 // The following were inspired by Len Pitre
2504 // A small set of highly-sought-after code pointers
2507 void A_Spawn(mobj_t
*mo
)
2509 if (mo
->state
->misc1
)
2511 /* mobj_t *newmobj = */
2512 P_SpawnMobj(mo
->x
, mo
->y
, (mo
->state
->misc2
<< FRACBITS
) + mo
->z
,
2513 mo
->state
->misc1
- 1);
2514 /* CPhipps - no friendlyness (yet)
2515 newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND);
2520 void A_Turn(mobj_t
*mo
)
2522 mo
->angle
+= (unsigned int)(((uint_64_t
) mo
->state
->misc1
<< 32) / 360);
2525 void A_Face(mobj_t
*mo
)
2527 mo
->angle
= (unsigned int)(((uint_64_t
) mo
->state
->misc1
<< 32) / 360);
2530 void A_Scratch(mobj_t
*mo
)
2532 mo
->target
&& (A_FaceTarget(mo
), P_CheckMeleeRange(mo
)) ?
2533 mo
->state
->misc2
? S_StartSound(mo
, mo
->state
->misc2
) : (void) 0,
2534 P_DamageMobj(mo
->target
, mo
, mo
, mo
->state
->misc1
) : (void) 0;
2537 void A_PlaySound(mobj_t
*mo
)
2539 S_StartSound(mo
->state
->misc2
? NULL
: mo
, mo
->state
->misc1
);
2542 void A_RandomJump(mobj_t
*mo
)
2544 if (P_Random(pr_randomjump
) < mo
->state
->misc2
)
2545 P_SetMobjState(mo
, mo
->state
->misc1
);
2549 // This allows linedef effects to be activated inside deh frames.
2552 void A_LineEffect(mobj_t
*mo
)
2556 player_t
*oldplayer
;
2558 oldplayer
= mo
->player
;
2559 mo
->player
= &player
;
2560 player
.health
= 100;
2561 junk
.special
= (short)mo
->state
->misc1
;
2564 junk
.tag
= (short)mo
->state
->misc2
;
2565 if (!P_UseSpecialLine(mo
, &junk
, 0))
2566 P_CrossSpecialLine(&junk
, 0, mo
);
2567 mo
->state
->misc1
= junk
.special
;
2568 mo
->player
= oldplayer
;
2571 /***** Start of new functions for Andy Baker's stealth monsters ******/
2573 void P_BecomeVisible(mobj_t
* actor
)
2575 actor
->invisible
= false;
2576 actor
->flags
&= ~MF_TRANSLUCBITS
;
2579 void P_IncreaseVisibility(mobj_t
* actor
)
2581 if (actor
->invisible
) {
2582 actor
->invisible
= false;
2583 actor
->flags
|= MF_TRANSLUC25
;
2584 } else switch (actor
->flags
& MF_TRANSLUCBITS
) {
2586 actor
->flags
&= ~MF_TRANSLUCBITS
;
2587 actor
->flags
|= MF_TRANSLUC50
;
2590 actor
->flags
&= ~MF_TRANSLUCBITS
;
2591 actor
->flags
|= MF_TRANSLUC25
;
2592 actor
->flags
|= MF_TRANSLUC50
;
2595 actor
->flags
&= ~MF_TRANSLUCBITS
;
2600 void P_DecreaseVisibility(mobj_t
* actor
)
2602 if (actor
->invisible
)
2603 return; // already invisible
2605 switch (actor
->flags
& MF_TRANSLUCBITS
) {
2607 actor
->flags
&= ~MF_TRANSLUCBITS
;
2608 actor
->flags
|= MF_TRANSLUC75
;
2611 actor
->flags
&= ~MF_TRANSLUCBITS
;
2612 actor
->flags
|= MF_TRANSLUC50
;
2615 actor
->flags
&= ~MF_TRANSLUCBITS
;
2616 actor
->flags
|= MF_TRANSLUC25
;
2619 actor
->flags
&= ~MF_TRANSLUCBITS
;
2620 actor
->invisible
= true;
2623 /***** End of new functions for Andy Baker's stealth monsters ******/