Skip to content

Instantly share code, notes, and snippets.

@daftmugi
Last active September 22, 2023 08:11
Show Gist options
  • Save daftmugi/43a23ca3471ae1d49eb0b9aa92ea8457 to your computer and use it in GitHub Desktop.
Save daftmugi/43a23ca3471ae1d49eb0b9aa92ea8457 to your computer and use it in GitHub Desktop.
6320: Add New Lean
diff --git game/Player.cpp game/Player.cpp
index 2973772..305b900 100644
--- game/Player.cpp
+++ game/Player.cpp
@@ -6076,23 +6076,23 @@ void idPlayer::PerformKeyRelease(int impulse, int holdTime)
case IMPULSE_LEAN_FORWARD:
- if ( !cv_pm_lean_toggle.GetBool() && physicsObj.IsLeaning() )
+ if ( !cv_pm_lean_toggle.GetBool() )
{
- physicsObj.ToggleLean(90.0);
+ physicsObj.UnLean(90.0);
}
break;
case IMPULSE_LEAN_LEFT:
- if ( !cv_pm_lean_toggle.GetBool() && physicsObj.IsLeaning() )
+ if ( !cv_pm_lean_toggle.GetBool() )
{
- physicsObj.ToggleLean(180.0);
+ physicsObj.UnLean(180.0);
}
break;
case IMPULSE_LEAN_RIGHT:
- if ( !cv_pm_lean_toggle.GetBool() && physicsObj.IsLeaning() )
+ if ( !cv_pm_lean_toggle.GetBool() )
{
- physicsObj.ToggleLean(0.0);
+ physicsObj.UnLean(0.0);
}
break;
diff --git game/gamesys/SysCvar.cpp game/gamesys/SysCvar.cpp
index f689060..04dfa6f 100644
--- game/gamesys/SysCvar.cpp
+++ game/gamesys/SysCvar.cpp
@@ -310,6 +310,15 @@ idCVar cv_pm_lean_door_max( "pm_lean_door_max", "40", CVAR_GAME | CVAR_ARCH
idCVar cv_pm_lean_door_bounds_exp( "pm_lean_door_bounds_exp", "8.0", CVAR_GAME | CVAR_ARCHIVE | CVAR_FLOAT, "Amount to expand the camera view bounds by when testing if the player is still pressed against a door for listening purposes (default 8.0).");
idCVar cv_pm_lean_toggle( "pm_lean_toggle", "0", CVAR_GAME | CVAR_ARCHIVE | CVAR_BOOL, "Set to 1 to make leaning toggleable." );
+// Daft Mugi #6320: Add New Lean
+idCVar cv_pm_lean2_mode("pm_lean2_mode", "1", CVAR_GAME | CVAR_ARCHIVE | CVAR_BOOL, "Set to 1 to enable lean2 mode.");
+idCVar cv_pm_lean2_time_to_lean("pm_lean2_time_to_lean", "400", CVAR_GAME | CVAR_ARCHIVE | CVAR_FLOAT, "Time it takes to get to a full lean, in milliseconds.", 0.0f, 2000.0f);
+idCVar cv_pm_lean2_time_to_unlean("pm_lean2_time_to_unlean", "300", CVAR_GAME | CVAR_ARCHIVE | CVAR_FLOAT, "Time it takes to unlean, in milliseconds.", 0.0f, 2000.0f);
+idCVar cv_pm_lean2_slide("pm_lean2_slide", "200", CVAR_GAME | CVAR_ARCHIVE | CVAR_FLOAT, "The slide distance that the player moves during a lean.", 0.0f, 1000.0f);
+idCVar cv_pm_lean2_angle("pm_lean2_angle", "8", CVAR_GAME | CVAR_ARCHIVE | CVAR_FLOAT, "The tilt angle that the player can lean to at a full lean, in degrees.", 0.0f, 180.0f);
+idCVar cv_pm_lean2_angle_mod("pm_lean2_angle_mod", "0.5", CVAR_GAME | CVAR_FLOAT | CVAR_ARCHIVE, "The multiplier applied to the roll view angle during a left/right lean", 0.0f, 1.0f);
+
+
/**
* Dark Mod Frobbing
* Frob expansion radius for easier frobbing, time it takes for frob highlight to fade in and out
diff --git game/gamesys/SysCvar.h game/gamesys/SysCvar.h
index 6c92078..c76a1de 100644
--- game/gamesys/SysCvar.h
+++ game/gamesys/SysCvar.h
@@ -256,6 +256,14 @@ extern idCVar cv_pm_lean_door_max;
extern idCVar cv_pm_lean_door_bounds_exp;
extern idCVar cv_pm_lean_toggle;
+// Daft Mugi #6320: Add New Lean
+extern idCVar cv_pm_lean2_mode;
+extern idCVar cv_pm_lean2_time_to_lean;
+extern idCVar cv_pm_lean2_time_to_unlean;
+extern idCVar cv_pm_lean2_slide;
+extern idCVar cv_pm_lean2_angle;
+extern idCVar cv_pm_lean2_angle_mod;
+
extern idCVar cv_frob_distance_default;
extern idCVar cv_frob_width;
extern idCVar cv_frob_debug_bounds;
diff --git game/physics/Physics_Player.cpp game/physics/Physics_Player.cpp
index bf3e085..c0ea3f5 100644
--- game/physics/Physics_Player.cpp
+++ game/physics/Physics_Player.cpp
@@ -3388,6 +3388,15 @@ void idPhysics_Player::Restore( idRestoreGame *savefile ) {
savefile->ReadVec3 (m_LeanListenPos);
m_LeanEnt.Restore( savefile );
+ // Cancel all leaning on load
+ if (m_CurrentLeanTiltDegrees > 0.0f)
+ {
+ m_leanMoveStartTilt = m_CurrentLeanTiltDegrees;
+ m_leanTime = 0.0f;
+ m_b_leanFinished = false;
+ m_leanMoveEndTilt = 0.0f;
+ }
+
savefile->ReadStaticObject( *m_PushForce );
// ishtvan: To avoid accidental latching, clear held crouch key var
@@ -5199,6 +5208,9 @@ void idPhysics_Player::PerformMantle()
void idPhysics_Player::ToggleLean(float leanYawAngleDegrees)
{
+ if (cv_pm_lean2_mode.GetBool())
+ return ToggleLean2(leanYawAngleDegrees);
+
idPlayer* pPlayer = static_cast<idPlayer*>(self);
if (pPlayer == NULL)
{
@@ -5238,37 +5250,106 @@ void idPhysics_Player::ToggleLean(float leanYawAngleDegrees)
}
else
{
- if (m_leanTime > 0 && m_leanMoveEndTilt == 0)
- {
- // We are already un-leaning
- return;
- }
+ UnLean(leanYawAngleDegrees);
+ DM_LOG(LC_MOVEMENT, LT_DEBUG)LOGSTRING("ToggleLean ending lean\r");
+ }
+}
- // End the lean
+void idPhysics_Player::ToggleLean2(float leanYawAngleDegrees)
+{
+ idPlayer* pPlayer = static_cast<idPlayer*>(self);
+ if (pPlayer == NULL)
+ {
+ DM_LOG(LC_MOVEMENT, LT_ERROR)LOGSTRING("pPlayer is NULL\r");
+ return;
+ }
+ if (pPlayer->GetImmobilization() & EIM_LEAN)
+ // If lean immobilization is set, do nothing!
+ return;
+
+ const bool isLeaning = m_CurrentLeanTiltDegrees >= 0.1f;
+ const bool isSameDirection = m_leanYawAngleDegrees == leanYawAngleDegrees;
+ const bool isStopping = m_leanMoveEndTilt == 0;
+
+ const bool stopLeanOnKeyUp = !cv_pm_lean_toggle.GetBool()
+ && isLeaning // already leaning
+ && isSameDirection // only stop when same direction
+ && !isStopping; // not already stopping
+ const bool stopLeanOnToggle = cv_pm_lean_toggle.GetBool()
+ && isLeaning; // already leaning
+
+ if (stopLeanOnKeyUp || stopLeanOnToggle)
+ {
+ UnLean(leanYawAngleDegrees);
+ DM_LOG(LC_MOVEMENT, LT_DEBUG)LOGSTRING("ToggleLean ending lean\r");
+ return;
+ }
+
+ const bool isForwardLean = leanYawAngleDegrees == 90.0f;
+ float angle = isForwardLean ? 8.0f : cv_pm_lean2_angle.GetFloat();
+ float standingViewHeight = pm_normalviewheight.GetFloat();
+ float eyeHeight = pPlayer->EyeHeight();
+ float eyeHeightDelta = standingViewHeight - eyeHeight;
+ float crouchAngleAdjustment = (14 + (2 * (eyeHeight / standingViewHeight))) / 16.0f;
+ float forwardAngleAdjustment = isForwardLean ? (15.0f/16.0f) : 1.0f;
+
+ if (!isLeaning || (isStopping && isSameDirection))
+ {
+ // Start the lean
m_leanMoveStartTilt = m_CurrentLeanTiltDegrees;
- m_leanTime = cv_pm_lean_forward_time.GetFloat();
- m_leanMoveEndTilt = 0.0;
+ m_leanYawAngleDegrees = leanYawAngleDegrees;
+
+ m_leanTime = cv_pm_lean2_time_to_lean.GetFloat();
+ m_leanMoveEndTilt = angle
+ * forwardAngleAdjustment
+ * crouchAngleAdjustment;
+ m_leanMoveMaxAngle = m_leanMoveEndTilt;
+ m_leanMoveMaxStretch = 0.0f; // keep this in case player toggled 'pm_lean2_mode'
+
m_b_leanFinished = false;
- // greebo: Leave the rest of the variables as they are
- // to avoid view-jumping issues due to leaning back.
+ DM_LOG(LC_MOVEMENT, LT_DEBUG)LOGSTRING("ToggleLean starting lean\r");
+ }
+}
- DM_LOG(LC_MOVEMENT, LT_DEBUG)LOGSTRING("ToggleLean ending lean\r");
+void idPhysics_Player::UnLean(float leanYawAngleDegrees)
+{
+ if (m_leanYawAngleDegrees != leanYawAngleDegrees)
+ {
+ // Not same direction
+ return;
+ }
+
+ if (m_leanTime > 0 && m_leanMoveEndTilt == 0)
+ {
+ // Already un-leaning
+ return;
}
+
+ // End the lean
+ m_leanMoveStartTilt = m_CurrentLeanTiltDegrees;
+ m_leanMoveEndTilt = 0.0;
+ m_b_leanFinished = false;
+ m_leanTime = cv_pm_lean2_mode.GetBool()
+ ? cv_pm_lean2_time_to_unlean.GetFloat()
+ : cv_pm_lean_forward_time.GetFloat();
+
+ // greebo: Leave the rest of the variables as they are
+ // to avoid view-jumping issues due to leaning back.
}
//----------------------------------------------------------------------
bool idPhysics_Player::IsLeaning()
{
- if (m_CurrentLeanTiltDegrees < 0.001)
+ if (m_CurrentLeanTiltDegrees > 0.0f)
{
- return false;
+ // entering, exiting, or holding lean
+ return true;
}
else
{
- // entering, exiting, or holding lean
- return true;
+ return false;
}
}
@@ -5376,7 +5457,9 @@ void idPhysics_Player::UpdateLeanAngle (float deltaLeanTiltDegrees, float deltaL
if ( m_LeanEnt.GetEntity() == NULL ) // not set up yet?
{
CFrobDoor* door = static_cast<CFrobDoor*>(traceEnt);
- if ( (m_leanYawAngleDegrees == 0.0f) || (m_leanYawAngleDegrees == 180.0f) ) // no listening when leaning forward (90 degrees)
+ if ( (m_leanYawAngleDegrees == 0.0f) ||
+ (m_leanYawAngleDegrees == 180.0f) ||
+ (m_leanYawAngleDegrees == 90.0f) )
{
if ( !door->IsOpen() )
{
@@ -5404,17 +5487,6 @@ void idPhysics_Player::UpdateLeanAngle (float deltaLeanTiltDegrees, float deltaL
if ( distFromEye2PeakEntity < PEEK_MAX_DIST )
{
ProcessPeek(peekEntity.GetEntity(), door, trTest.c.normal);
-
- // Can listen while in a forward lean
-
- if ( !door->IsOpen() )
- {
- // can the door be listened through?
- if ( FindLeanListenPos(trTest.c.point) ) // grayman #4882
- {
- m_LeanEnt = door;
- }
- }
}
}
}
@@ -5503,6 +5575,9 @@ void idPhysics_Player::UpdateLeanAngle (float deltaLeanTiltDegrees, float deltaL
void idPhysics_Player::LeanMove()
{
+ if (cv_pm_lean2_mode.GetBool())
+ return Lean2Move();
+
// Test for leaning immobilization
idPlayer* pPlayer = static_cast<idPlayer*>(self);
if (pPlayer == NULL)
@@ -5587,6 +5662,87 @@ void idPhysics_Player::LeanMove()
// TODO: Update lean radius if player is crouching/uncrouching
}
+void idPhysics_Player::Lean2Move()
+{
+ // Test for leaning immobilization
+ idPlayer* pPlayer = static_cast<idPlayer*>(self);
+ if (pPlayer == NULL)
+ {
+ DM_LOG(LC_MOVEMENT, LT_ERROR)LOGSTRING("pPlayer is NULL\r");
+ return;
+ }
+ if (pPlayer->GetImmobilization() & EIM_LEAN)
+ {
+ // Cancel all leaning
+ if (m_leanMoveEndTilt > 0.0f)
+ {
+ m_leanMoveStartTilt = m_CurrentLeanTiltDegrees;
+ m_leanTime = cv_pm_lean2_time_to_unlean.GetFloat();
+ m_b_leanFinished = false;
+ m_leanMoveEndTilt = 0.0f;
+ }
+ }
+
+ // Change in lean tilt this frame
+ float deltaLeanTiltDegrees = 0.0;
+ float newLeanTiltDegrees = 0.0;
+
+ if ( !m_b_leanFinished )
+ {
+ // Update lean time
+ m_leanTime -= framemsec;
+ if (m_leanTime <= 0.0)
+ {
+ m_leanTime = 0.0;
+ m_b_leanFinished = true;
+ }
+
+ // Time ratio
+ float t = (m_leanMoveEndTilt > 0.0f)
+ ? m_leanTime / cv_pm_lean2_time_to_lean.GetFloat()
+ : m_leanTime / cv_pm_lean2_time_to_unlean.GetFloat();
+
+ // Cubic bezier params
+ float p[4] = {0.0f, 0.02f, 0.80f, 1.0f};
+
+ // Cubic bezier curve movement
+ float cb = (pow(1 - t, 3) * p[0])
+ + (3 * pow(1 - t, 2) * t * p[1])
+ + (3 * (1 - t) * pow(t, 2) * p[2])
+ + (pow(t, 3) * p[3]);
+ cb = 1.0f - cb;
+
+ if (m_leanMoveEndTilt > m_leanMoveStartTilt)
+ newLeanTiltDegrees = (cb * (m_leanMoveEndTilt - m_leanMoveStartTilt)) + m_leanMoveStartTilt;
+ else if (m_leanMoveStartTilt > m_leanMoveEndTilt)
+ newLeanTiltDegrees = m_leanMoveStartTilt - (cb * (m_leanMoveStartTilt - m_leanMoveEndTilt));
+
+ deltaLeanTiltDegrees = newLeanTiltDegrees - m_CurrentLeanTiltDegrees;
+ }
+
+ // Perform any change to leaning
+ if (deltaLeanTiltDegrees != 0.0)
+ {
+ // Re-orient clip model before change so that collision tests
+ // are accurate (player may have rotated mid-lean)
+ UpdateLeanAngle(deltaLeanTiltDegrees, 0);
+ }
+
+ // If player is leaned at all, do an additional clip test and unlean them
+ // In case they lean and walk into something, or a moveable moves into them, etc.
+ if (m_CurrentLeanTiltDegrees != 0.0 && TestLeanClip())
+ {
+ DM_LOG(LC_MOVEMENT,LT_DEBUG)LOGSTRING("Leaned player clipped solid, unleaning to valid position \r");
+ UnleanToValidPosition();
+ }
+
+ // Lean door test
+ if (IsLeaning())
+ {
+ UpdateLean();
+ }
+}
+
bool idPhysics_Player::TestLeanClip()
{
idPlayer *p_player = static_cast<idPlayer*>(self);
@@ -5616,6 +5772,9 @@ bool idPhysics_Player::TestLeanClip()
idVec3 idPhysics_Player::LeanParmsToPoint(float tilt, float stretch)
{
+ if (cv_pm_lean2_mode.GetBool())
+ return Lean2ParmsToPoint(tilt);
+
idPlayer* p_player = static_cast<idPlayer*>(self);
// Find the lean fulcrum to rotate about, and radius of lean
@@ -5664,6 +5823,56 @@ idVec3 idPhysics_Player::LeanParmsToPoint(float tilt, float stretch)
return vPoint;
}
+idVec3 idPhysics_Player::Lean2ParmsToPoint(float tilt)
+{
+ idPlayer* p_player = static_cast<idPlayer*>(self);
+
+ // Set slide distance - adjust for player height
+ const bool isForwardLean = m_leanYawAngleDegrees == 90.0f;
+ float standingViewHeight = pm_normalviewheight.GetFloat();
+ float eyeHeight = p_player->EyeHeight();
+ float eyeHeightDelta = standingViewHeight - eyeHeight;
+ float slide = isForwardLean ? 200.0f : cv_pm_lean2_slide.GetFloat();
+ float slideDist = slide - eyeHeightDelta;
+
+ // Set lean view angles
+ float pitchAngle = tilt * idMath::Sin(DEG2RAD(m_leanYawAngleDegrees));
+ float rollAngle = tilt * idMath::Cos(DEG2RAD(m_leanYawAngleDegrees));
+
+ // This will be the point in space relative to the player's eye position
+ idVec3 vPoint(
+ slideDist * idMath::Sin(DEG2RAD(-pitchAngle)),
+ slideDist * idMath::Sin(DEG2RAD(rollAngle)),
+ 0.0
+ );
+
+ // Calculate the z-coordinate of the point, by projecting it
+ // onto a sphere of radius <slideDist>
+ vPoint.ProjectSelfOntoSphere(slideDist);
+
+ // Subtract the radius, we only need the difference relative to the eyepos
+ vPoint.z -= slideDist;
+
+ // Rotate to player's facing
+ // this worked for yaw, but had issues with pitch, try something instead
+ //idMat4 rotMat = viewAngles.ToMat4();
+ idAngles viewAngNoPitch = viewAngles;
+ viewAngNoPitch.pitch = 0.0f;
+ idMat4 rotMat = viewAngNoPitch.ToMat4();
+
+ vPoint *= rotMat;
+
+ // Sign h4x0rx
+ vPoint.x *= -1;
+ vPoint.y *= -1;
+
+ // Extract what the player's eye position would be without lean
+ // Need to do this rather than just adding origin and eye offset due to smoothing
+ vPoint += p_player->GetEyePosition() - rotMat * m_viewLeanTranslation;
+
+ return vPoint;
+}
+
void idPhysics_Player::RopeRemovalCleanup( idEntity *RopeEnt )
{
if( RopeEnt && m_RopeEntity.GetEntity() && m_RopeEntity.GetEntity() == RopeEnt )
@@ -5696,12 +5905,17 @@ void idPhysics_Player::UpdateLeanPhysics()
idVec3 viewOrig = p_player->GetEyePosition();
// convert angle and stretch to a viewpoint in space:
idVec3 newPoint = LeanParmsToPoint( m_CurrentLeanTiltDegrees, m_CurrentLeanStretch );
-
+
// This is cumbersome, but it lets us extract the smoothed view origin from idPlayer
m_viewLeanTranslation = newPoint - (viewOrig - rotPlayerToWorld * m_viewLeanTranslation);
m_viewLeanTranslation *= rotWorldToPlayer;
- float angle = m_CurrentLeanTiltDegrees;
+ const bool isForwardLean = m_leanYawAngleDegrees == 90.0f;
+ float lean2_angle_mod = isForwardLean ? 0.5f : cv_pm_lean2_angle_mod.GetFloat();
+
+ float angle = cv_pm_lean2_mode.GetBool()
+ ? m_CurrentLeanTiltDegrees * lean2_angle_mod
+ : m_CurrentLeanTiltDegrees;
m_viewLeanAngles.pitch = angle * idMath::Sin(DEG2RAD(m_leanYawAngleDegrees));
m_viewLeanAngles.roll = angle * idMath::Cos(DEG2RAD(m_leanYawAngleDegrees));
diff --git game/physics/Physics_Player.h game/physics/Physics_Player.h
index ba17de1..17ca40e 100644
--- game/physics/Physics_Player.h
+++ game/physics/Physics_Player.h
@@ -827,6 +827,7 @@ protected:
* lean movement.
**/
void LeanMove();
+ void Lean2Move(); // Daft Mugi #6320: Add New Lean
/**
* Test clipping for the current eye position, plus delta in the lean direction
@@ -837,6 +838,7 @@ protected:
* Convert a lean angle and stretch into a point in space, in world coordinates
**/
idVec3 LeanParmsToPoint( float AngTilt, float Stretch );
+ idVec3 Lean2ParmsToPoint( float AngTilt ); // Daft Mugi #6320: Add New Lean
/**
* Start and maintain a peeking state until exited
@@ -897,6 +899,8 @@ public:
*
*/
void ToggleLean(float leanYawAngleDegrees);
+ void ToggleLean2(float leanYawAngleDegrees); // Daft Mugi #6320: Add New Lean
+ void UnLean(float leanYawAngleDegrees); // Daft Mugi #6320: Add New Lean
/*!
* This method tests if the player is in the middle of a leaning
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment