Disabled player sprites when crossing through portals.

This commit is contained in:
Major Cooke 2023-12-29 00:34:03 -06:00 committed by Rachael Alexanderson
parent cf7654bb5a
commit f647545c1d
7 changed files with 52 additions and 14 deletions

View file

@ -375,6 +375,7 @@ public:
int chickenPeck = 0; // chicken peck countdown
int jumpTics = 0; // delay the next jump for a moment
bool onground = 0; // Identifies if this player is on the ground or other object
bool crossingPortal = 0; // Crossing a portal (disables sprite from showing up)
int respawn_time = 0; // [RH] delay respawning until this tic
TObjPtr<AActor*> camera = MakeObjPtr<AActor*>(nullptr); // [RH] Whose eyes this player sees through

View file

@ -51,6 +51,7 @@ struct FCheckPosition;
struct FTranslatedLineTarget;
struct FLinePortal;
class DViewPosition;
struct FRenderViewpoint;
#include <stdlib.h>
@ -396,7 +397,7 @@ void P_PlaySpawnSound(AActor *missile, AActor *spawner);
void P_AimCamera (AActor *t1, DVector3 &, DAngle &, sector_t *&sec, bool &unlinked);
// [MC] Aiming for ViewPos
void P_AdjustViewPos(AActor *t1, DVector3 orig, DVector3 &, sector_t *&sec, bool &unlinked, DViewPosition *VP);
void P_AdjustViewPos(AActor *t1, DVector3 orig, DVector3 &, sector_t *&sec, bool &unlinked, DViewPosition *VP, FRenderViewpoint *view);
// [RH] Means of death

View file

@ -2636,6 +2636,8 @@ bool P_TryMove(AActor *thing, const DVector2 &pos,
auto p = thing->Level->GetConsolePlayer();
if (p) p->viewz += hit.pos.Z; // needs to be done here because otherwise the renderer will not catch the change.
P_TranslatePortalAngle(ld, hit.angle);
if (thing->player && (port->mType == PORTT_INTERACTIVE || port->mType == PORTT_TELEPORT))
thing->player->crossingPortal = true;
}
R_AddInterpolationPoint(hit);
}
@ -5600,24 +5602,47 @@ void P_AimCamera(AActor *t1, DVector3 &campos, DAngle &camangle, sector_t *&Came
camangle = trace.SrcAngleFromTarget - DAngle::fromDeg(180.);
}
struct ViewPosPortal
{
int counter;
};
static ETraceStatus VPos_CheckPortal(FTraceResults &res, void *userdata)
{
//[MC] Mirror how third person works.
ViewPosPortal *pc = (ViewPosPortal *)userdata;
if (res.HitType == TRACE_CrossingPortal)
{
res.HitType = TRACE_HitNone; // Needed to force the trace to continue appropriately.
pc->counter++;
return TRACE_Skip;
}
if (res.HitType == TRACE_HitActor)
{
return TRACE_Skip;
}
return TRACE_Stop;
}
// [MC] Used for ViewPos. Uses code borrowed from P_AimCamera.
void P_AdjustViewPos(AActor *t1, DVector3 orig, DVector3 &campos, sector_t *&CameraSector, bool &unlinked, DViewPosition *VP)
void P_AdjustViewPos(AActor *t1, DVector3 orig, DVector3 &campos, sector_t *&CameraSector, bool &unlinked, DViewPosition *VP, FRenderViewpoint *view)
{
FTraceResults trace;
ViewPosPortal pc;
pc.counter = 0;
const DVector3 vvec = campos - orig;
const double distance = vvec.Length();
// Trace handles all of the portal crossing, which is why there is no usage of Vec#Offset(Z).
if (Trace(orig, t1->Sector, vvec.Unit(), distance, 0, 0, t1, trace) &&
if (Trace(orig, CameraSector, vvec.Unit(), distance, 0, 0, t1, trace, TRACE_ReportPortals, VPos_CheckPortal, &pc) &&
trace.Distance > 5)
{
// Position camera slightly in front of hit thing
campos = orig + vvec.Unit() * (trace.Distance - 5);
}
else
{
campos = trace.HitPos - trace.HitVector * 1 / 256.;
}
if (pc.counter > 2) view->noviewer = true;
CameraSector = trace.Sector;
unlinked = trace.unlinked;
}

View file

@ -3771,7 +3771,8 @@ void AActor::Tick ()
}
else
{
if (player)
player->crossingPortal = false;
if (!player || !(player->cheats & CF_PREDICTING))
{
// Handle powerup effects here so that the order is controlled

View file

@ -770,13 +770,23 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
{
return;
}
// Some added checks if the camera actor is not supposed to be seen. It can happen that some portal setup has this actor in view in which case it may not be skipped here
if (viewmaster == camera && !vp.showviewer)
{
if (vp.noviewer || (viewmaster->player && viewmaster->player->crossingPortal)) return;
DVector3 vieworigin = viewmaster->Pos();
if (thruportal == 1) vieworigin += di->Level->Displacements.getOffset(viewmaster->Sector->PortalGroup, sector->PortalGroup);
if (fabs(vieworigin.X - vp.ActorPos.X) < 2 && fabs(vieworigin.Y - vp.ActorPos.Y) < 2) return;
// Necessary in order to prevent sprite pop-ins with viewpos and models.
auto* sec = viewmaster->Sector;
if (sec && !sec->PortalBlocksMovement(sector_t::ceiling))
{
double zh = sec->GetPortalPlaneZ(sector_t::ceiling);
double top = (viewmaster->player ? max<double>(viewmaster->player->viewz, viewmaster->Top()) + 1 : viewmaster->Top());
if (viewmaster->Z() < zh && top >= zh)
return;
}
}
// Thing is invisible if close to the camera.
if (viewmaster->renderflags & RF_MAYBEINVISIBLE)
@ -858,7 +868,6 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
{
return;
}
if (!modelframe)
{
bool mirror = false;

View file

@ -600,6 +600,7 @@ void R_InterpolateView (FRenderViewpoint &viewpoint, player_t *player, double Fr
else break;
}
}
if (moved) viewpoint.noviewer = true;
}
//==========================================================================
@ -947,7 +948,7 @@ void R_SetupFrame (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, AActor
// Interpolation still happens with everything else though and seems to work fine.
DefaultDraw = false;
viewpoint.NoPortalPath = true;
P_AdjustViewPos(mo, orig, next, viewpoint.sector, unlinked, VP);
P_AdjustViewPos(mo, orig, next, viewpoint.sector, unlinked, VP, &viewpoint);
if (viewpoint.sector->PortalGroup != oldsector->PortalGroup || (unlinked && ((iview->New.Pos.XY() - iview->Old.Pos.XY()).LengthSquared()) > 256 * 256))
{

View file

@ -44,7 +44,7 @@ struct FRenderViewpoint
int extralight; // extralight to be added to this viewpoint
bool showviewer; // show the camera actor?
bool NoPortalPath; // Disable portal interpolation path for actor viewpos.
bool noviewer; // Force camera sprite off for first person.
void SetViewAngle(const FViewWindow &viewwindow);
};