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
;
66 void A_Fall(mobj_t
*actor
);
67 void A_FaceTarget(mobj_t
*actor
);
68 static void P_NewChaseDir(mobj_t
*actor
);
69 void P_ZBumpCheck(mobj_t
*); // phares
73 // Enemies are allways spawned
74 // with targetplayer = -1, threshold = 0
75 // Most monsters are spawned unaware of all players,
76 // but some can be made preaware
80 // Called by P_NoiseAlert.
81 // Recursively traverse adjacent sectors,
82 // sound blocking lines cut off traversal.
84 // killough 5/5/98: reformatted, cleaned up
86 static void P_RecursiveSound(sector_t
*sec
, int soundblocks
,
91 // wake up all monsters in this sector
92 if (sec
->validcount
== validcount
&& sec
->soundtraversed
<= soundblocks
+1)
93 return; // already flooded
95 sec
->validcount
= validcount
;
96 sec
->soundtraversed
= soundblocks
+1;
97 P_SetTarget(&sec
->soundtarget
, soundtarget
);
99 for (i
=0; i
<sec
->linecount
; i
++)
102 line_t
*check
= sec
->lines
[i
];
104 if (!(check
->flags
& ML_TWOSIDED
))
107 P_LineOpening(check
);
110 continue; // closed door
112 other
=sides
[check
->sidenum
[sides
[check
->sidenum
[0]].sector
==sec
]].sector
;
114 if (!(check
->flags
& ML_SOUNDBLOCK
))
115 P_RecursiveSound(other
, soundblocks
, soundtarget
);
118 P_RecursiveSound(other
, 1, soundtarget
);
124 // If a monster yells at a player,
125 // it will alert other monsters to the player.
127 void P_NoiseAlert(mobj_t
*target
, mobj_t
*emitter
)
130 P_RecursiveSound(emitter
->subsector
->sector
, 0, target
);
137 static boolean
P_CheckMeleeRange(mobj_t
*actor
)
139 mobj_t
*pl
= actor
->target
;
141 return // killough 7/18/98: friendly monsters don't attack other friends
142 pl
&& !(actor
->flags
& pl
->flags
& MF_FRIEND
) &&
143 (P_AproxDistance(pl
->x
-actor
->x
, pl
->y
-actor
->y
) <
144 MELEERANGE
- 20*FRACUNIT
+ pl
->info
->radius
) &&
145 P_CheckSight(actor
, actor
->target
);
152 // This function tries to prevent shooting at friends
154 static boolean
P_HitFriend(mobj_t
*actor
)
156 return actor
->flags
& MF_FRIEND
&& actor
->target
&&
157 (P_AimLineAttack(actor
,
158 R_PointToAngle2(actor
->x
, actor
->y
,
159 actor
->target
->x
, actor
->target
->y
),
160 P_AproxDistance(actor
->x
-actor
->target
->x
,
161 actor
->y
-actor
->target
->y
), 0),
162 linetarget
) && linetarget
!= actor
->target
&&
163 !((linetarget
->flags
^ actor
->flags
) & MF_FRIEND
);
167 // P_CheckMissileRange
169 boolean
P_CheckMissileRange(mobj_t
*actor
)
173 if (!P_CheckSight(actor
, actor
->target
))
176 if (actor
->flags
& MF_JUSTHIT
)
177 { // the target just hit the enemy, so fight back!
178 actor
->flags
&= ~MF_JUSTHIT
;
180 /* killough 7/18/98: no friendly fire at corpses
181 * killough 11/98: prevent too much infighting among friends
182 * cph - yikes, talk about fitting everything on one line... */
185 !(actor
->flags
& MF_FRIEND
) ||
186 (actor
->target
->health
> 0 &&
187 (!(actor
->target
->flags
& MF_FRIEND
) ||
188 (actor
->target
->player
?
189 monster_infighting
|| P_Random(pr_defect
) >128 :
190 !(actor
->target
->flags
& MF_JUSTHIT
) && P_Random(pr_defect
) >128)));
193 /* killough 7/18/98: friendly monsters don't attack other friendly
194 * monsters or players (except when attacked, and then only once)
196 if (actor
->flags
& actor
->target
->flags
& MF_FRIEND
)
199 if (actor
->reactiontime
)
200 return false; // do not attack yet
202 // OPTIMIZE: get this from a global checksight
203 dist
= P_AproxDistance ( actor
->x
-actor
->target
->x
,
204 actor
->y
-actor
->target
->y
) - 64*FRACUNIT
;
206 if (!actor
->info
->meleestate
)
207 dist
-= 128*FRACUNIT
; // no melee attack, so fire more
211 if (actor
->type
== MT_VILE
)
213 return false; // too far away
216 if (actor
->type
== MT_UNDEAD
)
219 return false; // close for fist attack
223 if (actor
->type
== MT_CYBORG
||
224 actor
->type
== MT_SPIDER
||
225 actor
->type
== MT_SKULL
)
231 if (actor
->type
== MT_CYBORG
&& dist
> 160)
234 if (P_Random(pr_missrange
) < dist
)
237 if (P_HitFriend(actor
))
248 * Returns true if the object is on a lift. Used for AI,
249 * since it may indicate the need for crowded conditions,
250 * or that a monster should stay on the lift for a while
251 * while it goes up or down.
254 static boolean
P_IsOnLift(const mobj_t
*actor
)
256 const sector_t
*sec
= actor
->subsector
->sector
;
260 // Short-circuit: it's on a lift which is active.
261 if (sec
->floordata
&& ((thinker_t
*) sec
->floordata
)->function
==T_PlatRaise
)
264 // Check to see if it's in a sector which can be activated as a lift.
265 if ((line
.tag
= sec
->tag
))
266 for (l
= -1; (l
= P_FindLineFromLineTag(&line
, l
)) >= 0;)
267 switch (lines
[l
].special
)
269 case 10: case 14: case 15: case 20: case 21: case 22:
270 case 47: case 53: case 62: case 66: case 67: case 68:
271 case 87: case 88: case 95: case 120: case 121: case 122:
272 case 123: case 143: case 162: case 163: case 181: case 182:
273 case 144: case 148: case 149: case 211: case 227: case 228:
274 case 231: case 232: case 235: case 236:
286 * Returns nonzero if the object is under damage based on
287 * their current position. Returns 1 if the damage is moderate,
288 * -1 if it is serious. Used for AI.
291 static int P_IsUnderDamage(mobj_t
*actor
)
293 const struct msecnode_s
*seclist
;
294 const ceiling_t
*cl
; // Crushing ceiling
296 for (seclist
=actor
->touching_sectorlist
; seclist
; seclist
=seclist
->m_tnext
)
297 if ((cl
= seclist
->m_sector
->ceilingdata
) &&
298 cl
->thinker
.function
== T_MoveCeiling
)
299 dir
|= cl
->direction
;
305 // Move in the current direction,
306 // returns false if the move is blocked.
309 static fixed_t xspeed
[8] = {FRACUNIT
,47000,0,-47000,-FRACUNIT
,-47000,0,47000};
310 static fixed_t yspeed
[8] = {0,47000,FRACUNIT
,47000,0,-47000,-FRACUNIT
,-47000};
312 // 1/11/98 killough: Limit removed on special lines crossed
313 extern line_t
**spechit
; // New code -- killough
314 extern int numspechit
;
316 static boolean
P_Move(mobj_t
*actor
, boolean dropoff
) /* killough 9/12/98 */
318 fixed_t tryx
, tryy
, deltax
, deltay
, origx
, origy
;
320 int movefactor
= ORIG_FRICTION_FACTOR
; // killough 10/98
321 int friction
= ORIG_FRICTION
;
324 if (actor
->movedir
== DI_NODIR
)
328 if ((unsigned)actor
->movedir
>= 8)
329 I_Error ("P_Move: Weird actor->movedir!");
332 // killough 10/98: make monsters get affected by ice and sludge too:
334 if (monster_friction
)
335 movefactor
= P_GetMoveFactor(actor
, &friction
);
337 speed
= actor
->info
->speed
;
339 if (friction
< ORIG_FRICTION
&& // sludge
340 !(speed
= ((ORIG_FRICTION_FACTOR
- (ORIG_FRICTION_FACTOR
-movefactor
)/2)
341 * speed
) / ORIG_FRICTION_FACTOR
))
342 speed
= 1; // always give the monster a little bit of speed
344 tryx
= (origx
= actor
->x
) + (deltax
= speed
* xspeed
[actor
->movedir
]);
345 tryy
= (origy
= actor
->y
) + (deltay
= speed
* yspeed
[actor
->movedir
]);
347 try_ok
= P_TryMove(actor
, tryx
, tryy
, dropoff
);
350 // Let normal momentum carry them, instead of steptoeing them across ice.
352 if (try_ok
&& friction
> ORIG_FRICTION
)
356 movefactor
*= FRACUNIT
/ ORIG_FRICTION_FACTOR
/ 4;
357 actor
->momx
+= FixedMul(deltax
, movefactor
);
358 actor
->momy
+= FixedMul(deltay
, movefactor
);
362 { // open any specials
365 if (actor
->flags
& MF_FLOAT
&& floatok
)
367 if (actor
->z
< tmfloorz
) // must adjust height
368 actor
->z
+= FLOATSPEED
;
370 actor
->z
-= FLOATSPEED
;
372 actor
->flags
|= MF_INFLOAT
;
380 actor
->movedir
= DI_NODIR
;
382 /* if the special is not a door that can be opened, return false
384 * killough 8/9/98: this is what caused monsters to get stuck in
385 * doortracks, because it thought that the monster freed itself
386 * by opening a door, even if it was moving towards the doortrack,
387 * and not the door itself.
389 * killough 9/9/98: If a line blocking the monster is activated,
390 * return true 90% of the time. If a line blocking the monster is
391 * not activated, but some other line is, return false 90% of the
392 * time. A bit of randomness is needed to ensure it's free from
393 * lockups, but for most cases, it returns the correct result.
395 * Do NOT simply return false 1/4th of the time (causes monsters to
396 * back out when they shouldn't, and creates secondary stickiness).
399 for (good
= false; numspechit
--; )
400 if (P_UseSpecialLine(actor
, spechit
[numspechit
], 0))
401 good
|= spechit
[numspechit
] == blockline
? 1 : 2;
403 /* cph - compatibility maze here
404 * Boom v2.01 and orig. Doom return "good"
405 * Boom v2.02 and LxDoom return good && (P_Random(pr_trywalk)&3)
406 * MBF plays even more games
408 if (!good
|| comp
[comp_doorstuck
]) return good
;
410 return (P_Random(pr_trywalk
)&3); /* jff 8/13/98 */
411 else /* finally, MBF code */
412 return ((P_Random(pr_opendoor
) >= 230) ^ (good
& 1));
415 actor
->flags
&= ~MF_INFLOAT
;
417 /* killough 11/98: fall more slowly, under gravity, if felldown==true */
418 if (!(actor
->flags
& MF_FLOAT
) &&
419 (!felldown
|| !mbf_features
))
420 actor
->z
= actor
->floorz
;
428 * killough 9/12/98: Same as P_Move, except smarter
431 static boolean
P_SmartMove(mobj_t
*actor
)
433 mobj_t
*target
= actor
->target
;
434 int on_lift
, dropoff
= false, under_damage
;
436 /* killough 9/12/98: Stay on a lift if target is on one */
437 on_lift
= !comp
[comp_staylift
]
438 && target
&& target
->health
> 0
439 && target
->subsector
->sector
->tag
==actor
->subsector
->sector
->tag
&&
442 under_damage
= monster_avoid_hazards
&& P_IsUnderDamage(actor
);
444 // killough 10/98: allow dogs to drop off of taller ledges sometimes.
445 // dropoff==1 means always allow it, dropoff==2 means only up to 128 high,
446 // and only if the target is immediately on the other side of the line.
449 if (actor
->type
== MT_DOGS
&& target
&& dog_jumping
&&
450 !((target
->flags
^ actor
->flags
) & MF_FRIEND
) &&
451 P_AproxDistance(actor
->x
- target
->x
,
452 actor
->y
- target
->y
) < FRACUNIT
*144 &&
453 P_Random(pr_dropoff
) < 235)
457 if (!P_Move(actor
, dropoff
))
460 // killough 9/9/98: avoid crushing ceilings or other damaging areas
462 (on_lift
&& P_Random(pr_stayonlift
) < 230 && // Stay on lift
465 (monster_avoid_hazards
&& !under_damage
&& // Get away from damage
466 (under_damage
= P_IsUnderDamage(actor
)) &&
467 (under_damage
< 0 || P_Random(pr_avoidcrush
) < 200))
469 actor
->movedir
= DI_NODIR
; // avoid the area (most of the time anyway)
476 // Attempts to move actor on
477 // in its current (ob->moveangle) direction.
478 // If blocked by either a wall or an actor
480 // If move is either clear or blocked only by a door,
481 // returns TRUE and sets...
482 // If a door is in the way,
483 // an OpenDoor call is made to start it opening.
486 boolean
P_TryWalk(mobj_t
*actor
)
488 if (!P_SmartMove(actor
))
490 actor
->movecount
= P_Random(pr_trywalk
)&15;
499 // Most of P_NewChaseDir(), except for what
500 // determines the new direction to take
503 static void P_DoNewChaseDir(mobj_t
*actor
, fixed_t deltax
, fixed_t deltay
)
505 dirtype_t xdir
, ydir
, tdir
;
506 dirtype_t olddir
= actor
->movedir
;
507 dirtype_t turnaround
= olddir
;
509 if (turnaround
!= DI_NODIR
) // find reverse direction
513 deltax
> 10*FRACUNIT
? DI_EAST
:
514 deltax
< -10*FRACUNIT
? DI_WEST
: DI_NODIR
;
517 deltay
< -10*FRACUNIT
? DI_SOUTH
:
518 deltay
> 10*FRACUNIT
? DI_NORTH
: DI_NODIR
;
521 if (xdir
!= DI_NODIR
&& ydir
!= DI_NODIR
&& turnaround
!=
522 (actor
->movedir
= deltay
< 0 ? deltax
> 0 ? DI_SOUTHEAST
: DI_SOUTHWEST
:
523 deltax
> 0 ? DI_NORTHEAST
: DI_NORTHWEST
) && P_TryWalk(actor
))
526 // try other directions
527 if (P_Random(pr_newchase
) > 200 || abs(deltay
)>abs(deltax
))
528 tdir
= xdir
, xdir
= ydir
, ydir
= tdir
;
530 if ((xdir
== turnaround
? xdir
= DI_NODIR
: xdir
) != DI_NODIR
&&
531 (actor
->movedir
= xdir
, P_TryWalk(actor
)))
532 return; // either moved forward or attacked
534 if ((ydir
== turnaround
? ydir
= DI_NODIR
: ydir
) != DI_NODIR
&&
535 (actor
->movedir
= ydir
, P_TryWalk(actor
)))
538 // there is no direct path to the player, so pick another direction.
539 if (olddir
!= DI_NODIR
&& (actor
->movedir
= olddir
, P_TryWalk(actor
)))
542 // randomly determine direction of search
543 if (P_Random(pr_newchasedir
) & 1)
545 for (tdir
= DI_EAST
; tdir
<= DI_SOUTHEAST
; tdir
++)
546 if (tdir
!= turnaround
&& (actor
->movedir
= tdir
, P_TryWalk(actor
)))
550 for (tdir
= DI_SOUTHEAST
; tdir
!= (dirtype_t
)(DI_EAST
-1); tdir
--)
551 if (tdir
!= turnaround
&& (actor
->movedir
= tdir
, P_TryWalk(actor
)))
554 if ((actor
->movedir
= turnaround
) != DI_NODIR
&& !P_TryWalk(actor
))
555 actor
->movedir
= DI_NODIR
;
561 // Monsters try to move away from tall dropoffs.
563 // In Doom, they were never allowed to hang over dropoffs,
564 // and would remain stuck if involuntarily forced over one.
565 // This logic, combined with p_map.c (P_TryMove), allows
566 // monsters to free themselves without making them tend to
567 // hang over dropoffs.
569 static fixed_t dropoff_deltax
, dropoff_deltay
, floorz
;
571 static boolean
PIT_AvoidDropoff(line_t
*line
)
573 if (line
->backsector
&& // Ignore one-sided linedefs
574 tmbbox
[BOXRIGHT
] > line
->bbox
[BOXLEFT
] &&
575 tmbbox
[BOXLEFT
] < line
->bbox
[BOXRIGHT
] &&
576 tmbbox
[BOXTOP
] > line
->bbox
[BOXBOTTOM
] && // Linedef must be contacted
577 tmbbox
[BOXBOTTOM
] < line
->bbox
[BOXTOP
] &&
578 P_BoxOnLineSide(tmbbox
, line
) == -1)
580 fixed_t front
= line
->frontsector
->floorheight
;
581 fixed_t back
= line
->backsector
->floorheight
;
584 // The monster must contact one of the two floors,
585 // and the other must be a tall dropoff (more than 24).
587 if (back
== floorz
&& front
< floorz
- FRACUNIT
*24)
588 angle
= R_PointToAngle2(0,0,line
->dx
,line
->dy
); // front side dropoff
590 if (front
== floorz
&& back
< floorz
- FRACUNIT
*24)
591 angle
= R_PointToAngle2(line
->dx
,line
->dy
,0,0); // back side dropoff
595 // Move away from dropoff at a standard speed.
596 // Multiple contacted linedefs are cumulative (e.g. hanging over corner)
597 dropoff_deltax
-= finesine
[angle
>> ANGLETOFINESHIFT
]*32;
598 dropoff_deltay
+= finecosine
[angle
>> ANGLETOFINESHIFT
]*32;
607 static fixed_t
P_AvoidDropoff(mobj_t
*actor
)
609 int yh
=((tmbbox
[BOXTOP
] = actor
->y
+actor
->radius
)-bmaporgy
)>>MAPBLOCKSHIFT
;
610 int yl
=((tmbbox
[BOXBOTTOM
]= actor
->y
-actor
->radius
)-bmaporgy
)>>MAPBLOCKSHIFT
;
611 int xh
=((tmbbox
[BOXRIGHT
] = actor
->x
+actor
->radius
)-bmaporgx
)>>MAPBLOCKSHIFT
;
612 int xl
=((tmbbox
[BOXLEFT
] = actor
->x
-actor
->radius
)-bmaporgx
)>>MAPBLOCKSHIFT
;
615 floorz
= actor
->z
; // remember floor height
617 dropoff_deltax
= dropoff_deltay
= 0;
622 for (bx
=xl
; bx
<=xh
; bx
++)
623 for (by
=yl
; by
<=yh
; by
++)
624 P_BlockLinesIterator(bx
, by
, PIT_AvoidDropoff
); // all contacted lines
626 return dropoff_deltax
| dropoff_deltay
; // Non-zero if movement prescribed
632 // killough 9/8/98: Split into two functions
635 static void P_NewChaseDir(mobj_t
*actor
)
637 mobj_t
*target
= actor
->target
;
638 fixed_t deltax
= target
->x
- actor
->x
;
639 fixed_t deltay
= target
->y
- actor
->y
;
641 // killough 8/8/98: sometimes move away from target, keeping distance
643 // 1) Stay a certain distance away from a friend, to avoid being in their way
644 // 2) Take advantage over an enemy without missiles, by keeping distance
646 actor
->strafecount
= 0;
649 if (actor
->floorz
- actor
->dropoffz
> FRACUNIT
*24 &&
650 actor
->z
<= actor
->floorz
&&
651 !(actor
->flags
& (MF_DROPOFF
|MF_FLOAT
)) &&
652 !comp
[comp_dropoff
] &&
653 P_AvoidDropoff(actor
)) /* Move away from dropoff */
655 P_DoNewChaseDir(actor
, dropoff_deltax
, dropoff_deltay
);
657 // If moving away from dropoff, set movecount to 1 so that
658 // small steps are taken to get monster away from dropoff.
660 actor
->movecount
= 1;
665 fixed_t dist
= P_AproxDistance(deltax
, deltay
);
667 // Move away from friends when too close, except
668 // in certain situations (e.g. a crowded lift)
670 if (actor
->flags
& target
->flags
& MF_FRIEND
&&
671 distfriend
<< FRACBITS
> dist
&&
672 !P_IsOnLift(target
) && !P_IsUnderDamage(actor
))
674 deltax
= -deltax
, deltay
= -deltay
;
676 if (target
->health
> 0 && (actor
->flags
^ target
->flags
) & MF_FRIEND
)
677 { // Live enemy target
678 if (monster_backing
&&
679 actor
->info
->missilestate
&& actor
->type
!= MT_SKULL
&&
680 ((!target
->info
->missilestate
&& dist
< MELEERANGE
*2) ||
681 (target
->player
&& dist
< MELEERANGE
*3 &&
682 (target
->player
->readyweapon
== wp_fist
||
683 target
->player
->readyweapon
== wp_chainsaw
))))
684 { // Back away from melee attacker
685 actor
->strafecount
= P_Random(pr_enemystrafe
) & 15;
686 deltax
= -deltax
, deltay
= -deltay
;
692 P_DoNewChaseDir(actor
, deltax
, deltay
);
694 // If strafing, set movecount to strafecount so that old Doom
695 // logic still works the same, except in the strafing part
697 if (actor
->strafecount
)
698 actor
->movecount
= actor
->strafecount
;
704 // killough 9/9/98: whether a target is visible to a monster
707 static boolean
P_IsVisible(mobj_t
*actor
, mobj_t
*mo
, boolean allaround
)
711 angle_t an
= R_PointToAngle2(actor
->x
, actor
->y
,
712 mo
->x
, mo
->y
) - actor
->angle
;
713 if (an
> ANG90
&& an
< ANG270
&&
714 P_AproxDistance(mo
->x
-actor
->x
, mo
->y
-actor
->y
) > MELEERANGE
)
717 return P_CheckSight(actor
, mo
);
725 // Finds monster targets for other monsters
728 static int current_allaround
;
730 static boolean
PIT_FindTarget(mobj_t
*mo
)
732 mobj_t
*actor
= current_actor
;
734 if (!((mo
->flags
^ actor
->flags
) & MF_FRIEND
&& // Invalid target
735 mo
->health
> 0 && (mo
->flags
& MF_COUNTKILL
|| mo
->type
== MT_SKULL
)))
738 // If the monster is already engaged in a one-on-one attack
739 // with a healthy friend, don't attack around 60% the time
741 const mobj_t
*targ
= mo
->target
;
742 if (targ
&& targ
->target
== mo
&&
743 P_Random(pr_skiptarget
) > 100 &&
744 (targ
->flags
^ mo
->flags
) & MF_FRIEND
&&
745 targ
->health
*2 >= targ
->info
->spawnhealth
)
749 if (!P_IsVisible(actor
, mo
, current_allaround
))
752 P_SetTarget(&actor
->lastenemy
, actor
->target
); // Remember previous target
753 P_SetTarget(&actor
->target
, mo
); // Found target
755 // Move the selected monster to the end of its associated
756 // list, so that it gets searched last next time.
759 thinker_t
*cap
= &thinkerclasscap
[mo
->flags
& MF_FRIEND
?
760 th_friends
: th_enemies
];
761 (mo
->thinker
.cprev
->cnext
= mo
->thinker
.cnext
)->cprev
= mo
->thinker
.cprev
;
762 (mo
->thinker
.cprev
= cap
->cprev
)->cnext
= &mo
->thinker
;
763 (mo
->thinker
.cnext
= cap
)->cprev
= &mo
->thinker
;
771 // If allaround is false, only look 180 degrees in front.
772 // Returns true if a player is targeted.
775 static boolean
P_LookForPlayers(mobj_t
*actor
, boolean allaround
)
780 if (actor
->flags
& MF_FRIEND
)
781 { // killough 9/9/98: friendly monsters go about players differently
785 if (!allaround
) // If you want friendly monsters not to awaken unprovoked
789 // Go back to a player, no matter whether it's visible or not
790 for (anyone
=0; anyone
<=1; anyone
++)
791 for (c
=0; c
<MAXPLAYERS
; c
++)
792 if (playeringame
[c
] && players
[c
].playerstate
==PST_LIVE
&&
793 (anyone
|| P_IsVisible(actor
, players
[c
].mo
, allaround
)))
795 P_SetTarget(&actor
->target
, players
[c
].mo
);
798 // get out of refiring loop, to avoid hitting player accidentally
800 if (actor
->info
->missilestate
)
802 P_SetMobjState(actor
, actor
->info
->seestate
);
803 actor
->flags
&= ~MF_JUSTHIT
;
812 // Change mask of 3 to (MAXPLAYERS-1) -- killough 2/15/98:
813 stop
= (actor
->lastlook
-1)&(MAXPLAYERS
-1);
817 stopc
= !mbf_features
&&
818 !demo_compatibility
&& monsters_remember
?
819 MAXPLAYERS
: 2; // killough 9/9/98
821 for (;; actor
->lastlook
= (actor
->lastlook
+1)&(MAXPLAYERS
-1))
823 if (!playeringame
[actor
->lastlook
])
826 // killough 2/15/98, 9/9/98:
827 if (c
++ == stopc
|| actor
->lastlook
== stop
) // done looking
830 player
= &players
[actor
->lastlook
];
832 if (player
->health
<= 0)
835 if (!P_IsVisible(actor
, player
->mo
, allaround
))
838 P_SetTarget(&actor
->target
, player
->mo
);
840 /* killough 9/9/98: give monsters a threshold towards getting players
841 * (we don't want it to be too easy for a player with dogs :)
843 if (!comp
[comp_pursuit
])
844 actor
->threshold
= 60;
851 // Friendly monsters, by Lee Killough 7/18/98
853 // Friendly monsters go after other monsters first, but
854 // also return to owner if they cannot find any targets.
855 // A marine's best friend :) killough 7/18/98, 9/98
858 static boolean
P_LookForMonsters(mobj_t
*actor
, boolean allaround
)
862 if (demo_compatibility
)
865 if (actor
->lastenemy
&& actor
->lastenemy
->health
> 0 && monsters_remember
&&
866 !(actor
->lastenemy
->flags
& actor
->flags
& MF_FRIEND
)) // not friends
868 P_SetTarget(&actor
->target
, actor
->lastenemy
);
869 P_SetTarget(&actor
->lastenemy
, NULL
);
873 /* Old demos do not support monster-seeking bots */
877 // Search the threaded list corresponding to this object's potential targets
878 cap
= &thinkerclasscap
[actor
->flags
& MF_FRIEND
? th_enemies
: th_friends
];
880 // Search for new enemy
882 if (cap
->cnext
!= cap
) // Empty list? bail out early
884 int x
= (actor
->x
- bmaporgx
)>>MAPBLOCKSHIFT
;
885 int y
= (actor
->y
- bmaporgy
)>>MAPBLOCKSHIFT
;
888 current_actor
= actor
;
889 current_allaround
= allaround
;
891 // Search first in the immediate vicinity.
893 if (!P_BlockThingsIterator(x
, y
, PIT_FindTarget
))
900 if (!P_BlockThingsIterator(x
+i
, y
-d
, PIT_FindTarget
) ||
901 !P_BlockThingsIterator(x
+i
, y
+d
, PIT_FindTarget
))
905 if (!P_BlockThingsIterator(x
-d
, y
+i
, PIT_FindTarget
) ||
906 !P_BlockThingsIterator(x
+d
, y
+i
, PIT_FindTarget
))
908 while (--i
+ d
>= 0);
911 { // Random number of monsters, to prevent patterns from forming
912 int n
= (P_Random(pr_friends
) & 31) + 15;
914 for (th
= cap
->cnext
; th
!= cap
; th
= th
->cnext
)
917 // Only a subset of the monsters were searched. Move all of
918 // the ones which were searched so far, to the end of the list.
920 (cap
->cnext
->cprev
= cap
->cprev
)->cnext
= cap
->cnext
;
921 (cap
->cprev
= th
->cprev
)->cnext
= cap
;
922 (th
->cprev
= cap
)->cnext
= th
;
926 if (!PIT_FindTarget((mobj_t
*) th
)) // If target sighted
931 return false; // No monster found
937 // killough 9/5/98: look for targets to go after, depending on kind of monster
940 static boolean
P_LookForTargets(mobj_t
*actor
, int allaround
)
942 return actor
->flags
& MF_FRIEND
?
943 P_LookForMonsters(actor
, allaround
) || P_LookForPlayers (actor
, allaround
):
944 P_LookForPlayers (actor
, allaround
) || P_LookForMonsters(actor
, allaround
);
950 // killough 9/8/98: Help friends in danger of dying
953 static boolean
P_HelpFriend(mobj_t
*actor
)
957 // If less than 33% health, self-preservation rules
958 if (actor
->health
*3 < actor
->info
->spawnhealth
)
961 current_actor
= actor
;
962 current_allaround
= true;
964 // Possibly help a friend under 50% health
965 cap
= &thinkerclasscap
[actor
->flags
& MF_FRIEND
? th_friends
: th_enemies
];
967 for (th
= cap
->cnext
; th
!= cap
; th
= th
->cnext
)
968 if (((mobj_t
*) th
)->health
*2 >= ((mobj_t
*) th
)->info
->spawnhealth
)
970 if (P_Random(pr_helpfriend
) < 180)
974 if (((mobj_t
*) th
)->flags
& MF_JUSTHIT
&&
975 ((mobj_t
*) th
)->target
&&
976 ((mobj_t
*) th
)->target
!= actor
->target
&&
977 !PIT_FindTarget(((mobj_t
*) th
)->target
))
979 // Ignore any attacking monsters, while searching for friend
980 actor
->threshold
= BASETHRESHOLD
;
989 // DOOM II special, map 32.
990 // Uses special tag 666.
992 void A_KeenDie(mobj_t
* mo
)
999 // scan the remaining thinkers to see if all Keens are dead
1001 for (th
= thinkercap
.next
; th
!= &thinkercap
; th
=th
->next
)
1002 if (th
->function
== P_MobjThinker
)
1004 mobj_t
*mo2
= (mobj_t
*) th
;
1005 if (mo2
!= mo
&& mo2
->type
== mo
->type
&& mo2
->health
> 0)
1006 return; // other Keen not dead
1010 EV_DoDoor(&junk
,p_open
);
1020 // Stay in state until a player is sighted.
1023 void A_Look(mobj_t
*actor
)
1025 mobj_t
*targ
= actor
->subsector
->sector
->soundtarget
;
1026 actor
->threshold
= 0; // any shot will wake up
1028 /* killough 7/18/98:
1029 * Friendly monsters go after other monsters first, but
1030 * also return to player, without attacking them, if they
1031 * cannot find any targets. A marine's best friend :)
1033 actor
->pursuecount
= 0;
1035 if (!(actor
->flags
& MF_FRIEND
&& P_LookForTargets(actor
, false)) &&
1036 !((targ
= actor
->subsector
->sector
->soundtarget
) &&
1037 targ
->flags
& MF_SHOOTABLE
&&
1038 (P_SetTarget(&actor
->target
, targ
),
1039 !(actor
->flags
& MF_AMBUSH
) || P_CheckSight(actor
, targ
))) &&
1040 (actor
->flags
& MF_FRIEND
|| !P_LookForTargets(actor
, false)))
1043 // go into chase state
1045 if (actor
->info
->seesound
)
1048 switch (actor
->info
->seesound
)
1053 sound
= sfx_posit1
+P_Random(pr_see
)%3;
1058 sound
= sfx_bgsit1
+P_Random(pr_see
)%2;
1062 sound
= actor
->info
->seesound
;
1065 if (actor
->type
==MT_SPIDER
|| actor
->type
== MT_CYBORG
)
1066 S_StartSound(NULL
, sound
); // full volume
1068 S_StartSound(actor
, sound
);
1070 P_SetMobjState(actor
, actor
->info
->seestate
);
1077 // Allows monsters to continue movement while attacking
1080 void A_KeepChasing(mobj_t
*actor
)
1082 if (actor
->movecount
)
1085 if (actor
->strafecount
)
1086 actor
->strafecount
--;
1093 // Actor has a melee attack,
1094 // so it tries to close as fast as possible
1097 void A_Chase(mobj_t
*actor
)
1099 if (actor
->reactiontime
)
1100 actor
->reactiontime
--;
1102 if (actor
->threshold
) { /* modify target threshold */
1103 if (!actor
->target
|| actor
->target
->health
<= 0)
1104 actor
->threshold
= 0;
1109 /* turn towards movement direction if not there yet
1110 * killough 9/7/98: keep facing towards target if strafing or backing out
1113 if (actor
->strafecount
)
1114 A_FaceTarget(actor
);
1115 else if (actor
->movedir
< 8)
1117 int delta
= (actor
->angle
&= (7<<29)) - (actor
->movedir
<< 29);
1119 actor
->angle
-= ANG90
/2;
1122 actor
->angle
+= ANG90
/2;
1125 if (!actor
->target
|| !(actor
->target
->flags
&MF_SHOOTABLE
))
1127 if (!P_LookForTargets(actor
,true)) // look for a new target
1128 P_SetMobjState(actor
, actor
->info
->spawnstate
); // no new target
1132 // do not attack twice in a row
1133 if (actor
->flags
& MF_JUSTATTACKED
)
1135 actor
->flags
&= ~MF_JUSTATTACKED
;
1136 if (gameskill
!= sk_nightmare
&& !fastparm
)
1137 P_NewChaseDir(actor
);
1141 // check for melee attack
1142 if (actor
->info
->meleestate
&& P_CheckMeleeRange(actor
))
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
;
1154 // check for missile attack
1155 if (actor
->info
->missilestate
)
1156 if (!(gameskill
< sk_nightmare
&& !fastparm
&& actor
->movecount
))
1157 if (P_CheckMissileRange(actor
))
1159 P_SetMobjState(actor
, actor
->info
->missilestate
);
1160 actor
->flags
|= MF_JUSTATTACKED
;
1164 if (!actor
->threshold
) {
1166 { /* killough 9/9/98: for backward demo compatibility */
1167 if (netgame
&& !P_CheckSight(actor
, actor
->target
) &&
1168 P_LookForPlayers(actor
, true))
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
--;
1178 /* Our pursuit time has expired. We're going to think about
1179 * changing targets */
1180 actor
->pursuecount
= BASETHRESHOLD
;
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 */
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))
1195 /* (Current target was good, or no new target was found.)
1197 * If monster is a missile-less friend, give up pursuit and
1198 * return to player, if no attacks have occurred recently.
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 */
1210 if (actor
->strafecount
)
1211 actor
->strafecount
--;
1213 // chase towards player
1214 if (--actor
->movecount
<0 || !P_SmartMove(actor
))
1215 P_NewChaseDir(actor
);
1217 // make active sound
1218 if (actor
->info
->activesound
&& P_Random(pr_see
)<3)
1219 S_StartSound(actor
, actor
->info
->activesound
);
1225 void A_FaceTarget(mobj_t
*actor
)
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;
1243 void A_PosAttack(mobj_t
*actor
)
1245 int angle
, damage
, slope
, t
;
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
);
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
);
1261 void A_SPosAttack(mobj_t
* actor
)
1263 int i
, bangle
, slope
;
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 */
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
);
1280 void A_CPosAttack(mobj_t
*actor
)
1282 int angle
, bangle
, damage
, slope
, t
;
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 */
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
);
1298 void A_CPosRefire(mobj_t
*actor
)
1300 // keep firing unless target got out of sight
1301 A_FaceTarget(actor
);
1303 /* killough 12/98: Stop firing if a friend has gotten in the way */
1304 if (P_HitFriend(actor
))
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
)
1315 if (!actor
->target
|| actor
->target
->health
<= 0
1316 || !P_CheckSight(actor
, actor
->target
))
1317 stop
: P_SetMobjState(actor
, actor
->info
->seestate
);
1320 void A_SpidRefire(mobj_t
* actor
)
1322 // keep firing unless target got out of sight
1323 A_FaceTarget(actor
);
1325 /* killough 12/98: Stop firing if a friend has gotten in the way */
1326 if (P_HitFriend(actor
))
1329 if (P_Random(pr_spidrefire
) < 10)
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
);
1339 void A_BspiAttack(mobj_t
*actor
)
1343 A_FaceTarget(actor
);
1344 P_SpawnMissile(actor
, actor
->target
, MT_ARACHPLAZ
); // launch a missile
1351 void A_TroopAttack(mobj_t
*actor
)
1355 A_FaceTarget(actor
);
1356 if (P_CheckMeleeRange(actor
))
1359 S_StartSound(actor
, sfx_claw
);
1360 damage
= (P_Random(pr_troopattack
)%8+1)*3;
1361 P_DamageMobj(actor
->target
, actor
, actor
, damage
);
1364 P_SpawnMissile(actor
, actor
->target
, MT_TROOPSHOT
); // launch a missile
1367 void A_SargAttack(mobj_t
*actor
)
1371 A_FaceTarget(actor
);
1372 if (P_CheckMeleeRange(actor
))
1374 int damage
= ((P_Random(pr_sargattack
)%10)+1)*4;
1375 P_DamageMobj(actor
->target
, actor
, actor
, damage
);
1379 void A_HeadAttack(mobj_t
*actor
)
1383 A_FaceTarget (actor
);
1384 if (P_CheckMeleeRange(actor
))
1386 int damage
= (P_Random(pr_headattack
)%6+1)*10;
1387 P_DamageMobj(actor
->target
, actor
, actor
, damage
);
1390 P_SpawnMissile(actor
, actor
->target
, MT_HEADSHOT
); // launch a missile
1393 void A_CyberAttack(mobj_t
*actor
)
1397 A_FaceTarget(actor
);
1398 P_SpawnMissile(actor
, actor
->target
, MT_ROCKET
);
1401 void A_BruisAttack(mobj_t
*actor
)
1405 if (P_CheckMeleeRange(actor
))
1408 S_StartSound(actor
, sfx_claw
);
1409 damage
= (P_Random(pr_bruisattack
)%8+1)*10;
1410 P_DamageMobj(actor
->target
, actor
, actor
, damage
);
1413 P_SpawnMissile(actor
, actor
->target
, MT_BRUISERSHOT
); // launch a missile
1420 void A_SkelMissile(mobj_t
*actor
)
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
1434 P_SetTarget(&mo
->tracer
, actor
->target
);
1437 int TRACEANGLE
= 0xc000000;
1439 void A_Tracer(mobj_t
*actor
)
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.
1451 * killough 3/6/98: fix revenant internal demo bug by subtracting
1452 * levelstarttic from gametic.
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.
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).
1462 if ((gametic
-basetic
) & 3)
1465 // spawn a puff of smoke behind the rocket
1466 P_SpawnPuff(actor
->x
, actor
->y
, actor
->z
);
1468 th
= P_SpawnMobj (actor
->x
-actor
->momx
,
1469 actor
->y
-actor
->momy
,
1470 actor
->z
, MT_SMOKE
);
1472 th
->momz
= FRACUNIT
;
1473 th
->tics
-= P_Random(pr_tracer
) & 3;
1478 dest
= actor
->tracer
;
1480 if (!dest
|| dest
->health
<= 0)
1484 exact
= R_PointToAngle2(actor
->x
, actor
->y
, dest
->x
, dest
->y
);
1486 if (exact
!= actor
->angle
) {
1487 if (exact
- actor
->angle
> 0x80000000)
1489 actor
->angle
-= TRACEANGLE
;
1490 if (exact
- actor
->angle
< 0x80000000)
1491 actor
->angle
= exact
;
1495 actor
->angle
+= TRACEANGLE
;
1496 if (exact
- actor
->angle
> 0x80000000)
1497 actor
->angle
= exact
;
1501 exact
= actor
->angle
>>ANGLETOFINESHIFT
;
1502 actor
->momx
= FixedMul(actor
->info
->speed
, finecosine
[exact
]);
1503 actor
->momy
= FixedMul(actor
->info
->speed
, finesine
[exact
]);
1506 dist
= P_AproxDistance(dest
->x
- actor
->x
, dest
->y
- actor
->y
);
1508 dist
= dist
/ actor
->info
->speed
;
1513 slope
= (dest
->z
+40*FRACUNIT
- actor
->z
) / dist
;
1515 if (slope
< actor
->momz
)
1516 actor
->momz
-= FRACUNIT
/8;
1518 actor
->momz
+= FRACUNIT
/8;
1521 void A_SkelWhoosh(mobj_t
*actor
)
1525 A_FaceTarget(actor
);
1526 S_StartSound(actor
,sfx_skeswg
);
1529 void A_SkelFist(mobj_t
*actor
)
1533 A_FaceTarget(actor
);
1534 if (P_CheckMeleeRange(actor
))
1536 int damage
= ((P_Random(pr_skelfist
)%10)+1)*6;
1537 S_StartSound(actor
, sfx_skepch
);
1538 P_DamageMobj(actor
->target
, actor
, actor
, damage
);
1544 // Detect a corpse that could be raised.
1552 boolean
PIT_VileCheck(mobj_t
*thing
)
1557 if (!(thing
->flags
& MF_CORPSE
) )
1558 return true; // not a monster
1560 if (thing
->tics
!= -1)
1561 return true; // not lying still yet
1563 if (thing
->info
->raisestate
== S_NULL
)
1564 return true; // monster doesn't have a raise state
1566 maxdist
= thing
->info
->radius
+ mobjinfo
[MT_VILE
].radius
;
1568 if (D_abs(thing
->x
-viletryx
) > maxdist
|| D_abs(thing
->y
-viletryy
) > maxdist
)
1569 return true; // not actually touching
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
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
1579 // if (Option3) // ^
1580 // if ((thing->height == 0) && (thing->radius == 0)) // |
1581 // return true; // phares
1584 corpsehit
->momx
= corpsehit
->momy
= 0;
1585 if (comp
[comp_vile
]) // phares
1587 corpsehit
->height
<<= 2; // V
1588 check
= P_CheckPosition(corpsehit
,corpsehit
->x
,corpsehit
->y
);
1589 corpsehit
->height
>>= 2;
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
;
1607 return true; // doesn't fit here
1608 return false; // got one, so stop checking
1613 // Check for ressurecting a body
1616 void A_VileChase(mobj_t
* actor
)
1622 if (actor
->movedir
!= DI_NODIR
)
1624 // check for corpses to raise
1626 actor
->x
+ actor
->info
->speed
*xspeed
[actor
->movedir
];
1628 actor
->y
+ actor
->info
->speed
*yspeed
[actor
->movedir
];
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
;
1636 for (bx
=xl
; bx
<=xh
; bx
++)
1638 for (by
=yl
; by
<=yh
; by
++)
1640 // Call PIT_VileCheck to check
1641 // whether object is a corpse
1642 // that canbe raised.
1643 if (!P_BlockThingsIterator(bx
,by
,PIT_VileCheck
))
1648 mobj_t
* temp
= actor
->target
;
1649 actor
->target
= corpsehit
;
1650 A_FaceTarget(actor
);
1651 actor
->target
= temp
;
1653 P_SetMobjState(actor
, S_VILE_HEAL1
);
1654 S_StartSound(corpsehit
, sfx_slop
);
1655 info
= corpsehit
->info
;
1657 P_SetMobjState(corpsehit
,info
->raisestate
);
1659 if (comp
[comp_vile
]) // phares
1660 corpsehit
->height
<<= 2; // |
1663 corpsehit
->height
= info
->height
; // fix Ghost bug
1664 corpsehit
->radius
= info
->radius
; // fix Ghost bug
1667 /* killough 7/18/98:
1668 * friendliness is transferred from AV to raised corpse
1671 (info
->flags
& ~MF_FRIEND
) | (actor
->flags
& MF_FRIEND
);
1673 if (!((corpsehit
->flags
^ MF_COUNTKILL
) & (MF_FRIEND
| MF_COUNTKILL
)))
1676 corpsehit
->health
= info
->spawnhealth
;
1677 P_SetTarget(&corpsehit
->target
, NULL
); // killough 11/98
1680 { /* kilough 9/9/98 */
1681 P_SetTarget(&corpsehit
->lastenemy
, NULL
);
1682 corpsehit
->flags
&= ~MF_JUSTHIT
;
1685 /* killough 8/29/98: add to appropriate thread */
1686 P_UpdateThinker(&corpsehit
->thinker
);
1693 A_Chase(actor
); // Return to normal attack.
1700 void A_VileStart(mobj_t
*actor
)
1702 S_StartSound(actor
, sfx_vilatk
);
1707 // Keep fire in front of player unless out of sight
1710 void A_Fire(mobj_t
*actor
);
1712 void A_StartFire(mobj_t
*actor
)
1714 S_StartSound(actor
,sfx_flamst
);
1718 void A_FireCrackle(mobj_t
* actor
)
1720 S_StartSound(actor
,sfx_flame
);
1724 void A_Fire(mobj_t
*actor
)
1727 mobj_t
*dest
= actor
->tracer
;
1732 // don't move it if the vile lost sight
1733 if (!P_CheckSight(actor
->target
, dest
) )
1736 an
= dest
->angle
>> ANGLETOFINESHIFT
;
1738 P_UnsetThingPosition(actor
);
1739 actor
->x
= dest
->x
+ FixedMul(24*FRACUNIT
, finecosine
[an
]);
1740 actor
->y
= dest
->y
+ FixedMul(24*FRACUNIT
, finesine
[an
]);
1742 P_SetThingPosition(actor
);
1747 // Spawn the hellfire
1750 void A_VileTarget(mobj_t
*actor
)
1757 A_FaceTarget(actor
);
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
);
1764 P_SetTarget(&actor
->tracer
, fog
);
1765 P_SetTarget(&fog
->target
, actor
);
1766 P_SetTarget(&fog
->tracer
, actor
->target
);
1774 void A_VileAttack(mobj_t
*actor
)
1782 A_FaceTarget(actor
);
1784 if (!P_CheckSight(actor
, actor
->target
))
1787 S_StartSound(actor
, sfx_barexp
);
1788 P_DamageMobj(actor
->target
, actor
, actor
, 20);
1789 actor
->target
->momz
= 1000*FRACUNIT
/actor
->target
->info
->mass
;
1791 an
= actor
->angle
>> ANGLETOFINESHIFT
;
1793 fire
= actor
->tracer
;
1798 // move the fire between the vile and the player
1799 fire
->x
= actor
->target
->x
- FixedMul (24*FRACUNIT
, finecosine
[an
]);
1800 fire
->y
= actor
->target
->y
- FixedMul (24*FRACUNIT
, finesine
[an
]);
1801 P_RadiusAttack(fire
, actor
, 70);
1806 // firing three missiles (bruisers)
1807 // in three different directions?
1808 // Doesn't look like it.
1811 #define FATSPREAD (ANG90/8)
1813 void A_FatRaise(mobj_t
*actor
)
1815 A_FaceTarget(actor
);
1816 S_StartSound(actor
, sfx_manatk
);
1819 void A_FatAttack1(mobj_t
*actor
)
1824 A_FaceTarget(actor
);
1826 // Change direction to ...
1827 actor
->angle
+= FATSPREAD
;
1829 P_SpawnMissile(actor
, actor
->target
, MT_FATSHOT
);
1831 mo
= P_SpawnMissile (actor
, actor
->target
, MT_FATSHOT
);
1832 mo
->angle
+= FATSPREAD
;
1833 an
= mo
->angle
>> ANGLETOFINESHIFT
;
1834 mo
->momx
= FixedMul(mo
->info
->speed
, finecosine
[an
]);
1835 mo
->momy
= FixedMul(mo
->info
->speed
, finesine
[an
]);
1838 void A_FatAttack2(mobj_t
*actor
)
1843 A_FaceTarget(actor
);
1844 // Now here choose opposite deviation.
1845 actor
->angle
-= FATSPREAD
;
1846 P_SpawnMissile(actor
, actor
->target
, MT_FATSHOT
);
1848 mo
= P_SpawnMissile(actor
, actor
->target
, MT_FATSHOT
);
1849 mo
->angle
-= FATSPREAD
*2;
1850 an
= mo
->angle
>> ANGLETOFINESHIFT
;
1851 mo
->momx
= FixedMul(mo
->info
->speed
, finecosine
[an
]);
1852 mo
->momy
= FixedMul(mo
->info
->speed
, finesine
[an
]);
1855 void A_FatAttack3(mobj_t
*actor
)
1860 A_FaceTarget(actor
);
1862 mo
= P_SpawnMissile(actor
, actor
->target
, MT_FATSHOT
);
1863 mo
->angle
-= FATSPREAD
/2;
1864 an
= mo
->angle
>> ANGLETOFINESHIFT
;
1865 mo
->momx
= FixedMul(mo
->info
->speed
, finecosine
[an
]);
1866 mo
->momy
= FixedMul(mo
->info
->speed
, finesine
[an
]);
1868 mo
= P_SpawnMissile(actor
, actor
->target
, MT_FATSHOT
);
1869 mo
->angle
+= FATSPREAD
/2;
1870 an
= mo
->angle
>> ANGLETOFINESHIFT
;
1871 mo
->momx
= FixedMul(mo
->info
->speed
, finecosine
[an
]);
1872 mo
->momy
= FixedMul(mo
->info
->speed
, finesine
[an
]);
1878 // Fly at the player like a missile.
1880 #define SKULLSPEED (20*FRACUNIT)
1882 void A_SkullAttack(mobj_t
*actor
)
1891 dest
= actor
->target
;
1892 actor
->flags
|= MF_SKULLFLY
;
1894 S_StartSound(actor
, actor
->info
->attacksound
);
1895 A_FaceTarget(actor
);
1896 an
= actor
->angle
>> ANGLETOFINESHIFT
;
1897 actor
->momx
= FixedMul(SKULLSPEED
, finecosine
[an
]);
1898 actor
->momy
= FixedMul(SKULLSPEED
, finesine
[an
]);
1899 dist
= P_AproxDistance(dest
->x
- actor
->x
, dest
->y
- actor
->y
);
1900 dist
= dist
/ SKULLSPEED
;
1904 actor
->momz
= (dest
->z
+(dest
->height
>>1) - actor
->z
) / dist
;
1909 // Spawn a lost soul and launch it at the target
1912 void A_PainShootSkull(mobj_t
*actor
, angle_t angle
)
1919 // The original code checked for 20 skulls on the level, // phares
1920 // and wouldn't spit another one if there were. If not in // phares
1921 // compatibility mode, we remove the limit. // phares
1923 if (comp
[comp_pain
]) /* killough 10/98: compatibility-optioned */
1925 // count total number of skulls currently on the level
1927 thinker_t
*currentthinker
;
1928 for (currentthinker
= thinkercap
.next
;
1929 currentthinker
!= &thinkercap
;
1930 currentthinker
= currentthinker
->next
)
1931 if ((currentthinker
->function
== P_MobjThinker
)
1932 && ((mobj_t
*)currentthinker
)->type
== MT_SKULL
)
1934 if (count
> 20) // phares
1938 // okay, there's room for another one
1940 an
= angle
>> ANGLETOFINESHIFT
;
1942 prestep
= 4*FRACUNIT
+ 3*(actor
->info
->radius
+ mobjinfo
[MT_SKULL
].radius
)/2;
1944 x
= actor
->x
+ FixedMul(prestep
, finecosine
[an
]);
1945 y
= actor
->y
+ FixedMul(prestep
, finesine
[an
]);
1946 z
= actor
->z
+ 8*FRACUNIT
;
1948 if (comp
[comp_skull
]) /* killough 10/98: compatibility-optioned */
1949 newmobj
= P_SpawnMobj(x
, y
, z
, MT_SKULL
); // phares
1952 // Check whether the Lost Soul is being fired through a 1-sided
1953 // wall or an impassible line, or a "monsters can't cross" line.
1954 // If it is, then we don't allow the spawn. This is a bug fix, but
1955 // it should be considered an enhancement, since it may disturb
1956 // existing demos, so don't do it in compatibility mode.
1958 if (Check_Sides(actor
,x
,y
))
1961 newmobj
= P_SpawnMobj(x
, y
, z
, MT_SKULL
);
1963 // Check to see if the new Lost Soul's z value is above the
1964 // ceiling of its new sector, or below the floor. If so, kill it.
1967 (newmobj
->subsector
->sector
->ceilingheight
- newmobj
->height
)) ||
1968 (newmobj
->z
< newmobj
->subsector
->sector
->floorheight
))
1970 // kill it immediately
1971 P_DamageMobj(newmobj
,actor
,actor
,10000);
1976 /* killough 7/20/98: PEs shoot lost souls with the same friendliness */
1977 newmobj
->flags
= (newmobj
->flags
& ~MF_FRIEND
) | (actor
->flags
& MF_FRIEND
);
1979 /* killough 8/29/98: add to appropriate thread */
1980 P_UpdateThinker(&newmobj
->thinker
);
1982 // Check for movements.
1983 // killough 3/15/98: don't jump over dropoffs:
1985 if (!P_TryMove(newmobj
, newmobj
->x
, newmobj
->y
, false))
1987 // kill it immediately
1988 P_DamageMobj(newmobj
, actor
, actor
, 10000);
1992 P_SetTarget(&newmobj
->target
, actor
->target
);
1993 A_SkullAttack(newmobj
);
1998 // Spawn a lost soul and launch it at the target
2001 void A_PainAttack(mobj_t
*actor
)
2005 A_FaceTarget(actor
);
2006 A_PainShootSkull(actor
, actor
->angle
);
2009 void A_PainDie(mobj_t
*actor
)
2012 A_PainShootSkull(actor
, actor
->angle
+ANG90
);
2013 A_PainShootSkull(actor
, actor
->angle
+ANG180
);
2014 A_PainShootSkull(actor
, actor
->angle
+ANG270
);
2017 void A_Scream(mobj_t
*actor
)
2021 switch (actor
->info
->deathsound
)
2029 sound
= sfx_podth1
+ P_Random(pr_scream
)%3;
2034 sound
= sfx_bgdth1
+ P_Random(pr_scream
)%2;
2038 sound
= actor
->info
->deathsound
;
2042 // Check for bosses.
2043 if (actor
->type
==MT_SPIDER
|| actor
->type
== MT_CYBORG
)
2044 S_StartSound(NULL
, sound
); // full volume
2046 S_StartSound(actor
, sound
);
2049 void A_XScream(mobj_t
*actor
)
2051 S_StartSound(actor
, sfx_slop
);
2054 void A_Pain(mobj_t
*actor
)
2056 if (actor
->info
->painsound
)
2057 S_StartSound(actor
, actor
->info
->painsound
);
2060 void A_Fall(mobj_t
*actor
)
2062 // actor is on ground, it can be walked over
2063 actor
->flags
&= ~MF_SOLID
;
2069 void A_Explode(mobj_t
*thingy
)
2071 P_RadiusAttack( thingy
, thingy
->target
, 128 );
2076 // Possibly trigger special effects
2077 // if on first boss level
2080 void A_BossDeath(mobj_t
*mo
)
2086 if (gamemode
== commercial
)
2091 if ((mo
->type
!= MT_FATSO
)
2092 && (mo
->type
!= MT_BABY
))
2103 if (mo
->type
!= MT_BRUISER
)
2111 if (mo
->type
!= MT_CYBORG
)
2119 if (mo
->type
!= MT_SPIDER
)
2128 if (mo
->type
!= MT_CYBORG
)
2133 if (mo
->type
!= MT_SPIDER
)
2151 // make sure there is a player alive for victory
2152 for (i
=0; i
<MAXPLAYERS
; i
++)
2153 if (playeringame
[i
] && players
[i
].health
> 0)
2157 return; // no one left alive, so do not end game
2159 // scan the remaining thinkers to see
2160 // if all bosses are dead
2161 for (th
= thinkercap
.next
; th
!= &thinkercap
; th
=th
->next
)
2162 if (th
->function
== P_MobjThinker
)
2164 mobj_t
*mo2
= (mobj_t
*) th
;
2165 if (mo2
!= mo
&& mo2
->type
== mo
->type
&& mo2
->health
> 0)
2166 return; // other boss not dead
2170 if ( gamemode
== commercial
)
2174 if (mo
->type
== MT_FATSO
)
2177 EV_DoFloor(&junk
,lowerFloorToLowest
);
2181 if (mo
->type
== MT_BABY
)
2184 EV_DoFloor(&junk
,raiseToTexture
);
2195 EV_DoFloor(&junk
, lowerFloorToLowest
);
2204 EV_DoDoor(&junk
, blazeOpen
);
2210 EV_DoFloor(&junk
, lowerFloorToLowest
);
2220 void A_Hoof (mobj_t
* mo
)
2222 S_StartSound(mo
, sfx_hoof
);
2226 void A_Metal(mobj_t
*mo
)
2228 S_StartSound(mo
, sfx_metal
);
2232 void A_BabyMetal(mobj_t
*mo
)
2234 S_StartSound(mo
, sfx_bspwlk
);
2238 void A_OpenShotgun2(player_t
*player
, pspdef_t
*psp
)
2241 S_StartSound(player
->mo
, sfx_dbopn
);
2244 void A_LoadShotgun2(player_t
*player
, pspdef_t
*psp
)
2247 S_StartSound(player
->mo
, sfx_dbload
);
2250 void A_ReFire(player_t
*player
, pspdef_t
*psp
);
2252 void A_CloseShotgun2(player_t
*player
, pspdef_t
*psp
)
2254 S_StartSound(player
->mo
, sfx_dbcls
);
2255 A_ReFire(player
,psp
);
2258 // killough 2/7/98: Remove limit on icon landings:
2259 mobj_t
**braintargets
;
2260 int numbraintargets_alloc
;
2261 int numbraintargets
;
2263 struct brain_s brain
; // killough 3/26/98: global state of boss brain
2265 // killough 3/26/98: initialize icon landings at level startup,
2266 // rather than at boss wakeup, to prevent savegame-related crashes
2268 void P_SpawnBrainTargets(void) // killough 3/26/98: renamed old function
2272 // find all the target spots
2273 numbraintargets
= 0;
2275 brain
.easy
= 0; // killough 3/26/98: always init easy to 0
2277 for (thinker
= thinkercap
.next
;
2278 thinker
!= &thinkercap
;
2279 thinker
= thinker
->next
)
2280 if (thinker
->function
== P_MobjThinker
)
2282 mobj_t
*m
= (mobj_t
*) thinker
;
2284 if (m
->type
== MT_BOSSTARGET
)
2285 { // killough 2/7/98: remove limit on icon landings:
2286 if (numbraintargets
>= numbraintargets_alloc
)
2287 braintargets
= realloc(braintargets
,
2288 (numbraintargets_alloc
= numbraintargets_alloc
?
2289 numbraintargets_alloc
*2 : 32) *sizeof *braintargets
);
2290 braintargets
[numbraintargets
++] = m
;
2295 void A_BrainAwake(mobj_t
*mo
)
2298 S_StartSound(NULL
,sfx_bossit
); // killough 3/26/98: only generates sound now
2301 void A_BrainPain(mobj_t
*mo
)
2304 S_StartSound(NULL
,sfx_bospn
);
2307 void A_BrainScream(mobj_t
*mo
)
2310 for (x
=mo
->x
- 196*FRACUNIT
; x
< mo
->x
+ 320*FRACUNIT
; x
+= FRACUNIT
*8)
2312 int y
= mo
->y
- 320*FRACUNIT
;
2313 int z
= 128 + P_Random(pr_brainscream
)*2*FRACUNIT
;
2314 mobj_t
*th
= P_SpawnMobj (x
,y
,z
, MT_ROCKET
);
2315 th
->momz
= P_Random(pr_brainscream
)*512;
2316 P_SetMobjState(th
, S_BRAINEXPLODE1
);
2317 th
->tics
-= P_Random(pr_brainscream
)&7;
2321 S_StartSound(NULL
,sfx_bosdth
);
2324 void A_BrainExplode(mobj_t
*mo
)
2325 { // killough 5/5/98: remove dependence on order of evaluation:
2327 int t
= P_Random(pr_brainexp
);
2328 int x
= mo
->x
+ (t
- P_Random(pr_brainexp
))*2048;
2330 int z
= 128 + P_Random(pr_brainexp
)*2*FRACUNIT
;
2331 mobj_t
*th
= P_SpawnMobj(x
,y
,z
, MT_ROCKET
);
2332 th
->momz
= P_Random(pr_brainexp
)*512;
2333 P_SetMobjState(th
, S_BRAINEXPLODE1
);
2334 th
->tics
-= P_Random(pr_brainexp
)&7;
2339 void A_BrainDie(mobj_t
*mo
)
2345 void A_BrainSpit(mobj_t
*mo
)
2347 mobj_t
*targ
, *newmobj
;
2349 if (!numbraintargets
) // killough 4/1/98: ignore if no targets
2352 brain
.easy
^= 1; // killough 3/26/98: use brain struct
2353 if (gameskill
<= sk_easy
&& !brain
.easy
)
2356 // shoot a cube at current target
2357 targ
= braintargets
[brain
.targeton
++]; // killough 3/26/98:
2358 brain
.targeton
%= numbraintargets
; // Use brain struct for targets
2360 // spawn brain missile
2361 newmobj
= P_SpawnMissile(mo
, targ
, MT_SPAWNSHOT
);
2362 P_SetTarget(&newmobj
->target
, targ
);
2363 newmobj
->reactiontime
= (short)(((targ
->y
-mo
->y
)/newmobj
->momy
)/newmobj
->state
->tics
);
2365 // killough 7/18/98: brain friendliness is transferred
2366 newmobj
->flags
= (newmobj
->flags
& ~MF_FRIEND
) | (mo
->flags
& MF_FRIEND
);
2368 // killough 8/29/98: add to appropriate thread
2369 P_UpdateThinker(&newmobj
->thinker
);
2371 S_StartSound(NULL
, sfx_bospit
);
2374 void A_SpawnFly(mobj_t
*mo
);
2376 // travelling cube sound
2377 void A_SpawnSound(mobj_t
*mo
)
2379 S_StartSound(mo
,sfx_boscub
);
2383 void A_SpawnFly(mobj_t
*mo
)
2391 if (--mo
->reactiontime
)
2392 return; // still flying
2396 // First spawn teleport fog.
2397 fog
= P_SpawnMobj(targ
->x
, targ
->y
, targ
->z
, MT_SPAWNFIRE
);
2398 S_StartSound(fog
, sfx_telept
);
2400 // Randomly select monster to spawn.
2401 r
= P_Random(pr_spawnfly
);
2403 // Probability distribution (kind of :), decreasing likelihood.
2427 newmobj
= P_SpawnMobj(targ
->x
, targ
->y
, targ
->z
, type
);
2429 /* killough 7/18/98: brain friendliness is transferred */
2430 newmobj
->flags
= (newmobj
->flags
& ~MF_FRIEND
) | (mo
->flags
& MF_FRIEND
);
2432 /* killough 8/29/98: add to appropriate thread */
2433 P_UpdateThinker(&newmobj
->thinker
);
2435 if (P_LookForTargets(newmobj
,true)) /* killough 9/4/98 */
2436 P_SetMobjState(newmobj
, newmobj
->info
->seestate
);
2438 // telefrag anything in this spot
2439 P_TeleportMove(newmobj
, newmobj
->x
, newmobj
->y
, true); /* killough 8/9/98 */
2441 // remove self (i.e., cube).
2445 void A_PlayerScream(mobj_t
*mo
)
2447 int sound
= sfx_pldeth
; // Default death sound.
2448 if (gamemode
!= shareware
&& mo
->health
< -50)
2449 sound
= sfx_pdiehi
; // IF THE PLAYER DIES LESS THAN -50% WITHOUT GIBBING
2450 S_StartSound(mo
, sound
);
2453 /* cph - MBF-added codepointer functions */
2455 // killough 11/98: kill an object
2456 void A_Die(mobj_t
*actor
)
2458 P_DamageMobj(actor
, NULL
, NULL
, actor
->health
);
2463 // killough 8/9/98: same as A_Explode, except that the damage is variable
2466 void A_Detonate(mobj_t
*mo
)
2468 P_RadiusAttack(mo
, mo
->target
, mo
->info
->damage
);
2472 // killough 9/98: a mushroom explosion effect, sorta :)
2473 // Original idea: Linguica
2476 void A_Mushroom(mobj_t
*actor
)
2478 int i
, j
, n
= actor
->info
->damage
;
2480 A_Explode(actor
); // First make normal explosion
2482 // Now launch mushroom cloud
2483 for (i
= -n
; i
<= n
; i
+= 8)
2484 for (j
= -n
; j
<= n
; j
+= 8)
2486 mobj_t target
= *actor
, *mo
;
2487 target
.x
+= i
<< FRACBITS
; // Aim in many directions from source
2488 target
.y
+= j
<< FRACBITS
;
2489 target
.z
+= P_AproxDistance(i
,j
) << (FRACBITS
+2); // Aim up fairly high
2490 mo
= P_SpawnMissile(actor
, &target
, MT_FATSHOT
); // Launch fireball
2492 mo
->momy
>>= 1; // Slow it down a bit
2494 mo
->flags
&= ~MF_NOGRAVITY
; // Make debris fall under gravity
2501 // The following were inspired by Len Pitre
2503 // A small set of highly-sought-after code pointers
2506 void A_Spawn(mobj_t
*mo
)
2508 if (mo
->state
->misc1
)
2510 /* mobj_t *newmobj = */
2511 P_SpawnMobj(mo
->x
, mo
->y
, (mo
->state
->misc2
<< FRACBITS
) + mo
->z
,
2512 mo
->state
->misc1
- 1);
2513 /* CPhipps - no friendlyness (yet)
2514 newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND);
2519 void A_Turn(mobj_t
*mo
)
2521 mo
->angle
+= (unsigned int)(((uint_64_t
) mo
->state
->misc1
<< 32) / 360);
2524 void A_Face(mobj_t
*mo
)
2526 mo
->angle
= (unsigned int)(((uint_64_t
) mo
->state
->misc1
<< 32) / 360);
2529 void A_Scratch(mobj_t
*mo
)
2531 mo
->target
&& (A_FaceTarget(mo
), P_CheckMeleeRange(mo
)) ?
2532 mo
->state
->misc2
? S_StartSound(mo
, mo
->state
->misc2
) : (void) 0,
2533 P_DamageMobj(mo
->target
, mo
, mo
, mo
->state
->misc1
) : (void) 0;
2536 void A_PlaySound(mobj_t
*mo
)
2538 S_StartSound(mo
->state
->misc2
? NULL
: mo
, mo
->state
->misc1
);
2541 void A_RandomJump(mobj_t
*mo
)
2543 if (P_Random(pr_randomjump
) < mo
->state
->misc2
)
2544 P_SetMobjState(mo
, mo
->state
->misc1
);
2548 // This allows linedef effects to be activated inside deh frames.
2551 void A_LineEffect(mobj_t
*mo
)
2555 player_t
*oldplayer
;
2557 oldplayer
= mo
->player
;
2558 mo
->player
= &player
;
2559 player
.health
= 100;
2560 junk
.special
= (short)mo
->state
->misc1
;
2563 junk
.tag
= (short)mo
->state
->misc2
;
2564 if (!P_UseSpecialLine(mo
, &junk
, 0))
2565 P_CrossSpecialLine(&junk
, 0, mo
);
2566 mo
->state
->misc1
= junk
.special
;
2567 mo
->player
= oldplayer
;
2570 /***** Start of new functions for Andy Baker's stealth monsters ******/
2572 void P_BecomeVisible(mobj_t
* actor
)
2574 actor
->invisible
= false;
2575 actor
->flags
&= ~MF_TRANSLUCBITS
;
2578 void P_IncreaseVisibility(mobj_t
* actor
)
2580 if (actor
->invisible
) {
2581 actor
->invisible
= false;
2582 actor
->flags
|= MF_TRANSLUC25
;
2583 } else switch (actor
->flags
& MF_TRANSLUCBITS
) {
2585 actor
->flags
&= ~MF_TRANSLUCBITS
;
2586 actor
->flags
|= MF_TRANSLUC50
;
2589 actor
->flags
&= ~MF_TRANSLUCBITS
;
2590 actor
->flags
|= MF_TRANSLUC25
;
2591 actor
->flags
|= MF_TRANSLUC50
;
2594 actor
->flags
&= ~MF_TRANSLUCBITS
;
2599 void P_DecreaseVisibility(mobj_t
* actor
)
2601 if (actor
->invisible
)
2602 return; // already invisible
2604 switch (actor
->flags
& MF_TRANSLUCBITS
) {
2606 actor
->flags
&= ~MF_TRANSLUCBITS
;
2607 actor
->flags
|= MF_TRANSLUC75
;
2610 actor
->flags
&= ~MF_TRANSLUCBITS
;
2611 actor
->flags
|= MF_TRANSLUC50
;
2614 actor
->flags
&= ~MF_TRANSLUCBITS
;
2615 actor
->flags
|= MF_TRANSLUC25
;
2618 actor
->flags
&= ~MF_TRANSLUCBITS
;
2619 actor
->invisible
= true;
2622 /***** End of new functions for Andy Baker's stealth monsters ******/