1 /* P_map.c */
2 
3 #include "doomdef.h"
4 #include "p_local.h"
5 #include "soundst.h"
6 
7 #ifdef GL_HERETIC
8 #include "gl_struct.h"
9 #endif
10 
11 /*
12   ===============================================================================
13 
14   NOTES:
15 
16 
17   ===============================================================================
18 */
19 
20 /*
21   ===============================================================================
22 
23   mobj_t NOTES
24 
25   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.
26 
27   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.
28 
29   The sound code uses the x,y, and subsector fields to do stereo positioning of any sound effited by the mobj_t.
30 
31   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.
32 
33 
34   Every mobj_t is linked into a single sector based on it's origin coordinates.
35   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.
36 
37   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.
38 
39   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.
40 
41 
42   ===============================================================================
43 */
44 
45 fixed_t		tmbbox[4];
46 mobj_t		*tmthing;
47 int		tmflags;
48 fixed_t		tmx, tmy;
49 
50 boolean		floatok;	    /* if true, move would be ok if */
51 /* within tmfloorz - tmceilingz */
52 
53 fixed_t		tmfloorz, tmceilingz, tmdropoffz;
54 
55 /* keep track of the line that lowers the ceiling, so missiles don't explode */
56 /* against sky hack walls */
57 line_t		*ceilingline;
58 
59 /* keep track of special lines as they are hit, but don't process them */
60 /* until the move is proven valid */
61 #define	MAXSPECIALCROSS		8
62 line_t	        *spechit[MAXSPECIALCROSS];
63 int		numspechit;
64 
65 mobj_t *onmobj; /* generic global onmobj...used for landing on pods/players */
66 
67 /*
68   ===============================================================================
69 
70   TELEPORT MOVE
71 
72   ===============================================================================
73 */
74 
75 /*
76   ==================
77   =
78   = PIT_StompThing
79   =
80   ==================
81 */
82 
PIT_StompThing(mobj_t * thing)83 boolean PIT_StompThing (mobj_t *thing)
84 {
85   fixed_t		blockdist;
86 
87   if (!(thing->flags & MF_SHOOTABLE) )
88     return true;
89 
90   blockdist = thing->radius + tmthing->radius;
91   if ( abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist )
92     return true;		/* didn't hit it */
93 
94   if (thing == tmthing)
95     return true;		/* don't clip against self */
96 
97   if(!(tmthing->flags2&MF2_TELESTOMP))
98     { /* Not allowed to stomp things */
99       return(false);
100     }
101 
102   P_DamageMobj (thing, tmthing, tmthing, 10000);
103 
104   return true;
105 }
106 
107 
108 /*
109   ===================
110   =
111   = P_TeleportMove
112   =
113   ===================
114 */
115 
P_TeleportMove(mobj_t * thing,fixed_t x,fixed_t y)116 boolean P_TeleportMove (mobj_t *thing, fixed_t x, fixed_t y)
117 {
118   int			xl,xh,yl,yh,bx,by;
119   subsector_t		*newsubsec;
120 
121   /*
122    * kill anything occupying the position
123    */
124 
125   tmthing = thing;
126   tmflags = thing->flags;
127 
128   tmx = x;
129   tmy = y;
130 
131   tmbbox[BOXTOP] = y + tmthing->radius;
132   tmbbox[BOXBOTTOM] = y - tmthing->radius;
133   tmbbox[BOXRIGHT] = x + tmthing->radius;
134   tmbbox[BOXLEFT] = x - tmthing->radius;
135 
136   newsubsec = R_PointInSubsector (x,y);
137   ceilingline = NULL;
138 
139   /*
140    * the base floor / ceiling is from the subsector that contains the
141    * point.  Any contacted lines the step closer together will adjust them
142    */
143   tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
144   tmceilingz = newsubsec->sector->ceilingheight;
145 
146   validcount++;
147   numspechit = 0;
148 
149   /*
150    * stomp on any things contacted
151    */
152   xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
153   xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
154   yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
155   yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
156 
157   for (bx=xl ; bx<=xh ; bx++)
158     for (by=yl ; by<=yh ; by++)
159       if (!P_BlockThingsIterator(bx,by,PIT_StompThing))
160 	return false;
161 
162   /*
163    * the move is ok, so link the thing into its new position
164    */
165   P_UnsetThingPosition (thing);
166 
167   thing->floorz = tmfloorz;
168   thing->ceilingz = tmceilingz;
169   thing->x = x;
170   thing->y = y;
171 
172   P_SetThingPosition (thing);
173 
174   return true;
175 }
176 
177 /*
178   ===============================================================================
179 
180   MOVEMENT ITERATOR FUNCTIONS
181 
182   ===============================================================================
183 */
184 
185 /*
186   ==================
187   =
188   = PIT_CheckLine
189   =
190   = Adjusts tmfloorz and tmceilingz as lines are contacted
191   ==================
192 */
193 
PIT_CheckLine(line_t * ld)194 boolean PIT_CheckLine(line_t *ld)
195 {
196   if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
197       ||	tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
198       ||	tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
199       ||	tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
200     {
201       return(true);
202     }
203   if(P_BoxOnLineSide(tmbbox, ld) != -1)
204     {
205       return(true);
206     }
207 
208   /* a line has been hit */
209   /*
210     =
211     = The moving thing's destination position will cross the given line.
212     = If this should not be allowed, return false.
213     = If the line is special, keep track of it to process later if the move
214     = 	is proven ok.  NOTE: specials are NOT sorted by order, so two special lines
215     = 	that are only 8 pixels apart could be crossed in either order.
216   */
217 
218   if(!ld->backsector)
219     { /* One sided line */
220       if(tmthing->flags&MF_MISSILE)
221 	{ /* Missiles can trigger impact specials */
222 	  if(ld->special)
223 	    {
224 	      spechit[numspechit] = ld;
225 	      numspechit++;
226 	    }
227 	}
228       return false;
229     }
230   if(!(tmthing->flags&MF_MISSILE))
231     {
232       if(ld->flags&ML_BLOCKING)
233 	{ /* Explicitly blocking everything */
234 	  return(false);
235 	}
236       if(!tmthing->player && ld->flags&ML_BLOCKMONSTERS
237 	 && tmthing->type != MT_POD)
238 	{ /* Block monsters only */
239 	  return(false);
240 	}
241     }
242   P_LineOpening(ld);		/* set openrange, opentop, openbottom */
243   /* adjust floor / ceiling heights */
244   if(opentop < tmceilingz)
245     {
246       tmceilingz = opentop;
247       ceilingline = ld;
248     }
249   if(openbottom > tmfloorz)
250     {
251       tmfloorz = openbottom;
252     }
253   if(lowfloor < tmdropoffz)
254     {
255       tmdropoffz = lowfloor;
256     }
257   if(ld->special)
258     { /* Contacted a special line, add it to the list */
259       spechit[numspechit] = ld;
260       numspechit++;
261     }
262   return(true);
263 }
264 
265 /*
266   //---------------------------------------------------------------------------
267   //
268   // FUNC PIT_CheckThing
269   //
270   //---------------------------------------------------------------------------
271 */
PIT_CheckThing(mobj_t * thing)272 boolean PIT_CheckThing(mobj_t *thing)
273 {
274   fixed_t blockdist;
275   boolean solid;
276   int damage;
277 
278   if(!(thing->flags&(MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
279     { /* Can't hit thing */
280       return(true);
281     }
282   blockdist = thing->radius+tmthing->radius;
283   if(abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist)
284     { /* Didn't hit thing */
285       return(true);
286     }
287   if(thing == tmthing)
288     { /* Don't clip against self */
289       return(true);
290     }
291   if(tmthing->flags2&MF2_PASSMOBJ)
292     { /* check if a mobj passed over/under another object */
293       if((tmthing->type == MT_IMP || tmthing->type == MT_WIZARD)
294 	 && (thing->type == MT_IMP || thing->type == MT_WIZARD))
295 	{ /* don't let imps/wizards fly over other imps/wizards */
296 	  return false;
297 	}
298       if(tmthing->z > thing->z+thing->height
299 	 && !(thing->flags&MF_SPECIAL))
300 	{
301 	  return(true);
302 	}
303       else if(tmthing->z+tmthing->height < thing->z
304 	      && !(thing->flags&MF_SPECIAL))
305 	{ /* under thing */
306 	  return(true);
307 	}
308     }
309   /* Check for skulls slamming into things */
310   if(tmthing->flags&MF_SKULLFLY)
311     {
312       damage = ((P_Random()%8)+1)*tmthing->damage;
313       P_DamageMobj(thing, tmthing, tmthing, damage);
314       tmthing->flags &= ~MF_SKULLFLY;
315       tmthing->momx = tmthing->momy = tmthing->momz = 0;
316       P_SetMobjState(tmthing, tmthing->info->seestate);
317       return(false);
318     }
319   /* Check for missile */
320   if(tmthing->flags&MF_MISSILE)
321     {
322       /* Check for passing through a ghost */
323       if((thing->flags&MF_SHADOW) && (tmthing->flags2&MF2_THRUGHOST))
324 	{
325 	  return(true);
326 	}
327       /* Check if it went over / under */
328       if(tmthing->z > thing->z+thing->height)
329 	{ /* Over thing */
330 	  return(true);
331 	}
332       if(tmthing->z+tmthing->height < thing->z)
333 	{ /* Under thing */
334 	  return(true);
335 	}
336       if(tmthing->target && tmthing->target->type == thing->type)
337 	{ /* Don't hit same species as originator */
338 	  if(thing == tmthing->target)
339 	    { /* Don't missile self */
340 	      return(true);
341 	    }
342 	  if(thing->type != MT_PLAYER)
343 	    { /* Hit same species as originator, explode, no damage */
344 	      return(false);
345 	    }
346 	}
347       if(!(thing->flags&MF_SHOOTABLE))
348 	{ /* Didn't do any damage */
349 	  return!(thing->flags&MF_SOLID);
350 	}
351       if(tmthing->flags2&MF2_RIP)
352 	{
353 	  if(!(thing->flags&MF_NOBLOOD))
354 	    { /* Ok to spawn some blood */
355 	      P_RipperBlood(tmthing);
356 	    }
357 	  S_StartSound(tmthing, sfx_ripslop);
358 	  damage = ((P_Random()&3)+2)*tmthing->damage;
359 	  P_DamageMobj(thing, tmthing, tmthing->target, damage);
360 	  if(thing->flags2&MF2_PUSHABLE
361 	     && !(tmthing->flags2&MF2_CANNOTPUSH))
362 	    { /* Push thing */
363 	      thing->momx += tmthing->momx>>2;
364 	      thing->momy += tmthing->momy>>2;
365 	    }
366 	  numspechit = 0;
367 	  return(true);
368 	}
369       /* Do damage */
370       damage = ((P_Random()%8)+1)*tmthing->damage;
371       if(damage)
372 	{
373 	  if(!(thing->flags&MF_NOBLOOD) && P_Random() < 192)
374 	    {
375 	      P_BloodSplatter(tmthing->x, tmthing->y, tmthing->z, thing);
376 #ifdef GL_HERETIC
377 	      GL_CheckForBloodSplash(tmthing->x,tmthing->y,tmthing->z,damage);
378 #endif
379 	    }
380 	  P_DamageMobj(thing, tmthing, tmthing->target, damage);
381 	}
382       return(false);
383     }
384   if(thing->flags2&MF2_PUSHABLE && !(tmthing->flags2&MF2_CANNOTPUSH))
385     { /* Push thing */
386       thing->momx += tmthing->momx>>2;
387       thing->momy += tmthing->momy>>2;
388     }
389   /* Check for special thing */
390   if(thing->flags&MF_SPECIAL)
391     {
392       solid = thing->flags&MF_SOLID;
393       if(tmflags&MF_PICKUP)
394 	{ /* Can be picked up by tmthing */
395 	  P_TouchSpecialThing(thing, tmthing); /* Can remove thing */
396 	}
397       return(!solid);
398     }
399   return(!(thing->flags&MF_SOLID));
400 }
401 
402 /*
403   //---------------------------------------------------------------------------
404   //
405   // PIT_CheckOnmobjZ
406   //
407   //---------------------------------------------------------------------------
408 */
PIT_CheckOnmobjZ(mobj_t * thing)409 boolean PIT_CheckOnmobjZ(mobj_t *thing)
410 {
411   fixed_t blockdist;
412 
413   if(!(thing->flags&(MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
414     { /* Can't hit thing */
415       return(true);
416     }
417   blockdist = thing->radius+tmthing->radius;
418   if(abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist)
419     { /* Didn't hit thing */
420       return(true);
421     }
422   if(thing == tmthing)
423     { /* Don't clip against self */
424       return(true);
425     }
426   if(tmthing->z > thing->z+thing->height)
427     {
428       return(true);
429     }
430   else if(tmthing->z+tmthing->height < thing->z)
431     { /* under thing */
432       return(true);
433     }
434   if(thing->flags&MF_SOLID)
435     {
436       onmobj = thing;
437     }
438   return(!(thing->flags&MF_SOLID));
439 }
440 
441 /*
442   ===============================================================================
443 
444   MOVEMENT CLIPPING
445 
446   ===============================================================================
447 */
448 
449 /*
450   //----------------------------------------------------------------------------
451   //
452   // FUNC P_TestMobjLocation
453   //
454   // Returns true if the mobj is not blocked by anything at its current
455   // location, otherwise returns false.
456   //
457   //----------------------------------------------------------------------------
458 */
P_TestMobjLocation(mobj_t * mobj)459 boolean P_TestMobjLocation(mobj_t *mobj)
460 {
461   int flags;
462 
463   flags = mobj->flags;
464   mobj->flags &= ~MF_PICKUP;
465   if(P_CheckPosition(mobj, mobj->x, mobj->y))
466     { /* XY is ok, now check Z */
467       mobj->flags = flags;
468       if((mobj->z < mobj->floorz)
469 	 || (mobj->z+mobj->height > mobj->ceilingz))
470 	{ /* Bad Z */
471 	  return(false);
472 	}
473       return(true);
474     }
475   mobj->flags = flags;
476   return(false);
477 }
478 
479 /*
480   ==================
481   =
482   = P_CheckPosition
483   =
484   = This is purely informative, nothing is modified (except things picked up)
485 
486   in:
487   a mobj_t (can be valid or invalid)
488   a position to be checked (doesn't need to be related to the mobj_t->x,y)
489 
490   during:
491   special things are touched if MF_PICKUP
492   early out on solid lines?
493 
494   out:
495   newsubsec
496   floorz
497   ceilingz
498   tmdropoffz		the lowest point contacted (monsters won't move to a dropoff)
499   speciallines[]
500   numspeciallines
501 
502   ==================
503 */
504 
P_CheckPosition(mobj_t * thing,fixed_t x,fixed_t y)505 boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y)
506 {
507   int			xl,xh,yl,yh,bx,by;
508   subsector_t		*newsubsec;
509 
510   tmthing = thing;
511   tmflags = thing->flags;
512 
513   tmx = x;
514   tmy = y;
515 
516   tmbbox[BOXTOP] = y + tmthing->radius;
517   tmbbox[BOXBOTTOM] = y - tmthing->radius;
518   tmbbox[BOXRIGHT] = x + tmthing->radius;
519   tmbbox[BOXLEFT] = x - tmthing->radius;
520 
521   newsubsec = R_PointInSubsector (x,y);
522   ceilingline = NULL;
523 
524   /*
525    * the base floor / ceiling is from the subsector that contains the
526    * point.  Any contacted lines the step closer together will adjust them
527    */
528   tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
529   tmceilingz = newsubsec->sector->ceilingheight;
530 
531   validcount++;
532   numspechit = 0;
533 
534   if ( tmflags & MF_NOCLIP )
535     return true;
536 
537   /*
538    * check things first, possibly picking things up
539    * the bounding box is extended by MAXRADIUS because mobj_ts are grouped
540    * into mapblocks based on their origin point, and can overlap into adjacent
541    * blocks by up to MAXRADIUS units
542    */
543   xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
544   xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
545   yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
546   yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
547 
548   for (bx=xl ; bx<=xh ; bx++)
549     for (by=yl ; by<=yh ; by++)
550       if (!P_BlockThingsIterator(bx,by,PIT_CheckThing))
551 	return false;
552   /*
553    * check lines
554    */
555   xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
556   xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
557   yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
558   yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
559 
560   for (bx=xl ; bx<=xh ; bx++)
561     for (by=yl ; by<=yh ; by++)
562       if (!P_BlockLinesIterator (bx,by,PIT_CheckLine))
563 	return false;
564 
565   return true;
566 }
567 
568 /*
569   //=============================================================================
570   //
571   // P_CheckOnmobj(mobj_t *thing)
572   //
573   // 		Checks if the new Z position is legal
574   //=============================================================================
575 */
P_CheckOnmobj(mobj_t * thing)576 mobj_t *P_CheckOnmobj(mobj_t *thing)
577 {
578   int			xl,xh,yl,yh,bx,by;
579   subsector_t		*newsubsec;
580   fixed_t               x;
581   fixed_t               y;
582   mobj_t                oldmo;
583 
584   x = thing->x;
585   y = thing->y;
586   tmthing = thing;
587   tmflags = thing->flags;
588   oldmo = *thing; /* save the old mobj before the fake zmovement */
589   P_FakeZMovement(tmthing);
590 
591   tmx = x;
592   tmy = y;
593 
594   tmbbox[BOXTOP] = y + tmthing->radius;
595   tmbbox[BOXBOTTOM] = y - tmthing->radius;
596   tmbbox[BOXRIGHT] = x + tmthing->radius;
597   tmbbox[BOXLEFT] = x - tmthing->radius;
598 
599   newsubsec = R_PointInSubsector (x,y);
600   ceilingline = NULL;
601 
602   /*
603    * the base floor / ceiling is from the subsector that contains the
604    * point.  Any contacted lines the step closer together will adjust them
605    */
606   tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
607   tmceilingz = newsubsec->sector->ceilingheight;
608 
609   validcount++;
610   numspechit = 0;
611 
612   if ( tmflags & MF_NOCLIP )
613     return NULL;
614 
615   /*
616    * check things first, possibly picking things up
617    * the bounding box is extended by MAXRADIUS because mobj_ts are grouped
618    * into mapblocks based on their origin point, and can overlap into adjacent
619    * blocks by up to MAXRADIUS units
620    */
621   xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
622   xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
623   yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
624   yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
625 
626   for (bx=xl ; bx<=xh ; bx++)
627     for (by=yl ; by<=yh ; by++)
628       if (!P_BlockThingsIterator(bx,by,PIT_CheckOnmobjZ))
629 	{
630 	  *tmthing = oldmo;
631 	  return onmobj;
632 	}
633   *tmthing = oldmo;
634   return NULL;
635 }
636 
637 /*
638   //=============================================================================
639   //
640   // P_FakeZMovement
641   //
642   // 		Fake the zmovement so that we can check if a move is legal
643   //=============================================================================
644 */
P_FakeZMovement(mobj_t * mo)645 void P_FakeZMovement(mobj_t *mo)
646 {
647   int dist;
648   int delta;
649   /*
650    * adjust height
651    */
652   mo->z += mo->momz;
653   if(mo->flags&MF_FLOAT && mo->target)
654     {	/* float down towards target if too close */
655       if(!(mo->flags&MF_SKULLFLY) && !(mo->flags&MF_INFLOAT))
656 	{
657 	  dist = P_AproxDistance(mo->x-mo->target->x, mo->y-mo->target->y);
658 	  delta =( mo->target->z+(mo->height>>1))-mo->z;
659 	  if (delta < 0 && dist < -(delta*3))
660 	    mo->z -= FLOATSPEED;
661 	  else if (delta > 0 && dist < (delta*3))
662 	    mo->z += FLOATSPEED;
663 	}
664     }
665   if(mo->player && mo->flags2&MF2_FLY && !(mo->z <= mo->floorz)
666      && leveltime&2)
667     {
668       mo->z += finesine[(FINEANGLES/20*leveltime>>2)&FINEMASK];
669     }
670 
671   /*
672    * clip movement
673    */
674   if(mo->z <= mo->floorz)
675     { /* Hit the floor */
676       mo->z = mo->floorz;
677       if(mo->momz < 0)
678 	{
679 	  mo->momz = 0;
680 	}
681       if(mo->flags&MF_SKULLFLY)
682 	{ /* The skull slammed into something */
683 	  mo->momz = -mo->momz;
684 	}
685       if(mo->info->crashstate && (mo->flags&MF_CORPSE))
686 	{
687 	  return;
688 	}
689     }
690   else if(mo->flags2&MF2_LOGRAV)
691     {
692       if(mo->momz == 0)
693 	mo->momz = -(GRAVITY>>3)*2;
694       else
695 	mo->momz -= GRAVITY>>3;
696     }
697   else if (! (mo->flags & MF_NOGRAVITY) )
698     {
699       if (mo->momz == 0)
700 	mo->momz = -GRAVITY*2;
701       else
702 	mo->momz -= GRAVITY;
703     }
704 
705   if (mo->z + mo->height > mo->ceilingz)
706     {	/* hit the ceiling */
707       if (mo->momz > 0)
708 	mo->momz = 0;
709       mo->z = mo->ceilingz - mo->height;
710       if (mo->flags & MF_SKULLFLY)
711 	{	/* the skull slammed into something */
712 	  mo->momz = -mo->momz;
713 	}
714     }
715 }
716 
717 /*
718   //==========================================================================
719   //
720   // CheckMissileImpact
721   //
722   //==========================================================================
723 */
CheckMissileImpact(mobj_t * mobj)724 void CheckMissileImpact(mobj_t *mobj)
725 {
726   int i;
727 
728   if(!numspechit || !(mobj->flags&MF_MISSILE) || !mobj->target)
729     {
730       return;
731     }
732   if(!mobj->target->player)
733     {
734       return;
735     }
736   for(i = numspechit-1; i >= 0; i--)
737     {
738       P_ShootSpecialLine(mobj->target, spechit[i]);
739     }
740 }
741 
742 /*
743   ===================
744   =
745   = P_TryMove
746   =
747   = Attempt to move to a new position, crossing special lines unless MF_TELEPORT
748   = is set
749   =
750   ===================
751 */
752 
P_TryMove(mobj_t * thing,fixed_t x,fixed_t y)753 boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y)
754 {
755   fixed_t		oldx, oldy;
756   int			side, oldside;
757   line_t		*ld;
758 
759   floatok = false;
760   if(!P_CheckPosition(thing, x, y))
761     { /* Solid wall or thing */
762       CheckMissileImpact(thing);
763       return false;
764     }
765   if(!(thing->flags&MF_NOCLIP))
766     {
767       if(tmceilingz-tmfloorz < thing->height)
768 	{ /* Doesn't fit */
769 	  CheckMissileImpact(thing);
770 	  return false;
771 	}
772       floatok = true;
773       if(!(thing->flags&MF_TELEPORT)
774 	 && tmceilingz-thing->z < thing->height
775 	 && !(thing->flags2&MF2_FLY))
776 	{ /* mobj must lower itself to fit */
777 	  CheckMissileImpact(thing);
778 	  return false;
779 	}
780       if(thing->flags2&MF2_FLY)
781 	{
782 	  if(thing->z+thing->height > tmceilingz)
783 	    {
784 	      thing->momz = -8*FRACUNIT;
785 	      return false;
786 	    }
787 	  else if(thing->z < tmfloorz && tmfloorz-tmdropoffz > 24*FRACUNIT)
788 	    {
789 	      thing->momz = 8*FRACUNIT;
790 	      return false;
791 	    }
792 	}
793       if(!(thing->flags&MF_TELEPORT)
794 	 /* The Minotaur floor fire (MT_MNTRFX2) can step up any amount */
795 	 && thing->type != MT_MNTRFX2
796 	 && tmfloorz-thing->z > 24*FRACUNIT)
797 	{ /* Too big a step up */
798 	  CheckMissileImpact(thing);
799 	  return false;
800 	}
801       if((thing->flags&MF_MISSILE) && tmfloorz > thing->z)
802 	{
803 	  CheckMissileImpact(thing);
804 	}
805       if(!(thing->flags&(MF_DROPOFF|MF_FLOAT))
806 	 && tmfloorz-tmdropoffz > 24*FRACUNIT)
807 	{ /* Can't move over a dropoff */
808 	  return false;
809 	}
810     }
811 
812   /*
813    * the move is ok, so link the thing into its new position
814    */
815   P_UnsetThingPosition (thing);
816 
817   oldx = thing->x;
818   oldy = thing->y;
819   thing->floorz = tmfloorz;
820   thing->ceilingz = tmceilingz;
821   thing->x = x;
822   thing->y = y;
823 
824   P_SetThingPosition (thing);
825 
826   if(thing->flags2&MF2_FOOTCLIP && P_GetThingFloorType(thing) != FLOOR_SOLID)
827     {
828       thing->flags2 |= MF2_FEETARECLIPPED;
829     }
830   else if(thing->flags2&MF2_FEETARECLIPPED)
831     {
832       thing->flags2 &= ~MF2_FEETARECLIPPED;
833     }
834 
835   /*
836    * if any special lines were hit, do the effect
837    */
838   if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) )
839     while (numspechit--)
840       {
841 	/* see if the line was crossed */
842 	ld = spechit[numspechit];
843 	side = P_PointOnLineSide (thing->x, thing->y, ld);
844 	oldside = P_PointOnLineSide (oldx, oldy, ld);
845 	if (side != oldside)
846 	  {
847 	    if (ld->special)
848 	      P_CrossSpecialLine (ld-lines, oldside, thing);
849 	  }
850       }
851   return true;
852 }
853 
854 /*
855   ==================
856   =
857   = P_ThingHeightClip
858   =
859   = Takes a valid thing and adjusts the thing->floorz, thing->ceilingz,
860   = anf possibly thing->z
861   =
862   = This is called for all nearby monsters whenever a sector changes height
863   =
864   = If the thing doesn't fit, the z will be set to the lowest value and
865   = false will be returned
866   ==================
867 */
868 
P_ThingHeightClip(mobj_t * thing)869 boolean P_ThingHeightClip (mobj_t *thing)
870 {
871   boolean		onfloor;
872 
873   onfloor = (thing->z == thing->floorz);
874 
875   P_CheckPosition (thing, thing->x, thing->y);
876   /* what about stranding a monster partially off an edge? */
877 
878   thing->floorz = tmfloorz;
879   thing->ceilingz = tmceilingz;
880 
881   if (onfloor)
882     /* walking monsters rise and fall with the floor */
883     thing->z = thing->floorz;
884   else
885     {	/* don't adjust a floating monster unless forced to */
886       if (thing->z+thing->height > thing->ceilingz)
887 	thing->z = thing->ceilingz - thing->height;
888     }
889 
890   if (thing->ceilingz - thing->floorz < thing->height)
891     return false;
892 
893   return true;
894 }
895 
896 
897 /*
898   ==============================================================================
899 
900   SLIDE MOVE
901 
902   Allows the player to slide along any angled walls
903 
904   ==============================================================================
905 */
906 
907 fixed_t		bestslidefrac, secondslidefrac;
908 line_t		*bestslideline, *secondslideline;
909 mobj_t		*slidemo;
910 
911 fixed_t		tmxmove, tmymove;
912 
913 /*
914   ==================
915   =
916   = P_HitSlideLine
917   =
918   = Adjusts the xmove / ymove so that the next move will slide along the wall
919   ==================
920 */
921 
P_HitSlideLine(line_t * ld)922 void P_HitSlideLine (line_t *ld)
923 {
924   int			side;
925   angle_t		lineangle, moveangle, deltaangle;
926   fixed_t		movelen, newlen;
927 
928 
929   if (ld->slopetype == ST_HORIZONTAL)
930     {
931       tmymove = 0;
932       return;
933     }
934   if (ld->slopetype == ST_VERTICAL)
935     {
936       tmxmove = 0;
937       return;
938     }
939 
940   side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
941 
942   lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy);
943   if (side == 1)
944     lineangle += ANG180;
945   moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove);
946   deltaangle = moveangle-lineangle;
947   if (deltaangle > ANG180)
948     deltaangle += ANG180;
949   /*		I_Error ("SlideLine: ang>ANG180"); */
950 
951   lineangle >>= ANGLETOFINESHIFT;
952   deltaangle >>= ANGLETOFINESHIFT;
953 
954   movelen = P_AproxDistance (tmxmove, tmymove);
955   newlen = FixedMul (movelen, finecosine[deltaangle]);
956   tmxmove = FixedMul (newlen, finecosine[lineangle]);
957   tmymove = FixedMul (newlen, finesine[lineangle]);
958 }
959 
960 /*
961   ==============
962   =
963   = PTR_SlideTraverse
964   =
965   ==============
966 */
967 
PTR_SlideTraverse(intercept_t * in)968 boolean		PTR_SlideTraverse (intercept_t *in)
969 {
970   line_t	*li;
971 
972   if (!in->isaline)
973     I_Error ("PTR_SlideTraverse: not a line?");
974 
975   li = in->d.line;
976   if ( ! (li->flags & ML_TWOSIDED) )
977     {
978       if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
979 	return true;		/* don't hit the back side */
980       goto isblocking;
981     }
982 
983   P_LineOpening (li);		/* set openrange, opentop, openbottom */
984   if (openrange < slidemo->height)
985     goto isblocking;		/* doesn't fit */
986 
987   if (opentop - slidemo->z < slidemo->height)
988     goto isblocking;		/* mobj is too high */
989 
990   if (openbottom - slidemo->z > 24*FRACUNIT )
991     goto isblocking;		/* too big a step up */
992 
993   return true;		        /* this line doesn't block movement */
994 
995   /* the line does block movement, see if it is closer than best so far */
996  isblocking:
997   if (in->frac < bestslidefrac)
998     {
999       secondslidefrac = bestslidefrac;
1000       secondslideline = bestslideline;
1001       bestslidefrac = in->frac;
1002       bestslideline = li;
1003     }
1004 
1005   return false;	/* stop */
1006 }
1007 
1008 
1009 /*
1010   ==================
1011   =
1012   = P_SlideMove
1013   =
1014   = The momx / momy move is bad, so try to slide along a wall
1015   =
1016   = Find the first line hit, move flush to it, and slide along it
1017   =
1018   = This is a kludgy mess.
1019   ==================
1020 */
1021 
P_SlideMove(mobj_t * mo)1022 void P_SlideMove (mobj_t *mo)
1023 {
1024   fixed_t		leadx, leady;
1025   fixed_t		trailx, traily;
1026   fixed_t		newx, newy;
1027   int			hitcount;
1028 
1029   slidemo = mo;
1030   hitcount = 0;
1031  retry:
1032   if (++hitcount == 3)
1033     goto stairstep;	       /* don't loop forever */
1034 
1035   /*
1036    * trace along the three leading corners
1037    */
1038   if (mo->momx > 0)
1039     {
1040       leadx = mo->x + mo->radius;
1041       trailx = mo->x - mo->radius;
1042     }
1043   else
1044     {
1045       leadx = mo->x - mo->radius;
1046       trailx = mo->x + mo->radius;
1047     }
1048 
1049   if (mo->momy > 0)
1050     {
1051       leady = mo->y + mo->radius;
1052       traily = mo->y - mo->radius;
1053     }
1054   else
1055     {
1056       leady = mo->y - mo->radius;
1057       traily = mo->y + mo->radius;
1058     }
1059 
1060   bestslidefrac = FRACUNIT+1;
1061 
1062   P_PathTraverse ( leadx, leady, leadx+mo->momx, leady+mo->momy,
1063 		   PT_ADDLINES, PTR_SlideTraverse );
1064   P_PathTraverse ( trailx, leady, trailx+mo->momx, leady+mo->momy,
1065 		   PT_ADDLINES, PTR_SlideTraverse );
1066   P_PathTraverse ( leadx, traily, leadx+mo->momx, traily+mo->momy,
1067 		   PT_ADDLINES, PTR_SlideTraverse );
1068 
1069   /*
1070    * move up to the wall
1071    */
1072   if (bestslidefrac == FRACUNIT+1)
1073     {	/* the move most have hit the middle, so stairstep */
1074     stairstep:
1075       if (!P_TryMove (mo, mo->x, mo->y + mo->momy))
1076 	P_TryMove (mo, mo->x + mo->momx, mo->y);
1077       return;
1078     }
1079 
1080   bestslidefrac -= 0x800;	/* fudge a bit to make sure it doesn't hit */
1081   if (bestslidefrac > 0)
1082     {
1083       newx = FixedMul (mo->momx, bestslidefrac);
1084       newy = FixedMul (mo->momy, bestslidefrac);
1085       if (!P_TryMove (mo, mo->x+newx, mo->y+newy))
1086 	goto stairstep;
1087     }
1088 
1089   /*
1090    * now continue along the wall
1091    */
1092   bestslidefrac = FRACUNIT-(bestslidefrac+0x800);	/* remainder */
1093   if (bestslidefrac > FRACUNIT)
1094     bestslidefrac = FRACUNIT;
1095   if (bestslidefrac <= 0)
1096     return;
1097 
1098   tmxmove = FixedMul (mo->momx, bestslidefrac);
1099   tmymove = FixedMul (mo->momy, bestslidefrac);
1100 
1101   P_HitSlideLine (bestslideline);			/* clip the moves */
1102 
1103   mo->momx = tmxmove;
1104   mo->momy = tmymove;
1105 
1106   if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove))
1107     {
1108       goto retry;
1109     }
1110 }
1111 
1112 
1113 
1114 /*
1115   ==============================================================================
1116 
1117   P_LineAttack
1118 
1119   ==============================================================================
1120 */
1121 
1122 
1123 mobj_t		*linetarget;	    /* who got hit (or NULL) */
1124 mobj_t		*shootthing;
1125 fixed_t		shootz;		    /* height if not aiming up or down */
1126 /* ???: use slope for monsters? */
1127 int		la_damage;
1128 fixed_t		attackrange;
1129 
1130 fixed_t		aimslope;
1131 
1132 extern	fixed_t	   topslope, bottomslope;  /* slopes to top and bottom of target */
1133 
1134 /*
1135   ===============================================================================
1136   =
1137   = PTR_AimTraverse
1138   =
1139   = Sets linetaget and aimslope when a target is aimed at
1140   ===============================================================================
1141 */
1142 
PTR_AimTraverse(intercept_t * in)1143 boolean		PTR_AimTraverse (intercept_t *in)
1144 {
1145   line_t		*li;
1146   mobj_t		*th;
1147   fixed_t		slope, thingtopslope, thingbottomslope;
1148   fixed_t		dist;
1149 
1150   if (in->isaline)
1151     {
1152       li = in->d.line;
1153       if ( !(li->flags & ML_TWOSIDED) )
1154 	return false;		/* stop */
1155       /*
1156        * crosses a two sided line
1157        * a two sided line will restrict the possible target ranges
1158        */
1159       P_LineOpening (li);
1160 
1161       if (openbottom >= opentop)
1162 	return false;		/* stop */
1163 
1164       dist = FixedMul (attackrange, in->frac);
1165 
1166       if (li->frontsector->floorheight != li->backsector->floorheight)
1167 	{
1168 	  slope = FixedDiv (openbottom - shootz , dist);
1169 	  if (slope > bottomslope)
1170 	    bottomslope = slope;
1171 	}
1172 
1173       if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
1174 	{
1175 	  slope = FixedDiv (opentop - shootz , dist);
1176 	  if (slope < topslope)
1177 	    topslope = slope;
1178 	}
1179 
1180       if (topslope <= bottomslope)
1181 	return false;		/* stop */
1182 
1183       return true;		/* shot continues */
1184     }
1185 
1186   /*
1187    * shoot a thing
1188    */
1189   th = in->d.thing;
1190   if (th == shootthing)
1191     return true;		/* can't shoot self */
1192   if (!(th->flags&MF_SHOOTABLE))
1193     return true;		/* corpse or something */
1194   if(th->type == MT_POD)
1195     { /* Can't auto-aim at pods */
1196       return(true);
1197     }
1198 
1199   /* check angles to see if the thing can be aimed at */
1200 
1201   dist = FixedMul (attackrange, in->frac);
1202   thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
1203   if (thingtopslope < bottomslope)
1204     return true;		/* shot over the thing */
1205   thingbottomslope = FixedDiv (th->z - shootz, dist);
1206   if (thingbottomslope > topslope)
1207     return true;		/* shot under the thing */
1208 
1209   /*
1210    * this thing can be hit!
1211    */
1212   if (thingtopslope > topslope)
1213     thingtopslope = topslope;
1214   if (thingbottomslope < bottomslope)
1215     thingbottomslope = bottomslope;
1216 
1217   aimslope = (thingtopslope+thingbottomslope)/2;
1218   linetarget = th;
1219 
1220   return false;			/* don't go any farther */
1221 }
1222 
1223 
1224 /*
1225   ==============================================================================
1226   =
1227   = PTR_ShootTraverse
1228   =
1229   ==============================================================================
1230 */
1231 
1232 #ifdef GL_HERETIC
1233 void GL_vGenerateWallImpact(line_t *line,float x,float y,float z,char type,float size);
1234 #endif
1235 
PTR_ShootTraverse(intercept_t * in)1236 boolean		PTR_ShootTraverse (intercept_t *in)
1237 {
1238   fixed_t		x,y,z;
1239   fixed_t		frac;
1240   line_t		*li;
1241   mobj_t		*th;
1242   fixed_t		slope;
1243   fixed_t		dist;
1244   fixed_t		thingtopslope, thingbottomslope;
1245   mobj_t *mo;
1246 
1247   if (in->isaline)
1248     {
1249       li = in->d.line;
1250       if (li->special)
1251 	P_ShootSpecialLine (shootthing, li);
1252       if ( !(li->flags & ML_TWOSIDED) )
1253 	goto hitline;
1254 
1255       /*
1256        * crosses a two sided line
1257        */
1258       P_LineOpening (li);
1259 
1260       dist = FixedMul (attackrange, in->frac);
1261 
1262       if (li->frontsector->floorheight != li->backsector->floorheight)
1263 	{
1264 	  slope = FixedDiv (openbottom - shootz , dist);
1265 	  if (slope > aimslope)
1266 	    goto hitline;
1267 	}
1268 
1269       if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
1270 	{
1271 	  slope = FixedDiv (opentop - shootz , dist);
1272 	  if (slope < aimslope)
1273 	    goto hitline;
1274 	}
1275 
1276       return true;		/* shot continues */
1277       /*
1278        * hit line
1279        */
1280     hitline:
1281       /* position a bit closer */
1282       frac = in->frac - FixedDiv (4*FRACUNIT,attackrange);
1283       x = trace.x + FixedMul (trace.dx, frac);
1284       y = trace.y + FixedMul (trace.dy, frac);
1285       z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
1286 
1287       if (li->frontsector->ceilingpic == skyflatnum)
1288 	{
1289 	  if (z > li->frontsector->ceilingheight)
1290 	    return false;		/* don't shoot the sky! */
1291 	  if	(li->backsector && li->backsector->ceilingpic == skyflatnum)
1292 	    return false;		/* it's a sky hack wall */
1293 	}
1294 
1295       P_SpawnPuff (x,y,z);
1296 #ifdef GL_HERETIC
1297       GL_vGenerateWallImpact(li,(float)x,(float)y,(float)z,0,0.02f);
1298 #endif
1299       return false;			/* don't go any farther */
1300     }
1301 
1302   /*
1303    * shoot a thing
1304    */
1305   th = in->d.thing;
1306   if (th == shootthing)
1307     return true;		        /* can't shoot self */
1308   if (!(th->flags&MF_SHOOTABLE))
1309     return true;		        /* corpse or something */
1310 
1311   /*
1312    * check for physical attacks on a ghost
1313    */
1314   if(th->flags&MF_SHADOW && shootthing->player->readyweapon == wp_staff)
1315     {
1316       return(true);
1317     }
1318 
1319   /* check angles to see if the thing can be aimed at */
1320   dist = FixedMul (attackrange, in->frac);
1321   thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
1322   if (thingtopslope < aimslope)
1323     return true;		        /* shot over the thing */
1324   thingbottomslope = FixedDiv (th->z - shootz, dist);
1325   if (thingbottomslope > aimslope)
1326     return true;		        /* shot under the thing */
1327 
1328   /*
1329    * hit thing
1330    */
1331   /* position a bit closer */
1332   frac = in->frac - FixedDiv (10*FRACUNIT,attackrange);
1333   x = trace.x + FixedMul(trace.dx, frac);
1334   y = trace.y + FixedMul(trace.dy, frac);
1335   z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange));
1336   if(PuffType == MT_BLASTERPUFF1)
1337     { /* Make blaster big puff */
1338       mo = P_SpawnMobj(x, y, z, MT_BLASTERPUFF2);
1339       S_StartSound(mo, sfx_blshit);
1340     }
1341   else
1342     {
1343       P_SpawnPuff(x, y, z);
1344     }
1345   if(la_damage)
1346     {
1347       if(!(in->d.thing->flags&MF_NOBLOOD) && P_Random() < 192)
1348 	{
1349 	  P_BloodSplatter(x, y, z, in->d.thing);
1350 #ifdef GL_HERETIC
1351 	  GL_CheckForBloodSplash(x,y,z,la_damage);
1352 #endif
1353 	}
1354       P_DamageMobj(th, shootthing, shootthing, la_damage);
1355     }
1356   return(false); /* don't go any farther */
1357 }
1358 
1359 /*
1360   =================
1361   =
1362   = P_AimLineAttack
1363   =
1364   =================
1365 */
1366 
P_AimLineAttack(mobj_t * t1,angle_t angle,fixed_t distance)1367 fixed_t P_AimLineAttack (mobj_t *t1, angle_t angle, fixed_t distance)
1368 {
1369   fixed_t		x2, y2;
1370 
1371   angle >>= ANGLETOFINESHIFT;
1372   shootthing = t1;
1373   x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
1374   y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
1375   shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
1376   topslope = 100*FRACUNIT/160;	/* can't shoot outside view angles */
1377   bottomslope = -100*FRACUNIT/160;
1378   attackrange = distance;
1379   linetarget = NULL;
1380 
1381   P_PathTraverse ( t1->x, t1->y, x2, y2
1382 		   , PT_ADDLINES|PT_ADDTHINGS, PTR_AimTraverse );
1383 
1384   if (linetarget)
1385     return aimslope;
1386   return 0;
1387 }
1388 
1389 
1390 
1391 /*
1392   =================
1393   =
1394   = P_LineAttack
1395   =
1396   = if damage == 0, it is just a test trace that will leave linetarget set
1397   =
1398   =================
1399 */
1400 
1401 #ifdef GL_HERETIC
1402 boolean PTR_BloodTraverse (intercept_t* in);
1403 extern GLboolean GL_bBloodSplash(void);
1404 #endif
1405 
P_LineAttack(mobj_t * t1,angle_t angle,fixed_t distance,fixed_t slope,int damage)1406 void P_LineAttack (mobj_t *t1, angle_t angle, fixed_t distance, fixed_t slope, int damage)
1407 {
1408   fixed_t		x2, y2;
1409 
1410   angle >>= ANGLETOFINESHIFT;
1411   shootthing = t1;
1412   la_damage = damage;
1413   x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
1414   y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
1415   shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
1416   if(t1->flags2&MF2_FEETARECLIPPED)
1417     {
1418       shootz -= FOOTCLIPSIZE;
1419     }
1420   attackrange = distance;
1421   aimslope = slope;
1422 
1423   P_PathTraverse ( t1->x, t1->y, x2, y2
1424 		   , PT_ADDLINES|PT_ADDTHINGS, PTR_ShootTraverse );
1425 #ifdef GL_HERETIC
1426   if (GL_bBloodSplash())
1427     P_PathTraverse ( t1->x, t1->y, x2, y2,
1428 		     PT_ADDLINES, PTR_BloodTraverse );
1429 #endif
1430 }
1431 
1432 
1433 
1434 /*
1435   ==============================================================================
1436 
1437   USE LINES
1438 
1439   ==============================================================================
1440 */
1441 
1442 mobj_t		*usething;
1443 
PTR_UseTraverse(intercept_t * in)1444 boolean		PTR_UseTraverse (intercept_t *in)
1445 {
1446   if (!in->d.line->special)
1447     {
1448       P_LineOpening (in->d.line);
1449       if (openrange <= 0)
1450 	{
1451 	  /*   S_StartSound (usething, sfx_noway);   */
1452 	  return false;	/* can't use through a wall */
1453 	}
1454       return true ;		/* not a special line, but keep checking */
1455     }
1456 
1457   if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
1458     return false;		/* don't use back sides */
1459 
1460   P_UseSpecialLine (usething, in->d.line);
1461 
1462   return false;			/* can't use for than one special line in a row */
1463 }
1464 
1465 
1466 /*
1467   ================
1468   =
1469   = P_UseLines
1470   =
1471   = Looks for special lines in front of the player to activate
1472   ================
1473 */
1474 
P_UseLines(player_t * player)1475 void P_UseLines (player_t *player)
1476 {
1477   int			angle;
1478   fixed_t		x1, y1, x2, y2;
1479 
1480   usething = player->mo;
1481 
1482   angle = player->mo->angle >> ANGLETOFINESHIFT;
1483   x1 = player->mo->x;
1484   y1 = player->mo->y;
1485   x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
1486   y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
1487 
1488   P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
1489 }
1490 
1491 
1492 
1493 /*
1494   ==============================================================================
1495 
1496   RADIUS ATTACK
1497 
1498   ==============================================================================
1499 */
1500 
1501 mobj_t		*bombsource;
1502 mobj_t		*bombspot;
1503 int		bombdamage;
1504 
1505 /*
1506   =================
1507   =
1508   = PIT_RadiusAttack
1509   =
1510   = Source is the creature that casued the explosion at spot
1511   =================
1512 */
1513 
PIT_RadiusAttack(mobj_t * thing)1514 boolean PIT_RadiusAttack (mobj_t *thing)
1515 {
1516   fixed_t dx, dy, dist;
1517 
1518   if(!(thing->flags&MF_SHOOTABLE))
1519     {
1520       return true;
1521     }
1522   if(thing->type == MT_MINOTAUR || thing->type == MT_SORCERER1
1523      || thing->type == MT_SORCERER2)
1524     { /* Episode 2 and 3 bosses take no damage from PIT_RadiusAttack */
1525       return(true);
1526     }
1527   dx = abs(thing->x - bombspot->x);
1528   dy = abs(thing->y - bombspot->y);
1529   dist = dx > dy ? dx : dy;
1530   dist = (dist - thing->radius) >> FRACBITS;
1531   if(dist < 0)
1532     {
1533       dist = 0;
1534     }
1535   if(dist >= bombdamage)
1536     { /* Out of range */
1537       return true;
1538     }
1539   if(P_CheckSight(thing, bombspot))
1540     { /* OK to damage, target is in direct path */
1541       P_DamageMobj(thing, bombspot, bombsource, bombdamage - dist);
1542     }
1543   return(true);
1544 }
1545 
1546 /*
1547   =================
1548   =
1549   = P_RadiusAttack
1550   =
1551   = Source is the creature that casued the explosion at spot
1552   =================
1553 */
1554 
P_RadiusAttack(mobj_t * spot,mobj_t * source,int damage)1555 void P_RadiusAttack (mobj_t *spot, mobj_t *source, int damage)
1556 {
1557   int			x,y, xl, xh, yl, yh;
1558   fixed_t		dist;
1559 
1560   dist = (damage+MAXRADIUS)<<FRACBITS;
1561   yh = (spot->y + dist - bmaporgy)>>MAPBLOCKSHIFT;
1562   yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT;
1563   xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT;
1564   xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT;
1565   bombspot = spot;
1566   if(spot->type == MT_POD && spot->target)
1567     {
1568       bombsource = spot->target;
1569     }
1570   else
1571     {
1572       bombsource = source;
1573     }
1574   bombdamage = damage;
1575   for (y=yl ; y<=yh ; y++)
1576     for (x=xl ; x<=xh ; x++)
1577       P_BlockThingsIterator (x, y, PIT_RadiusAttack );
1578 }
1579 
1580 
1581 /*
1582   ==============================================================================
1583 
1584   SECTOR HEIGHT CHANGING
1585 
1586   = After modifying a sectors floor or ceiling height, call this
1587   = routine to adjust the positions of all things that touch the
1588   = sector.
1589   =
1590   = If anything doesn't fit anymore, true will be returned.
1591   = If crunch is true, they will take damage as they are being crushed
1592   = If Crunch is false, you should set the sector height back the way it
1593   = was and call P_ChangeSector again to undo the changes
1594   ==============================================================================
1595 */
1596 
1597 boolean		crushchange;
1598 boolean		nofit;
1599 
1600 /*
1601   ===============
1602   =
1603   = PIT_ChangeSector
1604   =
1605   ===============
1606 */
1607 
PIT_ChangeSector(mobj_t * thing)1608 boolean PIT_ChangeSector (mobj_t *thing)
1609 {
1610   mobj_t		*mo;
1611 
1612   if (P_ThingHeightClip (thing))
1613     return true;		/* keep checking */
1614 
1615   /* crunch bodies to giblets */
1616   if (thing->health <= 0)
1617     {
1618       /*   P_SetMobjState (thing, S_GIBS);   */
1619       thing->height = 0;
1620       thing->radius = 0;
1621       return true;		/* keep checking */
1622     }
1623 
1624   /* crunch dropped items */
1625   if (thing->flags & MF_DROPPED)
1626     {
1627       P_RemoveMobj (thing);
1628       return true;		/* keep checking */
1629     }
1630 
1631   if (! (thing->flags & MF_SHOOTABLE) )
1632     return true;	        /* assume it is bloody gibs or something */
1633 
1634   nofit = true;
1635   if (crushchange && !(leveltime&3) )
1636     {
1637       P_DamageMobj(thing,NULL,NULL,10);
1638       /* spray blood in a random direction */
1639       mo = P_SpawnMobj (thing->x, thing->y, thing->z + thing->height/2, MT_BLOOD);
1640       mo->momx = (P_Random() - P_Random ())<<12;
1641       mo->momy = (P_Random() - P_Random ())<<12;
1642     }
1643 
1644   return true;		/* keep checking (crush other things) */
1645 }
1646 
1647 /*
1648   ===============
1649   =
1650   = P_ChangeSector
1651   =
1652   ===============
1653 */
1654 
P_ChangeSector(sector_t * sector,boolean crunch)1655 boolean P_ChangeSector (sector_t *sector, boolean crunch)
1656 {
1657   int			x,y;
1658 
1659   nofit = false;
1660   crushchange = crunch;
1661 
1662   /* recheck heights for all things near the moving sector */
1663 
1664   for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++)
1665     for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++)
1666       P_BlockThingsIterator (x, y, PIT_ChangeSector);
1667 
1668 
1669   return nofit;
1670 }
1671 
1672 
1673