This commit is contained in:
Christoph Oelckers 2016-03-08 13:12:03 +01:00
commit c2e7123a36
32 changed files with 1365 additions and 754 deletions

View file

@ -140,7 +140,7 @@ DEFINE_SPECIAL(Sector_ChangeSound, 140, 2, 2, 2)
DEFINE_SPECIAL(Teleport_NoStop, 154, 2, 3, 3)
// portal specials
DEFINE_SPECIAL(Line_SetPortal, 156, -1, -1, 3)
DEFINE_SPECIAL(Line_SetPortal, 156, -1, -1, 4)
// GZDoom/Vavoom specials
// Although ZDoom doesn't support them it's better to have them defined so that
// WADs using them somewhere can at least be started without aborting due

View file

@ -743,7 +743,7 @@ public:
inline bool IsNoClip2() const;
void CheckPortalTransition(bool islinked);
fixedvec3 GetPortalTransition(fixed_t byoffset);
fixedvec3 GetPortalTransition(fixed_t byoffset, sector_t **pSec = NULL);
// What species am I?
virtual FName GetSpecies();
@ -813,12 +813,6 @@ public:
return bloodcls;
}
bool intersects(AActor *other) const
{
fixed_t blockdist = radius + other->radius;
return ( abs(X() - other->X()) < blockdist && abs(Y() - other->Y()) < blockdist);
}
fixed_t AproxDistance(fixed_t otherx, fixed_t othery)
{
return P_AproxDistance(X() - otherx, Y() - othery);
@ -829,6 +823,11 @@ public:
return R_PointToAngle2(X(), Y(), otherx, othery);
}
fixed_t AngleTo(fixedvec2 other)
{
return R_PointToAngle2(X(), Y(), other.x, other.y);
}
// 'absolute' is reserved for a linked portal implementation which needs
// to distinguish between portal-aware and portal-unaware distance calculation.
fixed_t AproxDistance(AActor *other, bool absolute = false)
@ -1218,6 +1217,7 @@ public:
return __pos;
}
fixedvec3 PosRelative(int grp) const;
fixedvec3 PosRelative(const AActor *other) const;
fixedvec3 PosRelative(sector_t *sec) const;
fixedvec3 PosRelative(line_t *line) const;

View file

@ -112,30 +112,56 @@ struct fixedvec3
return *this;
}
fixedvec3 &operator -=(const fixedvec2 &other)
{
x -= other.x;
y -= other.y;
return *this;
}
fixedvec3 &operator -=(const fixedvec3 &other)
{
x -= other.x;
y -= other.y;
z -= other.z;
return *this;
}
operator fixedvec2()
{
fixedvec2 ret = { x, y };
return ret;
return { x, y };
}
};
inline fixedvec2 operator +(const fixedvec2 &v1, const fixedvec2 &v2)
{
fixedvec2 v = { v1.x + v2.x, v1.y + v2.y };
return v;
return { v1.x + v2.x, v1.y + v2.y };
}
inline fixedvec2 operator -(const fixedvec2 &v1, const fixedvec2 &v2)
{
return { v1.x - v2.x, v1.y - v2.y };
}
inline fixedvec3 operator +(const fixedvec3 &v1, const fixedvec3 &v2)
{
fixedvec3 v = { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z };
return v;
return { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z };
}
inline fixedvec3 operator +(const fixedvec3 &v1, const fixedvec2 &v2)
{
fixedvec3 v = { v1.x + v2.x, v1.y + v2.y, v1.z };
return v;
return { v1.x + v2.x, v1.y + v2.y, v1.z };
}
inline fixedvec3 operator -(const fixedvec3 &v1, const fixedvec2 &v2)
{
return{ v1.x - v2.x, v1.y - v2.y, v1.z };
}
inline fixedvec3 operator -(const fixedvec3 &v1, const fixedvec3 &v2)
{
return{ v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };
}
#define FIXED_MAX (signed)(0x7fffffff)

View file

@ -205,6 +205,7 @@ CUSTOM_CVAR (String, vid_cursor, "None", CVAR_ARCHIVE | CVAR_NOINITCALL)
}
}
bool wantToRestart;
bool DrawFSHUD; // [RH] Draw fullscreen HUD?
TArray<FString> allwads;
bool devparm; // started game with -devparm
@ -1012,6 +1013,11 @@ void D_DoomLoop ()
I_StartTic ();
D_Display ();
S_UpdateMusic(); // OpenAL needs this to keep the music running, thanks to a complete lack of a sane streaming implementation using callbacks. :(
if (wantToRestart)
{
wantToRestart = false;
return;
}
}
catch (CRecoverableError &error)
{
@ -2635,12 +2641,12 @@ void D_DoomMain (void)
setmodeneeded = false; // This may be set to true here, but isn't needed for a restart
}
try
{
D_DoomLoop (); // never returns
}
catch (CRestartException &)
{
D_DoomLoop (); // this only returns if a 'restart' CCMD is given.
//
// Clean up after a restart
//
// Music and sound should be stopped first
S_StopMusic(true);
S_StopAllChannels ();
@ -2688,7 +2694,6 @@ void D_DoomMain (void)
restart++;
PClass::bShutdown = false;
}
}
while (1);
}
@ -2721,8 +2726,7 @@ CCMD(restart)
}
}
// initiate the restart
throw CRestartException();
wantToRestart = true;
}
//==========================================================================

View file

@ -2382,9 +2382,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
{
if (trace.HitType == TRACE_HitWall)
{
DImpactDecal::StaticCreate (s,
trace.X, trace.Y, trace.Z,
trace.Line->sidedef[trace.Side], NULL);
DImpactDecal::StaticCreate (s, trace.HitPos, trace.Line->sidedef[trace.Side], NULL);
}
}
}

View file

@ -121,7 +121,7 @@ struct maplinedef2_t
// LineDef attributes.
//
enum ELineFlags
enum ELineFlags : unsigned
{
ML_BLOCKING =0x00000001, // solid, is an obstacle
ML_BLOCKMONSTERS =0x00000002, // blocks monsters only
@ -163,6 +163,8 @@ enum ELineFlags
ML_BLOCKSIGHT = 0x04000000, // blocks monster line of sight
ML_BLOCKHITSCAN = 0x08000000, // blocks hitscan attacks
ML_3DMIDTEX_IMPASS = 0x10000000, // [TP] if 3D midtex, behaves like a height-restricted ML_BLOCKING
ML_PORTALCONNECT = 0x80000000, // for internal use only: This line connects to a sector with a linked portal (used to speed up sight checks.)
};

View file

@ -64,7 +64,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer)
return 0;
// spawn a puff of smoke behind the rocket
P_SpawnPuff (self, PClass::FindActor(NAME_BulletPuff), self->X(), self->Y(), self->Z(), 0, 3);
P_SpawnPuff (self, PClass::FindActor(NAME_BulletPuff), self->Pos(), self->angle, self->angle, 3);
smoke = Spawn ("RevenantTracerSmoke", self->Vec3Offset(-self->velx, -self->vely, 0), ALLOW_REPLACE);

View file

@ -153,24 +153,32 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustImpale)
{
PARAM_ACTION_PROLOGUE;
AActor *thing;
// This doesn't need to iterate through portals.
FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), self->radius));
while ((thing = it.Next()))
FPortalGroupArray check;
FMultiBlockThingsIterator it(check, self);
FMultiBlockThingsIterator::CheckResult cres;
while (it.Next(&cres))
{
if (!thing->intersects(self))
fixed_t blockdist = self->radius + cres.thing->radius;
if (abs(self->X() - cres.position.x) >= blockdist || abs(self->Y() - cres.position.y) >= blockdist)
continue;
// Q: Make this z-aware for everything? It never was before.
if (cres.thing->Top() < self->Z() || cres.thing->Z() > self->Top())
{
if (self->Sector->PortalGroup != cres.thing->Sector->PortalGroup)
continue;
}
if (!(thing->flags & MF_SHOOTABLE) )
if (!(cres.thing->flags & MF_SHOOTABLE) )
continue;
if (thing == self)
if (cres.thing == self)
continue; // don't clip against self
int newdam = P_DamageMobj (thing, self, self, 10001, NAME_Crush);
P_TraceBleed (newdam > 0 ? newdam : 10001, thing);
int newdam = P_DamageMobj (cres.thing, self, self, 10001, NAME_Crush);
P_TraceBleed (newdam > 0 ? newdam : 10001, cres.thing);
self->args[1] = 1; // Mark thrust thing as bloody
}
return 0;

View file

@ -638,7 +638,7 @@ void DImpactDecal::CheckMax ()
}
}
DImpactDecal *DImpactDecal::StaticCreate (const char *name, fixed_t x, fixed_t y, fixed_t z, side_t *wall, F3DFloor * ffloor, PalEntry color)
DImpactDecal *DImpactDecal::StaticCreate (const char *name, const fixedvec3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color)
{
if (cl_maxdecals > 0)
{
@ -646,13 +646,13 @@ DImpactDecal *DImpactDecal::StaticCreate (const char *name, fixed_t x, fixed_t y
if (tpl != NULL && (tpl = tpl->GetDecal()) != NULL)
{
return StaticCreate (tpl, x, y, z, wall, ffloor, color);
return StaticCreate (tpl, pos, wall, ffloor, color);
}
}
return NULL;
}
DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, fixed_t x, fixed_t y, fixed_t z, side_t *wall, F3DFloor * ffloor, PalEntry color)
DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, const fixedvec3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color)
{
DImpactDecal *decal = NULL;
if (tpl != NULL && cl_maxdecals > 0 && !(wall->Flags & WALLF_NOAUTODECALS))
@ -666,16 +666,16 @@ DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, fixed_t x,
// apply the custom color as well.
if (tpl->ShadeColor != tpl_low->ShadeColor) lowercolor=0;
else lowercolor = color;
StaticCreate (tpl_low, x, y, z, wall, ffloor, lowercolor);
StaticCreate (tpl_low, pos, wall, ffloor, lowercolor);
}
DImpactDecal::CheckMax();
decal = new DImpactDecal (z);
decal = new DImpactDecal (pos.z);
if (decal == NULL)
{
return NULL;
}
if (!decal->StickToWall (wall, x, y, ffloor).isValid())
if (!decal->StickToWall (wall, pos.x, pos.y, ffloor).isValid())
{
return NULL;
}
@ -692,7 +692,7 @@ DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, fixed_t x,
}
// Spread decal to nearby walls if it does not all fit on this one
decal->Spread (tpl, wall, x, y, z, ffloor);
decal->Spread (tpl, wall, pos.x, pos.y, pos.z, ffloor);
}
return decal;
}
@ -779,22 +779,20 @@ DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t *
{
if (permanent)
{
decal = new DBaseDecal(trace.Z);
decal = new DBaseDecal(trace.HitPos.z);
wall = trace.Line->sidedef[trace.Side];
decal->StickToWall(wall, trace.X, trace.Y, trace.ffloor);
decal->StickToWall(wall, trace.HitPos.x, trace.HitPos.y, trace.ffloor);
tpl->ApplyToDecal(decal, wall);
// Spread decal to nearby walls if it does not all fit on this one
if (cl_spreaddecals)
{
decal->Spread(tpl, wall, trace.X, trace.Y, trace.Z, trace.ffloor);
decal->Spread(tpl, wall, trace.HitPos.x, trace.HitPos.y, trace.HitPos.z, trace.ffloor);
}
return decal;
}
else
{
return DImpactDecal::StaticCreate(tpl,
trace.X, trace.Y, trace.Z,
trace.Line->sidedef[trace.Side], NULL);
return DImpactDecal::StaticCreate(tpl, trace.HitPos, trace.Line->sidedef[trace.Side], NULL);
}
}
return NULL;

View file

@ -63,8 +63,8 @@ public:
DImpactDecal (fixed_t z);
DImpactDecal (side_t *wall, const FDecalTemplate *templ);
static DImpactDecal *StaticCreate (const char *name, fixed_t x, fixed_t y, fixed_t z, side_t *wall, F3DFloor * ffloor, PalEntry color=0);
static DImpactDecal *StaticCreate (const FDecalTemplate *tpl, fixed_t x, fixed_t y, fixed_t z, side_t *wall, F3DFloor * ffloor, PalEntry color=0);
static DImpactDecal *StaticCreate (const char *name, const fixedvec3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color=0);
static DImpactDecal *StaticCreate (const FDecalTemplate *tpl, const fixedvec3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color=0);
void BeginPlay ();
void Destroy ();

View file

