p_map.c
上传用户:xuyinpeng
上传日期:2021-05-12
资源大小:455k
文件大小:29k
源码类别:

射击游戏

开发平台:

Visual C++

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