This commit is contained in:
Christoph Oelckers 2016-04-16 19:42:12 +02:00
commit 6db95182cf
9 changed files with 295 additions and 310 deletions

View file

@ -621,19 +621,65 @@ void P_DrawSplash2 (int count, const DVector3 &pos, DAngle angle, int updown, in
}
}
void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &portalhits, const DVector3 &end, int color1, int color2, double maxdiff_d, int flags, PClassActor *spawnclass, DAngle angle, int duration, double sparsity, double drift, int SpiralOffset)
struct TrailSegment
{
double length, lengthsquared;
DVector3 start;
DVector3 dir;
DVector3 extend;
DVector2 soundpos;
double length;
double sounddist;
};
void P_DrawRailTrail(AActor *source, TArray<SPortalHit> &portalhits, int color1, int color2, double maxdiff, int flags, PClassActor *spawnclass, DAngle angle, int duration, double sparsity, double drift, int SpiralOffset)
{
double length = 0;
int steps, i;
TArray<TrailSegment> trail;
TAngle<double> deg;
DVector3 step, dir, pos, extend;
DVector3 pos;
bool fullbright;
float maxdiff = (float)maxdiff_d;
unsigned segment;
double lencount;
for (unsigned i = 0; i < portalhits.Size() - 1; i++)
{
TrailSegment seg;
seg.start = portalhits[i].ContPos;
seg.dir = portalhits[i].OutDir;
seg.length = (portalhits[i + 1].HitPos - seg.start).Length();
//Calculate PerpendicularVector (extend, dir):
double minelem = 1;
int epos;
int ii;
for (epos = 0, ii = 0; ii < 3; ++ii)
{
if (fabs(seg.dir[ii]) < minelem)
{
epos = ii;
minelem = fabs(seg.dir[ii]);
}
}
DVector3 tempvec(0, 0, 0);
tempvec[epos] = 1;
seg.extend = (tempvec - (seg.dir | tempvec) * seg.dir) * 3;
length += seg.length;
// Only consider sound in 2D (for now, anyway)
// [BB] You have to divide by lengthsquared here, not multiply with it.
AActor *mo = players[consoleplayer].camera;
double r = ((seg.start.Y - mo->Y()) * (-seg.dir.Y) - (seg.start.X - mo->X()) * (seg.dir.X)) / (seg.length * seg.length);
r = clamp<double>(r, 0., 1.);
seg.soundpos = seg.start + r * seg.dir;
seg.sounddist = (seg.soundpos - mo->Pos()).LengthSquared();
trail.Push(seg);
}
dir = end - start;
lengthsquared = dir | dir;
length = g_sqrt(lengthsquared);
steps = xs_FloorToInt(length / 3);
fullbright = !!(flags & RAF_FULLBRIGHT);
@ -652,30 +698,19 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
// The railgun's sound is special. It gets played from the
// point on the slug's trail that is closest to the hearing player.
AActor *mo = players[consoleplayer].camera;
DVector3 point;
double r;
double dirz;
if (fabs(mo->X() - start.X) < 20
&& fabs(mo->Y() - start.Y) < 20)
if (fabs(mo->X() - trail[0].start.X) < 20 && fabs(mo->Y() - trail[0].start.Y) < 20)
{ // This player (probably) fired the railgun
S_Sound (mo, CHAN_WEAPON, sound, 1, ATTN_NORM);
}
else
{
// Only consider sound in 2D (for now, anyway)
// [BB] You have to divide by lengthsquared here, not multiply with it.
r = ((start.Y - mo->Y()) * (-dir.Y) - (start.X - mo->X()) * (dir.X)) / lengthsquared;
r = clamp<double>(r, 0., 1.);
dirz = dir.Z;
dir.Z = 0;
point = start + r * dir;
dir.Z = dirz;
S_Sound (DVector3(point.X, point.Y, ViewPos.Z), CHAN_WEAPON, sound, 1, ATTN_NORM);
TrailSegment *shortest = NULL;
for (auto &seg : trail)
{
if (shortest == NULL || shortest->sounddist > seg.sounddist) shortest = &seg;
}
S_Sound (DVector3(shortest->soundpos, ViewPos.Z), CHAN_WEAPON, sound, 1, ATTN_NORM);
}
}
}
@ -685,35 +720,16 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
return;
}
dir /= length;
//Calculate PerpendicularVector (extend, dir):
double minelem = 1;
int epos;
for (epos = 0, i = 0; i < 3; ++i)
{
if (fabs(dir[i]) < minelem)
{
epos = i;
minelem = fabs(dir[i]);
}
}
DVector3 tempvec(0, 0, 0);
tempvec[epos] = 1;
extend = tempvec - (dir | tempvec) * dir;
//
extend *= 3;
step = dir * 3;
// Create the outer spiral.
if (color1 != -1 && (!r_rail_smartspiral || color2 == -1) && r_rail_spiralsparsity > 0 && (spawnclass == NULL))
{
DVector3 spiral_step = step * r_rail_spiralsparsity * sparsity;
double stepsize = 3 * r_rail_spiralsparsity * sparsity;
int spiral_steps = (int)(steps * r_rail_spiralsparsity / sparsity);
segment = 0;
lencount = trail[0].length;
color1 = color1 == 0 ? -1 : ParticleColor(color1);
pos = start;
pos = trail[0].start;
deg = (double)SpiralOffset;
for (i = spiral_steps; i; i--)
{
@ -731,12 +747,12 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
p->size = 3;
p->bright = fullbright;
tempvec = DMatrix3x3(dir, deg) * extend;
tempvec = DMatrix3x3(trail[segment].dir, deg) * trail[segment].extend;
p->Vel = tempvec * drift / 16.;
p->Pos = tempvec + pos;
pos += spiral_step;
pos += trail[segment].dir * stepsize;
deg += double(r_rail_spiralsparsity * 14);
lencount -= stepsize;
if (color1 == -1)
{
int rand = M_Random();
@ -754,19 +770,36 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
{
p->color = color1;
}
if (lencount <= 0)
{
segment++;
if (segment < trail.Size())
{
pos = trail[segment].start - trail[segment].dir * lencount;
lencount += trail[segment].length;
}
else
{
// should never happen but if something goes wrong, just terminate the loop.
break;
}
}
}
}
// Create the inner trail.
if (color2 != -1 && r_rail_trailsparsity > 0 && spawnclass == NULL)
{
DVector3 trail_step = step * r_rail_trailsparsity * sparsity;
double stepsize = 3 * r_rail_spiralsparsity * sparsity;
int trail_steps = xs_FloorToInt(steps * r_rail_trailsparsity / sparsity);
color2 = color2 == 0 ? -1 : ParticleColor(color2);
DVector3 diff(0, 0, 0);
pos = start;
pos = trail[0].start;
lencount = trail[0].length;
segment = 0;
for (i = trail_steps; i; i--)
{
// [XA] inner trail uses a different default duration (33).
@ -793,8 +826,8 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
p->Pos = postmp;
if (color1 != -1)
p->Acc.Z -= 1./4096;
pos += trail_step;
pos += trail[segment].dir * stepsize;
lencount -= stepsize;
p->bright = fullbright;
if (color2 == -1)
@ -812,6 +845,21 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
{
p->color = color2;
}
if (lencount <= 0)
{
segment++;
if (segment < trail.Size())
{
pos = trail[segment].start - trail[segment].dir * lencount;
lencount += trail[segment].length;
}
else
{
// should never happen but if something goes wrong, just terminate the loop.
break;
}
}
}
}
// create actors
@ -820,11 +868,14 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
if (sparsity < 1)
sparsity = 32;
DVector3 trail_step = (step / 3) * sparsity;
double stepsize = 3 * r_rail_spiralsparsity * sparsity;
int trail_steps = (int)((steps * 3) / sparsity);
DVector3 diff(0, 0, 0);
pos = start;
pos = trail[0].start;
lencount = trail[0].length;
segment = 0;
for (i = trail_steps; i; i--)
{
if (maxdiff > 0)
@ -840,7 +891,22 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
AActor *thing = Spawn (spawnclass, pos + diff, ALLOW_REPLACE);
if (thing)
thing->Angles.Yaw = angle;
pos += trail_step;
pos += trail[segment].dir * stepsize;
lencount -= stepsize;
if (lencount <= 0)
{
segment++;
if (segment < trail.Size())
{
pos = trail[segment].start - trail[segment].dir * lencount;
lencount += trail[segment].length;
}
else
{
// should never happen but if something goes wrong, just terminate the loop.
break;
}
}
}
}
}

