diff --git a/source/core/gameinput.cpp b/source/core/gameinput.cpp index b30aedfd8..73e35e0c6 100644 --- a/source/core/gameinput.cpp +++ b/source/core/gameinput.cpp @@ -36,6 +36,12 @@ CVAR(Float, m_pitch, 1.f, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) CVAR(Float, m_yaw, 1.f, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) CVAR(Float, m_forward, 1.f, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) CVAR(Float, m_side, 1.f, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) +CVAR(Float, cl_viewtiltscale, 1.f, CVAR_GLOBALCONFIG | CVAR_ARCHIVE); +CUSTOM_CVAR(Int, cl_viewtilting, 0, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) +{ + if (self < 0) self = 0; + else if (self > 3) self = 3; +} //--------------------------------------------------------------------------- @@ -500,6 +506,52 @@ void PlayerAngles::doViewYaw(InputPacket* const input) } +//--------------------------------------------------------------------------- +// +// View tilting effects, mostly for Exhumed to enhance its gameplay feel. +// +//--------------------------------------------------------------------------- + +void PlayerAngles::doViewTilting(InputPacket* const pInput, const DVector2& nVelVect, const double nMaxVel, const bool bUnderwater) +{ + // Scale/attenuate tilting based on player actions. + const auto runScale = 1. / (!(pInput->actions & SB_RUN) + 1); + const auto waterScale = 1. / (bUnderwater + 1); + const auto strafeScale = !!pInput->svel + 1; + + if (cl_viewtilting == 1) + { + // Console-like yaw rolling. Adjustment == (90/32) for keyboard turning. Clamp is 1.5x this value. + const auto rollAdj = pActor->spr.Angles.Roll.Degrees() + pInput->avel * (48779.f / 150000.f) * cl_viewtiltscale; + const auto rollAmp = waterScale; + const auto rollMax = (11553170. / 1347146.) * cl_viewtiltscale; + pActor->spr.Angles.Roll = DAngle::fromDeg(clamp(rollAdj * rollAmp, -rollMax, rollMax)); + scaletozero(pActor->spr.Angles.Roll, ROLL_TILTRETURN); + } + else if (cl_viewtilting == 2) + { + // Quake-like strafe rolling. Adjustment == (90/48) for running keyboard strafe. + const auto rollAdj = StrafeVel * cl_viewtiltscale; + const auto rollAmp = strafeScale * waterScale; + const auto rollMax = nMaxVel * runScale * cl_viewtiltscale; + pActor->spr.Angles.Roll = DAngle::fromDeg(clamp(rollAdj * rollAmp, -rollMax, rollMax) * (1.875 / nMaxVel)); + } + else if (cl_viewtilting == 3) + { + // Movement rolling from player's velocity. Adjustment == (90/48) for running keyboard strafe. + const auto rollAdj = nVelVect.Rotated(-pActor->spr.Angles.Yaw).Y * cl_viewtiltscale; + const auto rollAmp = strafeScale * waterScale; + const auto rollMax = nMaxVel * runScale * cl_viewtiltscale; + pActor->spr.Angles.Roll = DAngle::fromDeg(clamp(rollAdj * rollAmp, -rollMax, rollMax) * (1.875 / nMaxVel)); + } + else + { + // Always reset roll if we're not tilting at all. + pActor->spr.Angles.Roll = nullAngle; + } +} + + //--------------------------------------------------------------------------- // // diff --git a/source/core/gameinput.h b/source/core/gameinput.h index da15cbb94..56a718e28 100644 --- a/source/core/gameinput.h +++ b/source/core/gameinput.h @@ -78,6 +78,9 @@ struct PlayerAngles // Player viewing angles, separate from the camera. DRotator PrevViewAngles, ViewAngles; + // Strafe roll counter, to be incremented/managed by the game's velocity handler. + double PrevStrafeVel, StrafeVel; + // Holder of current yaw spin state for the 180 degree turn. DAngle YawSpin; @@ -90,6 +93,7 @@ struct PlayerAngles void doYawInput(InputPacket* const input); void doViewPitch(const bool canslopetilt, const bool climbing = false); void doViewYaw(InputPacket* const input); + void doViewTilting(InputPacket* const pInput, const DVector2& nVelVect, const double nMaxVel, const bool bUnderwater); // General methods. void initialize(DCoreActor* const actor, const DAngle viewyaw = nullAngle) @@ -149,6 +153,7 @@ private: DCoreActor* pActor; // Constants used throughout input functions. + static constexpr double ROLL_TILTRETURN = 15.; static constexpr double YAW_LOOKINGSPEED = 801.5625; static constexpr double YAW_ROTATESPEED = 63.28125; static constexpr double YAW_LOOKRETURN = 7.5; diff --git a/source/games/blood/src/actor.cpp b/source/games/blood/src/actor.cpp index 3840979e9..ad2b8a2aa 100644 --- a/source/games/blood/src/actor.cpp +++ b/source/games/blood/src/actor.cpp @@ -5153,8 +5153,16 @@ void MoveDude(DBloodActor* actor) actor->vel.X += FixedToFloat(-mulscale16r(FloatToFixed(actor->vel.X), nDrag)); actor->vel.Y += FixedToFloat(-mulscale16r(FloatToFixed(actor->vel.Y), nDrag)); + if (pPlayer) + { + pPlayer->Angles.StrafeVel += FixedToFloat(-mulscale16r(FloatToFixed(pPlayer->Angles.StrafeVel), nDrag)); + } + if (actor->vel.XY().Length() < 0.0625) + { actor->vel.XY().Zero(); + if (pPlayer) pPlayer->Angles.StrafeVel = 0; + } } } diff --git a/source/games/blood/src/player.cpp b/source/games/blood/src/player.cpp index e678c66e5..846494c89 100644 --- a/source/games/blood/src/player.cpp +++ b/source/games/blood/src/player.cpp @@ -1571,11 +1571,15 @@ void ProcessInput(PLAYER* pPlayer) const double& fvAccel = pInput->fvel > 0 ? pPosture->frontAccel : pPosture->backAccel; const double& svAccel = pPosture->sideAccel; actor->vel.XY() += DVector2(pInput->fvel * fvAccel, pInput->svel * svAccel).Rotated(actor->spr.Angles.Yaw) * speed; + pPlayer->Angles.StrafeVel += pInput->svel * svAccel * speed; } pPlayer->Angles.doViewYaw(pInput); pPlayer->Angles.doYawInput(pInput); + constexpr auto maxVel = (36211. / 3000.); + pPlayer->Angles.doViewTilting(pInput, actor->vel.XY(), maxVel, pPlayer->posture == kPostureSwim); + if (!(pInput->actions & SB_JUMP)) pPlayer->cantJump = 0; diff --git a/source/games/duke/src/player_d.cpp b/source/games/duke/src/player_d.cpp index 1d4804516..bc12aac40 100644 --- a/source/games/duke/src/player_d.cpp +++ b/source/games/duke/src/player_d.cpp @@ -1630,6 +1630,10 @@ void processinput_d(int snum) ESyncBits& actions = p->sync.actions; + // Get strafe value before it's rotated by the angle. + const auto strafeVel = PlayerInputSideVel(snum); + constexpr auto maxVel = (117351124. / 10884538.); + processinputvel(snum); auto sb_fvel = PlayerInputForwardVel(snum); auto sb_svel = PlayerInputSideVel(snum); @@ -1872,6 +1876,7 @@ void processinput_d(int snum) p->vel.X += sb_fvel * doubvel * (5. / 16.); p->vel.Y += sb_svel * doubvel * (5. / 16.); + p->Angles.StrafeVel += strafeVel * doubvel * (5. / 16.); bool check; @@ -1880,28 +1885,37 @@ void processinput_d(int snum) if (check) { p->vel.XY() *= gs.playerfriction - 0.125; + p->Angles.StrafeVel *= gs.playerfriction - 0.125; } else { if (psectlotag == 2) { p->vel.XY() *= gs.playerfriction - FixedToFloat(0x1400); + p->Angles.StrafeVel *= gs.playerfriction - FixedToFloat(0x1400); } else { p->vel.XY() *= gs.playerfriction; + p->Angles.StrafeVel *= gs.playerfriction; } } if (abs(p->vel.X) < 1/128. && abs(p->vel.Y) < 1 / 128.) + { p->vel.X = p->vel.Y = 0; + p->Angles.StrafeVel = 0; + } if (shrunk) { p->vel.XY() *= gs.playerfriction * 0.75; + p->Angles.StrafeVel *= gs.playerfriction * 0.75; } } + p->Angles.doViewTilting(&p->sync, p->vel.XY(), maxVel, (psectlotag == 1) || (psectlotag == 2)); + HORIZONLY: double iif = (psectlotag == 1 || p->spritebridge == 1) ? 4 : 20; diff --git a/source/games/duke/src/player_r.cpp b/source/games/duke/src/player_r.cpp index 8c27135a3..8d1a638bb 100644 --- a/source/games/duke/src/player_r.cpp +++ b/source/games/duke/src/player_r.cpp @@ -2335,6 +2335,10 @@ void processinput_r(int snum) ESyncBits& actions = p->sync.actions; + // Get strafe value before it's rotated by the angle. + const auto strafeVel = PlayerInputSideVel(snum); + constexpr auto maxVel = (117351124. / 10884538.); + auto psectp = p->cursector; if (p->OnMotorcycle && pact->spr.extra > 0) { @@ -2689,20 +2693,24 @@ void processinput_r(int snum) p->vel.X += sb_fvel * doubvel * (5. / 16.); p->vel.Y += sb_svel * doubvel * (5. / 16.); + p->Angles.StrafeVel += strafeVel * doubvel * (5. / 16.); if (!isRRRA() && ((p->curr_weapon == KNEE_WEAPON && p->kickback_pic > 10 && p->on_ground) || (p->on_ground && (actions & SB_CROUCH)))) { p->vel.XY() *= gs.playerfriction - 0.125; + p->Angles.StrafeVel *= gs.playerfriction - 0.125; } else { if (psectlotag == 2) { p->vel.XY() *= gs.playerfriction - FixedToFloat(0x1400); + p->Angles.StrafeVel *= gs.playerfriction - FixedToFloat(0x1400); } else { p->vel.XY() *= gs.playerfriction; + p->Angles.StrafeVel *= gs.playerfriction; } } @@ -2724,6 +2732,7 @@ void processinput_r(int snum) else { p->vel.XY() *= gs.playerfriction; + p->Angles.StrafeVel *= gs.playerfriction; } } else if (tilesurface(psectp->floortexture) == TSURF_MUDDY) @@ -2733,6 +2742,7 @@ void processinput_r(int snum) if (p->on_ground) { p->vel.XY() *= gs.playerfriction - FixedToFloat(0x1800); + p->Angles.StrafeVel *= gs.playerfriction - FixedToFloat(0x1800); } } else @@ -2741,18 +2751,25 @@ void processinput_r(int snum) else { p->vel.XY() *= gs.playerfriction - FixedToFloat(0x1800); + p->Angles.StrafeVel *= gs.playerfriction - FixedToFloat(0x1800); } } if (abs(p->vel.X) < 1 / 128. && abs(p->vel.Y) < 1 / 128.) + { p->vel.X = p->vel.Y = 0; + p->Angles.StrafeVel = 0; + } if (shrunk) { p->vel.XY() *= gs.playerfriction * 0.75; + p->Angles.StrafeVel *= gs.playerfriction * 0.75; } } + p->Angles.doViewTilting(&p->sync, p->vel.XY(), maxVel, (psectlotag == 1) || (psectlotag == 2)); + HORIZONLY: double iif = (psectlotag == 1 || p->spritebridge == 1) ? 4 : 20; diff --git a/source/games/exhumed/src/player.cpp b/source/games/exhumed/src/player.cpp index 04a49c44c..5d38220b3 100644 --- a/source/games/exhumed/src/player.cpp +++ b/source/games/exhumed/src/player.cpp @@ -36,12 +36,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include -CUSTOM_CVAR(Int, cl_exviewtilting, 0, CVAR_ARCHIVE) -{ - if (self < 0) self = 0; - else if (self > 3) self = 3; -} -CVAR(Float, cl_extiltscale, 1.f, CVAR_ARCHIVE); CVAR(Bool, cl_exjumprebound, false, CVAR_ARCHIVE); CVAR(Float, cl_exviewbobspeed, 4.f, CVAR_ARCHIVE); CVAR(Float, cl_exviewbobheight, 5.f, CVAR_ARCHIVE); @@ -1124,8 +1118,8 @@ static void updatePlayerVelocity(Player* const pPlayer) { pPlayer->vel += inputvect; pPlayer->vel *= 0.953125; - pPlayer->nStrafeRoll += pInput->svel * 0.375; - pPlayer->nStrafeRoll *= 0.953125; + pPlayer->Angles.StrafeVel += pInput->svel * 0.375; + pPlayer->Angles.StrafeVel *= 0.953125; } } @@ -1133,7 +1127,7 @@ static void updatePlayerVelocity(Player* const pPlayer) { pPlayer->vel.Zero(); pPlayer->nIdxBobZ = 0; - pPlayer->nStrafeRoll = 0; + pPlayer->Angles.StrafeVel = 0; } pPlayerActor->vel.XY() = pPlayer->vel; @@ -1567,50 +1561,21 @@ static void doPlayerCameraEffects(Player* const pPlayer, const double nDestVertP { const auto pPlayerActor = pPlayer->pActor; const auto pInput = &pPlayer->input; - const auto pAngles = &pPlayerActor->spr.Angles; const auto nUnderwater = !!(pPlayerActor->sector()->Flag & kSectUnderwater); - const auto waterScale = 1. / (nUnderwater + 1); constexpr auto maxVel = 15.25; // Pitch tilting when player's Z changes (stairs, jumping, etc). doPlayerVertPanning(pPlayer, nDestVertPan * cl_slopetilting); // Roll tilting effect, either console or Quake-style. - if (cl_exviewtilting == 1) - { - // Console-like yaw rolling. Adjustment == (90/32) for keyboard turning. Clamp is 1.5x this value. - const auto rollAdj = pAngles->Roll.Degrees() + pInput->avel * (48779.f / 150000.f) * cl_extiltscale; - const auto rollMax = (11553170. / 1347146.) * cl_extiltscale; - pAngles->Roll = DAngle::fromDeg(clamp(rollAdj * waterScale, -rollMax, rollMax)); - scaletozero(pAngles->Roll, GameTicRate * 0.5); - } - else if (cl_exviewtilting == 2) - { - // Quake-like strafe rolling. Adjustment == (90/48) for running keyboard strafe. - const auto rollAdj = pPlayer->nStrafeRoll * cl_extiltscale; - const auto rollAmp = (!!pInput->svel + 1.) * waterScale; - const auto rollMax = maxVel / (!(pInput->actions & SB_RUN) + 1) * cl_extiltscale; - pAngles->Roll = DAngle::fromDeg(clamp(rollAdj * rollAmp, -rollMax, rollMax) * (15. / 122.)); - } - else if (cl_exviewtilting == 3) - { - // Movement rolling. Adjustment == (90/48) for running keyboard strafe. - const auto rollAdj = pPlayerActor->vel.XY().Rotated(-pAngles->Yaw).Y * cl_extiltscale; - const auto rollAmp = (!!pInput->svel + 1.) * waterScale; - const auto rollMax = maxVel / (!(pInput->actions & SB_RUN) + 1) * cl_extiltscale; - pAngles->Roll = DAngle::fromDeg(clamp(rollAdj * rollAmp, -rollMax, rollMax) * (15. / 122.)); - } - else - { - pAngles->Roll = nullAngle; - } + pPlayer->Angles.doViewTilting(pInput, pPlayerActor->vel.XY(), maxVel, nUnderwater); // Update Z bobbing. if (cl_viewbob) { // Increment index, attenuating by bob speed, type and whether we're underwater. pPlayer->nPrevBobZ = pPlayer->nBobZ; - pPlayer->nIdxBobZ += (2048. / 90.) * cl_exviewbobspeed / cl_viewbob * waterScale; + pPlayer->nIdxBobZ += (2048. / 90.) * cl_exviewbobspeed / cl_viewbob / (nUnderwater + 1); pPlayer->nIdxBobZ *= !pPlayerActor->vel.Z; // Increment bob value with index's sine, amplifed by player velocity, bob type and bob height CVAR. diff --git a/source/games/exhumed/src/player.h b/source/games/exhumed/src/player.h index 44a3f7aa5..3d2517284 100644 --- a/source/games/exhumed/src/player.h +++ b/source/games/exhumed/src/player.h @@ -104,7 +104,6 @@ struct Player double nIdxBobZ; double nPrevWeapBob; double nWeapBob; - double nStrafeRoll; bool crouch_toggle; bool bTouchFloor; bool bJumping; diff --git a/source/games/sw/src/game.h b/source/games/sw/src/game.h index f4ef42f2a..abf3f0025 100644 --- a/source/games/sw/src/game.h +++ b/source/games/sw/src/game.h @@ -1837,6 +1837,7 @@ struct PLAYER char cookieQuote[256]; // Should be an FString but must be POD for now so that PLAYER remains POD. int cookieTime; double height; + double svel; uint8_t WpnReloadState; diff --git a/source/games/sw/src/player.cpp b/source/games/sw/src/player.cpp index d7eff90dd..27834feda 100644 --- a/source/games/sw/src/player.cpp +++ b/source/games/sw/src/player.cpp @@ -2038,9 +2038,11 @@ void DoPlayerMove(PLAYER* pp) DoPlayerSlide(pp); pp->ovect = pp->vect; + pp->Angles.PrevStrafeVel = pp->Angles.StrafeVel; pp->vect.X += pp->input.fvel * INPUT_SCALE; pp->vect.Y += pp->input.svel * INPUT_SCALE; + pp->Angles.StrafeVel += pp->svel * INPUT_SCALE; friction = pp->friction; if (!(pp->Flags & PF_SWIMMING) && pp->WadeDepth) @@ -2049,23 +2051,32 @@ void DoPlayerMove(PLAYER* pp) } pp->vect *= FixedToFloat(friction); + pp->Angles.StrafeVel *= FixedToFloat(friction); if (pp->Flags & (PF_FLYING)) { // do a bit of weighted averaging pp->vect = (pp->vect + (pp->ovect*1))/2; + pp->Angles.StrafeVel = (pp->Angles.StrafeVel + (pp->Angles.PrevStrafeVel*1))/2; } else if (pp->Flags & (PF_DIVING)) { // do a bit of weighted averaging pp->vect = (pp->vect + (pp->ovect*2))/3; + pp->Angles.StrafeVel = (pp->Angles.StrafeVel + (pp->Angles.PrevStrafeVel*2))/3; } if (abs(pp->vect.X) < 0.05 && abs(pp->vect.Y) < 0.05) + { pp->vect.Zero(); + pp->Angles.StrafeVel = 0; + } actor->vel.X = pp->vect.Length(); + constexpr auto maxVel = (380401538. / 36022361.); + pp->Angles.doViewTilting(&pp->input, pp->vect, maxVel, pp->Flags & (PF_SWIMMING|PF_DIVING)); + if (pp->Flags & (PF_CLIP_CHEAT)) { auto sect = pp->cursector; @@ -6971,6 +6982,9 @@ void domovethings(void) DoPlayerSectorUpdatePreMove(pp); ChopsCheck(pp); + // Get strafe value before it's rotated by the angle. + pp->svel = pp->input.svel; + // convert fvel/svel into a vector before performing actions. const auto velvect = DVector2(pp->input.fvel, pp->input.svel).Rotated(pp->actor->spr.Angles.Yaw); pp->input.fvel = (float)velvect.X; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 2d28e93de..3af8fd891 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1132,14 +1132,14 @@ OptionMenu "VideoOptions" protected Option "$DSPLYMNU_VIEWBOB", "cl_viewbob", "ViewBobbing" Slider "$DSPLYMNU_VIEWBOBSPEED", "cl_exviewbobspeed", 0.0, 10.0, 0.1 Slider "$DSPLYMNU_VIEWBOBHEIGHT", "cl_exviewbobheight", 0.0, 20.0, 0.1 - Option "$DSPLYMNU_VIEWTILTING", "cl_exviewtilting", "ViewTilting" - Slider "$DSPLYMNU_VIEWTILTSCALE", "cl_extiltscale", 0.0, 2.0, 0.05 } ifgame(Blood) { Option "$DSPLYMNU_VIEWBOB", "cl_viewvbob", "OnOff" Option "$DSPLYMNU_VIEWSWAY", "cl_viewhbob", "OnOff" } + Option "$DSPLYMNU_VIEWTILTING", "cl_viewtilting", "ViewTilting" + Slider "$DSPLYMNU_VIEWTILTSCALE", "cl_viewtiltscale", 0.0, 2.0, 0.05 Slider "$DSPLYMNU_FOV", "r_fov", 60, 130, 10, 1 StaticText ""