@ -4546,7 +4546,7 @@ bool GetVarAddrType(AActor *self, FName varname, int index, void *&addr, PType *
// unwrap contained type
type = arraytype->ElementType;
// offset by index (if in bounds)
if ((unsigned)index < arraytype->ElementCount)
if ((unsigned)index >= arraytype->ElementCount)
{ // out of bounds
return false;
}

View file

@ -196,7 +196,6 @@ void DCeiling::Tick ()
{
case ceilCrushAndRaise:
case ceilLowerAndCrush:
case ceilLowerAndCrushDist:
if (m_Speed1 == FRACUNIT && m_Speed2 == FRACUNIT)
m_Speed = FRACUNIT / 8;
break;
@ -259,16 +258,8 @@ DCeiling *DCeiling::Create(sector_t *sec, DCeiling::ECeiling type, line_t *line,
case ceilCrushRaiseAndStay:
ceiling->m_TopHeight = sec->ceilingplane.d;
case ceilLowerAndCrush:
case ceilLowerAndCrushDist:
targheight = sec->FindHighestFloorPoint (&spot);
if (type == ceilLowerAndCrush)
{
targheight += 8*FRACUNIT;
}
else if (type == ceilCrushAndRaise)
{
targheight += height;
}
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;

View file

@ -656,19 +656,19 @@ FUNC(LS_Ceiling_RaiseByValueTimes8)
FUNC(LS_Ceiling_CrushAndRaise)
// Ceiling_CrushAndRaise (tag, speed, crush, crushtype)
{
return EV_DoCeiling (DCeiling::ceilCrushAndRaise, ln, arg0, SPEED(arg1), SPEED(arg1)/2, 0, arg2, 0, 0, CRUSHTYPE(arg3));
return EV_DoCeiling (DCeiling::ceilCrushAndRaise, ln, arg0, SPEED(arg1), SPEED(arg1)/2, 8*FRACUNIT, arg2, 0, 0, CRUSHTYPE(arg3));
}
FUNC(LS_Ceiling_LowerAndCrush)
// Ceiling_LowerAndCrush (tag, speed, crush, crushtype)
{
return EV_DoCeiling (DCeiling::ceilLowerAndCrush, ln, arg0, SPEED(arg1), SPEED(arg1), 0, arg2, 0, 0, CRUSHTYPE(arg3));
return EV_DoCeiling (DCeiling::ceilLowerAndCrush, ln, arg0, SPEED(arg1), SPEED(arg1), 8*FRACUNIT, arg2, 0, 0, CRUSHTYPE(arg3));
}
FUNC(LS_Ceiling_LowerAndCrushDist)
// Ceiling_LowerAndCrush (tag, speed, crush, dist, crushtype)
{
return EV_DoCeiling (DCeiling::ceilLowerAndCrushDist, ln, arg0, SPEED(arg1), SPEED(arg1), arg3*FRACUNIT, arg2, 0, 0, CRUSHTYPE(arg4));
return EV_DoCeiling (DCeiling::ceilLowerAndCrush, ln, arg0, SPEED(arg1), SPEED(arg1), arg3*FRACUNIT, arg2, 0, 0, CRUSHTYPE(arg4));
}
FUNC(LS_Ceiling_CrushStop)
@ -680,7 +680,7 @@ FUNC(LS_Ceiling_CrushStop)
FUNC(LS_Ceiling_CrushRaiseAndStay)
// Ceiling_CrushRaiseAndStay (tag, speed, crush, crushtype)
{
return EV_DoCeiling (DCeiling::ceilCrushRaiseAndStay, ln, arg0, SPEED(arg1), SPEED(arg1)/2, 0, arg2, 0, 0, CRUSHTYPE(arg3));
return EV_DoCeiling (DCeiling::ceilCrushRaiseAndStay, ln, arg0, SPEED(arg1), SPEED(arg1)/2, 8*FRACUNIT, arg2, 0, 0, CRUSHTYPE(arg3));
}
FUNC(LS_Ceiling_MoveToValueTimes8)

View file

@ -141,18 +141,18 @@ enum EPuffFlags
PF_NORANDOMZ = 16
};
AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0, AActor *vict = NULL);
inline AActor *P_SpawnPuff(AActor *source, PClassActor *pufftype, const fixedvec3 &pos, angle_t dir, int updown, int flags = 0, AActor *vict = NULL)
AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t hitdir, angle_t particledir, int updown, int flags = 0, AActor *vict = NULL);
inline AActor *P_SpawnPuff(AActor *source, PClassActor *pufftype, const fixedvec3 &pos, angle_t hitdir, angle_t particledir, int updown, int flags = 0, AActor *vict = NULL)
{
return P_SpawnPuff(source, pufftype, pos.x, pos.y, pos.z, dir, updown, flags, vict);
return P_SpawnPuff(source, pufftype, pos.x, pos.y, pos.z, hitdir, particledir, updown, flags, vict);
}
void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator);
inline void P_SpawnBlood(const fixedvec3 &pos, angle_t dir, int damage, AActor *originator)
{
P_SpawnBlood(pos.x, pos.y, pos.z, dir, damage, originator);
}
void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator);
void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator);
void P_BloodSplatter (fixedvec3 pos, AActor *originator);
void P_BloodSplatter2 (fixedvec3 pos, AActor *originator);
void P_RipperBlood (AActor *mo, AActor *bleeder);
int P_GetThingFloorType (AActor *thing);
void P_ExplodeMissile (AActor *missile, line_t *explodeline, AActor *target);
@ -275,7 +275,7 @@ void P_PlayerStartStomp (AActor *actor, bool mononly=false); // [RH] Stomp on t
void P_SlideMove (AActor* mo, fixed_t tryx, fixed_t tryy, int numsteps);
bool P_BounceWall (AActor *mo);
bool P_BounceActor (AActor *mo, AActor *BlockingMobj, bool ontop);
bool P_CheckSight (const AActor *t1, const AActor *t2, int flags=0);
bool P_CheckSight (AActor *t1, AActor *t2, int flags=0);
enum ESightFlags
{
@ -328,12 +328,20 @@ enum // P_LineAttack flags
AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, PClassActor *pufftype, int flags = 0, FTranslatedLineTarget *victim = NULL, int *actualdamage = NULL);
AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, int flags = 0, FTranslatedLineTarget *victim = NULL, int *actualdamage = NULL);
void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch);
inline void P_TraceBleed(int damage, const fixedvec3 &pos, AActor *target, angle_t angle, int pitch)
{
P_TraceBleed(damage, pos.x, pos.y, pos.z, target, angle, pitch);
}
void P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch);
void P_TraceBleed (int damage, AActor *target, AActor *missile); // missile version
void P_TraceBleed(int damage, FTranslatedLineTarget *t, AActor *puff); // hitscan version
void P_TraceBleed (int damage, AActor *target); // random direction version
bool P_HitFloor (AActor *thing);
bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true, bool force = false);
inline bool P_HitWater(AActor *thing, sector_t *sec, const fixedvec3 &pos, bool checkabove = false, bool alert = true, bool force = false)
{
return P_HitWater(thing, sec, pos.x, pos.y, pos.z, checkabove, alert, force);
}
void P_CheckSplash(AActor *self, fixed_t distance);
void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, double maxdiff = 0, int flags = 0, PClassActor *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, double sparsity = 1.0, double drift = 1.0, PClassActor *spawnclass = NULL, int SpiralOffset = 270); // [RH] Shoot a railgun
@ -351,7 +359,7 @@ bool P_CheckMissileSpawn (AActor *missile, fixed_t maxdist);
void P_PlaySpawnSound(AActor *missile, AActor *spawner);
// [RH] Position the chasecam
void P_AimCamera (AActor *t1, fixed_t &x, fixed_t &y, fixed_t &z, sector_t *&sec);
void P_AimCamera (AActor *t1, fixed_t &x, fixed_t &y, fixed_t &z, sector_t *&sec, bool &unlinked);
// [RH] Means of death
enum

View file

