p_map.c 28 KB

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