1
2 //**************************************************************************
3 //**
4 //** p_sight.c : Heretic 2 : Raven Software, Corp.
5 //**
6 //** $RCSfile: p_sight.c,v $
7 //** $Revision: 1.1 $
8 //** $Date: 95/05/11 00:22:50 $
9 //** $Author: bgokey $
10 //**
11 //**************************************************************************
12
13 #include "h2def.h"
14 #include "p_local.h"
15
16 /*
17 ==============================================================================
18
19 P_CheckSight
20
21 This uses specialized forms of the maputils routines for optimized performance
22
23 ==============================================================================
24 */
25
26 fixed_t sightzstart; // eye z of looker
27 fixed_t topslope, bottomslope; // slopes to top and bottom of target
28
29 int sightcounts[3];
30
31 /*
32 ==============
33 =
34 = PTR_SightTraverse
35 =
36 ==============
37 */
38
PTR_SightTraverse(intercept_t * in)39 boolean PTR_SightTraverse (intercept_t *in)
40 {
41 line_t *li;
42 fixed_t slope;
43
44 li = in->d.line;
45
46 //
47 // crosses a two sided line
48 //
49 P_LineOpening (li);
50
51 if (openbottom >= opentop) // quick test for totally closed doors
52 return false; // stop
53
54 if (li->frontsector->floorheight != li->backsector->floorheight)
55 {
56 slope = FixedDiv (openbottom - sightzstart , in->frac);
57 if (slope > bottomslope)
58 bottomslope = slope;
59 }
60
61 if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
62 {
63 slope = FixedDiv (opentop - sightzstart , in->frac);
64 if (slope < topslope)
65 topslope = slope;
66 }
67
68 if (topslope <= bottomslope)
69 return false; // stop
70
71 return true; // keep going
72 }
73
74
75
76 /*
77 ==================
78 =
79 = P_SightBlockLinesIterator
80 =
81 ===================
82 */
83
P_SightBlockLinesIterator(int x,int y)84 boolean P_SightBlockLinesIterator (int x, int y )
85 {
86 int offset;
87 short *list;
88 line_t *ld;
89 int s1, s2;
90 divline_t dl;
91
92 polyblock_t *polyLink;
93 seg_t **segList;
94 int i;
95 extern polyblock_t **PolyBlockMap;
96
97 offset = y*bmapwidth+x;
98
99 polyLink = PolyBlockMap[offset];
100 while(polyLink)
101 {
102 if(polyLink->polyobj)
103 { // only check non-empty links
104 if(polyLink->polyobj->validcount != validcount)
105 {
106 segList = polyLink->polyobj->segs;
107 for(i = 0; i < polyLink->polyobj->numsegs; i++, segList++)
108 {
109 ld = (*segList)->linedef;
110 if(ld->validcount == validcount)
111 {
112 continue;
113 }
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);
117 if (s1 == s2)
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);
122 if (s1 == s2)
123 continue; // line isn't crossed
124
125 // try to early out the check
126 if (!ld->backsector)
127 return false; // stop checking
128
129 // store the line for later intersection testing
130 intercept_p->d.line = ld;
131 intercept_p++;
132 }
133 polyLink->polyobj->validcount = validcount;
134 }
135 }
136 polyLink = polyLink->next;
137 }
138
139 offset = *(blockmap+offset);
140
141 for ( list = blockmaplump+offset ; *list != -1 ; list++)
142 {
143 ld = &lines[*list];
144 if (ld->validcount == validcount)
145 continue; // line has already been checked
146 ld->validcount = validcount;
147
148 s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
149 s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
150 if (s1 == s2)
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);
155 if (s1 == s2)
156 continue; // line isn't crossed
157
158 // try to early out the check
159 if (!ld->backsector)
160 return false; // stop checking
161
162 // store the line for later intersection testing
163 intercept_p->d.line = ld;
164 intercept_p++;
165
166 }
167
168 return true; // everything was checked
169 }
170
171 /*
172 ====================
173 =
174 = P_SightTraverseIntercepts
175 =
176 = Returns true if the traverser function returns true for all lines
177 ====================
178 */
179
P_SightTraverseIntercepts(void)180 boolean P_SightTraverseIntercepts ( void )
181 {
182 int count;
183 fixed_t dist;
184 intercept_t *scan, *in;
185 divline_t dl;
186
187 count = intercept_p - intercepts;
188 //
189 // calculate intercept distance
190 //
191 for (scan = intercepts ; scan<intercept_p ; scan++)
192 {
193 P_MakeDivline (scan->d.line, &dl);
194 scan->frac = P_InterceptVector (&trace, &dl);
195 }
196
197 //
198 // go through in order
199 //
200 in = 0; // shut up compiler warning
201
202 while (count--)
203 {
204 dist = MAXINT;
205 for (scan = intercepts ; scan<intercept_p ; scan++)
206 if (scan->frac < dist)
207 {
208 dist = scan->frac;
209 in = scan;
210 }
211
212 if ( !PTR_SightTraverse (in) )
213 return false; // don't bother going farther
214 in->frac = MAXINT;
215 }
216
217 return true; // everything was traversed
218 }
219
220
221
222 /*
223 ==================
224 =
225 = P_SightPathTraverse
226 =
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
229 ==================
230 */
231
P_SightPathTraverse(fixed_t x1,fixed_t y1,fixed_t x2,fixed_t y2)232 boolean P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
233 {
234 fixed_t xt1,yt1,xt2,yt2;
235 fixed_t xstep,ystep;
236 fixed_t partial;
237 fixed_t xintercept, yintercept;
238 int mapx, mapy, mapxstep, mapystep;
239 int count;
240
241 validcount++;
242 intercept_p = intercepts;
243
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
248 trace.x = x1;
249 trace.y = y1;
250 trace.dx = x2 - x1;
251 trace.dy = y2 - y1;
252
253 x1 -= bmaporgx;
254 y1 -= bmaporgy;
255 xt1 = x1>>MAPBLOCKSHIFT;
256 yt1 = y1>>MAPBLOCKSHIFT;
257
258 x2 -= bmaporgx;
259 y2 -= bmaporgy;
260 xt2 = x2>>MAPBLOCKSHIFT;
261 yt2 = y2>>MAPBLOCKSHIFT;
262
263 // points should never be out of bounds, but check once instead of
264 // each block
265 if (xt1<0 || yt1<0 || xt1>=bmapwidth || yt1>=bmapheight
266 || xt2<0 || yt2<0 || xt2>=bmapwidth || yt2>=bmapheight)
267 return false;
268
269 if (xt2 > xt1)
270 {
271 mapxstep = 1;
272 partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1));
273 ystep = FixedDiv (y2-y1,abs(x2-x1));
274 }
275 else if (xt2 < xt1)
276 {
277 mapxstep = -1;
278 partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1);
279 ystep = FixedDiv (y2-y1,abs(x2-x1));
280 }
281 else
282 {
283 mapxstep = 0;
284 partial = FRACUNIT;
285 ystep = 256*FRACUNIT;
286 }
287 yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep);
288
289
290 if (yt2 > yt1)
291 {
292 mapystep = 1;
293 partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1));
294 xstep = FixedDiv (x2-x1,abs(y2-y1));
295 }
296 else if (yt2 < yt1)
297 {
298 mapystep = -1;
299 partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1);
300 xstep = FixedDiv (x2-x1,abs(y2-y1));
301 }
302 else
303 {
304 mapystep = 0;
305 partial = FRACUNIT;
306 xstep = 256*FRACUNIT;
307 }
308 xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep);
309
310
311 //
312 // step through map blocks
313 // Count is present to prevent a round off error from skipping the break
314 mapx = xt1;
315 mapy = yt1;
316
317
318 for (count = 0 ; count < 64 ; count++)
319 {
320 if (!P_SightBlockLinesIterator (mapx, mapy))
321 {
322 sightcounts[1]++;
323 return false; // early out
324 }
325
326 if (mapx == xt2 && mapy == yt2)
327 break;
328
329 if ( (yintercept >> FRACBITS) == mapy)
330 {
331 yintercept += ystep;
332 mapx += mapxstep;
333 }
334 else if ( (xintercept >> FRACBITS) == mapx)
335 {
336 xintercept += xstep;
337 mapy += mapystep;
338 }
339
340 }
341
342
343 //
344 // couldn't early out, so go through the sorted list
345 //
346 sightcounts[2]++;
347
348 return P_SightTraverseIntercepts ( );
349 }
350
351
352
353 /*
354 =====================
355 =
356 = P_CheckSight
357 =
358 = Returns true if a straight line between t1 and t2 is unobstructed
359 = look from eyes of t1 to any part of t2
360 =
361 =====================
362 */
363
P_CheckSight(mobj_t * t1,mobj_t * t2)364 boolean P_CheckSight (mobj_t *t1, mobj_t *t2)
365 {
366 int s1, s2;
367 int pnum, bytenum, bitnum;
368
369 //
370 // check for trivial rejection
371 //
372 s1 = (t1->subsector->sector - sectors);
373 s2 = (t2->subsector->sector - sectors);
374 pnum = s1*numsectors + s2;
375 bytenum = pnum>>3;
376 bitnum = 1 << (pnum&7);
377
378 if (rejectmatrix[bytenum]&bitnum)
379 {
380 sightcounts[0]++;
381 return false; // can't possibly be connected
382 }
383
384 //
385 // check precisely
386 //
387 sightzstart = t1->z + t1->height - (t1->height>>2);
388 topslope = (t2->z+t2->height) - sightzstart;
389 bottomslope = (t2->z) - sightzstart;
390
391 return P_SightPathTraverse ( t1->x, t1->y, t2->x, t2->y );
392 }
393
394
395
396