View file

@ -97,7 +97,7 @@ struct SPortalHit
DVector3 OutDir;
};
void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &portalhits, const DVector3 &end, int color1, int color2, double maxdiff = 0, int flags = 0, PClassActor *spawnclass = NULL, DAngle angle = 0., int duration = 35, double sparsity = 1.0, double drift = 1.0, int SpiralOffset = 270);
void P_DrawRailTrail(AActor *source, TArray<SPortalHit> &portalhits, int color1, int color2, double maxdiff = 0, int flags = 0, PClassActor *spawnclass = NULL, DAngle angle = 0., int duration = 35, double sparsity = 1.0, double drift = 1.0, int SpiralOffset = 270);
void P_DrawSplash (int count, const DVector3 &pos, DAngle angle, int kind);
void P_DrawSplash2 (int count, const DVector3 &pos, DAngle angle, int updown, int kind);
void P_DisconnectEffect (AActor *actor);

View file

@ -4598,15 +4598,8 @@ void P_RailAttack(FRailParams *p)
rail_data.StopAtInvul = (puffDefaults->flags3 & MF3_FOILINVUL) ? false : true;
rail_data.ThruSpecies = (puffDefaults->flags6 & MF6_MTHRUSPECIES) ? true : false;
// to make things easier, push the start position and directional vector onto the PortalHits array as its first element
SPortalHit phit = { start, start, vec };
rail_data.PortalHits.Push(phit);
Trace(start, source->Sector, vec, p->distance, MF_SHOOTABLE, ML_BLOCKEVERYTHING, source, trace, flags, ProcessRailHit, &rail_data);
// and push the hit position, too, so that the array contains the entire trace with all transition points.
phit = { trace.HitPos, trace.HitPos, trace.HitVector };
rail_data.PortalHits.Push(phit);
// Hurt anything the trace hit
unsigned int i;
FName damagetype = (puffDefaults == NULL || puffDefaults->DamageType == NAME_None) ? FName(NAME_Railgun) : puffDefaults->DamageType;
@ -4709,7 +4702,7 @@ void P_RailAttack(FRailParams *p)
}
// Draw the slug's trail.
P_DrawRailTrail(source, start, rail_data.PortalHits, trace.HitPos, p->color1, p->color2, p->maxdiff, p->flags, p->spawnclass, angle, p->duration, p->sparsity, p->drift, p->SpiralOffset);
P_DrawRailTrail(source, rail_data.PortalHits, p->color1, p->color2, p->maxdiff, p->flags, p->spawnclass, angle, p->duration, p->sparsity, p->drift, p->SpiralOffset);
}
//==========================================================================