@ -65,8 +65,7 @@ CVAR(Bool, cl_doautoaim, false, CVAR_ARCHIVE)
static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, fixedvec2 * posforwindowcheck = NULL);
static void SpawnShootDecal(AActor *t1, const FTraceResults &trace);
static void SpawnDeepSplash(AActor *t1, const FTraceResults &trace, AActor *puff,
fixed_t vx, fixed_t vy, fixed_t vz, fixed_t shootz, bool ffloor = false);
static void SpawnDeepSplash(AActor *t1, const FTraceResults &trace, AActor *puff);
static FRandom pr_tracebleed("TraceBleed");
static FRandom pr_checkthing("CheckThing");
@ -245,7 +244,7 @@ static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator &mit, FMultiBlockLines
if (open.top < tmf.ceilingz)
{
tmf.ceilingz = open.top;
if (open.topsec != NULL) tmf.floorsector = open.topsec;
if (open.topsec != NULL) tmf.ceilingsector = open.topsec;
if (ffcf_verbose) Printf(" Adjust ceilingz to %f\n", FIXED2FLOAT(open.top));
mit.StopUp();
}
@ -1527,7 +1526,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch
!(tm.thing->flags3 & MF3_BLOODLESSIMPACT) &&
(pr_checkthing() < 192))
{
P_BloodSplatter(tm.thing->X(), tm.thing->Y(), tm.thing->Z(), thing);
P_BloodSplatter(tm.thing->Pos(), thing);
}
if (!(tm.thing->flags3 & MF3_BLOODLESSIMPACT))
{
@ -3667,7 +3666,7 @@ struct aim_t
void EnterSectorPortal(int position, fixed_t frac, sector_t *entersec, fixed_t newtoppitch, fixed_t newbottompitch)
{
AActor *portal = entersec->SkyBoxes[position];
if (portal == NULL)
if (position == sector_t::ceiling && portal->threshold < limitz) return;
else if (position == sector_t::floor && portal->threshold > limitz) return;
aim_t newtrace = Clone();
@ -3779,7 +3778,7 @@ struct aim_t
if (aimdebug)
Printf("Start AimTraverse, start = %f,%f,%f, vect = %f,%f,%f\n",
startpos.x / 65536., startpos.y / 65536., startpos.y / 65536.,
startpos.x / 65536., startpos.y / 65536., startpos.z / 65536.,
aimtrace.x / 65536., aimtrace.y / 65536.);
while ((in = it.Next()))
@ -4102,7 +4101,7 @@ fixed_t P_AimLineAttack(AActor *t1, angle_t angle, fixed_t distance, FTranslated
//==========================================================================
//
//
// Helper stuff for P_LineAttack
//
//==========================================================================
@ -4231,7 +4230,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance,
}
if (puffDefaults != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF)
{ // Spawn the puff anyway
puff = P_SpawnPuff(t1, pufftype, trace.X, trace.Y, trace.Z, angle - ANG180, 2, puffFlags);
puff = P_SpawnPuff(t1, pufftype, trace.HitPos, trace.SrcAngleToTarget, trace.SrcAngleToTarget, 2, puffFlags);
}
else
{
@ -4240,21 +4239,19 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance,
}
else
{
fixed_t hitx = 0, hity = 0, hitz = 0;
if (trace.HitType != TRACE_HitActor)
{
// position a bit closer for puffs
if (trace.HitType != TRACE_HitWall || trace.Line->special != Line_Horizon)
{
fixed_t closer = trace.Distance - 4 * FRACUNIT;
fixedvec2 pos = t1->Vec2Offset(FixedMul(vx, closer), FixedMul(vy, closer));
puff = P_SpawnPuff(t1, pufftype, pos.x, pos.y,
shootz + FixedMul(vz, closer), angle - ANG90, 0, puffFlags);
fixedvec2 pos = P_GetOffsetPosition(trace.HitPos.x, trace.HitPos.y, -trace.HitVector.x * 4, -trace.HitVector.y * 4);
puff = P_SpawnPuff(t1, pufftype, pos.x, pos.y, trace.HitPos.z - trace.HitVector.z * 4, trace.SrcAngleToTarget,
trace.SrcAngleToTarget - ANGLE_90, 0, puffFlags);
puff->radius = 1;
}
// [RH] Spawn a decal
if (trace.HitType == TRACE_HitWall && trace.Line->special != Line_Horizon && !(flags & LAF_NOIMPACTDECAL) && !(puffDefaults->flags7 & MF7_NODECAL))
if (trace.HitType == TRACE_HitWall && trace.Line->special != Line_Horizon && !trace.Line->isVisualPortal() && !(flags & LAF_NOIMPACTDECAL) && !(puffDefaults->flags7 & MF7_NODECAL))
{
// [TN] If the actor or weapon has a decal defined, use that one.
if (t1->DecalGenerator != NULL ||
@ -4283,7 +4280,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance,
trace.Sector->heightsec == NULL &&
trace.HitType == TRACE_HitFloor)
{
P_HitWater(puff, trace.Sector, trace.X, trace.Y, trace.Z);
P_HitWater(puff, trace.Sector, trace.HitPos);
}
}
else
@ -4297,14 +4294,15 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance,
(t1->player->ReadyWeapon->WeaponFlags & WIF_AXEBLOOD));
// Hit a thing, so it could be either a puff or blood
fixed_t dist = trace.Distance;
fixedvec3 bleedpos = trace.HitPos;
// position a bit closer for puffs/blood if using compatibility mode.
if (i_compatflags & COMPATF_HITSCAN) dist -= 10 * FRACUNIT;
hitx = t1->X() + FixedMul(vx, dist);
hity = t1->Y() + FixedMul(vy, dist);
hitz = shootz + FixedMul(vz, dist);
if (i_compatflags & COMPATF_HITSCAN)
{
fixedvec2 ofs = P_GetOffsetPosition(bleedpos.x, bleedpos.y, -10 * trace.HitVector.x, -10 * trace.HitVector.y);
bleedpos.x = ofs.x;
bleedpos.y = ofs.y;
bleedpos.z -= -10 * trace.HitVector.z;
}
// Spawn bullet puffs or blood spots, depending on target type.
if ((puffDefaults != NULL && puffDefaults->flags3 & MF3_PUFFONACTORS) ||
@ -4315,7 +4313,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance,
puffFlags |= PF_HITTHINGBLEED;
// We must pass the unreplaced puff type here
puff = P_SpawnPuff(t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, puffFlags | PF_HITTHING, trace.Actor);
puff = P_SpawnPuff(t1, pufftype, bleedpos, trace.SrcAngleToTarget, trace.SrcAngleToTarget - ANGLE_90, 2, puffFlags | PF_HITTHING, trace.Actor);
}
// Allow puffs to inflict poison damage, so that hitscans can poison, too.
@ -4341,11 +4339,10 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance,
{
// Since the puff is the damage inflictor we need it here
// regardless of whether it is displayed or not.
puff = P_SpawnPuff(t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, puffFlags | PF_HITTHING | PF_TEMPORARY);
puff = P_SpawnPuff(t1, pufftype, bleedpos, 0, 0, 2, puffFlags | PF_HITTHING | PF_TEMPORARY);
killPuff = true;
}
#pragma message("damage angle")
newdam = P_DamageMobj(trace.Actor, puff ? puff : t1, t1, damage, damageType, dmgflags);
newdam = P_DamageMobj(trace.Actor, puff ? puff : t1, t1, damage, damageType, dmgflags|DMG_USEANGLE, trace.SrcAngleToTarget);
if (actualdamage != NULL)
{
*actualdamage = newdam;
@ -4357,7 +4354,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance,
!(trace.Actor->flags & MF_NOBLOOD) &&
!(trace.Actor->flags2 & (MF2_INVULNERABLE | MF2_DORMANT)))
{
P_SpawnBlood(hitx, hity, hitz, angle - ANG180, newdam > 0 ? newdam : damage, trace.Actor);
P_SpawnBlood(bleedpos, trace.SrcAngleToTarget, newdam > 0 ? newdam : damage, trace.Actor);
}
if (damage)
@ -4369,35 +4366,34 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance,
{
if (axeBlood)
{
P_BloodSplatter2(hitx, hity, hitz, trace.Actor);
P_BloodSplatter2(bleedpos, trace.Actor);
}
if (pr_lineattack() < 192)
{
P_BloodSplatter(hitx, hity, hitz, trace.Actor);
P_BloodSplatter(bleedpos, trace.Actor);
}
}
}
// [RH] Stick blood to walls
P_TraceBleed(newdam > 0 ? newdam : damage, trace.X, trace.Y, trace.Z,
trace.Actor, srcangle, srcpitch);
P_TraceBleed(newdam > 0 ? newdam : damage, trace.HitPos,
trace.Actor, trace.SrcAngleToTarget, srcpitch);
}
}
if (victim != NULL)
{
victim->linetarget = trace.Actor;
victim->angleFromSource = R_PointToAngle2(t1->X(), t1->Y(), trace.Actor->X(), trace.Actor->Y());
victim->unlinked = false;
victim->angleFromSource = trace.SrcAngleToTarget;
victim->unlinked = trace.unlinked;
}
}
if (trace.Crossed3DWater || trace.CrossedWater)
{
if (puff == NULL)
{ // Spawn puff just to get a mass for the splash
puff = P_SpawnPuff(t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, puffFlags | PF_HITTHING | PF_TEMPORARY);
puff = P_SpawnPuff(t1, pufftype, trace.HitPos, 0, 0, 2, puffFlags | PF_HITTHING | PF_TEMPORARY);
killPuff = true;
}
SpawnDeepSplash(t1, trace, puff, vx, vy, vz, shootz, trace.Crossed3DWater != NULL);
SpawnDeepSplash(t1, trace, puff);
}
}
if (killPuff && puff != NULL)
@ -4553,11 +4549,8 @@ void P_TraceBleed(int damage, fixed_t x, fixed_t y, fixed_t z, AActor *actor, an
bloodcolor.a = 1;
}
DImpactDecal::StaticCreate(bloodType,
bleedtrace.X, bleedtrace.Y, bleedtrace.Z,
bleedtrace.Line->sidedef[bleedtrace.Side],
bleedtrace.ffloor,
bloodcolor);
DImpactDecal::StaticCreate(bloodType, bleedtrace.HitPos,
bleedtrace.Line->sidedef[bleedtrace.Side], bleedtrace.ffloor, bloodcolor);
}
}
}
@ -4645,7 +4638,8 @@ void P_TraceBleed(int damage, AActor *target)
struct SRailHit
{
AActor *HitActor;
fixed_t Distance;
fixedvec3 HitPos;
angle_t HitAngle;
};
struct RailData
{
@ -4679,7 +4673,15 @@ static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata)
// Save this thing for damaging later, and continue the trace
SRailHit newhit;
newhit.HitActor = res.Actor;
newhit.Distance = res.Distance - 10 * FRACUNIT; // put blood in front
newhit.HitPos = res.HitPos;
newhit.HitAngle = res.SrcAngleToTarget;
if (i_compatflags & COMPATF_HITSCAN)
{
fixedvec2 ofs = P_GetOffsetPosition(newhit.HitPos.x, newhit.HitPos.y, -10 * res.HitVector.x, -10 * res.HitVector.y);
newhit.HitPos.x = ofs.x;
newhit.HitPos.y = ofs.y;
newhit.HitPos.z -= -10 * res.HitVector.z;
}
data->RailHits.Push(newhit);
return data->StopAtOne ? TRACE_Stop : TRACE_Continue;
@ -4761,17 +4763,13 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
{
fixed_t x, y, z;
bool spawnpuff;
bool bleed = false;
int puffflags = PF_HITTHING;
AActor *hitactor = rail_data.RailHits[i].HitActor;
fixed_t hitdist = rail_data.RailHits[i].Distance;
x = xy.x + FixedMul(hitdist, vx);
y = xy.y + FixedMul(hitdist, vy);
z = shootz + FixedMul(hitdist, vz);
fixedvec3 &hitpos = rail_data.RailHits[i].HitPos;
angle_t hitangle = rail_data.RailHits[i].HitAngle;
if ((hitactor->flags & MF_NOBLOOD) ||
(hitactor->flags2 & MF2_DORMANT || ((hitactor->flags2 & MF2_INVULNERABLE) && !(puffDefaults->flags3 & MF3_FOILINVUL))))
@ -4789,7 +4787,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
}
if (spawnpuff)
{
P_SpawnPuff(source, puffclass, x, y, z, (source->angle + angleoffset) - ANG90, 1, puffflags, hitactor);
P_SpawnPuff(source, puffclass, hitpos, trace.SrcAngleToTarget, trace.SrcAngleToTarget - ANGLE_90, 1, puffflags, hitactor);
}
int dmgFlagPass = DMG_INFLICTOR_IS_PUFF;
@ -4802,13 +4800,12 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
if (puffDefaults->flags3 & MF3_FOILINVUL) dmgFlagPass |= DMG_FOILINVUL;
if (puffDefaults->flags7 & MF7_FOILBUDDHA) dmgFlagPass |= DMG_FOILBUDDHA;
}
#pragma message("damage angle")
int newdam = P_DamageMobj(hitactor, thepuff ? thepuff : source, source, damage, damagetype, dmgFlagPass);
int newdam = P_DamageMobj(hitactor, thepuff ? thepuff : source, source, damage, damagetype, dmgFlagPass|DMG_USEANGLE, hitangle);
if (bleed)
{
P_SpawnBlood(x, y, z, (source->angle + angleoffset) - ANG180, newdam > 0 ? newdam : damage, hitactor);
P_TraceBleed(newdam > 0 ? newdam : damage, x, y, z, hitactor, source->angle, pitch);
P_SpawnBlood(hitpos, hitangle, newdam > 0 ? newdam : damage, hitactor);
P_TraceBleed(newdam > 0 ? newdam : damage, hitpos, hitactor, source->angle, pitch);
}
}
@ -4819,7 +4816,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF)
{
puff = P_SpawnPuff(source, puffclass, trace.X, trace.Y, trace.Z, (source->angle + angleoffset) - ANG90, 1, 0);
puff = P_SpawnPuff(source, puffclass, trace.HitPos, trace.SrcAngleToTarget, trace.SrcAngleToTarget - ANGLE_90, 1, 0);
if (puff && (trace.Line != NULL) && (trace.Line->special == Line_Horizon) && !(puff->flags3 & MF3_SKYEXPLODE))
puff->Destroy();
}
@ -4834,7 +4831,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
AActor* puff = NULL;
if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF)
{
puff = P_SpawnPuff(source, puffclass, trace.X, trace.Y, trace.Z, (source->angle + angleoffset) - ANG90, 1, 0);
puff = P_SpawnPuff(source, puffclass, trace.HitPos, trace.SrcAngleToTarget, trace.SrcAngleToTarget - ANGLE_90, 1, 0);
if (puff && !(puff->flags3 & MF3_SKYEXPLODE) &&
(((trace.HitType == TRACE_HitFloor) && (puff->floorpic == skyflatnum)) ||
((trace.HitType == TRACE_HitCeiling) && (puff->ceilingpic == skyflatnum))))
@ -4845,23 +4842,21 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
}
if (thepuff != NULL)
{
if (trace.HitType == TRACE_HitFloor &&
trace.CrossedWater == NULL &&
trace.Sector->heightsec == NULL)
{
P_HitWater(thepuff, trace.Sector, trace.X, trace.Y, trace.Z);
}
if (trace.Crossed3DWater || trace.CrossedWater)
{
SpawnDeepSplash(source, trace, thepuff, vx, vy, vz, shootz, trace.Crossed3DWater != NULL);
SpawnDeepSplash(source, trace, thepuff);
}
else if (trace.HitType == TRACE_HitFloor && trace.Sector->heightsec == NULL)
{
P_HitWater(thepuff, trace.Sector, trace.HitPos);
}
thepuff->Destroy();
}
// Draw the slug's trail.
end.X = FIXED2DBL(trace.X);
end.Y = FIXED2DBL(trace.Y);
end.Z = FIXED2DBL(trace.Z);
end.X = FIXED2DBL(trace.HitPos.x);
end.Y = FIXED2DBL(trace.HitPos.y);
end.Z = FIXED2DBL(trace.HitPos.z);
P_DrawRailTrail(source, start, end, color1, color2, maxdiff, railflags, spawnclass, source->angle + angleoffset, duration, sparsity, drift, SpiralOffset);
}
@ -4874,7 +4869,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
CVAR(Float, chase_height, -8.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Float, chase_dist, 90.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
void P_AimCamera(AActor *t1, fixed_t &CameraX, fixed_t &CameraY, fixed_t &CameraZ, sector_t *&CameraSector)
void P_AimCamera(AActor *t1, fixed_t &CameraX, fixed_t &CameraY, fixed_t &CameraZ, sector_t *&CameraSector, bool &unlinked)
{
fixed_t distance = (fixed_t)(clamp<double>(chase_dist, 0, 30000) * FRACUNIT);
angle_t angle = (t1->angle - ANG180) >> ANGLETOFINESHIFT;
@ -4900,11 +4895,12 @@ void P_AimCamera(AActor *t1, fixed_t &CameraX, fixed_t &CameraY, fixed_t &Camera
}
else
{
CameraX = trace.X;
CameraY = trace.Y;
CameraZ = trace.Z;
CameraX = trace.HitPos.x;
CameraY = trace.HitPos.y;
CameraZ = trace.HitPos.z;
}
CameraSector = trace.Sector;
unlinked = trace.unlinked;
}
@ -5249,20 +5245,23 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo
if (bombdistance <= 0)
return;
fulldamagedistance = clamp<int>(fulldamagedistance, 0, bombdistance - 1);
fixed_t bombdistfix = bombdistance << FRACBITS;
double bombdistancefloat = 1.f / (double)(bombdistance - fulldamagedistance);
double bombdamagefloat = (double)bombdamage;
FBlockThingsIterator it(FBoundingBox(bombspot->X(), bombspot->Y(), bombdistance << FRACBITS));
AActor *thing;
FPortalGroupArray grouplist;
FMultiBlockThingsIterator it(grouplist, bombspot->X(), bombspot->Y(), bombspot->Z() - bombdistfix, bombspot->height + bombdistfix*2, bombdistfix);
FMultiBlockThingsIterator::CheckResult cres;
if (flags & RADF_SOURCEISSPOT)
{ // The source is actually the same as the spot, even if that wasn't what we received.
bombsource = bombspot;
}
while ((thing = it.Next()))
while ((it.Next(&cres)))
{
AActor *thing = cres.thing;
// Vulnerable actors can be damaged by radius attacks even if not shootable
// Used to emulate MBF's vulnerability of non-missile bouncers to explosions.
if (!((thing->flags & MF_SHOOTABLE) || (thing->flags6 & MF6_VULNERABLE)))
@ -5521,14 +5520,16 @@ void P_FindAboveIntersectors(AActor *actor)
if (!(actor->flags & MF_SOLID))
return;
AActor *thing;
FBlockThingsIterator it(FBoundingBox(actor->X(), actor->Y(), actor->radius));
while ((thing = it.Next()))
{
if (!thing->intersects(actor))
FPortalGroupArray check;
FMultiBlockThingsIterator it(check, actor);
FMultiBlockThingsIterator::CheckResult cres;
while (it.Next(&cres))
{
AActor *thing = cres.thing;
fixed_t blockdist = actor->radius + thing->radius;
if (abs(actor->X() - cres.position.x) >= blockdist || abs(actor->Y() - cres.position.y) >= blockdist)
continue;
}
if (!(thing->flags & MF_SOLID))
{ // Can't hit thing
continue;
@ -5575,14 +5576,16 @@ void P_FindBelowIntersectors(AActor *actor)
if (!(actor->flags & MF_SOLID))
return;
AActor *thing;
FBlockThingsIterator it(FBoundingBox(actor->X(), actor->Y(), actor->radius));
while ((thing = it.Next()))
{
if (!thing->intersects(actor))
FPortalGroupArray check;
FMultiBlockThingsIterator it(check, actor);
FMultiBlockThingsIterator::CheckResult cres;
while (it.Next(&cres))
{
AActor *thing = cres.thing;
fixed_t blockdist = actor->radius + thing->radius;
if (abs(actor->X() - cres.position.x) >= blockdist || abs(actor->Y() - cres.position.y) >= blockdist)
continue;
}
if (!(thing->flags & MF_SOLID))
{ // Can't hit thing
continue;
@ -5726,6 +5729,7 @@ int P_PushUp(AActor *thing, FChangePosition *cpos)
return 2;
}
}
thing->CheckPortalTransition(true);
return 0;
}
@ -5773,6 +5777,7 @@ int P_PushDown(AActor *thing, FChangePosition *cpos)
}
}
}
thing->CheckPortalTransition(true);
return 0;
}
@ -6425,7 +6430,7 @@ void SpawnShootDecal(AActor *t1, const FTraceResults &trace)
if (decalbase != NULL)
{
DImpactDecal::StaticCreate(decalbase->GetDecal(),
trace.X, trace.Y, trace.Z, trace.Line->sidedef[trace.Side], trace.ffloor);
trace.HitPos, trace.Line->sidedef[trace.Side], trace.ffloor);
}
}
@ -6435,31 +6440,20 @@ void SpawnShootDecal(AActor *t1, const FTraceResults &trace)
//
//==========================================================================
static void SpawnDeepSplash(AActor *t1, const FTraceResults &trace, AActor *puff,
fixed_t vx, fixed_t vy, fixed_t vz, fixed_t shootz, bool ffloor)
static void SpawnDeepSplash(AActor *t1, const FTraceResults &trace, AActor *puff)
{
const secplane_t *plane;
if (ffloor && trace.Crossed3DWater)
plane = trace.Crossed3DWater->top.plane;
const fixedvec3 *hitpos;
if (trace.Crossed3DWater)
{
hitpos = &trace.Crossed3DWaterPos;
}
else if (trace.CrossedWater && trace.CrossedWater->heightsec)
plane = &trace.CrossedWater->heightsec->floorplane;
{
hitpos = &trace.CrossedWaterPos;
}
else return;
fixed_t num, den, hitdist;
den = TMulScale16(plane->a, vx, plane->b, vy, plane->c, vz);
if (den != 0)
{
num = TMulScale16(plane->a, t1->X(), plane->b, t1->Y(), plane->c, shootz) + plane->d;
hitdist = FixedDiv(-num, den);
if (hitdist >= 0 && hitdist <= trace.Distance)
{
fixedvec2 hitpos = t1->Vec2Offset(FixedMul(vx, hitdist), FixedMul(vy, hitdist));
fixed_t hitz = shootz + FixedMul(vz, hitdist);
P_HitWater(puff != NULL ? puff : t1, P_PointInSector(hitpos.x, hitpos.y), hitpos.x, hitpos.y, hitz);
}
}
P_HitWater(puff != NULL ? puff : t1, P_PointInSector(hitpos->x, hitpos->y), *hitpos);
}
//=============================================================================

