Subversion Repositories Kolibri OS

Rev

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