9 ===============================================================================
14 ===============================================================================
18 ===============================================================================
22 mobj_ts are used to tell the refresh where to draw an image, tell the world simulation when objects are contacted, and tell the sound driver how to position a sound.
24 The refresh uses the next and prev links to follow lists of things in sectors as they are being drawn. The sprite, frame, and angle elements determine which patch_t is used to draw the sprite if it is visible. The sprite and frame values are allmost allways set from state_t structures. The statescr.exe utility generates the states.h and states.c files that contain the sprite/frame numbers from the statescr.txt source file. The xyz origin point represents a point at the bottom middle of the sprite (between the feet of a biped). This is the default origin position for patch_ts grabbed with lumpy.exe. A walking creature will have its z equal to the floor it is standing on.
26 The sound code uses the x,y, and subsector fields to do stereo positioning of any sound effited by the mobj_t.
28 The play simulation uses the blocklinks, x,y,z, radius, height to determine when mobj_ts are touching each other, touching lines in the map, or hit by trace lines (gunshots, lines of sight, etc). The mobj_t->flags element has various bit flags used by the simulation.
31 Every mobj_t is linked into a single sector based on it's origin coordinates.
32 The subsector_t is found with R_PointInSubsector(x,y), and the sector_t can be found with subsector->sector. The sector links are only used by the rendering code, the play simulation does not care about them at all.
34 Any mobj_t that needs to be acted upon be something else in the play world (block movement, be shot, etc) will also need to be linked into the blockmap. If the thing has the MF_NOBLOCK flag set, it will not use the block links. It can still interact with other things, but only as the instigator (missiles will run into other things, but nothing can run into a missile). Each block in the grid is 128*128 units, and knows about every line_t that it contains a piece of, and every interactable mobj_t that has it's origin contained.
36 A valid mobj_t is a mobj_t that has the proper subsector_t filled in for it's xy coordinates and is linked into the subsector's sector or has the MF_NOSECTOR flag set (the subsector_t needs to be valid even if MF_NOSECTOR is set), and is linked into a blockmap block or has the MF_NOBLOCKMAP flag set. Links should only be modified by the P_[Un]SetThingPosition () functions. Do not change the MF_NO? flags while a thing is valid.
39 ===============================================================================
47 boolean floatok; // if true, move would be ok if
48 // within tmfloorz - tmceilingz
50 fixed_t tmfloorz, tmceilingz, tmdropoffz;
52 // keep track of the line that lowers the ceiling, so missiles don't explode
53 // against sky hack walls
56 // keep track of special lines as they are hit, but don't process them
57 // until the move is proven valid
58 #define MAXSPECIALCROSS 8
59 line_t *spechit[MAXSPECIALCROSS];
62 mobj_t *onmobj; //generic global onmobj...used for landing on pods/players
65 ===============================================================================
69 ===============================================================================
80 boolean PIT_StompThing (mobj_t *thing)
84 if (!(thing->flags & MF_SHOOTABLE) )
87 blockdist = thing->radius + tmthing->radius;
88 if ( abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist )
89 return true; // didn't hit it
92 return true; // don't clip against self
94 if(!(tmthing->flags2&MF2_TELESTOMP))
95 { // Not allowed to stomp things
99 P_DamageMobj (thing, tmthing, tmthing, 10000);
113 boolean P_TeleportMove (mobj_t *thing, fixed_t x, fixed_t y)
115 int xl,xh,yl,yh,bx,by;
116 subsector_t *newsubsec;
119 // kill anything occupying the position
123 tmflags = thing->flags;
128 tmbbox[BOXTOP] = y + tmthing->radius;
129 tmbbox[BOXBOTTOM] = y - tmthing->radius;
130 tmbbox[BOXRIGHT] = x + tmthing->radius;
131 tmbbox[BOXLEFT] = x - tmthing->radius;
133 newsubsec = R_PointInSubsector (x,y);
137 // the base floor / ceiling is from the subsector that contains the
138 // point. Any contacted lines the step closer together will adjust them
140 tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
141 tmceilingz = newsubsec->sector->ceilingheight;
147 // stomp on any things contacted
149 xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
150 xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
151 yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
152 yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
154 for (bx=xl ; bx<=xh ; bx++)
155 for (by=yl ; by<=yh ; by++)
156 if (!P_BlockThingsIterator(bx,by,PIT_StompThing))
160 // the move is ok, so link the thing into its new position
162 P_UnsetThingPosition (thing);
164 thing->floorz = tmfloorz;
165 thing->ceilingz = tmceilingz;
169 P_SetThingPosition (thing);
175 ===============================================================================
177 MOVEMENT ITERATOR FUNCTIONS
179 ===============================================================================
187 = Adjusts tmfloorz and tmceilingz as lines are contacted
191 boolean PIT_CheckLine(line_t *ld)
193 if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
194 || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
195 || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
196 || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
200 if(P_BoxOnLineSide(tmbbox, ld) != -1)
205 // a line has been hit
208 = The moving thing's destination position will cross the given line.
209 = If this should not be allowed, return false.
210 = If the line is special, keep track of it to process later if the move
211 = is proven ok. NOTE: specials are NOT sorted by order, so two special lines
212 = that are only 8 pixels apart could be crossed in either order.
217 if(tmthing->flags&MF_MISSILE)
218 { // Missiles can trigger impact specials
221 spechit[numspechit] = ld;
227 if(!(tmthing->flags&MF_MISSILE))
229 if(ld->flags&ML_BLOCKING)
230 { // Explicitly blocking everything
233 if(!tmthing->player && ld->flags&ML_BLOCKMONSTERS
234 && tmthing->type != MT_POD)
235 { // Block monsters only
239 P_LineOpening(ld); // set openrange, opentop, openbottom
240 // adjust floor / ceiling heights
241 if(opentop < tmceilingz)
243 tmceilingz = opentop;
246 if(openbottom > tmfloorz)
248 tmfloorz = openbottom;
250 if(lowfloor < tmdropoffz)
252 tmdropoffz = lowfloor;
255 { // Contacted a special line, add it to the list
256 spechit[numspechit] = ld;
262 //---------------------------------------------------------------------------
264 // FUNC PIT_CheckThing
266 //---------------------------------------------------------------------------
268 boolean PIT_CheckThing(mobj_t *thing)
274 if(!(thing->flags&(MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
278 blockdist = thing->radius+tmthing->radius;
279 if(abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist)
280 { // Didn't hit thing
284 { // Don't clip against self
287 if(tmthing->flags2&MF2_PASSMOBJ)
288 { // check if a mobj passed over/under another object
289 if((tmthing->type == MT_IMP || tmthing->type == MT_WIZARD)
290 && (thing->type == MT_IMP || thing->type == MT_WIZARD))
291 { // don't let imps/wizards fly over other imps/wizards
294 if(tmthing->z > thing->z+thing->height
295 && !(thing->flags&MF_SPECIAL))
299 else if(tmthing->z+tmthing->height < thing->z
300 && !(thing->flags&MF_SPECIAL))
305 // Check for skulls slamming into things
306 if(tmthing->flags&MF_SKULLFLY)
308 damage = ((P_Random()%8)+1)*tmthing->damage;
309 P_DamageMobj(thing, tmthing, tmthing, damage);
310 tmthing->flags &= ~MF_SKULLFLY;
311 tmthing->momx = tmthing->momy = tmthing->momz = 0;
312 P_SetMobjState(tmthing, tmthing->info->seestate);
316 if(tmthing->flags&MF_MISSILE)
318 // Check for passing through a ghost
319 if((thing->flags&MF_SHADOW) && (tmthing->flags2&MF2_THRUGHOST))
323 // Check if it went over / under
324 if(tmthing->z > thing->z+thing->height)
328 if(tmthing->z+tmthing->height < thing->z)
332 if(tmthing->target && tmthing->target->type == thing->type)
333 { // Don't hit same species as originator
334 if(thing == tmthing->target)
335 { // Don't missile self
338 if(thing->type != MT_PLAYER)
339 { // Hit same species as originator, explode, no damage
343 if(!(thing->flags&MF_SHOOTABLE))
344 { // Didn't do any damage
345 return!(thing->flags&MF_SOLID);
347 if(tmthing->flags2&MF2_RIP)
349 if(!(thing->flags&MF_NOBLOOD))
350 { // Ok to spawn some blood
351 P_RipperBlood(tmthing);
353 S_StartSound(tmthing, sfx_ripslop);
354 damage = ((P_Random()&3)+2)*tmthing->damage;
355 P_DamageMobj(thing, tmthing, tmthing->target, damage);
356 if(thing->flags2&MF2_PUSHABLE
357 && !(tmthing->flags2&MF2_CANNOTPUSH))
359 thing->momx += tmthing->momx>>2;
360 thing->momy += tmthing->momy>>2;
366 damage = ((P_Random()%8)+1)*tmthing->damage;
369 if(!(thing->flags&MF_NOBLOOD) && P_Random() < 192)
371 P_BloodSplatter(tmthing->x, tmthing->y, tmthing->z, thing);
373 P_DamageMobj(thing, tmthing, tmthing->target, damage);
377 if(thing->flags2&MF2_PUSHABLE && !(tmthing->flags2&MF2_CANNOTPUSH))
379 thing->momx += tmthing->momx>>2;
380 thing->momy += tmthing->momy>>2;
382 // Check for special thing
383 if(thing->flags&MF_SPECIAL)
385 solid = thing->flags&MF_SOLID;
386 if(tmflags&MF_PICKUP)
387 { // Can be picked up by tmthing
388 P_TouchSpecialThing(thing, tmthing); // Can remove thing
392 return(!(thing->flags&MF_SOLID));
395 //---------------------------------------------------------------------------
399 //---------------------------------------------------------------------------
401 boolean PIT_CheckOnmobjZ(mobj_t *thing)
405 if(!(thing->flags&(MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
409 blockdist = thing->radius+tmthing->radius;
410 if(abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist)
411 { // Didn't hit thing
415 { // Don't clip against self
418 if(tmthing->z > thing->z+thing->height)
422 else if(tmthing->z+tmthing->height < thing->z)
426 if(thing->flags&MF_SOLID)
430 return(!(thing->flags&MF_SOLID));
434 ===============================================================================
438 ===============================================================================
441 //----------------------------------------------------------------------------
443 // FUNC P_TestMobjLocation
445 // Returns true if the mobj is not blocked by anything at its current
446 // location, otherwise returns false.
448 //----------------------------------------------------------------------------
450 boolean P_TestMobjLocation(mobj_t *mobj)
455 mobj->flags &= ~MF_PICKUP;
456 if(P_CheckPosition(mobj, mobj->x, mobj->y))
457 { // XY is ok, now check Z
459 if((mobj->z < mobj->floorz)
460 || (mobj->z+mobj->height > mobj->ceilingz))
475 = This is purely informative, nothing is modified (except things picked up)
478 a mobj_t (can be valid or invalid)
479 a position to be checked (doesn't need to be related to the mobj_t->x,y)
482 special things are touched if MF_PICKUP
483 early out on solid lines?
489 tmdropoffz the lowest point contacted (monsters won't move to a dropoff)
496 boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y)
498 int xl,xh,yl,yh,bx,by;
499 subsector_t *newsubsec;
502 tmflags = thing->flags;
507 tmbbox[BOXTOP] = y + tmthing->radius;
508 tmbbox[BOXBOTTOM] = y - tmthing->radius;
509 tmbbox[BOXRIGHT] = x + tmthing->radius;
510 tmbbox[BOXLEFT] = x - tmthing->radius;
512 newsubsec = R_PointInSubsector (x,y);
516 // the base floor / ceiling is from the subsector that contains the
517 // point. Any contacted lines the step closer together will adjust them
519 tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
520 tmceilingz = newsubsec->sector->ceilingheight;
525 if ( tmflags & MF_NOCLIP )
529 // check things first, possibly picking things up
530 // the bounding box is extended by MAXRADIUS because mobj_ts are grouped
531 // into mapblocks based on their origin point, and can overlap into adjacent
532 // blocks by up to MAXRADIUS units
534 xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
535 xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
536 yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
537 yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
539 for (bx=xl ; bx<=xh ; bx++)
540 for (by=yl ; by<=yh ; by++)
541 if (!P_BlockThingsIterator(bx,by,PIT_CheckThing))
546 xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
547 xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
548 yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
549 yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
551 for (bx=xl ; bx<=xh ; bx++)
552 for (by=yl ; by<=yh ; by++)
553 if (!P_BlockLinesIterator (bx,by,PIT_CheckLine))
559 //=============================================================================
561 // P_CheckOnmobj(mobj_t *thing)
563 // Checks if the new Z position is legal
564 //=============================================================================
566 mobj_t *P_CheckOnmobj(mobj_t *thing)
568 int xl,xh,yl,yh,bx,by;
569 subsector_t *newsubsec;
577 tmflags = thing->flags;
578 oldmo = *thing; // save the old mobj before the fake zmovement
579 P_FakeZMovement(tmthing);
584 tmbbox[BOXTOP] = y + tmthing->radius;
585 tmbbox[BOXBOTTOM] = y - tmthing->radius;
586 tmbbox[BOXRIGHT] = x + tmthing->radius;
587 tmbbox[BOXLEFT] = x - tmthing->radius;
589 newsubsec = R_PointInSubsector (x,y);
593 // the base floor / ceiling is from the subsector that contains the
594 // point. Any contacted lines the step closer together will adjust them
596 tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
597 tmceilingz = newsubsec->sector->ceilingheight;
602 if ( tmflags & MF_NOCLIP )
606 // check things first, possibly picking things up
607 // the bounding box is extended by MAXRADIUS because mobj_ts are grouped
608 // into mapblocks based on their origin point, and can overlap into adjacent
609 // blocks by up to MAXRADIUS units
611 xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
612 xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
613 yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
614 yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
616 for (bx=xl ; bx<=xh ; bx++)
617 for (by=yl ; by<=yh ; by++)
618 if (!P_BlockThingsIterator(bx,by,PIT_CheckOnmobjZ))
627 //=============================================================================
631 // Fake the zmovement so that we can check if a move is legal
632 //=============================================================================
634 void P_FakeZMovement(mobj_t *mo)
642 if(mo->flags&MF_FLOAT && mo->target)
643 { // float down towards target if too close
644 if(!(mo->flags&MF_SKULLFLY) && !(mo->flags&MF_INFLOAT))
646 dist = P_AproxDistance(mo->x-mo->target->x, mo->y-mo->target->y);
647 delta =( mo->target->z+(mo->height>>1))-mo->z;
648 if (delta < 0 && dist < -(delta*3))
650 else if (delta > 0 && dist < (delta*3))
654 if(mo->player && mo->flags2&MF2_FLY && !(mo->z <= mo->floorz)
657 mo->z += finesine[(FINEANGLES/20*leveltime>>2)&FINEMASK];
663 if(mo->z <= mo->floorz)
670 if(mo->flags&MF_SKULLFLY)
671 { // The skull slammed into something
672 mo->momz = -mo->momz;
674 if(mo->info->crashstate && (mo->flags&MF_CORPSE))
679 else if(mo->flags2&MF2_LOGRAV)
682 mo->momz = -(GRAVITY>>3)*2;
684 mo->momz -= GRAVITY>>3;
686 else if (! (mo->flags & MF_NOGRAVITY) )
689 mo->momz = -GRAVITY*2;
694 if (mo->z + mo->height > mo->ceilingz)
698 mo->z = mo->ceilingz - mo->height;
699 if (mo->flags & MF_SKULLFLY)
700 { // the skull slammed into something
701 mo->momz = -mo->momz;
706 //==========================================================================
708 // CheckMissileImpact
710 //==========================================================================
712 void CheckMissileImpact(mobj_t *mobj)
716 if(!numspechit || !(mobj->flags&MF_MISSILE) || !mobj->target)
720 if(!mobj->target->player)
724 for(i = numspechit-1; i >= 0; i--)
726 P_ShootSpecialLine(mobj->target, spechit[i]);
735 = Attempt to move to a new position, crossing special lines unless MF_TELEPORT
741 boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y)
748 if(!P_CheckPosition(thing, x, y))
749 { // Solid wall or thing
750 CheckMissileImpact(thing);
753 if(!(thing->flags&MF_NOCLIP))
755 if(tmceilingz-tmfloorz < thing->height)
757 CheckMissileImpact(thing);
761 if(!(thing->flags&MF_TELEPORT)
762 && tmceilingz-thing->z < thing->height
763 && !(thing->flags2&MF2_FLY))
764 { // mobj must lower itself to fit
765 CheckMissileImpact(thing);
768 if(thing->flags2&MF2_FLY)
770 if(thing->z+thing->height > tmceilingz)
772 thing->momz = -8*FRACUNIT;
775 else if(thing->z < tmfloorz && tmfloorz-tmdropoffz > 24*FRACUNIT)
777 thing->momz = 8*FRACUNIT;
781 if(!(thing->flags&MF_TELEPORT)
782 // The Minotaur floor fire (MT_MNTRFX2) can step up any amount
783 && thing->type != MT_MNTRFX2
784 && tmfloorz-thing->z > 24*FRACUNIT)
785 { // Too big a step up
786 CheckMissileImpact(thing);
789 if((thing->flags&MF_MISSILE) && tmfloorz > thing->z)
791 CheckMissileImpact(thing);
793 if(!(thing->flags&(MF_DROPOFF|MF_FLOAT))
794 && tmfloorz-tmdropoffz > 24*FRACUNIT)
795 { // Can't move over a dropoff
801 // the move is ok, so link the thing into its new position
803 P_UnsetThingPosition (thing);
807 thing->floorz = tmfloorz;
808 thing->ceilingz = tmceilingz;
812 P_SetThingPosition (thing);
814 if(thing->flags2&MF2_FOOTCLIP && P_GetThingFloorType(thing) != FLOOR_SOLID)
816 thing->flags2 |= MF2_FEETARECLIPPED;
818 else if(thing->flags2&MF2_FEETARECLIPPED)
820 thing->flags2 &= ~MF2_FEETARECLIPPED;
824 // if any special lines were hit, do the effect
826 if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) )
829 // see if the line was crossed
830 ld = spechit[numspechit];
831 side = P_PointOnLineSide (thing->x, thing->y, ld);
832 oldside = P_PointOnLineSide (oldx, oldy, ld);
836 P_CrossSpecialLine (ld-lines, oldside, thing);
848 = Takes a valid thing and adjusts the thing->floorz, thing->ceilingz,
849 = anf possibly thing->z
851 = This is called for all nearby monsters whenever a sector changes height
853 = If the thing doesn't fit, the z will be set to the lowest value and
854 = false will be returned
858 boolean P_ThingHeightClip (mobj_t *thing)
862 onfloor = (thing->z == thing->floorz);
864 P_CheckPosition (thing, thing->x, thing->y);
865 // what about stranding a monster partially off an edge?
867 thing->floorz = tmfloorz;
868 thing->ceilingz = tmceilingz;
871 // walking monsters rise and fall with the floor
872 thing->z = thing->floorz;
874 { // don't adjust a floating monster unless forced to
875 if (thing->z+thing->height > thing->ceilingz)
876 thing->z = thing->ceilingz - thing->height;
879 if (thing->ceilingz - thing->floorz < thing->height)
887 ==============================================================================
891 Allows the player to slide along any angled walls
893 ==============================================================================
896 fixed_t bestslidefrac, secondslidefrac;
897 line_t *bestslideline, *secondslideline;
900 fixed_t tmxmove, tmymove;
907 = Adjusts the xmove / ymove so that the next move will slide along the wall
911 void P_HitSlideLine (line_t *ld)
914 angle_t lineangle, moveangle, deltaangle;
915 fixed_t movelen, newlen;
918 if (ld->slopetype == ST_HORIZONTAL)
923 if (ld->slopetype == ST_VERTICAL)
929 side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
931 lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy);
934 moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove);
935 deltaangle = moveangle-lineangle;
936 if (deltaangle > ANG180)
937 deltaangle += ANG180;
938 // I_Error ("SlideLine: ang>ANG180");
940 lineangle >>= ANGLETOFINESHIFT;
941 deltaangle >>= ANGLETOFINESHIFT;
943 movelen = P_AproxDistance (tmxmove, tmymove);
944 newlen = FixedMul (movelen, finecosine[deltaangle]);
945 tmxmove = FixedMul (newlen, finecosine[lineangle]);
946 tmymove = FixedMul (newlen, finesine[lineangle]);
957 boolean PTR_SlideTraverse (intercept_t *in)
962 I_Error ("PTR_SlideTraverse: not a line?");
965 if ( ! (li->flags & ML_TWOSIDED) )
967 if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
968 return true; // don't hit the back side
972 P_LineOpening (li); // set openrange, opentop, openbottom
973 if (openrange < slidemo->height)
974 goto isblocking; // doesn't fit
976 if (opentop - slidemo->z < slidemo->height)
977 goto isblocking; // mobj is too high
979 if (openbottom - slidemo->z > 24*FRACUNIT )
980 goto isblocking; // too big a step up
982 return true; // this line doesn't block movement
984 // the line does block movement, see if it is closer than best so far
986 if (in->frac < bestslidefrac)
988 secondslidefrac = bestslidefrac;
989 secondslideline = bestslideline;
990 bestslidefrac = in->frac;
994 return false; // stop
1003 = The momx / momy move is bad, so try to slide along a wall
1005 = Find the first line hit, move flush to it, and slide along it
1007 = This is a kludgy mess.
1011 void P_SlideMove (mobj_t *mo)
1013 fixed_t leadx, leady;
1014 fixed_t trailx, traily;
1021 if (++hitcount == 3)
1022 goto stairstep; // don't loop forever
1025 // trace along the three leading corners
1029 leadx = mo->x + mo->radius;
1030 trailx = mo->x - mo->radius;
1034 leadx = mo->x - mo->radius;
1035 trailx = mo->x + mo->radius;
1040 leady = mo->y + mo->radius;
1041 traily = mo->y - mo->radius;
1045 leady = mo->y - mo->radius;
1046 traily = mo->y + mo->radius;
1049 bestslidefrac = FRACUNIT+1;
1051 P_PathTraverse ( leadx, leady, leadx+mo->momx, leady+mo->momy,
1052 PT_ADDLINES, PTR_SlideTraverse );
1053 P_PathTraverse ( trailx, leady, trailx+mo->momx, leady+mo->momy,
1054 PT_ADDLINES, PTR_SlideTraverse );
1055 P_PathTraverse ( leadx, traily, leadx+mo->momx, traily+mo->momy,
1056 PT_ADDLINES, PTR_SlideTraverse );
1059 // move up to the wall
1061 if (bestslidefrac == FRACUNIT+1)
1062 { // the move most have hit the middle, so stairstep
1064 if (!P_TryMove (mo, mo->x, mo->y + mo->momy))
1065 P_TryMove (mo, mo->x + mo->momx, mo->y);
1069 bestslidefrac -= 0x800; // fudge a bit to make sure it doesn't hit
1070 if (bestslidefrac > 0)
1072 newx = FixedMul (mo->momx, bestslidefrac);
1073 newy = FixedMul (mo->momy, bestslidefrac);
1074 if (!P_TryMove (mo, mo->x+newx, mo->y+newy))
1079 // now continue along the wall
1081 bestslidefrac = FRACUNIT-(bestslidefrac+0x800); // remainder
1082 if (bestslidefrac > FRACUNIT)
1083 bestslidefrac = FRACUNIT;
1084 if (bestslidefrac <= 0)
1087 tmxmove = FixedMul (mo->momx, bestslidefrac);
1088 tmymove = FixedMul (mo->momy, bestslidefrac);
1090 P_HitSlideLine (bestslideline); // clip the moves
1095 if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove))
1104 ==============================================================================
1108 ==============================================================================
1112 mobj_t *linetarget; // who got hit (or NULL)
1114 fixed_t shootz; // height if not aiming up or down
1115 // ???: use slope for monsters?
1117 fixed_t attackrange;
1121 extern fixed_t topslope, bottomslope; // slopes to top and bottom of target
1124 ===============================================================================
1128 = Sets linetaget and aimslope when a target is aimed at
1129 ===============================================================================
1132 boolean PTR_AimTraverse (intercept_t *in)
1136 fixed_t slope, thingtopslope, thingbottomslope;
1142 if ( !(li->flags & ML_TWOSIDED) )
1143 return false; // stop
1145 // crosses a two sided line
1146 // a two sided line will restrict the possible target ranges
1149 if (openbottom >= opentop)
1150 return false; // stop
1152 dist = FixedMul (attackrange, in->frac);
1154 if (li->frontsector->floorheight != li->backsector->floorheight)
1156 slope = FixedDiv (openbottom - shootz , dist);
1157 if (slope > bottomslope)
1158 bottomslope = slope;
1161 if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
1163 slope = FixedDiv (opentop - shootz , dist);
1164 if (slope < topslope)
1168 if (topslope <= bottomslope)
1169 return false; // stop
1171 return true; // shot continues
1178 if (th == shootthing)
1179 return true; // can't shoot self
1180 if (!(th->flags&MF_SHOOTABLE))
1181 return true; // corpse or something
1182 if(th->type == MT_POD)
1183 { // Can't auto-aim at pods
1187 // check angles to see if the thing can be aimed at
1189 dist = FixedMul (attackrange, in->frac);
1190 thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
1191 if (thingtopslope < bottomslope)
1192 return true; // shot over the thing
1193 thingbottomslope = FixedDiv (th->z - shootz, dist);
1194 if (thingbottomslope > topslope)
1195 return true; // shot under the thing
1198 // this thing can be hit!
1200 if (thingtopslope > topslope)
1201 thingtopslope = topslope;
1202 if (thingbottomslope < bottomslope)
1203 thingbottomslope = bottomslope;
1205 aimslope = (thingtopslope+thingbottomslope)/2;
1208 return false; // don't go any farther
1213 ==============================================================================
1217 ==============================================================================
1220 boolean PTR_ShootTraverse (intercept_t *in)
1228 fixed_t thingtopslope, thingbottomslope;
1235 P_ShootSpecialLine (shootthing, li);
1236 if ( !(li->flags & ML_TWOSIDED) )
1240 // crosses a two sided line
1244 dist = FixedMul (attackrange, in->frac);
1246 if (li->frontsector->floorheight != li->backsector->floorheight)
1248 slope = FixedDiv (openbottom - shootz , dist);
1249 if (slope > aimslope)
1253 if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
1255 slope = FixedDiv (opentop - shootz , dist);
1256 if (slope < aimslope)
1260 return true; // shot continues
1265 // position a bit closer
1266 frac = in->frac - FixedDiv (4*FRACUNIT,attackrange);
1267 x = trace.x + FixedMul (trace.dx, frac);
1268 y = trace.y + FixedMul (trace.dy, frac);
1269 z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
1271 if (li->frontsector->ceilingpic == skyflatnum)
1273 if (z > li->frontsector->ceilingheight)
1274 return false; // don't shoot the sky!
1275 if (li->backsector && li->backsector->ceilingpic == skyflatnum)
1276 return false; // it's a sky hack wall
1279 P_SpawnPuff (x,y,z);
1280 return false; // don't go any farther
1287 if (th == shootthing)
1288 return true; // can't shoot self
1289 if (!(th->flags&MF_SHOOTABLE))
1290 return true; // corpse or something
1293 // check for physical attacks on a ghost
1295 if(th->flags&MF_SHADOW && shootthing->player->readyweapon == wp_staff)
1300 // check angles to see if the thing can be aimed at
1301 dist = FixedMul (attackrange, in->frac);
1302 thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
1303 if (thingtopslope < aimslope)
1304 return true; // shot over the thing
1305 thingbottomslope = FixedDiv (th->z - shootz, dist);
1306 if (thingbottomslope > aimslope)
1307 return true; // shot under the thing
1312 // position a bit closer
1313 frac = in->frac - FixedDiv (10*FRACUNIT,attackrange);
1314 x = trace.x + FixedMul(trace.dx, frac);
1315 y = trace.y + FixedMul(trace.dy, frac);
1316 z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange));
1317 if(PuffType == MT_BLASTERPUFF1)
1318 { // Make blaster big puff
1319 mo = P_SpawnMobj(x, y, z, MT_BLASTERPUFF2);
1320 S_StartSound(mo, sfx_blshit);
1324 P_SpawnPuff(x, y, z);
1328 if(!(in->d.thing->flags&MF_NOBLOOD) && P_Random() < 192)
1330 P_BloodSplatter(x, y, z, in->d.thing);
1332 P_DamageMobj(th, shootthing, shootthing, la_damage);
1334 return(false); // don't go any farther
1345 fixed_t P_AimLineAttack (mobj_t *t1, angle_t angle, fixed_t distance)
1349 angle >>= ANGLETOFINESHIFT;
1351 x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
1352 y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
1353 shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
1354 topslope = 100*FRACUNIT/160; // can't shoot outside view angles
1355 bottomslope = -100*FRACUNIT/160;
1356 attackrange = distance;
1359 P_PathTraverse ( t1->x, t1->y, x2, y2
1360 , PT_ADDLINES|PT_ADDTHINGS, PTR_AimTraverse );
1374 = if damage == 0, it is just a test trace that will leave linetarget set
1379 void P_LineAttack (mobj_t *t1, angle_t angle, fixed_t distance, fixed_t slope, int damage)
1383 angle >>= ANGLETOFINESHIFT;
1386 x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
1387 y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
1388 shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
1389 if(t1->flags2&MF2_FEETARECLIPPED)
1391 shootz -= FOOTCLIPSIZE;
1393 attackrange = distance;
1396 P_PathTraverse ( t1->x, t1->y, x2, y2
1397 , PT_ADDLINES|PT_ADDTHINGS, PTR_ShootTraverse );
1403 ==============================================================================
1407 ==============================================================================
1412 boolean PTR_UseTraverse (intercept_t *in)
1414 if (!in->d.line->special)
1416 P_LineOpening (in->d.line);
1419 //S_StartSound (usething, sfx_noway);
1420 return false; // can't use through a wall
1422 return true ; // not a special line, but keep checking
1425 if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
1426 return false; // don't use back sides
1428 P_UseSpecialLine (usething, in->d.line);
1430 return false; // can't use for than one special line in a row
1439 = Looks for special lines in front of the player to activate
1443 void P_UseLines (player_t *player)
1446 fixed_t x1, y1, x2, y2;
1448 usething = player->mo;
1450 angle = player->mo->angle >> ANGLETOFINESHIFT;
1453 x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
1454 y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
1456 P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
1462 ==============================================================================
1466 ==============================================================================
1478 = Source is the creature that casued the explosion at spot
1482 boolean PIT_RadiusAttack (mobj_t *thing)
1484 fixed_t dx, dy, dist;
1486 if(!(thing->flags&MF_SHOOTABLE))
1490 if(thing->type == MT_MINOTAUR || thing->type == MT_SORCERER1
1491 || thing->type == MT_SORCERER2)
1492 { // Episode 2 and 3 bosses take no damage from PIT_RadiusAttack
1495 dx = abs(thing->x - bombspot->x);
1496 dy = abs(thing->y - bombspot->y);
1497 dist = dx > dy ? dx : dy;
1498 dist = (dist - thing->radius) >> FRACBITS;
1503 if(dist >= bombdamage)
1507 if(P_CheckSight(thing, bombspot))
1508 { // OK to damage, target is in direct path
1509 P_DamageMobj(thing, bombspot, bombsource, bombdamage - dist);
1519 = Source is the creature that casued the explosion at spot
1523 void P_RadiusAttack (mobj_t *spot, mobj_t *source, int damage)
1525 int x,y, xl, xh, yl, yh;
1528 dist = (damage+MAXRADIUS)<<FRACBITS;
1529 yh = (spot->y + dist - bmaporgy)>>MAPBLOCKSHIFT;
1530 yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT;
1531 xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT;
1532 xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT;
1534 if(spot->type == MT_POD && spot->target)
1536 bombsource = spot->target;
1540 bombsource = source;
1542 bombdamage = damage;
1543 for (y=yl ; y<=yh ; y++)
1544 for (x=xl ; x<=xh ; x++)
1545 P_BlockThingsIterator (x, y, PIT_RadiusAttack );
1550 ==============================================================================
1552 SECTOR HEIGHT CHANGING
1554 = After modifying a sectors floor or ceiling height, call this
1555 = routine to adjust the positions of all things that touch the
1558 = If anything doesn't fit anymore, true will be returned.
1559 = If crunch is true, they will take damage as they are being crushed
1560 = If Crunch is false, you should set the sector height back the way it
1561 = was and call P_ChangeSector again to undo the changes
1562 ==============================================================================
1565 boolean crushchange;
1576 boolean PIT_ChangeSector (mobj_t *thing)
1580 if (P_ThingHeightClip (thing))
1581 return true; // keep checking
1583 // crunch bodies to giblets
1584 if (thing->health <= 0)
1586 //P_SetMobjState (thing, S_GIBS);
1589 return true; // keep checking
1592 // crunch dropped items
1593 if (thing->flags & MF_DROPPED)
1595 P_RemoveMobj (thing);
1596 return true; // keep checking
1599 if (! (thing->flags & MF_SHOOTABLE) )
1600 return true; // assume it is bloody gibs or something
1603 if (crushchange && !(leveltime&3) )
1605 P_DamageMobj(thing,NULL,NULL,10);
1606 // spray blood in a random direction
1607 mo = P_SpawnMobj (thing->x, thing->y, thing->z + thing->height/2, MT_BLOOD);
1608 mo->momx = (P_Random() - P_Random ())<<12;
1609 mo->momy = (P_Random() - P_Random ())<<12;
1612 return true; // keep checking (crush other things)
1623 boolean P_ChangeSector (sector_t *sector, boolean crunch)
1628 crushchange = crunch;
1630 // recheck heights for all things near the moving sector
1632 for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++)
1633 for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++)
1634 P_BlockThingsIterator (x, y, PIT_ChangeSector);