mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-25 13:41:05 +00:00
Merge branch 'master' of https://github.com/rheit/zdoom
This commit is contained in:
commit
c2e7123a36
32 changed files with 1365 additions and 754 deletions
|
@ -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
|
||||
|
|
14
src/actor.h
14
src/actor.h
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
108
src/d_main.cpp
108
src/d_main.cpp
|
@ -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,59 +2641,58 @@ void D_DoomMain (void)
|
|||
setmodeneeded = false; // This may be set to true here, but isn't needed for a restart
|
||||
}
|
||||
|
||||
try
|
||||
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 ();
|
||||
|
||||
M_ClearMenus(); // close menu if open
|
||||
F_EndFinale(); // If an intermission is active, end it now
|
||||
|
||||
// clean up game state
|
||||
ST_Clear();
|
||||
D_ErrorCleanup ();
|
||||
P_FreeLevelData();
|
||||
P_FreeExtraLevelData();
|
||||
|
||||
M_SaveDefaults(NULL); // save config before the restart
|
||||
|
||||
// delete all data that cannot be left until reinitialization
|
||||
V_ClearFonts(); // must clear global font pointers
|
||||
R_DeinitTranslationTables(); // some tables are initialized from outside the translation code.
|
||||
gameinfo.~gameinfo_t();
|
||||
new (&gameinfo) gameinfo_t; // Reset gameinfo
|
||||
S_Shutdown(); // free all channels and delete playlist
|
||||
C_ClearAliases(); // CCMDs won't be reinitialized so these need to be deleted here
|
||||
DestroyCVarsFlagged(CVAR_MOD); // Delete any cvar left by mods
|
||||
|
||||
GC::FullGC(); // clean up before taking down the object list.
|
||||
|
||||
// Delete the VM functions here. The garbage collector will not do this automatically because they are referenced from the global action function definitions.
|
||||
FAutoSegIterator probe(ARegHead, ARegTail);
|
||||
while (*++probe != NULL)
|
||||
{
|
||||
D_DoomLoop (); // never returns
|
||||
AFuncDesc *afunc = (AFuncDesc *)*probe;
|
||||
*(afunc->VMPointer) = NULL;
|
||||
}
|
||||
catch (CRestartException &)
|
||||
|
||||
ReleaseGlobalSymbols();
|
||||
PClass::StaticShutdown();
|
||||
|
||||
GC::FullGC(); // perform one final garbage collection after shutdown
|
||||
|
||||
for (DObject *obj = GC::Root; obj; obj = obj->ObjNext)
|
||||
{
|
||||
// Music and sound should be stopped first
|
||||
S_StopMusic(true);
|
||||
S_StopAllChannels ();
|
||||
|
||||
M_ClearMenus(); // close menu if open
|
||||
F_EndFinale(); // If an intermission is active, end it now
|
||||
|
||||
// clean up game state
|
||||
ST_Clear();
|
||||
D_ErrorCleanup ();
|
||||
P_FreeLevelData();
|
||||
P_FreeExtraLevelData();
|
||||
|
||||
M_SaveDefaults(NULL); // save config before the restart
|
||||
|
||||
// delete all data that cannot be left until reinitialization
|
||||
V_ClearFonts(); // must clear global font pointers
|
||||
R_DeinitTranslationTables(); // some tables are initialized from outside the translation code.
|
||||
gameinfo.~gameinfo_t();
|
||||
new (&gameinfo) gameinfo_t; // Reset gameinfo
|
||||
S_Shutdown(); // free all channels and delete playlist
|
||||
C_ClearAliases(); // CCMDs won't be reinitialized so these need to be deleted here
|
||||
DestroyCVarsFlagged(CVAR_MOD); // Delete any cvar left by mods
|
||||
|
||||
GC::FullGC(); // clean up before taking down the object list.
|
||||
|
||||
// Delete the VM functions here. The garbage collector will not do this automatically because they are referenced from the global action function definitions.
|
||||
FAutoSegIterator probe(ARegHead, ARegTail);
|
||||
while (*++probe != NULL)
|
||||
{
|
||||
AFuncDesc *afunc = (AFuncDesc *)*probe;
|
||||
*(afunc->VMPointer) = NULL;
|
||||
}
|
||||
|
||||
ReleaseGlobalSymbols();
|
||||
PClass::StaticShutdown();
|
||||
|
||||
GC::FullGC(); // perform one final garbage collection after shutdown
|
||||
|
||||
for (DObject *obj = GC::Root; obj; obj = obj->ObjNext)
|
||||
{
|
||||
obj->ClearClass(); // Delete the Class pointer because the data it points to has been deleted. This will automatically be reset if needed.
|
||||
}
|
||||
|
||||
restart++;
|
||||
PClass::bShutdown = false;
|
||||
obj->ClearClass(); // Delete the Class pointer because the data it points to has been deleted. This will automatically be reset if needed.
|
||||
}
|
||||
|
||||
restart++;
|
||||
PClass::bShutdown = false;
|
||||
}
|
||||
while (1);
|
||||
}
|
||||
|
@ -2715,14 +2720,13 @@ CCMD(restart)
|
|||
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
for(int i=1;i<argv.argc(); i++)
|
||||
for (int i = 1; i<argv.argc(); i++)
|
||||
{
|
||||
Args->AppendArg(argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// initiate the restart
|
||||
throw CRestartException();
|
||||
wantToRestart = true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.)
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
targheight += height;
|
||||
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
|
||||
ceiling->m_Direction = -1;
|
||||
break;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
210
src/p_map.cpp
210
src/p_map.cpp
|
@ -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()))
|
||||
FPortalGroupArray check;
|
||||
FMultiBlockThingsIterator it(check, actor);
|
||||
FMultiBlockThingsIterator::CheckResult cres;
|
||||
while (it.Next(&cres))
|
||||
{
|
||||
if (!thing->intersects(actor))
|
||||
{
|
||||
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()))
|
||||
FPortalGroupArray check;
|
||||
FMultiBlockThingsIterator it(check, actor);
|
||||
FMultiBlockThingsIterator::CheckResult cres;
|
||||
while (it.Next(&cres))
|
||||
{
|
||||
if (!thing->intersects(actor))
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
AllPlayerStarts.Push(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);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
316
src/p_sight.cpp
316
src/p_sight.cpp
|
@ -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 (slope > bottomslope)
|
||||
bottomslope = slope;
|
||||
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 (slope < topslope)
|
||||
topslope = slope;
|
||||
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)
|
||||
|
@ -329,8 +468,11 @@ bool SightCheck::P_SightBlockLinesIterator (int x, int y)
|
|||
polyLink->polyobj->validcount = validcount;
|
||||
for (i = 0; i < polyLink->polyobj->Linedefs.Size(); i++)
|
||||
{
|
||||
if (!P_SightCheckLine (polyLink->polyobj->Linedefs[i]))
|
||||
return false;
|
||||
if (!P_SightCheckLine(polyLink->polyobj->Linedefs[i]))
|
||||
{
|
||||
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)
|
||||
{
|
||||
sightcounts[1]++;
|
||||
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:
|
||||
|
|
|
@ -626,7 +626,7 @@ public:
|
|||
ceilRaiseInstant,
|
||||
ceilCrushAndRaise,
|
||||
ceilLowerAndCrush,
|
||||
ceilLowerAndCrushDist,
|
||||
ceil_placeholder,
|
||||
ceilCrushRaiseAndStay,
|
||||
ceilRaiseToNearest,
|
||||
ceilLowerToLowest,
|
||||
|
|
|
@ -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)
|
||||
|
|
1109
src/p_trace.cpp
1109
src/p_trace.cpp
File diff suppressed because it is too large
Load diff
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include <stddef.h>
|
||||
#include "actor.h"
|
||||
#include "cmdlib.h"
|
||||
#include "textures/textures.h"
|
||||
|
||||
struct sector_t;
|
||||
|
@ -64,23 +65,47 @@ struct FTraceResults
|
|||
{
|
||||
sector_t *Sector;
|
||||
FTextureID HitTexture;
|
||||
fixed_t X, Y, Z;
|
||||
fixedvec3 HitPos;
|
||||
fixedvec3 HitVector;
|
||||
fixedvec3 SrcFromTarget;
|
||||
angle_t SrcAngleToTarget;
|
||||
|
||||
fixed_t Distance;
|
||||
fixed_t Fraction;
|
||||
|
||||
|
||||
AActor *Actor; // valid if hit an actor
|
||||
|
||||
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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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?
|
||||
|
||||
|
|
13
src/r_defs.h
13
src/r_defs.h
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 *)¢ralfile, 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 *)¢ralfile, 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 *)¢ralfile, sizeof(UINT32)) != 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue