in doom_py/src/vizdoom/src/p_trace.cpp [248:629]
bool FTraceInfo::TraceTraverse (int ptflags)
{
FPathTraverse it(StartX, StartY, FixedMul (Vx, MaxDist), FixedMul (Vy, MaxDist), ptflags | PT_DELTA);
intercept_t *in;
while ((in = it.Next()))
{
fixed_t hitx, hity, hitz;
fixed_t dist;
// Deal with splashes in 3D floors
if (CurSector->e->XFloor.ffloors.Size())
{
for(unsigned int i=0;i<CurSector->e->XFloor.ffloors.Size();i++)
{
F3DFloor * rover=CurSector->e->XFloor.ffloors[i];
if (!(rover->flags&FF_EXISTS))
continue;
// Deal with splashy stuff
if (rover->flags&FF_SWIMMABLE && Results->Crossed3DWater == NULL)
{
if (Check3DFloorPlane(rover, false))
Results->Crossed3DWater = rover;
}
}
}
if (in->isaline)
{
int lineside;
sector_t *entersector;
dist = FixedMul (MaxDist, in->frac);
hitx = StartX + FixedMul (Vx, dist);
hity = StartY + FixedMul (Vy, dist);
hitz = StartZ + FixedMul (Vz, dist);
fixed_t ff, fc, bf = 0, bc = 0;
// CurSector may be a copy so we must compare the sector number, not the index!
if (in->d.line->frontsector->sectornum == CurSector->sectornum)
{
lineside = 0;
}
else if (in->d.line->backsector && in->d.line->backsector->sectornum == CurSector->sectornum)
{
lineside = 1;
}
else
{ // Dammit. Why does Doom have to allow non-closed sectors?
if (in->d.line->backsector == NULL)
{
lineside = 0;
CurSector = in->d.line->frontsector;
}
else
{
lineside = P_PointOnLineSide (StartX, StartY, in->d.line);
CurSector = lineside ? in->d.line->backsector : in->d.line->frontsector;
}
}
if (!(in->d.line->flags & ML_TWOSIDED))
{
entersector = NULL;
}
else
{
entersector = (lineside == 0) ? in->d.line->backsector : in->d.line->frontsector;
// For backwards compatibility: Ignore lines with the same sector on both sides.
// This is the way Doom.exe did it and some WADs (e.g. Alien Vendetta MAP15) need it.
if (i_compatflags & COMPATF_TRACE && in->d.line->backsector == in->d.line->frontsector)
{
// We must check special activation here because the code below is never reached.
if (TraceFlags & TRACE_PCross)
{
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_PCross);
}
if (TraceFlags & TRACE_Impact)
{
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact);
}
continue;
}
}
ff = CurSector->floorplane.ZatPoint (hitx, hity);
fc = CurSector->ceilingplane.ZatPoint (hitx, hity);
if (entersector != NULL)
{
bf = entersector->floorplane.ZatPoint (hitx, hity);
bc = entersector->ceilingplane.ZatPoint (hitx, hity);
}
sector_t *hsec = CurSector->GetHeightSec();
if (Results->CrossedWater == NULL &&
hsec != NULL &&
//CurSector->heightsec->waterzone &&
hitz <= hsec->floorplane.ZatPoint (hitx, hity))
{
// hit crossed a water plane
Results->CrossedWater = §ors[CurSector->sectornum];
}
if (hitz <= ff)
{ // hit floor in front of wall
Results->HitType = TRACE_HitFloor;
Results->HitTexture = CurSector->GetTexture(sector_t::floor);
}
else if (hitz >= fc)
{ // hit ceiling in front of wall
Results->HitType = TRACE_HitCeiling;
Results->HitTexture = CurSector->GetTexture(sector_t::ceiling);
}
else if (entersector == NULL ||
hitz < bf || hitz > bc ||
in->d.line->flags & WallMask)
{ // hit the wall
Results->HitType = TRACE_HitWall;
Results->Tier =
entersector == NULL ? TIER_Middle :
hitz <= bf ? TIER_Lower :
hitz >= bc ? TIER_Upper : TIER_Middle;
if (TraceFlags & TRACE_Impact)
{
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact);
}
}
else
{ // made it past the wall
// check for 3D floors first
if (entersector->e->XFloor.ffloors.Size())
{
memcpy(&DummySector[sectorsel],entersector,sizeof(sector_t));
entersector=&DummySector[sectorsel];
sectorsel^=1;
for(unsigned int i=0;i<entersector->e->XFloor.ffloors.Size();i++)
{
F3DFloor * rover=entersector->e->XFloor.ffloors[i];
int entershootthrough = !!(rover->flags&FF_SHOOTTHROUGH);
if (entershootthrough != inshootthrough && rover->flags&FF_EXISTS)
{
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(hitx, hity);
fixed_t ff_top=rover->top.plane->ZatPoint(hitx, hity);
// clip to the part of the sector we are in
if (hitz>ff_top)
{
// above
if (bf<ff_top)
{
entersector->floorplane=*rover->top.plane;
entersector->SetTexture(sector_t::floor, *rover->top.texture, false);
bf=ff_top;
}
}
else if (hitz<ff_bottom)
{
//below
if (bc>ff_bottom)
{
entersector->ceilingplane=*rover->bottom.plane;
entersector->SetTexture(sector_t::ceiling, *rover->bottom.texture, false);
bc=ff_bottom;
}
}
else
{
//hit the edge - equivalent to hitting the wall
Results->HitType = TRACE_HitWall;
Results->Tier = TIER_FFloor;
Results->ffloor = rover;
if ((TraceFlags & TRACE_Impact) && in->d.line->special)
{
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact);
}
goto cont;
}
}
}
}
Results->HitType = TRACE_HitNone;
if (TraceFlags & TRACE_PCross)
{
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_PCross);
}
if (TraceFlags & TRACE_Impact)
{ // This is incorrect for "impact", but Hexen did this, so
// we need to as well, for compatibility
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact);
}
}
cont:
if (Results->HitType != TRACE_HitNone)
{
// We hit something, so figure out where exactly
Results->Sector = §ors[CurSector->sectornum];
if (Results->HitType != TRACE_HitWall &&
!CheckSectorPlane (CurSector, Results->HitType == TRACE_HitFloor))
{ // trace is parallel to the plane (or right on it)
if (entersector == NULL)
{
Results->HitType = TRACE_HitWall;
Results->Tier = TIER_Middle;
}
else
{
if (hitz <= bf || hitz >= bc)
{
Results->HitType = TRACE_HitWall;
Results->Tier =
hitz <= bf ? TIER_Lower :
hitz >= bc ? TIER_Upper : TIER_Middle;
}
else
{
Results->HitType = TRACE_HitNone;
}
}
if (Results->HitType == TRACE_HitWall && TraceFlags & TRACE_Impact)
{
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact);
}
}
if (Results->HitType == TRACE_HitWall)
{
Results->X = hitx;
Results->Y = hity;
Results->Z = hitz;
Results->Distance = dist;
Results->Fraction = in->frac;
Results->Line = in->d.line;
Results->Side = lineside;
}
}
if (Results->HitType == TRACE_HitNone)
{
CurSector = entersector;
EnterDist = dist;
continue;
}
if (TraceCallback != NULL)
{
switch (TraceCallback(*Results, TraceCallbackData))
{
case TRACE_Stop: return false;
case TRACE_Abort: Results->HitType = TRACE_HitNone; return false;
case TRACE_Skip: Results->HitType = TRACE_HitNone; break;
default: break;
}
}
else
{
return false;
}
}
// Encountered an actor
if (!(in->d.thing->flags & ActorMask) || in->d.thing == IgnoreThis)
{
continue;
}
dist = FixedMul (MaxDist, in->frac);
hitx = StartX + FixedMul (Vx, dist);
hity = StartY + FixedMul (Vy, dist);
hitz = StartZ + FixedMul (Vz, dist);
if (hitz > in->d.thing->Top())
{ // trace enters above actor
if (Vz >= 0) continue; // Going up: can't hit
// Does it hit the top of the actor?
dist = FixedDiv(in->d.thing->Top() - StartZ, Vz);
if (dist > MaxDist) continue;
in->frac = FixedDiv(dist, MaxDist);
hitx = StartX + FixedMul (Vx, dist);
hity = StartY + FixedMul (Vy, dist);
hitz = StartZ + FixedMul (Vz, dist);
// calculated coordinate is outside the actor's bounding box
if (abs(hitx - in->d.thing->X()) > in->d.thing->radius ||
abs(hity - in->d.thing->Y()) > in->d.thing->radius) continue;
}
else if (hitz < in->d.thing->Z())
{ // trace enters below actor
if (Vz <= 0) continue; // Going down: can't hit
// Does it hit the bottom of the actor?
dist = FixedDiv(in->d.thing->Z() - StartZ, Vz);
if (dist > MaxDist) continue;
in->frac = FixedDiv(dist, MaxDist);
hitx = StartX + FixedMul (Vx, dist);
hity = StartY + FixedMul (Vy, dist);
hitz = StartZ + FixedMul (Vz, dist);
// calculated coordinate is outside the actor's bounding box
if (abs(hitx - in->d.thing->X()) > in->d.thing->radius ||
abs(hity - in->d.thing->Y()) > in->d.thing->radius) continue;
}
// check for extrafloors first
if (CurSector->e->XFloor.ffloors.Size())
{
fixed_t ff_floor=CurSector->floorplane.ZatPoint(hitx, hity);
fixed_t ff_ceiling=CurSector->ceilingplane.ZatPoint(hitx, hity);
if (hitz>ff_ceiling) // actor is hit above the current ceiling
{
Results->HitType=TRACE_HitCeiling;
Results->HitTexture = CurSector->GetTexture(sector_t::ceiling);
}
else if (hitz<ff_floor) // actor is hit below the current floor
{
Results->HitType=TRACE_HitFloor;
Results->HitTexture = CurSector->GetTexture(sector_t::floor);
}
else goto cont1;
// the trace hit a 3D-floor before the thing.
// Calculate an intersection and abort.
Results->Sector = §ors[CurSector->sectornum];
if (!CheckSectorPlane(CurSector, Results->HitType == TRACE_HitFloor))
{
Results->HitType = TRACE_HitNone;
}
if (TraceCallback != NULL)
{
switch (TraceCallback(*Results, TraceCallbackData))
{
case TRACE_Continue: return true;
case TRACE_Stop: return false;
case TRACE_Abort: Results->HitType = TRACE_HitNone; return false;
case TRACE_Skip: Results->HitType = TRACE_HitNone; return true;
}
}
else
{
return false;
}
}
cont1:
Results->HitType = TRACE_HitActor;
Results->X = hitx;
Results->Y = hity;
Results->Z = hitz;
Results->Distance = dist;
Results->Fraction = in->frac;
Results->Actor = in->d.thing;
if (TraceCallback != NULL)
{
switch (TraceCallback(*Results, TraceCallbackData))
{
case TRACE_Stop: return false;
case TRACE_Abort: Results->HitType = TRACE_HitNone; return false;
case TRACE_Skip: Results->HitType = TRACE_HitNone; break;
default: break;
}
}
else
{
return false;
}
}
return true;
}