Subversion Repositories Kolibri OS

Rev

Rev 298 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. // Emacs style mode select   -*- C++ -*-
  2. //-----------------------------------------------------------------------------
  3. //
  4. // $Id:$
  5. //
  6. // Copyright (C) 1993-1996 by id Software, Inc.
  7. //
  8. // This source is available for distribution and/or modification
  9. // only under the terms of the DOOM Source Code License as
  10. // published by id Software. All rights reserved.
  11. //
  12. // The source is distributed in the hope that it will be useful,
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
  15. // for more details.
  16. //
  17. // $Log:$
  18. //
  19. // DESCRIPTION:
  20. //      Movement, collision handling.
  21. //      Shooting and aiming.
  22. //
  23. //-----------------------------------------------------------------------------
  24.  
  25. static const char
  26. rcsid[] = "$Id: p_map.c,v 1.5 1997/02/03 22:45:11 b1 Exp $";
  27.  
  28. #include <stdlib.h>
  29.  
  30. #include "doomtype.h"
  31. #include "m_bbox.h"
  32. #include "m_random.h"
  33. #include "i_system.h"
  34.  
  35. #include "doomdef.h"
  36. #include "p_local.h"
  37.  
  38. #include "s_sound.h"
  39.  
  40. // State.
  41. #include "doomstat.h"
  42. #include "r_state.h"
  43. // Data.
  44. #include "sounds.h"
  45.  
  46.  
  47. fixed_t         tmbbox[4];
  48. mobj_t*         tmthing;
  49. int             tmflags;
  50. fixed_t         tmx;
  51. fixed_t         tmy;
  52.  
  53.  
  54. // If "floatok" true, move would be ok
  55. // if within "tmfloorz - tmceilingz".
  56. boolean         floatok;
  57.  
  58. fixed_t         tmfloorz;
  59. fixed_t         tmceilingz;
  60. fixed_t         tmdropoffz;
  61.  
  62. // keep track of the line that lowers the ceiling,
  63. // so missiles don't explode against sky hack walls
  64. line_t*         ceilingline;
  65.  
  66. // keep track of special lines as they are hit,
  67. // but don't process them until the move is proven valid
  68. #define MAXSPECIALCROSS         8
  69.  
  70. line_t*         spechit[MAXSPECIALCROSS];
  71. int             numspechit;
  72.  
  73.  
  74.  
  75. //
  76. // TELEPORT MOVE
  77. //
  78.  
  79. //
  80. // PIT_StompThing
  81. //
  82. boolean PIT_StompThing (mobj_t* thing)
  83. {
  84.     fixed_t     blockdist;
  85.                
  86.     if (!(thing->flags & MF_SHOOTABLE) )
  87.         return true;
  88.                
  89.     blockdist = thing->radius + tmthing->radius;
  90.    
  91.     if ( abs(thing->x - tmx) >= blockdist
  92.          || abs(thing->y - tmy) >= blockdist )
  93.     {
  94.         // didn't hit it
  95.         return true;
  96.     }
  97.    
  98.     // don't clip against self
  99.     if (thing == tmthing)
  100.         return true;
  101.    
  102.     // monsters don't stomp things except on boss level
  103.     if ( !tmthing->player && gamemap != 30)
  104.         return false;  
  105.                
  106.     P_DamageMobj (thing, tmthing, tmthing, 10000);
  107.        
  108.     return true;
  109. }
  110.  
  111.  
  112. //
  113. // P_TeleportMove
  114. //
  115. boolean
  116. P_TeleportMove
  117. ( mobj_t*       thing,
  118.   fixed_t       x,
  119.   fixed_t       y )
  120. {
  121.     int                 xl;
  122.     int                 xh;
  123.     int                 yl;
  124.     int                 yh;
  125.     int                 bx;
  126.     int                 by;
  127.    
  128.     subsector_t*        newsubsec;
  129.    
  130.     // kill anything occupying the position
  131.     tmthing = thing;
  132.     tmflags = thing->flags;
  133.        
  134.     tmx = x;
  135.     tmy = y;
  136.        
  137.     tmbbox[BOXTOP] = y + tmthing->radius;
  138.     tmbbox[BOXBOTTOM] = y - tmthing->radius;
  139.     tmbbox[BOXRIGHT] = x + tmthing->radius;
  140.     tmbbox[BOXLEFT] = x - tmthing->radius;
  141.  
  142.     newsubsec = R_PointInSubsector (x,y);
  143.     ceilingline = NULL;
  144.    
  145.     // The base floor/ceiling is from the subsector
  146.     // that contains the point.
  147.     // Any contacted lines the step closer together
  148.     // will adjust them.
  149.     tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  150.     tmceilingz = newsubsec->sector->ceilingheight;
  151.                        
  152.     validcount++;
  153.     numspechit = 0;
  154.    
  155.     // stomp on any things contacted
  156.     xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  157.     xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  158.     yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  159.     yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  160.  
  161.     for (bx=xl ; bx<=xh ; bx++)
  162.         for (by=yl ; by<=yh ; by++)
  163.             if (!P_BlockThingsIterator(bx,by,PIT_StompThing))
  164.                 return false;
  165.    
  166.     // the move is ok,
  167.     // so link the thing into its new position
  168.     P_UnsetThingPosition (thing);
  169.  
  170.     thing->floorz = tmfloorz;
  171.     thing->ceilingz = tmceilingz;      
  172.     thing->x = x;
  173.     thing->y = y;
  174.  
  175.     P_SetThingPosition (thing);
  176.        
  177.     return true;
  178. }
  179.  
  180.  
  181. //
  182. // MOVEMENT ITERATOR FUNCTIONS
  183. //
  184.  
  185.  
  186. //
  187. // PIT_CheckLine
  188. // Adjusts tmfloorz and tmceilingz as lines are contacted
  189. //
  190. boolean PIT_CheckLine (line_t* ld)
  191. {
  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] )
  196.         return true;
  197.  
  198.     if (P_BoxOnLineSide (tmbbox, ld) != -1)
  199.         return true;
  200.                
  201.     // A line has been hit
  202.    
  203.     // The moving thing's destination position will cross
  204.     // the given line.
  205.     // If this should not be allowed, return false.
  206.     // If the line is special, keep track of it
  207.     // to process later if the move is proven ok.
  208.     // NOTE: specials are NOT sorted by order,
  209.     // so two special lines that are only 8 pixels apart
  210.     // could be crossed in either order.
  211.    
  212.     if (!ld->backsector)
  213.         return false;           // one sided line
  214.                
  215.     if (!(tmthing->flags & MF_MISSILE) )
  216.     {
  217.         if ( ld->flags & ML_BLOCKING )
  218.             return false;       // explicitly blocking everything
  219.  
  220.         if ( !tmthing->player && ld->flags & ML_BLOCKMONSTERS )
  221.             return false;       // block monsters only
  222.     }
  223.  
  224.     // set openrange, opentop, openbottom
  225.     P_LineOpening (ld);
  226.        
  227.     // adjust floor / ceiling heights
  228.     if (opentop < tmceilingz)
  229.     {
  230.         tmceilingz = opentop;
  231.         ceilingline = ld;
  232.     }
  233.  
  234.     if (openbottom > tmfloorz)
  235.         tmfloorz = openbottom;  
  236.  
  237.     if (lowfloor < tmdropoffz)
  238.         tmdropoffz = lowfloor;
  239.                
  240.     // if contacted a special line, add it to the list
  241.     if (ld->special)
  242.     {
  243.         spechit[numspechit] = ld;
  244.         numspechit++;
  245.     }
  246.  
  247.     return true;
  248. }
  249.  
  250. //
  251. // PIT_CheckThing
  252. //
  253. boolean PIT_CheckThing (mobj_t* thing)
  254. {
  255.     fixed_t             blockdist;
  256.     boolean             solid;
  257.     int                 damage;
  258.                
  259.     if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE) ))
  260.         return true;
  261.    
  262.     blockdist = thing->radius + tmthing->radius;
  263.  
  264.     if ( abs(thing->x - tmx) >= blockdist
  265.          || abs(thing->y - tmy) >= blockdist )
  266.     {
  267.         // didn't hit it
  268.         return true;    
  269.     }
  270.    
  271.     // don't clip against self
  272.     if (thing == tmthing)
  273.         return true;
  274.    
  275.     // check for skulls slamming into things
  276.     if (tmthing->flags & MF_SKULLFLY)
  277.     {
  278.         damage = ((P_Random()%8)+1)*tmthing->info->damage;
  279.        
  280.         P_DamageMobj (thing, tmthing, tmthing, damage);
  281.        
  282.         tmthing->flags &= ~MF_SKULLFLY;
  283.         tmthing->momx = tmthing->momy = tmthing->momz = 0;
  284.        
  285.         P_SetMobjState (tmthing, tmthing->info->spawnstate);
  286.        
  287.         return false;           // stop moving
  288.     }
  289.  
  290.    
  291.     // missiles can hit other things
  292.     if (tmthing->flags & MF_MISSILE)
  293.     {
  294.         // see if it went over / under
  295.         if (tmthing->z > thing->z + thing->height)
  296.             return true;                // overhead
  297.         if (tmthing->z+tmthing->height < thing->z)
  298.             return true;                // underneath
  299.                
  300.         if (tmthing->target && (
  301.             tmthing->target->type == thing->type ||
  302.             (tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER)||
  303.             (tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT) ) )
  304.         {
  305.             // Don't hit same species as originator.
  306.             if (thing == tmthing->target)
  307.                 return true;
  308.  
  309.             if (thing->type != MT_PLAYER)
  310.             {
  311.                 // Explode, but do no damage.
  312.                 // Let players missile other players.
  313.                 return false;
  314.             }
  315.         }
  316.        
  317.         if (! (thing->flags & MF_SHOOTABLE) )
  318.         {
  319.             // didn't do any damage
  320.             return !(thing->flags & MF_SOLID);  
  321.         }
  322.        
  323.         // damage / explode
  324.         damage = ((P_Random()%8)+1)*tmthing->info->damage;
  325.         P_DamageMobj (thing, tmthing, tmthing->target, damage);
  326.  
  327.         // don't traverse any more
  328.         return false;                          
  329.     }
  330.    
  331.     // check for special pickup
  332.     if (thing->flags & MF_SPECIAL)
  333.     {
  334.         solid = thing->flags&MF_SOLID;
  335.         if (tmflags&MF_PICKUP)
  336.         {
  337.             // can remove thing
  338.             P_TouchSpecialThing (thing, tmthing);
  339.         }
  340.         return !solid;
  341.     }
  342.        
  343.     return !(thing->flags & MF_SOLID);
  344. }
  345.  
  346.  
  347. //
  348. // MOVEMENT CLIPPING
  349. //
  350.  
  351. //
  352. // P_CheckPosition
  353. // This is purely informative, nothing is modified
  354. // (except things picked up).
  355. //
  356. // in:
  357. //  a mobj_t (can be valid or invalid)
  358. //  a position to be checked
  359. //   (doesn't need to be related to the mobj_t->x,y)
  360. //
  361. // during:
  362. //  special things are touched if MF_PICKUP
  363. //  early out on solid lines?
  364. //
  365. // out:
  366. //  newsubsec
  367. //  floorz
  368. //  ceilingz
  369. //  tmdropoffz
  370. //   the lowest point contacted
  371. //   (monsters won't move to a dropoff)
  372. //  speciallines[]
  373. //  numspeciallines
  374. //
  375. boolean
  376. P_CheckPosition
  377. ( mobj_t*       thing,
  378.   fixed_t       x,
  379.   fixed_t       y )
  380. {
  381.     int                 xl;
  382.     int                 xh;
  383.     int                 yl;
  384.     int                 yh;
  385.     int                 bx;
  386.     int                 by;
  387.     subsector_t*        newsubsec;
  388.  
  389.     tmthing = thing;
  390.     tmflags = thing->flags;
  391.        
  392.     tmx = x;
  393.     tmy = y;
  394.        
  395.     tmbbox[BOXTOP] = y + tmthing->radius;
  396.     tmbbox[BOXBOTTOM] = y - tmthing->radius;
  397.     tmbbox[BOXRIGHT] = x + tmthing->radius;
  398.     tmbbox[BOXLEFT] = x - tmthing->radius;
  399.  
  400.     newsubsec = R_PointInSubsector (x,y);
  401.     ceilingline = NULL;
  402.    
  403.     // The base floor / ceiling is from the subsector
  404.     // that contains the point.
  405.     // Any contacted lines the step closer together
  406.     // will adjust them.
  407.     tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  408.     tmceilingz = newsubsec->sector->ceilingheight;
  409.                        
  410.     validcount++;
  411.     numspechit = 0;
  412.  
  413.     if ( tmflags & MF_NOCLIP )
  414.         return true;
  415.    
  416.     // Check things first, possibly picking things up.
  417.     // The bounding box is extended by MAXRADIUS
  418.     // because mobj_ts are grouped into mapblocks
  419.     // based on their origin point, and can overlap
  420.     // into adjacent blocks by up to MAXRADIUS units.
  421.     xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  422.     xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  423.     yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  424.     yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  425.  
  426.     for (bx=xl ; bx<=xh ; bx++)
  427.         for (by=yl ; by<=yh ; by++)
  428.             if (!P_BlockThingsIterator(bx,by,PIT_CheckThing))
  429.                 return false;
  430.    
  431.     // check lines
  432.     xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
  433.     xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
  434.     yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
  435.     yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
  436.  
  437.     for (bx=xl ; bx<=xh ; bx++)
  438.         for (by=yl ; by<=yh ; by++)
  439.             if (!P_BlockLinesIterator (bx,by,PIT_CheckLine))
  440.                 return false;
  441.  
  442.     return true;
  443. }
  444.  
  445.  
  446. //
  447. // P_TryMove
  448. // Attempt to move to a new position,
  449. // crossing special lines unless MF_TELEPORT is set.
  450. //
  451. boolean
  452. P_TryMove
  453. ( mobj_t*       thing,
  454.   fixed_t       x,
  455.   fixed_t       y )
  456. {
  457.     fixed_t     oldx;
  458.     fixed_t     oldy;
  459.     int         side;
  460.     int         oldside;
  461.     line_t*     ld;
  462.  
  463.     floatok = false;
  464.     if (!P_CheckPosition (thing, x, y))
  465.         return false;           // solid wall or thing
  466.    
  467.     if ( !(thing->flags & MF_NOCLIP) )
  468.     {
  469.         if (tmceilingz - tmfloorz < thing->height)
  470.             return false;       // doesn't fit
  471.  
  472.         floatok = true;
  473.        
  474.         if ( !(thing->flags&MF_TELEPORT)
  475.              &&tmceilingz - thing->z < thing->height)
  476.             return false;       // mobj must lower itself to fit
  477.  
  478.         if ( !(thing->flags&MF_TELEPORT)
  479.              && tmfloorz - thing->z > 24*FRACUNIT )
  480.             return false;       // too big a step up
  481.  
  482.         if ( !(thing->flags&(MF_DROPOFF|MF_FLOAT))
  483.              && tmfloorz - tmdropoffz > 24*FRACUNIT )
  484.             return false;       // don't stand over a dropoff
  485.     }
  486.    
  487.     // the move is ok,
  488.     // so link the thing into its new position
  489.     P_UnsetThingPosition (thing);
  490.  
  491.     oldx = thing->x;
  492.     oldy = thing->y;
  493.     thing->floorz = tmfloorz;
  494.     thing->ceilingz = tmceilingz;      
  495.     thing->x = x;
  496.     thing->y = y;
  497.  
  498.     P_SetThingPosition (thing);
  499.    
  500.     // if any special lines were hit, do the effect
  501.     if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) )
  502.     {
  503.         while (numspechit--)
  504.         {
  505.             // see if the line was crossed
  506.             ld = spechit[numspechit];
  507.             side = P_PointOnLineSide (thing->x, thing->y, ld);
  508.             oldside = P_PointOnLineSide (oldx, oldy, ld);
  509.             if (side != oldside)
  510.             {
  511.                 if (ld->special)
  512.                     P_CrossSpecialLine (ld-lines, oldside, thing);
  513.             }
  514.         }
  515.     }
  516.  
  517.     return true;
  518. }
  519.  
  520.  
  521. //
  522. // P_ThingHeightClip
  523. // Takes a valid thing and adjusts the thing->floorz,
  524. // thing->ceilingz, and possibly thing->z.
  525. // This is called for all nearby monsters
  526. // whenever a sector changes height.
  527. // If the thing doesn't fit,
  528. // the z will be set to the lowest value
  529. // and false will be returned.
  530. //
  531. boolean P_ThingHeightClip (mobj_t* thing)
  532. {
  533.     boolean             onfloor;
  534.        
  535.     onfloor = (thing->z == thing->floorz);
  536.        
  537.     P_CheckPosition (thing, thing->x, thing->y);        
  538.     // what about stranding a monster partially off an edge?
  539.        
  540.     thing->floorz = tmfloorz;
  541.     thing->ceilingz = tmceilingz;
  542.        
  543.     if (onfloor)
  544.     {
  545.         // walking monsters rise and fall with the floor
  546.         thing->z = thing->floorz;
  547.     }
  548.     else
  549.     {
  550.         // don't adjust a floating monster unless forced to
  551.         if (thing->z+thing->height > thing->ceilingz)
  552.             thing->z = thing->ceilingz - thing->height;
  553.     }
  554.        
  555.     if (thing->ceilingz - thing->floorz < thing->height)
  556.         return false;
  557.                
  558.     return true;
  559. }
  560.  
  561.  
  562.  
  563. //
  564. // SLIDE MOVE
  565. // Allows the player to slide along any angled walls.
  566. //
  567. fixed_t         bestslidefrac;
  568. fixed_t         secondslidefrac;
  569.  
  570. line_t*         bestslideline;
  571. line_t*         secondslideline;
  572.  
  573. mobj_t*         slidemo;
  574.  
  575. fixed_t         tmxmove;
  576. fixed_t         tmymove;
  577.  
  578.  
  579.  
  580. //
  581. // P_HitSlideLine
  582. // Adjusts the xmove / ymove
  583. // so that the next move will slide along the wall.
  584. //
  585. void P_HitSlideLine (line_t* ld)
  586. {
  587.     int                 side;
  588.  
  589.     angle_t             lineangle;
  590.     angle_t             moveangle;
  591.     angle_t             deltaangle;
  592.    
  593.     fixed_t             movelen;
  594.     fixed_t             newlen;
  595.        
  596.        
  597.     if (ld->slopetype == ST_HORIZONTAL)
  598.     {
  599.         tmymove = 0;
  600.         return;
  601.     }
  602.    
  603.     if (ld->slopetype == ST_VERTICAL)
  604.     {
  605.         tmxmove = 0;
  606.         return;
  607.     }
  608.        
  609.     side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
  610.        
  611.     lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy);
  612.  
  613.     if (side == 1)
  614.         lineangle += ANG180;
  615.  
  616.     moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove);
  617.     deltaangle = moveangle-lineangle;
  618.  
  619.     if (deltaangle > ANG180)
  620.         deltaangle += ANG180;
  621.     //  I_Error ("SlideLine: ang>ANG180");
  622.  
  623.     lineangle >>= ANGLETOFINESHIFT;
  624.     deltaangle >>= ANGLETOFINESHIFT;
  625.        
  626.     movelen = P_AproxDistance (tmxmove, tmymove);
  627.     newlen = FixedMul (movelen, finecosine[deltaangle]);
  628.  
  629.     tmxmove = FixedMul (newlen, finecosine[lineangle]);
  630.     tmymove = FixedMul (newlen, finesine[lineangle]);  
  631. }
  632.  
  633.  
  634. //
  635. // PTR_SlideTraverse
  636. //
  637. boolean PTR_SlideTraverse (intercept_t* in)
  638. {
  639.     line_t*     li;
  640.        
  641.     if (!in->isaline)
  642.         I_Error ("PTR_SlideTraverse: not a line?");
  643.                
  644.     li = in->d.line;
  645.    
  646.     if ( ! (li->flags & ML_TWOSIDED) )
  647.     {
  648.         if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
  649.         {
  650.             // don't hit the back side
  651.             return true;                
  652.         }
  653.         goto isblocking;
  654.     }
  655.  
  656.     // set openrange, opentop, openbottom
  657.     P_LineOpening (li);
  658.    
  659.     if (openrange < slidemo->height)
  660.         goto isblocking;                // doesn't fit
  661.                
  662.     if (opentop - slidemo->z < slidemo->height)
  663.         goto isblocking;                // mobj is too high
  664.  
  665.     if (openbottom - slidemo->z > 24*FRACUNIT )
  666.         goto isblocking;                // too big a step up
  667.  
  668.     // this line doesn't block movement
  669.     return true;                
  670.        
  671.     // the line does block movement,
  672.     // see if it is closer than best so far
  673.   isblocking:          
  674.     if (in->frac < bestslidefrac)
  675.     {
  676.         secondslidefrac = bestslidefrac;
  677.         secondslideline = bestslideline;
  678.         bestslidefrac = in->frac;
  679.         bestslideline = li;
  680.     }
  681.        
  682.     return false;       // stop
  683. }
  684.  
  685.  
  686.  
  687. //
  688. // P_SlideMove
  689. // The momx / momy move is bad, so try to slide
  690. // along a wall.
  691. // Find the first line hit, move flush to it,
  692. // and slide along it
  693. //
  694. // This is a kludgy mess.
  695. //
  696. void P_SlideMove (mobj_t* mo)
  697. {
  698.     fixed_t             leadx;
  699.     fixed_t             leady;
  700.     fixed_t             trailx;
  701.     fixed_t             traily;
  702.     fixed_t             newx;
  703.     fixed_t             newy;
  704.     int                 hitcount;
  705.                
  706.     slidemo = mo;
  707.     hitcount = 0;
  708.    
  709.   retry:
  710.     if (++hitcount == 3)
  711.         goto stairstep;         // don't loop forever
  712.  
  713.    
  714.     // trace along the three leading corners
  715.     if (mo->momx > 0)
  716.     {
  717.         leadx = mo->x + mo->radius;
  718.         trailx = mo->x - mo->radius;
  719.     }
  720.     else
  721.     {
  722.         leadx = mo->x - mo->radius;
  723.         trailx = mo->x + mo->radius;
  724.     }
  725.        
  726.     if (mo->momy > 0)
  727.     {
  728.         leady = mo->y + mo->radius;
  729.         traily = mo->y - mo->radius;
  730.     }
  731.     else
  732.     {
  733.         leady = mo->y - mo->radius;
  734.         traily = mo->y + mo->radius;
  735.     }
  736.                
  737.     bestslidefrac = FRACUNIT+1;
  738.        
  739.     P_PathTraverse ( leadx, leady, leadx+mo->momx, leady+mo->momy,
  740.                      PT_ADDLINES, PTR_SlideTraverse );
  741.     P_PathTraverse ( trailx, leady, trailx+mo->momx, leady+mo->momy,
  742.                      PT_ADDLINES, PTR_SlideTraverse );
  743.     P_PathTraverse ( leadx, traily, leadx+mo->momx, traily+mo->momy,
  744.                      PT_ADDLINES, PTR_SlideTraverse );
  745.    
  746.     // move up to the wall
  747.     if (bestslidefrac == FRACUNIT+1)
  748.     {
  749.         // the move most have hit the middle, so stairstep
  750.       stairstep:
  751.         if (!P_TryMove (mo, mo->x, mo->y + mo->momy))
  752.             P_TryMove (mo, mo->x + mo->momx, mo->y);
  753.         return;
  754.     }
  755.  
  756.     // fudge a bit to make sure it doesn't hit
  757.     bestslidefrac -= 0x800;    
  758.     if (bestslidefrac > 0)
  759.     {
  760.         newx = FixedMul (mo->momx, bestslidefrac);
  761.         newy = FixedMul (mo->momy, bestslidefrac);
  762.        
  763.         if (!P_TryMove (mo, mo->x+newx, mo->y+newy))
  764.             goto stairstep;
  765.     }
  766.    
  767.     // Now continue along the wall.
  768.     // First calculate remainder.
  769.     bestslidefrac = FRACUNIT-(bestslidefrac+0x800);
  770.    
  771.     if (bestslidefrac > FRACUNIT)
  772.         bestslidefrac = FRACUNIT;
  773.    
  774.     if (bestslidefrac <= 0)
  775.         return;
  776.    
  777.     tmxmove = FixedMul (mo->momx, bestslidefrac);
  778.     tmymove = FixedMul (mo->momy, bestslidefrac);
  779.  
  780.     P_HitSlideLine (bestslideline);     // clip the moves
  781.  
  782.     mo->momx = tmxmove;
  783.     mo->momy = tmymove;
  784.                
  785.     if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove))
  786.     {
  787.         goto retry;
  788.     }
  789. }
  790.  
  791.  
  792. //
  793. // P_LineAttack
  794. //
  795. mobj_t*         linetarget;     // who got hit (or NULL)
  796. mobj_t*         shootthing;
  797.  
  798. // Height if not aiming up or down
  799. // ???: use slope for monsters?
  800. fixed_t         shootz;
  801.  
  802. int             la_damage;
  803. fixed_t         attackrange;
  804.  
  805. fixed_t         aimslope;
  806.  
  807. // slopes to top and bottom of target
  808. extern fixed_t  topslope;
  809. extern fixed_t  bottomslope;    
  810.  
  811.  
  812. //
  813. // PTR_AimTraverse
  814. // Sets linetaget and aimslope when a target is aimed at.
  815. //
  816. boolean
  817. PTR_AimTraverse (intercept_t* in)
  818. {
  819.     line_t*             li;
  820.     mobj_t*             th;
  821.     fixed_t             slope;
  822.     fixed_t             thingtopslope;
  823.     fixed_t             thingbottomslope;
  824.     fixed_t             dist;
  825.                
  826.     if (in->isaline)
  827.     {
  828.         li = in->d.line;
  829.        
  830.         if ( !(li->flags & ML_TWOSIDED) )
  831.             return false;               // stop
  832.        
  833.         // Crosses a two sided line.
  834.         // A two sided line will restrict
  835.         // the possible target ranges.
  836.         P_LineOpening (li);
  837.        
  838.         if (openbottom >= opentop)
  839.             return false;               // stop
  840.        
  841.         dist = FixedMul (attackrange, in->frac);
  842.  
  843.         if (li->frontsector->floorheight != li->backsector->floorheight)
  844.         {
  845.             slope = FixedDiv (openbottom - shootz , dist);
  846.             if (slope > bottomslope)
  847.                 bottomslope = slope;
  848.         }
  849.                
  850.         if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
  851.         {
  852.             slope = FixedDiv (opentop - shootz , dist);
  853.             if (slope < topslope)
  854.                 topslope = slope;
  855.         }
  856.                
  857.         if (topslope <= bottomslope)
  858.             return false;               // stop
  859.                        
  860.         return true;                    // shot continues
  861.     }
  862.    
  863.     // shoot a thing
  864.     th = in->d.thing;
  865.     if (th == shootthing)
  866.         return true;                    // can't shoot self
  867.    
  868.     if (!(th->flags&MF_SHOOTABLE))
  869.         return true;                    // corpse or something
  870.  
  871.     // check angles to see if the thing can be aimed at
  872.     dist = FixedMul (attackrange, in->frac);
  873.     thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
  874.  
  875.     if (thingtopslope < bottomslope)
  876.         return true;                    // shot over the thing
  877.  
  878.     thingbottomslope = FixedDiv (th->z - shootz, dist);
  879.  
  880.     if (thingbottomslope > topslope)
  881.         return true;                    // shot under the thing
  882.    
  883.     // this thing can be hit!
  884.     if (thingtopslope > topslope)
  885.         thingtopslope = topslope;
  886.    
  887.     if (thingbottomslope < bottomslope)
  888.         thingbottomslope = bottomslope;
  889.  
  890.     aimslope = (thingtopslope+thingbottomslope)/2;
  891.     linetarget = th;
  892.  
  893.     return false;                       // don't go any farther
  894. }
  895.  
  896.  
  897. //
  898. // PTR_ShootTraverse
  899. //
  900. boolean PTR_ShootTraverse (intercept_t* in)
  901. {
  902.     fixed_t             x;
  903.     fixed_t             y;
  904.     fixed_t             z;
  905.     fixed_t             frac;
  906.    
  907.     line_t*             li;
  908.    
  909.     mobj_t*             th;
  910.  
  911.     fixed_t             slope;
  912.     fixed_t             dist;
  913.     fixed_t             thingtopslope;
  914.     fixed_t             thingbottomslope;
  915.                
  916.     if (in->isaline)
  917.     {
  918.         li = in->d.line;
  919.        
  920.         if (li->special)
  921.             P_ShootSpecialLine (shootthing, li);
  922.  
  923.         if ( !(li->flags & ML_TWOSIDED) )
  924.             goto hitline;
  925.        
  926.         // crosses a two sided line
  927.         P_LineOpening (li);
  928.                
  929.         dist = FixedMul (attackrange, in->frac);
  930.  
  931.         if (li->frontsector->floorheight != li->backsector->floorheight)
  932.         {
  933.             slope = FixedDiv (openbottom - shootz , dist);
  934.             if (slope > aimslope)
  935.                 goto hitline;
  936.         }
  937.                
  938.         if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
  939.         {
  940.             slope = FixedDiv (opentop - shootz , dist);
  941.             if (slope < aimslope)
  942.                 goto hitline;
  943.         }
  944.  
  945.         // shot continues
  946.         return true;
  947.        
  948.        
  949.         // hit line
  950.       hitline:
  951.         // position a bit closer
  952.         frac = in->frac - FixedDiv (4*FRACUNIT,attackrange);
  953.         x = trace.x + FixedMul (trace.dx, frac);
  954.         y = trace.y + FixedMul (trace.dy, frac);
  955.         z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
  956.  
  957.         if (li->frontsector->ceilingpic == skyflatnum)
  958.         {
  959.             // don't shoot the sky!
  960.             if (z > li->frontsector->ceilingheight)
  961.                 return false;
  962.            
  963.             // it's a sky hack wall
  964.             if  (li->backsector && li->backsector->ceilingpic == skyflatnum)
  965.                 return false;          
  966.         }
  967.  
  968.         // Spawn bullet puffs.
  969.         P_SpawnPuff (x,y,z);
  970.        
  971.         // don't go any farther
  972.         return false;  
  973.     }
  974.    
  975.     // shoot a thing
  976.     th = in->d.thing;
  977.     if (th == shootthing)
  978.         return true;            // can't shoot self
  979.    
  980.     if (!(th->flags&MF_SHOOTABLE))
  981.         return true;            // corpse or something
  982.                
  983.     // check angles to see if the thing can be aimed at
  984.     dist = FixedMul (attackrange, in->frac);
  985.     thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
  986.  
  987.     if (thingtopslope < aimslope)
  988.         return true;            // shot over the thing
  989.  
  990.     thingbottomslope = FixedDiv (th->z - shootz, dist);
  991.  
  992.     if (thingbottomslope > aimslope)
  993.         return true;            // shot under the thing
  994.  
  995.    
  996.     // hit thing
  997.     // position a bit closer
  998.     frac = in->frac - FixedDiv (10*FRACUNIT,attackrange);
  999.  
  1000.     x = trace.x + FixedMul (trace.dx, frac);
  1001.     y = trace.y + FixedMul (trace.dy, frac);
  1002.     z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
  1003.  
  1004.     // Spawn bullet puffs or blod spots,
  1005.     // depending on target type.
  1006.     if (in->d.thing->flags & MF_NOBLOOD)
  1007.         P_SpawnPuff (x,y,z);
  1008.     else
  1009.         P_SpawnBlood (x,y,z, la_damage);
  1010.  
  1011.     if (la_damage)
  1012.         P_DamageMobj (th, shootthing, shootthing, la_damage);
  1013.  
  1014.     // don't go any farther
  1015.     return false;
  1016.        
  1017. }
  1018.  
  1019.  
  1020. //
  1021. // P_AimLineAttack
  1022. //
  1023. fixed_t
  1024. P_AimLineAttack
  1025. ( mobj_t*       t1,
  1026.   angle_t       angle,
  1027.   fixed_t       distance )
  1028. {
  1029.     fixed_t     x2;
  1030.     fixed_t     y2;
  1031.        
  1032.     angle >>= ANGLETOFINESHIFT;
  1033.     shootthing = t1;
  1034.    
  1035.     x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
  1036.     y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
  1037.     shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
  1038.  
  1039.     // can't shoot outside view angles
  1040.     topslope = 100*FRACUNIT/160;        
  1041.     bottomslope = -100*FRACUNIT/160;
  1042.    
  1043.     attackrange = distance;
  1044.     linetarget = NULL;
  1045.        
  1046.     P_PathTraverse ( t1->x, t1->y,
  1047.                      x2, y2,
  1048.                      PT_ADDLINES|PT_ADDTHINGS,
  1049.                      PTR_AimTraverse );
  1050.                
  1051.     if (linetarget)
  1052.         return aimslope;
  1053.  
  1054.     return 0;
  1055. }
  1056.  
  1057.  
  1058. //
  1059. // P_LineAttack
  1060. // If damage == 0, it is just a test trace
  1061. // that will leave linetarget set.
  1062. //
  1063. void
  1064. P_LineAttack
  1065. ( mobj_t*       t1,
  1066.   angle_t       angle,
  1067.   fixed_t       distance,
  1068.   fixed_t       slope,
  1069.   int           damage )
  1070. {
  1071.     fixed_t     x2;
  1072.     fixed_t     y2;
  1073.        
  1074.     angle >>= ANGLETOFINESHIFT;
  1075.     shootthing = t1;
  1076.     la_damage = damage;
  1077.     x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
  1078.     y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
  1079.     shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
  1080.     attackrange = distance;
  1081.     aimslope = slope;
  1082.                
  1083.     P_PathTraverse ( t1->x, t1->y,
  1084.                      x2, y2,
  1085.                      PT_ADDLINES|PT_ADDTHINGS,
  1086.                      PTR_ShootTraverse );
  1087. }
  1088.  
  1089.  
  1090.  
  1091. //
  1092. // USE LINES
  1093. //
  1094. mobj_t*         usething;
  1095.  
  1096. boolean PTR_UseTraverse (intercept_t* in)
  1097. {
  1098.     int         side;
  1099.        
  1100.     if (!in->d.line->special)
  1101.     {
  1102.         P_LineOpening (in->d.line);
  1103.         if (openrange <= 0)
  1104.         {
  1105.             S_StartSound (usething, sfx_noway);
  1106.            
  1107.             // can't use through a wall
  1108.             return false;      
  1109.         }
  1110.         // not a special line, but keep checking
  1111.         return true ;          
  1112.     }
  1113.        
  1114.     side = 0;
  1115.     if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
  1116.         side = 1;
  1117.    
  1118.     //  return false;           // don't use back side
  1119.        
  1120.     P_UseSpecialLine (usething, in->d.line, side);
  1121.  
  1122.     // can't use for than one special line in a row
  1123.     return false;
  1124. }
  1125.  
  1126.  
  1127. //
  1128. // P_UseLines
  1129. // Looks for special lines in front of the player to activate.
  1130. //
  1131. void P_UseLines (player_t*      player)
  1132. {
  1133.     int         angle;
  1134.     fixed_t     x1;
  1135.     fixed_t     y1;
  1136.     fixed_t     x2;
  1137.     fixed_t     y2;
  1138.        
  1139.     usething = player->mo;
  1140.                
  1141.     angle = player->mo->angle >> ANGLETOFINESHIFT;
  1142.  
  1143.     x1 = player->mo->x;
  1144.     y1 = player->mo->y;
  1145.     x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
  1146.     y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
  1147.        
  1148.     P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
  1149. }
  1150.  
  1151.  
  1152. //
  1153. // RADIUS ATTACK
  1154. //
  1155. mobj_t*         bombsource;
  1156. mobj_t*         bombspot;
  1157. int             bombdamage;
  1158.  
  1159.  
  1160. //
  1161. // PIT_RadiusAttack
  1162. // "bombsource" is the creature
  1163. // that caused the explosion at "bombspot".
  1164. //
  1165. boolean PIT_RadiusAttack (mobj_t* thing)
  1166. {
  1167.     fixed_t     dx;
  1168.     fixed_t     dy;
  1169.     fixed_t     dist;
  1170.        
  1171.     if (!(thing->flags & MF_SHOOTABLE) )
  1172.         return true;
  1173.  
  1174.     // Boss spider and cyborg
  1175.     // take no damage from concussion.
  1176.     if (thing->type == MT_CYBORG
  1177.         || thing->type == MT_SPIDER)
  1178.         return true;    
  1179.                
  1180.     dx = abs(thing->x - bombspot->x);
  1181.     dy = abs(thing->y - bombspot->y);
  1182.    
  1183.     dist = dx>dy ? dx : dy;
  1184.     dist = (dist - thing->radius) >> FRACBITS;
  1185.  
  1186.     if (dist < 0)
  1187.         dist = 0;
  1188.  
  1189.     if (dist >= bombdamage)
  1190.         return true;    // out of range
  1191.  
  1192.     if ( P_CheckSight (thing, bombspot) )
  1193.     {
  1194.         // must be in direct path
  1195.         P_DamageMobj (thing, bombspot, bombsource, bombdamage - dist);
  1196.     }
  1197.    
  1198.     return true;
  1199. }
  1200.  
  1201.  
  1202. //
  1203. // P_RadiusAttack
  1204. // Source is the creature that caused the explosion at spot.
  1205. //
  1206. void
  1207. P_RadiusAttack
  1208. ( mobj_t*       spot,
  1209.   mobj_t*       source,
  1210.   int           damage )
  1211. {
  1212.     int         x;
  1213.     int         y;
  1214.    
  1215.     int         xl;
  1216.     int         xh;
  1217.     int         yl;
  1218.     int         yh;
  1219.    
  1220.     fixed_t     dist;
  1221.        
  1222.     dist = (damage+MAXRADIUS)<<FRACBITS;
  1223.     yh = (spot->y + dist - bmaporgy)>>MAPBLOCKSHIFT;
  1224.     yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT;
  1225.     xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT;
  1226.     xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT;
  1227.     bombspot = spot;
  1228.     bombsource = source;
  1229.     bombdamage = damage;
  1230.        
  1231.     for (y=yl ; y<=yh ; y++)
  1232.         for (x=xl ; x<=xh ; x++)
  1233.             P_BlockThingsIterator (x, y, PIT_RadiusAttack );
  1234. }
  1235.  
  1236.  
  1237.  
  1238. //
  1239. // SECTOR HEIGHT CHANGING
  1240. // After modifying a sectors floor or ceiling height,
  1241. // call this routine to adjust the positions
  1242. // of all things that touch the sector.
  1243. //
  1244. // If anything doesn't fit anymore, true will be returned.
  1245. // If crunch is true, they will take damage
  1246. //  as they are being crushed.
  1247. // If Crunch is false, you should set the sector height back
  1248. //  the way it was and call P_ChangeSector again
  1249. //  to undo the changes.
  1250. //
  1251. boolean         crushchange;
  1252. boolean         nofit;
  1253.  
  1254.  
  1255. //
  1256. // PIT_ChangeSector
  1257. //
  1258. boolean PIT_ChangeSector (mobj_t*       thing)
  1259. {
  1260.     mobj_t*     mo;
  1261.        
  1262.     if (P_ThingHeightClip (thing))
  1263.     {
  1264.         // keep checking
  1265.         return true;
  1266.     }
  1267.    
  1268.  
  1269.     // crunch bodies to giblets
  1270.     if (thing->health <= 0)
  1271.     {
  1272.         P_SetMobjState (thing, S_GIBS);
  1273.  
  1274.         thing->flags &= ~MF_SOLID;
  1275.         thing->height = 0;
  1276.         thing->radius = 0;
  1277.  
  1278.         // keep checking
  1279.         return true;            
  1280.     }
  1281.  
  1282.     // crunch dropped items
  1283.     if (thing->flags & MF_DROPPED)
  1284.     {
  1285.         P_RemoveMobj (thing);
  1286.        
  1287.         // keep checking
  1288.         return true;            
  1289.     }
  1290.  
  1291.     if (! (thing->flags & MF_SHOOTABLE) )
  1292.     {
  1293.         // assume it is bloody gibs or something
  1294.         return true;                    
  1295.     }
  1296.    
  1297.     nofit = true;
  1298.  
  1299.     if (crushchange && !(leveltime&3) )
  1300.     {
  1301.         P_DamageMobj(thing,NULL,NULL,10);
  1302.  
  1303.         // spray blood in a random direction
  1304.         mo = P_SpawnMobj (thing->x,
  1305.                           thing->y,
  1306.                           thing->z + thing->height/2, MT_BLOOD);
  1307.        
  1308.         mo->momx = (P_Random() - P_Random ())<<12;
  1309.         mo->momy = (P_Random() - P_Random ())<<12;
  1310.     }
  1311.  
  1312.     // keep checking (crush other things)      
  1313.     return true;        
  1314. }
  1315.  
  1316.  
  1317.  
  1318. //
  1319. // P_ChangeSector
  1320. //
  1321. boolean
  1322. P_ChangeSector
  1323. ( sector_t*     sector,
  1324.   boolean       crunch )
  1325. {
  1326.     int         x;
  1327.     int         y;
  1328.        
  1329.     nofit = false;
  1330.     crushchange = crunch;
  1331.        
  1332.     // re-check heights for all things near the moving sector
  1333.     for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++)
  1334.         for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++)
  1335.             P_BlockThingsIterator (x, y, PIT_ChangeSector);
  1336.        
  1337.        
  1338.     return nofit;
  1339. }
  1340.  
  1341.