View file

@ -162,7 +162,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
front = linedef->frontsector;
back = linedef->backsector;
if (!(flags & FFCF_NOPORTALS))
if (!(flags & FFCF_NOPORTALS) && (linedef->flags & ML_PORTALCONNECT))
{
if (!linedef->frontsector->PortalBlocksMovement(sector_t::ceiling)) fc = FIXED_MAX;
if (!linedef->backsector->PortalBlocksMovement(sector_t::ceiling)) bc = FIXED_MAX;

View file

@ -1444,8 +1444,7 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target)
}
}
DImpactDecal::StaticCreate (base->GetDecal (),
x, y, z, line->sidedef[side], ffloor);
DImpactDecal::StaticCreate(base->GetDecal(), { x, y, z }, line->sidedef[side], ffloor);
}
}
}
@ -3286,7 +3285,7 @@ void AActor::SetRoll(angle_t r, bool interpolate)
}
fixedvec3 AActor::GetPortalTransition(fixed_t byoffset)
fixedvec3 AActor::GetPortalTransition(fixed_t byoffset, sector_t **pSec)
{
bool moved = false;
sector_t *sec = Sector;
@ -3317,6 +3316,7 @@ fixedvec3 AActor::GetPortalTransition(fixed_t byoffset)
else break;
}
}
if (pSec) *pSec = sec;
return pos;
}
@ -5021,7 +5021,29 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
// save spots for respawning in network games
FPlayerStart start(mthing, pnum+1);
playerstarts[pnum] = start;
if (level.flags2 & LEVEL2_RANDOMPLAYERSTARTS)
{ // When using random player starts, all starts count
AllPlayerStarts.Push(start);
}
else
{ // When not using random player starts, later single player
// starts should override earlier ones, since the earlier
// ones are for voodoo dolls and not likely to be ideal for
// spawning regular players.
unsigned i;
for (i = 0; i < AllPlayerStarts.Size(); ++i)
{
if (AllPlayerStarts[i].type == pnum+1)
{
AllPlayerStarts[i] = start;
break;
}
}
if (i == AllPlayerStarts.Size())
{
AllPlayerStarts.Push(start);
}
}
if (!deathmatch && !(level.flags2 & LEVEL2_RANDOMPLAYERSTARTS))
{
return P_SpawnPlayer(&start, pnum, (level.flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0);
@ -5228,7 +5250,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
// P_SpawnPuff
//
AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags, AActor *vict)
AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t hitdir, angle_t particledir, int updown, int flags, AActor *vict)
{
AActor *puff;
@ -5256,8 +5278,8 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y
if ( puff && (puff->flags5 & MF5_PUFFGETSOWNER))
puff->target = source;
if (source != NULL) puff->angle = puff->AngleTo(source);
// Angle is the opposite of the hit direction (i.e. the puff faces the source.)
puff->angle = hitdir + ANGLE_180;
// If a puff has a crash state and an actor was not hit,
// it will enter the crash state. This is used by the StrifeSpark
@ -5282,7 +5304,7 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y
{
if (cl_pufftype && updown != 3 && (puff->flags4 & MF4_ALLOWPARTICLES))
{
P_DrawSplash2 (32, x, y, z, dir, updown, 1);
P_DrawSplash2 (32, x, y, z, particledir, updown, 1);
puff->renderflags |= RF_INVISIBLE;
}
@ -5402,7 +5424,7 @@ void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AAc
//
//---------------------------------------------------------------------------
void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
void P_BloodSplatter (fixedvec3 pos, AActor *originator)
{
PalEntry bloodcolor = originator->GetBloodColor();
PClassActor *bloodcls = originator->GetBloodType(1);
@ -5416,7 +5438,7 @@ void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
{
AActor *mo;
mo = Spawn(bloodcls, x, y, z, NO_REPLACE); // GetBloodType already performed the replacement
mo = Spawn(bloodcls, pos, NO_REPLACE); // GetBloodType already performed the replacement
mo->target = originator;
mo->velx = pr_splatter.Random2 () << 10;
mo->vely = pr_splatter.Random2 () << 10;
@ -5432,7 +5454,7 @@ void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
}
if (bloodtype >= 1)
{
P_DrawSplash2 (40, x, y, z, 0u - originator->AngleTo(x, y), 2, bloodcolor);
P_DrawSplash2 (40, pos.x, pos.y, pos.z, 0u - originator->AngleTo(pos), 2, bloodcolor);
}
}
@ -5442,7 +5464,7 @@ void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
//
//===========================================================================
void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
void P_BloodSplatter2 (fixedvec3 pos, AActor *originator)
{
PalEntry bloodcolor = originator->GetBloodColor();
PClassActor *bloodcls = originator->GetBloodType(2);
@ -5456,10 +5478,10 @@ void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
{
AActor *mo;
x += ((pr_splat()-128)<<11);
y += ((pr_splat()-128)<<11);
pos.x += ((pr_splat()-128)<<11);
pos.y += ((pr_splat()-128)<<11);
mo = Spawn (bloodcls, x, y, z, NO_REPLACE); // GetBloodType already performed the replacement
mo = Spawn (bloodcls, pos, NO_REPLACE); // GetBloodType already performed the replacement
mo->target = originator;
// colorize the blood!
@ -5472,7 +5494,7 @@ void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
}
if (bloodtype >= 1)
{
P_DrawSplash2 (100, x, y, z, 0u - originator->AngleTo(x, y), 2, bloodcolor);
P_DrawSplash2 (100, pos.x, pos.y, pos.z, 0u - originator->AngleTo(pos), 2, bloodcolor);
}
}
@ -5733,7 +5755,7 @@ bool P_HitFloor (AActor *thing)
{
if (rover->top.plane->ZatPoint(pos.x, pos.y) == thing->Z())
{
return P_HitWater (thing, m->m_sector, pos.x, pos.y, pos.z);
return P_HitWater (thing, m->m_sector, pos);
}
}
}
@ -5743,7 +5765,7 @@ bool P_HitFloor (AActor *thing)
return false;
}
return P_HitWater (thing, m->m_sector, pos.x, pos.y, pos.z);
return P_HitWater (thing, m->m_sector, pos);
}
//---------------------------------------------------------------------------

View file