View file

@ -450,13 +450,13 @@ void AActor::LinkToWorld(bool spawningmapthing, sector_t *sector)
// link into blockmap (inert things don't need to be in the blockmap)
if (!(flags & MF_NOBLOCKMAP))
{
FPortalGroupArray check(FPortalGroupArray::PGA_NoSectorPortals);
FPortalGroupArray check;
P_CollectConnectedGroups(Sector->PortalGroup, Pos(), Top(), radius, check);
for (int i = -1; i < (int)check.Size(); i++)
{
DVector3 pos = i==-1? Pos() : PosRelative(check[i]);
DVector3 pos = i==-1? Pos() : PosRelative(check[i] & ~FPortalGroupArray::FLAT);
int x1 = GetBlockX(pos.X - radius);
int x2 = GetBlockX(pos.X + radius);
@ -1616,12 +1616,22 @@ int FPathTraverse::PortalRelocate(intercept_t *in, int flags, DVector3 *optpos)
P_TranslatePortalXY(in->d.line, optpos->X, optpos->Y);
P_TranslatePortalZ(in->d.line, optpos->Z);
}
line_t *saved = in->d.line; // this gets overwriitten by the init call.
line_t *saved = in->d.line; // this gets overwritten by the init call.
intercepts.Resize(intercept_index);
init(hitx, hity, endx, endy, flags, in->frac);
init(hitx, hity, endx, endy, flags, in->frac + EQUAL_EPSILON);
return saved->getPortal()->mType == PORTT_LINKED? 1:-1;
}
void FPathTraverse::PortalRelocate(AActor *portalthing, int flags, double hitfrac)
{
double hitx = trace.x + portalthing->Scale.X;
double hity = trace.y + portalthing->Scale.Y;
double endx = hitx + trace.dx;
double endy = hity + trace.dy;
intercepts.Resize(intercept_index);
init(hitx, hity, endx, endy, flags, hitfrac);
}
//===========================================================================
//
//

