diff --git a/libraries/discordrpc/src/CMakeLists.txt b/libraries/discordrpc/src/CMakeLists.txt index 18c3009e2..34aca1e4b 100644 --- a/libraries/discordrpc/src/CMakeLists.txt +++ b/libraries/discordrpc/src/CMakeLists.txt @@ -118,10 +118,6 @@ if (${BUILD_SHARED_LIBS}) target_compile_definitions(discord-rpc PRIVATE -DDISCORD_BUILDING_SDK) endif(${BUILD_SHARED_LIBS}) -if (CLANG_FORMAT_CMD) - add_dependencies(discord-rpc clangformat) -endif(CLANG_FORMAT_CMD) - # install install( diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2f1eb068e..15aea2823 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -49,6 +49,8 @@ if( NOT PROJECT_LIBRARIES ) set( PROJECT_LIBRARIES "" ) endif() +add_definitions( -DTHIS_IS_GZDOOM ) + if( WIN32 ) add_definitions( -D_WIN32 ) diff --git a/src/common/engine/namedef.h b/src/common/engine/namedef.h index 86543ca37..8fc201385 100644 --- a/src/common/engine/namedef.h +++ b/src/common/engine/namedef.h @@ -79,6 +79,7 @@ xx(__decorate_internal_float__) // Per-actor sound channels (for deprecated PlaySoundEx function) Do not separate this block!!! xx(Auto) xx(Weapon) +xx(BobPivot3D) xx(Voice) xx(Item) xx(Body) diff --git a/src/common/scripting/backend/codegen.h b/src/common/scripting/backend/codegen.h index e26cea84d..f7ea48177 100644 --- a/src/common/scripting/backend/codegen.h +++ b/src/common/scripting/backend/codegen.h @@ -567,6 +567,7 @@ class FxVectorValue : public FxExpression public: friend class ZCCCompiler; + friend class ZCCDoomCompiler; FxVectorValue(FxExpression *x, FxExpression *y, FxExpression *z, FxExpression* w, const FScriptPosition &sc); ~FxVectorValue(); diff --git a/src/common/scripting/vm/vm.h b/src/common/scripting/vm/vm.h index ef089eba5..8a19d5f77 100644 --- a/src/common/scripting/vm/vm.h +++ b/src/common/scripting/vm/vm.h @@ -215,6 +215,11 @@ struct VMReturn Location = loc; RegType = REGT_FLOAT | REGT_MULTIREG2; } + void Vec3At(DVector3 *loc) + { + Location = loc; + RegType = REGT_FLOAT | REGT_MULTIREG3; + } void StringAt(FString *loc) { Location = loc; @@ -229,6 +234,7 @@ struct VMReturn VMReturn(int *loc) { IntAt(loc); } VMReturn(double *loc) { FloatAt(loc); } VMReturn(DVector2 *loc) { Vec2At(loc); } + VMReturn(DVector3 *loc) { Vec3At(loc); } VMReturn(FString *loc) { StringAt(loc); } VMReturn(void **loc) { PointerAt(loc); } }; diff --git a/src/d_main.cpp b/src/d_main.cpp index 12b3fb9ff..d9177fbb4 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -899,11 +899,8 @@ void D_Display () DAngle fov = DAngle::fromDeg(90.); AActor *cam = players[consoleplayer].camera; if (cam) - { - if (cam->player) - fov = DAngle::fromDeg(cam->player->FOV); - else fov = DAngle::fromDeg(cam->CameraFOV); - } + fov = DAngle::fromDeg(cam->GetFOV(I_GetTimeFrac())); + R_SetFOV(vp, fov); } diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 6c31fbe73..e2876da9a 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -63,6 +63,7 @@ CVAR (Int, team, TEAM_NONE, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (String, gender, "male", CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Bool, neverswitchonpickup, false, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Float, movebob, 0.25f, CVAR_USERINFO | CVAR_ARCHIVE); +CVAR (Bool, fviewbob, true, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Float, stillbob, 0.f, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Float, wbobspeed, 1.f, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Float, wbobfire, 0.f, CVAR_USERINFO | CVAR_ARCHIVE); @@ -80,6 +81,7 @@ enum INFO_Gender, INFO_NeverSwitchOnPickup, INFO_MoveBob, + INFO_FViewBob, INFO_StillBob, INFO_WBobSpeed, INFO_WBobFire, diff --git a/src/g_level.cpp b/src/g_level.cpp index 8aa011506..ff348a879 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1702,6 +1702,7 @@ int FLevelLocals::FinishTravel () } pawn->LinkToWorld (nullptr); pawn->ClearInterpolation(); + pawn->ClearFOVInterpolation(); const int tid = pawn->tid; // Save TID (actor isn't linked into the hash chain yet) pawn->tid = 0; // Reset TID pawn->SetTID(tid); // Set TID (and link actor into the hash chain) diff --git a/src/namedef_custom.h b/src/namedef_custom.h index e55d5cb07..e6f6c6e9d 100644 --- a/src/namedef_custom.h +++ b/src/namedef_custom.h @@ -450,6 +450,7 @@ xx(Playermenu) xx(ColorSet) xx(NeverSwitchOnPickup) xx(MoveBob) +xx(FViewBob) xx(StillBob) xx(ClassicFlight) xx(WBobSpeed) diff --git a/src/p_tick.cpp b/src/p_tick.cpp index 57cc986af..59d66a285 100644 --- a/src/p_tick.cpp +++ b/src/p_tick.cpp @@ -158,6 +158,7 @@ void P_Ticker (void) while ((ac = it.Next())) { ac->ClearInterpolation(); + ac->ClearFOVInterpolation(); } P_ThinkParticles(Level); // [RH] make the particles think diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 271ac78af..b1c848e40 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -929,6 +929,8 @@ public: void SetViewAngle(DAngle ang, int fflags); void SetViewRoll(DAngle roll, int fflags); + double GetFOV(double ticFrac); + PClassActor *GetBloodType(int type = 0) const; double Distance2DSquared(AActor *other, bool absolute = false) @@ -998,6 +1000,7 @@ public: DVector3 Vec3Angle(double length, DAngle angle, double dz, bool absolute = false); void ClearInterpolation(); + void ClearFOVInterpolation(); void Move(const DVector3 &vel) { @@ -1278,6 +1281,7 @@ public: // [RH] Used to interpolate the view to get >35 FPS DVector3 Prev; DRotator PrevAngles; + DAngle PrevFOV; int PrevPortalGroup; TArray AttachedLights; TDeletingArray UserLights; diff --git a/src/playsim/actorinlines.h b/src/playsim/actorinlines.h index 56a2e6ab8..939807c98 100644 --- a/src/playsim/actorinlines.h +++ b/src/playsim/actorinlines.h @@ -34,6 +34,14 @@ inline void AActor::ClearInterpolation() else PrevPortalGroup = 0; } +inline void AActor::ClearFOVInterpolation() +{ + if (player) + PrevFOV = DAngle::fromDeg(player->FOV); + else + PrevFOV = DAngle::fromDeg(CameraFOV); +} + inline double secplane_t::ZatPoint(const AActor *ac) const { return (D + normal.X*ac->X() + normal.Y*ac->Y()) * negiC; diff --git a/src/playsim/d_player.h b/src/playsim/d_player.h index 549748070..27fd860dd 100644 --- a/src/playsim/d_player.h +++ b/src/playsim/d_player.h @@ -124,6 +124,7 @@ typedef enum CF_INTERPVIEW = 1 << 14, // [RH] view was changed outside of input, so interpolate one frame CF_INTERPVIEWANGLES = 1 << 15, // [MR] flag for interpolating view angles without interpolating the entire frame CF_SCALEDNOLERP = 1 << 15, // [MR] flag for applying angles changes in the ticrate without interpolating the frame + CF_NOFOVINTERP = 1 << 16, // [B] Disable FOV interpolation when instantly zooming CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths. CF_BUDDHA2 = 1 << 24, // [MC] Absolute buddha. No voodoo can kill it either. CF_GODMODE2 = 1 << 25, // [MC] Absolute godmode. No voodoo can kill it either. @@ -226,6 +227,10 @@ struct userinfo_t : TMap { return *static_cast(*CheckKey(NAME_MoveBob)); } + double GetFViewBob() const + { + return *static_cast(*CheckKey(NAME_FViewBob)); + } double GetStillBob() const { return *static_cast(*CheckKey(NAME_StillBob)); diff --git a/src/playsim/p_acs.cpp b/src/playsim/p_acs.cpp index 01def4758..374a1611d 100644 --- a/src/playsim/p_acs.cpp +++ b/src/playsim/p_acs.cpp @@ -535,6 +535,7 @@ PLAYERINFO_PLAYERCLASS, PLAYERINFO_FOV, PLAYERINFO_DESIREDFOV, + PLAYERINFO_FVIEWBOB, }; @@ -9958,6 +9959,7 @@ scriptwait: case PLAYERINFO_PLAYERCLASS: STACK(2) = userinfo->GetPlayerClassNum(); break; case PLAYERINFO_DESIREDFOV: STACK(2) = (int)pl->DesiredFOV; break; case PLAYERINFO_FOV: STACK(2) = (int)pl->FOV; break; + case PLAYERINFO_FVIEWBOB: STACK(2) = DoubleToACS(userinfo->GetFViewBob()); break; default: STACK(2) = 0; break; } } diff --git a/src/playsim/p_maputl.cpp b/src/playsim/p_maputl.cpp index aca40e741..9c5bd14b1 100644 --- a/src/playsim/p_maputl.cpp +++ b/src/playsim/p_maputl.cpp @@ -2092,3 +2092,42 @@ int BoxOnLineSide(const FBoundingBox &box, const line_t* ld) return (p1 == p2) ? p1 : -1; } +DEFINE_ACTION_FUNCTION(FLevelLocals, PointOnLineSide) +{ + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_POINTER(l, line_t); + PARAM_BOOL(precise); + + int res; + if (precise) // allow forceful overriding of compat flag + res = P_PointOnLineSidePrecise(x, y, l); + else + res = P_PointOnLineSide(x, y, l); + + ACTION_RETURN_INT(res); +} + +DEFINE_ACTION_FUNCTION(FLevelLocals, ActorOnLineSide) +{ + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + PARAM_OBJECT(mo, AActor); + PARAM_POINTER(l, line_t); + + FBoundingBox box(mo->X(), mo->Y(), mo->radius); + ACTION_RETURN_INT(BoxOnLineSide(box, l)); +} + +DEFINE_ACTION_FUNCTION(FLevelLocals, BoxOnLineSide) +{ + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(radius); + PARAM_POINTER(l, line_t); + + FBoundingBox box(x, y, radius); + ACTION_RETURN_INT(BoxOnLineSide(box, l)); +} + diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index bcc825e0d..9f5756394 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -407,6 +407,7 @@ void AActor::PostSerialize() } } ClearInterpolation(); + ClearFOVInterpolation(); UpdateWaterLevel(false); } @@ -2410,7 +2411,10 @@ static void P_ZMovement (AActor *mo, double oldfloorz) } if (mo->player && (mo->flags & MF_NOGRAVITY) && (mo->Z() > mo->floorz)) { - if (!mo->IsNoClip2()) + FBaseCVar* const fViewBobCvar = G_GetUserCVar(int(mo->player - players),"FViewBob"); + bool const fViewBob = fViewBobCvar->GetGenericRep(fViewBobCvar->GetRealType()).Bool; + + if (!mo->IsNoClip2() && fViewBob) { mo->AddZ(DAngle::fromDeg(360 / 80.f * mo->Level->maptime).Sin() / 8); } @@ -3549,6 +3553,28 @@ void AActor::SetViewAngle(DAngle ang, int fflags) } +double AActor::GetFOV(double ticFrac) +{ + // [B] Disable interpolation when playing online, otherwise it gets vomit inducing + if (netgame) + return player ? player->FOV : CameraFOV; + + double fov; + if (player) + { + if (player->cheats & CF_NOFOVINTERP) + return player->FOV; + + fov = player->FOV; + } + else + { + fov = CameraFOV; + } + + return PrevFOV.Degrees() * (1 - ticFrac) + fov * ticFrac; +} + void AActor::SetViewRoll(DAngle r, int fflags) { if (r != ViewAngles.Roll) @@ -4563,6 +4589,7 @@ void ConstructActor(AActor *actor, const DVector3 &pos, bool SpawningMapThing) // set subsector and/or block links actor->LinkToWorld (nullptr, SpawningMapThing); actor->ClearInterpolation(); + actor->ClearFOVInterpolation(); actor->dropoffz = actor->floorz = actor->Sector->floorplane.ZatPoint(pos); actor->ceilingz = actor->Sector->ceilingplane.ZatPoint(pos); diff --git a/src/playsim/p_pspr.cpp b/src/playsim/p_pspr.cpp index 38560fba2..b32ce67e6 100644 --- a/src/playsim/p_pspr.cpp +++ b/src/playsim/p_pspr.cpp @@ -641,6 +641,26 @@ void P_BobWeapon (player_t *player, float *x, float *y, double ticfrac) *x = *y = 0; } +void P_BobWeapon3D (player_t *player, FVector3 *translation, FVector3 *rotation, double ticfrac) { + IFVIRTUALPTRNAME(player->mo, NAME_PlayerPawn, BobWeapon3D) + { + VMValue param[] = { player->mo, ticfrac }; + DVector3 t, r; + VMReturn returns[2]; + returns[0].Vec3At(&t); + returns[1].Vec3At(&r); + VMCall(func, param, 2, returns, 2); + translation->X = (float)t.X; + translation->Y = (float)t.Y; + translation->Z = (float)t.Z; + rotation->X = (float)r.X; + rotation->Y = (float)r.Y; + rotation->Z = (float)r.Z; + return; + } + *translation = *rotation = {}; +} + //--------------------------------------------------------------------------- // // PROC P_CheckWeaponButtons diff --git a/src/playsim/p_pspr.h b/src/playsim/p_pspr.h index a992e90d8..85add7b6b 100644 --- a/src/playsim/p_pspr.h +++ b/src/playsim/p_pspr.h @@ -156,6 +156,7 @@ void P_SetPsprite(player_t *player, PSPLayers id, FState *state, bool pending = void P_BringUpWeapon (player_t *player); void P_FireWeapon (player_t *player); void P_BobWeapon (player_t *player, float *x, float *y, double ticfrac); +void P_BobWeapon3D (player_t *player, FVector3 *translation, FVector3 *rotation, double ticfrac); DAngle P_BulletSlope (AActor *mo, FTranslatedLineTarget *pLineTarget = NULL, int aimflags = 0); AActor *P_AimTarget(AActor *mo); diff --git a/src/playsim/p_user.cpp b/src/playsim/p_user.cpp index 0fa33a90e..0084bf16f 100644 --- a/src/playsim/p_user.cpp +++ b/src/playsim/p_user.cpp @@ -796,6 +796,12 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, GetMoveBob) ACTION_RETURN_FLOAT(self->userinfo.GetMoveBob()); } +DEFINE_ACTION_FUNCTION(_PlayerInfo, GetFViewBob) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + ACTION_RETURN_BOOL(self->userinfo.GetFViewBob()); +} + DEFINE_ACTION_FUNCTION(_PlayerInfo, GetStillBob) { PARAM_SELF_STRUCT_PROLOGUE(player_t); @@ -1260,6 +1266,7 @@ void P_PlayerThink (player_t *player) player->cheats &= ~CF_INTERPVIEW; player->cheats &= ~CF_INTERPVIEWANGLES; player->cheats &= ~CF_SCALEDNOLERP; + player->cheats &= ~CF_NOFOVINTERP; player->mo->FloatVar("prevBob") = player->bob; IFVIRTUALPTRNAME(player->mo, NAME_PlayerPawn, PlayerThink) diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp index b58dfaa47..fd7d0c06c 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -193,10 +193,9 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod renderer->EndDrawModel(actor->RenderStyle, smf); } -void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, float ofsX, float ofsY) +void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, FVector3 translation, FVector3 rotation, FVector3 rotation_pivot, FSpriteModelFrame *smf) { AActor * playermo = players[consoleplayer].camera; - FSpriteModelFrame *smf = psp->Caller != nullptr ? FindModelFrame(psp->Caller->modelData != nullptr ? psp->Caller->modelData->modelDef != NAME_None ? PClass::FindActor(psp->Caller->modelData->modelDef) : psp->Caller->GetClass() : psp->Caller->GetClass(), psp->GetSprite(), psp->GetFrame(), false) : nullptr; // [BB] No model found for this sprite, so we can't render anything. if (smf == nullptr) @@ -221,8 +220,19 @@ void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, float ofsX, float o objectToWorldMatrix.translate(smf->xoffset / smf->xscale, smf->zoffset / smf->zscale, smf->yoffset / smf->yscale); // [BB] Weapon bob, very similar to the normal Doom weapon bob. - objectToWorldMatrix.rotate(ofsX / 4, 0, 1, 0); - objectToWorldMatrix.rotate((ofsY - WEAPONTOP) / -4., 1, 0, 0); + + + + objectToWorldMatrix.translate(rotation_pivot.X, rotation_pivot.Y, rotation_pivot.Z); + + objectToWorldMatrix.rotate(rotation.X, 0, 1, 0); + objectToWorldMatrix.rotate(rotation.Y, 1, 0, 0); + objectToWorldMatrix.rotate(rotation.Z, 0, 0, 1); + + objectToWorldMatrix.translate(-rotation_pivot.X, -rotation_pivot.Y, -rotation_pivot.Z); + + objectToWorldMatrix.translate(translation.X, translation.Y, translation.Z); + // [BB] For some reason the jDoom models need to be rotated. objectToWorldMatrix.rotate(90.f, 0, 1, 0); diff --git a/src/r_data/models.h b/src/r_data/models.h index d347c0ba6..568ad5399 100644 --- a/src/r_data/models.h +++ b/src/r_data/models.h @@ -110,7 +110,7 @@ void BSPWalkCircle(FLevelLocals *Level, float x, float y, float radiusSquared, c } void RenderModel(FModelRenderer* renderer, float x, float y, float z, FSpriteModelFrame* smf, AActor* actor, double ticFrac); -void RenderHUDModel(FModelRenderer* renderer, DPSprite* psp, float ofsX, float ofsY); +void RenderHUDModel(FModelRenderer* renderer, DPSprite* psp, FVector3 translation, FVector3 rotation, FVector3 rotation_pivot, FSpriteModelFrame *smf); EXTERN_CVAR(Float, cl_scaleweaponfov) diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.h b/src/rendering/hwrenderer/scene/hw_drawinfo.h index 5ed4a09ff..68afcb246 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.h +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.h @@ -216,6 +216,9 @@ private: float GetFogDensity(int lightlevel, PalEntry fogcolor, int sectorfogdensity, int blendfactor); bool CheckFog(sector_t *frontsector, sector_t *backsector); WeaponLighting GetWeaponLighting(sector_t *viewsector, const DVector3 &pos, int cm, area_t in_area, const DVector3 &playerpos); + + void PreparePlayerSprites2D(sector_t * viewsector, area_t in_area); + void PreparePlayerSprites3D(sector_t * viewsector, area_t in_area); public: void SetCameraPos(const DVector3 &pos) diff --git a/src/rendering/hwrenderer/scene/hw_weapon.cpp b/src/rendering/hwrenderer/scene/hw_weapon.cpp index 01cbf5328..5d9f44d7c 100644 --- a/src/rendering/hwrenderer/scene/hw_weapon.cpp +++ b/src/rendering/hwrenderer/scene/hw_weapon.cpp @@ -89,7 +89,7 @@ void HWDrawInfo::DrawPSprite(HUDSprite *huds, FRenderState &state) state.AlphaFunc(Alpha_GEqual, 0); FHWModelRenderer renderer(this, state, huds->lightindex); - RenderHUDModel(&renderer, huds->weapon, huds->mx, huds->my); + RenderHUDModel(&renderer, huds->weapon, huds->translation, huds->rotation + FVector3(huds->mx / 4., (huds->my - WEAPONTOP) / -4., 0), huds->pivot, huds->mframe); state.SetVertexBuffer(screen->mVertexData); } else @@ -157,9 +157,9 @@ static bool isBright(DPSprite *psp) // //========================================================================== -static WeaponPosition GetWeaponPosition(player_t *player, double ticFrac) +static WeaponPosition2D GetWeaponPosition2D(player_t *player, double ticFrac) { - WeaponPosition w; + WeaponPosition2D w; P_BobWeapon(player, &w.bobx, &w.boby, ticFrac); // Interpolate the main weapon layer once so as to be able to add it to other layers. @@ -184,13 +184,55 @@ static WeaponPosition GetWeaponPosition(player_t *player, double ticFrac) return w; } +static WeaponPosition3D GetWeaponPosition3D(player_t *player, double ticFrac) +{ + WeaponPosition3D w; + P_BobWeapon3D(player, &w.translation, &w.rotation, ticFrac); + + // Interpolate the main weapon layer once so as to be able to add it to other layers. + if ((w.weapon = player->FindPSprite(PSP_WEAPON)) != nullptr) + { + if (w.weapon->firstTic) + { + w.wx = (float)w.weapon->x; + w.wy = (float)w.weapon->y; + } + else + { + w.wx = (float)(w.weapon->oldx + (w.weapon->x - w.weapon->oldx) * ticFrac); + w.wy = (float)(w.weapon->oldy + (w.weapon->y - w.weapon->oldy) * ticFrac); + } + + auto weaponActor = w.weapon->GetCaller(); + + if (weaponActor && weaponActor->IsKindOf(NAME_Weapon)) + { + DVector3 *dPivot = (DVector3*) weaponActor->ScriptVar(NAME_BobPivot3D, nullptr); + w.pivot.X = (float) dPivot->X; + w.pivot.Y = (float) dPivot->Y; + w.pivot.Z = (float) dPivot->Z; + } + else + { + w.pivot = FVector3(0,0,0); + } + } + else + { + w.wx = 0; + w.wy = 0; + w.pivot = FVector3(0,0,0); + } + return w; +} + //========================================================================== // // Bobbing // //========================================================================== -static FVector2 BobWeapon(WeaponPosition &weap, DPSprite *psp, double ticFrac) +static FVector2 BobWeapon2D(WeaponPosition2D &weap, DPSprite *psp, double ticFrac) { if (psp->firstTic) { // Can't interpolate the first tic. @@ -215,6 +257,46 @@ static FVector2 BobWeapon(WeaponPosition &weap, DPSprite *psp, double ticFrac) return { sx, sy }; } +static FVector2 BobWeapon3D(WeaponPosition3D &weap, DPSprite *psp, FVector3 &translation, FVector3 &rotation, FVector3 &pivot, double ticFrac) +{ + if (psp->firstTic) + { // Can't interpolate the first tic. + psp->firstTic = false; + psp->ResetInterpolation(); + } + + float sx = float(psp->oldx + (psp->x - psp->oldx) * ticFrac); + float sy = float(psp->oldy + (psp->y - psp->oldy) * ticFrac); + float sz = 0; + + if (psp->Flags & PSPF_ADDBOB) + { + if (psp->Flags & PSPF_MIRROR) + { + translation = FVector3(-weap.translation.X, weap.translation.Y, weap.translation.Z); + rotation = FVector3(-weap.rotation.X, weap.rotation.Y, weap.rotation.Z); + pivot = FVector3(-weap.pivot.X, weap.pivot.Y, weap.pivot.Z); + } + else + { + translation = weap.translation ; + rotation = weap.rotation ; + pivot = weap.pivot ; + } + } + else + { + translation = rotation = pivot = FVector3(0,0,0); + } + + if (psp->Flags & PSPF_ADDWEAPON && psp->GetID() != PSP_WEAPON) + { + sx += weap.wx; + sy += weap.wy; + } + return { sx, sy }; +} + //========================================================================== // // Lighting @@ -587,11 +669,119 @@ bool HUDSprite::GetWeaponRect(HWDrawInfo *di, DPSprite *psp, float sx, float sy, // R_DrawPlayerSprites // //========================================================================== +void HWDrawInfo::PreparePlayerSprites2D(sector_t * viewsector, area_t in_area) +{ + AActor * playermo = players[consoleplayer].camera; + player_t * player = playermo->player; + + const auto &vp = Viewpoint; + + AActor *camera = vp.camera; + + WeaponPosition2D weap = GetWeaponPosition2D(camera->player, vp.TicFrac); + WeaponLighting light = GetWeaponLighting(viewsector, vp.Pos, isFullbrightScene(), in_area, camera->Pos()); + + // hack alert! Rather than changing everything in the underlying lighting code let's just temporarily change + // light mode here to draw the weapon sprite. + auto oldlightmode = lightmode; + if (isSoftwareLighting()) SetFallbackLightMode(); + + for (DPSprite *psp = player->psprites; psp != nullptr && psp->GetID() < PSP_TARGETCENTER; psp = psp->GetNext()) + { + if (!psp->GetState()) continue; + + FSpriteModelFrame *smf = psp->Caller != nullptr ? FindModelFrame(psp->Caller->modelData != nullptr ? psp->Caller->modelData->modelDef != NAME_None ? PClass::FindActor(psp->Caller->modelData->modelDef) : psp->Caller->GetClass() : psp->Caller->GetClass(), psp->GetSprite(), psp->GetFrame(), false) : nullptr; + + // This is an 'either-or' proposition. This maybe needs some work to allow overlays with weapon models but as originally implemented this just won't work. + if (smf) continue; + + HUDSprite hudsprite; + hudsprite.owner = playermo; + hudsprite.mframe = smf; + hudsprite.weapon = psp; + + if (!hudsprite.GetWeaponRenderStyle(psp, camera, viewsector, light)) continue; + + FVector2 spos = BobWeapon2D(weap, psp, vp.TicFrac); + + hudsprite.dynrgb[0] = hudsprite.dynrgb[1] = hudsprite.dynrgb[2] = 0; + hudsprite.lightindex = -1; + // set the lighting parameters + if (hudsprite.RenderStyle.BlendOp != STYLEOP_Shadow && Level->HasDynamicLights && !isFullbrightScene() && gl_light_sprites) + { + GetDynSpriteLight(playermo, nullptr, hudsprite.dynrgb); + } + + if (!hudsprite.GetWeaponRect(this, psp, spos.X, spos.Y, player, vp.TicFrac)) continue; + hudsprites.Push(hudsprite); + } + lightmode = oldlightmode; +} + +void HWDrawInfo::PreparePlayerSprites3D(sector_t * viewsector, area_t in_area) +{ + AActor * playermo = players[consoleplayer].camera; + player_t * player = playermo->player; + + const auto &vp = Viewpoint; + + AActor *camera = vp.camera; + + WeaponPosition3D weap = GetWeaponPosition3D(camera->player, vp.TicFrac); + WeaponLighting light = GetWeaponLighting(viewsector, vp.Pos, isFullbrightScene(), in_area, camera->Pos()); + + // hack alert! Rather than changing everything in the underlying lighting code let's just temporarily change + // light mode here to draw the weapon sprite. + auto oldlightmode = lightmode; + if (isSoftwareLighting()) SetFallbackLightMode(); + + for (DPSprite *psp = player->psprites; psp != nullptr && psp->GetID() < PSP_TARGETCENTER; psp = psp->GetNext()) + { + if (!psp->GetState()) continue; + FSpriteModelFrame *smf = psp->Caller != nullptr ? FindModelFrame(psp->Caller->modelData != nullptr ? psp->Caller->modelData->modelDef != NAME_None ? PClass::FindActor(psp->Caller->modelData->modelDef) : psp->Caller->GetClass() : psp->Caller->GetClass(), psp->GetSprite(), psp->GetFrame(), false) : nullptr; + + // This is an 'either-or' proposition. This maybe needs some work to allow overlays with weapon models but as originally implemented this just won't work. + if (!smf) continue; + + HUDSprite hudsprite; + hudsprite.owner = playermo; + hudsprite.mframe = smf; + hudsprite.weapon = psp; + + if (!hudsprite.GetWeaponRenderStyle(psp, camera, viewsector, light)) continue; + + //FVector2 spos = BobWeapon3D(weap, psp, hudsprite.translation, hudsprite.rotation, hudsprite.pivot, vp.TicFrac); + + FVector2 spos = BobWeapon3D(weap, psp, hudsprite.translation, hudsprite.rotation, hudsprite.pivot, vp.TicFrac); + + hudsprite.dynrgb[0] = hudsprite.dynrgb[1] = hudsprite.dynrgb[2] = 0; + hudsprite.lightindex = -1; + // set the lighting parameters + if (hudsprite.RenderStyle.BlendOp != STYLEOP_Shadow && Level->HasDynamicLights && !isFullbrightScene() && gl_light_sprites) + { + hw_GetDynModelLight(playermo, lightdata); + hudsprite.lightindex = screen->mLights->UploadLights(lightdata); + LightProbe* probe = FindLightProbe(playermo->Level, playermo->X(), playermo->Y(), playermo->Center()); + if (probe) + { + hudsprite.dynrgb[0] = probe->Red; + hudsprite.dynrgb[1] = probe->Green; + hudsprite.dynrgb[2] = probe->Blue; + } + } + + // [BB] In the HUD model step we just render the model and break out. + hudsprite.mx = spos.X; + hudsprite.my = spos.Y; + + hudsprites.Push(hudsprite); + } + lightmode = oldlightmode; +} void HWDrawInfo::PreparePlayerSprites(sector_t * viewsector, area_t in_area) { - bool brightflash = false; AActor * playermo = players[consoleplayer].camera; player_t * player = playermo->player; @@ -608,67 +798,16 @@ void HWDrawInfo::PreparePlayerSprites(sector_t * viewsector, area_t in_area) return; const bool hudModelStep = IsHUDModelForPlayerAvailable(camera->player); - WeaponPosition weap = GetWeaponPosition(camera->player, vp.TicFrac); - WeaponLighting light = GetWeaponLighting(viewsector, vp.Pos, isFullbrightScene(), in_area, camera->Pos()); - - // hack alert! Rather than changing everything in the underlying lighting code let's just temporarily change - // light mode here to draw the weapon sprite. - auto oldlightmode = lightmode; - if (isSoftwareLighting()) SetFallbackLightMode(); - - for (DPSprite *psp = player->psprites; psp != nullptr && psp->GetID() < PSP_TARGETCENTER; psp = psp->GetNext()) + + if(hudModelStep) { - if (!psp->GetState()) continue; - FSpriteModelFrame *smf = psp->Caller != nullptr ? FindModelFrame(psp->Caller->modelData != nullptr ? psp->Caller->modelData->modelDef != NAME_None ? PClass::FindActor(psp->Caller->modelData->modelDef) : psp->Caller->GetClass() : psp->Caller->GetClass(), psp->GetSprite(), psp->GetFrame(), false) : nullptr; - // This is an 'either-or' proposition. This maybe needs some work to allow overlays with weapon models but as originally implemented this just won't work. - if (smf && !hudModelStep) continue; - if (!smf && hudModelStep) continue; - - HUDSprite hudsprite; - hudsprite.owner = playermo; - hudsprite.mframe = smf; - hudsprite.weapon = psp; - - if (!hudsprite.GetWeaponRenderStyle(psp, camera, viewsector, light)) continue; - - FVector2 spos = BobWeapon(weap, psp, vp.TicFrac); - - hudsprite.dynrgb[0] = hudsprite.dynrgb[1] = hudsprite.dynrgb[2] = 0; - hudsprite.lightindex = -1; - // set the lighting parameters - if (hudsprite.RenderStyle.BlendOp != STYLEOP_Shadow && Level->HasDynamicLights && !isFullbrightScene() && gl_light_sprites) - { - if (!hudModelStep) - { - GetDynSpriteLight(playermo, nullptr, hudsprite.dynrgb); - } - else - { - hw_GetDynModelLight(playermo, lightdata); - hudsprite.lightindex = screen->mLights->UploadLights(lightdata); - LightProbe* probe = FindLightProbe(playermo->Level, playermo->X(), playermo->Y(), playermo->Center()); - if (probe) - { - hudsprite.dynrgb[0] = probe->Red; - hudsprite.dynrgb[1] = probe->Green; - hudsprite.dynrgb[2] = probe->Blue; - } - } - } - - // [BB] In the HUD model step we just render the model and break out. - if (hudModelStep) - { - hudsprite.mx = spos.X; - hudsprite.my = spos.Y; - } - else - { - if (!hudsprite.GetWeaponRect(this, psp, spos.X, spos.Y, player, vp.TicFrac)) continue; - } - hudsprites.Push(hudsprite); + PreparePlayerSprites3D(viewsector,in_area); } - lightmode = oldlightmode; + else + { + PreparePlayerSprites2D(viewsector,in_area); + } + PrepareTargeterSprites(vp.TicFrac); } diff --git a/src/rendering/hwrenderer/scene/hw_weapon.h b/src/rendering/hwrenderer/scene/hw_weapon.h index 76df17d6c..97f39ad8e 100644 --- a/src/rendering/hwrenderer/scene/hw_weapon.h +++ b/src/rendering/hwrenderer/scene/hw_weapon.h @@ -11,13 +11,25 @@ struct HWDrawInfo; class FGameTexture; -struct WeaponPosition +struct WeaponPosition2D { float wx, wy; float bobx, boby; DPSprite *weapon; }; +struct WeaponPosition3D +{ + float wx, + wy; + + FVector3 translation, + rotation, + pivot; + + DPSprite *weapon; +}; + struct WeaponLighting { FColormap cm; @@ -43,6 +55,8 @@ struct HUDSprite float mx, my; float dynrgb[3]; + FVector3 rotation, translation, pivot; + int lightindex; void SetBright(bool isbelow); diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index facbc59e3..8b7edabc2 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -716,6 +716,13 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, ClearInterpolation, ClearInterpolation) return 0; } +DEFINE_ACTION_FUNCTION(AActor, ClearFOVInterpolation) +{ + PARAM_SELF_PROLOGUE(AActor); + self->ClearFOVInterpolation(); + return 0; +} + static int ApplyDamageFactors(PClassActor *itemcls, int damagetype, int damage, int defdamage) { DmgFactors &df = itemcls->ActorInfo()->DamageFactors; diff --git a/src/scripting/zscript/zcc_compile_doom.cpp b/src/scripting/zscript/zcc_compile_doom.cpp index 69b8b773f..964d3a61c 100644 --- a/src/scripting/zscript/zcc_compile_doom.cpp +++ b/src/scripting/zscript/zcc_compile_doom.cpp @@ -452,9 +452,105 @@ void ZCCDoomCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt * } else if (!ex->isConstant()) { + if (ex->ExprType == EFX_VectorValue && ex->ValueType == f->Type) + { + auto v = static_cast(ex); + if (f->Type == TypeVector2) + { + if(!v->isConstVector(2)) + { + Error(exp, "%s: non-constant Vector2 parameter", prop->SymbolName.GetChars()); + return; + } + (*(DVector2*)addr) = DVector2( + static_cast(v->xyzw[0])->GetValue().GetFloat(), + static_cast(v->xyzw[1])->GetValue().GetFloat() + ); + goto vector_ok; + } + else if (f->Type == TypeFVector2) + { + if(!v->isConstVector(2)) + { + Error(exp, "%s: non-constant FVector2 parameter", prop->SymbolName.GetChars()); + return; + } + (*(FVector2*)addr) = FVector2( + static_cast(v->xyzw[0])->GetValue().GetFloat(), + static_cast(v->xyzw[1])->GetValue().GetFloat() + ); + goto vector_ok; + } + else if (f->Type == TypeVector3) + { + if(!v->isConstVector(3)) + { + Error(exp, "%s: non-constant Vector3 parameter", prop->SymbolName.GetChars()); + return; + } + (*(DVector3*)addr) = DVector3( + static_cast(v->xyzw[0])->GetValue().GetFloat(), + static_cast(v->xyzw[1])->GetValue().GetFloat(), + static_cast(v->xyzw[2])->GetValue().GetFloat() + ); + goto vector_ok; + } + else if (f->Type == TypeFVector3) + { + if(!v->isConstVector(3)) + { + Error(exp, "%s: non-constant FVector3 parameter", prop->SymbolName.GetChars()); + return; + } + (*(FVector3*)addr) = FVector3( + static_cast(v->xyzw[0])->GetValue().GetFloat(), + static_cast(v->xyzw[1])->GetValue().GetFloat(), + static_cast(v->xyzw[2])->GetValue().GetFloat() + ); + goto vector_ok; + } + else if (f->Type == TypeVector4) + { + if(!v->isConstVector(4)) + { + Error(exp, "%s: non-constant Vector4 parameter", prop->SymbolName.GetChars()); + return; + } + (*(DVector4*)addr) = DVector4( + static_cast(v->xyzw[0])->GetValue().GetFloat(), + static_cast(v->xyzw[1])->GetValue().GetFloat(), + static_cast(v->xyzw[2])->GetValue().GetFloat(), + static_cast(v->xyzw[3])->GetValue().GetFloat() + ); + goto vector_ok; + } + else if (f->Type == TypeFVector4) + { + if(!v->isConstVector(4)) + { + Error(exp, "%s: non-constant FVector4 parameter", prop->SymbolName.GetChars()); + return; + } + (*(FVector4*)addr) = FVector4( + static_cast(v->xyzw[0])->GetValue().GetFloat(), + static_cast(v->xyzw[1])->GetValue().GetFloat(), + static_cast(v->xyzw[2])->GetValue().GetFloat(), + static_cast(v->xyzw[3])->GetValue().GetFloat() + ); + goto vector_ok; + } + else + { + Error(exp, "%s: invalid vector parameter", prop->SymbolName.GetChars()); + return; + } + } + else + { + if (exp->Type != TypeError) Error(exp, "%s: non-constant parameter", prop->SymbolName.GetChars()); + return; + } // If we get TypeError, there has already been a message from deeper down so do not print another one. - if (exp->Type != TypeError) Error(exp, "%s: non-constant parameter", prop->SymbolName.GetChars()); - return; } if (f->Type == TypeBool) @@ -511,6 +607,7 @@ void ZCCDoomCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt * { Error(property, "unhandled property type %s", f->Type->DescriptiveName()); } +vector_ok: exp->ToErrorNode(); // invalidate after processing. exp = static_cast(exp->SiblingNext); } diff --git a/wadsrc/static/language.csv b/wadsrc/static/language.csv index 18e6a6d8f..8805aa159 100644 --- a/wadsrc/static/language.csv +++ b/wadsrc/static/language.csv @@ -2762,6 +2762,7 @@ Interpolate monster movement,DSPLYMNU_NOMONSTERINTERPOLATION,,,,Interpolovat poh Menu dim,DSPLYMNU_MENUDIM,,,,Síla barvy pozadí v menu,Menüabdunklung,,Menuo-malheleco,Atenuación del menú,,Valikon himmennys,Assombrissement menu,Menü homályosítása,Offuscamento menu,メニュー背景,메뉴 배경색 강도,Donkere menuachtergrond,Mgła w menu,Atenuação do menu,,Întunecare meniu,Затемнение фона меню,Пригушивање менија Dim color,DSPLYMNU_DIMCOLOR,,,Dim colour,Barva pozadí v menu,Abdunklungsfarbe,,Malheleca koloro,Color de la atenuación,,Himmennysväri,Couleur de l'assombrissement,Homályosítás színe,Colore offuscamento,背景色,배경색 설정,Donkere kleur,Kolor mgły,Cor da atenuação,,Culoare întunecare,Цвет затемнения,Боја пригушивања View bob amount while moving,DSPLYMNU_MOVEBOB,,,,Pohupování pohledu při pohybu,Waffenpendeln beim Bewegen,,Vidi kvanton de kapo-balanciĝo dum movado,Cantidad de balanceo al moverse,,Aseen heilumisvoimakkuus liikkeessä,Chaloupage arme en movement,Fegyver mozgása lépés közben,Ammontare di bob di movimento,視点揺れする移動値,이동 시 화면 흔들림 강도,,Dygaj kiedy się ruszasz,Quantidade de balanço durante movimento,,Mișcare cameră în timpul deplasării,Покачивание камеры при движении,Тресење камере током кретања +View bobbing while flying,MISCMNU_FVIEWBOB,,,,,,,,,,,,,,,,,,,,,, View bob amount while not moving,DSPLYMNU_STILLBOB,,,,Pohupování pohledu v klidu,Waffenpendeln bei Nichtbewegen,,Vidi kvanton de kapo-balanciĝo dum ne movado,Cantidad de balanceo al no moverse,,Aseen heilumisvoimakkuus levossa,Chaloupage arme statique,Fegyver mozgása egy helyben,Ammontare di bob di movimento da fermo,視点揺れしない移動値,정지 시 화면 움직임 강도,,Dygaj kiedy się nie ruszasz,Quantidade de balanço parado,,Mișcare cameră în timpul staționării,Покачивание камеры при бездействии,Тресење камере током неактивности Weapon bob speed,DSPLYMNU_BOBSPEED,,,,Rychlost pohupování zbraně,Waffenpendelgeschwindigkeit,,Rapido de armilo-balanciĝo,Velocidad de balanceo de Arma,,Aseen heilumisnopeus,Vitesse du chaloupage,Fegyver mozgás sebesség,Velocità di bob dell'arma,武器揺れ速度,무기 흔들림 속도,Snelheid wapenzwaaieffect,Szybkość ruchu broni,Velocidade de balanço de arma,,Viteză mișcare arme,Скорость покачивания оружия,Брзина трсења оружја ,,Scaling,,,,,,,,,,,,,,,,,,,,, diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 8167ae5e4..b05ee889b 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1221,6 +1221,7 @@ OptionMenu "MiscOptions" protected } Option "$MISCMNU_QUERYIWAD", "queryiwad", "OnOff" StaticText " " + Option "$MISCMNU_FVIEWBOB", "fviewbob", "OnOff" Option "$MISCMNU_NOCHEATS", "nocheats", "OnOff" Option "$MISCMNU_ALLCHEATS", "allcheats", "OnOff" Option "$MISCMNU_ENABLEAUTOSAVES", "disableautosave", "Autosave" diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 978fc34ab..fe8feefc3 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -669,6 +669,7 @@ class Actor : Thinker native native bool UpdateWaterLevel (bool splash = true); native bool IsZeroDamage(); native void ClearInterpolation(); + native void ClearFOVInterpolation(); native clearscope Vector3 PosRelative(sector sec) const; native void RailAttack(FRailParams p); diff --git a/wadsrc/static/zscript/actors/inventory/weapons.zs b/wadsrc/static/zscript/actors/inventory/weapons.zs index 288ae8f8f..d4aa0e57d 100644 --- a/wadsrc/static/zscript/actors/inventory/weapons.zs +++ b/wadsrc/static/zscript/actors/inventory/weapons.zs @@ -37,6 +37,8 @@ class Weapon : StateProvider // AmmoUse1 will be set to the first attack's ammo use so that checking for empty weapons still works meta int SlotNumber; meta double SlotPriority; + + Vector3 BobPivot3D; // Pivot used for BobWeapon3D property AmmoGive: AmmoGive1; property AmmoGive1: AmmoGive1; @@ -63,6 +65,7 @@ class Weapon : StateProvider property SlotNumber: SlotNumber; property SlotPriority: SlotPriority; property LookScale: LookScale; + property BobPivot3D : BobPivot3D; flagdef NoAutoFire: WeaponFlags, 0; // weapon does not autofire flagdef ReadySndHalf: WeaponFlags, 1; // ready sound is played ~1/2 the time @@ -102,6 +105,7 @@ class Weapon : StateProvider Weapon.WeaponScaleY 1.2; Weapon.SlotNumber -1; Weapon.SlotPriority 32767; + Weapon.BobPivot3D (0.0, 0.0, 0.0); +WEAPONSPAWN DefaultStateUsage SUF_ACTOR|SUF_OVERLAY|SUF_WEAPON; } @@ -460,6 +464,7 @@ class Weapon : StateProvider if (flags & 1) { // Make the zoom instant. player.FOV = player.DesiredFOV * zoom; + player.cheats |= CF_NOFOVINTERP; } if (flags & 2) { // Disable pitch/yaw scaling. diff --git a/wadsrc/static/zscript/actors/player/player.zs b/wadsrc/static/zscript/actors/player/player.zs index e72bef838..bd5710e68 100644 --- a/wadsrc/static/zscript/actors/player/player.zs +++ b/wadsrc/static/zscript/actors/player/player.zs @@ -590,7 +590,11 @@ class PlayerPawn : Actor return; } - if (still) + if (bFly && !GetCVar("FViewBob")) + { + bob = 0; + } + else if (still) { if (player.health > 0) { @@ -638,6 +642,7 @@ class PlayerPawn : Actor bob = 0; } player.viewz = pos.Z + player.viewheight + (bob * clamp(ViewBob, 0. , 1.5)); // [SP] Allow DECORATE changes to view bobbing speed. + if (Floorclip && player.playerstate != PST_DEAD && pos.Z <= floorz) { @@ -2437,6 +2442,12 @@ class PlayerPawn : Actor } return p1 * (1. - ticfrac) + p2 * ticfrac; } + + virtual Vector3 /*translation*/ , Vector3 /*rotation*/ BobWeapon3D (double ticfrac) + { + Vector2 oldBob = BobWeapon(ticfrac); + return (0, 0, 0) , ( oldBob.x / 4, oldBob.y / -4, 0); + } //---------------------------------------------------------------------------- // @@ -2794,6 +2805,7 @@ struct PlayerInfo native play // self is what internally is known as player_t native double GetWBobSpeed() const; native double GetWBobFire() const; native double GetMoveBob() const; + native bool GetFViewBob() const; native double GetStillBob() const; native void SetFOV(float fov); native clearscope bool GetClassicFlight() const; diff --git a/wadsrc/static/zscript/actors/player/player_morph.zs b/wadsrc/static/zscript/actors/player/player_morph.zs index e6ca560a4..77df1ef26 100644 --- a/wadsrc/static/zscript/actors/player/player_morph.zs +++ b/wadsrc/static/zscript/actors/player/player_morph.zs @@ -220,6 +220,7 @@ extend class PlayerPawn { p.camera = morphed; } + morphed.ClearFOVInterpolation(); morphed.ScoreIcon = ScoreIcon; // [GRB] if (eflash) eflash.target = morphed; @@ -336,6 +337,7 @@ extend class PlayerPawn { player.camera = altmo; } + altmo.ClearFOVInterpolation(); // [MH] // If the player that was morphed is the one diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index fac6619af..a8bc17bda 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -1140,6 +1140,7 @@ enum EPlayerCheats CF_INTERPVIEW = 1 << 14, // [RH] view was changed outside of input, so interpolate one frame CF_INTERPVIEWANGLES = 1 << 15, // [MR] flag for interpolating view angles without interpolating the entire frame CF_SCALEDNOLERP = 1 << 15, // [MR] flag for applying angles changes in the ticrate without interpolating the frame + CF_NOFOVINTERP = 1 << 16, // [B] Disable FOV interpolation when instantly zooming CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths. diff --git a/wadsrc/static/zscript/doombase.zs b/wadsrc/static/zscript/doombase.zs index c9fa7e1d7..58677b8ca 100644 --- a/wadsrc/static/zscript/doombase.zs +++ b/wadsrc/static/zscript/doombase.zs @@ -516,6 +516,9 @@ struct LevelLocals native native clearscope vector3 Vec3Offset(vector3 pos, vector3 dir, bool absolute = false) const; native clearscope Vector2 GetDisplacement(int pg1, int pg2) const; native clearscope int GetPortalGroupCount() const; + native clearscope int PointOnLineSide(Vector2 pos, Line l, bool precise = false) const; + native clearscope int ActorOnLineSide(Actor mo, Line l) const; + native clearscope int BoxOnLineSide(Vector2 pos, double radius, Line l) const; native String GetChecksum() const;