P_MAPUTL.C 21 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057
  1. //**************************************************************************
  2. //**
  3. //** p_maputl.c : Heretic 2 : Raven Software, Corp.
  4. //**
  5. //** $RCSfile: p_maputl.c,v $
  6. //** $Revision: 1.11 $
  7. //** $Date: 95/10/04 02:39:28 $
  8. //** $Author: paul $
  9. //**
  10. //**************************************************************************
  11. #include "h2def.h"
  12. #include "p_local.h"
  13. static mobj_t *RoughBlockCheck(mobj_t *mo, int index);
  14. /*
  15. ===================
  16. =
  17. = P_AproxDistance
  18. =
  19. = Gives an estimation of distance (not exact)
  20. =
  21. ===================
  22. */
  23. fixed_t P_AproxDistance (fixed_t dx, fixed_t dy)
  24. {
  25. dx = abs(dx);
  26. dy = abs(dy);
  27. if (dx < dy)
  28. return dx+dy-(dx>>1);
  29. return dx+dy-(dy>>1);
  30. }
  31. /*
  32. ==================
  33. =
  34. = P_PointOnLineSide
  35. =
  36. = Returns 0 or 1
  37. ==================
  38. */
  39. int P_PointOnLineSide (fixed_t x, fixed_t y, line_t *line)
  40. {
  41. fixed_t dx,dy;
  42. fixed_t left, right;
  43. if (!line->dx)
  44. {
  45. if (x <= line->v1->x)
  46. return line->dy > 0;
  47. return line->dy < 0;
  48. }
  49. if (!line->dy)
  50. {
  51. if (y <= line->v1->y)
  52. return line->dx < 0;
  53. return line->dx > 0;
  54. }
  55. dx = (x - line->v1->x);
  56. dy = (y - line->v1->y);
  57. left = FixedMul ( line->dy>>FRACBITS , dx );
  58. right = FixedMul ( dy , line->dx>>FRACBITS );
  59. if (right < left)
  60. return 0; // front side
  61. return 1; // back side
  62. }
  63. /*
  64. =================
  65. =
  66. = P_BoxOnLineSide
  67. =
  68. = Considers the line to be infinite
  69. = Returns side 0 or 1, -1 if box crosses the line
  70. =================
  71. */
  72. int P_BoxOnLineSide (fixed_t *tmbox, line_t *ld)
  73. {
  74. int p1, p2;
  75. switch (ld->slopetype)
  76. {
  77. case ST_HORIZONTAL:
  78. p1 = tmbox[BOXTOP] > ld->v1->y;
  79. p2 = tmbox[BOXBOTTOM] > ld->v1->y;
  80. if (ld->dx < 0)
  81. {
  82. p1 ^= 1;
  83. p2 ^= 1;
  84. }
  85. break;
  86. case ST_VERTICAL:
  87. p1 = tmbox[BOXRIGHT] < ld->v1->x;
  88. p2 = tmbox[BOXLEFT] < ld->v1->x;
  89. if (ld->dy < 0)
  90. {
  91. p1 ^= 1;
  92. p2 ^= 1;
  93. }
  94. break;
  95. case ST_POSITIVE:
  96. p1 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXTOP], ld);
  97. p2 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld);
  98. break;
  99. case ST_NEGATIVE:
  100. p1 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXTOP], ld);
  101. p2 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld);
  102. break;
  103. }
  104. if (p1 == p2)
  105. return p1;
  106. return -1;
  107. }
  108. /*
  109. ==================
  110. =
  111. = P_PointOnDivlineSide
  112. =
  113. = Returns 0 or 1
  114. ==================
  115. */
  116. int P_PointOnDivlineSide (fixed_t x, fixed_t y, divline_t *line)
  117. {
  118. fixed_t dx,dy;
  119. fixed_t left, right;
  120. if (!line->dx)
  121. {
  122. if (x <= line->x)
  123. return line->dy > 0;
  124. return line->dy < 0;
  125. }
  126. if (!line->dy)
  127. {
  128. if (y <= line->y)
  129. return line->dx < 0;
  130. return line->dx > 0;
  131. }
  132. dx = (x - line->x);
  133. dy = (y - line->y);
  134. // try to quickly decide by looking at sign bits
  135. if ( (line->dy ^ line->dx ^ dx ^ dy)&0x80000000 )
  136. {
  137. if ( (line->dy ^ dx) & 0x80000000 )
  138. return 1; // (left is negative)
  139. return 0;
  140. }
  141. left = FixedMul ( line->dy>>8, dx>>8 );
  142. right = FixedMul ( dy>>8 , line->dx>>8 );
  143. if (right < left)
  144. return 0; // front side
  145. return 1; // back side
  146. }
  147. /*
  148. ==============
  149. =
  150. = P_MakeDivline
  151. =
  152. ==============
  153. */
  154. void P_MakeDivline (line_t *li, divline_t *dl)
  155. {
  156. dl->x = li->v1->x;
  157. dl->y = li->v1->y;
  158. dl->dx = li->dx;
  159. dl->dy = li->dy;
  160. }
  161. /*
  162. ===============
  163. =
  164. = P_InterceptVector
  165. =
  166. = Returns the fractional intercept point along the first divline
  167. =
  168. = This is only called by the addthings and addlines traversers
  169. ===============
  170. */
  171. fixed_t P_InterceptVector (divline_t *v2, divline_t *v1)
  172. {
  173. #if 1
  174. fixed_t frac, num, den;
  175. den = FixedMul (v1->dy>>8,v2->dx) - FixedMul(v1->dx>>8,v2->dy);
  176. if (den == 0)
  177. return 0;
  178. // I_Error ("P_InterceptVector: parallel");
  179. num = FixedMul ( (v1->x - v2->x)>>8 ,v1->dy) +
  180. FixedMul ( (v2->y - v1->y)>>8 , v1->dx);
  181. frac = FixedDiv (num , den);
  182. return frac;
  183. #else
  184. float frac, num, den, v1x,v1y,v1dx,v1dy,v2x,v2y,v2dx,v2dy;
  185. v1x = (float)v1->x/FRACUNIT;
  186. v1y = (float)v1->y/FRACUNIT;
  187. v1dx = (float)v1->dx/FRACUNIT;
  188. v1dy = (float)v1->dy/FRACUNIT;
  189. v2x = (float)v2->x/FRACUNIT;
  190. v2y = (float)v2->y/FRACUNIT;
  191. v2dx = (float)v2->dx/FRACUNIT;
  192. v2dy = (float)v2->dy/FRACUNIT;
  193. den = v1dy*v2dx - v1dx*v2dy;
  194. if (den == 0)
  195. return 0; // parallel
  196. num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx;
  197. frac = num / den;
  198. return frac*FRACUNIT;
  199. #endif
  200. }
  201. /*
  202. ==================
  203. =
  204. = P_LineOpening
  205. =
  206. = Sets opentop and openbottom to the window through a two sided line
  207. = OPTIMIZE: keep this precalculated
  208. ==================
  209. */
  210. fixed_t opentop, openbottom, openrange;
  211. fixed_t lowfloor;
  212. void P_LineOpening (line_t *linedef)
  213. {
  214. sector_t *front, *back;
  215. if (linedef->sidenum[1] == -1)
  216. { // single sided line
  217. openrange = 0;
  218. return;
  219. }
  220. front = linedef->frontsector;
  221. back = linedef->backsector;
  222. if (front->ceilingheight < back->ceilingheight)
  223. opentop = front->ceilingheight;
  224. else
  225. opentop = back->ceilingheight;
  226. if (front->floorheight > back->floorheight)
  227. {
  228. openbottom = front->floorheight;
  229. lowfloor = back->floorheight;
  230. tmfloorpic = front->floorpic;
  231. }
  232. else
  233. {
  234. openbottom = back->floorheight;
  235. lowfloor = front->floorheight;
  236. tmfloorpic = back->floorpic;
  237. }
  238. openrange = opentop - openbottom;
  239. }
  240. /*
  241. ===============================================================================
  242. THING POSITION SETTING
  243. ===============================================================================
  244. */
  245. /*
  246. ===================
  247. =
  248. = P_UnsetThingPosition
  249. =
  250. = Unlinks a thing from block map and sectors
  251. =
  252. ===================
  253. */
  254. void P_UnsetThingPosition (mobj_t *thing)
  255. {
  256. int blockx, blocky;
  257. if ( ! (thing->flags & MF_NOSECTOR) )
  258. { // inert things don't need to be in blockmap
  259. // unlink from subsector
  260. if (thing->snext)
  261. thing->snext->sprev = thing->sprev;
  262. if (thing->sprev)
  263. thing->sprev->snext = thing->snext;
  264. else
  265. thing->subsector->sector->thinglist = thing->snext;
  266. }
  267. if ( ! (thing->flags & MF_NOBLOCKMAP) )
  268. { // inert things don't need to be in blockmap
  269. // unlink from block map
  270. if (thing->bnext)
  271. thing->bnext->bprev = thing->bprev;
  272. if (thing->bprev)
  273. thing->bprev->bnext = thing->bnext;
  274. else
  275. {
  276. blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
  277. blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
  278. if (blockx>=0 && blockx < bmapwidth
  279. && blocky>=0 && blocky <bmapheight)
  280. blocklinks[blocky*bmapwidth+blockx] = thing->bnext;
  281. }
  282. }
  283. }
  284. /*
  285. ===================
  286. =
  287. = P_SetThingPosition
  288. =
  289. = Links a thing into both a block and a subsector based on it's x y
  290. = Sets thing->subsector properly
  291. =
  292. ===================
  293. */
  294. void P_SetThingPosition (mobj_t *thing)
  295. {
  296. subsector_t *ss;
  297. sector_t *sec;
  298. int blockx, blocky;
  299. mobj_t **link;
  300. //
  301. // link into subsector
  302. //
  303. ss = R_PointInSubsector (thing->x,thing->y);
  304. thing->subsector = ss;
  305. if ( ! (thing->flags & MF_NOSECTOR) )
  306. { // invisible things don't go into the sector links
  307. sec = ss->sector;
  308. thing->sprev = NULL;
  309. thing->snext = sec->thinglist;
  310. if (sec->thinglist)
  311. sec->thinglist->sprev = thing;
  312. sec->thinglist = thing;
  313. }
  314. //
  315. // link into blockmap
  316. //
  317. if ( ! (thing->flags & MF_NOBLOCKMAP) )
  318. { // inert things don't need to be in blockmap
  319. blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
  320. blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
  321. if (blockx>=0 && blockx < bmapwidth && blocky>=0 && blocky <bmapheight)
  322. {
  323. link = &blocklinks[blocky*bmapwidth+blockx];
  324. thing->bprev = NULL;
  325. thing->bnext = *link;
  326. if (*link)
  327. (*link)->bprev = thing;
  328. *link = thing;
  329. }
  330. else
  331. { // thing is off the map
  332. thing->bnext = thing->bprev = NULL;
  333. }
  334. }
  335. }
  336. /*
  337. ===============================================================================
  338. BLOCK MAP ITERATORS
  339. For each line/thing in the given mapblock, call the passed function.
  340. If the function returns false, exit with false without checking anything else.
  341. ===============================================================================
  342. */
  343. /*
  344. ==================
  345. =
  346. = P_BlockLinesIterator
  347. =
  348. = The validcount flags are used to avoid checking lines
  349. = that are marked in multiple mapblocks, so increment validcount before
  350. = the first call to P_BlockLinesIterator, then make one or more calls to it
  351. ===================
  352. */
  353. boolean P_BlockLinesIterator (int x, int y, boolean(*func)(line_t*) )
  354. {
  355. int offset;
  356. short *list;
  357. line_t *ld;
  358. int i;
  359. polyblock_t *polyLink;
  360. seg_t **tempSeg;
  361. extern polyblock_t **PolyBlockMap;
  362. if (x < 0 || y<0 || x>=bmapwidth || y>=bmapheight)
  363. return true;
  364. offset = y*bmapwidth+x;
  365. polyLink = PolyBlockMap[offset];
  366. while(polyLink)
  367. {
  368. if(polyLink->polyobj)
  369. {
  370. if(polyLink->polyobj->validcount != validcount)
  371. {
  372. polyLink->polyobj->validcount = validcount;
  373. tempSeg = polyLink->polyobj->segs;
  374. for(i = 0; i < polyLink->polyobj->numsegs; i++, tempSeg++)
  375. {
  376. if((*tempSeg)->linedef->validcount == validcount)
  377. {
  378. continue;
  379. }
  380. (*tempSeg)->linedef->validcount = validcount;
  381. if(!func((*tempSeg)->linedef))
  382. {
  383. return false;
  384. }
  385. }
  386. }
  387. }
  388. polyLink = polyLink->next;
  389. }
  390. offset = *(blockmap+offset);
  391. for ( list = blockmaplump+offset ; *list != -1 ; list++)
  392. {
  393. ld = &lines[*list];
  394. if (ld->validcount == validcount)
  395. continue; // line has already been checked
  396. ld->validcount = validcount;
  397. if ( !func(ld) )
  398. return false;
  399. }
  400. return true; // everything was checked
  401. }
  402. /*
  403. ==================
  404. =
  405. = P_BlockThingsIterator
  406. =
  407. ==================
  408. */
  409. boolean P_BlockThingsIterator (int x, int y, boolean(*func)(mobj_t*) )
  410. {
  411. mobj_t *mobj;
  412. if (x<0 || y<0 || x>=bmapwidth || y>=bmapheight)
  413. return true;
  414. for (mobj = blocklinks[y*bmapwidth+x] ; mobj ; mobj = mobj->bnext)
  415. if (!func( mobj ) )
  416. return false;
  417. return true;
  418. }
  419. /*
  420. ===============================================================================
  421. INTERCEPT ROUTINES
  422. ===============================================================================
  423. */
  424. intercept_t intercepts[MAXINTERCEPTS], *intercept_p;
  425. divline_t trace;
  426. boolean earlyout;
  427. int ptflags;
  428. /*
  429. ==================
  430. =
  431. = PIT_AddLineIntercepts
  432. =
  433. = Looks for lines in the given block that intercept the given trace
  434. = to add to the intercepts list
  435. = A line is crossed if its endpoints are on opposite sides of the trace
  436. = Returns true if earlyout and a solid line hit
  437. ==================
  438. */
  439. boolean PIT_AddLineIntercepts (line_t *ld)
  440. {
  441. int s1, s2;
  442. fixed_t frac;
  443. divline_t dl;
  444. // avoid precision problems with two routines
  445. if ( trace.dx > FRACUNIT*16 || trace.dy > FRACUNIT*16
  446. || trace.dx < -FRACUNIT*16 || trace.dy < -FRACUNIT*16)
  447. {
  448. s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
  449. s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
  450. }
  451. else
  452. {
  453. s1 = P_PointOnLineSide (trace.x, trace.y, ld);
  454. s2 = P_PointOnLineSide (trace.x+trace.dx, trace.y+trace.dy, ld);
  455. }
  456. if (s1 == s2)
  457. return true; // line isn't crossed
  458. //
  459. // hit the line
  460. //
  461. P_MakeDivline (ld, &dl);
  462. frac = P_InterceptVector (&trace, &dl);
  463. if (frac < 0)
  464. return true; // behind source
  465. // try to early out the check
  466. if (earlyout && frac < FRACUNIT && !ld->backsector)
  467. return false; // stop checking
  468. intercept_p->frac = frac;
  469. intercept_p->isaline = true;
  470. intercept_p->d.line = ld;
  471. intercept_p++;
  472. return true; // continue
  473. }
  474. /*
  475. ==================
  476. =
  477. = PIT_AddThingIntercepts
  478. =
  479. ==================
  480. */
  481. boolean PIT_AddThingIntercepts (mobj_t *thing)
  482. {
  483. fixed_t x1,y1, x2,y2;
  484. int s1, s2;
  485. boolean tracepositive;
  486. divline_t dl;
  487. fixed_t frac;
  488. tracepositive = (trace.dx ^ trace.dy)>0;
  489. // check a corner to corner crossection for hit
  490. if (tracepositive)
  491. {
  492. x1 = thing->x - thing->radius;
  493. y1 = thing->y + thing->radius;
  494. x2 = thing->x + thing->radius;
  495. y2 = thing->y - thing->radius;
  496. }
  497. else
  498. {
  499. x1 = thing->x - thing->radius;
  500. y1 = thing->y - thing->radius;
  501. x2 = thing->x + thing->radius;
  502. y2 = thing->y + thing->radius;
  503. }
  504. s1 = P_PointOnDivlineSide (x1, y1, &trace);
  505. s2 = P_PointOnDivlineSide (x2, y2, &trace);
  506. if (s1 == s2)
  507. return true; // line isn't crossed
  508. dl.x = x1;
  509. dl.y = y1;
  510. dl.dx = x2-x1;
  511. dl.dy = y2-y1;
  512. frac = P_InterceptVector (&trace, &dl);
  513. if (frac < 0)
  514. return true; // behind source
  515. intercept_p->frac = frac;
  516. intercept_p->isaline = false;
  517. intercept_p->d.thing = thing;
  518. intercept_p++;
  519. return true; // keep going
  520. }
  521. /*
  522. ====================
  523. =
  524. = P_TraverseIntercepts
  525. =
  526. = Returns true if the traverser function returns true for all lines
  527. ====================
  528. */
  529. boolean P_TraverseIntercepts ( traverser_t func, fixed_t maxfrac )
  530. {
  531. int count;
  532. fixed_t dist;
  533. intercept_t *scan, *in;
  534. count = intercept_p - intercepts;
  535. in = 0; // shut up compiler warning
  536. while (count--)
  537. {
  538. dist = MAXINT;
  539. for (scan = intercepts ; scan<intercept_p ; scan++)
  540. if (scan->frac < dist)
  541. {
  542. dist = scan->frac;
  543. in = scan;
  544. }
  545. if (dist > maxfrac)
  546. return true; // checked everything in range
  547. #if 0
  548. { // don't check these yet, ther may be others inserted
  549. in = scan = intercepts;
  550. for ( scan = intercepts ; scan<intercept_p ; scan++)
  551. if (scan->frac > maxfrac)
  552. *in++ = *scan;
  553. intercept_p = in;
  554. return false;
  555. }
  556. #endif
  557. if ( !func (in) )
  558. return false; // don't bother going farther
  559. in->frac = MAXINT;
  560. }
  561. return true; // everything was traversed
  562. }
  563. /*
  564. ==================
  565. =
  566. = P_PathTraverse
  567. =
  568. = Traces a line from x1,y1 to x2,y2, calling the traverser function for each
  569. = Returns true if the traverser function returns true for all lines
  570. ==================
  571. */
  572. boolean P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2,
  573. int flags, boolean (*trav) (intercept_t *))
  574. {
  575. fixed_t xt1,yt1,xt2,yt2;
  576. fixed_t xstep,ystep;
  577. fixed_t partial;
  578. fixed_t xintercept, yintercept;
  579. int mapx, mapy, mapxstep, mapystep;
  580. int count;
  581. earlyout = flags & PT_EARLYOUT;
  582. validcount++;
  583. intercept_p = intercepts;
  584. if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0)
  585. x1 += FRACUNIT; // don't side exactly on a line
  586. if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0)
  587. y1 += FRACUNIT; // don't side exactly on a line
  588. trace.x = x1;
  589. trace.y = y1;
  590. trace.dx = x2 - x1;
  591. trace.dy = y2 - y1;
  592. x1 -= bmaporgx;
  593. y1 -= bmaporgy;
  594. xt1 = x1>>MAPBLOCKSHIFT;
  595. yt1 = y1>>MAPBLOCKSHIFT;
  596. x2 -= bmaporgx;
  597. y2 -= bmaporgy;
  598. xt2 = x2>>MAPBLOCKSHIFT;
  599. yt2 = y2>>MAPBLOCKSHIFT;
  600. if (xt2 > xt1)
  601. {
  602. mapxstep = 1;
  603. partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1));
  604. ystep = FixedDiv (y2-y1,abs(x2-x1));
  605. }
  606. else if (xt2 < xt1)
  607. {
  608. mapxstep = -1;
  609. partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1);
  610. ystep = FixedDiv (y2-y1,abs(x2-x1));
  611. }
  612. else
  613. {
  614. mapxstep = 0;
  615. partial = FRACUNIT;
  616. ystep = 256*FRACUNIT;
  617. }
  618. yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep);
  619. if (yt2 > yt1)
  620. {
  621. mapystep = 1;
  622. partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1));
  623. xstep = FixedDiv (x2-x1,abs(y2-y1));
  624. }
  625. else if (yt2 < yt1)
  626. {
  627. mapystep = -1;
  628. partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1);
  629. xstep = FixedDiv (x2-x1,abs(y2-y1));
  630. }
  631. else
  632. {
  633. mapystep = 0;
  634. partial = FRACUNIT;
  635. xstep = 256*FRACUNIT;
  636. }
  637. xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep);
  638. //
  639. // step through map blocks
  640. // Count is present to prevent a round off error from skipping the break
  641. mapx = xt1;
  642. mapy = yt1;
  643. for (count = 0 ; count < 64 ; count++)
  644. {
  645. if (flags & PT_ADDLINES)
  646. {
  647. if (!P_BlockLinesIterator (mapx, mapy,PIT_AddLineIntercepts))
  648. return false; // early out
  649. }
  650. if (flags & PT_ADDTHINGS)
  651. {
  652. if (!P_BlockThingsIterator (mapx, mapy,PIT_AddThingIntercepts))
  653. return false; // early out
  654. }
  655. if (mapx == xt2 && mapy == yt2)
  656. break;
  657. if ( (yintercept >> FRACBITS) == mapy)
  658. {
  659. yintercept += ystep;
  660. mapx += mapxstep;
  661. }
  662. else if ( (xintercept >> FRACBITS) == mapx)
  663. {
  664. xintercept += xstep;
  665. mapy += mapystep;
  666. }
  667. }
  668. //
  669. // go through the sorted list
  670. //
  671. return P_TraverseIntercepts ( trav, FRACUNIT );
  672. }
  673. //===========================================================================
  674. //
  675. // P_RoughMonsterSearch
  676. //
  677. // Searches though the surrounding mapblocks for monsters/players
  678. // distance is in MAPBLOCKUNITS
  679. //===========================================================================
  680. mobj_t *P_RoughMonsterSearch(mobj_t *mo, int distance)
  681. {
  682. int blockX;
  683. int blockY;
  684. int startX, startY;
  685. int blockIndex;
  686. int firstStop;
  687. int secondStop;
  688. int thirdStop;
  689. int finalStop;
  690. int count;
  691. mobj_t *target;
  692. startX = (mo->x-bmaporgx)>>MAPBLOCKSHIFT;
  693. startY = (mo->y-bmaporgy)>>MAPBLOCKSHIFT;
  694. if(startX >= 0 && startX < bmapwidth && startY >= 0 && startY < bmapheight)
  695. {
  696. if(target = RoughBlockCheck(mo, startY*bmapwidth+startX))
  697. { // found a target right away
  698. return target;
  699. }
  700. }
  701. for(count = 1; count <= distance; count++)
  702. {
  703. blockX = startX-count;
  704. blockY = startY-count;
  705. if(blockY < 0)
  706. {
  707. blockY = 0;
  708. }
  709. else if(blockY >= bmapheight)
  710. {
  711. blockY = bmapheight-1;
  712. }
  713. if(blockX < 0)
  714. {
  715. blockX = 0;
  716. }
  717. else if(blockX >= bmapwidth)
  718. {
  719. blockX = bmapwidth-1;
  720. }
  721. blockIndex = blockY*bmapwidth+blockX;
  722. firstStop = startX+count;
  723. if(firstStop < 0)
  724. {
  725. continue;
  726. }
  727. if(firstStop >= bmapwidth)
  728. {
  729. firstStop = bmapwidth-1;
  730. }
  731. secondStop = startY+count;
  732. if(secondStop < 0)
  733. {
  734. continue;
  735. }
  736. if(secondStop >= bmapheight)
  737. {
  738. secondStop = bmapheight-1;
  739. }
  740. thirdStop = secondStop*bmapwidth+blockX;
  741. secondStop = secondStop*bmapwidth+firstStop;
  742. firstStop += blockY*bmapwidth;
  743. finalStop = blockIndex;
  744. // Trace the first block section (along the top)
  745. for(; blockIndex <= firstStop; blockIndex++)
  746. {
  747. if(target = RoughBlockCheck(mo, blockIndex))
  748. {
  749. return target;
  750. }
  751. }
  752. // Trace the second block section (right edge)
  753. for(blockIndex--; blockIndex <= secondStop; blockIndex += bmapwidth)
  754. {
  755. if(target = RoughBlockCheck(mo, blockIndex))
  756. {
  757. return target;
  758. }
  759. }
  760. // Trace the third block section (bottom edge)
  761. for(blockIndex -= bmapwidth; blockIndex >= thirdStop; blockIndex--)
  762. {
  763. if(target = RoughBlockCheck(mo, blockIndex))
  764. {
  765. return target;
  766. }
  767. }
  768. // Trace the final block section (left edge)
  769. for(blockIndex++; blockIndex > finalStop; blockIndex -= bmapwidth)
  770. {
  771. if(target = RoughBlockCheck(mo, blockIndex))
  772. {
  773. return target;
  774. }
  775. }
  776. }
  777. return NULL;
  778. }
  779. //===========================================================================
  780. //
  781. // RoughBlockCheck
  782. //
  783. //===========================================================================
  784. static mobj_t *RoughBlockCheck(mobj_t *mo, int index)
  785. {
  786. mobj_t *link;
  787. mobj_t *master;
  788. angle_t angle;
  789. link = blocklinks[index];
  790. while(link)
  791. {
  792. if (mo->player) // Minotaur looking around player
  793. {
  794. if ((link->flags&MF_COUNTKILL) ||
  795. (link->player && (link != mo)))
  796. {
  797. if (!(link->flags&MF_SHOOTABLE))
  798. {
  799. link = link->bnext;
  800. continue;
  801. }
  802. if (link->flags2&MF2_DORMANT)
  803. {
  804. link = link->bnext;
  805. continue;
  806. }
  807. if ((link->type == MT_MINOTAUR) &&
  808. (((mobj_t *)link->special1) == mo))
  809. {
  810. link = link->bnext;
  811. continue;
  812. }
  813. if(netgame && !deathmatch && link->player)
  814. {
  815. link = link->bnext;
  816. continue;
  817. }
  818. if(P_CheckSight(mo, link))
  819. {
  820. return link;
  821. }
  822. }
  823. link = link->bnext;
  824. }
  825. else if (mo->type == MT_MINOTAUR) // looking around minotaur
  826. {
  827. master = (mobj_t *)mo->special1;
  828. if ((link->flags&MF_COUNTKILL) ||
  829. (link->player && (link != master)))
  830. {
  831. if (!(link->flags&MF_SHOOTABLE))
  832. {
  833. link = link->bnext;
  834. continue;
  835. }
  836. if (link->flags2&MF2_DORMANT)
  837. {
  838. link = link->bnext;
  839. continue;
  840. }
  841. if ((link->type == MT_MINOTAUR) &&
  842. (link->special1 == mo->special1))
  843. {
  844. link = link->bnext;
  845. continue;
  846. }
  847. if(netgame && !deathmatch && link->player)
  848. {
  849. link = link->bnext;
  850. continue;
  851. }
  852. if(P_CheckSight(mo, link))
  853. {
  854. return link;
  855. }
  856. }
  857. link = link->bnext;
  858. }
  859. else if (mo->type == MT_MSTAFF_FX2) // bloodscourge
  860. {
  861. if ((link->flags&MF_COUNTKILL ||
  862. (link->player && link != mo->target))
  863. && !(link->flags2&MF2_DORMANT))
  864. {
  865. if (!(link->flags&MF_SHOOTABLE))
  866. {
  867. link = link->bnext;
  868. continue;
  869. }
  870. if(netgame && !deathmatch && link->player)
  871. {
  872. link = link->bnext;
  873. continue;
  874. }
  875. else if(P_CheckSight(mo, link))
  876. {
  877. master = mo->target;
  878. angle = R_PointToAngle2(master->x, master->y,
  879. link->x, link->y) - master->angle;
  880. angle >>= 24;
  881. if (angle>226 || angle<30)
  882. {
  883. return link;
  884. }
  885. }
  886. }
  887. link = link->bnext;
  888. }
  889. else // spirits
  890. {
  891. if ((link->flags&MF_COUNTKILL ||
  892. (link->player && link != mo->target))
  893. && !(link->flags2&MF2_DORMANT))
  894. {
  895. if (!(link->flags&MF_SHOOTABLE))
  896. {
  897. link = link->bnext;
  898. continue;
  899. }
  900. if(netgame && !deathmatch && link->player)
  901. {
  902. link = link->bnext;
  903. continue;
  904. }
  905. if (link == mo->target)
  906. {
  907. link = link->bnext;
  908. continue;
  909. }
  910. else if(P_CheckSight(mo, link))
  911. {
  912. return link;
  913. }
  914. }
  915. link = link->bnext;
  916. }
  917. }
  918. return NULL;
  919. }