View file

@ -373,6 +373,7 @@ public:
}
void init(double x1, double y1, double x2, double y2, int flags, double startfrac = 0);
int PortalRelocate(intercept_t *in, int flags, DVector3 *optpos = NULL);
void PortalRelocate(AActor *portalthing, int flags, double hitfrac);
virtual ~FPathTraverse();
const divline_t &Trace() const { return trace; }

View file

@ -55,7 +55,6 @@ struct FTraceInfo
DWORD WallMask;
AActor *IgnoreThis;
FTraceResults *Results;
FTraceResults *TempResults;
sector_t *CurSector;
double MaxDist;
double EnterDist;
@ -64,10 +63,8 @@ struct FTraceInfo
DWORD TraceFlags;
int inshootthrough;
double startfrac;
int aimdir;
double limitz;
double lastfloorportalheight;
double lastceilingportalheight;
int ptflags;
// These are required for 3D-floor checking
// to create a fake sector with a floor
@ -76,12 +73,12 @@ struct FTraceInfo
int sectorsel;
void Setup3DFloors();
bool LineCheck(intercept_t *in);
bool ThingCheck(intercept_t *in);
bool LineCheck(intercept_t *in, double dist, DVector3 hit);
bool ThingCheck(intercept_t *in, double dist, DVector3 hit);
bool TraceTraverse (int ptflags);
bool CheckPlane(const secplane_t &plane);
int EnterLinePortal(line_t *li, double frac);
void EnterSectorPortal(int position, double frac, sector_t *entersec);
void EnterLinePortal(FPathTraverse &pt, intercept_t *in);
void EnterSectorPortal(FPathTraverse &pt, int position, double frac, sector_t *entersec);
bool CheckSectorPlane(const sector_t *sector, bool checkFloor)
@ -107,6 +104,38 @@ struct FTraceInfo
static bool EditTraceResult (DWORD flags, FTraceResults &res);
static void GetPortalTransition(DVector3 &pos, sector_t *&sec)
{
bool moved = false;
double testz = pos.Z;
while (!sec->PortalBlocksMovement(sector_t::ceiling))
{
AActor *port = sec->SkyBoxes[sector_t::ceiling];
if (pos.Z > port->specialf1)
{
pos += port->Scale;
sec = P_PointInSector(pos);
moved = true;
}
else break;
}
if (!moved)
{
while (!sec->PortalBlocksMovement(sector_t::floor))
{
AActor *port = sec->SkyBoxes[sector_t::floor];
if (pos.Z <= port->specialf1)
{
pos += port->Scale;
sec = P_PointInSector(pos);
}
else break;
}
}
}
//==========================================================================
//
// Trace entry point
@ -117,16 +146,15 @@ bool Trace(const DVector3 &start, sector_t *sector, const DVector3 &direction, d
ActorFlags actorMask, DWORD wallMask, AActor *ignore, FTraceResults &res, DWORD flags,
ETraceStatus(*callback)(FTraceResults &res, void *), void *callbackdata)
{
int ptflags;
FTraceInfo inf;
FTraceResults tempResult;
memset(&tempResult, 0, sizeof(tempResult));
tempResult.Fraction = tempResult.Distance = NO_VALUE;
ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS|PT_COMPATIBLE : PT_ADDLINES;
inf.Start = start;
GetPortalTransition(inf.Start, sector);
inf.ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS|PT_COMPATIBLE : PT_ADDLINES;
inf.Vec = direction;
inf.ActorMask = actorMask;
inf.WallMask = wallMask;
@ -138,15 +166,30 @@ bool Trace(const DVector3 &start, sector_t *sector, const DVector3 &direction, d
inf.TraceCallbackData = callbackdata;
inf.TraceFlags = flags;
inf.Results = &res;
inf.TempResults = &tempResult;
inf.inshootthrough = true;
inf.sectorsel=0;
inf.aimdir = -1;
inf.startfrac = 0;
inf.lastfloorportalheight = inf.lastceilingportalheight = start.Z;
inf.limitz = inf.Start.Z;
memset(&res, 0, sizeof(res));
if (inf.TraceTraverse (ptflags))
if ((flags & TRACE_ReportPortals) && callback != NULL)
{
tempResult.HitType = TRACE_CrossingPortal;
tempResult.HitPos = tempResult.SrcFromTarget = inf.Start;
tempResult.HitVector = inf.Vec;
callback(tempResult, inf.TraceCallbackData);
}
bool reslt = inf.TraceTraverse(inf.ptflags);
if ((flags & TRACE_ReportPortals) && callback != NULL)
{
tempResult.HitType = TRACE_CrossingPortal;
tempResult.HitPos = tempResult.SrcFromTarget = inf.Results->HitPos;
tempResult.HitVector = inf.Vec;
callback(tempResult, inf.TraceCallbackData);
}
if (reslt)
{
return flags ? EditTraceResult(flags, res) : true;
}
@ -163,48 +206,32 @@ bool Trace(const DVector3 &start, sector_t *sector, const DVector3 &direction, d
//
//============================================================================
void FTraceInfo::EnterSectorPortal(int position, double frac, sector_t *entersec)
void FTraceInfo::EnterSectorPortal(FPathTraverse &pt, int position, double frac, sector_t *entersec)
{
if (aimdir != -1 && aimdir != position) return;
AActor *portal = entersec->SkyBoxes[position];
if (aimdir == sector_t::ceiling && portal->specialf1 < limitz) return;
else if (aimdir == sector_t::floor && portal->specialf1 > limitz) return;
FTraceInfo newtrace;
FTraceResults results;
memset(&results, 0, sizeof(results));
newtrace.Start += portal->Scale;
frac += 1 / MaxDist;
double enterdist = MaxDist * frac;
DVector2 enter = newtrace.Start.XY() + enterdist * Vec.XY();
DVector3 exit = Start + enterdist * Vec;
DVector3 enter = exit + portal->Scale;
newtrace.Vec = Vec;
newtrace.ActorMask = ActorMask;
newtrace.WallMask = WallMask;
newtrace.IgnoreThis = IgnoreThis;
newtrace.Results = &results;
newtrace.TempResults = TempResults;
newtrace.CurSector = P_PointInSector(enter);
newtrace.MaxDist = MaxDist;
newtrace.EnterDist = EnterDist;
newtrace.TraceCallback = TraceCallback;
newtrace.TraceCallbackData = TraceCallbackData;
newtrace.TraceFlags = TraceFlags;
newtrace.inshootthrough = true;
newtrace.startfrac = frac;
newtrace.aimdir = position;
newtrace.limitz = portal->specialf1;
newtrace.sectorsel = 0;
newtrace.lastfloorportalheight = newtrace.lastceilingportalheight = limitz;
Start += portal->Scale;
CurSector = P_PointInSector(enter);
inshootthrough = true;
startfrac = frac;
EnterDist = enterdist;
pt.PortalRelocate(portal, ptflags, frac);
if (newtrace.TraceTraverse(ActorMask ? PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE : PT_ADDLINES))
if ((TraceFlags & TRACE_ReportPortals) && TraceCallback != NULL)
{
TempResults->CopyIfCloser(newtrace.Results);
enterdist = MaxDist * frac;
Results->HitType = TRACE_CrossingPortal;
Results->HitPos = exit;
Results->SrcFromTarget = enter;
Results->HitVector = Vec;
TraceCallback(*Results, TraceCallbackData);
}
Setup3DFloors();
}
//============================================================================
@ -213,59 +240,38 @@ void FTraceInfo::EnterSectorPortal(int position, double frac, sector_t *entersec
//
//============================================================================
int FTraceInfo::EnterLinePortal(line_t *li, double frac)
void FTraceInfo::EnterLinePortal(FPathTraverse &pt, intercept_t *in)
{
line_t *li = in->d.line;
FLinePortal *port = li->getPortal();
// The caller cannot handle portals without global offset.
if (port->mType != PORTT_LINKED && (TraceFlags & TRACE_PortalRestrict)) return -1;
double frac = in->frac + EQUAL_EPSILON;
double enterdist = MaxDist * frac;
DVector3 exit = Start + MaxDist * in->frac * Vec;
FTraceInfo newtrace;
P_TranslatePortalXY(li, Start.X, Start.Y);
P_TranslatePortalZ(li, Start.Z);
P_TranslatePortalVXVY(li, Vec.X, Vec.Y);
P_TranslatePortalZ(li, limitz);
newtrace.Start = Start;
newtrace.Vec = Vec;
P_TranslatePortalXY(li, newtrace.Start.X, newtrace.Start.Y);
P_TranslatePortalZ(li, newtrace.Start.Z);
P_TranslatePortalVXVY(li, newtrace.Vec.X, newtrace.Vec.Y);
frac += 1 / MaxDist;
double enterdist = MaxDist / frac;
DVector3 enter = newtrace.Start + enterdist * Vec;
newtrace.ActorMask = ActorMask;
newtrace.WallMask = WallMask;
newtrace.IgnoreThis = IgnoreThis;
newtrace.Results = Results;
newtrace.TempResults = TempResults;
newtrace.CurSector = P_PointInSector(enter);
newtrace.MaxDist = MaxDist;
newtrace.EnterDist = EnterDist;
newtrace.TraceCallback = TraceCallback;
newtrace.TraceCallbackData = TraceCallbackData;
newtrace.TraceFlags = TraceFlags;
newtrace.inshootthrough = true;
newtrace.startfrac = frac;
newtrace.aimdir = aimdir;
newtrace.limitz = limitz;
P_TranslatePortalZ(li, newtrace.limitz);
newtrace.lastfloorportalheight = newtrace.lastceilingportalheight = newtrace.limitz;
newtrace.sectorsel = 0;
Results->unlinked = true;
CurSector = P_PointInSector(Start + enterdist * Vec);
EnterDist = enterdist;
inshootthrough = true;
startfrac = frac;
Results->unlinked |= (port->mType != PORTT_LINKED);
pt.PortalRelocate(in, ptflags);
if ((TraceFlags & TRACE_ReportPortals) && TraceCallback != NULL)
{
enterdist = MaxDist * in->frac;
Results->HitType = TRACE_CrossingPortal;
Results->HitPos = enter;
P_TranslatePortalXY(li, enter.X, enter.Y);
P_TranslatePortalZ(li, enter.Z);
Results->SrcFromTarget = enter;
Results->HitVector = newtrace.Vec;
Results->HitPos = exit;
P_TranslatePortalXY(li, exit.X, exit.Y);
P_TranslatePortalZ(li, exit.Z);
Results->SrcFromTarget = exit;
Results->HitVector = Vec;
TraceCallback(*Results, TraceCallbackData);
}
return newtrace.TraceTraverse(ActorMask ? PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE : PT_ADDLINES);
}
//==========================================================================
@ -355,14 +361,6 @@ void FTraceInfo::Setup3DFloors()
}
}
}
if (!CurSector->PortalBlocksMovement(sector_t::ceiling))
{
EnterSectorPortal(sector_t::ceiling, startfrac, CurSector);
}
if (!CurSector->PortalBlocksMovement(sector_t::floor))
{
EnterSectorPortal(sector_t::floor, startfrac, CurSector);
}
}
@ -372,14 +370,11 @@ void FTraceInfo::Setup3DFloors()
//
//==========================================================================
bool FTraceInfo::LineCheck(intercept_t *in)
bool FTraceInfo::LineCheck(intercept_t *in, double dist, DVector3 hit)
{
int lineside;
sector_t *entersector;
double dist = MaxDist * in->frac;
DVector3 hit = Start + Vec * dist;
double ff, fc, bf = 0, bc = 0;
if (in->d.line->frontsector->sectornum == CurSector->sectornum)
@ -454,78 +449,15 @@ bool FTraceInfo::LineCheck(intercept_t *in)
if (hit.Z <= ff)
{
if (CurSector->PortalBlocksMovement(sector_t::floor))
{
// hit floor in front of wall
Results->HitType = TRACE_HitFloor;
Results->HitTexture = CurSector->GetTexture(sector_t::floor);
}
else
{
if ((TraceFlags & TRACE_ReportPortals) && lastfloorportalheight > fc)
{
lastfloorportalheight = fc;
if (TraceCallback != NULL)
{
Results->HitType = TRACE_CrossingPortal;
double hitz = CurSector->SkyBoxes[sector_t::floor]->specialf1;
Results->HitPos = Start + Vec * (hitz - Start.Z) / Vec.Z;
Results->SrcFromTarget = Results->HitPos + CurSector->SkyBoxes[sector_t::floor]->Scale;
Results->HitVector = Vec;
TraceCallback(*Results, TraceCallbackData);
}
}
if (entersector == NULL || entersector->PortalBlocksMovement(sector_t::floor))
{
// hit beyond a portal plane. This needs to be taken care of by the trace spawned on the other side.
Results->HitType = TRACE_HitNone;
return false;
}
}
// hit floor in front of wall
Results->HitType = TRACE_HitFloor;
Results->HitTexture = CurSector->GetTexture(sector_t::floor);
}
else if (hit.Z >= fc)
{
if (CurSector->PortalBlocksMovement(sector_t::ceiling))
{
// hit ceiling in front of wall
Results->HitType = TRACE_HitCeiling;
Results->HitTexture = CurSector->GetTexture(sector_t::ceiling);
}
else
{
if ((TraceFlags & TRACE_ReportPortals) && lastceilingportalheight < fc)
{
lastceilingportalheight = fc;
if (TraceCallback != NULL)
{
Results->HitType = TRACE_CrossingPortal;
double hitz = CurSector->SkyBoxes[sector_t::ceiling]->specialf1;
Results->HitPos = Start + Vec * (hitz - Start.Z) / Vec.Z;
Results->SrcFromTarget = Results->HitPos + CurSector->SkyBoxes[sector_t::ceiling]->Scale;
Results->HitVector = Vec;
TraceCallback(*Results, TraceCallbackData);
}
}
if (entersector == NULL || entersector->PortalBlocksMovement(sector_t::ceiling))
{
// hit beyond a portal plane. This needs to be taken care of by the trace spawned on the other side.
Results->HitType = TRACE_HitNone;
return false;
}
}
}
else if (in->d.line->isLinePortal())
{
if (entersector == NULL || (hit.Z >= bf && hit.Z <= bc))
{
int res = EnterLinePortal(in->d.line, in->frac);
if (res != -1)
{
aimdir = INT_MAX; // flag for ending the traverse
return !!res;
}
}
goto normalline; // hit upper or lower tier.
// hit ceiling in front of wall
Results->HitType = TRACE_HitCeiling;
Results->HitTexture = CurSector->GetTexture(sector_t::ceiling);
}
else if (entersector == NULL ||
hit.Z < bf || hit.Z > bc ||
@ -610,15 +542,6 @@ normalline:
// we need to as well, for compatibility
P_ActivateLine(in->d.line, IgnoreThis, lineside, SPAC_Impact);
}
if (!entersector->PortalBlocksMovement(sector_t::ceiling))
{
EnterSectorPortal(sector_t::ceiling, in->frac, entersector);
}
if (!entersector->PortalBlocksMovement(sector_t::floor))
{
EnterSectorPortal(sector_t::floor, in->frac, entersector);
}
}
cont:
@ -696,11 +619,8 @@ cont:
//
//==========================================================================
bool FTraceInfo::ThingCheck(intercept_t *in)
bool FTraceInfo::ThingCheck(intercept_t *in, double dist, DVector3 hit)
{
double dist = MaxDist * in->frac;
DVector3 hit = Start + Vec * dist;
if (hit.Z > in->d.thing->Top())
{
// trace enters above actor
@ -834,49 +754,59 @@ bool FTraceInfo::TraceTraverse (int ptflags)
lastsplashsector = CurSector->sectornum;
}
// We have something closer in the storage for portal subtraces.
if (TempResults->HitType != TRACE_HitNone && in->frac > TempResults->Fraction)
double dist = MaxDist * in->frac;
DVector3 hit = Start + Vec * dist;
// Crossed a floor portal?
if (Vec.Z < 0 && !CurSector->PortalBlocksMovement(sector_t::floor))
{
break;
// calculate position where the portal is crossed
double portz = CurSector->SkyBoxes[sector_t::floor]->specialf1;
if (hit.Z < portz && limitz > portz)
{
limitz = portz;
EnterSectorPortal(it, sector_t::floor, (portz - Start.Z) / (Vec.Z * MaxDist), CurSector);
continue;
}
}
else if (in->isaline)
// ... or a ceiling portal?
else if (Vec.Z > 0 && !CurSector->PortalBlocksMovement(sector_t::ceiling))
{
bool res = LineCheck(in);
if (aimdir == INT_MAX) return res; // signal for immediate abort
if (!res) break;
// calculate position where the portal is crossed
double portz = CurSector->SkyBoxes[sector_t::ceiling]->specialf1;
if (hit.Z > portz && limitz < portz)
{
limitz = portz;
EnterSectorPortal(it, sector_t::ceiling, (portz - Start.Z) / (Vec.Z * MaxDist), CurSector);
continue;
}
}
if (in->isaline)
{
if (in->d.line->isLinePortal() && P_PointOnLineSidePrecise(Start, in->d.line) == 0)
{
sector_t *entersector = in->d.line->backsector;
if (entersector == NULL || (hit.Z >= entersector->floorplane.ZatPoint(hit) && hit.Z <= entersector->ceilingplane.ZatPoint(hit)))
{
FLinePortal *port = in->d.line->getPortal();
// The caller cannot handle portals without global offset.
if (port->mType == PORTT_LINKED || !(TraceFlags & TRACE_PortalRestrict))
{
EnterLinePortal(it, in);
continue;
}
}
}
if (!LineCheck(in, dist, hit)) break;
}
else if ((in->d.thing->flags & ActorMask) && in->d.thing != IgnoreThis)
{
if (!ThingCheck(in)) break;
if (!ThingCheck(in, dist, hit)) break;
}
}
// Check if one subtrace through a portal yielded a better result.
if (TempResults->HitType != TRACE_HitNone &&
(Results->HitType == TRACE_HitNone || Results->Fraction > TempResults->Fraction))
{
// We still need to do a water check here or this may get missed on occasion
if (Results->CrossedWater == NULL &&
CurSector->heightsec != NULL &&
CurSector->heightsec->floorplane.ZatPoint(Results->HitPos) >= Results->HitPos.Z)
{
// Save the result so that the water check doesn't destroy it.
FTraceResults *res = Results;
FTraceResults hsecResult;
Results = &hsecResult;
if (CheckSectorPlane(CurSector->heightsec, true))
{
Results->CrossedWater = &sectors[CurSector->sectornum];
Results->CrossedWaterPos = Results->HitPos;
}
Results = res;
}
Results->CopyIfCloser(TempResults);
return true;
}
else if (Results->HitType == TRACE_HitNone)
if (Results->HitType == TRACE_HitNone)
{
if (CurSector->PortalBlocksMovement(sector_t::floor) && CheckSectorPlane(CurSector, true))
{

View file

@ -87,24 +87,6 @@ struct FTraceResults
DVector3 CrossedWaterPos; // remember the position so that we can use it for spawning the splash
F3DFloor *Crossed3DWater; // For 3D floor-based deep water
DVector3 Crossed3DWaterPos;
void CopyIfCloser(FTraceResults *other)
{
if (other->Distance < Distance || HitType == TRACE_HitNone)
{
memcpy(this, other, myoffsetof(FTraceResults, CrossedWater));
}
if (CrossedWater == NULL && other->CrossedWater != NULL)
{
CrossedWater = other->CrossedWater;
CrossedWaterPos = other->CrossedWaterPos;
}
if (Crossed3DWater == NULL && other->Crossed3DWater != NULL)
{
Crossed3DWater = other->Crossed3DWater;
Crossed3DWaterPos = other->Crossed3DWaterPos;
}
}
};

View file

@ -1157,7 +1157,8 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd)
performBlockingThrust = true;
}
FBoundingBox box(mobj->X(), mobj->Y(), mobj->radius);
DVector2 pos = mobj->PosRelative(ld);
FBoundingBox box(pos.X, pos.Y, mobj->radius);
if (!box.inRange(ld) || box.BoxOnLineSide(ld) != -1)
{

View file

@ -661,10 +661,10 @@ DVector2 P_GetOffsetPosition(double x, double y, double dx, double dy)
if (blockx < 0 || blocky < 0 || blockx >= bmapwidth || blocky >= bmapheight || !PortalBlockmap(blockx, blocky).neighborContainsLines) return dest;
}
FLinePortalTraverse it;
bool repeat;
do
{
FLinePortalTraverse it;
it.init(actx, acty, dx, dy, PT_ADDLINES|PT_DELTA);
intercept_t *in;
@ -696,6 +696,8 @@ DVector2 P_GetOffsetPosition(double x, double y, double dx, double dy)
// update the fields, end this trace and restart from the new position
dx = dest.X - hit.X;
dy = dest.Y - hit.Y;
actx = hit.X;
acty = hit.Y;
repeat = true;
}