p_maputl.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. /* Emacs style mode select -*- C++ -*-
  2. *-----------------------------------------------------------------------------
  3. *
  4. *
  5. * PrBoom: a Doom port merged with LxDoom and LSDLDoom
  6. * based on BOOM, a modified and improved DOOM engine
  7. * Copyright (C) 1999 by
  8. * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
  9. * Copyright (C) 1999-2000 by
  10. * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
  11. * Copyright 2005, 2006 by
  12. * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
  13. *
  14. * This program is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU General Public License
  16. * as published by the Free Software Foundation; either version 2
  17. * of the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  27. * 02111-1307, USA.
  28. *
  29. * DESCRIPTION:
  30. * Movement/collision utility functions,
  31. * as used by function in p_map.c.
  32. * BLOCKMAP Iterator functions,
  33. * and some PIT_* functions to use for iteration.
  34. *
  35. *-----------------------------------------------------------------------------*/
  36. #include "doomstat.h"
  37. #include "m_bbox.h"
  38. #include "r_main.h"
  39. #include "p_maputl.h"
  40. #include "p_map.h"
  41. #include "p_setup.h"
  42. //
  43. // P_AproxDistance
  44. // Gives an estimation of distance (not exact)
  45. //
  46. fixed_t CONSTFUNC P_AproxDistance(fixed_t dx, fixed_t dy)
  47. {
  48. dx = D_abs(dx);
  49. dy = D_abs(dy);
  50. if (dx < dy)
  51. return dx+dy-(dx>>1);
  52. return dx+dy-(dy>>1);
  53. }
  54. //
  55. // P_PointOnLineSide
  56. // Returns 0 or 1
  57. //
  58. // killough 5/3/98: reformatted, cleaned up
  59. int PUREFUNC P_PointOnLineSide(fixed_t x, fixed_t y, const line_t *line)
  60. {
  61. return
  62. !line->dx ? x <= line->v1->x ? line->dy > 0 : line->dy < 0 :
  63. !line->dy ? y <= line->v1->y ? line->dx < 0 : line->dx > 0 :
  64. FixedMul(y-line->v1->y, line->dx>>FRACBITS) >=
  65. FixedMul(line->dy>>FRACBITS, x-line->v1->x);
  66. }
  67. //
  68. // P_BoxOnLineSide
  69. // Considers the line to be infinite
  70. // Returns side 0 or 1, -1 if box crosses the line.
  71. //
  72. // killough 5/3/98: reformatted, cleaned up
  73. int PUREFUNC P_BoxOnLineSide(const fixed_t *tmbox, const line_t *ld)
  74. {
  75. switch (ld->slopetype)
  76. {
  77. int p;
  78. default: // shut up compiler warnings -- killough
  79. case ST_HORIZONTAL:
  80. return
  81. (tmbox[BOXBOTTOM] > ld->v1->y) == (p = tmbox[BOXTOP] > ld->v1->y) ?
  82. p ^ (ld->dx < 0) : -1;
  83. case ST_VERTICAL:
  84. return
  85. (tmbox[BOXLEFT] < ld->v1->x) == (p = tmbox[BOXRIGHT] < ld->v1->x) ?
  86. p ^ (ld->dy < 0) : -1;
  87. case ST_POSITIVE:
  88. return
  89. P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld) ==
  90. (p = P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXTOP], ld)) ? p : -1;
  91. case ST_NEGATIVE:
  92. return
  93. (P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld)) ==
  94. (p = P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXTOP], ld)) ? p : -1;
  95. }
  96. }
  97. //
  98. // P_PointOnDivlineSide
  99. // Returns 0 or 1.
  100. //
  101. // killough 5/3/98: reformatted, cleaned up
  102. static int PUREFUNC P_PointOnDivlineSide(fixed_t x, fixed_t y, const divline_t *line)
  103. {
  104. return
  105. !line->dx ? x <= line->x ? line->dy > 0 : line->dy < 0 :
  106. !line->dy ? y <= line->y ? line->dx < 0 : line->dx > 0 :
  107. (line->dy^line->dx^(x -= line->x)^(y -= line->y)) < 0 ? (line->dy^x) < 0 :
  108. FixedMul(y>>8, line->dx>>8) >= FixedMul(line->dy>>8, x>>8);
  109. }
  110. //
  111. // P_MakeDivline
  112. //
  113. static void P_MakeDivline(const line_t *li, divline_t *dl)
  114. {
  115. dl->x = li->v1->x;
  116. dl->y = li->v1->y;
  117. dl->dx = li->dx;
  118. dl->dy = li->dy;
  119. }
  120. //
  121. // P_InterceptVector
  122. // Returns the fractional intercept point
  123. // along the first divline.
  124. // This is only called by the addthings
  125. // and addlines traversers.
  126. //
  127. /* cph - this is killough's 4/19/98 version of P_InterceptVector and
  128. * P_InterceptVector2 (which were interchangeable). We still use this
  129. * in compatibility mode. */
  130. fixed_t PUREFUNC P_InterceptVector2(const divline_t *v2, const divline_t *v1)
  131. {
  132. fixed_t den;
  133. return (den = FixedMul(v1->dy>>8, v2->dx) - FixedMul(v1->dx>>8, v2->dy)) ?
  134. FixedDiv(FixedMul((v1->x - v2->x)>>8, v1->dy) +
  135. FixedMul((v2->y - v1->y)>>8, v1->dx), den) : 0;
  136. }
  137. fixed_t PUREFUNC P_InterceptVector(const divline_t *v2, const divline_t *v1)
  138. {
  139. if (compatibility_level < prboom_4_compatibility)
  140. return P_InterceptVector2(v2, v1);
  141. else {
  142. /* cph - This was introduced at prboom_4_compatibility - no precision/overflow problems */
  143. int_64_t den = (int_64_t)v1->dy * v2->dx - (int_64_t)v1->dx * v2->dy;
  144. den >>= 16;
  145. if (!den)
  146. return 0;
  147. return (fixed_t)(((int_64_t)(v1->x - v2->x) * v1->dy - (int_64_t)(v1->y - v2->y) * v1->dx) / den);
  148. }
  149. }
  150. //
  151. // P_LineOpening
  152. // Sets opentop and openbottom to the window
  153. // through a two sided line.
  154. // OPTIMIZE: keep this precalculated
  155. //
  156. fixed_t opentop;
  157. fixed_t openbottom;
  158. fixed_t openrange;
  159. fixed_t lowfloor;
  160. // moved front and back outside P-LineOpening and changed // phares 3/7/98
  161. // them to these so we can pick up the new friction value
  162. // in PIT_CheckLine()
  163. sector_t *openfrontsector; // made global // phares
  164. sector_t *openbacksector; // made global
  165. void P_LineOpening(const line_t *linedef)
  166. {
  167. if (linedef->sidenum[1] == NO_INDEX) // single sided line
  168. {
  169. openrange = 0;
  170. return;
  171. }
  172. openfrontsector = linedef->frontsector;
  173. openbacksector = linedef->backsector;
  174. if (openfrontsector->ceilingheight < openbacksector->ceilingheight)
  175. opentop = openfrontsector->ceilingheight;
  176. else
  177. opentop = openbacksector->ceilingheight;
  178. if (openfrontsector->floorheight > openbacksector->floorheight)
  179. {
  180. openbottom = openfrontsector->floorheight;
  181. lowfloor = openbacksector->floorheight;
  182. }
  183. else
  184. {
  185. openbottom = openbacksector->floorheight;
  186. lowfloor = openfrontsector->floorheight;
  187. }
  188. openrange = opentop - openbottom;
  189. }
  190. //
  191. // THING POSITION SETTING
  192. //
  193. //
  194. // P_UnsetThingPosition
  195. // Unlinks a thing from block map and sectors.
  196. // On each position change, BLOCKMAP and other
  197. // lookups maintaining lists ot things inside
  198. // these structures need to be updated.
  199. //
  200. void P_UnsetThingPosition (mobj_t *thing)
  201. {
  202. if (!(thing->flags & MF_NOSECTOR))
  203. {
  204. /* invisible things don't need to be in sector list
  205. * unlink from subsector
  206. *
  207. * killough 8/11/98: simpler scheme using pointers-to-pointers for prev
  208. * pointers, allows head node pointers to be treated like everything else
  209. */
  210. mobj_t **sprev = thing->sprev;
  211. mobj_t *snext = thing->snext;
  212. if ((*sprev = snext)) // unlink from sector list
  213. snext->sprev = sprev;
  214. // phares 3/14/98
  215. //
  216. // Save the sector list pointed to by touching_sectorlist.
  217. // In P_SetThingPosition, we'll keep any nodes that represent
  218. // sectors the Thing still touches. We'll add new ones then, and
  219. // delete any nodes for sectors the Thing has vacated. Then we'll
  220. // put it back into touching_sectorlist. It's done this way to
  221. // avoid a lot of deleting/creating for nodes, when most of the
  222. // time you just get back what you deleted anyway.
  223. //
  224. // If this Thing is being removed entirely, then the calling
  225. // routine will clear out the nodes in sector_list.
  226. sector_list = thing->touching_sectorlist;
  227. thing->touching_sectorlist = NULL; //to be restored by P_SetThingPosition
  228. }
  229. if (!(thing->flags & MF_NOBLOCKMAP))
  230. {
  231. /* inert things don't need to be in blockmap
  232. *
  233. * killough 8/11/98: simpler scheme using pointers-to-pointers for prev
  234. * pointers, allows head node pointers to be treated like everything else
  235. *
  236. * Also more robust, since it doesn't depend on current position for
  237. * unlinking. Old method required computing head node based on position
  238. * at time of unlinking, assuming it was the same position as during
  239. * linking.
  240. */
  241. mobj_t *bnext, **bprev = thing->bprev;
  242. if (bprev && (*bprev = bnext = thing->bnext)) // unlink from block map
  243. bnext->bprev = bprev;
  244. }
  245. }
  246. //
  247. // P_SetThingPosition
  248. // Links a thing into both a block and a subsector
  249. // based on it's x y.
  250. // Sets thing->subsector properly
  251. //
  252. // killough 5/3/98: reformatted, cleaned up
  253. void P_SetThingPosition(mobj_t *thing)
  254. { // link into subsector
  255. subsector_t *ss = thing->subsector = R_PointInSubsector(thing->x, thing->y);
  256. if (!(thing->flags & MF_NOSECTOR))
  257. {
  258. // invisible things don't go into the sector links
  259. // killough 8/11/98: simpler scheme using pointer-to-pointer prev
  260. // pointers, allows head nodes to be treated like everything else
  261. mobj_t **link = &ss->sector->thinglist;
  262. mobj_t *snext = *link;
  263. if ((thing->snext = snext))
  264. snext->sprev = &thing->snext;
  265. thing->sprev = link;
  266. *link = thing;
  267. // phares 3/16/98
  268. //
  269. // If sector_list isn't NULL, it has a collection of sector
  270. // nodes that were just removed from this Thing.
  271. // Collect the sectors the object will live in by looking at
  272. // the existing sector_list and adding new nodes and deleting
  273. // obsolete ones.
  274. // When a node is deleted, its sector links (the links starting
  275. // at sector_t->touching_thinglist) are broken. When a node is
  276. // added, new sector links are created.
  277. P_CreateSecNodeList(thing,thing->x,thing->y);
  278. thing->touching_sectorlist = sector_list; // Attach to Thing's mobj_t
  279. sector_list = NULL; // clear for next time
  280. }
  281. // link into blockmap
  282. if (!(thing->flags & MF_NOBLOCKMAP))
  283. {
  284. // inert things don't need to be in blockmap
  285. int blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
  286. int blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
  287. if (blockx>=0 && blockx < bmapwidth && blocky>=0 && blocky < bmapheight)
  288. {
  289. // killough 8/11/98: simpler scheme using pointer-to-pointer prev
  290. // pointers, allows head nodes to be treated like everything else
  291. mobj_t **link = &blocklinks[blocky*bmapwidth+blockx];
  292. mobj_t *bnext = *link;
  293. if ((thing->bnext = bnext))
  294. bnext->bprev = &thing->bnext;
  295. thing->bprev = link;
  296. *link = thing;
  297. }
  298. else // thing is off the map
  299. thing->bnext = NULL, thing->bprev = NULL;
  300. }
  301. }
  302. //
  303. // BLOCK MAP ITERATORS
  304. // For each line/thing in the given mapblock,
  305. // call the passed PIT_* function.
  306. // If the function returns false,
  307. // exit with false without checking anything else.
  308. //
  309. //
  310. // P_BlockLinesIterator
  311. // The validcount flags are used to avoid checking lines
  312. // that are marked in multiple mapblocks,
  313. // so increment validcount before the first call
  314. // to P_BlockLinesIterator, then make one or more calls
  315. // to it.
  316. //
  317. // killough 5/3/98: reformatted, cleaned up
  318. boolean P_BlockLinesIterator(int x, int y, boolean func(line_t*))
  319. {
  320. int offset;
  321. const long *list; // killough 3/1/98: for removal of blockmap limit
  322. if (x<0 || y<0 || x>=bmapwidth || y>=bmapheight)
  323. return true;
  324. offset = y*bmapwidth+x;
  325. offset = *(blockmap+offset);
  326. list = blockmaplump+offset; // original was reading // phares
  327. // delmiting 0 as linedef 0 // phares
  328. // killough 1/31/98: for compatibility we need to use the old method.
  329. // Most demos go out of sync, and maybe other problems happen, if we
  330. // don't consider linedef 0. For safety this should be qualified.
  331. if (!demo_compatibility) // killough 2/22/98: demo_compatibility check
  332. list++; // skip 0 starting delimiter // phares
  333. for ( ; *list != -1 ; list++) // phares
  334. {
  335. line_t *ld = &lines[*list];
  336. if (ld->validcount == validcount)
  337. continue; // line has already been checked
  338. ld->validcount = validcount;
  339. if (!func(ld))
  340. return false;
  341. }
  342. return true; // everything was checked
  343. }
  344. //
  345. // P_BlockThingsIterator
  346. //
  347. // killough 5/3/98: reformatted, cleaned up
  348. boolean P_BlockThingsIterator(int x, int y, boolean func(mobj_t*))
  349. {
  350. mobj_t *mobj;
  351. if (!(x<0 || y<0 || x>=bmapwidth || y>=bmapheight))
  352. for (mobj = blocklinks[y*bmapwidth+x]; mobj; mobj = mobj->bnext)
  353. if (!func(mobj))
  354. return false;
  355. return true;
  356. }
  357. //
  358. // INTERCEPT ROUTINES
  359. //
  360. // 1/11/98 killough: Intercept limit removed
  361. static intercept_t *intercepts, *intercept_p;
  362. // Check for limit and double size if necessary -- killough
  363. static void check_intercept(void)
  364. {
  365. static size_t num_intercepts;
  366. size_t offset = intercept_p - intercepts;
  367. if (offset >= num_intercepts)
  368. {
  369. num_intercepts = num_intercepts ? num_intercepts*2 : 128;
  370. intercepts = realloc(intercepts, sizeof(*intercepts)*num_intercepts);
  371. intercept_p = intercepts + offset;
  372. }
  373. }
  374. divline_t trace;
  375. // PIT_AddLineIntercepts.
  376. // Looks for lines in the given block
  377. // that intercept the given trace
  378. // to add to the intercepts list.
  379. //
  380. // A line is crossed if its endpoints
  381. // are on opposite sides of the trace.
  382. //
  383. // killough 5/3/98: reformatted, cleaned up
  384. boolean PIT_AddLineIntercepts(line_t *ld)
  385. {
  386. int s1;
  387. int s2;
  388. fixed_t frac;
  389. divline_t dl;
  390. // avoid precision problems with two routines
  391. if (trace.dx > FRACUNIT*16 || trace.dy > FRACUNIT*16 ||
  392. trace.dx < -FRACUNIT*16 || trace.dy < -FRACUNIT*16)
  393. {
  394. s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
  395. s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
  396. }
  397. else
  398. {
  399. s1 = P_PointOnLineSide (trace.x, trace.y, ld);
  400. s2 = P_PointOnLineSide (trace.x+trace.dx, trace.y+trace.dy, ld);
  401. }
  402. if (s1 == s2)
  403. return true; // line isn't crossed
  404. // hit the line
  405. P_MakeDivline(ld, &dl);
  406. frac = P_InterceptVector(&trace, &dl);
  407. if (frac < 0)
  408. return true; // behind source
  409. check_intercept(); // killough
  410. intercept_p->frac = frac;
  411. intercept_p->isaline = true;
  412. intercept_p->d.line = ld;
  413. intercept_p++;
  414. return true; // continue
  415. }
  416. //
  417. // PIT_AddThingIntercepts
  418. //
  419. // killough 5/3/98: reformatted, cleaned up
  420. boolean PIT_AddThingIntercepts(mobj_t *thing)
  421. {
  422. fixed_t x1, y1;
  423. fixed_t x2, y2;
  424. int s1, s2;
  425. divline_t dl;
  426. fixed_t frac;
  427. // check a corner to corner crossection for hit
  428. if ((trace.dx ^ trace.dy) > 0)
  429. {
  430. x1 = thing->x - thing->radius;
  431. y1 = thing->y + thing->radius;
  432. x2 = thing->x + thing->radius;
  433. y2 = thing->y - thing->radius;
  434. }
  435. else
  436. {
  437. x1 = thing->x - thing->radius;
  438. y1 = thing->y - thing->radius;
  439. x2 = thing->x + thing->radius;
  440. y2 = thing->y + thing->radius;
  441. }
  442. s1 = P_PointOnDivlineSide (x1, y1, &trace);
  443. s2 = P_PointOnDivlineSide (x2, y2, &trace);
  444. if (s1 == s2)
  445. return true; // line isn't crossed
  446. dl.x = x1;
  447. dl.y = y1;
  448. dl.dx = x2-x1;
  449. dl.dy = y2-y1;
  450. frac = P_InterceptVector (&trace, &dl);
  451. if (frac < 0)
  452. return true; // behind source
  453. check_intercept(); // killough
  454. intercept_p->frac = frac;
  455. intercept_p->isaline = false;
  456. intercept_p->d.thing = thing;
  457. intercept_p++;
  458. return true; // keep going
  459. }
  460. //
  461. // P_TraverseIntercepts
  462. // Returns true if the traverser function returns true
  463. // for all lines.
  464. //
  465. // killough 5/3/98: reformatted, cleaned up
  466. boolean P_TraverseIntercepts(traverser_t func, fixed_t maxfrac)
  467. {
  468. intercept_t *in = NULL;
  469. int count = intercept_p - intercepts;
  470. while (count--)
  471. {
  472. fixed_t dist = INT_MAX;
  473. intercept_t *scan;
  474. for (scan = intercepts; scan < intercept_p; scan++)
  475. if (scan->frac < dist)
  476. dist = (in=scan)->frac;
  477. if (dist > maxfrac)
  478. return true; // checked everything in range
  479. if (!func(in))
  480. return false; // don't bother going farther
  481. in->frac = INT_MAX;
  482. }
  483. return true; // everything was traversed
  484. }
  485. //
  486. // P_PathTraverse
  487. // Traces a line from x1,y1 to x2,y2,
  488. // calling the traverser function for each.
  489. // Returns true if the traverser function returns true
  490. // for all lines.
  491. //
  492. // killough 5/3/98: reformatted, cleaned up
  493. boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2,
  494. int flags, boolean trav(intercept_t *))
  495. {
  496. fixed_t xt1, yt1;
  497. fixed_t xt2, yt2;
  498. fixed_t xstep, ystep;
  499. fixed_t partial;
  500. fixed_t xintercept, yintercept;
  501. int mapx, mapy;
  502. int mapxstep, mapystep;
  503. int count;
  504. validcount++;
  505. intercept_p = intercepts;
  506. if (!((x1-bmaporgx)&(MAPBLOCKSIZE-1)))
  507. x1 += FRACUNIT; // don't side exactly on a line
  508. if (!((y1-bmaporgy)&(MAPBLOCKSIZE-1)))
  509. y1 += FRACUNIT; // don't side exactly on a line
  510. trace.x = x1;
  511. trace.y = y1;
  512. trace.dx = x2 - x1;
  513. trace.dy = y2 - y1;
  514. x1 -= bmaporgx;
  515. y1 -= bmaporgy;
  516. xt1 = x1>>MAPBLOCKSHIFT;
  517. yt1 = y1>>MAPBLOCKSHIFT;
  518. x2 -= bmaporgx;
  519. y2 -= bmaporgy;
  520. xt2 = x2>>MAPBLOCKSHIFT;
  521. yt2 = y2>>MAPBLOCKSHIFT;
  522. if (xt2 > xt1)
  523. {
  524. mapxstep = 1;
  525. partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1));
  526. ystep = FixedDiv (y2-y1,D_abs(x2-x1));
  527. }
  528. else
  529. if (xt2 < xt1)
  530. {
  531. mapxstep = -1;
  532. partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1);
  533. ystep = FixedDiv (y2-y1,D_abs(x2-x1));
  534. }
  535. else
  536. {
  537. mapxstep = 0;
  538. partial = FRACUNIT;
  539. ystep = 256*FRACUNIT;
  540. }
  541. yintercept = (y1>>MAPBTOFRAC) + FixedMul(partial, ystep);
  542. if (yt2 > yt1)
  543. {
  544. mapystep = 1;
  545. partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1));
  546. xstep = FixedDiv (x2-x1,D_abs(y2-y1));
  547. }
  548. else
  549. if (yt2 < yt1)
  550. {
  551. mapystep = -1;
  552. partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1);
  553. xstep = FixedDiv (x2-x1,D_abs(y2-y1));
  554. }
  555. else
  556. {
  557. mapystep = 0;
  558. partial = FRACUNIT;
  559. xstep = 256*FRACUNIT;
  560. }
  561. xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep);
  562. // Step through map blocks.
  563. // Count is present to prevent a round off error
  564. // from skipping the break.
  565. mapx = xt1;
  566. mapy = yt1;
  567. for (count = 0; count < 64; count++)
  568. {
  569. if (flags & PT_ADDLINES)
  570. if (!P_BlockLinesIterator(mapx, mapy,PIT_AddLineIntercepts))
  571. return false; // early out
  572. if (flags & PT_ADDTHINGS)
  573. if (!P_BlockThingsIterator(mapx, mapy,PIT_AddThingIntercepts))
  574. return false; // early out
  575. if (mapx == xt2 && mapy == yt2)
  576. break;
  577. if ((yintercept >> FRACBITS) == mapy)
  578. {
  579. yintercept += ystep;
  580. mapx += mapxstep;
  581. }
  582. else
  583. if ((xintercept >> FRACBITS) == mapx)
  584. {
  585. xintercept += xstep;
  586. mapy += mapystep;
  587. }
  588. }
  589. // go through the sorted list
  590. return P_TraverseIntercepts(trav, FRACUNIT);
  591. }