8 ===============================================================================
13 ===============================================================================
17 ===============================================================================
21 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.
23 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.
25 The sound code uses the x,y, and subsector fields to do stereo positioning of any sound effited by the mobj_t.
27 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.
30 Every mobj_t is linked into a single sector based on it's origin coordinates.
31 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.
33 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.
35 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.
38 ===============================================================================
46 boolean floatok; // if true, move would be ok if
47 // within tmfloorz - tmceilingz
49 fixed_t tmfloorz, tmceilingz, tmdropoffz;
51 // keep track of the line that lowers the ceiling, so missiles don't explode
52 // against sky hack walls
55 // keep track of special lines as they are hit, but don't process them
56 // until the move is proven valid
57 #define MAXSPECIALCROSS 8
58 line_t *spechit[MAXSPECIALCROSS];
61 mobj_t *onmobj; //generic global onmobj...used for landing on pods/players
64 ===============================================================================
68 ===============================================================================
79 boolean PIT_StompThing (mobj_t *thing)
83 if (!(thing->flags & MF_SHOOTABLE) )
86 blockdist = thing->radius + tmthing->radius;
87 if ( abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist )
88 return true; // didn't hit it
91 return true; // don't clip against self
93 if(!(tmthing->flags2&MF2_TELESTOMP))
94 { // Not allowed to stomp things
98 P_DamageMobj (thing, tmthing, tmthing, 10000);
112 boolean P_TeleportMove (mobj_t *thing, fixed_t x, fixed_t y)
114 int xl,xh,yl,yh,bx,by;
115 subsector_t *newsubsec;
118 // kill anything occupying the position
122 tmflags = thing->flags;
127 tmbbox[BOXTOP] = y + tmthing->radius;
128 tmbbox[BOXBOTTOM] = y - tmthing->radius;
129 tmbbox[BOXRIGHT] = x + tmthing->radius;
130 tmbbox[BOXLEFT] = x - tmthing->radius;
132 newsubsec = R_PointInSubsector (x,y);
136 // the base floor / ceiling is from the subsector that contains the
137 // point. Any contacted lines the step closer together will adjust them
139 tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
140 tmceilingz = newsubsec->sector->ceilingheight;
146 // stomp on any things contacted
148 xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
149 xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
150 yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
151 yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
153 for (bx=xl ; bx<=xh ; bx++)
154 for (by=yl ; by<=yh ; by++)
155 if (!P_BlockThingsIterator(bx,by,PIT_StompThing))
159 // the move is ok, so link the thing into its new position
161 P_UnsetThingPosition (thing);
163 thing->floorz = tmfloorz;
164 thing->ceilingz = tmceilingz;
168 P_SetThingPosition (thing);
174 ===============================================================================
176 MOVEMENT ITERATOR FUNCTIONS
178 ===============================================================================
186 = Adjusts tmfloorz and tmceilingz as lines are contacted
190 boolean PIT_CheckLine(line_t *ld)
192 if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
193 || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
194 || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
195 || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
199 if(P_BoxOnLineSide(tmbbox, ld) != -1)
204 // a line has been hit
207 = The moving thing's destination position will cross the given line.
208 = If this should not be allowed, return false.
209 = If the line is special, keep track of it to process later if the move
210 = is proven ok. NOTE: specials are NOT sorted by order, so two special lines
211 = that are only 8 pixels apart could be crossed in either order.
216 if(tmthing->flags&MF_MISSILE)
217 { // Missiles can trigger impact specials
220 spechit[numspechit] = ld;
226 if(!(tmthing->flags&MF_MISSILE))
228 if(ld->flags&ML_BLOCKING)
229 { // Explicitly blocking everything
232 if(!tmthing->player && ld->flags&ML_BLOCKMONSTERS
233 && tmthing->type != MT_POD)
234 { // Block monsters only
238 P_LineOpening(ld); // set openrange, opentop, openbottom
239 // adjust floor / ceiling heights
240 if(opentop < tmceilingz)
242 tmceilingz = opentop;
245 if(openbottom > tmfloorz)
247 tmfloorz = openbottom;
249 if(lowfloor < tmdropoffz)
251 tmdropoffz = lowfloor;
254 { // Contacted a special line, add it to the list
255 spechit[numspechit] = ld;
261 //---------------------------------------------------------------------------
263 // FUNC PIT_CheckThing
265 //---------------------------------------------------------------------------
267 boolean PIT_CheckThing(mobj_t *thing)
273 if(!(thing->flags&(MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
277 blockdist = thing->radius+tmthing->radius;
278 if(abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist)
279 { // Didn't hit thing
283 { // Don't clip against self
286 if(tmthing->flags2&MF2_PASSMOBJ)
287 { // check if a mobj passed over/under another object
288 if((tmthing->type == MT_IMP || tmthing->type == MT_WIZARD)
289 && (thing->type == MT_IMP || thing->type == MT_WIZARD))
290 { // don't let imps/wizards fly over other imps/wizards
293 if(tmthing->z > thing->z+thing->height
294 && !(thing->flags&MF_SPECIAL))
298 else if(tmthing->z+tmthing->height < thing->z
299 && !(thing->flags&MF_SPECIAL))
304 // Check for skulls slamming into things
305 if(tmthing->flags&MF_SKULLFLY)
307 damage = ((P_Random()%8)+1)*tmthing->damage;
308 P_DamageMobj(thing, tmthing, tmthing, damage);
309 tmthing->flags &= ~MF_SKULLFLY;
310 tmthing->momx = tmthing->momy = tmthing->momz = 0;
311 P_SetMobjState(tmthing, tmthing->info->seestate);
315 if(tmthing->flags&MF_MISSILE)
317 // Check for passing through a ghost
318 if((thing->flags&MF_SHADOW) && (tmthing->flags2&MF2_THRUGHOST))
322 // Check if it went over / under
323 if(tmthing->z > thing->z+thing->height)
327 if(tmthing->z+tmthing->height < thing->z)
331 if(tmthing->target && tmthing->target->type == thing->type)
332 { // Don't hit same species as originator
333 if(thing == tmthing->target)
334 { // Don't missile self
337 if(thing->type != MT_PLAYER)
338 { // Hit same species as originator, explode, no damage
342 if(!(thing->flags&MF_SHOOTABLE))
343 { // Didn't do any damage
344 return!(thing->flags&MF_SOLID);
346 if(tmthing->flags2&MF2_RIP)
348 if(!(thing->flags&MF_NOBLOOD))
349 { // Ok to spawn some blood
350 P_RipperBlood(tmthing);
352 S_StartSound(tmthing, sfx_ripslop);
353 damage = ((P_Random()&3)+2)*tmthing->damage;
354 P_DamageMobj(thing, tmthing, tmthing->target, damage);
355 if(thing->flags2&MF2_PUSHABLE
356 && !(tmthing->flags2&MF2_CANNOTPUSH))
358 thing->momx += tmthing->momx>>2;
359 thing->momy += tmthing->momy>>2;
365 damage = ((P_Random()%8)+1)*tmthing->damage;
368 if(!(thing->flags&MF_NOBLOOD) && P_Random() < 192)
370 P_BloodSplatter(tmthing->x, tmthing->y, tmthing->z, thing);
372 P_DamageMobj(thing, tmthing, tmthing->target, damage);
376 if(thing->flags2&MF2_PUSHABLE && !(tmthing->flags2&MF2_CANNOTPUSH))
378 thing->momx += tmthing->momx>>2;
379 thing->momy += tmthing->momy>>2;
381 // Check for special thing
382 if(thing->flags&MF_SPECIAL)
384 solid = thing->flags&MF_SOLID;
385 if(tmflags&MF_PICKUP)
386 { // Can be picked up by tmthing
387 P_TouchSpecialThing(thing, tmthing); // Can remove thing
391 return(!(thing->flags&MF_SOLID));
394 //---------------------------------------------------------------------------
398 //---------------------------------------------------------------------------
400 boolean PIT_CheckOnmobjZ(mobj_t *thing)
404 if(!(thing->flags&(MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
408 blockdist = thing->radius+tmthing->radius;
409 if(abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist)
410 { // Didn't hit thing
414 { // Don't clip against self
417 if(tmthing->z > thing->z+thing->height)
421 else if(tmthing->z+tmthing->height < thing->z)
425 if(thing->flags&MF_SOLID)
429 return(!(thing->flags&MF_SOLID));
433 ===============================================================================
437 ===============================================================================
440 //----------------------------------------------------------------------------
442 // FUNC P_TestMobjLocation
444 // Returns true if the mobj is not blocked by anything at its current
445 // location, otherwise returns false.
447 //----------------------------------------------------------------------------
449 boolean P_TestMobjLocation(mobj_t *mobj)
454 mobj->flags &= ~MF_PICKUP;
455 if(P_CheckPosition(mobj, mobj->x, mobj->y))
456 { // XY is ok, now check Z
458 if((mobj->z < mobj->floorz)
459 || (mobj->z+mobj->height > mobj->ceilingz))
474 = This is purely informative, nothing is modified (except things picked up)
477 a mobj_t (can be valid or invalid)
478 a position to be checked (doesn't need to be related to the mobj_t->x,y)
481 special things are touched if MF_PICKUP
482 early out on solid lines?
488 tmdropoffz the lowest point contacted (monsters won't move to a dropoff)
495 boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y)
497 int xl,xh,yl,yh,bx,by;
498 subsector_t *newsubsec;
501 tmflags = thing->flags;
506 tmbbox[BOXTOP] = y + tmthing->radius;
507 tmbbox[BOXBOTTOM] = y - tmthing->radius;
508 tmbbox[BOXRIGHT] = x + tmthing->radius;
509 tmbbox[BOXLEFT] = x - tmthing->radius;
511 newsubsec = R_PointInSubsector (x,y);
515 // the base floor / ceiling is from the subsector that contains the
516 // point. Any contacted lines the step closer together will adjust them
518 tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
519 tmceilingz = newsubsec->sector->ceilingheight;
524 if ( tmflags & MF_NOCLIP )
528 // check things first, possibly picking things up
529 // the bounding box is extended by MAXRADIUS because mobj_ts are grouped
530 // into mapblocks based on their origin point, and can overlap into adjacent
531 // blocks by up to MAXRADIUS units
533 xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
534 xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
535 yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
536 yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
538 for (bx=xl ; bx<=xh ; bx++)
539 for (by=yl ; by<=yh ; by++)
540 if (!P_BlockThingsIterator(bx,by,PIT_CheckThing))
545 xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
546 xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
547 yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
548 yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
550 for (bx=xl ; bx<=xh ; bx++)
551 for (by=yl ; by<=yh ; by++)
552 if (!P_BlockLinesIterator (bx,by,PIT_CheckLine))
558 //=============================================================================
560 // P_CheckOnmobj(mobj_t *thing)
562 // Checks if the new Z position is legal
563 //=============================================================================
565 mobj_t *P_CheckOnmobj(mobj_t *thing)
567 int xl,xh,yl,yh,bx,by;
568 subsector_t *newsubsec;
576 tmflags = thing->flags;
577 oldmo = *thing; // save the old mobj before the fake zmovement
578 P_FakeZMovement(tmthing);
583 tmbbox[BOXTOP] = y + tmthing->radius;
584 tmbbox[BOXBOTTOM] = y - tmthing->radius;
585 tmbbox[BOXRIGHT] = x + tmthing->radius;
586 tmbbox[BOXLEFT] = x - tmthing->radius;
588 newsubsec = R_PointInSubsector (x,y);
592 // the base floor / ceiling is from the subsector that contains the
593 // point. Any contacted lines the step closer together will adjust them
595 tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
596 tmceilingz = newsubsec->sector->ceilingheight;
601 if ( tmflags & MF_NOCLIP )
605 // check things first, possibly picking things up
606 // the bounding box is extended by MAXRADIUS because mobj_ts are grouped
607 // into mapblocks based on their origin point, and can overlap into adjacent
608 // blocks by up to MAXRADIUS units
610 xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
611 xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
612 yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
613 yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
615 for (bx=xl ; bx<=xh ; bx++)
616 for (by=yl ; by<=yh ; by++)
617 if (!P_BlockThingsIterator(bx,by,PIT_CheckOnmobjZ))
626 //=============================================================================
630 // Fake the zmovement so that we can check if a move is legal
631 //=============================================================================
633 void P_FakeZMovement(mobj_t *mo)
641 if(mo->flags&MF_FLOAT && mo->target)
642 { // float down towards target if too close
643 if(!(mo->flags&MF_SKULLFLY) && !(mo->flags&MF_INFLOAT))
645 dist = P_AproxDistance(mo->x-mo->target->x, mo->y-mo->target->y);
646 delta =( mo->target->z+(mo->height>>1))-mo->z;
647 if (delta < 0 && dist < -(delta*3))
649 else if (delta > 0 && dist < (delta*3))
653 if(mo->player && mo->flags2&MF2_FLY && !(mo->z <= mo->floorz)
656 mo->z += finesine[(FINEANGLES/20*leveltime>>2)&FINEMASK];
662 if(mo->z <= mo->floorz)
669 if(mo->flags&MF_SKULLFLY)
670 { // The skull slammed into something
671 mo->momz = -mo->momz;
673 if(mo->info->crashstate && (mo->flags&MF_CORPSE))
678 else if(mo->flags2&MF2_LOGRAV)
681 mo->momz = -(GRAVITY>>3)*2;
683 mo->momz -= GRAVITY>>3;
685 else if (! (mo->flags & MF_NOGRAVITY) )
688 mo->momz = -GRAVITY*2;
693 if (mo->z + mo->height > mo->ceilingz)
697 mo->z = mo->ceilingz - mo->height;
698 if (mo->flags & MF_SKULLFLY)
699 { // the skull slammed into something
700 mo->momz = -mo->momz;
705 //==========================================================================
707 // CheckMissileImpact
709 //==========================================================================
711 void CheckMissileImpact(mobj_t *mobj)
715 if(!numspechit || !(mobj->flags&MF_MISSILE) || !mobj->target)
719 if(!mobj->target->player)
723 for(i = numspechit-1; i >= 0; i--)
725 P_ShootSpecialLine(mobj->target, spechit[i]);
734 = Attempt to move to a new position, crossing special lines unless MF_TELEPORT
740 boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y)
747 if(!P_CheckPosition(thing, x, y))
748 { // Solid wall or thing
749 CheckMissileImpact(thing);
752 if(!(thing->flags&MF_NOCLIP))
754 if(tmceilingz-tmfloorz < thing->height)
756 CheckMissileImpact(thing);
760 if(!(thing->flags&MF_TELEPORT)
761 && tmceilingz-thing->z < thing->height
762 && !(thing->flags2&MF2_FLY))
763 { // mobj must lower itself to fit
764 CheckMissileImpact(thing);
767 if(thing->flags2&MF2_FLY)
769 if(thing->z+thing->height > tmceilingz)
771 thing->momz = -8*FRACUNIT;
774 else if(thing->z < tmfloorz && tmfloorz-tmdropoffz > 24*FRACUNIT)
776 thing->momz = 8*FRACUNIT;
780 if(!(thing->flags&MF_TELEPORT)
781 // The Minotaur floor fire (MT_MNTRFX2) can step up any amount
782 && thing->type != MT_MNTRFX2
783 && tmfloorz-thing->z > 24*FRACUNIT)
784 { // Too big a step up
785 CheckMissileImpact(thing);
788 if((thing->flags&MF_MISSILE) && tmfloorz > thing->z)
790 CheckMissileImpact(thing);
792 if(!(thing->flags&(MF_DROPOFF|MF_FLOAT))
793 && tmfloorz-tmdropoffz > 24*FRACUNIT)
794 { // Can't move over a dropoff
800 // the move is ok, so link the thing into its new position
802 P_UnsetThingPosition (thing);
806 thing->floorz = tmfloorz;
807 thing->ceilingz = tmceilingz;
811 P_SetThingPosition (thing);
813 if(thing->flags2&MF2_FOOTCLIP && P_GetThingFloorType(thing) != FLOOR_SOLID)
815 thing->flags2 |= MF2_FEETARECLIPPED;
817 else if(thing->flags2&MF2_FEETARECLIPPED)
819 thing->flags2 &= ~MF2_FEETARECLIPPED;
823 // if any special lines were hit, do the effect
825 if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) )
828 // see if the line was crossed
829 ld = spechit[numspechit];
830 side = P_PointOnLineSide (thing->x, thing->y, ld);
831 oldside = P_PointOnLineSide (oldx, oldy, ld);
835 P_CrossSpecialLine (ld-lines, oldside, thing);
847 = Takes a valid thing and adjusts the thing->floorz, thing->ceilingz,
848 = anf possibly thing->z
850 = This is called for all nearby monsters whenever a sector changes height
852 = If the thing doesn't fit, the z will be set to the lowest value and
853 = false will be returned
857 boolean P_ThingHeightClip (mobj_t *thing)
861 onfloor = (thing->z == thing->floorz);
863 P_CheckPosition (thing, thing->x, thing->y);
864 // what about stranding a monster partially off an edge?
866 thing->floorz = tmfloorz;
867 thing->ceilingz = tmceilingz;
870 // walking monsters rise and fall with the floor
871 thing->z = thing->floorz;
873 { // don't adjust a floating monster unless forced to
874 if (thing->z+thing->height > thing->ceilingz)
875 thing->z = thing->ceilingz - thing->height;
878 if (thing->ceilingz - thing->floorz < thing->height)
886 ==============================================================================
890 Allows the player to slide along any angled walls
892 ==============================================================================
895 fixed_t bestslidefrac, secondslidefrac;
896 line_t *bestslideline, *secondslideline;
899 fixed_t tmxmove, tmymove;
906 = Adjusts the xmove / ymove so that the next move will slide along the wall
910 void P_HitSlideLine (line_t *ld)
913 angle_t lineangle, moveangle, deltaangle;
914 fixed_t movelen, newlen;
917 if (ld->slopetype == ST_HORIZONTAL)
922 if (ld->slopetype == ST_VERTICAL)
928 side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
930 lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy);
933 moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove);
934 deltaangle = moveangle-lineangle;
935 if (deltaangle > ANG180)
936 deltaangle += ANG180;
937 // I_Error ("SlideLine: ang>ANG180");
939 lineangle >>= ANGLETOFINESHIFT;
940 deltaangle >>= ANGLETOFINESHIFT;
942 movelen = P_AproxDistance (tmxmove, tmymove);
943 newlen = FixedMul (movelen, finecosine[deltaangle]);
944 tmxmove = FixedMul (newlen, finecosine[lineangle]);
945 tmymove = FixedMul (newlen, finesine[lineangle]);
956 boolean PTR_SlideTraverse (intercept_t *in)
961 I_Error ("PTR_SlideTraverse: not a line?");
964 if ( ! (li->flags & ML_TWOSIDED) )
966 if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
967 return true; // don't hit the back side
971 P_LineOpening (li); // set openrange, opentop, openbottom
972 if (openrange < slidemo->height)
973 goto isblocking; // doesn't fit
975 if (opentop - slidemo->z < slidemo->height)
976 goto isblocking; // mobj is too high
978 if (openbottom - slidemo->z > 24*FRACUNIT )
979 goto isblocking; // too big a step up
981 return true; // this line doesn't block movement
983 // the line does block movement, see if it is closer than best so far
985 if (in->frac < bestslidefrac)
987 secondslidefrac = bestslidefrac;
988 secondslideline = bestslideline;
989 bestslidefrac = in->frac;
993 return false; // stop
1002 = The momx / momy move is bad, so try to slide along a wall
1004 = Find the first line hit, move flush to it, and slide along it
1006 = This is a kludgy mess.
1010 void P_SlideMove (mobj_t *mo)
1012 fixed_t leadx, leady;
1013 fixed_t trailx, traily;
1020 if (++hitcount == 3)
1021 goto stairstep; // don't loop forever
1024 // trace along the three leading corners
1028 leadx = mo->x + mo->radius;
1029 trailx = mo->x - mo->radius;
1033 leadx = mo->x - mo->radius;
1034 trailx = mo->x + mo->radius;
1039 leady = mo->y + mo->radius;
1040 traily = mo->y - mo->radius;
1044 leady = mo->y - mo->radius;
1045 traily = mo->y + mo->radius;
1048 bestslidefrac = FRACUNIT+1;
1050 P_PathTraverse ( leadx, leady, leadx+mo->momx, leady+mo->momy,
1051 PT_ADDLINES, PTR_SlideTraverse );
1052 P_PathTraverse ( trailx, leady, trailx+mo->momx, leady+mo->momy,
1053 PT_ADDLINES, PTR_SlideTraverse );
1054 P_PathTraverse ( leadx, traily, leadx+mo->momx, traily+mo->momy,
1055 PT_ADDLINES, PTR_SlideTraverse );
1058 // move up to the wall
1060 if (bestslidefrac == FRACUNIT+1)
1061 { // the move most have hit the middle, so stairstep
1063 if (!P_TryMove (mo, mo->x, mo->y + mo->momy))
1064 P_TryMove (mo, mo->x + mo->momx, mo->y);
1068 bestslidefrac -= 0x800; // fudge a bit to make sure it doesn't hit
1069 if (bestslidefrac > 0)
1071 newx = FixedMul (mo->momx, bestslidefrac);
1072 newy = FixedMul (mo->momy, bestslidefrac);
1073 if (!P_TryMove (mo, mo->x+newx, mo->y+newy))
1078 // now continue along the wall
1080 bestslidefrac = FRACUNIT-(bestslidefrac+0x800); // remainder
1081 if (bestslidefrac > FRACUNIT)
1082 bestslidefrac = FRACUNIT;
1083 if (bestslidefrac <= 0)
1086 tmxmove = FixedMul (mo->momx, bestslidefrac);
1087 tmymove = FixedMul (mo->momy, bestslidefrac);
1089 P_HitSlideLine (bestslideline); // clip the moves
1094 if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove))
1103 ==============================================================================
1107 ==============================================================================
1111 mobj_t *linetarget; // who got hit (or NULL)
1113 fixed_t shootz; // height if not aiming up or down
1114 // ???: use slope for monsters?
1116 fixed_t attackrange;
1120 extern fixed_t topslope, bottomslope; // slopes to top and bottom of target
1123 ===============================================================================
1127 = Sets linetaget and aimslope when a target is aimed at
1128 ===============================================================================
1131 boolean PTR_AimTraverse (intercept_t *in)
1135 fixed_t slope, thingtopslope, thingbottomslope;
1141 if ( !(li->flags & ML_TWOSIDED) )
1142 return false; // stop
1144 // crosses a two sided line
1145 // a two sided line will restrict the possible target ranges
1148 if (openbottom >= opentop)
1149 return false; // stop
1151 dist = FixedMul (attackrange, in->frac);
1153 if (li->frontsector->floorheight != li->backsector->floorheight)
1155 slope = FixedDiv (openbottom - shootz , dist);
1156 if (slope > bottomslope)
1157 bottomslope = slope;
1160 if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
1162 slope = FixedDiv (opentop - shootz , dist);
1163 if (slope < topslope)
1167 if (topslope <= bottomslope)
1168 return false; // stop
1170 return true; // shot continues
1177 if (th == shootthing)
1178 return true; // can't shoot self
1179 if (!(th->flags&MF_SHOOTABLE))
1180 return true; // corpse or something
1181 if(th->type == MT_POD)
1182 { // Can't auto-aim at pods
1186 // check angles to see if the thing can be aimed at
1188 dist = FixedMul (attackrange, in->frac);
1189 thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
1190 if (thingtopslope < bottomslope)
1191 return true; // shot over the thing
1192 thingbottomslope = FixedDiv (th->z - shootz, dist);
1193 if (thingbottomslope > topslope)
1194 return true; // shot under the thing
1197 // this thing can be hit!
1199 if (thingtopslope > topslope)
1200 thingtopslope = topslope;
1201 if (thingbottomslope < bottomslope)
1202 thingbottomslope = bottomslope;
1204 aimslope = (thingtopslope+thingbottomslope)/2;
1207 return false; // don't go any farther
1212 ==============================================================================
1216 ==============================================================================
1219 boolean PTR_ShootTraverse (intercept_t *in)
1227 fixed_t thingtopslope, thingbottomslope;
1234 P_ShootSpecialLine (shootthing, li);
1235 if ( !(li->flags & ML_TWOSIDED) )
1239 // crosses a two sided line
1243 dist = FixedMul (attackrange, in->frac);
1245 if (li->frontsector->floorheight != li->backsector->floorheight)
1247 slope = FixedDiv (openbottom - shootz , dist);
1248 if (slope > aimslope)
1252 if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
1254 slope = FixedDiv (opentop - shootz , dist);
1255 if (slope < aimslope)
1259 return true; // shot continues
1264 // position a bit closer
1265 frac = in->frac - FixedDiv (4*FRACUNIT,attackrange);
1266 x = trace.x + FixedMul (trace.dx, frac);
1267 y = trace.y + FixedMul (trace.dy, frac);
1268 z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
1270 if (li->frontsector->ceilingpic == skyflatnum)
1272 if (z > li->frontsector->ceilingheight)
1273 return false; // don't shoot the sky!
1274 if (li->backsector && li->backsector->ceilingpic == skyflatnum)
1275 return false; // it's a sky hack wall
1278 P_SpawnPuff (x,y,z);
1279 return false; // don't go any farther
1286 if (th == shootthing)
1287 return true; // can't shoot self
1288 if (!(th->flags&MF_SHOOTABLE))
1289 return true; // corpse or something
1292 // check for physical attacks on a ghost
1294 if(th->flags&MF_SHADOW && shootthing->player->readyweapon == wp_staff)
1299 // check angles to see if the thing can be aimed at
1300 dist = FixedMul (attackrange, in->frac);
1301 thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
1302 if (thingtopslope < aimslope)
1303 return true; // shot over the thing
1304 thingbottomslope = FixedDiv (th->z - shootz, dist);
1305 if (thingbottomslope > aimslope)
1306 return true; // shot under the thing
1311 // position a bit closer
1312 frac = in->frac - FixedDiv (10*FRACUNIT,attackrange);
1313 x = trace.x + FixedMul(trace.dx, frac);
1314 y = trace.y + FixedMul(trace.dy, frac);
1315 z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange));
1316 if(PuffType == MT_BLASTERPUFF1)
1317 { // Make blaster big puff
1318 mo = P_SpawnMobj(x, y, z, MT_BLASTERPUFF2);
1319 S_StartSound(mo, sfx_blshit);
1323 P_SpawnPuff(x, y, z);
1327 if(!(in->d.thing->flags&MF_NOBLOOD) && P_Random() < 192)
1329 P_BloodSplatter(x, y, z, in->d.thing);
1331 P_DamageMobj(th, shootthing, shootthing, la_damage);
1333 return(false); // don't go any farther
1344 fixed_t P_AimLineAttack (mobj_t *t1, angle_t angle, fixed_t distance)
1348 angle >>= ANGLETOFINESHIFT;
1350 x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
1351 y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
1352 shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
1353 topslope = 100*FRACUNIT/160; // can't shoot outside view angles
1354 bottomslope = -100*FRACUNIT/160;
1355 attackrange = distance;
1358 P_PathTraverse ( t1->x, t1->y, x2, y2
1359 , PT_ADDLINES|PT_ADDTHINGS, PTR_AimTraverse );
1373 = if damage == 0, it is just a test trace that will leave linetarget set
1378 void P_LineAttack (mobj_t *t1, angle_t angle, fixed_t distance, fixed_t slope, int damage)
1382 angle >>= ANGLETOFINESHIFT;
1385 x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
1386 y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
1387 shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
1388 if(t1->flags2&MF2_FEETARECLIPPED)
1390 shootz -= FOOTCLIPSIZE;
1392 attackrange = distance;
1395 P_PathTraverse ( t1->x, t1->y, x2, y2
1396 , PT_ADDLINES|PT_ADDTHINGS, PTR_ShootTraverse );
1402 ==============================================================================
1406 ==============================================================================
1411 boolean PTR_UseTraverse (intercept_t *in)
1413 if (!in->d.line->special)
1415 P_LineOpening (in->d.line);
1418 //S_StartSound (usething, sfx_noway);
1419 return false; // can't use through a wall
1421 return true ; // not a special line, but keep checking
1424 if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
1425 return false; // don't use back sides
1427 P_UseSpecialLine (usething, in->d.line);
1429 return false; // can't use for than one special line in a row
1438 = Looks for special lines in front of the player to activate
1442 void P_UseLines (player_t *player)
1445 fixed_t x1, y1, x2, y2;
1447 usething = player->mo;
1449 angle = player->mo->angle >> ANGLETOFINESHIFT;
1452 x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
1453 y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
1455 P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
1461 ==============================================================================
1465 ==============================================================================
1477 = Source is the creature that casued the explosion at spot
1481 boolean PIT_RadiusAttack (mobj_t *thing)
1483 fixed_t dx, dy, dist;
1485 if(!(thing->flags&MF_SHOOTABLE))
1489 if(thing->type == MT_MINOTAUR || thing->type == MT_SORCERER1
1490 || thing->type == MT_SORCERER2)
1491 { // Episode 2 and 3 bosses take no damage from PIT_RadiusAttack
1494 dx = abs(thing->x - bombspot->x);
1495 dy = abs(thing->y - bombspot->y);
1496 dist = dx > dy ? dx : dy;
1497 dist = (dist - thing->radius) >> FRACBITS;
1502 if(dist >= bombdamage)
1506 if(P_CheckSight(thing, bombspot))
1507 { // OK to damage, target is in direct path
1508 P_DamageMobj(thing, bombspot, bombsource, bombdamage - dist);
1518 = Source is the creature that casued the explosion at spot
1522 void P_RadiusAttack (mobj_t *spot, mobj_t *source, int damage)
1524 int x,y, xl, xh, yl, yh;
1527 dist = (damage+MAXRADIUS)<<FRACBITS;
1528 yh = (spot->y + dist - bmaporgy)>>MAPBLOCKSHIFT;
1529 yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT;
1530 xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT;
1531 xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT;
1533 if(spot->type == MT_POD && spot->target)
1535 bombsource = spot->target;
1539 bombsource = source;
1541 bombdamage = damage;
1542 for (y=yl ; y<=yh ; y++)
1543 for (x=xl ; x<=xh ; x++)
1544 P_BlockThingsIterator (x, y, PIT_RadiusAttack );
1549 ==============================================================================
1551 SECTOR HEIGHT CHANGING
1553 = After modifying a sectors floor or ceiling height, call this
1554 = routine to adjust the positions of all things that touch the
1557 = If anything doesn't fit anymore, true will be returned.
1558 = If crunch is true, they will take damage as they are being crushed
1559 = If Crunch is false, you should set the sector height back the way it
1560 = was and call P_ChangeSector again to undo the changes
1561 ==============================================================================
1564 boolean crushchange;
1575 boolean PIT_ChangeSector (mobj_t *thing)
1579 if (P_ThingHeightClip (thing))
1580 return true; // keep checking
1582 // crunch bodies to giblets
1583 if (thing->health <= 0)
1585 //P_SetMobjState (thing, S_GIBS);
1588 return true; // keep checking
1591 // crunch dropped items
1592 if (thing->flags & MF_DROPPED)
1594 P_RemoveMobj (thing);
1595 return true; // keep checking
1598 if (! (thing->flags & MF_SHOOTABLE) )
1599 return true; // assume it is bloody gibs or something
1602 if (crushchange && !(leveltime&3) )
1604 P_DamageMobj(thing,NULL,NULL,10);
1605 // spray blood in a random direction
1606 mo = P_SpawnMobj (thing->x, thing->y, thing->z + thing->height/2, MT_BLOOD);
1607 mo->momx = (P_Random() - P_Random ())<<12;
1608 mo->momy = (P_Random() - P_Random ())<<12;
1611 return true; // keep checking (crush other things)
1622 boolean P_ChangeSector (sector_t *sector, boolean crunch)
1627 crushchange = crunch;
1629 // recheck heights for all things near the moving sector
1631 for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++)
1632 for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++)
1633 P_BlockThingsIterator (x, y, PIT_ChangeSector);