1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
6 // Copyright (C) 1993-1996 by id Software, Inc.
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
20 // Movement, collision handling.
21 // Shooting and aiming.
23 //-----------------------------------------------------------------------------
26 rcsid[] = "$Id: p_map.c,v 1.5 1997/02/03 22:45:11 b1 Exp $";
51 // If "floatok" true, move would be ok
52 // if within "tmfloorz - tmceilingz".
59 // keep track of the line that lowers the ceiling,
60 // so missiles don't explode against sky hack walls
63 // keep track of special lines as they are hit,
64 // but don't process them until the move is proven valid
65 #define MAXSPECIALCROSS 8
67 line_t* spechit[MAXSPECIALCROSS];
79 boolean PIT_StompThing (mobj_t* thing)
83 if (!(thing->flags & MF_SHOOTABLE) )
86 blockdist = thing->radius + tmthing->radius;
88 if ( abs(thing->x - tmx) >= blockdist
89 || abs(thing->y - tmy) >= blockdist )
95 // don't clip against self
99 // monsters don't stomp things except on boss level
100 if ( !tmthing->player && gamemap != 30)
103 P_DamageMobj (thing, tmthing, tmthing, 10000);
125 subsector_t* newsubsec;
127 // kill anything occupying the position
129 tmflags = thing->flags;
134 tmbbox[BOXTOP] = y + tmthing->radius;
135 tmbbox[BOXBOTTOM] = y - tmthing->radius;
136 tmbbox[BOXRIGHT] = x + tmthing->radius;
137 tmbbox[BOXLEFT] = x - tmthing->radius;
139 newsubsec = R_PointInSubsector (x,y);
142 // The base floor/ceiling is from the subsector
143 // that contains the point.
144 // Any contacted lines the step closer together
146 tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
147 tmceilingz = newsubsec->sector->ceilingheight;
152 // stomp on any things contacted
153 xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
154 xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
155 yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
156 yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
158 for (bx=xl ; bx<=xh ; bx++)
159 for (by=yl ; by<=yh ; by++)
160 if (!P_BlockThingsIterator(bx,by,PIT_StompThing))
164 // so link the thing into its new position
165 P_UnsetThingPosition (thing);
167 thing->floorz = tmfloorz;
168 thing->ceilingz = tmceilingz;
172 P_SetThingPosition (thing);
179 // MOVEMENT ITERATOR FUNCTIONS
185 // Adjusts tmfloorz and tmceilingz as lines are contacted
187 boolean PIT_CheckLine (line_t* ld)
189 if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
190 || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
191 || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
192 || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP] )
195 if (P_BoxOnLineSide (tmbbox, ld) != -1)
198 // A line has been hit
200 // The moving thing's destination position will cross
202 // If this should not be allowed, return false.
203 // If the line is special, keep track of it
204 // to process later if the move is proven ok.
205 // NOTE: specials are NOT sorted by order,
206 // so two special lines that are only 8 pixels apart
207 // could be crossed in either order.
210 return false; // one sided line
212 if (!(tmthing->flags & MF_MISSILE) )
214 if ( ld->flags & ML_BLOCKING )
215 return false; // explicitly blocking everything
217 if ( !tmthing->player && ld->flags & ML_BLOCKMONSTERS )
218 return false; // block monsters only
221 // set openrange, opentop, openbottom
224 // adjust floor / ceiling heights
225 if (opentop < tmceilingz)
227 tmceilingz = opentop;
231 if (openbottom > tmfloorz)
232 tmfloorz = openbottom;
234 if (lowfloor < tmdropoffz)
235 tmdropoffz = lowfloor;
237 // if contacted a special line, add it to the list
240 spechit[numspechit] = ld;
250 boolean PIT_CheckThing (mobj_t* thing)
256 if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE) ))
259 blockdist = thing->radius + tmthing->radius;
261 if ( abs(thing->x - tmx) >= blockdist
262 || abs(thing->y - tmy) >= blockdist )
268 // don't clip against self
269 if (thing == tmthing)
272 // check for skulls slamming into things
273 if (tmthing->flags & MF_SKULLFLY)
275 damage = ((P_Random()%8)+1)*tmthing->info->damage;
277 P_DamageMobj (thing, tmthing, tmthing, damage);
279 tmthing->flags &= ~MF_SKULLFLY;
280 tmthing->momx = tmthing->momy = tmthing->momz = 0;
282 P_SetMobjState (tmthing, tmthing->info->spawnstate);
284 return false; // stop moving
288 // missiles can hit other things
289 if (tmthing->flags & MF_MISSILE)
291 // see if it went over / under
292 if (tmthing->z > thing->z + thing->height)
293 return true; // overhead
294 if (tmthing->z+tmthing->height < thing->z)
295 return true; // underneath
297 if (tmthing->target && (
298 tmthing->target->type == thing->type ||
299 (tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER)||
300 (tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT) ) )
302 // Don't hit same species as originator.
303 if (thing == tmthing->target)
306 if (thing->type != MT_PLAYER)
308 // Explode, but do no damage.
309 // Let players missile other players.
314 if (! (thing->flags & MF_SHOOTABLE) )
316 // didn't do any damage
317 return !(thing->flags & MF_SOLID);
321 damage = ((P_Random()%8)+1)*tmthing->info->damage;
322 P_DamageMobj (thing, tmthing, tmthing->target, damage);
324 // don't traverse any more
328 // check for special pickup
329 if (thing->flags & MF_SPECIAL)
331 solid = thing->flags&MF_SOLID;
332 if (tmflags&MF_PICKUP)
335 P_TouchSpecialThing (thing, tmthing);
340 return !(thing->flags & MF_SOLID);
350 // This is purely informative, nothing is modified
351 // (except things picked up).
354 // a mobj_t (can be valid or invalid)
355 // a position to be checked
356 // (doesn't need to be related to the mobj_t->x,y)
359 // special things are touched if MF_PICKUP
360 // early out on solid lines?
367 // the lowest point contacted
368 // (monsters won't move to a dropoff)
384 subsector_t* newsubsec;
387 tmflags = thing->flags;
392 tmbbox[BOXTOP] = y + tmthing->radius;
393 tmbbox[BOXBOTTOM] = y - tmthing->radius;
394 tmbbox[BOXRIGHT] = x + tmthing->radius;
395 tmbbox[BOXLEFT] = x - tmthing->radius;
397 newsubsec = R_PointInSubsector (x,y);
400 // The base floor / ceiling is from the subsector
401 // that contains the point.
402 // Any contacted lines the step closer together
404 tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
405 tmceilingz = newsubsec->sector->ceilingheight;
410 if ( tmflags & MF_NOCLIP )
413 // Check things first, possibly picking things up.
414 // The bounding box is extended by MAXRADIUS
415 // because mobj_ts are grouped into mapblocks
416 // based on their origin point, and can overlap
417 // into adjacent blocks by up to MAXRADIUS units.
418 xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
419 xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
420 yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
421 yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
423 for (bx=xl ; bx<=xh ; bx++)
424 for (by=yl ; by<=yh ; by++)
425 if (!P_BlockThingsIterator(bx,by,PIT_CheckThing))
429 xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
430 xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
431 yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
432 yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
434 for (bx=xl ; bx<=xh ; bx++)
435 for (by=yl ; by<=yh ; by++)
436 if (!P_BlockLinesIterator (bx,by,PIT_CheckLine))
445 // Attempt to move to a new position,
446 // crossing special lines unless MF_TELEPORT is set.
461 if (!P_CheckPosition (thing, x, y))
462 return false; // solid wall or thing
464 if ( !(thing->flags & MF_NOCLIP) )
466 if (tmceilingz - tmfloorz < thing->height)
467 return false; // doesn't fit
471 if ( !(thing->flags&MF_TELEPORT)
472 &&tmceilingz - thing->z < thing->height)
473 return false; // mobj must lower itself to fit
475 if ( !(thing->flags&MF_TELEPORT)
476 && tmfloorz - thing->z > 24*FRACUNIT )
477 return false; // too big a step up
479 if ( !(thing->flags&(MF_DROPOFF|MF_FLOAT))
480 && tmfloorz - tmdropoffz > 24*FRACUNIT )
481 return false; // don't stand over a dropoff
485 // so link the thing into its new position
486 P_UnsetThingPosition (thing);
490 thing->floorz = tmfloorz;
491 thing->ceilingz = tmceilingz;
495 P_SetThingPosition (thing);
497 // if any special lines were hit, do the effect
498 if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) )
502 // see if the line was crossed
503 ld = spechit[numspechit];
504 side = P_PointOnLineSide (thing->x, thing->y, ld);
505 oldside = P_PointOnLineSide (oldx, oldy, ld);
509 P_CrossSpecialLine (ld-lines, oldside, thing);
520 // Takes a valid thing and adjusts the thing->floorz,
521 // thing->ceilingz, and possibly thing->z.
522 // This is called for all nearby monsters
523 // whenever a sector changes height.
524 // If the thing doesn't fit,
525 // the z will be set to the lowest value
526 // and false will be returned.
528 boolean P_ThingHeightClip (mobj_t* thing)
532 onfloor = (thing->z == thing->floorz);
534 P_CheckPosition (thing, thing->x, thing->y);
535 // what about stranding a monster partially off an edge?
537 thing->floorz = tmfloorz;
538 thing->ceilingz = tmceilingz;
542 // walking monsters rise and fall with the floor
543 thing->z = thing->floorz;
547 // don't adjust a floating monster unless forced to
548 if (thing->z+thing->height > thing->ceilingz)
549 thing->z = thing->ceilingz - thing->height;
552 if (thing->ceilingz - thing->floorz < thing->height)
562 // Allows the player to slide along any angled walls.
564 fixed_t bestslidefrac;
565 fixed_t secondslidefrac;
567 line_t* bestslideline;
568 line_t* secondslideline;
579 // Adjusts the xmove / ymove
580 // so that the next move will slide along the wall.
582 void P_HitSlideLine (line_t* ld)
594 if (ld->slopetype == ST_HORIZONTAL)
600 if (ld->slopetype == ST_VERTICAL)
606 side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
608 lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy);
613 moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove);
614 deltaangle = moveangle-lineangle;
616 if (deltaangle > ANG180)
617 deltaangle += ANG180;
618 // I_Error ("SlideLine: ang>ANG180");
620 lineangle >>= ANGLETOFINESHIFT;
621 deltaangle >>= ANGLETOFINESHIFT;
623 movelen = P_AproxDistance (tmxmove, tmymove);
624 newlen = FixedMul (movelen, finecosine[deltaangle]);
626 tmxmove = FixedMul (newlen, finecosine[lineangle]);
627 tmymove = FixedMul (newlen, finesine[lineangle]);
634 boolean PTR_SlideTraverse (intercept_t* in)
639 I_Error ("PTR_SlideTraverse: not a line?");
643 if ( ! (li->flags & ML_TWOSIDED) )
645 if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
647 // don't hit the back side
653 // set openrange, opentop, openbottom
656 if (openrange < slidemo->height)
657 goto isblocking; // doesn't fit
659 if (opentop - slidemo->z < slidemo->height)
660 goto isblocking; // mobj is too high
662 if (openbottom - slidemo->z > 24*FRACUNIT )
663 goto isblocking; // too big a step up
665 // this line doesn't block movement
668 // the line does block movement,
669 // see if it is closer than best so far
671 if (in->frac < bestslidefrac)
673 secondslidefrac = bestslidefrac;
674 secondslideline = bestslideline;
675 bestslidefrac = in->frac;
679 return false; // stop
686 // The momx / momy move is bad, so try to slide
688 // Find the first line hit, move flush to it,
689 // and slide along it
691 // This is a kludgy mess.
693 void P_SlideMove (mobj_t* mo)
708 goto stairstep; // don't loop forever
711 // trace along the three leading corners
714 leadx = mo->x + mo->radius;
715 trailx = mo->x - mo->radius;
719 leadx = mo->x - mo->radius;
720 trailx = mo->x + mo->radius;
725 leady = mo->y + mo->radius;
726 traily = mo->y - mo->radius;
730 leady = mo->y - mo->radius;
731 traily = mo->y + mo->radius;
734 bestslidefrac = FRACUNIT+1;
736 P_PathTraverse ( leadx, leady, leadx+mo->momx, leady+mo->momy,
737 PT_ADDLINES, PTR_SlideTraverse );
738 P_PathTraverse ( trailx, leady, trailx+mo->momx, leady+mo->momy,
739 PT_ADDLINES, PTR_SlideTraverse );
740 P_PathTraverse ( leadx, traily, leadx+mo->momx, traily+mo->momy,
741 PT_ADDLINES, PTR_SlideTraverse );
743 // move up to the wall
744 if (bestslidefrac == FRACUNIT+1)
746 // the move most have hit the middle, so stairstep
748 if (!P_TryMove (mo, mo->x, mo->y + mo->momy))
749 P_TryMove (mo, mo->x + mo->momx, mo->y);
753 // fudge a bit to make sure it doesn't hit
754 bestslidefrac -= 0x800;
755 if (bestslidefrac > 0)
757 newx = FixedMul (mo->momx, bestslidefrac);
758 newy = FixedMul (mo->momy, bestslidefrac);
760 if (!P_TryMove (mo, mo->x+newx, mo->y+newy))
764 // Now continue along the wall.
765 // First calculate remainder.
766 bestslidefrac = FRACUNIT-(bestslidefrac+0x800);
768 if (bestslidefrac > FRACUNIT)
769 bestslidefrac = FRACUNIT;
771 if (bestslidefrac <= 0)
774 tmxmove = FixedMul (mo->momx, bestslidefrac);
775 tmymove = FixedMul (mo->momy, bestslidefrac);
777 P_HitSlideLine (bestslideline); // clip the moves
782 if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove))
792 mobj_t* linetarget; // who got hit (or NULL)
795 // Height if not aiming up or down
796 // ???: use slope for monsters?
804 // slopes to top and bottom of target
805 extern fixed_t topslope;
806 extern fixed_t bottomslope;
811 // Sets linetaget and aimslope when a target is aimed at.
814 PTR_AimTraverse (intercept_t* in)
819 fixed_t thingtopslope;
820 fixed_t thingbottomslope;
827 if ( !(li->flags & ML_TWOSIDED) )
828 return false; // stop
830 // Crosses a two sided line.
831 // A two sided line will restrict
832 // the possible target ranges.
835 if (openbottom >= opentop)
836 return false; // stop
838 dist = FixedMul (attackrange, in->frac);
840 if (li->frontsector->floorheight != li->backsector->floorheight)
842 slope = FixedDiv (openbottom - shootz , dist);
843 if (slope > bottomslope)
847 if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
849 slope = FixedDiv (opentop - shootz , dist);
850 if (slope < topslope)
854 if (topslope <= bottomslope)
855 return false; // stop
857 return true; // shot continues
862 if (th == shootthing)
863 return true; // can't shoot self
865 if (!(th->flags&MF_SHOOTABLE))
866 return true; // corpse or something
868 // check angles to see if the thing can be aimed at
869 dist = FixedMul (attackrange, in->frac);
870 thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
872 if (thingtopslope < bottomslope)
873 return true; // shot over the thing
875 thingbottomslope = FixedDiv (th->z - shootz, dist);
877 if (thingbottomslope > topslope)
878 return true; // shot under the thing
880 // this thing can be hit!
881 if (thingtopslope > topslope)
882 thingtopslope = topslope;
884 if (thingbottomslope < bottomslope)
885 thingbottomslope = bottomslope;
887 aimslope = (thingtopslope+thingbottomslope)/2;
890 return false; // don't go any farther
897 boolean PTR_ShootTraverse (intercept_t* in)
910 fixed_t thingtopslope;
911 fixed_t thingbottomslope;
918 P_ShootSpecialLine (shootthing, li);
920 if ( !(li->flags & ML_TWOSIDED) )
923 // crosses a two sided line
926 dist = FixedMul (attackrange, in->frac);
928 if (li->frontsector->floorheight != li->backsector->floorheight)
930 slope = FixedDiv (openbottom - shootz , dist);
931 if (slope > aimslope)
935 if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
937 slope = FixedDiv (opentop - shootz , dist);
938 if (slope < aimslope)
948 // position a bit closer
949 frac = in->frac - FixedDiv (4*FRACUNIT,attackrange);
950 x = trace.x + FixedMul (trace.dx, frac);
951 y = trace.y + FixedMul (trace.dy, frac);
952 z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
954 if (li->frontsector->ceilingpic == skyflatnum)
956 // don't shoot the sky!
957 if (z > li->frontsector->ceilingheight)
960 // it's a sky hack wall
961 if (li->backsector && li->backsector->ceilingpic == skyflatnum)
965 // Spawn bullet puffs.
968 // don't go any farther
974 if (th == shootthing)
975 return true; // can't shoot self
977 if (!(th->flags&MF_SHOOTABLE))
978 return true; // corpse or something
980 // check angles to see if the thing can be aimed at
981 dist = FixedMul (attackrange, in->frac);
982 thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
984 if (thingtopslope < aimslope)
985 return true; // shot over the thing
987 thingbottomslope = FixedDiv (th->z - shootz, dist);
989 if (thingbottomslope > aimslope)
990 return true; // shot under the thing
994 // position a bit closer
995 frac = in->frac - FixedDiv (10*FRACUNIT,attackrange);
997 x = trace.x + FixedMul (trace.dx, frac);
998 y = trace.y + FixedMul (trace.dy, frac);
999 z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
1001 // Spawn bullet puffs or blod spots,
1002 // depending on target type.
1003 if (in->d.thing->flags & MF_NOBLOOD)
1004 P_SpawnPuff (x,y,z);
1006 P_SpawnBlood (x,y,z, la_damage);
1009 P_DamageMobj (th, shootthing, shootthing, la_damage);
1011 // don't go any farther
1029 angle >>= ANGLETOFINESHIFT;
1032 x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
1033 y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
1034 shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
1036 // can't shoot outside view angles
1037 topslope = 100*FRACUNIT/160;
1038 bottomslope = -100*FRACUNIT/160;
1040 attackrange = distance;
1043 P_PathTraverse ( t1->x, t1->y,
1045 PT_ADDLINES|PT_ADDTHINGS,
1057 // If damage == 0, it is just a test trace
1058 // that will leave linetarget set.
1071 angle >>= ANGLETOFINESHIFT;
1074 x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
1075 y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
1076 shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
1077 attackrange = distance;
1080 P_PathTraverse ( t1->x, t1->y,
1082 PT_ADDLINES|PT_ADDTHINGS,
1083 PTR_ShootTraverse );
1093 boolean PTR_UseTraverse (intercept_t* in)
1097 if (!in->d.line->special)
1099 P_LineOpening (in->d.line);
1102 S_StartSound (usething, sfx_noway);
1104 // can't use through a wall
1107 // not a special line, but keep checking
1112 if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
1115 // return false; // don't use back side
1117 P_UseSpecialLine (usething, in->d.line, side);
1119 // can't use for than one special line in a row
1126 // Looks for special lines in front of the player to activate.
1128 void P_UseLines (player_t* player)
1136 usething = player->mo;
1138 angle = player->mo->angle >> ANGLETOFINESHIFT;
1142 x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
1143 y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
1145 P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
1159 // "bombsource" is the creature
1160 // that caused the explosion at "bombspot".
1162 boolean PIT_RadiusAttack (mobj_t* thing)
1168 if (!(thing->flags & MF_SHOOTABLE) )
1171 // Boss spider and cyborg
1172 // take no damage from concussion.
1173 if (thing->type == MT_CYBORG
1174 || thing->type == MT_SPIDER)
1177 dx = abs(thing->x - bombspot->x);
1178 dy = abs(thing->y - bombspot->y);
1180 dist = dx>dy ? dx : dy;
1181 dist = (dist - thing->radius) >> FRACBITS;
1186 if (dist >= bombdamage)
1187 return true; // out of range
1189 if ( P_CheckSight (thing, bombspot) )
1191 // must be in direct path
1192 P_DamageMobj (thing, bombspot, bombsource, bombdamage - dist);
1201 // Source is the creature that caused the explosion at spot.
1219 dist = (damage+MAXRADIUS)<<FRACBITS;
1220 yh = (spot->y + dist - bmaporgy)>>MAPBLOCKSHIFT;
1221 yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT;
1222 xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT;
1223 xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT;
1225 bombsource = source;
1226 bombdamage = damage;
1228 for (y=yl ; y<=yh ; y++)
1229 for (x=xl ; x<=xh ; x++)
1230 P_BlockThingsIterator (x, y, PIT_RadiusAttack );
1236 // SECTOR HEIGHT CHANGING
1237 // After modifying a sectors floor or ceiling height,
1238 // call this routine to adjust the positions
1239 // of all things that touch the sector.
1241 // If anything doesn't fit anymore, true will be returned.
1242 // If crunch is true, they will take damage
1243 // as they are being crushed.
1244 // If Crunch is false, you should set the sector height back
1245 // the way it was and call P_ChangeSector again
1246 // to undo the changes.
1248 boolean crushchange;
1255 boolean PIT_ChangeSector (mobj_t* thing)
1259 if (P_ThingHeightClip (thing))
1266 // crunch bodies to giblets
1267 if (thing->health <= 0)
1269 P_SetMobjState (thing, S_GIBS);
1271 thing->flags &= ~MF_SOLID;
1279 // crunch dropped items
1280 if (thing->flags & MF_DROPPED)
1282 P_RemoveMobj (thing);
1288 if (! (thing->flags & MF_SHOOTABLE) )
1290 // assume it is bloody gibs or something
1296 if (crushchange && !(leveltime&3) )
1298 P_DamageMobj(thing,NULL,NULL,10);
1300 // spray blood in a random direction
1301 mo = P_SpawnMobj (thing->x,
1303 thing->z + thing->height/2, MT_BLOOD);
1305 mo->momx = P_Random2()<<12;
1306 mo->momy = P_Random2()<<12;
1309 // keep checking (crush other things)
1327 crushchange = crunch;
1329 // re-check heights for all things near the moving sector
1330 for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++)
1331 for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++)
1332 P_BlockThingsIterator (x, y, PIT_ChangeSector);