From 3327e9680ccc563d90c49f83e9e65b4576efb0d0 Mon Sep 17 00:00:00 2001 From: serge_shubin Date: Sat, 21 Mar 2026 05:45:18 +0800 Subject: [PATCH] QL movement foundation: auto-hop, PM_Jump/PM_CanJump extraction, lastJumpTime - Extract PM_Jump from PM_CheckJump for reuse by future step jump code - Add PM_CanJump gate function (checks respawned, pm_type, upmove) - Remove PMF_JUMP_HELD gate for QL-style auto-hop (hold jump to bunny hop) - Add lastJumpTime to playerState_t (networked via msg.c) for jump cooldown - bg_slidemove.c unchanged (no step jump yet -- needs proper QL analysis) Co-Authored-By: Claude Opus 4.6 (1M context) --- code/game/bg_local.h | 2 ++ code/game/bg_pmove.c | 43 ++++++++++++++++++++++++++++++++----------- code/game/q_shared.h | 3 +++ code/qcommon/msg.c | 3 ++- 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/code/game/bg_local.h b/code/game/bg_local.h index 223c688..d3ede18 100644 --- a/code/game/bg_local.h +++ b/code/game/bg_local.h @@ -77,6 +77,8 @@ void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ); void PM_AddTouchEnt( int entityNum ); void PM_AddEvent( int newEvent ); +qboolean PM_CanJump( void ); +void PM_Jump( void ); qboolean PM_SlideMove( qboolean gravity ); void PM_StepSlideMove( qboolean gravity ); diff --git a/code/game/bg_pmove.c b/code/game/bg_pmove.c index 8864f95..36bae08 100644 --- a/code/game/bg_pmove.c +++ b/code/game/bg_pmove.c @@ -360,13 +360,40 @@ Extracted from PM_CheckJump so it can be called from other contexts (step jump, double jump, etc). ============= */ -static void PM_Jump( void ) { +/* +============= +PM_CanJump + +Returns qtrue if a jump would succeed right now. +Checks both player state AND input (upmove >= 10). +Used by PM_StepSlideMove to decide whether stepping +up stairs should trigger a jump. +============= +*/ +qboolean PM_CanJump( void ) { + if ( pm->ps->pm_flags & PMF_RESPAWNED ) { + return qfalse; + } + + if ( pm->ps->pm_type != PM_NORMAL ) { + return qfalse; + } + + if ( pm->cmd.upmove < 10 ) { + return qfalse; + } + + return qtrue; +} + +void PM_Jump( void ) { pml.groundPlane = qfalse; // jumping away pml.walking = qfalse; pm->ps->pm_flags |= PMF_JUMP_HELD; pm->ps->groundEntityNum = ENTITYNUM_NONE; pm->ps->velocity[2] = JUMP_VELOCITY; + pm->ps->lastJumpTime = pm->cmd.serverTime; PM_AddEvent( EV_JUMP ); if ( pm->cmd.forwardmove >= 0 ) { @@ -384,19 +411,13 @@ PM_CheckJump ============= */ static qboolean PM_CheckJump( void ) { - if ( pm->ps->pm_flags & PMF_RESPAWNED ) { - return qfalse; // don't allow jump until all buttons are up - } - - if ( pm->cmd.upmove < 10 ) { - // not holding jump + if ( !PM_CanJump() ) { return qfalse; } - // QL autohop: don't require jump release between hops. - // The Pmove() outer loop already forces upmove=20 when - // PMF_JUMP_HELD is set, so removing this gate lets the - // player hold jump to bunny hop continuously. + // QL autohop: no PMF_JUMP_HELD gate here. + // The Pmove() outer loop forces upmove=20 when + // PMF_JUMP_HELD is set, allowing continuous bunny hopping. PM_Jump(); diff --git a/code/game/q_shared.h b/code/game/q_shared.h index eed5689..99e5a67 100644 --- a/code/game/q_shared.h +++ b/code/game/q_shared.h @@ -1212,6 +1212,9 @@ typedef struct playerState_s { int pmove_framecount; // FIXME: don't transmit over the network int jumppad_frame; int entityEventSequence; + + // QL additions + int lastJumpTime; // serverTime of last jump, for 100ms cooldown } playerState_t; diff --git a/code/qcommon/msg.c b/code/qcommon/msg.c index 27891cc..97110f8 100644 --- a/code/qcommon/msg.c +++ b/code/qcommon/msg.c @@ -1147,7 +1147,8 @@ netField_t playerStateFields[] = { PSF(grapplePoint[1]), 0 }, { PSF(grapplePoint[2]), 0 }, { PSF(jumppad_ent), 10 }, -{ PSF(loopSound), 16 } +{ PSF(loopSound), 16 }, +{ PSF(lastJumpTime), 32 } }; /*