@ -48,43 +48,140 @@ static int sightcounts[6];
static cycle_t SightCycles;
static cycle_t MaxSightCycles;
enum
{
SO_TOPFRONT = 1,
SO_TOPBACK = 2,
SO_BOTTOMFRONT = 4,
SO_BOTTOMBACK = 8,
};
struct SightOpening
{
fixed_t top;
fixed_t bottom;
int range;
int portalflags;
void SwapSides()
{
portalflags = ((portalflags & (SO_TOPFRONT | SO_BOTTOMFRONT)) << 1) | ((portalflags & (SO_TOPBACK | SO_BOTTOMBACK)) >> 1);
}
};
struct SightTask
{
fixed_t frac;
fixed_t topslope;
fixed_t bottomslope;
int direction;
int portalgroup;
};
static TArray<intercept_t> intercepts (128);
static TArray<SightTask> portals(32);
class SightCheck
{
fixed_t sightzstart; // eye z of looker
const AActor * sightthing;
const AActor * seeingthing;
fixedvec3 sightstart;
fixedvec2 sightend;
fixed_t startfrac;
AActor * seeingthing;
fixed_t lastztop; // z at last line
fixed_t lastzbottom; // z at last line
sector_t * lastsector; // last sector being entered by trace
fixed_t topslope, bottomslope; // slopes to top and bottom of target
int Flags;
divline_t trace;
int portaldir;
int portalgroup;
bool portalfound;
unsigned int myseethrough;
void P_SightOpening(SightOpening &open, const line_t *linedef, fixed_t x, fixed_t y);
bool PTR_SightTraverse (intercept_t *in);
bool P_SightCheckLine (line_t *ld);
bool P_SightBlockLinesIterator (int x, int y);
int P_SightBlockLinesIterator (int x, int y);
bool P_SightTraverseIntercepts ();
public:
bool P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2);
bool P_SightPathTraverse ();
SightCheck(const AActor * t1, const AActor * t2, int flags)
void init(AActor * t1, AActor * t2, sector_t *startsector, SightTask *task, int flags)
{
lastztop = lastzbottom = sightzstart = t1->Z() + t1->height - (t1->height>>2);
lastsector = t1->Sector;
sightthing=t1;
sightstart = t1->PosRelative(task->portalgroup);
sightend = t2->PosRelative(task->portalgroup);
sightstart.z += t1->height - (t1->height >> 2);
startfrac = task->frac;
trace = { sightstart.x, sightstart.y, sightend.x - sightstart.x, sightend.y - sightstart.y };
lastztop = lastzbottom = sightstart.z;
lastsector = startsector;
seeingthing=t2;
bottomslope = t2->Z() - sightzstart;
topslope = bottomslope + t2->height;
topslope = task->topslope;
bottomslope = task->bottomslope;
Flags = flags;
portaldir = task->direction;
portalfound = false;
myseethrough = FF_SEETHROUGH;
}
};
//==========================================================================
//
// P_SightOpening
//
// Simplified version that removes everything not needed for a sight check
//
//==========================================================================
void SightCheck::P_SightOpening(SightOpening &open, const line_t *linedef, fixed_t x, fixed_t y)
{
open.portalflags = 0;
sector_t *front = linedef->frontsector;
sector_t *back = linedef->backsector;
if (back == NULL)
{
// single sided line
if (linedef->flags & ML_PORTALCONNECT)
{
if (!front->PortalBlocksSight(sector_t::ceiling)) open.portalflags |= SO_TOPFRONT;
if (!front->PortalBlocksSight(sector_t::floor)) open.portalflags |= SO_BOTTOMFRONT;
}
open.range = 0;
return;
}
fixed_t fc = 0, ff = 0, bc = 0, bf = 0;
if (linedef->flags & ML_PORTALCONNECT)
{
if (!front->PortalBlocksSight(sector_t::ceiling)) fc = FIXED_MAX, open.portalflags |= SO_TOPFRONT;
if (!back->PortalBlocksSight(sector_t::ceiling)) bc = FIXED_MAX, open.portalflags |= SO_TOPBACK;
if (!front->PortalBlocksSight(sector_t::floor)) ff = FIXED_MIN, open.portalflags |= SO_BOTTOMFRONT;
if (!back->PortalBlocksSight(sector_t::floor)) bf = FIXED_MIN, open.portalflags |= SO_BOTTOMBACK;
}
if (fc == 0) fc = front->ceilingplane.ZatPoint(x, y);
if (bc == 0) bc = back->ceilingplane.ZatPoint(x, y);
if (ff == 0) ff = front->floorplane.ZatPoint(x, y);
if (bf == 0) bf = back->floorplane.ZatPoint(x, y);
open.bottom = MAX(ff, bf);
open.top = MIN(fc, bc);
// we only want to know if there is an opening, not how large it is.
open.range = open.bottom >= open.top ? 0 : 1;
}
/*
==============
=
@ -93,14 +190,12 @@ public:
==============
*/
/*
static bool PTR_SightTraverse (intercept_t *in)
*/
bool SightCheck::PTR_SightTraverse (intercept_t *in)
{
line_t *li;
fixed_t slope;
FLineOpening open;
SightOpening open;
int frontflag = -1;
li = in->d.line;
@ -114,30 +209,68 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in)
fixed_t trX=trace.x + FixedMul (trace.dx, in->frac);
fixed_t trY=trace.y + FixedMul (trace.dy, in->frac);
P_LineOpening (open, NULL, li, trX, trY);
P_SightOpening (open, li, trX, trY);
if (open.range <= 0) // quick test for totally closed doors
FLinePortal *lport = li->getPortal();
if (open.range == 0 && open.portalflags == 0 && (lport == NULL || lport->mType != PORTT_LINKED)) // quick test for totally closed doors (must be delayed if portal checks are needed, though)
return false; // stop
// check bottom
slope = FixedDiv (open.bottom - sightzstart, in->frac);
if (open.bottom > FIXED_MIN)
{
slope = FixedDiv(open.bottom - sightstart.z, in->frac);
if (slope > bottomslope)
bottomslope = slope;
}
// check top
slope = FixedDiv (open.top - sightzstart, in->frac);
if (open.top < FIXED_MAX)
{
slope = FixedDiv(open.top - sightstart.z, in->frac);
if (slope < topslope)
topslope = slope;
}
if (topslope <= bottomslope)
if (open.portalflags)
{
sector_t *frontsec, *backsec;
frontflag = P_PointOnLineSidePrecise(sightstart.x, sightstart.y, li);
if (!frontflag)
{
frontsec = li->frontsector;
backsec = li->backsector;
}
else
{
frontsec = li->backsector;
if (!frontsec) return false; // We are looking through the backside of a one-sided line. Just abort if that happens.
backsec = li->frontsector;
open.SwapSides(); // swap flags to make the next checks simpler.
}
if (portaldir != sector_t::floor && (open.portalflags & SO_TOPBACK) && !(open.portalflags & SO_TOPFRONT))
{
portals.Push({ in->frac, topslope, bottomslope, sector_t::ceiling, backsec->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup });
}
if (portaldir != sector_t::ceiling && (open.portalflags & SO_BOTTOMBACK) && !(open.portalflags & SO_BOTTOMFRONT))
{
portals.Push({ in->frac, topslope, bottomslope, sector_t::floor, backsec->SkyBoxes[sector_t::floor]->Sector->PortalGroup });
}
}
if (lport)
{
portals.Push({ in->frac, topslope, bottomslope, portaldir, lport->mDestination->frontsector->PortalGroup });
return false;
}
if (topslope <= bottomslope || open.range == 0)
return false; // stop
// now handle 3D-floors
if(li->frontsector->e->XFloor.ffloors.Size() || li->backsector->e->XFloor.ffloors.Size())
{
int frontflag;
frontflag = P_PointOnLineSidePrecise(sightthing->X(), sightthing->Y(), li);
if (frontflag == -1) frontflag = P_PointOnLineSidePrecise(sightstart.x, sightstart.y, li);
//Check 3D FLOORS!
for(int i=1;i<=2;i++)
@ -145,8 +278,8 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in)
sector_t * s=i==1? li->frontsector:li->backsector;
fixed_t highslope, lowslope;
fixed_t topz= FixedMul (topslope, in->frac) + sightzstart;
fixed_t bottomz= FixedMul (bottomslope, in->frac) + sightzstart;
fixed_t topz= FixedMul (topslope, in->frac) + sightstart.z;
fixed_t bottomz= FixedMul (bottomslope, in->frac) + sightstart.z;
for(unsigned int j=0;j<s->e->XFloor.ffloors.Size();j++)
{
@ -158,8 +291,8 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in)
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(trX, trY);
fixed_t ff_top=rover->top.plane->ZatPoint(trX, trY);
highslope = FixedDiv (ff_top - sightzstart, in->frac);
lowslope = FixedDiv (ff_bottom - sightzstart, in->frac);
highslope = FixedDiv (ff_top - sightstart.z, in->frac);
lowslope = FixedDiv (ff_bottom - sightstart.z, in->frac);
if (highslope>=topslope)
{
@ -221,8 +354,8 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in)
}
else lastsector=NULL; // don't need it if there are no 3D-floors
lastztop= FixedMul (topslope, in->frac) + sightzstart;
lastzbottom= FixedMul (bottomslope, in->frac) + sightzstart;
lastztop= FixedMul (topslope, in->frac) + sightstart.z;
lastzbottom= FixedMul (bottomslope, in->frac) + sightstart.z;
return true; // keep going
}
@ -308,10 +441,11 @@ bool SightCheck::P_SightCheckLine (line_t *ld)
===================
*/
bool SightCheck::P_SightBlockLinesIterator (int x, int y)
int SightCheck::P_SightBlockLinesIterator (int x, int y)
{
int offset;
int *list;
int res = 1;
polyblock_t *polyLink;
unsigned int i;
@ -319,7 +453,12 @@ bool SightCheck::P_SightBlockLinesIterator (int x, int y)
offset = y*bmapwidth+x;
// if any of the previous blocks may contain a portal we may abort the collection of lines here, but we may not abort the sight check.
// (We still try to delay activating this for as long as possible.)
portalfound = portalfound || PortalBlockmap(x, y).containsLinkedPortals;
polyLink = PolyBlockMap[offset];
portalfound |= (polyLink && PortalBlockmap.hasLinkedPolyPortals);
while (polyLink)
{
if (polyLink->polyobj)
@ -330,7 +469,10 @@ bool SightCheck::P_SightBlockLinesIterator (int x, int y)
for (i = 0; i < polyLink->polyobj->Linedefs.Size(); i++)
{
if (!P_SightCheckLine(polyLink->polyobj->Linedefs[i]))
return false;
{
if (!portalfound) return 0;
else res = -1;
}
}
}
}
@ -342,10 +484,13 @@ bool SightCheck::P_SightBlockLinesIterator (int x, int y)
for (list = blockmaplump + offset + 1; *list != -1; list++)
{
if (!P_SightCheckLine (&lines[*list]))
return false;
{
if (!portalfound) return 0;
else res = -1;
}
}
return true; // everything was checked
return res; // everything was checked
}
/*
@ -374,12 +519,16 @@ bool SightCheck::P_SightTraverseIntercepts ()
scan = &intercepts[scanpos];
P_MakeDivline (scan->d.line, &dl);
scan->frac = P_InterceptVector (&trace, &dl);
if (scan->frac < startfrac)
{
scan->frac = FIXED_MAX;
count--;
}
}
//
// go through in order
// [RH] Is it really necessary to go through in order? All we care about is if
// the trace is obstructed, not what specifically obstructed it.
// proper order is needed to handle 3D floors and portals.
//
in = NULL;
@ -408,8 +557,8 @@ bool SightCheck::P_SightTraverseIntercepts ()
{
// we must do one last check whether the trace has crossed a 3D floor in the last sector
fixed_t topz= topslope + sightzstart;
fixed_t bottomz= bottomslope + sightzstart;
fixed_t topz= topslope + sightstart.z;
fixed_t bottomz= bottomslope + sightstart.z;
for(unsigned int i=0;i<lastsector->e->XFloor.ffloors.Size();i++)
{
@ -441,8 +590,9 @@ bool SightCheck::P_SightTraverseIntercepts ()
==================
*/
bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
bool SightCheck::P_SightPathTraverse ()
{
fixed_t x1, x2, y1, y2;
fixed_t xt1,yt1,xt2,yt2;
long long _x1,_y1,_x2,_y2;
fixed_t xstep,ystep;
@ -453,34 +603,49 @@ bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_
validcount++;
intercepts.Clear ();
x1 = sightstart.x + FixedMul(startfrac, trace.dx);
y1 = sightstart.y + FixedMul(startfrac, trace.dy);
x2 = sightend.x;
y2 = sightend.y;
if (lastsector == NULL) lastsector = P_PointInSector(x1, y1);
// for FF_SEETHROUGH the following rule applies:
// If the viewer is in an area without FF_SEETHROUGH he can only see into areas without this flag
// If the viewer is in an area with FF_SEETHROUGH he can only see into areas with this flag
bool checkfloor = true, checkceiling = true;
for(unsigned int i=0;i<lastsector->e->XFloor.ffloors.Size();i++)
{
F3DFloor* rover = lastsector->e->XFloor.ffloors[i];
if(!(rover->flags & FF_EXISTS)) continue;
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(sightthing);
fixed_t ff_top=rover->top.plane->ZatPoint(sightthing);
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(sightstart);
fixed_t ff_top=rover->top.plane->ZatPoint(sightstart);
if (sightzstart < ff_top && sightzstart >= ff_bottom)
if (sightstart.z < ff_top) checkceiling = false;
if (sightstart.z >= ff_bottom) checkfloor = false;
if (sightstart.z < ff_top && sightstart.z >= ff_bottom)
{
myseethrough = rover->flags & FF_SEETHROUGH;
break;
}
}
// We also must check if the starting sector contains portals, and start sight checks in those as well.
if (portaldir != sector_t::floor && checkceiling && !lastsector->PortalBlocksSight(sector_t::ceiling))
{
portals.Push({ 0, topslope, bottomslope, sector_t::ceiling, lastsector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup });
}
if (portaldir != sector_t::ceiling && checkfloor && !lastsector->PortalBlocksSight(sector_t::floor))
{
portals.Push({ 0, topslope, bottomslope, sector_t::floor, lastsector->SkyBoxes[sector_t::floor]->Sector->PortalGroup });
}
if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0)
x1 += FRACUNIT; // don't side exactly on a line
if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0)
y1 += FRACUNIT; // don't side exactly on a line
trace.x = x1;
trace.y = y1;
trace.dx = x2 - x1;
trace.dy = y2 - y1;
_x1 = (long long)x1 - bmaporgx;
_y1 = (long long)y1 - bmaporgy;
@ -496,12 +661,6 @@ bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_
xt2 = int(_x2 >> MAPBLOCKSHIFT);
yt2 = int(_y2 >> MAPBLOCKSHIFT);
// points should never be out of bounds, but check once instead of
// each block
if (xt1<0 || yt1<0 || xt1>=bmapwidth || yt1>=bmapheight
|| xt2<0 || yt2<0 || xt2>=bmapwidth || yt2>=bmapheight)
return false;
if (xt2 > xt1)
{
mapxstep = 1;
@ -572,13 +731,21 @@ bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_
for (count = 0 ; count < 100 ; count++)
{
if (!P_SightBlockLinesIterator (mapx, mapy))
// end traversing when reaching the end of the blockmap
// an early out is not possible because with portals a trace can easily land outside the map's bounds.
if (mapx < 0 || mapx >= bmapwidth || mapy < 0 || mapy >= bmapheight)
{
break;
}
int res = P_SightBlockLinesIterator(mapx, mapy);
if (res == 0)
{
sightcounts[1]++;
return false; // early out
}
if ((mapxstep | mapystep) == 0)
// either reached the end or had an early-out condition with portals left to check,
if (res == -1 || (mapxstep | mapystep) == 0)
break;
switch ((((yintercept >> FRACBITS) == mapy) << 1) | ((xintercept >> FRACBITS) == mapx))
@ -649,7 +816,7 @@ sightcounts[2]++;
=====================
*/
bool P_CheckSight (const AActor *t1, const AActor *t2, int flags)
bool P_CheckSight (AActor *t1, AActor *t2, int flags)
{
SightCycles.Clock();
@ -716,9 +883,34 @@ sightcounts[0]++;
// Now look from eyes of t1 to any part of t2.
validcount++;
portals.Clear();
{
SightCheck s(t1, t2, flags);
res = s.P_SightPathTraverse (t1->X(), t1->Y(), t2->X(), t2->Y());
sector_t *sec;
fixed_t lookheight = t1->height - (t1->height >> 2);
t1->GetPortalTransition(lookheight, &sec);
fixed_t bottomslope = t2->Z() - (t1->Z() + lookheight);
fixed_t topslope = bottomslope + t2->height;
SightTask task = { 0, topslope, bottomslope, -1, sec->PortalGroup };
SightCheck s;
s.init(t1, t2, sec, &task, flags);
res = s.P_SightPathTraverse ();
if (!res)
{
fixed_t dist = t1->AproxDistance(t2);
for (unsigned i = 0; i < portals.Size(); i++)
{
portals[i].frac += FixedDiv(FRACUNIT, dist);
s.init(t1, t2, NULL, &portals[i], flags);
if (s.P_SightPathTraverse())
{
res = true;
break;
}
}
}
}
done:

View file

@ -626,7 +626,7 @@ public:
ceilRaiseInstant,
ceilCrushAndRaise,
ceilLowerAndCrush,
ceilLowerAndCrushDist,
ceil_placeholder,
ceilCrushRaiseAndStay,
ceilRaiseToNearest,
ceilLowerToLowest,

View file

@ -702,6 +702,7 @@ int P_FindTerrain (FName name)
{
unsigned int i;
if (name == NAME_Null) return -1;
for (i = 0; i < Terrains.Size (); i++)
{
if (Terrains[i].Name == name)

View file

@ -41,6 +41,12 @@
#include "r_defs.h"
#include "p_spec.h"
//==========================================================================
//
//
//
//==========================================================================
struct FTraceInfo
{
fixed_t StartX, StartY, StartZ;
@ -49,6 +55,7 @@ struct FTraceInfo
DWORD WallMask;
AActor *IgnoreThis;
FTraceResults *Results;
FTraceResults *TempResults;
sector_t *CurSector;
fixed_t MaxDist;
fixed_t EnterDist;
@ -57,6 +64,8 @@ struct FTraceInfo
DWORD TraceFlags;
int inshootthrough;
fixed_t startfrac;
int aimdir;
fixed_t limitz;
// These are required for 3D-floor checking
// to create a fake sector with a floor
@ -64,15 +73,44 @@ struct FTraceInfo
sector_t DummySector[2];
int sectorsel;
void Setup3DFloors();
bool LineCheck(intercept_t *in);
bool ThingCheck(intercept_t *in);
bool TraceTraverse (int ptflags);
bool CheckPlane(const secplane_t &plane);
bool CheckSectorPlane (const sector_t *sector, bool checkFloor);
bool Check3DFloorPlane(const F3DFloor *ffloor, bool checkBottom);
int EnterLinePortal(line_t *li, fixed_t frac);
void EnterSectorPortal(int position, fixed_t frac, sector_t *entersec);
bool CheckSectorPlane(const sector_t *sector, bool checkFloor)
{
return CheckPlane(checkFloor ? sector->floorplane : sector->ceilingplane);
}
bool Check3DFloorPlane(const F3DFloor *ffloor, bool checkBottom)
{
return CheckPlane(checkBottom? *(ffloor->bottom.plane) : *(ffloor->top.plane));
}
void SetSourcePosition()
{
Results->SrcFromTarget = { StartX, StartY, StartZ };
Results->HitVector = { Vx, Vy, Vz };
Results->SrcAngleToTarget = R_PointToAngle2(0, 0, Results->HitPos.x - StartX, Results->HitPos.y - StartY);
}
};
static bool EditTraceResult (DWORD flags, FTraceResults &res);
//==========================================================================
//
// Trace entry point
//
//==========================================================================
bool 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,
@ -81,6 +119,10 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector,
{
int ptflags;
FTraceInfo inf;
FTraceResults tempResult;
memset(&tempResult, 0, sizeof(tempResult));
tempResult.Fraction = tempResult.Distance = FIXED_MAX;
ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS|PT_COMPATIBLE : PT_ADDLINES;
@ -100,25 +142,23 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector,
inf.TraceCallbackData = callbackdata;
inf.TraceFlags = flags;
inf.Results = &res;
inf.TempResults = &tempResult;
inf.inshootthrough = true;
inf.sectorsel=0;
inf.aimdir = -1;
inf.startfrac = 0;
memset(&res, 0, sizeof(res));
/* // Redundant with the memset
res.HitType = TRACE_HitNone;
res.CrossedWater = NULL;
res.Crossed3DWater = NULL;
*/
// check for overflows and clip if necessary
SQWORD xd = (SQWORD)x + ((SQWORD(vx) * SQWORD(maxDist)) >> 16);
if (xd>SQWORD(32767)*FRACUNIT)
{
maxDist = inf.MaxDist = FixedDiv(FIXED_MAX - x, vx);
inf.MaxDist = FixedDiv(FIXED_MAX - x, vx);
}
else if (xd<-SQWORD(32767)*FRACUNIT)
{
maxDist = inf.MaxDist = FixedDiv(FIXED_MIN - x, vx);
inf.MaxDist = FixedDiv(FIXED_MIN - x, vx);
}
@ -126,62 +166,139 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector,
if (yd>SQWORD(32767)*FRACUNIT)
{
maxDist = inf.MaxDist = FixedDiv(FIXED_MAX - y, vy);
inf.MaxDist = FixedDiv(FIXED_MAX - y, vy);
}
else if (yd<-SQWORD(32767)*FRACUNIT)
{
maxDist = inf.MaxDist = FixedDiv(FIXED_MIN - y, vy);
inf.MaxDist = FixedDiv(FIXED_MIN - y, vy);
}
// recalculate the trace's end points for robustness
if (inf.TraceTraverse (ptflags))
{ // check for intersection with floor/ceiling
res.Sector = &sectors[inf.CurSector->sectornum];
if (inf.CheckSectorPlane (inf.CurSector, true))
{
res.HitType = TRACE_HitFloor;
res.HitTexture = inf.CurSector->GetTexture(sector_t::floor);
if (res.CrossedWater == NULL &&
inf.CurSector->heightsec != NULL &&
inf.CurSector->heightsec->floorplane.ZatPoint (res.X, res.Y) >= res.Z)
{
res.CrossedWater = &sectors[inf.CurSector->sectornum];
}
}
else if (inf.CheckSectorPlane (inf.CurSector, false))
{
res.HitType = TRACE_HitCeiling;
res.HitTexture = inf.CurSector->GetTexture(sector_t::ceiling);
}
}
if (res.HitType != TRACE_HitNone)
{
if (flags)
{
return EditTraceResult (flags, res);
return flags ? EditTraceResult(flags, res) : true;
}
else
{
return true;
}
}
else
{
res.HitType = TRACE_HitNone;
res.X = x + FixedMul (vx, maxDist);
res.Y = y + FixedMul (vy, maxDist);
res.Z = z + FixedMul (vz, maxDist);
res.Distance = maxDist;
res.Fraction = FRACUNIT;
return false;
}
}
bool FTraceInfo::TraceTraverse (int ptflags)
//============================================================================
//
// traverses a sector portal
//
//============================================================================
void FTraceInfo::EnterSectorPortal(int position, fixed_t frac, sector_t *entersec)
{
if (aimdir != -1 && aimdir != position) return;
AActor *portal = entersec->SkyBoxes[position];
if (aimdir == sector_t::ceiling && portal->threshold < limitz) return;
else if (aimdir == sector_t::floor && portal->threshold > limitz) return;
FTraceInfo newtrace;
FTraceResults results;
memset(&results, 0, sizeof(results));
newtrace.StartX = StartX + portal->scaleX;
newtrace.StartY = StartY + portal->scaleY;
newtrace.StartZ = StartZ;
frac += FixedDiv(FRACUNIT, MaxDist);
fixed_t enterdist = FixedMul(MaxDist, frac);
fixed_t enterX = newtrace.StartX + FixedMul(enterdist, Vx);
fixed_t enterY = newtrace.StartY + FixedMul(enterdist, Vy);
newtrace.Vx = Vx;
newtrace.Vy = Vy;
newtrace.Vz = Vz;
newtrace.ActorMask = ActorMask;
newtrace.WallMask = WallMask;
newtrace.IgnoreThis = IgnoreThis;
newtrace.Results = &results;
newtrace.TempResults = TempResults;
newtrace.CurSector = P_PointInSector(enterX ,enterY);
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->threshold;
newtrace.sectorsel = 0;
if (newtrace.TraceTraverse(ActorMask ? PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE : PT_ADDLINES))
{
TempResults->CopyIfCloser(newtrace.Results);
}
}
//============================================================================
//
// traverses a line portal
// simply calling PortalRelocate does not work here because more needs to be set up
//
//============================================================================
int FTraceInfo::EnterLinePortal(line_t *li, fixed_t frac)
{
FLinePortal *port = li->getPortal();
// The caller cannot handle portals without global offset.
if (port->mType != PORTT_LINKED && (TraceFlags & TRACE_PortalRestrict)) return -1;
FTraceInfo newtrace;
newtrace.StartX = StartX;
newtrace.StartY = StartY;
newtrace.StartZ = StartZ;
newtrace.Vx = Vx;
newtrace.Vy = Vy;
newtrace.Vz = Vz;
P_TranslatePortalXY(li, newtrace.StartX, newtrace.StartY);
P_TranslatePortalZ(li, newtrace.StartZ);
P_TranslatePortalVXVY(li, newtrace.Vx, newtrace.Vy);
frac += FixedDiv(FRACUNIT, MaxDist);
fixed_t enterdist = FixedMul(MaxDist, frac);
fixed_t enterX = newtrace.StartX + FixedMul(enterdist, Vx);
fixed_t enterY = newtrace.StartY + FixedMul(enterdist, Vy);
newtrace.ActorMask = ActorMask;
newtrace.WallMask = WallMask;
newtrace.IgnoreThis = IgnoreThis;
newtrace.Results = Results;
newtrace.TempResults = TempResults;
newtrace.CurSector = P_PointInSector(enterX, enterY);
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.sectorsel = 0;
Results->unlinked = true;
return newtrace.TraceTraverse(ActorMask ? PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE : PT_ADDLINES);
}
//==========================================================================
//
// Checks 3D floors at trace start and sets up related data
//
//==========================================================================
void FTraceInfo::Setup3DFloors()
{
// Do a 3D floor check in the starting sector
TDeletingArray<F3DFloor*> &ff = CurSector->e->XFloor.ffloors;
if (ff.Size())
@ -195,6 +312,7 @@ bool FTraceInfo::TraceTraverse (int ptflags)
fixed_t y = StartY + FixedMul(Vy, sdist);
fixed_t z = StartZ + FixedMul(Vz, sdist);
fixed_t bf = CurSector->floorplane.ZatPoint(x, y);
fixed_t bc = CurSector->ceilingplane.ZatPoint(x, y);
@ -206,7 +324,10 @@ bool FTraceInfo::TraceTraverse (int ptflags)
if (rover->flags&FF_SWIMMABLE && Results->Crossed3DWater == NULL)
{
if (Check3DFloorPlane(rover, false))
{
Results->Crossed3DWater = rover;
Results->Crossed3DWaterPos = Results->HitPos;
}
}
if (!(rover->flags&FF_SHOOTTHROUGH))
@ -259,47 +380,35 @@ 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()))
if (!CurSector->PortalBlocksMovement(sector_t::ceiling))
{
fixed_t hitx, hity, hitz;
fixed_t dist;
// Deal with splashes in 3D floors
if (CurSector->e->XFloor.ffloors.Size())
EnterSectorPortal(sector_t::ceiling, startfrac, CurSector);
}
if (!CurSector->PortalBlocksMovement(sector_t::floor))
{
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;
}
EnterSectorPortal(sector_t::floor, startfrac, CurSector);
}
}
if (in->isaline)
//==========================================================================
//
// Processes one line intercept
//
//==========================================================================
bool FTraceInfo::LineCheck(intercept_t *in)
{
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 dist = FixedMul(MaxDist, in->frac);
fixed_t hitx = StartX + FixedMul(Vx, dist);
fixed_t hity = StartY + FixedMul(Vy, dist);
fixed_t 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;
@ -343,7 +452,7 @@ bool FTraceInfo::TraceTraverse (int ptflags)
{
P_ActivateLine(in->d.line, IgnoreThis, lineside, SPAC_Impact);
}
continue;
return true;
}
}
@ -363,23 +472,62 @@ bool FTraceInfo::TraceTraverse (int ptflags)
hitz <= hsec->floorplane.ZatPoint(hitx, hity))
{
// hit crossed a water plane
if (CheckSectorPlane(hsec, true))
{
Results->CrossedWater = &sectors[CurSector->sectornum];
Results->CrossedWaterPos = Results->HitPos;
}
}
if (hitz <= ff)
{ // hit floor in front of wall
{
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 (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;
}
}
else if (hitz >= fc)
{ // hit ceiling in front of wall
{
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 (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 || (hitz >= bf && hitz <= 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.
}
else if (entersector == NULL ||
hitz < bf || hitz > bc ||
in->d.line->flags & WallMask)
{ // hit the wall
{
normalline:
// hit the wall
Results->HitType = TRACE_HitWall;
Results->Tier =
entersector == NULL ? TIER_Middle :
@ -399,9 +547,8 @@ bool FTraceInfo::TraceTraverse (int ptflags)
entersector = &DummySector[sectorsel];
sectorsel ^= 1;
for(unsigned int i=0;i<entersector->e->XFloor.ffloors.Size();i++)
for (auto rover : entersector->e->XFloor.ffloors)
{
F3DFloor * rover=entersector->e->XFloor.ffloors[i];
int entershootthrough = !!(rover->flags&FF_SHOOTTHROUGH);
if (entershootthrough != inshootthrough && rover->flags&FF_EXISTS)
@ -417,6 +564,7 @@ bool FTraceInfo::TraceTraverse (int ptflags)
{
entersector->floorplane = *rover->top.plane;
entersector->SetTexture(sector_t::floor, *rover->top.texture, false);
entersector->SkyBoxes[sector_t::floor] = NULL;
bf = ff_top;
}
}
@ -427,6 +575,7 @@ bool FTraceInfo::TraceTraverse (int ptflags)
{
entersector->ceilingplane = *rover->bottom.plane;
entersector->SetTexture(sector_t::ceiling, *rover->bottom.texture, false);
entersector->SkyBoxes[sector_t::ceiling] = NULL;
bc = ff_bottom;
}
}
@ -456,6 +605,15 @@ bool FTraceInfo::TraceTraverse (int ptflags)
// 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:
@ -494,9 +652,8 @@ cont:
if (Results->HitType == TRACE_HitWall)
{
Results->X = hitx;
Results->Y = hity;
Results->Z = hitz;
Results->HitPos = { hitx, hity, hitz };
SetSourcePosition();
Results->Distance = dist;
Results->Fraction = in->frac;
Results->Line = in->d.line;
@ -504,14 +661,7 @@ cont:
}
}
if (Results->HitType == TRACE_HitNone)
{
CurSector = entersector;
EnterDist = dist;
continue;
}
if (TraceCallback != NULL)
if (TraceCallback != NULL && Results->HitType != TRACE_HitNone)
{
switch (TraceCallback(*Results, TraceCallbackData))
{
@ -521,31 +671,42 @@ cont:
default: break;
}
}
if (Results->HitType == TRACE_HitNone)
{
CurSector = entersector;
EnterDist = dist;
return true;
}
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);
//==========================================================================
//
//
//
//==========================================================================
bool FTraceInfo::ThingCheck(intercept_t *in)
{
fixed_t dist = FixedMul(MaxDist, in->frac);
fixed_t hitx = StartX + FixedMul(Vx, dist);
fixed_t hity = StartY + FixedMul(Vy, dist);
fixed_t hitz = StartZ + FixedMul(Vz, dist);
if (hitz > in->d.thing->Top())
{ // trace enters above actor
if (Vz >= 0) continue; // Going up: can't hit
{
// trace enters above actor
if (Vz >= 0) return true; // 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;
if (dist > MaxDist) return true;
in->frac = FixedDiv(dist, MaxDist);
hitx = StartX + FixedMul(Vx, dist);
@ -554,15 +715,15 @@ cont:
// 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;
abs(hity - in->d.thing->Y()) > in->d.thing->radius) return true;
}
else if (hitz < in->d.thing->Z())
{ // trace enters below actor
if (Vz <= 0) continue; // Going down: can't hit
if (Vz <= 0) return true; // 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;
if (dist > MaxDist) return true;
in->frac = FixedDiv(dist, MaxDist);
hitx = StartX + FixedMul(Vx, dist);
@ -571,28 +732,28 @@ cont:
// 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;
abs(hity - in->d.thing->Y()) > in->d.thing->radius) return true;
}
// check for extrafloors first
if (CurSector->e->XFloor.ffloors.Size())
{
// check for 3D floor hits first.
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
if (hitz > ff_ceiling && CurSector->PortalBlocksMovement(sector_t::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
else if (hitz < ff_floor && CurSector->PortalBlocksMovement(sector_t::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.
// the trace hit a 3D floor before the thing.
// Calculate an intersection and abort.
Results->Sector = &sectors[CurSector->sectornum];
if (!CheckSectorPlane(CurSector, Results->HitType == TRACE_HitFloor))
@ -616,10 +777,10 @@ cont:
}
cont1:
Results->HitType = TRACE_HitActor;
Results->X = hitx;
Results->Y = hity;
Results->Z = hitz;
Results->HitPos = { hitx, hity, hitz };
SetSourcePosition();
Results->Distance = dist;
Results->Fraction = in->frac;
Results->Actor = in->d.thing;
@ -630,8 +791,8 @@ cont1:
{
case TRACE_Stop: return false;
case TRACE_Abort: Results->HitType = TRACE_HitNone; return false;
case TRACE_Skip: Results->HitType = TRACE_HitNone; break;
default: break;
case TRACE_Skip: Results->HitType = TRACE_HitNone; return true;
default: return true;
}
}
else
@ -639,8 +800,134 @@ cont1:
return false;
}
}
//==========================================================================
//
//
//
//==========================================================================
bool FTraceInfo::TraceTraverse (int ptflags)
{
// Do a 3D floor check in the starting sector
Setup3DFloors();
FPathTraverse it(StartX, StartY, FixedMul (Vx, MaxDist), FixedMul (Vy, MaxDist), ptflags | PT_DELTA, startfrac);
intercept_t *in;
int lastsplashsector = -1;
while ((in = it.Next()))
{
// Deal with splashes in 3D floors (but only run once per sector, not each iteration - and stop if something was found.)
if (Results->Crossed3DWater == NULL && lastsplashsector != CurSector->sectornum)
{
for (auto rover : CurSector->e->XFloor.ffloors)
{
if ((rover->flags & FF_EXISTS) && (rover->flags&FF_SWIMMABLE))
{
if (Check3DFloorPlane(rover, false))
{
Results->Crossed3DWater = rover;
Results->Crossed3DWaterPos = Results->HitPos;
}
}
}
lastsplashsector = CurSector->sectornum;
}
// We have something closer in the storage for portal subtraces.
if (TempResults->HitType != TRACE_HitNone && in->frac > TempResults->Fraction)
{
break;
}
else if (in->isaline)
{
bool res = LineCheck(in);
if (aimdir == INT_MAX) return res; // signal for immediate abort
if (!res) break;
}
else if ((in->d.thing->flags & ActorMask) && in->d.thing != IgnoreThis)
{
if (!ThingCheck(in)) 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 (CurSector->PortalBlocksMovement(sector_t::floor) && CheckSectorPlane(CurSector, true))
{
Results->HitType = TRACE_HitFloor;
Results->HitTexture = CurSector->GetTexture(sector_t::floor);
}
else if (CurSector->PortalBlocksMovement(sector_t::ceiling) && CheckSectorPlane(CurSector, false))
{
Results->HitType = TRACE_HitCeiling;
Results->HitTexture = CurSector->GetTexture(sector_t::ceiling);
}
}
// check for intersection with floor/ceiling
Results->Sector = &sectors[CurSector->sectornum];
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;
}
if (Results->HitType == TRACE_HitNone && Results->Distance == 0)
{
Results->HitPos = {
StartX + FixedMul(Vx, MaxDist),
StartY + FixedMul(Vy, MaxDist),
StartZ + FixedMul(Vz, MaxDist) };
SetSourcePosition();
Results->Distance = MaxDist;
Results->Fraction = FRACUNIT;
}
return Results->HitType != TRACE_HitNone;
}
//==========================================================================
//
//
//
//==========================================================================
bool FTraceInfo::CheckPlane (const secplane_t &plane)
{
@ -656,9 +943,11 @@ bool FTraceInfo::CheckPlane (const secplane_t &plane)
if (hitdist > EnterDist && hitdist < MaxDist)
{
Results->X = StartX + FixedMul (Vx, hitdist);
Results->Y = StartY + FixedMul (Vy, hitdist);
Results->Z = StartZ + FixedMul (Vz, hitdist);
Results->HitPos = {
StartX + FixedMul(Vx, hitdist),
StartY + FixedMul(Vy, hitdist),
StartZ + FixedMul(Vz, hitdist) };
SetSourcePosition();
Results->Distance = hitdist;
Results->Fraction = FixedDiv (hitdist, MaxDist);
return true;
@ -667,37 +956,11 @@ bool FTraceInfo::CheckPlane (const secplane_t &plane)
return false;
}
bool FTraceInfo::CheckSectorPlane (const sector_t *sector, bool checkFloor)
{
secplane_t plane;
if (checkFloor)
{
plane = sector->floorplane;
}
else
{
plane = sector->ceilingplane;
}
return CheckPlane(plane);
}
bool FTraceInfo::Check3DFloorPlane (const F3DFloor *ffloor, bool checkBottom)
{
secplane_t plane;
if (checkBottom)
{
plane = *(ffloor->bottom.plane);
}
else
{
plane = *(ffloor->top.plane);
}
return CheckPlane(plane);
}
//==========================================================================
//
//
//
//==========================================================================
static bool EditTraceResult (DWORD flags, FTraceResults &res)
{

View file

@ -36,6 +36,7 @@
#include <stddef.h>
#include "actor.h"
#include "cmdlib.h"
#include "textures/textures.h"
struct sector_t;
@ -64,7 +65,8 @@ struct FTraceResults
{
sector_t *Sector;
FTextureID HitTexture;
fixed_t X, Y, Z;
fixedvec3 HitPos;
fixedvec3 HitVector;
fixedvec3 SrcFromTarget;
angle_t SrcAngleToTarget;
@ -76,12 +78,35 @@ struct FTraceResults
line_t *Line; // valid if hit a line
BYTE Side;
BYTE Tier;
bool unlinked; // passed through a portal without static offset.
ETraceResult HitType;
sector_t *CrossedWater; // For Boom-style, Transfer_Heights-based deep water
F3DFloor *Crossed3DWater; // For 3D floor-based deep water
F3DFloor *ffloor;
sector_t *CrossedWater; // For Boom-style, Transfer_Heights-based deep water
fixedvec3 CrossedWaterPos; // remember the position so that we can use it for spawning the splash
F3DFloor *Crossed3DWater; // For 3D floor-based deep water
fixedvec3 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;
}
}
};
enum
{
TRACE_NoSky = 1, // Hitting the sky returns TRACE_HitNone

View file

@ -122,15 +122,27 @@ static void BuildBlockmap()
PortalBlockmap.containsLines = true;
block.portallines.Push(ld);
block.neighborContainsLines = true;
if (ld->getPortal()->mType == PORTT_LINKED) block.containsLinkedPortals = true;
if (x > 0) PortalBlockmap(x - 1, y).neighborContainsLines = true;
if (y > 0) PortalBlockmap(x, y - 1).neighborContainsLines = true;
if (x < PortalBlockmap.dx - 1) PortalBlockmap(x + 1, y).neighborContainsLines = true;
if (y < PortalBlockmap.dy - 1) PortalBlockmap(x, y + 1).neighborContainsLines = true;
}
else
{
bool yes = ld->frontsector->PortalIsLinked(sector_t::ceiling) || ld->frontsector->PortalIsLinked(sector_t::floor);
if (ld->backsector)
{
yes |= ld->backsector->PortalIsLinked(sector_t::ceiling) || ld->backsector->PortalIsLinked(sector_t::floor);
}
block.containsLinkedPortals |= yes;
PortalBlockmap.hasLinkedSectorPortals |= yes;
}
}
}
}
if (!PortalBlockmap.containsLines) PortalBlockmap.Clear();
}
//===========================================================================
@ -1066,6 +1078,34 @@ void P_CreateLinkedPortals()
{
sectors[i].CheckPortalPlane(sector_t::floor);
sectors[i].CheckPortalPlane(sector_t::ceiling);
// set a flag on each line connecting to a plane portal sector. This is used to reduce the amount of checks in P_CheckSight.
if (sectors[i].PortalIsLinked(sector_t::floor) || sectors[i].PortalIsLinked(sector_t::ceiling))
{
for (int j = 0; j < sectors[i].linecount; j++)
{
sectors[i].lines[j]->flags |= ML_PORTALCONNECT;
}
}
if (sectors[i].PortalIsLinked(sector_t::ceiling) && sectors[i].PortalIsLinked(sector_t::floor))
{
fixed_t cz = sectors[i].SkyBoxes[sector_t::ceiling]->threshold;
fixed_t fz = sectors[i].SkyBoxes[sector_t::floor]->threshold;
if (cz < fz)
{
// This is a fatal condition. We have to remove one of the two portals. Choose the one that doesn't match the current plane
Printf("Error in sector %d: Ceiling portal at z=%d is below floor portal at z=%d\n", i, cz, fz);
fixed_t cp = sectors[i].ceilingplane.Zat0();
fixed_t fp = sectors[i].ceilingplane.Zat0();
if (cp < fp || fz == fp)
{
sectors[i].SkyBoxes[sector_t::ceiling] = NULL;
}
else
{
sectors[i].SkyBoxes[sector_t::floor] = NULL;
}
}
}
}
//BuildBlockmap();
}
@ -1078,11 +1118,6 @@ void P_CreateLinkedPortals()
//
//============================================================================
static bool ProcessLayer()
{
}
bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t upperz, fixed_t checkradius, FPortalGroupArray &out)
{
// Keep this temporary work stuff static. This function can never be called recursively

View file

@ -78,11 +78,13 @@ extern FDisplacementTable Displacements;
struct FPortalBlock
{
bool neighborContainsLines; // this is for skipping the traverser and exiting early if we can quickly decide that there's no portals nearby.
bool containsLinkedPortals; // this is for sight check optimization. We can't early-out on an impenetrable line if there may be portals being found in the same block later on.
TArray<line_t*> portallines;
FPortalBlock()
{
neighborContainsLines = false;
containsLinkedPortals = false;
}
};
@ -91,6 +93,8 @@ struct FPortalBlockmap
TArray<FPortalBlock> data;
int dx, dy;
bool containsLines;
bool hasLinkedSectorPortals; // global flag to shortcut portal checks if the map has none.
bool hasLinkedPolyPortals; // this means that any early-outs in P_CheckSight need to be disabled if a block contains polyobjects.
void Create(int blockx, int blocky)
{
@ -105,6 +109,8 @@ struct FPortalBlockmap
data.ShrinkToFit();
dx = dy = 0;
containsLines = false;
hasLinkedPolyPortals = false;
hasLinkedSectorPortals = false;
}
FPortalBlock &operator()(int x, int y)

View file

@ -101,7 +101,7 @@ WORD MirrorFlags;
TArray<PortalDrawseg> WallPortals(1000); // note: this array needs to go away as reallocation can cause crashes.
static subsector_t *InSubsector;
subsector_t *InSubsector;
CVAR (Bool, r_drawflat, false, 0) // [RH] Don't texture segs?

View file

@ -216,7 +216,6 @@ public:
//
class DSectorEffect;
struct sector_t;
struct line_t;
struct FRemapTable;
enum
@ -822,7 +821,7 @@ struct sector_t
bool PortalBlocksSight(int plane)
{
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
bool PortalBlocksMovement(int plane)
@ -837,6 +836,11 @@ struct sector_t
return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
bool PortalIsLinked(int plane)
{
return (SkyBoxes[plane] != NULL && SkyBoxes[plane]->special1 == SKYBOX_LINKEDPORTAL);
}
// These may only be called if the portal has been validated
fixedvec2 FloorDisplacement()
{
@ -1375,6 +1379,11 @@ inline sector_t *P_PointInSector(fixed_t x, fixed_t y)
return P_PointInSubsector(x, y)->sector;
}
inline fixedvec3 AActor::PosRelative(int portalgroup) const
{
return __pos + Displacements.getOffset(Sector->PortalGroup, portalgroup);
}
inline fixedvec3 AActor::PosRelative(const AActor *other) const
{
return __pos + Displacements.getOffset(Sector->PortalGroup, other->Sector->PortalGroup);

View file

@ -86,6 +86,8 @@ static void R_ShutdownRenderer();
extern short *openings;
extern bool r_fakingunderwater;
extern "C" int fuzzviewheight;
extern subsector_t *InSubsector;
extern bool r_showviewer;
// PRIVATE DATA DECLARATIONS -----------------------------------------------
@ -93,7 +95,6 @@ extern "C" int fuzzviewheight;
static float CurrentVisibility = 8.f;
static fixed_t MaxVisForWall;
static fixed_t MaxVisForFloor;
extern bool r_showviewer;
bool r_dontmaplines;
// PUBLIC DATA DEFINITIONS -------------------------------------------------
@ -772,6 +773,7 @@ void R_EnterPortal (PortalDrawseg* pds, int depth)
memcpy (ceilingclip + pds->x1, &pds->ceilingclip[0], pds->len*sizeof(*ceilingclip));
memcpy (floorclip + pds->x1, &pds->floorclip[0], pds->len*sizeof(*floorclip));
InSubsector = NULL;
R_RenderBSPNode (nodes + numnodes - 1);
R_3D_ResetClip(); // reset clips (floor/ceiling)
@ -916,6 +918,7 @@ void R_RenderActorView (AActor *actor, bool dontmaplines)
}
// Link the polyobjects right before drawing the scene to reduce the amounts of calls to this function
PO_LinkToSubsectors();
InSubsector = NULL;
R_RenderBSPNode (nodes + numnodes - 1); // The head node is the last node output.
R_3D_ResetClip(); // reset clips (floor/ceiling)
camera->renderflags = savedflags;

View file

@ -66,6 +66,8 @@
//EXTERN_CVAR (Int, tx)
//EXTERN_CVAR (Int, ty)
extern subsector_t *InSubsector;
static void R_DrawSkyStriped (visplane_t *pl);
planefunction_t floorfunc;
@ -1314,6 +1316,7 @@ void R_DrawSkyBoxes ()
viewzStack.Push (viewz);
visplaneStack.Push (pl);
InSubsector = NULL;
R_RenderBSPNode (nodes + numnodes - 1);
R_3D_ResetClip(); // reset clips (floor/ceiling)
R_DrawPlanes ();

View file

@ -927,6 +927,7 @@ void R_SetupFrame (AActor *actor)
player_t *player = actor->player;
unsigned int newblend;
InterpolationViewer *iview;
bool unlinked = false;
if (player != NULL && player->mo == actor)
{ // [RH] Use camera instead of viewplayer
@ -962,9 +963,22 @@ void R_SetupFrame (AActor *actor)
if (player != NULL && gamestate != GS_TITLELEVEL &&
((player->cheats & CF_CHASECAM) || (r_deathcamera && camera->health <= 0)))
{
sector_t *oldsector = R_PointInSubsector(iview->oviewx, iview->oviewy)->sector;
// [RH] Use chasecam view
P_AimCamera (camera, iview->nviewx, iview->nviewy, iview->nviewz, viewsector);
P_AimCamera (camera, iview->nviewx, iview->nviewy, iview->nviewz, viewsector, unlinked);
r_showviewer = true;
// Interpolating this is a very complicated thing because nothing keeps track of the aim camera's movement, so whenever we detect a portal transition
// it's probably best to just reset the interpolation for this move.
// Note that this can still cause problems with unusually linked portals
if (viewsector->PortalGroup != oldsector->PortalGroup || (unlinked && P_AproxDistance(iview->oviewx - iview->nviewx, iview->oviewy - iview->nviewy) > 256 * FRACUNIT))
{
iview->otic = nowtic;
iview->oviewx = iview->nviewx;
iview->oviewy = iview->nviewy;
iview->oviewz = iview->nviewz;
iview->oviewpitch = iview->nviewpitch;
iview->oviewangle = iview->nviewangle;
}
}
else
{

View file

@ -2913,11 +2913,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetScale)
PARAM_FIXED (scalex);
PARAM_FIXED_OPT (scaley) { scaley = scalex; }
PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; }
PARAM_BOOL_OPT (usezero) { usezero = false; }
AActor *ref = COPY_AAPTR(self, ptr);
if (ref != NULL)
{
if (scaley == 0 && !usezero)
{
scaley = scalex;
}
ref->scaleX = scalex;
ref->scaleY = scaley;
}
@ -5178,7 +5183,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack)
if ((0 && dpuff->flags3 & MF3_PUFFONACTORS) || !spawnblood)
{
spawnblood = false;
P_SpawnPuff(self, pufftype, bloodpos, angle, 0);
P_SpawnPuff(self, pufftype, bloodpos, angle, angle, 0);
}
}
else if (self->target->flags3 & MF3_GHOST)

