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
28 * Movement, collision handling.
29 * Shooting and aiming.
31 *-----------------------------------------------------------------------------*/
46 #include "rockmacros.h"
48 static mobj_t
*tmthing
;
51 static int pe_x
; // Pain Elemental position for Lost Soul checks // phares
52 static int pe_y
; // Pain Elemental position for Lost Soul checks // phares
53 static int ls_x
; // Lost Soul position for Lost Soul checks // phares
54 static int ls_y
; // Lost Soul position for Lost Soul checks // phares
56 // If "floatok" true, move would be ok
57 // if within "tmfloorz - tmceilingz".
61 /* killough 11/98: if "felldown" true, object was pushed down ledge */
64 // The tm* items are used to hold information globally, usually for
65 // line or object intersection checking
67 fixed_t tmbbox
[4]; // bounding box for line intersection checks
68 fixed_t tmfloorz
; // floor you'd hit if free to fall
69 fixed_t tmceilingz
; // ceiling of sector you're in
70 fixed_t tmdropoffz
; // dropoff on other side of line you're crossing
72 // keep track of the line that lowers the ceiling,
73 // so missiles don't explode against sky hack walls
76 line_t
*blockline
; /* killough 8/11/98: blocking linedef */
77 line_t
*floorline
; /* killough 8/1/98: Highest touched floor */
78 static int tmunstuck
; /* killough 8/1/98: whether to allow unsticking */
80 // keep track of special lines as they are hit,
81 // but don't process them until the move is proven valid
83 // 1/11/98 killough: removed limit on special lines crossed
84 line_t
**spechit
; // new code -- killough
85 static int spechit_max
; // killough
89 // Temporary holder for thing_sectorlist threads
90 msecnode_t
* sector_list
= NULL
; // phares 3/16/98
100 static boolean telefrag
; /* killough 8/9/98: whether to telefrag at exit */
102 boolean
PIT_StompThing (mobj_t
* thing
)
106 // phares 9/10/98: moved this self-check to start of routine
108 // don't clip against self
110 if (thing
== tmthing
)
113 if (!(thing
->flags
& MF_SHOOTABLE
)) // Can't shoot it? Can't stomp it!
116 blockdist
= thing
->radius
+ tmthing
->radius
;
118 if (D_abs(thing
->x
- tmx
) >= blockdist
|| D_abs(thing
->y
- tmy
) >= blockdist
)
119 return true; // didn't hit it
121 // monsters don't stomp things except on boss level
122 if (!telefrag
) // killough 8/9/98: make consistent across all levels
125 P_DamageMobj (thing
, tmthing
, tmthing
, 10000); // Stomp!
136 * Returns the friction associated with a particular mobj.
139 int P_GetFriction(const mobj_t
*mo
, int *frictionfactor
)
141 int friction
= ORIG_FRICTION
;
142 int movefactor
= ORIG_FRICTION_FACTOR
;
146 /* Assign the friction value to objects on the floor, non-floating,
147 * and clipped. Normally the object's friction value is kept at
148 * ORIG_FRICTION and this thinker changes it for icy or muddy floors.
150 * When the object is straddling sectors with the same
151 * floorheight that have different frictions, use the lowest
152 * friction value (muddy has precedence over icy).
155 if (!(mo
->flags
& (MF_NOCLIP
|MF_NOGRAVITY
))
156 && (mbf_features
|| (mo
->player
&& !compatibility
)) &&
158 for (m
= mo
->touching_sectorlist
; m
; m
= m
->m_tnext
)
159 if ((sec
= m
->m_sector
)->special
& FRICTION_MASK
&&
160 (sec
->friction
< friction
|| friction
== ORIG_FRICTION
) &&
161 (mo
->z
<= sec
->floorheight
||
162 (sec
->heightsec
!= -1 &&
163 mo
->z
<= sectors
[sec
->heightsec
].floorheight
&&
165 friction
= sec
->friction
, movefactor
= sec
->movefactor
;
168 *frictionfactor
= movefactor
;
174 * P_GetMoveFactor() returns the value by which the x,y
175 * movements are multiplied to add to player movement.
177 * killough 8/28/98: rewritten
180 int P_GetMoveFactor(const mobj_t
*mo
, int *frictionp
)
182 int movefactor
, friction
;
184 // If the floor is icy or muddy, it's harder to get moving. This is where
185 // the different friction factors are applied to 'trying to move'. In
186 // p_mobj.c, the friction factors are applied as you coast and slow down.
188 if ((friction
= P_GetFriction(mo
, &movefactor
)) < ORIG_FRICTION
)
190 // phares 3/11/98: you start off slowly, then increase as
191 // you get better footing
193 int momentum
= P_AproxDistance(mo
->momx
,mo
->momy
);
195 if (momentum
> MORE_FRICTION_MOMENTUM
<<2)
197 else if (momentum
> MORE_FRICTION_MOMENTUM
<<1)
199 else if (momentum
> MORE_FRICTION_MOMENTUM
)
204 *frictionp
= friction
;
213 boolean
P_TeleportMove (mobj_t
* thing
,fixed_t x
,fixed_t y
, boolean boss
)
222 subsector_t
* newsubsec
;
224 /* killough 8/9/98: make telefragging more consistent, preserve compatibility */
225 telefrag
= thing
->player
||
226 (!comp
[comp_telefrag
] ? boss
: (gamemap
==30));
228 // kill anything occupying the position
235 tmbbox
[BOXTOP
] = y
+ tmthing
->radius
;
236 tmbbox
[BOXBOTTOM
] = y
- tmthing
->radius
;
237 tmbbox
[BOXRIGHT
] = x
+ tmthing
->radius
;
238 tmbbox
[BOXLEFT
] = x
- tmthing
->radius
;
240 newsubsec
= R_PointInSubsector (x
,y
);
243 // The base floor/ceiling is from the subsector
244 // that contains the point.
245 // Any contacted lines the step closer together
248 tmfloorz
= tmdropoffz
= newsubsec
->sector
->floorheight
;
249 tmceilingz
= newsubsec
->sector
->ceilingheight
;
254 // stomp on any things contacted
256 xl
= (tmbbox
[BOXLEFT
] - bmaporgx
- MAXRADIUS
)>>MAPBLOCKSHIFT
;
257 xh
= (tmbbox
[BOXRIGHT
] - bmaporgx
+ MAXRADIUS
)>>MAPBLOCKSHIFT
;
258 yl
= (tmbbox
[BOXBOTTOM
] - bmaporgy
- MAXRADIUS
)>>MAPBLOCKSHIFT
;
259 yh
= (tmbbox
[BOXTOP
] - bmaporgy
+ MAXRADIUS
)>>MAPBLOCKSHIFT
;
261 for (bx
=xl
; bx
<=xh
; bx
++)
262 for (by
=yl
; by
<=yh
; by
++)
263 if (!P_BlockThingsIterator(bx
,by
,PIT_StompThing
))
267 // so unlink from the old position & link into the new position
269 P_UnsetThingPosition (thing
);
271 thing
->floorz
= tmfloorz
;
272 thing
->ceilingz
= tmceilingz
;
273 thing
->dropoffz
= tmdropoffz
; // killough 11/98
278 P_SetThingPosition (thing
);
285 // MOVEMENT ITERATOR FUNCTIONS
289 // PIT_CrossLine // |
290 // Checks to see if a PE->LS trajectory line crosses a blocking // V
291 // line. Returns false if it does.
293 // tmbbox holds the bounding box of the trajectory. If that box
294 // does not touch the bounding box of the line in question,
295 // then the trajectory is not blocked. If the PE is on one side
296 // of the line and the LS is on the other side, then the
297 // trajectory is blocked.
299 // Currently this assumes an infinite line, which is not quite
300 // correct. A more correct solution would be to check for an
301 // intersection of the trajectory and the line, but that takes
302 // longer and probably really isn't worth the effort.
305 static // killough 3/26/98: make static
306 boolean
PIT_CrossLine (line_t
* ld
)
308 if (!(ld
->flags
& ML_TWOSIDED
) ||
309 (ld
->flags
& (ML_BLOCKING
|ML_BLOCKMONSTERS
)))
310 if (!(tmbbox
[BOXLEFT
] > ld
->bbox
[BOXRIGHT
] ||
311 tmbbox
[BOXRIGHT
] < ld
->bbox
[BOXLEFT
] ||
312 tmbbox
[BOXTOP
] < ld
->bbox
[BOXBOTTOM
] ||
313 tmbbox
[BOXBOTTOM
] > ld
->bbox
[BOXTOP
]))
314 if (P_PointOnLineSide(pe_x
,pe_y
,ld
) != P_PointOnLineSide(ls_x
,ls_y
,ld
))
315 return(false); // line blocks trajectory // ^
316 return(true); // line doesn't block trajectory // |
320 /* killough 8/1/98: used to test intersection between thing and line
321 * assuming NO movement occurs -- used to avoid sticky situations.
324 static int untouched(line_t
*ld
)
326 fixed_t x
, y
, tmbbox
[4];
328 (tmbbox
[BOXRIGHT
] = (x
=tmthing
->x
)+tmthing
->radius
) <= ld
->bbox
[BOXLEFT
] ||
329 (tmbbox
[BOXLEFT
] = x
-tmthing
->radius
) >= ld
->bbox
[BOXRIGHT
] ||
330 (tmbbox
[BOXTOP
] = (y
=tmthing
->y
)+tmthing
->radius
) <= ld
->bbox
[BOXBOTTOM
] ||
331 (tmbbox
[BOXBOTTOM
] = y
-tmthing
->radius
) >= ld
->bbox
[BOXTOP
] ||
332 P_BoxOnLineSide(tmbbox
, ld
) != -1;
337 // Adjusts tmfloorz and tmceilingz as lines are contacted
340 static // killough 3/26/98: make static
341 boolean
PIT_CheckLine (line_t
* ld
)
343 if (tmbbox
[BOXRIGHT
] <= ld
->bbox
[BOXLEFT
]
344 || tmbbox
[BOXLEFT
] >= ld
->bbox
[BOXRIGHT
]
345 || tmbbox
[BOXTOP
] <= ld
->bbox
[BOXBOTTOM
]
346 || tmbbox
[BOXBOTTOM
] >= ld
->bbox
[BOXTOP
] )
347 return true; // didn't hit it
349 if (P_BoxOnLineSide(tmbbox
, ld
) != -1)
350 return true; // didn't hit it
352 // A line has been hit
354 // The moving thing's destination position will cross the given line.
355 // If this should not be allowed, return false.
356 // If the line is special, keep track of it
357 // to process later if the move is proven ok.
358 // NOTE: specials are NOT sorted by order,
359 // so two special lines that are only 8 pixels apart
360 // could be crossed in either order.
362 // killough 7/24/98: allow player to move out of 1s wall, to prevent sticking
363 if (!ld
->backsector
) // one sided line
366 return tmunstuck
&& !untouched(ld
) &&
367 FixedMul(tmx
-tmthing
->x
,ld
->dy
) > FixedMul(tmy
-tmthing
->y
,ld
->dx
);
370 // killough 8/10/98: allow bouncing objects to pass through as missiles
371 if (!(tmthing
->flags
& (MF_MISSILE
| MF_BOUNCES
)))
373 if (ld
->flags
& ML_BLOCKING
) // explicitly blocking everything
374 return tmunstuck
&& !untouched(ld
); // killough 8/1/98: allow escape
376 // killough 8/9/98: monster-blockers don't affect friends
377 if (!(tmthing
->flags
& MF_FRIEND
|| tmthing
->player
)
378 && ld
->flags
& ML_BLOCKMONSTERS
)
379 return false; // block monsters only
382 // set openrange, opentop, openbottom
383 // these define a 'window' from one sector to another across this line
387 // adjust floor & ceiling heights
389 if (opentop
< tmceilingz
)
391 tmceilingz
= opentop
;
396 if (openbottom
> tmfloorz
)
398 tmfloorz
= openbottom
;
399 floorline
= ld
; // killough 8/1/98: remember floor linedef
403 if (lowfloor
< tmdropoffz
)
404 tmdropoffz
= lowfloor
;
406 // if contacted a special line, add it to the list
410 // 1/11/98 killough: remove limit on lines hit, by array doubling
411 if (numspechit
>= spechit_max
)
413 spechit_max
= spechit_max
? spechit_max
*2 : 8;
414 spechit
= realloc(spechit
,sizeof *spechit
*spechit_max
); // killough
416 spechit
[numspechit
++] = ld
;
426 static boolean
PIT_CheckThing(mobj_t
*thing
) // killough 3/26/98: make static
431 // killough 11/98: add touchy things
432 if (!(thing
->flags
& (MF_SOLID
|MF_SPECIAL
|MF_SHOOTABLE
|MF_TOUCHY
)))
435 blockdist
= thing
->radius
+ tmthing
->radius
;
437 if (D_abs(thing
->x
- tmx
) >= blockdist
|| D_abs(thing
->y
- tmy
) >= blockdist
)
438 return true; // didn't hit it
442 // This test has less information content (it's almost always false), so it
443 // should not be moved up to first, as it adds more overhead than it removes.
445 // don't clip against self
447 if (thing
== tmthing
)
452 * TOUCHY flag, for mines or other objects which die on contact with solids.
453 * If a solid object of a different type comes in contact with a touchy
454 * thing, and the touchy thing is not the sole one moving relative to fixed
455 * surroundings such as walls, then the touchy thing dies immediately.
458 if (thing
->flags
& MF_TOUCHY
&& // touchy object
459 tmthing
->flags
& MF_SOLID
&& // solid object touches it
460 thing
->health
> 0 && // touchy object is alive
461 (thing
->intflags
& MIF_ARMED
|| // Thing is an armed mine
462 sentient(thing
)) && // ... or a sentient thing
463 (thing
->type
!= tmthing
->type
|| // only different species
464 thing
->type
== MT_PLAYER
) && // ... or different players
465 thing
->z
+ thing
->height
>= tmthing
->z
&& // touches vertically
466 tmthing
->z
+ tmthing
->height
>= thing
->z
&&
467 (thing
->type
^ MT_PAIN
) | // PEs and lost souls
468 (tmthing
->type
^ MT_SKULL
) && // are considered same
469 (thing
->type
^ MT_SKULL
) | // (but Barons & Knights
470 (tmthing
->type
^ MT_PAIN
)) // are intentionally not)
472 P_DamageMobj(thing
, NULL
, NULL
, thing
->health
); // kill object
476 // check for skulls slamming into things
478 if (tmthing
->flags
& MF_SKULLFLY
)
480 // A flying skull is smacking something.
481 // Determine damage amount, and the skull comes to a dead stop.
483 int damage
= ((P_Random(pr_skullfly
)%8)+1)*tmthing
->info
->damage
;
485 P_DamageMobj (thing
, tmthing
, tmthing
, damage
);
487 tmthing
->flags
&= ~MF_SKULLFLY
;
488 tmthing
->momx
= tmthing
->momy
= tmthing
->momz
= 0;
490 P_SetMobjState (tmthing
, tmthing
->info
->spawnstate
);
492 return false; // stop moving
495 // missiles can hit other things
496 // killough 8/10/98: bouncing non-solid things can hit other things too
498 if (tmthing
->flags
& MF_MISSILE
|| (tmthing
->flags
& MF_BOUNCES
&&
499 !(tmthing
->flags
& MF_SOLID
)))
501 // see if it went over / under
503 if (tmthing
->z
> thing
->z
+ thing
->height
)
504 return true; // overhead
506 if (tmthing
->z
+tmthing
->height
< thing
->z
)
507 return true; // underneath
509 if (tmthing
->target
&& (tmthing
->target
->type
== thing
->type
||
510 (tmthing
->target
->type
== MT_KNIGHT
&& thing
->type
== MT_BRUISER
)||
511 (tmthing
->target
->type
== MT_BRUISER
&& thing
->type
== MT_KNIGHT
)))
513 if (thing
== tmthing
->target
)
514 return true; // Don't hit same species as originator.
516 if (thing
->type
!= MT_PLAYER
) // Explode, but do no damage.
517 return false; // Let players missile other players.
520 // killough 8/10/98: if moving thing is not a missile, no damage
521 // is inflicted, and momentum is reduced if object hit is solid.
523 if (!(tmthing
->flags
& MF_MISSILE
)) {
524 if (!(thing
->flags
& MF_SOLID
)) {
527 tmthing
->momx
= -tmthing
->momx
;
528 tmthing
->momy
= -tmthing
->momy
;
529 if (!(tmthing
->flags
& MF_NOGRAVITY
))
538 if (!(thing
->flags
& MF_SHOOTABLE
))
539 return !(thing
->flags
& MF_SOLID
); // didn't do any damage
543 damage
= ((P_Random(pr_damage
)%8)+1)*tmthing
->info
->damage
;
544 P_DamageMobj (thing
, tmthing
, tmthing
->target
, damage
);
546 // don't traverse any more
550 // check for special pickup
552 if (thing
->flags
& MF_SPECIAL
)
554 uint_64_t solid
= thing
->flags
& MF_SOLID
;
555 if (tmthing
->flags
& MF_PICKUP
)
556 P_TouchSpecialThing(thing
, tmthing
); // can remove thing
560 // killough 3/16/98: Allow non-solid moving objects to move through solid
561 // ones, by allowing the moving thing (tmthing) to move if it's non-solid,
562 // despite another solid thing being in the way.
563 // killough 4/11/98: Treat no-clipping things as not blocking
565 return !((thing
->flags
& MF_SOLID
&& !(thing
->flags
& MF_NOCLIP
))
566 && (tmthing
->flags
& MF_SOLID
|| demo_compatibility
));
568 // return !(thing->flags & MF_SOLID); // old code -- killough
571 // This routine checks for Lost Souls trying to be spawned // phares
572 // across 1-sided lines, impassible lines, or "monsters can't // |
573 // cross" lines. Draw an imaginary line between the PE // V
574 // and the new Lost Soul spawn spot. If that line crosses
575 // a 'blocking' line, then disallow the spawn. Only search
576 // lines in the blocks of the blockmap where the bounding box
577 // of the trajectory line resides. Then check bounding box
578 // of the trajectory vs. the bounding box of each blocking
579 // line to see if the trajectory and the blocking line cross.
580 // Then check the PE and LS to see if they're on different
581 // sides of the blocking line. If so, return true, otherwise
584 boolean
Check_Sides(mobj_t
* actor
, int x
, int y
)
586 int bx
,by
,xl
,xh
,yl
,yh
;
593 // Here is the bounding box of the trajectory
595 tmbbox
[BOXLEFT
] = pe_x
< x
? pe_x
: x
;
596 tmbbox
[BOXRIGHT
] = pe_x
> x
? pe_x
: x
;
597 tmbbox
[BOXTOP
] = pe_y
> y
? pe_y
: y
;
598 tmbbox
[BOXBOTTOM
] = pe_y
< y
? pe_y
: y
;
600 // Determine which blocks to look in for blocking lines
602 xl
= (tmbbox
[BOXLEFT
] - bmaporgx
)>>MAPBLOCKSHIFT
;
603 xh
= (tmbbox
[BOXRIGHT
] - bmaporgx
)>>MAPBLOCKSHIFT
;
604 yl
= (tmbbox
[BOXBOTTOM
] - bmaporgy
)>>MAPBLOCKSHIFT
;
605 yh
= (tmbbox
[BOXTOP
] - bmaporgy
)>>MAPBLOCKSHIFT
;
607 // xl->xh, yl->yh determine the mapblock set to search
609 validcount
++; // prevents checking same line twice
610 for (bx
= xl
; bx
<= xh
; bx
++)
611 for (by
= yl
; by
<= yh
; by
++)
612 if (!P_BlockLinesIterator(bx
,by
,PIT_CrossLine
))
623 // This is purely informative, nothing is modified
624 // (except things picked up).
627 // a mobj_t (can be valid or invalid)
628 // a position to be checked
629 // (doesn't need to be related to the mobj_t->x,y)
632 // special things are touched if MF_PICKUP
633 // early out on solid lines?
640 // the lowest point contacted
641 // (monsters won't move to a dropoff)
646 boolean
P_CheckPosition (mobj_t
* thing
,fixed_t x
,fixed_t y
)
654 subsector_t
* newsubsec
;
661 tmbbox
[BOXTOP
] = y
+ tmthing
->radius
;
662 tmbbox
[BOXBOTTOM
] = y
- tmthing
->radius
;
663 tmbbox
[BOXRIGHT
] = x
+ tmthing
->radius
;
664 tmbbox
[BOXLEFT
] = x
- tmthing
->radius
;
666 newsubsec
= R_PointInSubsector (x
,y
);
667 floorline
= blockline
= ceilingline
= NULL
; // killough 8/1/98
669 // Whether object can get out of a sticky situation:
670 tmunstuck
= thing
->player
&& /* only players */
671 thing
->player
->mo
== thing
&& /* not voodoo dolls */
672 mbf_features
; /* not under old demos */
674 // The base floor / ceiling is from the subsector
675 // that contains the point.
676 // Any contacted lines the step closer together
679 tmfloorz
= tmdropoffz
= newsubsec
->sector
->floorheight
;
680 tmceilingz
= newsubsec
->sector
->ceilingheight
;
684 if ( tmthing
->flags
& MF_NOCLIP
)
687 // Check things first, possibly picking things up.
688 // The bounding box is extended by MAXRADIUS
689 // because mobj_ts are grouped into mapblocks
690 // based on their origin point, and can overlap
691 // into adjacent blocks by up to MAXRADIUS units.
693 xl
= (tmbbox
[BOXLEFT
] - bmaporgx
- MAXRADIUS
)>>MAPBLOCKSHIFT
;
694 xh
= (tmbbox
[BOXRIGHT
] - bmaporgx
+ MAXRADIUS
)>>MAPBLOCKSHIFT
;
695 yl
= (tmbbox
[BOXBOTTOM
] - bmaporgy
- MAXRADIUS
)>>MAPBLOCKSHIFT
;
696 yh
= (tmbbox
[BOXTOP
] - bmaporgy
+ MAXRADIUS
)>>MAPBLOCKSHIFT
;
699 for (bx
=xl
; bx
<=xh
; bx
++)
700 for (by
=yl
; by
<=yh
; by
++)
701 if (!P_BlockThingsIterator(bx
,by
,PIT_CheckThing
))
706 xl
= (tmbbox
[BOXLEFT
] - bmaporgx
)>>MAPBLOCKSHIFT
;
707 xh
= (tmbbox
[BOXRIGHT
] - bmaporgx
)>>MAPBLOCKSHIFT
;
708 yl
= (tmbbox
[BOXBOTTOM
] - bmaporgy
)>>MAPBLOCKSHIFT
;
709 yh
= (tmbbox
[BOXTOP
] - bmaporgy
)>>MAPBLOCKSHIFT
;
711 for (bx
=xl
; bx
<=xh
; bx
++)
712 for (by
=yl
; by
<=yh
; by
++)
713 if (!P_BlockLinesIterator (bx
,by
,PIT_CheckLine
))
714 return false; // doesn't fit
722 // Attempt to move to a new position,
723 // crossing special lines unless MF_TELEPORT is set.
725 boolean
P_TryMove(mobj_t
* thing
,fixed_t x
,fixed_t y
,
726 boolean dropoff
) // killough 3/15/98: allow dropoff as option
731 felldown
= floatok
= false; // killough 11/98
733 if (!P_CheckPosition (thing
, x
, y
))
734 return false; // solid wall or thing
736 if ( !(thing
->flags
& MF_NOCLIP
) )
738 // killough 7/26/98: reformatted slightly
739 // killough 8/1/98: Possibly allow escape if otherwise stuck
741 if (tmceilingz
- tmfloorz
< thing
->height
|| // doesn't fit
742 // mobj must lower to fit
743 (floatok
= true, !(thing
->flags
& MF_TELEPORT
) &&
744 tmceilingz
- thing
->z
< thing
->height
) ||
746 (!(thing
->flags
& MF_TELEPORT
) &&
747 tmfloorz
- thing
->z
> 24*FRACUNIT
))
749 && !(ceilingline
&& untouched(ceilingline
))
750 && !( floorline
&& untouched( floorline
));
752 /* killough 3/15/98: Allow certain objects to drop off
753 * killough 7/24/98, 8/1/98:
754 * Prevent monsters from getting stuck hanging off ledges
755 * killough 10/98: Allow dropoffs in controlled circumstances
756 * killough 11/98: Improve symmetry of clipping on stairs
759 if (!(thing
->flags
& (MF_DROPOFF
|MF_FLOAT
))) {
760 if (comp
[comp_dropoff
])
762 if ((compatibility
|| !dropoff
) && (tmfloorz
- tmdropoffz
> 24*FRACUNIT
))
763 return false; // don't stand over a dropoff
766 if (!dropoff
|| (dropoff
==2 && // large jump down (e.g. dogs)
767 (tmfloorz
-tmdropoffz
> 128*FRACUNIT
||
768 !thing
->target
|| thing
->target
->z
>tmdropoffz
)))
770 if (!monkeys
|| !mbf_features
?
771 tmfloorz
- tmdropoffz
> 24*FRACUNIT
:
772 thing
->floorz
- tmfloorz
> 24*FRACUNIT
||
773 thing
->dropoffz
- tmdropoffz
> 24*FRACUNIT
)
776 else { /* dropoff allowed -- check for whether it fell more than 24 */
777 felldown
= !(thing
->flags
& MF_NOGRAVITY
) &&
778 thing
->z
- tmfloorz
> 24*FRACUNIT
;
782 if (thing
->flags
& MF_BOUNCES
&& // killough 8/13/98
783 !(thing
->flags
& (MF_MISSILE
|MF_NOGRAVITY
)) &&
784 !sentient(thing
) && tmfloorz
- thing
->z
> 16*FRACUNIT
)
785 return false; // too big a step up for bouncers under gravity
787 // killough 11/98: prevent falling objects from going up too many steps
788 if (thing
->intflags
& MIF_FALLING
&& tmfloorz
- thing
->z
>
789 FixedMul(thing
->momx
,thing
->momx
)+FixedMul(thing
->momy
,thing
->momy
))
794 // so unlink from the old position and link into the new position
796 P_UnsetThingPosition (thing
);
800 thing
->floorz
= tmfloorz
;
801 thing
->ceilingz
= tmceilingz
;
802 thing
->dropoffz
= tmdropoffz
; // killough 11/98: keep track of dropoffs
806 P_SetThingPosition (thing
);
808 // if any special lines were hit, do the effect
810 if (! (thing
->flags
&(MF_TELEPORT
|MF_NOCLIP
)) )
812 if (spechit
[numspechit
]->special
) // see if the line was crossed
815 if ((oldside
= P_PointOnLineSide(oldx
, oldy
, spechit
[numspechit
])) !=
816 P_PointOnLineSide(thing
->x
, thing
->y
, spechit
[numspechit
]))
817 P_CrossSpecialLine(spechit
[numspechit
], oldside
, thing
);
826 * Apply "torque" to objects hanging off of ledges, so that they
827 * fall off. It's not really torque, since Doom has no concept of
828 * rotation, but it's a convincing effect which avoids anomalies
829 * such as lifeless objects hanging more than halfway off of ledges,
830 * and allows objects to roll off of the edges of moving lifts, or
831 * to slide up and then back down stairs, or to fall into a ditch.
832 * If more than one linedef is contacted, the effects are cumulative,
833 * so balancing is possible.
836 static boolean
PIT_ApplyTorque(line_t
*ld
)
838 if (ld
->backsector
&& // If thing touches two-sided pivot linedef
839 tmbbox
[BOXRIGHT
] > ld
->bbox
[BOXLEFT
] &&
840 tmbbox
[BOXLEFT
] < ld
->bbox
[BOXRIGHT
] &&
841 tmbbox
[BOXTOP
] > ld
->bbox
[BOXBOTTOM
] &&
842 tmbbox
[BOXBOTTOM
] < ld
->bbox
[BOXTOP
] &&
843 P_BoxOnLineSide(tmbbox
, ld
) == -1)
845 mobj_t
*mo
= tmthing
;
847 fixed_t dist
= // lever arm
848 + (ld
->dx
>> FRACBITS
) * (mo
->y
>> FRACBITS
)
849 - (ld
->dy
>> FRACBITS
) * (mo
->x
>> FRACBITS
)
850 - (ld
->dx
>> FRACBITS
) * (ld
->v1
->y
>> FRACBITS
)
851 + (ld
->dy
>> FRACBITS
) * (ld
->v1
->x
>> FRACBITS
);
853 if (dist
< 0 ? // dropoff direction
854 ld
->frontsector
->floorheight
< mo
->z
&&
855 ld
->backsector
->floorheight
>= mo
->z
:
856 ld
->backsector
->floorheight
< mo
->z
&&
857 ld
->frontsector
->floorheight
>= mo
->z
)
859 /* At this point, we know that the object straddles a two-sided
860 * linedef, and that the object's center of mass is above-ground.
863 fixed_t x
= D_abs(ld
->dx
), y
= D_abs(ld
->dy
);
872 y
= finesine
[(tantoangle
[FixedDiv(y
,x
)>>DBITS
] +
873 ANG90
) >> ANGLETOFINESHIFT
];
875 /* Momentum is proportional to distance between the
876 * object's center of mass and the pivot linedef.
878 * It is scaled by 2^(OVERDRIVE - gear). When gear is
879 * increased, the momentum gradually decreases to 0 for
880 * the same amount of pseudotorque, so that oscillations
881 * are prevented, yet it has a chance to reach equilibrium.
883 dist
= FixedDiv(FixedMul(dist
, (mo
->gear
< OVERDRIVE
) ?
884 y
<< -(mo
->gear
- OVERDRIVE
) :
885 y
>> +(mo
->gear
- OVERDRIVE
)), x
);
887 /* Apply momentum away from the pivot linedef. */
889 x
= FixedMul(ld
->dy
, dist
);
890 y
= FixedMul(ld
->dx
, dist
);
892 /* Avoid moving too fast all of a sudden (step into "overdrive") */
894 dist
= FixedMul(x
,x
) + FixedMul(y
,y
);
896 while (dist
> FRACUNIT
*4 && mo
->gear
< MAXGEAR
)
897 ++mo
->gear
, x
>>= 1, y
>>= 1, dist
>>= 1;
909 * Applies "torque" to objects, based on all contacted linedefs
912 void P_ApplyTorque(mobj_t
*mo
)
914 int xl
= ((tmbbox
[BOXLEFT
] =
915 mo
->x
- mo
->radius
) - bmaporgx
) >> MAPBLOCKSHIFT
;
916 int xh
= ((tmbbox
[BOXRIGHT
] =
917 mo
->x
+ mo
->radius
) - bmaporgx
) >> MAPBLOCKSHIFT
;
918 int yl
= ((tmbbox
[BOXBOTTOM
] =
919 mo
->y
- mo
->radius
) - bmaporgy
) >> MAPBLOCKSHIFT
;
920 int yh
= ((tmbbox
[BOXTOP
] =
921 mo
->y
+ mo
->radius
) - bmaporgy
) >> MAPBLOCKSHIFT
;
922 int bx
,by
,flags
= mo
->intflags
; //Remember the current state, for gear-change
925 validcount
++; /* prevents checking same line twice */
927 for (bx
= xl
; bx
<= xh
; bx
++)
928 for (by
= yl
; by
<= yh
; by
++)
929 P_BlockLinesIterator(bx
, by
, PIT_ApplyTorque
);
931 /* If any momentum, mark object as 'falling' using engine-internal flags */
932 if (mo
->momx
| mo
->momy
)
933 mo
->intflags
|= MIF_FALLING
;
934 else // Clear the engine-internal flag indicating falling object.
935 mo
->intflags
&= ~MIF_FALLING
;
937 /* If the object has been moving, step up the gear.
938 * This helps reach equilibrium and avoid oscillations.
940 * Doom has no concept of potential energy, much less
941 * of rotation, so we have to creatively simulate these
945 if (!((mo
->intflags
| flags
) & MIF_FALLING
)) // If not falling for a while,
946 mo
->gear
= 0; // Reset it to full strength
948 if (mo
->gear
< MAXGEAR
) // Else if not at max gear,
949 mo
->gear
++; // move up a gear
954 // Takes a valid thing and adjusts the thing->floorz,
955 // thing->ceilingz, and possibly thing->z.
956 // This is called for all nearby monsters
957 // whenever a sector changes height.
958 // If the thing doesn't fit,
959 // the z will be set to the lowest value
960 // and false will be returned.
963 boolean
P_ThingHeightClip (mobj_t
* thing
)
967 onfloor
= (thing
->z
== thing
->floorz
);
969 P_CheckPosition (thing
, thing
->x
, thing
->y
);
971 /* what about stranding a monster partially off an edge?
972 * killough 11/98: Answer: see below (upset balance if hanging off ledge)
975 thing
->floorz
= tmfloorz
;
976 thing
->ceilingz
= tmceilingz
;
977 thing
->dropoffz
= tmdropoffz
; /* killough 11/98: remember dropoffs */
982 // walking monsters rise and fall with the floor
984 thing
->z
= thing
->floorz
;
986 /* killough 11/98: Possibly upset balance of objects hanging off ledges */
987 if (thing
->intflags
& MIF_FALLING
&& thing
->gear
>= MAXGEAR
)
993 // don't adjust a floating monster unless forced to
995 if (thing
->z
+thing
->height
> thing
->ceilingz
)
996 thing
->z
= thing
->ceilingz
- thing
->height
;
999 return thing
->ceilingz
- thing
->floorz
>= thing
->height
;
1005 // Allows the player to slide along any angled walls.
1008 /* killough 8/2/98: make variables static */
1009 static fixed_t bestslidefrac
;
1010 static fixed_t secondslidefrac
;
1011 static line_t
* bestslideline
;
1012 static line_t
* secondslideline
;
1013 static mobj_t
* slidemo
;
1014 static fixed_t tmxmove
;
1015 static fixed_t tmymove
;
1020 // Adjusts the xmove / ymove
1021 // so that the next move will slide along the wall.
1022 // If the floor is icy, then you can bounce off a wall. // phares
1025 void P_HitSlideLine (line_t
* ld
)
1033 boolean icyfloor
; // is floor icy? // phares
1035 // Under icy conditions, if the angle of approach to the wall // V
1036 // is more than 45 degrees, then you'll bounce and lose half
1037 // your momentum. If less than 45 degrees, you'll slide along
1038 // the wall. 45 is arbitrary and is believable.
1040 // Check for the special cases of horz or vert walls.
1042 /* killough 10/98: only bounce if hit hard (prevents wobbling)
1043 * cph - DEMOSYNC - should only affect players in Boom demos? */
1046 P_AproxDistance(tmxmove
, tmymove
) > 4*FRACUNIT
: !compatibility
) &&
1047 variable_friction
&& // killough 8/28/98: calc friction on demand
1048 slidemo
->z
<= slidemo
->floorz
&&
1049 P_GetFriction(slidemo
, NULL
) > ORIG_FRICTION
;
1051 if (ld
->slopetype
== ST_HORIZONTAL
)
1053 if (icyfloor
&& (D_abs(tmymove
) > D_abs(tmxmove
)))
1055 tmxmove
/= 2; // absorb half the momentum
1056 tmymove
= -tmymove
/2;
1057 S_StartSound(slidemo
,sfx_oof
); // oooff!
1060 tmymove
= 0; // no more movement in the Y direction
1064 if (ld
->slopetype
== ST_VERTICAL
)
1066 if (icyfloor
&& (D_abs(tmxmove
) > D_abs(tmymove
)))
1068 tmxmove
= -tmxmove
/2; // absorb half the momentum
1070 S_StartSound(slidemo
,sfx_oof
); // oooff! // ^
1073 tmxmove
= 0; // no more movement in the X direction
1077 // The wall is angled. Bounce if the angle of approach is // phares
1078 // less than 45 degrees. // phares
1080 side
= P_PointOnLineSide (slidemo
->x
, slidemo
->y
, ld
);
1082 lineangle
= R_PointToAngle2 (0,0, ld
->dx
, ld
->dy
);
1084 lineangle
+= ANG180
;
1085 moveangle
= R_PointToAngle2 (0,0, tmxmove
, tmymove
);
1088 // The moveangle+=10 breaks v1.9 demo compatibility in
1089 // some demos, so it needs demo_compatibility switch.
1091 if (!demo_compatibility
)
1092 moveangle
+= 10; // prevents sudden path reversal due to // phares
1093 // rounding error // |
1094 deltaangle
= moveangle
-lineangle
; // V
1095 movelen
= P_AproxDistance (tmxmove
, tmymove
);
1096 if (icyfloor
&& (deltaangle
> ANG45
) && (deltaangle
< ANG90
+ANG45
))
1098 moveangle
= lineangle
- deltaangle
;
1099 movelen
/= 2; // absorb
1100 S_StartSound(slidemo
,sfx_oof
); // oooff!
1101 moveangle
>>= ANGLETOFINESHIFT
;
1102 tmxmove
= FixedMul (movelen
, finecosine
[moveangle
]);
1103 tmymove
= FixedMul (movelen
, finesine
[moveangle
]);
1107 if (deltaangle
> ANG180
)
1108 deltaangle
+= ANG180
;
1110 // I_Error ("SlideLine: ang>ANG180");
1112 lineangle
>>= ANGLETOFINESHIFT
;
1113 deltaangle
>>= ANGLETOFINESHIFT
;
1114 newlen
= FixedMul (movelen
, finecosine
[deltaangle
]);
1115 tmxmove
= FixedMul (newlen
, finecosine
[lineangle
]);
1116 tmymove
= FixedMul (newlen
, finesine
[lineangle
]);
1122 // PTR_SlideTraverse
1125 boolean
PTR_SlideTraverse (intercept_t
* in
)
1130 I_Error ("PTR_SlideTraverse: not a line?");
1134 if ( ! (li
->flags
& ML_TWOSIDED
) )
1136 if (P_PointOnLineSide (slidemo
->x
, slidemo
->y
, li
))
1137 return true; // don't hit the back side
1141 // set openrange, opentop, openbottom.
1142 // These define a 'window' from one sector to another across a line
1146 if (openrange
< slidemo
->height
)
1147 goto isblocking
; // doesn't fit
1149 if (opentop
- slidemo
->z
< slidemo
->height
)
1150 goto isblocking
; // mobj is too high
1152 if (openbottom
- slidemo
->z
> 24*FRACUNIT
)
1153 goto isblocking
; // too big a step up
1155 // this line doesn't block movement
1159 // the line does block movement,
1160 // see if it is closer than best so far
1164 if (in
->frac
< bestslidefrac
)
1166 secondslidefrac
= bestslidefrac
;
1167 secondslideline
= bestslideline
;
1168 bestslidefrac
= in
->frac
;
1172 return false; // stop
1178 // The momx / momy move is bad, so try to slide
1180 // Find the first line hit, move flush to it,
1181 // and slide along it
1183 // This is a kludgy mess.
1185 // killough 11/98: reformatted
1187 void P_SlideMove(mobj_t
*mo
)
1191 slidemo
= mo
; // the object that's sliding
1195 fixed_t leadx
, leady
, trailx
, traily
;
1198 goto stairstep
; // don't loop forever
1200 // trace along the three leading corners
1203 leadx
= mo
->x
+ mo
->radius
, trailx
= mo
->x
- mo
->radius
;
1205 leadx
= mo
->x
- mo
->radius
, trailx
= mo
->x
+ mo
->radius
;
1208 leady
= mo
->y
+ mo
->radius
, traily
= mo
->y
- mo
->radius
;
1210 leady
= mo
->y
- mo
->radius
, traily
= mo
->y
+ mo
->radius
;
1212 bestslidefrac
= FRACUNIT
+1;
1214 P_PathTraverse(leadx
, leady
, leadx
+mo
->momx
, leady
+mo
->momy
,
1215 PT_ADDLINES
, PTR_SlideTraverse
);
1216 P_PathTraverse(trailx
, leady
, trailx
+mo
->momx
, leady
+mo
->momy
,
1217 PT_ADDLINES
, PTR_SlideTraverse
);
1218 P_PathTraverse(leadx
, traily
, leadx
+mo
->momx
, traily
+mo
->momy
,
1219 PT_ADDLINES
, PTR_SlideTraverse
);
1221 // move up to the wall
1223 if (bestslidefrac
== FRACUNIT
+1)
1225 // the move must have hit the middle, so stairstep
1229 /* killough 3/15/98: Allow objects to drop off ledges
1231 * phares 5/4/98: kill momentum if you can't move at all
1232 * This eliminates player bobbing if pressed against a wall
1235 * killough 10/98: keep buggy code around for old Boom demos
1237 * cph 2000/09//23: buggy code was only in Boom v2.01
1240 if (!P_TryMove(mo
, mo
->x
, mo
->y
+ mo
->momy
, true))
1241 if (!P_TryMove(mo
, mo
->x
+ mo
->momx
, mo
->y
, true))
1242 if (compatibility_level
== boom_201_compatibility
)
1243 mo
->momx
= mo
->momy
= 0;
1248 // fudge a bit to make sure it doesn't hit
1250 if ((bestslidefrac
-= 0x800) > 0)
1252 fixed_t newx
= FixedMul(mo
->momx
, bestslidefrac
);
1253 fixed_t newy
= FixedMul(mo
->momy
, bestslidefrac
);
1255 // killough 3/15/98: Allow objects to drop off ledges
1257 if (!P_TryMove(mo
, mo
->x
+newx
, mo
->y
+newy
, true))
1261 // Now continue along the wall.
1262 // First calculate remainder.
1264 bestslidefrac
= FRACUNIT
-(bestslidefrac
+0x800);
1266 if (bestslidefrac
> FRACUNIT
)
1267 bestslidefrac
= FRACUNIT
;
1269 if (bestslidefrac
<= 0)
1272 tmxmove
= FixedMul(mo
->momx
, bestslidefrac
);
1273 tmymove
= FixedMul(mo
->momy
, bestslidefrac
);
1275 P_HitSlideLine(bestslideline
); // clip the moves
1280 /* killough 10/98: affect the bobbing the same way (but not voodoo dolls)
1281 * cph - DEMOSYNC? */
1282 if (mo
->player
&& mo
->player
->mo
== mo
)
1284 if (D_abs(mo
->player
->momx
) > D_abs(tmxmove
))
1285 mo
->player
->momx
= tmxmove
;
1286 if (D_abs(mo
->player
->momy
) > D_abs(tmymove
))
1287 mo
->player
->momy
= tmymove
;
1289 } // killough 3/15/98: Allow objects to drop off ledges:
1290 while (!P_TryMove(mo
, mo
->x
+tmxmove
, mo
->y
+tmymove
, true));
1296 mobj_t
* linetarget
; // who got hit (or NULL)
1297 static mobj_t
* shootthing
;
1299 /* killough 8/2/98: for more intelligent autoaiming */
1300 static uint_64_t aim_flags_mask
;
1302 // Height if not aiming up or down
1306 fixed_t attackrange
;
1308 static fixed_t aimslope
;
1310 // slopes to top and bottom of target
1311 // killough 4/20/98: make static instead of using ones in p_sight.c
1313 static fixed_t topslope
;
1314 static fixed_t bottomslope
;
1319 // Sets linetaget and aimslope when a target is aimed at.
1321 boolean
PTR_AimTraverse (intercept_t
* in
)
1326 fixed_t thingtopslope
;
1327 fixed_t thingbottomslope
;
1334 if ( !(li
->flags
& ML_TWOSIDED
) )
1335 return false; // stop
1337 // Crosses a two sided line.
1338 // A two sided line will restrict
1339 // the possible target ranges.
1343 if (openbottom
>= opentop
)
1344 return false; // stop
1346 dist
= FixedMul (attackrange
, in
->frac
);
1348 if (li
->frontsector
->floorheight
!= li
->backsector
->floorheight
)
1350 slope
= FixedDiv (openbottom
- shootz
, dist
);
1351 if (slope
> bottomslope
)
1352 bottomslope
= slope
;
1355 if (li
->frontsector
->ceilingheight
!= li
->backsector
->ceilingheight
)
1357 slope
= FixedDiv (opentop
- shootz
, dist
);
1358 if (slope
< topslope
)
1362 if (topslope
<= bottomslope
)
1363 return false; // stop
1365 return true; // shot continues
1371 if (th
== shootthing
)
1372 return true; // can't shoot self
1374 if (!(th
->flags
&MF_SHOOTABLE
))
1375 return true; // corpse or something
1377 /* killough 7/19/98, 8/2/98:
1378 * friends don't aim at friends (except players), at least not first
1380 if (th
->flags
& shootthing
->flags
& aim_flags_mask
&& !th
->player
)
1383 // check angles to see if the thing can be aimed at
1385 dist
= FixedMul (attackrange
, in
->frac
);
1386 thingtopslope
= FixedDiv (th
->z
+th
->height
- shootz
, dist
);
1388 if (thingtopslope
< bottomslope
)
1389 return true; // shot over the thing
1391 thingbottomslope
= FixedDiv (th
->z
- shootz
, dist
);
1393 if (thingbottomslope
> topslope
)
1394 return true; // shot under the thing
1396 // this thing can be hit!
1398 if (thingtopslope
> topslope
)
1399 thingtopslope
= topslope
;
1401 if (thingbottomslope
< bottomslope
)
1402 thingbottomslope
= bottomslope
;
1404 aimslope
= (thingtopslope
+thingbottomslope
)/2;
1407 return false; // don't go any farther
1412 // PTR_ShootTraverse
1414 boolean
PTR_ShootTraverse (intercept_t
* in
)
1425 fixed_t thingtopslope
;
1426 fixed_t thingbottomslope
;
1430 line_t
*li
= in
->d
.line
;
1433 P_ShootSpecialLine (shootthing
, li
);
1435 if (li
->flags
& ML_TWOSIDED
)
1436 { // crosses a two sided (really 2s) line
1438 dist
= FixedMul(attackrange
, in
->frac
);
1440 // killough 11/98: simplify
1442 if ((li
->frontsector
->floorheight
==li
->backsector
->floorheight
||
1443 (slope
= FixedDiv(openbottom
- shootz
, dist
)) <= aimslope
) &&
1444 (li
->frontsector
->ceilingheight
==li
->backsector
->ceilingheight
||
1445 (slope
= FixedDiv (opentop
- shootz
, dist
)) >= aimslope
))
1446 return true; // shot continues
1450 // position a bit closer
1452 frac
= in
->frac
- FixedDiv (4*FRACUNIT
,attackrange
);
1453 x
= trace
.x
+ FixedMul (trace
.dx
, frac
);
1454 y
= trace
.y
+ FixedMul (trace
.dy
, frac
);
1455 z
= shootz
+ FixedMul (aimslope
, FixedMul(frac
, attackrange
));
1457 if (li
->frontsector
->ceilingpic
== skyflatnum
)
1459 // don't shoot the sky!
1461 if (z
> li
->frontsector
->ceilingheight
)
1464 // it's a sky hack wall
1466 if (li
->backsector
&& li
->backsector
->ceilingpic
== skyflatnum
)
1468 // fix bullet-eaters -- killough:
1469 // WARNING: Almost all demos will lose sync without this
1470 // demo_compatibility flag check!!! killough 1/18/98
1471 if (demo_compatibility
|| li
->backsector
->ceilingheight
< z
)
1475 // Spawn bullet puffs.
1477 P_SpawnPuff (x
,y
,z
);
1479 // don't go any farther
1487 if (th
== shootthing
)
1488 return true; // can't shoot self
1490 if (!(th
->flags
&MF_SHOOTABLE
))
1491 return true; // corpse or something
1493 // check angles to see if the thing can be aimed at
1495 dist
= FixedMul (attackrange
, in
->frac
);
1496 thingtopslope
= FixedDiv (th
->z
+th
->height
- shootz
, dist
);
1498 if (thingtopslope
< aimslope
)
1499 return true; // shot over the thing
1501 thingbottomslope
= FixedDiv (th
->z
- shootz
, dist
);
1503 if (thingbottomslope
> aimslope
)
1504 return true; // shot under the thing
1507 // position a bit closer
1509 frac
= in
->frac
- FixedDiv (10*FRACUNIT
,attackrange
);
1511 x
= trace
.x
+ FixedMul (trace
.dx
, frac
);
1512 y
= trace
.y
+ FixedMul (trace
.dy
, frac
);
1513 z
= shootz
+ FixedMul (aimslope
, FixedMul(frac
, attackrange
));
1515 // Spawn bullet puffs or blod spots,
1516 // depending on target type.
1517 if (in
->d
.thing
->flags
& MF_NOBLOOD
)
1518 P_SpawnPuff (x
,y
,z
);
1520 P_SpawnBlood (x
,y
,z
, la_damage
);
1523 P_DamageMobj (th
, shootthing
, shootthing
, la_damage
);
1525 // don't go any farther
1533 fixed_t
P_AimLineAttack(mobj_t
* t1
,angle_t angle
,fixed_t distance
, uint_64_t mask
)
1538 angle
>>= ANGLETOFINESHIFT
;
1541 x2
= t1
->x
+ (distance
>>FRACBITS
)*finecosine
[angle
];
1542 y2
= t1
->y
+ (distance
>>FRACBITS
)*finesine
[angle
];
1543 shootz
= t1
->z
+ (t1
->height
>>1) + 8*FRACUNIT
;
1545 // can't shoot outside view angles
1547 topslope
= 100*FRACUNIT
/160;
1548 bottomslope
= -100*FRACUNIT
/160;
1550 attackrange
= distance
;
1553 /* killough 8/2/98: prevent friends from aiming at friends */
1554 aim_flags_mask
= mask
;
1556 P_PathTraverse(t1
->x
,t1
->y
,x2
,y2
,PT_ADDLINES
|PT_ADDTHINGS
,PTR_AimTraverse
);
1567 // If damage == 0, it is just a test trace
1568 // that will leave linetarget set.
1581 angle
>>= ANGLETOFINESHIFT
;
1584 x2
= t1
->x
+ (distance
>>FRACBITS
)*finecosine
[angle
];
1585 y2
= t1
->y
+ (distance
>>FRACBITS
)*finesine
[angle
];
1586 shootz
= t1
->z
+ (t1
->height
>>1) + 8*FRACUNIT
;
1587 attackrange
= distance
;
1590 P_PathTraverse(t1
->x
,t1
->y
,x2
,y2
,PT_ADDLINES
|PT_ADDTHINGS
,PTR_ShootTraverse
);
1600 boolean
PTR_UseTraverse (intercept_t
* in
)
1604 if (!in
->d
.line
->special
)
1606 P_LineOpening (in
->d
.line
);
1609 S_StartSound (usething
, sfx_noway
);
1611 // can't use through a wall
1615 // not a special line, but keep checking
1621 if (P_PointOnLineSide (usething
->x
, usething
->y
, in
->d
.line
) == 1)
1624 // return false; // don't use back side
1626 P_UseSpecialLine (usething
, in
->d
.line
, side
);
1628 //WAS can't use for than one special line in a row
1629 //jff 3/21/98 NOW multiple use allowed with enabling line flag
1631 return (!demo_compatibility
&& (in
->d
.line
->flags
&ML_PASSUSE
))?
1635 // Returns false if a "oof" sound should be made because of a blocking
1636 // linedef. Makes 2s middles which are impassable, as well as 2s uppers
1637 // and lowers which block the player, cause the sound effect when the
1638 // player tries to activate them. Specials are excluded, although it is
1639 // assumed that all special linedefs within reach have been considered
1640 // and rejected already (see P_UseLines).
1645 boolean
PTR_NoWayTraverse(intercept_t
* in
)
1647 line_t
*ld
= in
->d
.line
;
1649 return ld
->special
|| !( // Ignore specials
1650 ld
->flags
& ML_BLOCKING
|| ( // Always blocking
1651 P_LineOpening(ld
), // Find openings
1652 openrange
<= 0 || // No opening
1653 openbottom
> usething
->z
+24*FRACUNIT
|| // Too high it blocks
1654 opentop
< usething
->z
+usething
->height
// Too low it blocks
1661 // Looks for special lines in front of the player to activate.
1663 void P_UseLines (player_t
* player
)
1671 usething
= player
->mo
;
1673 angle
= player
->mo
->angle
>> ANGLETOFINESHIFT
;
1677 x2
= x1
+ (USERANGE
>>FRACBITS
)*finecosine
[angle
];
1678 y2
= y1
+ (USERANGE
>>FRACBITS
)*finesine
[angle
];
1682 // P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
1684 // This added test makes the "oof" sound work on 2s lines -- killough:
1686 if (P_PathTraverse ( x1
, y1
, x2
, y2
, PT_ADDLINES
, PTR_UseTraverse
))
1687 if (!comp
[comp_sound
] && !P_PathTraverse ( x1
, y1
, x2
, y2
, PT_ADDLINES
, PTR_NoWayTraverse
))
1688 S_StartSound (usething
, sfx_noway
);
1696 static mobj_t
*bombsource
, *bombspot
;
1697 static int bombdamage
;
1702 // "bombsource" is the creature
1703 // that caused the explosion at "bombspot".
1706 boolean
PIT_RadiusAttack (mobj_t
* thing
)
1712 /* killough 8/20/98: allow bouncers to take damage
1713 * (missile bouncers are already excluded with MF_NOBLOCKMAP)
1716 if (!(thing
->flags
& (MF_SHOOTABLE
| MF_BOUNCES
)))
1719 // Boss spider and cyborg
1720 // take no damage from concussion.
1722 // killough 8/10/98: allow grenades to hurt anyone, unless
1723 // fired by Cyberdemons, in which case it won't hurt Cybers.
1725 if (bombspot
->flags
& MF_BOUNCES
?
1726 thing
->type
== MT_CYBORG
&& bombsource
->type
== MT_CYBORG
:
1727 thing
->type
== MT_CYBORG
|| thing
->type
== MT_SPIDER
)
1730 dx
= D_abs(thing
->x
- bombspot
->x
);
1731 dy
= D_abs(thing
->y
- bombspot
->y
);
1733 dist
= dx
>dy
? dx
: dy
;
1734 dist
= (dist
- thing
->radius
) >> FRACBITS
;
1739 if (dist
>= bombdamage
)
1740 return true; // out of range
1742 if ( P_CheckSight (thing
, bombspot
) )
1744 // must be in direct path
1745 P_DamageMobj (thing
, bombspot
, bombsource
, bombdamage
- dist
);
1754 // Source is the creature that caused the explosion at spot.
1756 void P_RadiusAttack(mobj_t
* spot
,mobj_t
* source
,int damage
)
1768 dist
= (damage
+MAXRADIUS
)<<FRACBITS
;
1769 yh
= (spot
->y
+ dist
- bmaporgy
)>>MAPBLOCKSHIFT
;
1770 yl
= (spot
->y
- dist
- bmaporgy
)>>MAPBLOCKSHIFT
;
1771 xh
= (spot
->x
+ dist
- bmaporgx
)>>MAPBLOCKSHIFT
;
1772 xl
= (spot
->x
- dist
- bmaporgx
)>>MAPBLOCKSHIFT
;
1774 bombsource
= source
;
1775 bombdamage
= damage
;
1777 for (y
=yl
; y
<=yh
; y
++)
1778 for (x
=xl
; x
<=xh
; x
++)
1779 P_BlockThingsIterator (x
, y
, PIT_RadiusAttack
);
1785 // SECTOR HEIGHT CHANGING
1786 // After modifying a sectors floor or ceiling height,
1787 // call this routine to adjust the positions
1788 // of all things that touch the sector.
1790 // If anything doesn't fit anymore, true will be returned.
1791 // If crunch is true, they will take damage
1792 // as they are being crushed.
1793 // If Crunch is false, you should set the sector height back
1794 // the way it was and call P_ChangeSector again
1795 // to undo the changes.
1798 static boolean crushchange
, nofit
;
1804 boolean
PIT_ChangeSector (mobj_t
* thing
)
1808 if (P_ThingHeightClip (thing
))
1809 return true; // keep checking
1811 // crunch bodies to giblets
1813 if (thing
->health
<= 0)
1815 P_SetMobjState (thing
, S_GIBS
);
1817 thing
->flags
&= ~MF_SOLID
;
1820 return true; // keep checking
1823 // crunch dropped items
1825 if (thing
->flags
& MF_DROPPED
)
1827 P_RemoveMobj (thing
);
1833 /* killough 11/98: kill touchy things immediately */
1834 if (thing
->flags
& MF_TOUCHY
&&
1835 (thing
->intflags
& MIF_ARMED
|| sentient(thing
)))
1837 P_DamageMobj(thing
, NULL
, NULL
, thing
->health
); // kill object
1838 return true; // keep checking
1841 if (! (thing
->flags
& MF_SHOOTABLE
) )
1843 // assume it is bloody gibs or something
1849 if (crushchange
&& !(leveltime
&3)) {
1851 P_DamageMobj(thing
,NULL
,NULL
,10);
1853 // spray blood in a random direction
1854 mo
= P_SpawnMobj (thing
->x
,
1856 thing
->z
+ thing
->height
/2, MT_BLOOD
);
1858 /* killough 8/10/98: remove dependence on order of evaluation */
1859 t
= P_Random(pr_crush
);
1860 mo
->momx
= (t
- P_Random (pr_crush
))<<12;
1861 t
= P_Random(pr_crush
);
1862 mo
->momy
= (t
- P_Random (pr_crush
))<<12;
1865 // keep checking (crush other things)
1873 boolean
P_ChangeSector(sector_t
* sector
,boolean crunch
)
1879 crushchange
= crunch
;
1882 // This is horrendously slow!!!
1885 // re-check heights for all things near the moving sector
1887 for (x
=sector
->blockbox
[BOXLEFT
] ; x
<= sector
->blockbox
[BOXRIGHT
] ; x
++)
1888 for (y
=sector
->blockbox
[BOXBOTTOM
];y
<= sector
->blockbox
[BOXTOP
] ; y
++)
1889 P_BlockThingsIterator (x
, y
, PIT_ChangeSector
);
1896 // jff 3/19/98 added to just check monsters on the periphery
1897 // of a moving sector instead of all in bounding box of the
1898 // sector. Both more accurate and faster.
1901 boolean
P_CheckSector(sector_t
* sector
,boolean crunch
)
1905 if (comp
[comp_floors
]) /* use the old routine for old demos though */
1906 return P_ChangeSector(sector
,crunch
);
1909 crushchange
= crunch
;
1911 // killough 4/4/98: scan list front-to-back until empty or exhausted,
1912 // restarting from beginning after each thing is processed. Avoids
1913 // crashes, and is sure to examine all things in the sector, and only
1914 // the things which are in the sector, until a steady-state is reached.
1915 // Things can arbitrarily be inserted and removed and it won't mess up.
1917 // killough 4/7/98: simplified to avoid using complicated counter
1919 // Mark all things invalid
1921 for (n
=sector
->touching_thinglist
; n
; n
=n
->m_snext
)
1925 for (n
=sector
->touching_thinglist
; n
; n
=n
->m_snext
) // go through list
1926 if (!n
->visited
) // unprocessed thing found
1928 n
->visited
= true; // mark thing as processed
1929 if (!(n
->m_thing
->flags
& MF_NOBLOCKMAP
)) //jff 4/7/98 don't do these
1930 PIT_ChangeSector(n
->m_thing
); // process it
1931 break; // exit and start over
1933 while (n
); // repeat from scratch until all things left are marked valid
1940 // Use block memory allocator here
1942 #include "z_bmalloc.h"
1944 IMPLEMENT_BLOCK_MEMORY_ALLOC_ZONE(secnodezone
, sizeof(msecnode_t
), PU_LEVEL
, 32, "SecNodes");
1946 inline static msecnode_t
* P_GetSecnode(void)
1948 return (msecnode_t
*)Z_BMalloc(&secnodezone
);
1951 // P_PutSecnode() returns a node to the freelist.
1953 inline static void P_PutSecnode(msecnode_t
* node
)
1955 Z_BFree(&secnodezone
, node
);
1960 // P_AddSecnode() searches the current list to see if this sector is
1961 // already there. If not, it adds a sector node at the head of the list of
1962 // sectors this object appears in. This is called when creating a list of
1963 // nodes that will get linked in later. Returns a pointer to the new node.
1965 msecnode_t
* P_AddSecnode(sector_t
* s
, mobj_t
* thing
, msecnode_t
* nextnode
)
1972 if (node
->m_sector
== s
) // Already have a node for this sector?
1974 node
->m_thing
= thing
; // Yes. Setting m_thing says 'keep it'.
1977 node
= node
->m_tnext
;
1980 // Couldn't find an existing node for this sector. Add one at the head
1983 node
= P_GetSecnode();
1985 // killough 4/4/98, 4/7/98: mark new nodes unvisited.
1988 node
->m_sector
= s
; // sector
1989 node
->m_thing
= thing
; // mobj
1990 node
->m_tprev
= NULL
; // prev node on Thing thread
1991 node
->m_tnext
= nextnode
; // next node on Thing thread
1993 nextnode
->m_tprev
= node
; // set back link on Thing
1995 // Add new node at head of sector thread starting at s->touching_thinglist
1997 node
->m_sprev
= NULL
; // prev node on sector thread
1998 node
->m_snext
= s
->touching_thinglist
; // next node on sector thread
1999 if (s
->touching_thinglist
)
2000 node
->m_snext
->m_sprev
= node
;
2001 s
->touching_thinglist
= node
;
2006 // P_DelSecnode() deletes a sector node from the list of
2007 // sectors this object appears in. Returns a pointer to the next node
2008 // on the linked list, or NULL.
2010 msecnode_t
* P_DelSecnode(msecnode_t
* node
)
2012 msecnode_t
* tp
; // prev node on thing thread
2013 msecnode_t
* tn
; // next node on thing thread
2014 msecnode_t
* sp
; // prev node on sector thread
2015 msecnode_t
* sn
; // next node on sector thread
2020 // Unlink from the Thing thread. The Thing thread begins at
2021 // sector_list and not from mobj_t->touching_sectorlist.
2030 // Unlink from the sector thread. This thread begins at
2031 // sector_t->touching_thinglist.
2038 node
->m_sector
->touching_thinglist
= sn
;
2042 // Return this node to the freelist
2050 // Delete an entire sector list
2052 void P_DelSeclist(msecnode_t
* node
)
2056 node
= P_DelSecnode(node
);
2063 // Locates all the sectors the object is in by looking at the lines that
2064 // cross through it. You have already decided that the object is allowed
2065 // at this location, so don't bother with checking impassable or
2068 boolean
PIT_GetSectors(line_t
* ld
)
2070 if (tmbbox
[BOXRIGHT
] <= ld
->bbox
[BOXLEFT
] ||
2071 tmbbox
[BOXLEFT
] >= ld
->bbox
[BOXRIGHT
] ||
2072 tmbbox
[BOXTOP
] <= ld
->bbox
[BOXBOTTOM
] ||
2073 tmbbox
[BOXBOTTOM
] >= ld
->bbox
[BOXTOP
])
2076 if (P_BoxOnLineSide(tmbbox
, ld
) != -1)
2079 // This line crosses through the object.
2081 // Collect the sector(s) from the line and add to the
2082 // sector_list you're examining. If the Thing ends up being
2083 // allowed to move to this position, then the sector_list
2084 // will be attached to the Thing's mobj_t at touching_sectorlist.
2086 sector_list
= P_AddSecnode(ld
->frontsector
,tmthing
,sector_list
);
2088 /* Don't assume all lines are 2-sided, since some Things
2089 * like MT_TFOG are allowed regardless of whether their radius takes
2090 * them beyond an impassable linedef.
2092 * killough 3/27/98, 4/4/98:
2093 * Use sidedefs instead of 2s flag to determine two-sidedness.
2094 * killough 8/1/98: avoid duplicate if same sector on both sides
2095 * cph - DEMOSYNC? */
2097 if (ld
->backsector
&& ld
->backsector
!= ld
->frontsector
)
2098 sector_list
= P_AddSecnode(ld
->backsector
, tmthing
, sector_list
);
2106 // P_CreateSecNodeList alters/creates the sector_list that shows what sectors
2107 // the object resides in.
2109 void P_CreateSecNodeList(mobj_t
* thing
,fixed_t x
,fixed_t y
)
2118 mobj_t
* saved_tmthing
= tmthing
; /* cph - see comment at func end */
2119 fixed_t saved_tmx
= tmx
, saved_tmy
= tmy
; /* ditto */
2121 // First, clear out the existing m_thing fields. As each node is
2122 // added or verified as needed, m_thing will be set properly. When
2123 // finished, delete all nodes where m_thing is still NULL. These
2124 // represent the sectors the Thing has vacated.
2129 node
->m_thing
= NULL
;
2130 node
= node
->m_tnext
;
2138 tmbbox
[BOXTOP
] = y
+ tmthing
->radius
;
2139 tmbbox
[BOXBOTTOM
] = y
- tmthing
->radius
;
2140 tmbbox
[BOXRIGHT
] = x
+ tmthing
->radius
;
2141 tmbbox
[BOXLEFT
] = x
- tmthing
->radius
;
2143 validcount
++; // used to make sure we only process a line once
2145 xl
= (tmbbox
[BOXLEFT
] - bmaporgx
)>>MAPBLOCKSHIFT
;
2146 xh
= (tmbbox
[BOXRIGHT
] - bmaporgx
)>>MAPBLOCKSHIFT
;
2147 yl
= (tmbbox
[BOXBOTTOM
] - bmaporgy
)>>MAPBLOCKSHIFT
;
2148 yh
= (tmbbox
[BOXTOP
] - bmaporgy
)>>MAPBLOCKSHIFT
;
2150 for (bx
=xl
; bx
<=xh
; bx
++)
2151 for (by
=yl
; by
<=yh
; by
++)
2152 P_BlockLinesIterator(bx
,by
,PIT_GetSectors
);
2154 // Add the sector of the (x,y) point to sector_list.
2156 sector_list
= P_AddSecnode(thing
->subsector
->sector
,thing
,sector_list
);
2158 // Now delete any nodes that won't be used. These are the ones where
2159 // m_thing is still NULL.
2164 if (node
->m_thing
== NULL
)
2166 if (node
== sector_list
)
2167 sector_list
= node
->m_tnext
;
2168 node
= P_DelSecnode(node
);
2171 node
= node
->m_tnext
;
2175 * This is the strife we get into for using global variables. tmthing
2176 * is being used by several different functions calling
2177 * P_BlockThingIterator, including functions that can be called *from*
2178 * P_BlockThingIterator. Using a global tmthing is not reentrant.
2179 * OTOH for Boom/MBF demos we have to preserve the buggy behavior.
2180 * Fun. We restore its previous value unless we're in a Boom/MBF demo.
2182 if ((compatibility_level
< boom_compatibility_compatibility
) ||
2183 (compatibility_level
>= prboom_3_compatibility
))
2184 tmthing
= saved_tmthing
;
2185 /* And, duh, the same for tmx/y - cph 2002/09/22
2186 * And for tmbbox - cph 2003/08/10 */
2187 if ((compatibility_level
< boom_compatibility_compatibility
) /* ||
2188 (compatibility_level >= prboom_4_compatibility) */) {
2189 tmx
= saved_tmx
, tmy
= saved_tmy
;
2191 tmbbox
[BOXTOP
] = tmy
+ tmthing
->radius
;
2192 tmbbox
[BOXBOTTOM
] = tmy
- tmthing
->radius
;
2193 tmbbox
[BOXRIGHT
] = tmx
+ tmthing
->radius
;
2194 tmbbox
[BOXLEFT
] = tmx
- tmthing
->radius
;
2199 /* cphipps 2004/08/30 -
2200 * Must clear tmthing at tic end, as it might contain a pointer to a removed thinker, or the level might have ended/been ended and we clear the objects it was pointing too. Hopefully we don't need to carry this between tics for sync. */
2201 void P_MapStart(void) {
2202 if (tmthing
) I_Error("P_MapStart: tmthing set!");
2204 void P_MapEnd(void) {