1 /*
2 ** p_trace.cpp
3 ** Generalized trace function, like most 3D games have
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 1998-2006 Randy Heit
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 ** notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 ** notice, this list of conditions and the following disclaimer in the
17 ** documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 ** derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 */
34
35 #include "p_trace.h"
36 #include "p_local.h"
37 #include "i_system.h"
38 #include "r_sky.h"
39 #include "doomstat.h"
40
41 struct FTraceInfo
42 {
43 fixed_t StartX, StartY, StartZ;
44 fixed_t Vx, Vy, Vz;
45 ActorFlags ActorMask;
46 DWORD WallMask;
47 AActor *IgnoreThis;
48 FTraceResults *Results;
49 sector_t *CurSector;
50 fixed_t MaxDist;
51 fixed_t EnterDist;
52 ETraceStatus (*TraceCallback)(FTraceResults &res, void *data);
53 void *TraceCallbackData;
54 DWORD TraceFlags;
55 int inshootthrough;
56
57 // These are required for 3D-floor checking
58 // to create a fake sector with a floor
59 // or ceiling plane coming from a 3D-floor
60 sector_t DummySector[2];
61 int sectorsel;
62
63 bool TraceTraverse (int ptflags);
64 bool CheckPlane(const secplane_t &plane);
65 bool CheckSectorPlane (const sector_t *sector, bool checkFloor);
66 bool Check3DFloorPlane(const F3DFloor *ffloor, bool checkBottom);
67 };
68
69 static bool EditTraceResult (DWORD flags, FTraceResults &res);
70
71
Trace(fixed_t x,fixed_t y,fixed_t z,sector_t * sector,fixed_t vx,fixed_t vy,fixed_t vz,fixed_t maxDist,ActorFlags actorMask,DWORD wallMask,AActor * ignore,FTraceResults & res,DWORD flags,ETraceStatus (* callback)(FTraceResults & res,void *),void * callbackdata)72 bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector,
73 fixed_t vx, fixed_t vy, fixed_t vz, fixed_t maxDist,
74 ActorFlags actorMask, DWORD wallMask, AActor *ignore,
75 FTraceResults &res,
76 DWORD flags, ETraceStatus (*callback)(FTraceResults &res, void *), void *callbackdata)
77 {
78 int ptflags;
79 FTraceInfo inf;
80
81 ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS|PT_COMPATIBLE : PT_ADDLINES;
82
83 inf.StartX = x;
84 inf.StartY = y;
85 inf.StartZ = z;
86 inf.Vx = vx;
87 inf.Vy = vy;
88 inf.Vz = vz;
89 inf.ActorMask = actorMask;
90 inf.WallMask = wallMask;
91 inf.IgnoreThis = ignore;
92 inf.CurSector = sector;
93 inf.MaxDist = maxDist;
94 inf.EnterDist = 0;
95 inf.TraceCallback = callback;
96 inf.TraceCallbackData = callbackdata;
97 inf.TraceFlags = flags;
98 inf.Results = &res;
99 inf.inshootthrough = true;
100 inf.sectorsel=0;
101 memset(&res, 0, sizeof(res));
102 /* // Redundant with the memset
103 res.HitType = TRACE_HitNone;
104 res.CrossedWater = NULL;
105 res.Crossed3DWater = NULL;
106 */
107
108 // Do a 3D floor check in the starting sector
109 TDeletingArray<F3DFloor*> &ff = sector->e->XFloor.ffloors;
110
111 if (ff.Size())
112 {
113 memcpy(&inf.DummySector[0],sector,sizeof(sector_t));
114 inf.CurSector=sector=&inf.DummySector[0];
115 inf.sectorsel=1;
116 fixed_t bf = sector->floorplane.ZatPoint (x, y);
117 fixed_t bc = sector->ceilingplane.ZatPoint (x, y);
118
119 for(unsigned int i=0;i<ff.Size();i++)
120 {
121 F3DFloor * rover=ff[i];
122 if (!(rover->flags&FF_EXISTS))
123 continue;
124
125 if (rover->flags&FF_SWIMMABLE && res.Crossed3DWater == NULL)
126 {
127 if (inf.Check3DFloorPlane(rover, false))
128 res.Crossed3DWater = rover;
129 }
130
131 if (!(rover->flags&FF_SHOOTTHROUGH))
132 {
133 fixed_t ff_bottom=rover->bottom.plane->ZatPoint(x, y);
134 fixed_t ff_top=rover->top.plane->ZatPoint(x, y);
135 // clip to the part of the sector we are in
136 if (z>ff_top)
137 {
138 // above
139 if (bf<ff_top)
140 {
141 sector->floorplane=*rover->top.plane;
142 sector->SetTexture(sector_t::floor, *rover->top.texture, false);
143 bf=ff_top;
144 }
145 }
146 else if (z<ff_bottom)
147 {
148 //below
149 if (bc>ff_bottom)
150 {
151 sector->ceilingplane=*rover->bottom.plane;
152 sector->SetTexture(sector_t::ceiling, *rover->bottom.texture, false);
153 bc=ff_bottom;
154 }
155 }
156 else
157 {
158 // inside
159 if (bf<ff_bottom)
160 {
161 sector->floorplane=*rover->bottom.plane;
162 sector->SetTexture(sector_t::floor, *rover->bottom.texture, false);
163 bf=ff_bottom;
164 }
165
166 if (bc>ff_top)
167 {
168 sector->ceilingplane=*rover->top.plane;
169 sector->SetTexture(sector_t::ceiling, *rover->top.texture, false);
170 bc=ff_top;
171 }
172 inf.inshootthrough = false;
173 }
174 }
175 }
176 }
177
178 // check for overflows and clip if necessary
179 SQWORD xd = (SQWORD)x + ( ( SQWORD(vx) * SQWORD(maxDist) )>>16);
180
181 if (xd>SQWORD(32767)*FRACUNIT)
182 {
183 maxDist = inf.MaxDist = FixedDiv(FIXED_MAX - x, vx);
184 }
185 else if (xd<-SQWORD(32767)*FRACUNIT)
186 {
187 maxDist = inf.MaxDist = FixedDiv(FIXED_MIN - x, vx);
188 }
189
190
191 SQWORD yd = (SQWORD)y + ( ( SQWORD(vy) * SQWORD(maxDist) )>>16);
192
193 if (yd>SQWORD(32767)*FRACUNIT)
194 {
195 maxDist = inf.MaxDist=FixedDiv(FIXED_MAX-y,vy);
196 }
197 else if (yd<-SQWORD(32767)*FRACUNIT)
198 {
199 maxDist = inf.MaxDist=FixedDiv(FIXED_MIN-y,vy);
200 }
201
202 // recalculate the trace's end points for robustness
203 if (inf.TraceTraverse (ptflags))
204 { // check for intersection with floor/ceiling
205 res.Sector = §ors[inf.CurSector->sectornum];
206
207 if (inf.CheckSectorPlane (inf.CurSector, true))
208 {
209 res.HitType = TRACE_HitFloor;
210 res.HitTexture = inf.CurSector->GetTexture(sector_t::floor);
211 if (res.CrossedWater == NULL &&
212 inf.CurSector->heightsec != NULL &&
213 inf.CurSector->heightsec->floorplane.ZatPoint (res.X, res.Y) >= res.Z)
214 {
215 res.CrossedWater = §ors[inf.CurSector->sectornum];
216 }
217 }
218 else if (inf.CheckSectorPlane (inf.CurSector, false))
219 {
220 res.HitType = TRACE_HitCeiling;
221 res.HitTexture = inf.CurSector->GetTexture(sector_t::ceiling);
222 }
223 }
224
225 if (res.HitType != TRACE_HitNone)
226 {
227 if (flags)
228 {
229 return EditTraceResult (flags, res);
230 }
231 else
232 {
233 return true;
234 }
235 }
236 else
237 {
238 res.HitType = TRACE_HitNone;
239 res.X = x + FixedMul (vx, maxDist);
240 res.Y = y + FixedMul (vy, maxDist);
241 res.Z = z + FixedMul (vz, maxDist);
242 res.Distance = maxDist;
243 res.Fraction = FRACUNIT;
244 return false;
245 }
246 }
247
TraceTraverse(int ptflags)248 bool FTraceInfo::TraceTraverse (int ptflags)
249 {
250 FPathTraverse it(StartX, StartY, FixedMul (Vx, MaxDist), FixedMul (Vy, MaxDist), ptflags | PT_DELTA);
251 intercept_t *in;
252
253 while ((in = it.Next()))
254 {
255 fixed_t hitx, hity, hitz;
256 fixed_t dist;
257
258 // Deal with splashes in 3D floors
259 if (CurSector->e->XFloor.ffloors.Size())
260 {
261 for(unsigned int i=0;i<CurSector->e->XFloor.ffloors.Size();i++)
262 {
263 F3DFloor * rover=CurSector->e->XFloor.ffloors[i];
264 if (!(rover->flags&FF_EXISTS))
265 continue;
266
267 // Deal with splashy stuff
268 if (rover->flags&FF_SWIMMABLE && Results->Crossed3DWater == NULL)
269 {
270 if (Check3DFloorPlane(rover, false))
271 Results->Crossed3DWater = rover;
272 }
273 }
274 }
275
276 if (in->isaline)
277 {
278 int lineside;
279 sector_t *entersector;
280
281 dist = FixedMul (MaxDist, in->frac);
282 hitx = StartX + FixedMul (Vx, dist);
283 hity = StartY + FixedMul (Vy, dist);
284 hitz = StartZ + FixedMul (Vz, dist);
285
286 fixed_t ff, fc, bf = 0, bc = 0;
287
288 // CurSector may be a copy so we must compare the sector number, not the index!
289 if (in->d.line->frontsector->sectornum == CurSector->sectornum)
290 {
291 lineside = 0;
292 }
293 else if (in->d.line->backsector && in->d.line->backsector->sectornum == CurSector->sectornum)
294 {
295 lineside = 1;
296 }
297 else
298 { // Dammit. Why does Doom have to allow non-closed sectors?
299 if (in->d.line->backsector == NULL)
300 {
301 lineside = 0;
302 CurSector = in->d.line->frontsector;
303 }
304 else
305 {
306 lineside = P_PointOnLineSide (StartX, StartY, in->d.line);
307 CurSector = lineside ? in->d.line->backsector : in->d.line->frontsector;
308 }
309 }
310
311 if (!(in->d.line->flags & ML_TWOSIDED))
312 {
313 entersector = NULL;
314 }
315 else
316 {
317 entersector = (lineside == 0) ? in->d.line->backsector : in->d.line->frontsector;
318
319 // For backwards compatibility: Ignore lines with the same sector on both sides.
320 // This is the way Doom.exe did it and some WADs (e.g. Alien Vendetta MAP15) need it.
321 if (i_compatflags & COMPATF_TRACE && in->d.line->backsector == in->d.line->frontsector)
322 {
323 // We must check special activation here because the code below is never reached.
324 if (TraceFlags & TRACE_PCross)
325 {
326 P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_PCross);
327 }
328 if (TraceFlags & TRACE_Impact)
329 {
330 P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact);
331 }
332 continue;
333 }
334 }
335
336 ff = CurSector->floorplane.ZatPoint (hitx, hity);
337 fc = CurSector->ceilingplane.ZatPoint (hitx, hity);
338
339 if (entersector != NULL)
340 {
341 bf = entersector->floorplane.ZatPoint (hitx, hity);
342 bc = entersector->ceilingplane.ZatPoint (hitx, hity);
343 }
344
345 sector_t *hsec = CurSector->GetHeightSec();
346 if (Results->CrossedWater == NULL &&
347 hsec != NULL &&
348 //CurSector->heightsec->waterzone &&
349 hitz <= hsec->floorplane.ZatPoint (hitx, hity))
350 {
351 // hit crossed a water plane
352 Results->CrossedWater = §ors[CurSector->sectornum];
353 }
354
355 if (hitz <= ff)
356 { // hit floor in front of wall
357 Results->HitType = TRACE_HitFloor;
358 Results->HitTexture = CurSector->GetTexture(sector_t::floor);
359 }
360 else if (hitz >= fc)
361 { // hit ceiling in front of wall
362 Results->HitType = TRACE_HitCeiling;
363 Results->HitTexture = CurSector->GetTexture(sector_t::ceiling);
364 }
365 else if (entersector == NULL ||
366 hitz < bf || hitz > bc ||
367 in->d.line->flags & WallMask)
368 { // hit the wall
369 Results->HitType = TRACE_HitWall;
370 Results->Tier =
371 entersector == NULL ? TIER_Middle :
372 hitz <= bf ? TIER_Lower :
373 hitz >= bc ? TIER_Upper : TIER_Middle;
374 if (TraceFlags & TRACE_Impact)
375 {
376 P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact);
377 }
378 }
379 else
380 { // made it past the wall
381 // check for 3D floors first
382 if (entersector->e->XFloor.ffloors.Size())
383 {
384 memcpy(&DummySector[sectorsel],entersector,sizeof(sector_t));
385 entersector=&DummySector[sectorsel];
386 sectorsel^=1;
387
388 for(unsigned int i=0;i<entersector->e->XFloor.ffloors.Size();i++)
389 {
390 F3DFloor * rover=entersector->e->XFloor.ffloors[i];
391 int entershootthrough = !!(rover->flags&FF_SHOOTTHROUGH);
392
393 if (entershootthrough != inshootthrough && rover->flags&FF_EXISTS)
394 {
395 fixed_t ff_bottom=rover->bottom.plane->ZatPoint(hitx, hity);
396 fixed_t ff_top=rover->top.plane->ZatPoint(hitx, hity);
397
398 // clip to the part of the sector we are in
399 if (hitz>ff_top)
400 {
401 // above
402 if (bf<ff_top)
403 {
404 entersector->floorplane=*rover->top.plane;
405 entersector->SetTexture(sector_t::floor, *rover->top.texture, false);
406 bf=ff_top;
407 }
408 }
409 else if (hitz<ff_bottom)
410 {
411 //below
412 if (bc>ff_bottom)
413 {
414 entersector->ceilingplane=*rover->bottom.plane;
415 entersector->SetTexture(sector_t::ceiling, *rover->bottom.texture, false);
416 bc=ff_bottom;
417 }
418 }
419 else
420 {
421 //hit the edge - equivalent to hitting the wall
422 Results->HitType = TRACE_HitWall;
423 Results->Tier = TIER_FFloor;
424 Results->ffloor = rover;
425 if ((TraceFlags & TRACE_Impact) && in->d.line->special)
426 {
427 P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact);
428 }
429 goto cont;
430 }
431 }
432 }
433 }
434
435 Results->HitType = TRACE_HitNone;
436 if (TraceFlags & TRACE_PCross)
437 {
438 P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_PCross);
439 }
440 if (TraceFlags & TRACE_Impact)
441 { // This is incorrect for "impact", but Hexen did this, so
442 // we need to as well, for compatibility
443 P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact);
444 }
445 }
446 cont:
447
448 if (Results->HitType != TRACE_HitNone)
449 {
450 // We hit something, so figure out where exactly
451 Results->Sector = §ors[CurSector->sectornum];
452
453 if (Results->HitType != TRACE_HitWall &&
454 !CheckSectorPlane (CurSector, Results->HitType == TRACE_HitFloor))
455 { // trace is parallel to the plane (or right on it)
456 if (entersector == NULL)
457 {
458 Results->HitType = TRACE_HitWall;
459 Results->Tier = TIER_Middle;
460 }
461 else
462 {
463 if (hitz <= bf || hitz >= bc)
464 {
465 Results->HitType = TRACE_HitWall;
466 Results->Tier =
467 hitz <= bf ? TIER_Lower :
468 hitz >= bc ? TIER_Upper : TIER_Middle;
469 }
470 else
471 {
472 Results->HitType = TRACE_HitNone;
473 }
474 }
475 if (Results->HitType == TRACE_HitWall && TraceFlags & TRACE_Impact)
476 {
477 P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact);
478 }
479 }
480
481 if (Results->HitType == TRACE_HitWall)
482 {
483 Results->X = hitx;
484 Results->Y = hity;
485 Results->Z = hitz;
486 Results->Distance = dist;
487 Results->Fraction = in->frac;
488 Results->Line = in->d.line;
489 Results->Side = lineside;
490 }
491 }
492
493 if (Results->HitType == TRACE_HitNone)
494 {
495 CurSector = entersector;
496 EnterDist = dist;
497 continue;
498 }
499
500 if (TraceCallback != NULL)
501 {
502 switch (TraceCallback(*Results, TraceCallbackData))
503 {
504 case TRACE_Stop: return false;
505 case TRACE_Abort: Results->HitType = TRACE_HitNone; return false;
506 case TRACE_Skip: Results->HitType = TRACE_HitNone; break;
507 default: break;
508 }
509 }
510 else
511 {
512 return false;
513 }
514 }
515
516 // Encountered an actor
517 if (!(in->d.thing->flags & ActorMask) || in->d.thing == IgnoreThis)
518 {
519 continue;
520 }
521
522 dist = FixedMul (MaxDist, in->frac);
523 hitx = StartX + FixedMul (Vx, dist);
524 hity = StartY + FixedMul (Vy, dist);
525 hitz = StartZ + FixedMul (Vz, dist);
526
527 if (hitz > in->d.thing->Top())
528 { // trace enters above actor
529 if (Vz >= 0) continue; // Going up: can't hit
530
531 // Does it hit the top of the actor?
532 dist = FixedDiv(in->d.thing->Top() - StartZ, Vz);
533
534 if (dist > MaxDist) continue;
535 in->frac = FixedDiv(dist, MaxDist);
536
537 hitx = StartX + FixedMul (Vx, dist);
538 hity = StartY + FixedMul (Vy, dist);
539 hitz = StartZ + FixedMul (Vz, dist);
540
541 // calculated coordinate is outside the actor's bounding box
542 if (abs(hitx - in->d.thing->X()) > in->d.thing->radius ||
543 abs(hity - in->d.thing->Y()) > in->d.thing->radius) continue;
544 }
545 else if (hitz < in->d.thing->Z())
546 { // trace enters below actor
547 if (Vz <= 0) continue; // Going down: can't hit
548
549 // Does it hit the bottom of the actor?
550 dist = FixedDiv(in->d.thing->Z() - StartZ, Vz);
551 if (dist > MaxDist) continue;
552 in->frac = FixedDiv(dist, MaxDist);
553
554 hitx = StartX + FixedMul (Vx, dist);
555 hity = StartY + FixedMul (Vy, dist);
556 hitz = StartZ + FixedMul (Vz, dist);
557
558 // calculated coordinate is outside the actor's bounding box
559 if (abs(hitx - in->d.thing->X()) > in->d.thing->radius ||
560 abs(hity - in->d.thing->Y()) > in->d.thing->radius) continue;
561 }
562
563 // check for extrafloors first
564 if (CurSector->e->XFloor.ffloors.Size())
565 {
566 fixed_t ff_floor=CurSector->floorplane.ZatPoint(hitx, hity);
567 fixed_t ff_ceiling=CurSector->ceilingplane.ZatPoint(hitx, hity);
568
569 if (hitz>ff_ceiling) // actor is hit above the current ceiling
570 {
571 Results->HitType=TRACE_HitCeiling;
572 Results->HitTexture = CurSector->GetTexture(sector_t::ceiling);
573 }
574 else if (hitz<ff_floor) // actor is hit below the current floor
575 {
576 Results->HitType=TRACE_HitFloor;
577 Results->HitTexture = CurSector->GetTexture(sector_t::floor);
578 }
579 else goto cont1;
580
581 // the trace hit a 3D-floor before the thing.
582 // Calculate an intersection and abort.
583 Results->Sector = §ors[CurSector->sectornum];
584 if (!CheckSectorPlane(CurSector, Results->HitType == TRACE_HitFloor))
585 {
586 Results->HitType = TRACE_HitNone;
587 }
588 if (TraceCallback != NULL)
589 {
590 switch (TraceCallback(*Results, TraceCallbackData))
591 {
592 case TRACE_Continue: return true;
593 case TRACE_Stop: return false;
594 case TRACE_Abort: Results->HitType = TRACE_HitNone; return false;
595 case TRACE_Skip: Results->HitType = TRACE_HitNone; return true;
596 }
597 }
598 else
599 {
600 return false;
601 }
602 }
603 cont1:
604
605 Results->HitType = TRACE_HitActor;
606 Results->X = hitx;
607 Results->Y = hity;
608 Results->Z = hitz;
609 Results->Distance = dist;
610 Results->Fraction = in->frac;
611 Results->Actor = in->d.thing;
612
613 if (TraceCallback != NULL)
614 {
615 switch (TraceCallback(*Results, TraceCallbackData))
616 {
617 case TRACE_Stop: return false;
618 case TRACE_Abort: Results->HitType = TRACE_HitNone; return false;
619 case TRACE_Skip: Results->HitType = TRACE_HitNone; break;
620 default: break;
621 }
622 }
623 else
624 {
625 return false;
626 }
627 }
628 return true;
629 }
630
CheckPlane(const secplane_t & plane)631 bool FTraceInfo::CheckPlane (const secplane_t &plane)
632 {
633 fixed_t den = TMulScale16 (plane.a, Vx, plane.b, Vy, plane.c, Vz);
634
635 if (den != 0)
636 {
637 fixed_t num = TMulScale16 (plane.a, StartX,
638 plane.b, StartY,
639 plane.c, StartZ) + plane.d;
640
641 fixed_t hitdist = FixedDiv (-num, den);
642
643 if (hitdist > EnterDist && hitdist < MaxDist)
644 {
645 Results->X = StartX + FixedMul (Vx, hitdist);
646 Results->Y = StartY + FixedMul (Vy, hitdist);
647 Results->Z = StartZ + FixedMul (Vz, hitdist);
648 Results->Distance = hitdist;
649 Results->Fraction = FixedDiv (hitdist, MaxDist);
650 return true;
651 }
652 }
653 return false;
654 }
655
CheckSectorPlane(const sector_t * sector,bool checkFloor)656 bool FTraceInfo::CheckSectorPlane (const sector_t *sector, bool checkFloor)
657 {
658 secplane_t plane;
659
660 if (checkFloor)
661 {
662 plane = sector->floorplane;
663 }
664 else
665 {
666 plane = sector->ceilingplane;
667 }
668
669 return CheckPlane(plane);
670 }
671
Check3DFloorPlane(const F3DFloor * ffloor,bool checkBottom)672 bool FTraceInfo::Check3DFloorPlane (const F3DFloor *ffloor, bool checkBottom)
673 {
674 secplane_t plane;
675
676 if (checkBottom)
677 {
678 plane = *(ffloor->bottom.plane);
679 }
680 else
681 {
682 plane = *(ffloor->top.plane);
683 }
684
685 return CheckPlane(plane);
686 }
687
EditTraceResult(DWORD flags,FTraceResults & res)688 static bool EditTraceResult (DWORD flags, FTraceResults &res)
689 {
690 if (flags & TRACE_NoSky)
691 { // Throw away sky hits
692 if (res.HitType == TRACE_HitFloor || res.HitType == TRACE_HitCeiling)
693 {
694 if (res.HitTexture == skyflatnum)
695 {
696 res.HitType = TRACE_HitNone;
697 return false;
698 }
699 }
700 else if (res.HitType == TRACE_HitWall)
701 {
702 if (res.Tier == TIER_Upper &&
703 res.Line->frontsector->GetTexture(sector_t::ceiling) == skyflatnum &&
704 res.Line->backsector->GetTexture(sector_t::ceiling) == skyflatnum)
705 {
706 res.HitType = TRACE_HitNone;
707 return false;
708 }
709 }
710 }
711 return true;
712 }
713