1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
4 // Copyright(C) 1993-1996 Id Software, Inc.
5 // Copyright(C) 2005 Simon Howard, Andrey Budko
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23 // Movement, collision handling.
24 // Shooting and aiming.
26 //-----------------------------------------------------------------------------
50 // Spechit overrun magic value.
52 // This is the value used by PrBoom-plus. I think the value below is
53 // actually better and works with more demos. However, I think
54 // it's better for the spechits emulation to be compatible with
55 // PrBoom-plus, at least so that the big spechits emulation list
56 // on Doomworld can also be used with Chocolate Doom.
58 #define DEFAULT_SPECHIT_MAGIC 0x01C09C98
60 // This is from a post by myk on the Doomworld forums,
61 // outputted from entryway's spechit_magic generator for
62 // s205n546.lmp. The _exact_ value of this isn't too
63 // important; as long as it is in the right general
64 // range, it will usually work. Otherwise, we can use
65 // the generator (hacked doom2.exe) and provide it
68 //#define DEFAULT_SPECHIT_MAGIC 0x84f968e8
78 // If "floatok" true, move would be ok
79 // if within "tmfloorz - tmceilingz".
86 // keep track of the line that lowers the ceiling,
87 // so missiles don't explode against sky hack walls
90 // keep track of special lines as they are hit,
91 // but don't process them until the move is proven valid
93 // fraggle: I have increased the size of this buffer. In the original Doom,
94 // overrunning past this limit caused other bits of memory to be overwritten,
95 // affecting demo playback. However, in doing so, the limit was still
96 // exceeded. So we have to support more than 8 specials.
98 // We keep the original limit, to detect what variables in memory were
99 // overwritten (see SpechitOverrun())
101 #define MAXSPECIALCROSS 20
102 #define MAXSPECIALCROSS_ORIGINAL 8
104 line_t
* spechit
[MAXSPECIALCROSS
];
116 boolean
PIT_StompThing (mobj_t
* thing
)
120 if (!(thing
->flags
& MF_SHOOTABLE
) )
123 blockdist
= thing
->radius
+ tmthing
->radius
;
125 if ( abs(thing
->x
- tmx
) >= blockdist
126 || abs(thing
->y
- tmy
) >= blockdist
)
132 // don't clip against self
133 if (thing
== tmthing
)
136 // monsters don't stomp things except on boss level
137 if ( !tmthing
->player
&& gamemap
!= 30)
140 P_DamageMobj (thing
, tmthing
, tmthing
, 10000);
162 subsector_t
* newsubsec
;
164 // kill anything occupying the position
166 tmflags
= thing
->flags
;
171 tmbbox
[BOXTOP
] = y
+ tmthing
->radius
;
172 tmbbox
[BOXBOTTOM
] = y
- tmthing
->radius
;
173 tmbbox
[BOXRIGHT
] = x
+ tmthing
->radius
;
174 tmbbox
[BOXLEFT
] = x
- tmthing
->radius
;
176 newsubsec
= R_PointInSubsector (x
,y
);
179 // The base floor/ceiling is from the subsector
180 // that contains the point.
181 // Any contacted lines the step closer together
183 tmfloorz
= tmdropoffz
= newsubsec
->sector
->floorheight
;
184 tmceilingz
= newsubsec
->sector
->ceilingheight
;
189 // stomp on any things contacted
190 xl
= (tmbbox
[BOXLEFT
] - bmaporgx
- MAXRADIUS
)>>MAPBLOCKSHIFT
;
191 xh
= (tmbbox
[BOXRIGHT
] - bmaporgx
+ MAXRADIUS
)>>MAPBLOCKSHIFT
;
192 yl
= (tmbbox
[BOXBOTTOM
] - bmaporgy
- MAXRADIUS
)>>MAPBLOCKSHIFT
;
193 yh
= (tmbbox
[BOXTOP
] - bmaporgy
+ MAXRADIUS
)>>MAPBLOCKSHIFT
;
195 for (bx
=xl
; bx
<=xh
; bx
++)
196 for (by
=yl
; by
<=yh
; by
++)
197 if (!P_BlockThingsIterator(bx
,by
,PIT_StompThing
))
201 // so link the thing into its new position
202 P_UnsetThingPosition (thing
);
204 thing
->floorz
= tmfloorz
;
205 thing
->ceilingz
= tmceilingz
;
209 P_SetThingPosition (thing
);
216 // MOVEMENT ITERATOR FUNCTIONS
219 static void SpechitOverrun(line_t
*ld
);
223 // Adjusts tmfloorz and tmceilingz as lines are contacted
225 boolean
PIT_CheckLine (line_t
* ld
)
227 if (tmbbox
[BOXRIGHT
] <= ld
->bbox
[BOXLEFT
]
228 || tmbbox
[BOXLEFT
] >= ld
->bbox
[BOXRIGHT
]
229 || tmbbox
[BOXTOP
] <= ld
->bbox
[BOXBOTTOM
]
230 || tmbbox
[BOXBOTTOM
] >= ld
->bbox
[BOXTOP
] )
233 if (P_BoxOnLineSide (tmbbox
, ld
) != -1)
236 // A line has been hit
238 // The moving thing's destination position will cross
240 // If this should not be allowed, return false.
241 // If the line is special, keep track of it
242 // to process later if the move is proven ok.
243 // NOTE: specials are NOT sorted by order,
244 // so two special lines that are only 8 pixels apart
245 // could be crossed in either order.
248 return false; // one sided line
250 if (!(tmthing
->flags
& MF_MISSILE
) )
252 if ( ld
->flags
& ML_BLOCKING
)
253 return false; // explicitly blocking everything
255 if ( !tmthing
->player
&& ld
->flags
& ML_BLOCKMONSTERS
)
256 return false; // block monsters only
259 // set openrange, opentop, openbottom
262 // adjust floor / ceiling heights
263 if (opentop
< tmceilingz
)
265 tmceilingz
= opentop
;
269 if (openbottom
> tmfloorz
)
270 tmfloorz
= openbottom
;
272 if (lowfloor
< tmdropoffz
)
273 tmdropoffz
= lowfloor
;
275 // if contacted a special line, add it to the list
278 spechit
[numspechit
] = ld
;
281 // fraggle: spechits overrun emulation code from prboom-plus
282 if (numspechit
> MAXSPECIALCROSS_ORIGINAL
)
294 boolean
PIT_CheckThing (mobj_t
* thing
)
300 if (!(thing
->flags
& (MF_SOLID
|MF_SPECIAL
|MF_SHOOTABLE
) ))
303 blockdist
= thing
->radius
+ tmthing
->radius
;
305 if ( abs(thing
->x
- tmx
) >= blockdist
306 || abs(thing
->y
- tmy
) >= blockdist
)
312 // don't clip against self
313 if (thing
== tmthing
)
316 // check for skulls slamming into things
317 if (tmthing
->flags
& MF_SKULLFLY
)
319 damage
= ((P_Random()%8)+1)*tmthing
->info
->damage
;
321 P_DamageMobj (thing
, tmthing
, tmthing
, damage
);
323 tmthing
->flags
&= ~MF_SKULLFLY
;
324 tmthing
->momx
= tmthing
->momy
= tmthing
->momz
= 0;
326 P_SetMobjState (tmthing
, tmthing
->info
->spawnstate
);
328 return false; // stop moving
332 // missiles can hit other things
333 if (tmthing
->flags
& MF_MISSILE
)
335 // see if it went over / under
336 if (tmthing
->z
> thing
->z
+ thing
->height
)
337 return true; // overhead
338 if (tmthing
->z
+tmthing
->height
< thing
->z
)
339 return true; // underneath
342 && (tmthing
->target
->type
== thing
->type
||
343 (tmthing
->target
->type
== MT_KNIGHT
&& thing
->type
== MT_BRUISER
)||
344 (tmthing
->target
->type
== MT_BRUISER
&& thing
->type
== MT_KNIGHT
) ) )
346 // Don't hit same species as originator.
347 if (thing
== tmthing
->target
)
350 // sdh: Add deh_species_infighting here. We can override the
351 // "monsters of the same species cant hurt each other" behavior
352 // through dehacked patches
354 if (thing
->type
!= MT_PLAYER
&& !deh_species_infighting
)
356 // Explode, but do no damage.
357 // Let players missile other players.
362 if (! (thing
->flags
& MF_SHOOTABLE
) )
364 // didn't do any damage
365 return !(thing
->flags
& MF_SOLID
);
369 damage
= ((P_Random()%8)+1)*tmthing
->info
->damage
;
370 P_DamageMobj (thing
, tmthing
, tmthing
->target
, damage
);
372 // don't traverse any more
376 // check for special pickup
377 if (thing
->flags
& MF_SPECIAL
)
379 solid
= thing
->flags
&MF_SOLID
;
380 if (tmflags
&MF_PICKUP
)
383 P_TouchSpecialThing (thing
, tmthing
);
388 return !(thing
->flags
& MF_SOLID
);
398 // This is purely informative, nothing is modified
399 // (except things picked up).
402 // a mobj_t (can be valid or invalid)
403 // a position to be checked
404 // (doesn't need to be related to the mobj_t->x,y)
407 // special things are touched if MF_PICKUP
408 // early out on solid lines?
415 // the lowest point contacted
416 // (monsters won't move to a dropoff)
432 subsector_t
* newsubsec
;
435 tmflags
= thing
->flags
;
440 tmbbox
[BOXTOP
] = y
+ tmthing
->radius
;
441 tmbbox
[BOXBOTTOM
] = y
- tmthing
->radius
;
442 tmbbox
[BOXRIGHT
] = x
+ tmthing
->radius
;
443 tmbbox
[BOXLEFT
] = x
- tmthing
->radius
;
445 newsubsec
= R_PointInSubsector (x
,y
);
448 // The base floor / ceiling is from the subsector
449 // that contains the point.
450 // Any contacted lines the step closer together
452 tmfloorz
= tmdropoffz
= newsubsec
->sector
->floorheight
;
453 tmceilingz
= newsubsec
->sector
->ceilingheight
;
458 if ( tmflags
& MF_NOCLIP
)
461 // Check things first, possibly picking things up.
462 // The bounding box is extended by MAXRADIUS
463 // because mobj_ts are grouped into mapblocks
464 // based on their origin point, and can overlap
465 // into adjacent blocks by up to MAXRADIUS units.
466 xl
= (tmbbox
[BOXLEFT
] - bmaporgx
- MAXRADIUS
)>>MAPBLOCKSHIFT
;
467 xh
= (tmbbox
[BOXRIGHT
] - bmaporgx
+ MAXRADIUS
)>>MAPBLOCKSHIFT
;
468 yl
= (tmbbox
[BOXBOTTOM
] - bmaporgy
- MAXRADIUS
)>>MAPBLOCKSHIFT
;
469 yh
= (tmbbox
[BOXTOP
] - bmaporgy
+ MAXRADIUS
)>>MAPBLOCKSHIFT
;
471 for (bx
=xl
; bx
<=xh
; bx
++)
472 for (by
=yl
; by
<=yh
; by
++)
473 if (!P_BlockThingsIterator(bx
,by
,PIT_CheckThing
))
477 xl
= (tmbbox
[BOXLEFT
] - bmaporgx
)>>MAPBLOCKSHIFT
;
478 xh
= (tmbbox
[BOXRIGHT
] - bmaporgx
)>>MAPBLOCKSHIFT
;
479 yl
= (tmbbox
[BOXBOTTOM
] - bmaporgy
)>>MAPBLOCKSHIFT
;
480 yh
= (tmbbox
[BOXTOP
] - bmaporgy
)>>MAPBLOCKSHIFT
;
482 for (bx
=xl
; bx
<=xh
; bx
++)
483 for (by
=yl
; by
<=yh
; by
++)
484 if (!P_BlockLinesIterator (bx
,by
,PIT_CheckLine
))
493 // Attempt to move to a new position,
494 // crossing special lines unless MF_TELEPORT is set.
509 if (!P_CheckPosition (thing
, x
, y
))
510 return false; // solid wall or thing
512 if ( !(thing
->flags
& MF_NOCLIP
) )
514 if (tmceilingz
- tmfloorz
< thing
->height
)
515 return false; // doesn't fit
519 if ( !(thing
->flags
&MF_TELEPORT
)
520 &&tmceilingz
- thing
->z
< thing
->height
)
521 return false; // mobj must lower itself to fit
523 if ( !(thing
->flags
&MF_TELEPORT
)
524 && tmfloorz
- thing
->z
> 24*FRACUNIT
)
525 return false; // too big a step up
527 if ( !(thing
->flags
&(MF_DROPOFF
|MF_FLOAT
))
528 && tmfloorz
- tmdropoffz
> 24*FRACUNIT
)
529 return false; // don't stand over a dropoff
533 // so link the thing into its new position
534 P_UnsetThingPosition (thing
);
538 thing
->floorz
= tmfloorz
;
539 thing
->ceilingz
= tmceilingz
;
543 P_SetThingPosition (thing
);
545 // if any special lines were hit, do the effect
546 if (! (thing
->flags
&(MF_TELEPORT
|MF_NOCLIP
)) )
550 // see if the line was crossed
551 ld
= spechit
[numspechit
];
552 side
= P_PointOnLineSide (thing
->x
, thing
->y
, ld
);
553 oldside
= P_PointOnLineSide (oldx
, oldy
, ld
);
557 P_CrossSpecialLine (ld
-lines
, oldside
, thing
);
568 // Takes a valid thing and adjusts the thing->floorz,
569 // thing->ceilingz, and possibly thing->z.
570 // This is called for all nearby monsters
571 // whenever a sector changes height.
572 // If the thing doesn't fit,
573 // the z will be set to the lowest value
574 // and false will be returned.
576 boolean
P_ThingHeightClip (mobj_t
* thing
)
580 onfloor
= (thing
->z
== thing
->floorz
);
582 P_CheckPosition (thing
, thing
->x
, thing
->y
);
583 // what about stranding a monster partially off an edge?
585 thing
->floorz
= tmfloorz
;
586 thing
->ceilingz
= tmceilingz
;
590 // walking monsters rise and fall with the floor
591 thing
->z
= thing
->floorz
;
595 // don't adjust a floating monster unless forced to
596 if (thing
->z
+thing
->height
> thing
->ceilingz
)
597 thing
->z
= thing
->ceilingz
- thing
->height
;
600 if (thing
->ceilingz
- thing
->floorz
< thing
->height
)
610 // Allows the player to slide along any angled walls.
612 fixed_t bestslidefrac
;
613 fixed_t secondslidefrac
;
615 line_t
* bestslideline
;
616 line_t
* secondslideline
;
627 // Adjusts the xmove / ymove
628 // so that the next move will slide along the wall.
630 void P_HitSlideLine (line_t
* ld
)
642 if (ld
->slopetype
== ST_HORIZONTAL
)
648 if (ld
->slopetype
== ST_VERTICAL
)
654 side
= P_PointOnLineSide (slidemo
->x
, slidemo
->y
, ld
);
656 lineangle
= R_PointToAngle2 (0,0, ld
->dx
, ld
->dy
);
661 moveangle
= R_PointToAngle2 (0,0, tmxmove
, tmymove
);
662 deltaangle
= moveangle
-lineangle
;
664 if (deltaangle
> ANG180
)
665 deltaangle
+= ANG180
;
666 // I_Error ("SlideLine: ang>ANG180");
668 lineangle
>>= ANGLETOFINESHIFT
;
669 deltaangle
>>= ANGLETOFINESHIFT
;
671 movelen
= P_AproxDistance (tmxmove
, tmymove
);
672 newlen
= FixedMul (movelen
, finecosine
[deltaangle
]);
674 tmxmove
= FixedMul (newlen
, finecosine
[lineangle
]);
675 tmymove
= FixedMul (newlen
, finesine
[lineangle
]);
682 boolean
PTR_SlideTraverse (intercept_t
* in
)
687 I_Error ("PTR_SlideTraverse: not a line?");
691 if ( ! (li
->flags
& ML_TWOSIDED
) )
693 if (P_PointOnLineSide (slidemo
->x
, slidemo
->y
, li
))
695 // don't hit the back side
701 // set openrange, opentop, openbottom
704 if (openrange
< slidemo
->height
)
705 goto isblocking
; // doesn't fit
707 if (opentop
- slidemo
->z
< slidemo
->height
)
708 goto isblocking
; // mobj is too high
710 if (openbottom
- slidemo
->z
> 24*FRACUNIT
)
711 goto isblocking
; // too big a step up
713 // this line doesn't block movement
716 // the line does block movement,
717 // see if it is closer than best so far
719 if (in
->frac
< bestslidefrac
)
721 secondslidefrac
= bestslidefrac
;
722 secondslideline
= bestslideline
;
723 bestslidefrac
= in
->frac
;
727 return false; // stop
734 // The momx / momy move is bad, so try to slide
736 // Find the first line hit, move flush to it,
737 // and slide along it
739 // This is a kludgy mess.
741 void P_SlideMove (mobj_t
* mo
)
756 goto stairstep
; // don't loop forever
759 // trace along the three leading corners
762 leadx
= mo
->x
+ mo
->radius
;
763 trailx
= mo
->x
- mo
->radius
;
767 leadx
= mo
->x
- mo
->radius
;
768 trailx
= mo
->x
+ mo
->radius
;
773 leady
= mo
->y
+ mo
->radius
;
774 traily
= mo
->y
- mo
->radius
;
778 leady
= mo
->y
- mo
->radius
;
779 traily
= mo
->y
+ mo
->radius
;
782 bestslidefrac
= FRACUNIT
+1;
784 P_PathTraverse ( leadx
, leady
, leadx
+mo
->momx
, leady
+mo
->momy
,
785 PT_ADDLINES
, PTR_SlideTraverse
);
786 P_PathTraverse ( trailx
, leady
, trailx
+mo
->momx
, leady
+mo
->momy
,
787 PT_ADDLINES
, PTR_SlideTraverse
);
788 P_PathTraverse ( leadx
, traily
, leadx
+mo
->momx
, traily
+mo
->momy
,
789 PT_ADDLINES
, PTR_SlideTraverse
);
791 // move up to the wall
792 if (bestslidefrac
== FRACUNIT
+1)
794 // the move most have hit the middle, so stairstep
796 if (!P_TryMove (mo
, mo
->x
, mo
->y
+ mo
->momy
))
797 P_TryMove (mo
, mo
->x
+ mo
->momx
, mo
->y
);
801 // fudge a bit to make sure it doesn't hit
802 bestslidefrac
-= 0x800;
803 if (bestslidefrac
> 0)
805 newx
= FixedMul (mo
->momx
, bestslidefrac
);
806 newy
= FixedMul (mo
->momy
, bestslidefrac
);
808 if (!P_TryMove (mo
, mo
->x
+newx
, mo
->y
+newy
))
812 // Now continue along the wall.
813 // First calculate remainder.
814 bestslidefrac
= FRACUNIT
-(bestslidefrac
+0x800);
816 if (bestslidefrac
> FRACUNIT
)
817 bestslidefrac
= FRACUNIT
;
819 if (bestslidefrac
<= 0)
822 tmxmove
= FixedMul (mo
->momx
, bestslidefrac
);
823 tmymove
= FixedMul (mo
->momy
, bestslidefrac
);
825 P_HitSlideLine (bestslideline
); // clip the moves
830 if (!P_TryMove (mo
, mo
->x
+tmxmove
, mo
->y
+tmymove
))
840 mobj_t
* linetarget
; // who got hit (or NULL)
843 // Height if not aiming up or down
844 // ???: use slope for monsters?
852 // slopes to top and bottom of target
853 extern fixed_t topslope
;
854 extern fixed_t bottomslope
;
859 // Sets linetaget and aimslope when a target is aimed at.
862 PTR_AimTraverse (intercept_t
* in
)
867 fixed_t thingtopslope
;
868 fixed_t thingbottomslope
;
875 if ( !(li
->flags
& ML_TWOSIDED
) )
876 return false; // stop
878 // Crosses a two sided line.
879 // A two sided line will restrict
880 // the possible target ranges.
883 if (openbottom
>= opentop
)
884 return false; // stop
886 dist
= FixedMul (attackrange
, in
->frac
);
888 // Return false if there is no back sector. This should never
889 // be the case if the line is two-sided; however, some WADs
890 // (eg. ottawau.wad) use this as an "impassible glass" trick
891 // and rely on Vanilla Doom's (unintentional) support for this.
893 if (li
->backsector
== NULL
)
898 if (li
->frontsector
->floorheight
!= li
->backsector
->floorheight
)
900 slope
= FixedDiv (openbottom
- shootz
, dist
);
901 if (slope
> bottomslope
)
905 if (li
->frontsector
->ceilingheight
!= li
->backsector
->ceilingheight
)
907 slope
= FixedDiv (opentop
- shootz
, dist
);
908 if (slope
< topslope
)
912 if (topslope
<= bottomslope
)
913 return false; // stop
915 return true; // shot continues
920 if (th
== shootthing
)
921 return true; // can't shoot self
923 if (!(th
->flags
&MF_SHOOTABLE
))
924 return true; // corpse or something
926 // check angles to see if the thing can be aimed at
927 dist
= FixedMul (attackrange
, in
->frac
);
928 thingtopslope
= FixedDiv (th
->z
+th
->height
- shootz
, dist
);
930 if (thingtopslope
< bottomslope
)
931 return true; // shot over the thing
933 thingbottomslope
= FixedDiv (th
->z
- shootz
, dist
);
935 if (thingbottomslope
> topslope
)
936 return true; // shot under the thing
938 // this thing can be hit!
939 if (thingtopslope
> topslope
)
940 thingtopslope
= topslope
;
942 if (thingbottomslope
< bottomslope
)
943 thingbottomslope
= bottomslope
;
945 aimslope
= (thingtopslope
+thingbottomslope
)/2;
948 return false; // don't go any farther
955 boolean
PTR_ShootTraverse (intercept_t
* in
)
968 fixed_t thingtopslope
;
969 fixed_t thingbottomslope
;
976 P_ShootSpecialLine (shootthing
, li
);
978 if ( !(li
->flags
& ML_TWOSIDED
) )
981 // crosses a two sided line
984 dist
= FixedMul (attackrange
, in
->frac
);
986 // Check if backsector is NULL. See comment in PTR_AimTraverse.
988 if (li
->backsector
== NULL
)
993 if (li
->frontsector
->floorheight
!= li
->backsector
->floorheight
)
995 slope
= FixedDiv (openbottom
- shootz
, dist
);
996 if (slope
> aimslope
)
1000 if (li
->frontsector
->ceilingheight
!= li
->backsector
->ceilingheight
)
1002 slope
= FixedDiv (opentop
- shootz
, dist
);
1003 if (slope
< aimslope
)
1013 // position a bit closer
1014 frac
= in
->frac
- FixedDiv (4*FRACUNIT
,attackrange
);
1015 x
= trace
.x
+ FixedMul (trace
.dx
, frac
);
1016 y
= trace
.y
+ FixedMul (trace
.dy
, frac
);
1017 z
= shootz
+ FixedMul (aimslope
, FixedMul(frac
, attackrange
));
1019 if (li
->frontsector
->ceilingpic
== skyflatnum
)
1021 // don't shoot the sky!
1022 if (z
> li
->frontsector
->ceilingheight
)
1025 // it's a sky hack wall
1026 if (li
->backsector
&& li
->backsector
->ceilingpic
== skyflatnum
)
1030 // Spawn bullet puffs.
1031 P_SpawnPuff (x
,y
,z
);
1033 // don't go any farther
1039 if (th
== shootthing
)
1040 return true; // can't shoot self
1042 if (!(th
->flags
&MF_SHOOTABLE
))
1043 return true; // corpse or something
1045 // check angles to see if the thing can be aimed at
1046 dist
= FixedMul (attackrange
, in
->frac
);
1047 thingtopslope
= FixedDiv (th
->z
+th
->height
- shootz
, dist
);
1049 if (thingtopslope
< aimslope
)
1050 return true; // shot over the thing
1052 thingbottomslope
= FixedDiv (th
->z
- shootz
, dist
);
1054 if (thingbottomslope
> aimslope
)
1055 return true; // shot under the thing
1059 // position a bit closer
1060 frac
= in
->frac
- FixedDiv (10*FRACUNIT
,attackrange
);
1062 x
= trace
.x
+ FixedMul (trace
.dx
, frac
);
1063 y
= trace
.y
+ FixedMul (trace
.dy
, frac
);
1064 z
= shootz
+ FixedMul (aimslope
, FixedMul(frac
, attackrange
));
1066 // Spawn bullet puffs or blod spots,
1067 // depending on target type.
1068 if (in
->d
.thing
->flags
& MF_NOBLOOD
)
1069 P_SpawnPuff (x
,y
,z
);
1071 P_SpawnBlood (x
,y
,z
, la_damage
);
1074 P_DamageMobj (th
, shootthing
, shootthing
, la_damage
);
1076 // don't go any farther
1094 t1
= P_SubstNullMobj(t1
);
1096 angle
>>= ANGLETOFINESHIFT
;
1099 x2
= t1
->x
+ (distance
>>FRACBITS
)*finecosine
[angle
];
1100 y2
= t1
->y
+ (distance
>>FRACBITS
)*finesine
[angle
];
1101 shootz
= t1
->z
+ (t1
->height
>>1) + 8*FRACUNIT
;
1103 // can't shoot outside view angles
1104 topslope
= 100*FRACUNIT
/160;
1105 bottomslope
= -100*FRACUNIT
/160;
1107 attackrange
= distance
;
1110 P_PathTraverse ( t1
->x
, t1
->y
,
1112 PT_ADDLINES
|PT_ADDTHINGS
,
1124 // If damage == 0, it is just a test trace
1125 // that will leave linetarget set.
1138 angle
>>= ANGLETOFINESHIFT
;
1141 x2
= t1
->x
+ (distance
>>FRACBITS
)*finecosine
[angle
];
1142 y2
= t1
->y
+ (distance
>>FRACBITS
)*finesine
[angle
];
1143 shootz
= t1
->z
+ (t1
->height
>>1) + 8*FRACUNIT
;
1144 attackrange
= distance
;
1147 P_PathTraverse ( t1
->x
, t1
->y
,
1149 PT_ADDLINES
|PT_ADDTHINGS
,
1150 PTR_ShootTraverse
);
1160 boolean
PTR_UseTraverse (intercept_t
* in
)
1164 if (!in
->d
.line
->special
)
1166 P_LineOpening (in
->d
.line
);
1169 S_StartSound (usething
, sfx_noway
);
1171 // can't use through a wall
1174 // not a special line, but keep checking
1179 if (P_PointOnLineSide (usething
->x
, usething
->y
, in
->d
.line
) == 1)
1182 // return false; // don't use back side
1184 P_UseSpecialLine (usething
, in
->d
.line
, side
);
1186 // can't use for than one special line in a row
1193 // Looks for special lines in front of the player to activate.
1195 void P_UseLines (player_t
* player
)
1203 usething
= player
->mo
;
1205 angle
= player
->mo
->angle
>> ANGLETOFINESHIFT
;
1209 x2
= x1
+ (USERANGE
>>FRACBITS
)*finecosine
[angle
];
1210 y2
= y1
+ (USERANGE
>>FRACBITS
)*finesine
[angle
];
1212 P_PathTraverse ( x1
, y1
, x2
, y2
, PT_ADDLINES
, PTR_UseTraverse
);
1226 // "bombsource" is the creature
1227 // that caused the explosion at "bombspot".
1229 boolean
PIT_RadiusAttack (mobj_t
* thing
)
1235 if (!(thing
->flags
& MF_SHOOTABLE
) )
1238 // Boss spider and cyborg
1239 // take no damage from concussion.
1240 if (thing
->type
== MT_CYBORG
1241 || thing
->type
== MT_SPIDER
)
1244 dx
= abs(thing
->x
- bombspot
->x
);
1245 dy
= abs(thing
->y
- bombspot
->y
);
1247 dist
= dx
>dy
? dx
: dy
;
1248 dist
= (dist
- thing
->radius
) >> FRACBITS
;
1253 if (dist
>= bombdamage
)
1254 return true; // out of range
1256 if ( P_CheckSight (thing
, bombspot
) )
1258 // must be in direct path
1259 P_DamageMobj (thing
, bombspot
, bombsource
, bombdamage
- dist
);
1268 // Source is the creature that caused the explosion at spot.
1286 dist
= (damage
+MAXRADIUS
)<<FRACBITS
;
1287 yh
= (spot
->y
+ dist
- bmaporgy
)>>MAPBLOCKSHIFT
;
1288 yl
= (spot
->y
- dist
- bmaporgy
)>>MAPBLOCKSHIFT
;
1289 xh
= (spot
->x
+ dist
- bmaporgx
)>>MAPBLOCKSHIFT
;
1290 xl
= (spot
->x
- dist
- bmaporgx
)>>MAPBLOCKSHIFT
;
1292 bombsource
= source
;
1293 bombdamage
= damage
;
1295 for (y
=yl
; y
<=yh
; y
++)
1296 for (x
=xl
; x
<=xh
; x
++)
1297 P_BlockThingsIterator (x
, y
, PIT_RadiusAttack
);
1303 // SECTOR HEIGHT CHANGING
1304 // After modifying a sectors floor or ceiling height,
1305 // call this routine to adjust the positions
1306 // of all things that touch the sector.
1308 // If anything doesn't fit anymore, true will be returned.
1309 // If crunch is true, they will take damage
1310 // as they are being crushed.
1311 // If Crunch is false, you should set the sector height back
1312 // the way it was and call P_ChangeSector again
1313 // to undo the changes.
1315 boolean crushchange
;
1322 boolean
PIT_ChangeSector (mobj_t
* thing
)
1326 if (P_ThingHeightClip (thing
))
1333 // crunch bodies to giblets
1334 if (thing
->health
<= 0)
1336 P_SetMobjState (thing
, S_GIBS
);
1338 thing
->flags
&= ~MF_SOLID
;
1346 // crunch dropped items
1347 if (thing
->flags
& MF_DROPPED
)
1349 P_RemoveMobj (thing
);
1355 if (! (thing
->flags
& MF_SHOOTABLE
) )
1357 // assume it is bloody gibs or something
1363 if (crushchange
&& !(leveltime
&3) )
1365 P_DamageMobj(thing
,NULL
,NULL
,10);
1367 // spray blood in a random direction
1368 mo
= P_SpawnMobj (thing
->x
,
1370 thing
->z
+ thing
->height
/2, MT_BLOOD
);
1372 mo
->momx
= (P_Random() - P_Random ())<<12;
1373 mo
->momy
= (P_Random() - P_Random ())<<12;
1376 // keep checking (crush other things)
1394 crushchange
= crunch
;
1396 // re-check heights for all things near the moving sector
1397 for (x
=sector
->blockbox
[BOXLEFT
] ; x
<= sector
->blockbox
[BOXRIGHT
] ; x
++)
1398 for (y
=sector
->blockbox
[BOXBOTTOM
];y
<= sector
->blockbox
[BOXTOP
] ; y
++)
1399 P_BlockThingsIterator (x
, y
, PIT_ChangeSector
);
1405 // Code to emulate the behavior of Vanilla Doom when encountering an overrun
1406 // of the spechit array. This is by Andrey Budko (e6y) and comes from his
1407 // PrBoom plus port. A big thanks to Andrey for this.
1409 static void SpechitOverrun(line_t
*ld
)
1411 static unsigned int baseaddr
= 0;
1418 // This is the first time we have had an overrun. Work out
1419 // what base address we are going to use.
1420 // Allow a spechit value to be specified on the command line.
1426 // Use the specified magic value when emulating spechit overruns.
1429 p
= M_CheckParm("-spechit");
1433 M_StrToInt(myargv
[p
+1], (int *) &baseaddr
);
1437 baseaddr
= DEFAULT_SPECHIT_MAGIC
;
1441 // Calculate address used in doom2.exe
1443 addr
= baseaddr
+ (ld
- lines
) * 0x3E;
1451 tmbbox
[numspechit
-9] = addr
;
1460 fprintf(stderr
, "SpechitOverrun: Warning: unable to emulate"
1461 "an overrun where numspechit=%i\n",