fix remapping behavior. Remapping is only necessary if we are rendering on the workbe...
[AROS-Contrib.git] / Games / Doom / p_map.c
blob860b1b9003a3bf133bb9217e984ff5b0d92b5156
1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15 // for more details.
17 // $Log$
18 // Revision 1.1 2000/02/29 18:21:04 stegerg
19 // Doom port based on ADoomPPC. Read README.AROS!
22 // DESCRIPTION:
23 // Movement, collision handling.
24 // Shooting and aiming.
26 //-----------------------------------------------------------------------------
28 static const char
29 rcsid[] = "$Id$";
31 #include <stdlib.h>
33 #include "m_bbox.h"
34 #include "m_random.h"
35 #include "i_system.h"
37 #include "doomdef.h"
38 #include "p_local.h"
40 #include "s_sound.h"
42 // State.
43 #include "doomstat.h"
44 #include "r_state.h"
45 // Data.
46 #include "sounds.h"
49 fixed_t tmbbox[4];
50 mobj_t* tmthing;
51 int tmflags;
52 fixed_t tmx;
53 fixed_t tmy;
56 // If "floatok" true, move would be ok
57 // if within "tmfloorz - tmceilingz".
58 boolean floatok;
60 fixed_t tmfloorz;
61 fixed_t tmceilingz;
62 fixed_t tmdropoffz;
64 // keep track of the line that lowers the ceiling,
65 // so missiles don't explode against sky hack walls
66 line_t* ceilingline;
68 // keep track of special lines as they are hit,
69 // but don't process them until the move is proven valid
70 #define MAXSPECIALCROSS 20 /* was 8 */
72 line_t* spechit[MAXSPECIALCROSS];
73 int numspechit = 0;
78 // TELEPORT MOVE
79 //
82 // PIT_StompThing
84 boolean PIT_StompThing (mobj_t* thing)
86 fixed_t blockdist;
88 if (!(thing->flags & MF_SHOOTABLE) )
89 return true;
91 blockdist = thing->radius + tmthing->radius;
93 if ( iabs(thing->x - tmx) >= blockdist
94 || iabs(thing->y - tmy) >= blockdist )
96 // didn't hit it
97 return true;
100 // don't clip against self
101 if (thing == tmthing)
102 return true;
104 // monsters don't stomp things except on boss level
105 if ( !tmthing->player && gamemap != 30)
106 return false;
108 P_DamageMobj (thing, tmthing, tmthing, 10000);
110 return true;
115 // P_TeleportMove
117 boolean
118 P_TeleportMove
119 ( mobj_t* thing,
120 fixed_t x,
121 fixed_t y )
123 int xl;
124 int xh;
125 int yl;
126 int yh;
127 int bx;
128 int by;
130 subsector_t* newsubsec;
132 // kill anything occupying the position
133 tmthing = thing;
134 tmflags = thing->flags;
136 tmx = x;
137 tmy = y;
139 tmbbox[BOXTOP] = y + tmthing->radius;
140 tmbbox[BOXBOTTOM] = y - tmthing->radius;
141 tmbbox[BOXRIGHT] = x + tmthing->radius;
142 tmbbox[BOXLEFT] = x - tmthing->radius;
144 newsubsec = R_PointInSubsector (x,y);
145 ceilingline = NULL;
147 // The base floor/ceiling is from the subsector
148 // that contains the point.
149 // Any contacted lines the step closer together
150 // will adjust them.
151 tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
152 tmceilingz = newsubsec->sector->ceilingheight;
154 validcount++;
155 numspechit = 0;
157 // stomp on any things contacted
158 xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
159 xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
160 yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
161 yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
163 for (bx=xl ; bx<=xh ; bx++)
164 for (by=yl ; by<=yh ; by++)
165 if (!P_BlockThingsIterator(bx,by,PIT_StompThing))
166 return false;
168 // the move is ok,
169 // so link the thing into its new position
170 P_UnsetThingPosition (thing);
172 thing->floorz = tmfloorz;
173 thing->ceilingz = tmceilingz;
174 thing->x = x;
175 thing->y = y;
177 P_SetThingPosition (thing);
179 return true;
184 // MOVEMENT ITERATOR FUNCTIONS
189 // PIT_CheckLine
190 // Adjusts tmfloorz and tmceilingz as lines are contacted
192 boolean PIT_CheckLine (line_t* ld)
194 if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
195 || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
196 || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
197 || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP] )
198 return true;
200 if (P_BoxOnLineSide (tmbbox, ld) != -1)
201 return true;
203 // A line has been hit
205 // The moving thing's destination position will cross
206 // the given line.
207 // If this should not be allowed, return false.
208 // If the line is special, keep track of it
209 // to process later if the move is proven ok.
210 // NOTE: specials are NOT sorted by order,
211 // so two special lines that are only 8 pixels apart
212 // could be crossed in either order.
214 if (!ld->backsector)
215 return false; // one sided line
217 if (!(tmthing->flags & MF_MISSILE) )
219 if ( ld->flags & ML_BLOCKING )
220 return false; // explicitly blocking everything
222 if ( !tmthing->player && ld->flags & ML_BLOCKMONSTERS )
223 return false; // block monsters only
226 // set openrange, opentop, openbottom
227 P_LineOpening (ld);
229 // adjust floor / ceiling heights
230 if (opentop < tmceilingz)
232 tmceilingz = opentop;
233 ceilingline = ld;
236 if (openbottom > tmfloorz)
237 tmfloorz = openbottom;
239 if (lowfloor < tmdropoffz)
240 tmdropoffz = lowfloor;
242 // if contacted a special line, add it to the list
243 if (ld->special /* && numspechit < MAXSPECIALCROSS */ )
245 spechit[numspechit] = ld;
246 numspechit++;
249 return true;
253 // PIT_CheckThing
255 boolean PIT_CheckThing (mobj_t* thing)
257 fixed_t blockdist;
258 boolean solid;
259 int damage;
261 if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE) ))
262 return true;
264 blockdist = thing->radius + tmthing->radius;
266 if ( iabs(thing->x - tmx) >= blockdist
267 || iabs(thing->y - tmy) >= blockdist )
269 // didn't hit it
270 return true;
273 // don't clip against self
274 if (thing == tmthing)
275 return true;
277 // check for skulls slamming into things
278 if (tmthing->flags & MF_SKULLFLY)
280 damage = ((P_Random()%8)+1)*tmthing->info->damage;
282 P_DamageMobj (thing, tmthing, tmthing, damage);
284 tmthing->flags &= ~MF_SKULLFLY;
285 tmthing->momx = tmthing->momy = tmthing->momz = 0;
287 P_SetMobjState (tmthing, tmthing->info->spawnstate);
289 return false; // stop moving
293 // missiles can hit other things
294 if (tmthing->flags & MF_MISSILE)
296 // see if it went over / under
297 if (tmthing->z > thing->z + thing->height)
298 return true; // overhead
299 if (tmthing->z+tmthing->height < thing->z)
300 return true; // underneath
302 if (tmthing->target && (
303 tmthing->target->type == thing->type ||
304 (tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER)||
305 (tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT) ) )
307 // Don't hit same species as originator.
308 if (thing == tmthing->target)
309 return true;
311 if (thing->type != MT_PLAYER)
313 // Explode, but do no damage.
314 // Let players missile other players.
315 return false;
319 if (! (thing->flags & MF_SHOOTABLE) )
321 // didn't do any damage
322 return !(thing->flags & MF_SOLID);
325 // damage / explode
326 damage = ((P_Random()%8)+1)*tmthing->info->damage;
327 P_DamageMobj (thing, tmthing, tmthing->target, damage);
329 // don't traverse any more
330 return false;
333 // check for special pickup
334 if (thing->flags & MF_SPECIAL)
336 solid = thing->flags&MF_SOLID;
337 if (tmflags&MF_PICKUP)
339 // can remove thing
340 P_TouchSpecialThing (thing, tmthing);
342 return !solid;
345 return !(thing->flags & MF_SOLID);
350 // MOVEMENT CLIPPING
354 // P_CheckPosition
355 // This is purely informative, nothing is modified
356 // (except things picked up).
358 // in:
359 // a mobj_t (can be valid or invalid)
360 // a position to be checked
361 // (doesn't need to be related to the mobj_t->x,y)
363 // during:
364 // special things are touched if MF_PICKUP
365 // early out on solid lines?
367 // out:
368 // newsubsec
369 // floorz
370 // ceilingz
371 // tmdropoffz
372 // the lowest point contacted
373 // (monsters won't move to a dropoff)
374 // speciallines[]
375 // numspeciallines
377 boolean
378 P_CheckPosition
379 ( mobj_t* thing,
380 fixed_t x,
381 fixed_t y )
383 int xl;
384 int xh;
385 int yl;
386 int yh;
387 int bx;
388 int by;
389 subsector_t* newsubsec;
391 tmthing = thing;
392 tmflags = thing->flags;
394 tmx = x;
395 tmy = y;
397 tmbbox[BOXTOP] = y + tmthing->radius;
398 tmbbox[BOXBOTTOM] = y - tmthing->radius;
399 tmbbox[BOXRIGHT] = x + tmthing->radius;
400 tmbbox[BOXLEFT] = x - tmthing->radius;
402 newsubsec = R_PointInSubsector (x,y);
403 ceilingline = NULL;
405 // The base floor / ceiling is from the subsector
406 // that contains the point.
407 // Any contacted lines the step closer together
408 // will adjust them.
409 tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
410 tmceilingz = newsubsec->sector->ceilingheight;
412 validcount++;
413 numspechit = 0;
415 if ( tmflags & MF_NOCLIP )
416 return true;
418 // Check things first, possibly picking things up.
419 // The bounding box is extended by MAXRADIUS
420 // because mobj_ts are grouped into mapblocks
421 // based on their origin point, and can overlap
422 // into adjacent blocks by up to MAXRADIUS units.
423 xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
424 xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
425 yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
426 yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
428 for (bx=xl ; bx<=xh ; bx++)
429 for (by=yl ; by<=yh ; by++)
430 if (!P_BlockThingsIterator(bx,by,PIT_CheckThing))
431 return false;
433 // check lines
434 xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
435 xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
436 yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
437 yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
439 for (bx=xl ; bx<=xh ; bx++)
440 for (by=yl ; by<=yh ; by++)
441 if (!P_BlockLinesIterator (bx,by,PIT_CheckLine))
442 return false;
444 return true;
449 // P_TryMove
450 // Attempt to move to a new position,
451 // crossing special lines unless MF_TELEPORT is set.
453 boolean
454 P_TryMove
455 ( mobj_t* thing,
456 fixed_t x,
457 fixed_t y )
459 fixed_t oldx;
460 fixed_t oldy;
461 int side;
462 int oldside;
463 line_t* ld;
465 floatok = false;
466 if (!P_CheckPosition (thing, x, y))
467 return false; // solid wall or thing
469 if ( !(thing->flags & MF_NOCLIP) )
471 if (tmceilingz - tmfloorz < thing->height)
472 return false; // doesn't fit
474 floatok = true;
476 if ( !(thing->flags&MF_TELEPORT)
477 &&tmceilingz - thing->z < thing->height)
478 return false; // mobj must lower itself to fit
480 if ( !(thing->flags&MF_TELEPORT)
481 && tmfloorz - thing->z > 24*FRACUNIT )
482 return false; // too big a step up
484 if ( !(thing->flags&(MF_DROPOFF|MF_FLOAT))
485 && tmfloorz - tmdropoffz > 24*FRACUNIT )
486 return false; // don't stand over a dropoff
489 // the move is ok,
490 // so link the thing into its new position
491 P_UnsetThingPosition (thing);
493 oldx = thing->x;
494 oldy = thing->y;
495 thing->floorz = tmfloorz;
496 thing->ceilingz = tmceilingz;
497 thing->x = x;
498 thing->y = y;
500 P_SetThingPosition (thing);
502 // if any special lines were hit, do the effect
503 if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) )
505 while (numspechit--)
507 // see if the line was crossed
508 ld = spechit[numspechit];
509 side = P_PointOnLineSide (thing->x, thing->y, ld);
510 oldside = P_PointOnLineSide (oldx, oldy, ld);
511 if (side != oldside)
513 if (ld->special)
514 P_CrossSpecialLine (ld-lines, oldside, thing);
519 return true;
524 // P_ThingHeightClip
525 // Takes a valid thing and adjusts the thing->floorz,
526 // thing->ceilingz, and possibly thing->z.
527 // This is called for all nearby monsters
528 // whenever a sector changes height.
529 // If the thing doesn't fit,
530 // the z will be set to the lowest value
531 // and false will be returned.
533 boolean P_ThingHeightClip (mobj_t* thing)
535 boolean onfloor;
537 onfloor = (thing->z == thing->floorz);
539 P_CheckPosition (thing, thing->x, thing->y);
540 // what about stranding a monster partially off an edge?
542 thing->floorz = tmfloorz;
543 thing->ceilingz = tmceilingz;
545 if (onfloor)
547 // walking monsters rise and fall with the floor
548 thing->z = thing->floorz;
550 else
552 // don't adjust a floating monster unless forced to
553 if (thing->z+thing->height > thing->ceilingz)
554 thing->z = thing->ceilingz - thing->height;
557 if (thing->ceilingz - thing->floorz < thing->height)
558 return false;
560 return true;
566 // SLIDE MOVE
567 // Allows the player to slide along any angled walls.
569 fixed_t bestslidefrac;
570 fixed_t secondslidefrac;
572 line_t* bestslideline;
573 line_t* secondslideline;
575 mobj_t* slidemo;
577 fixed_t tmxmove;
578 fixed_t tmymove;
583 // P_HitSlideLine
584 // Adjusts the xmove / ymove
585 // so that the next move will slide along the wall.
587 void P_HitSlideLine (line_t* ld)
589 int side;
591 angle_t lineangle;
592 angle_t moveangle;
593 angle_t deltaangle;
595 fixed_t movelen;
596 fixed_t newlen;
599 if (ld->slopetype == ST_HORIZONTAL)
601 tmymove = 0;
602 return;
605 if (ld->slopetype == ST_VERTICAL)
607 tmxmove = 0;
608 return;
611 side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
613 lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy);
615 if (side == 1)
616 lineangle += ANG180;
618 moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove);
619 deltaangle = moveangle-lineangle;
621 if (deltaangle > ANG180)
622 deltaangle += ANG180;
623 // I_Error ("SlideLine: ang>ANG180");
625 lineangle >>= ANGLETOFINESHIFT;
626 deltaangle >>= ANGLETOFINESHIFT;
628 movelen = P_AproxDistance (tmxmove, tmymove);
629 newlen = FixedMul (movelen, finecosine[deltaangle]);
631 tmxmove = FixedMul (newlen, finecosine[lineangle]);
632 tmymove = FixedMul (newlen, finesine[lineangle]);
637 // PTR_SlideTraverse
639 boolean PTR_SlideTraverse (intercept_t* in)
641 line_t* li;
643 if (!in->isaline)
644 I_Error ("PTR_SlideTraverse: not a line?");
646 li = in->d.line;
648 if ( ! (li->flags & ML_TWOSIDED) )
650 if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
652 // don't hit the back side
653 return true;
655 goto isblocking;
658 // set openrange, opentop, openbottom
659 P_LineOpening (li);
661 if (openrange < slidemo->height)
662 goto isblocking; // doesn't fit
664 if (opentop - slidemo->z < slidemo->height)
665 goto isblocking; // mobj is too high
667 if (openbottom - slidemo->z > 24*FRACUNIT )
668 goto isblocking; // too big a step up
670 // this line doesn't block movement
671 return true;
673 // the line does block movement,
674 // see if it is closer than best so far
675 isblocking:
676 if (in->frac < bestslidefrac)
678 secondslidefrac = bestslidefrac;
679 secondslideline = bestslideline;
680 bestslidefrac = in->frac;
681 bestslideline = li;
684 return false; // stop
690 // P_SlideMove
691 // The momx / momy move is bad, so try to slide
692 // along a wall.
693 // Find the first line hit, move flush to it,
694 // and slide along it
696 // This is a kludgy mess.
698 void P_SlideMove (mobj_t* mo)
700 fixed_t leadx;
701 fixed_t leady;
702 fixed_t trailx;
703 fixed_t traily;
704 fixed_t newx;
705 fixed_t newy;
706 int hitcount;
708 slidemo = mo;
709 hitcount = 0;
711 retry:
712 if (++hitcount == 3)
713 goto stairstep; // don't loop forever
716 // trace along the three leading corners
717 if (mo->momx > 0)
719 leadx = mo->x + mo->radius;
720 trailx = mo->x - mo->radius;
722 else
724 leadx = mo->x - mo->radius;
725 trailx = mo->x + mo->radius;
728 if (mo->momy > 0)
730 leady = mo->y + mo->radius;
731 traily = mo->y - mo->radius;
733 else
735 leady = mo->y - mo->radius;
736 traily = mo->y + mo->radius;
739 bestslidefrac = FRACUNIT+1;
741 P_PathTraverse ( leadx, leady, leadx+mo->momx, leady+mo->momy,
742 PT_ADDLINES, PTR_SlideTraverse );
743 P_PathTraverse ( trailx, leady, trailx+mo->momx, leady+mo->momy,
744 PT_ADDLINES, PTR_SlideTraverse );
745 P_PathTraverse ( leadx, traily, leadx+mo->momx, traily+mo->momy,
746 PT_ADDLINES, PTR_SlideTraverse );
748 // move up to the wall
749 if (bestslidefrac == FRACUNIT+1)
751 // the move most have hit the middle, so stairstep
752 stairstep:
753 if (!P_TryMove (mo, mo->x, mo->y + mo->momy))
754 P_TryMove (mo, mo->x + mo->momx, mo->y);
755 return;
758 // fudge a bit to make sure it doesn't hit
759 bestslidefrac -= 0x800;
760 if (bestslidefrac > 0)
762 newx = FixedMul (mo->momx, bestslidefrac);
763 newy = FixedMul (mo->momy, bestslidefrac);
765 if (!P_TryMove (mo, mo->x+newx, mo->y+newy))
766 goto stairstep;
769 // Now continue along the wall.
770 // First calculate remainder.
771 bestslidefrac = FRACUNIT-(bestslidefrac+0x800);
773 if (bestslidefrac > FRACUNIT)
774 bestslidefrac = FRACUNIT;
776 if (bestslidefrac <= 0)
777 return;
779 tmxmove = FixedMul (mo->momx, bestslidefrac);
780 tmymove = FixedMul (mo->momy, bestslidefrac);
782 P_HitSlideLine (bestslideline); // clip the moves
784 mo->momx = tmxmove;
785 mo->momy = tmymove;
787 if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove))
789 goto retry;
795 // P_LineAttack
797 mobj_t* linetarget; // who got hit (or NULL)
798 mobj_t* shootthing;
800 // Height if not aiming up or down
801 // ???: use slope for monsters?
802 fixed_t shootz;
804 int la_damage;
805 fixed_t attackrange;
807 fixed_t aimslope;
809 // slopes to top and bottom of target
810 extern fixed_t topslope;
811 extern fixed_t bottomslope;
815 // PTR_AimTraverse
816 // Sets linetaget and aimslope when a target is aimed at.
818 boolean
819 PTR_AimTraverse (intercept_t* in)
821 line_t* li;
822 mobj_t* th;
823 fixed_t slope;
824 fixed_t thingtopslope;
825 fixed_t thingbottomslope;
826 fixed_t dist;
828 if (in->isaline)
830 li = in->d.line;
832 if ( !(li->flags & ML_TWOSIDED) )
833 return false; // stop
835 // Crosses a two sided line.
836 // A two sided line will restrict
837 // the possible target ranges.
838 P_LineOpening (li);
840 if (openbottom >= opentop)
841 return false; // stop
843 dist = FixedMul (attackrange, in->frac);
845 if (li->frontsector->floorheight != li->backsector->floorheight)
847 slope = FixedDiv (openbottom - shootz , dist);
848 if (slope > bottomslope)
849 bottomslope = slope;
852 if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
854 slope = FixedDiv (opentop - shootz , dist);
855 if (slope < topslope)
856 topslope = slope;
859 if (topslope <= bottomslope)
860 return false; // stop
862 return true; // shot continues
865 // shoot a thing
866 th = in->d.thing;
867 if (th == shootthing)
868 return true; // can't shoot self
870 if (!(th->flags&MF_SHOOTABLE))
871 return true; // corpse or something
873 // check angles to see if the thing can be aimed at
874 dist = FixedMul (attackrange, in->frac);
875 thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
877 if (thingtopslope < bottomslope)
878 return true; // shot over the thing
880 thingbottomslope = FixedDiv (th->z - shootz, dist);
882 if (thingbottomslope > topslope)
883 return true; // shot under the thing
885 // this thing can be hit!
886 if (thingtopslope > topslope)
887 thingtopslope = topslope;
889 if (thingbottomslope < bottomslope)
890 thingbottomslope = bottomslope;
892 aimslope = (thingtopslope+thingbottomslope)/2;
893 linetarget = th;
895 return false; // don't go any farther
900 // PTR_ShootTraverse
902 boolean PTR_ShootTraverse (intercept_t* in)
904 fixed_t x;
905 fixed_t y;
906 fixed_t z;
907 fixed_t frac;
909 line_t* li;
911 mobj_t* th;
913 fixed_t slope;
914 fixed_t dist;
915 fixed_t thingtopslope;
916 fixed_t thingbottomslope;
918 if (in->isaline)
920 li = in->d.line;
922 if (li->special)
923 P_ShootSpecialLine (shootthing, li);
925 if ( !(li->flags & ML_TWOSIDED) )
926 goto hitline;
928 // crosses a two sided line
929 P_LineOpening (li);
931 dist = FixedMul (attackrange, in->frac);
933 if (li->frontsector->floorheight != li->backsector->floorheight)
935 slope = FixedDiv (openbottom - shootz , dist);
936 if (slope > aimslope)
937 goto hitline;
940 if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
942 slope = FixedDiv (opentop - shootz , dist);
943 if (slope < aimslope)
944 goto hitline;
947 // shot continues
948 return true;
951 // hit line
952 hitline:
953 // position a bit closer
954 frac = in->frac - FixedDiv (4*FRACUNIT,attackrange);
955 x = trace.x + FixedMul (trace.dx, frac);
956 y = trace.y + FixedMul (trace.dy, frac);
957 z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
959 if (li->frontsector->ceilingpic == skyflatnum)
961 // don't shoot the sky!
962 if (z > li->frontsector->ceilingheight)
963 return false;
965 // it's a sky hack wall
966 if (li->backsector && li->backsector->ceilingpic == skyflatnum)
967 return false;
970 // Spawn bullet puffs.
971 P_SpawnPuff (x,y,z);
973 // don't go any farther
974 return false;
977 // shoot a thing
978 th = in->d.thing;
979 if (th == shootthing)
980 return true; // can't shoot self
982 if (!(th->flags&MF_SHOOTABLE))
983 return true; // corpse or something
985 // check angles to see if the thing can be aimed at
986 dist = FixedMul (attackrange, in->frac);
987 thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
989 if (thingtopslope < aimslope)
990 return true; // shot over the thing
992 thingbottomslope = FixedDiv (th->z - shootz, dist);
994 if (thingbottomslope > aimslope)
995 return true; // shot under the thing
998 // hit thing
999 // position a bit closer
1000 frac = in->frac - FixedDiv (10*FRACUNIT,attackrange);
1002 x = trace.x + FixedMul (trace.dx, frac);
1003 y = trace.y + FixedMul (trace.dy, frac);
1004 z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
1006 // Spawn bullet puffs or blod spots,
1007 // depending on target type.
1008 if (in->d.thing->flags & MF_NOBLOOD)
1009 P_SpawnPuff (x,y,z);
1010 else
1011 P_SpawnBlood (x,y,z, la_damage);
1013 if (la_damage)
1014 P_DamageMobj (th, shootthing, shootthing, la_damage);
1016 // don't go any farther
1017 return false;
1023 // P_AimLineAttack
1025 fixed_t
1026 P_AimLineAttack
1027 ( mobj_t* t1,
1028 angle_t angle,
1029 fixed_t distance )
1031 fixed_t x2;
1032 fixed_t y2;
1034 angle >>= ANGLETOFINESHIFT;
1035 shootthing = t1;
1037 x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
1038 y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
1039 shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
1041 // can't shoot outside view angles
1042 topslope = 100*FRACUNIT/160;
1043 bottomslope = -100*FRACUNIT/160;
1045 attackrange = distance;
1046 linetarget = NULL;
1048 P_PathTraverse ( t1->x, t1->y,
1049 x2, y2,
1050 PT_ADDLINES|PT_ADDTHINGS,
1051 PTR_AimTraverse );
1053 if (linetarget)
1054 return aimslope;
1056 return 0;
1061 // P_LineAttack
1062 // If damage == 0, it is just a test trace
1063 // that will leave linetarget set.
1065 void
1066 P_LineAttack
1067 ( mobj_t* t1,
1068 angle_t angle,
1069 fixed_t distance,
1070 fixed_t slope,
1071 int damage )
1073 fixed_t x2;
1074 fixed_t y2;
1076 angle >>= ANGLETOFINESHIFT;
1077 shootthing = t1;
1078 la_damage = damage;
1079 x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
1080 y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
1081 shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
1082 attackrange = distance;
1083 aimslope = slope;
1085 P_PathTraverse ( t1->x, t1->y,
1086 x2, y2,
1087 PT_ADDLINES|PT_ADDTHINGS,
1088 PTR_ShootTraverse );
1094 // USE LINES
1096 mobj_t* usething;
1098 boolean PTR_UseTraverse (intercept_t* in)
1100 int side;
1102 if (!in->d.line->special)
1104 P_LineOpening (in->d.line);
1105 if (openrange <= 0)
1107 S_StartSound (usething, sfx_noway);
1109 // can't use through a wall
1110 return false;
1112 // not a special line, but keep checking
1113 return true ;
1116 side = 0;
1117 if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
1118 side = 1;
1120 // return false; // don't use back side
1122 P_UseSpecialLine (usething, in->d.line, side);
1124 // can't use for than one special line in a row
1125 return false;
1130 // P_UseLines
1131 // Looks for special lines in front of the player to activate.
1133 void P_UseLines (player_t* player)
1135 int angle;
1136 fixed_t x1;
1137 fixed_t y1;
1138 fixed_t x2;
1139 fixed_t y2;
1141 usething = player->mo;
1143 angle = player->mo->angle >> ANGLETOFINESHIFT;
1145 x1 = player->mo->x;
1146 y1 = player->mo->y;
1147 x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
1148 y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
1150 P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
1155 // RADIUS ATTACK
1157 mobj_t* bombsource;
1158 mobj_t* bombspot;
1159 int bombdamage;
1163 // PIT_RadiusAttack
1164 // "bombsource" is the creature
1165 // that caused the explosion at "bombspot".
1167 boolean PIT_RadiusAttack (mobj_t* thing)
1169 fixed_t dx;
1170 fixed_t dy;
1171 fixed_t dist;
1173 if (!(thing->flags & MF_SHOOTABLE) )
1174 return true;
1176 // Boss spider and cyborg
1177 // take no damage from concussion.
1178 if (thing->type == MT_CYBORG
1179 || thing->type == MT_SPIDER)
1180 return true;
1182 dx = iabs(thing->x - bombspot->x);
1183 dy = iabs(thing->y - bombspot->y);
1185 dist = dx>dy ? dx : dy;
1186 dist = (dist - thing->radius) >> FRACBITS;
1188 if (dist < 0)
1189 dist = 0;
1191 if (dist >= bombdamage)
1192 return true; // out of range
1194 if ( P_CheckSight (thing, bombspot) )
1196 // must be in direct path
1197 P_DamageMobj (thing, bombspot, bombsource, bombdamage - dist);
1200 return true;
1205 // P_RadiusAttack
1206 // Source is the creature that caused the explosion at spot.
1208 void
1209 P_RadiusAttack
1210 ( mobj_t* spot,
1211 mobj_t* source,
1212 int damage )
1214 int x;
1215 int y;
1217 int xl;
1218 int xh;
1219 int yl;
1220 int yh;
1222 fixed_t dist;
1224 dist = (damage+MAXRADIUS)<<FRACBITS;
1225 yh = (spot->y + dist - bmaporgy)>>MAPBLOCKSHIFT;
1226 yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT;
1227 xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT;
1228 xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT;
1229 bombspot = spot;
1230 bombsource = source;
1231 bombdamage = damage;
1233 for (y=yl ; y<=yh ; y++)
1234 for (x=xl ; x<=xh ; x++)
1235 P_BlockThingsIterator (x, y, PIT_RadiusAttack );
1241 // SECTOR HEIGHT CHANGING
1242 // After modifying a sectors floor or ceiling height,
1243 // call this routine to adjust the positions
1244 // of all things that touch the sector.
1246 // If anything doesn't fit anymore, true will be returned.
1247 // If crunch is true, they will take damage
1248 // as they are being crushed.
1249 // If Crunch is false, you should set the sector height back
1250 // the way it was and call P_ChangeSector again
1251 // to undo the changes.
1253 boolean crushchange;
1254 boolean nofit;
1258 // PIT_ChangeSector
1260 boolean PIT_ChangeSector (mobj_t* thing)
1262 mobj_t* mo;
1264 if (P_ThingHeightClip (thing))
1266 // keep checking
1267 return true;
1271 // crunch bodies to giblets
1272 if (thing->health <= 0)
1274 P_SetMobjState (thing, S_GIBS);
1276 thing->flags &= ~MF_SOLID;
1277 thing->height = 0;
1278 thing->radius = 0;
1280 // keep checking
1281 return true;
1284 // crunch dropped items
1285 if (thing->flags & MF_DROPPED)
1287 P_RemoveMobj (thing);
1289 // keep checking
1290 return true;
1293 if (! (thing->flags & MF_SHOOTABLE) )
1295 // assume it is bloody gibs or something
1296 return true;
1299 nofit = true;
1301 if (crushchange && !(leveltime&3) )
1303 P_DamageMobj(thing,NULL,NULL,10);
1305 // spray blood in a random direction
1306 mo = P_SpawnMobj (thing->x,
1307 thing->y,
1308 thing->z + thing->height/2, MT_BLOOD);
1310 mo->momx = (P_Random() - P_Random ())<<12;
1311 mo->momy = (P_Random() - P_Random ())<<12;
1314 // keep checking (crush other things)
1315 return true;
1321 // P_ChangeSector
1323 boolean
1324 P_ChangeSector
1325 ( sector_t* sector,
1326 boolean crunch )
1328 int x;
1329 int y;
1331 nofit = false;
1332 crushchange = crunch;
1334 // re-check heights for all things near the moving sector
1335 for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++)
1336 for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++)
1337 P_BlockThingsIterator (x, y, PIT_ChangeSector);
1340 return nofit;