2 //**************************************************************************
4 //** p_sight.c : Heretic 2 : Raven Software, Corp.
11 //**************************************************************************
17 ==============================================================================
21 This uses specialized forms of the maputils routines for optimized performance
23 ==============================================================================
26 fixed_t sightzstart; // eye z of looker
27 fixed_t topslope, bottomslope; // slopes to top and bottom of target
39 boolean PTR_SightTraverse (intercept_t *in)
47 // crosses a two sided line
51 if (openbottom >= opentop) // quick test for totally closed doors
54 if (li->frontsector->floorheight != li->backsector->floorheight)
56 slope = FixedDiv (openbottom - sightzstart , in->frac);
57 if (slope > bottomslope)
61 if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
63 slope = FixedDiv (opentop - sightzstart , in->frac);
68 if (topslope <= bottomslope)
71 return true; // keep going
79 = P_SightBlockLinesIterator
84 boolean P_SightBlockLinesIterator (int x, int y )
92 polyblock_t *polyLink;
95 extern polyblock_t **PolyBlockMap;
97 offset = y*bmapwidth+x;
99 polyLink = PolyBlockMap[offset];
102 if(polyLink->polyobj)
103 { // only check non-empty links
104 if(polyLink->polyobj->validcount != validcount)
106 segList = polyLink->polyobj->segs;
107 for(i = 0; i < polyLink->polyobj->numsegs; i++, segList++)
109 ld = (*segList)->linedef;
110 if(ld->validcount == validcount)
114 ld->validcount = validcount;
115 s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
116 s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
118 continue; // line isn't crossed
119 P_MakeDivline (ld, &dl);
120 s1 = P_PointOnDivlineSide (trace.x, trace.y, &dl);
121 s2 = P_PointOnDivlineSide (trace.x+trace.dx, trace.y+trace.dy, &dl);
123 continue; // line isn't crossed
125 // try to early out the check
127 return false; // stop checking
129 // store the line for later intersection testing
130 intercept_p->d.line = ld;
133 polyLink->polyobj->validcount = validcount;
136 polyLink = polyLink->next;
139 offset = *(blockmap+offset);
141 for ( list = blockmaplump+offset ; *list != -1 ; list++)
144 if (ld->validcount == validcount)
145 continue; // line has already been checked
146 ld->validcount = validcount;
148 s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
149 s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
151 continue; // line isn't crossed
152 P_MakeDivline (ld, &dl);
153 s1 = P_PointOnDivlineSide (trace.x, trace.y, &dl);
154 s2 = P_PointOnDivlineSide (trace.x+trace.dx, trace.y+trace.dy, &dl);
156 continue; // line isn't crossed
158 // try to early out the check
160 return false; // stop checking
162 // store the line for later intersection testing
163 intercept_p->d.line = ld;
168 return true; // everything was checked
174 = P_SightTraverseIntercepts
176 = Returns true if the traverser function returns true for all lines
180 boolean P_SightTraverseIntercepts ( void )
184 intercept_t *scan, *in;
187 count = intercept_p - intercepts;
189 // calculate intercept distance
191 for (scan = intercepts ; scan<intercept_p ; scan++)
193 P_MakeDivline (scan->d.line, &dl);
194 scan->frac = P_InterceptVector (&trace, &dl);
198 // go through in order
200 in = 0; // shut up compiler warning
205 for (scan = intercepts ; scan<intercept_p ; scan++)
206 if (scan->frac < dist)
212 if ( !PTR_SightTraverse (in) )
213 return false; // don't bother going farther
217 return true; // everything was traversed
225 = P_SightPathTraverse
227 = Traces a line from x1,y1 to x2,y2, calling the traverser function for each
228 = Returns true if the traverser function returns true for all lines
232 boolean P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
234 fixed_t xt1,yt1,xt2,yt2;
237 fixed_t xintercept, yintercept;
238 int mapx, mapy, mapxstep, mapystep;
242 intercept_p = intercepts;
244 if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0)
245 x1 += FRACUNIT; // don't side exactly on a line
246 if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0)
247 y1 += FRACUNIT; // don't side exactly on a line
255 xt1 = x1>>MAPBLOCKSHIFT;
256 yt1 = y1>>MAPBLOCKSHIFT;
260 xt2 = x2>>MAPBLOCKSHIFT;
261 yt2 = y2>>MAPBLOCKSHIFT;
263 // points should never be out of bounds, but check once instead of
265 if (xt1<0 || yt1<0 || xt1>=bmapwidth || yt1>=bmapheight
266 || xt2<0 || yt2<0 || xt2>=bmapwidth || yt2>=bmapheight)
272 partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1));
273 ystep = FixedDiv (y2-y1,abs(x2-x1));
278 partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1);
279 ystep = FixedDiv (y2-y1,abs(x2-x1));
285 ystep = 256*FRACUNIT;
287 yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep);
293 partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1));
294 xstep = FixedDiv (x2-x1,abs(y2-y1));
299 partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1);
300 xstep = FixedDiv (x2-x1,abs(y2-y1));
306 xstep = 256*FRACUNIT;
308 xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep);
312 // step through map blocks
313 // Count is present to prevent a round off error from skipping the break
318 for (count = 0 ; count < 64 ; count++)
320 if (!P_SightBlockLinesIterator (mapx, mapy))
323 return false; // early out
326 if (mapx == xt2 && mapy == yt2)
329 if ( (yintercept >> FRACBITS) == mapy)
334 else if ( (xintercept >> FRACBITS) == mapx)
344 // couldn't early out, so go through the sorted list
348 return P_SightTraverseIntercepts ( );
354 =====================
358 = Returns true if a straight line between t1 and t2 is unobstructed
359 = look from eyes of t1 to any part of t2
361 =====================
364 boolean P_CheckSight (mobj_t *t1, mobj_t *t2)
367 int pnum, bytenum, bitnum;
370 // check for trivial rejection
372 s1 = (t1->subsector->sector - sectors);
373 s2 = (t2->subsector->sector - sectors);
374 pnum = s1*numsectors + s2;
376 bitnum = 1 << (pnum&7);
378 if (rejectmatrix[bytenum]&bitnum)
381 return false; // can't possibly be connected
387 sightzstart = t1->z + t1->height - (t1->height>>2);
388 topslope = (t2->z+t2->height) - sightzstart;
389 bottomslope = (t2->z) - sightzstart;
391 return P_SightPathTraverse ( t1->x, t1->y, t2->x, t2->y );