View file

@ -232,6 +232,9 @@ int Quiet;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static const UINT32 centralfile = ZIP_CENTRALFILE;
static const UINT32 endofdir = ZIP_ENDOFDIR;
static int no_mem;
static ISzAlloc Alloc = { SzAlloc, SzFree };
@ -1305,7 +1308,8 @@ int compress_ppmd(Byte *out, unsigned int *outlen, const Byte *in, unsigned int
return -1;
}
*(short *)out = LittleShort((maxorder - 1) + ((sasize - 1) << 4) + (cutoff << 12));
const short outval = LittleShort((maxorder - 1) + ((sasize - 1) << 4) + (cutoff << 12));
memcpy(out, (const Byte *)&outval, sizeof(short));
*outlen = *outlen - ppsout.buffersize;
return 0;
}
@ -1420,12 +1424,12 @@ BYTE *find_central_dir(FILE *fin)
free(dir);
return NULL;
}
if (*(UINT32 *)dir != ZIP_CENTRALFILE)
if (memcmp(dir, (const BYTE *)&centralfile, sizeof(UINT32)) != 0)
{
free(dir);
return NULL;
}
*(UINT32 *)(dir + LittleLong(eod.DirectorySize)) = ZIP_ENDOFDIR;
memcpy(dir + LittleLong(eod.DirectorySize), (const BYTE *)&endofdir, sizeof(UINT32));
return dir;
}
@ -1444,7 +1448,7 @@ CentralDirectoryEntry *find_file_in_zip(BYTE *dir, const char *path, unsigned in
CentralDirectoryEntry *ent;
int flags;
while (*(UINT32 *)dir == ZIP_CENTRALFILE)
while (memcmp(dir, (const BYTE *)&centralfile, sizeof(UINT32)) == 0)
{
ent = (CentralDirectoryEntry *)dir;
if (pathlen == LittleShort(ent->NameLength) &&
@ -1455,7 +1459,7 @@ CentralDirectoryEntry *find_file_in_zip(BYTE *dir, const char *path, unsigned in
}
dir += sizeof(*ent) + LittleShort(ent->NameLength) + LittleShort(ent->ExtraLength) + LittleShort(ent->CommentLength);
}
if (*(UINT32 *)dir != ZIP_CENTRALFILE)
if (memcmp(dir, (const BYTE *)&centralfile, sizeof(UINT32)) != 0)
{
return NULL;
}

View file

@ -207,7 +207,7 @@ ACTOR Actor native //: Thinker
action native A_FadeIn(float reduce = 0.1, int flags = 0);
action native A_FadeOut(float reduce = 0.1, int flags = 1); //bool remove == true
action native A_FadeTo(float target, float amount = 0.1, int flags = 0);
action native A_SetScale(float scalex, float scaley = 0, int ptr = AAPTR_DEFAULT);
action native A_SetScale(float scalex, float scaley = 0, int ptr = AAPTR_DEFAULT, bool usezero = false);
action native A_SetMass(int mass);
action native A_SpawnDebris(class<Actor> spawntype, bool transfer_translation = false, float mult_h = 1, float mult_v = 1);
action native A_SpawnParticle(color color1, int flags = 0, int lifetime = 35, int size = 1, float angle = 0, float xoff = 0, float yoff = 0, float zoff = 0, float velx = 0, float vely = 0, float velz = 0, float accelx = 0, float accely = 0, float accelz = 0, float startalphaf = 1, float fadestepf = -1);