Implant QL pmove system into Q3 Team Arena

Replace Q3TA player movement with Quake Live's pmove system,
decompiled from qagamex64.so via Ghidra MCP.

Struct changes:
- playerState_t: +12 bytes (field_08c, field_094, field_09c,
  lastJumpTime, jumped, crouchSlideTimer, forwardmove/rightmove/upmove)
- usercmd_t: +4 bytes (field_15, field_16 between weapon and forwardmove)
- pmove_t: +16 bytes (field_0dc/0e0/0e4/0f8, removed framecount)
- pml_t: +12 bytes (isJumppad, wallContact, isStepJump)
- pm_flags: remapped to QL values (21 flags, several moved/new)

New physics systems:
- Dual VQ3/PQL physics (PMF_PROMODE)
- Double jump, crouch slide, chain/ramp/step jump
- Wall contact movement, grapple hook physics
- 34 server-tunable pmove_* cvars with cgame prediction sync

Network protocol updated for new struct fields and usercmd bytes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
serge_shubin 2026-03-20 02:57:53 +08:00
parent 5eb0118ee3
commit ba2dbb803e
10 changed files with 3417 additions and 2504 deletions

View file

@ -1156,6 +1156,40 @@ extern vmCvar_t cg_smoothClients;
extern vmCvar_t pmove_fixed;
extern vmCvar_t pmove_msec;
//extern vmCvar_t cg_pmove_fixed;
extern vmCvar_t pmove_JumpVelocity;
extern vmCvar_t pmove_JumpVelocityMax;
extern vmCvar_t pmove_JumpVelocityScaleAdd;
extern vmCvar_t pmove_JumpVelocityTimeThreshold;
extern vmCvar_t pmove_JumpVelocityTimeThresholdOffset;
extern vmCvar_t pmove_JumpTimeDeltaMin;
extern vmCvar_t pmove_ChainJump;
extern vmCvar_t pmove_ChainJumpVelocity;
extern vmCvar_t pmove_StepJumpVelocity;
extern vmCvar_t pmove_RampJumpScale;
extern vmCvar_t pmove_StepHeight;
extern vmCvar_t pmove_WalkAccel;
extern vmCvar_t pmove_WalkFriction;
extern vmCvar_t pmove_StrafeAccel;
extern vmCvar_t pmove_CircleStrafeFriction;
extern vmCvar_t pmove_CrouchSlideFriction;
extern vmCvar_t pmove_CrouchSlideTime;
extern vmCvar_t pmove_WaterSwimScale;
extern vmCvar_t pmove_WaterWadeScale;
extern vmCvar_t pmove_WeaponDropTime;
extern vmCvar_t pmove_WeaponRaiseTime;
extern vmCvar_t pmove_WishSpeed;
extern vmCvar_t pmove_AirSteps;
extern vmCvar_t pmove_AirAccel;
extern vmCvar_t pmove_AirStopAccel;
extern vmCvar_t pmove_AirControl;
extern vmCvar_t pmove_AutoHop;
extern vmCvar_t pmove_BunnyHop;
extern vmCvar_t pmove_StepJump;
extern vmCvar_t pmove_CrouchStepJump;
extern vmCvar_t pmove_RampJump;
extern vmCvar_t pmove_DoubleJump;
extern vmCvar_t pmove_CrouchSlide;
extern vmCvar_t pmove_noPlayerClip;
extern vmCvar_t cg_cameraOrbit;
extern vmCvar_t cg_cameraOrbitDelay;
extern vmCvar_t cg_timescaleFadeEnd;

View file

@ -168,6 +168,42 @@ vmCvar_t pmove_fixed;
//vmCvar_t cg_pmove_fixed;
vmCvar_t pmove_msec;
vmCvar_t cg_pmove_msec;
// QL pmove cvars (synced from server)
vmCvar_t pmove_JumpVelocity;
vmCvar_t pmove_JumpVelocityMax;
vmCvar_t pmove_JumpVelocityScaleAdd;
vmCvar_t pmove_JumpVelocityTimeThreshold;
vmCvar_t pmove_JumpVelocityTimeThresholdOffset;
vmCvar_t pmove_JumpTimeDeltaMin;
vmCvar_t pmove_ChainJump;
vmCvar_t pmove_ChainJumpVelocity;
vmCvar_t pmove_StepJumpVelocity;
vmCvar_t pmove_RampJumpScale;
vmCvar_t pmove_StepHeight;
vmCvar_t pmove_WalkAccel;
vmCvar_t pmove_WalkFriction;
vmCvar_t pmove_StrafeAccel;
vmCvar_t pmove_CircleStrafeFriction;
vmCvar_t pmove_CrouchSlideFriction;
vmCvar_t pmove_CrouchSlideTime;
vmCvar_t pmove_WaterSwimScale;
vmCvar_t pmove_WaterWadeScale;
vmCvar_t pmove_WeaponDropTime;
vmCvar_t pmove_WeaponRaiseTime;
vmCvar_t pmove_WishSpeed;
vmCvar_t pmove_AirSteps;
vmCvar_t pmove_AirAccel;
vmCvar_t pmove_AirStopAccel;
vmCvar_t pmove_AirControl;
vmCvar_t pmove_AutoHop;
vmCvar_t pmove_BunnyHop;
vmCvar_t pmove_StepJump;
vmCvar_t pmove_CrouchStepJump;
vmCvar_t pmove_RampJump;
vmCvar_t pmove_DoubleJump;
vmCvar_t pmove_CrouchSlide;
vmCvar_t pmove_noPlayerClip;
vmCvar_t cg_cameraMode;
vmCvar_t cg_cameraOrbit;
vmCvar_t cg_cameraOrbitDelay;
@ -307,6 +343,41 @@ static cvarTable_t cvarTable[] = { // bk001129
{ &pmove_fixed, "pmove_fixed", "0", 0},
{ &pmove_msec, "pmove_msec", "8", 0},
// QL pmove cvars
{ &pmove_JumpVelocity, "pmove_JumpVelocity", "270", 0 },
{ &pmove_JumpVelocityMax, "pmove_JumpVelocityMax", "700", 0 },
{ &pmove_JumpVelocityScaleAdd, "pmove_JumpVelocityScaleAdd", "0", 0 },
{ &pmove_JumpVelocityTimeThreshold, "pmove_JumpVelocityTimeThreshold", "500", 0 },
{ &pmove_JumpVelocityTimeThresholdOffset, "pmove_JumpVelocityTimeThresholdOffset", "0.5", 0 },
{ &pmove_JumpTimeDeltaMin, "pmove_JumpTimeDeltaMin", "100", 0 },
{ &pmove_ChainJump, "pmove_ChainJump", "1", 0 },
{ &pmove_ChainJumpVelocity, "pmove_ChainJumpVelocity", "110", 0 },
{ &pmove_StepJumpVelocity, "pmove_StepJumpVelocity", "48", 0 },
{ &pmove_RampJumpScale, "pmove_RampJumpScale", "1", 0 },
{ &pmove_StepHeight, "pmove_StepHeight", "22", 0 },
{ &pmove_WalkAccel, "pmove_WalkAccel", "10", 0 },
{ &pmove_WalkFriction, "pmove_WalkFriction", "6", 0 },
{ &pmove_StrafeAccel, "pmove_StrafeAccel", "1", 0 },
{ &pmove_CircleStrafeFriction, "pmove_CircleStrafeFriction", "6", 0 },
{ &pmove_CrouchSlideFriction, "pmove_CrouchSlideFriction", "0.5", 0 },
{ &pmove_CrouchSlideTime, "pmove_CrouchSlideTime", "2", 0 },
{ &pmove_WaterSwimScale, "pmove_WaterSwimScale", "0.5", 0 },
{ &pmove_WaterWadeScale, "pmove_WaterWadeScale", "0.7", 0 },
{ &pmove_WeaponDropTime, "pmove_WeaponDropTime", "200", 0 },
{ &pmove_WeaponRaiseTime, "pmove_WeaponRaiseTime", "250", 0 },
{ &pmove_WishSpeed, "pmove_WishSpeed", "400", 0 },
{ &pmove_AirSteps, "pmove_AirSteps", "1", 0 },
{ &pmove_AirAccel, "pmove_AirAccel", "1", 0 },
{ &pmove_AirStopAccel, "pmove_AirStopAccel", "1", 0 },
{ &pmove_AirControl, "pmove_AirControl", "0", 0 },
{ &pmove_AutoHop, "pmove_AutoHop", "1", 0 },
{ &pmove_BunnyHop, "pmove_BunnyHop", "1", 0 },
{ &pmove_StepJump, "pmove_StepJump", "1", 0 },
{ &pmove_CrouchStepJump, "pmove_CrouchStepJump", "1", 0 },
{ &pmove_RampJump, "pmove_RampJump", "0", 0 },
{ &pmove_DoubleJump, "pmove_DoubleJump", "1", 0 },
{ &pmove_CrouchSlide, "pmove_CrouchSlide", "0", 0 },
{ &pmove_noPlayerClip, "pmove_noPlayerClip", "0", 0 },
{ &cg_noTaunt, "cg_noTaunt", "0", CVAR_ARCHIVE},
{ &cg_noProjectileTrail, "cg_noProjectileTrail", "0", CVAR_ARCHIVE},
{ &cg_smallFont, "ui_smallFont", "0.25", CVAR_ARCHIVE},

View file

@ -26,6 +26,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// It also handles local physics interaction, like fragments bouncing off walls
#include "cg_local.h"
#include "../game/bg_local.h"
static pmove_t cg_pmove;
@ -499,6 +500,42 @@ void CG_PredictPlayerState( void ) {
cg_pmove.pmove_fixed = pmove_fixed.integer;// | cg_pmove_fixed.integer;
cg_pmove.pmove_msec = pmove_msec.integer;
// sync QL pmove globals for client prediction
pm_jumpVelocity = pmove_JumpVelocity.value;
pm_jumpVelocityMax = pmove_JumpVelocityMax.value;
pm_jumpVelocityScaleAdd = pmove_JumpVelocityScaleAdd.value;
pm_jumpVelocityTimeThreshold = pmove_JumpVelocityTimeThreshold.value;
pm_jumpVelocityTimeThresholdOffset = pmove_JumpVelocityTimeThresholdOffset.value;
pm_jumpTimeDeltaMin = pmove_JumpTimeDeltaMin.value;
pm_chainJump = pmove_ChainJump.integer;
pm_chainJumpVelocity = pmove_ChainJumpVelocity.value;
pm_stepJumpVelocity = pmove_StepJumpVelocity.value;
pm_rampJumpScale = pmove_RampJumpScale.value;
pm_stepHeight = pmove_StepHeight.value;
pm_walkAccel = pmove_WalkAccel.value;
pm_walkFriction = pmove_WalkFriction.value;
pm_strafeAccel = pmove_StrafeAccel.value;
pm_circleStrafeFriction = pmove_CircleStrafeFriction.value;
pm_crouchSlideFriction = pmove_CrouchSlideFriction.value;
pm_crouchSlideTime = pmove_CrouchSlideTime.integer;
pm_waterSwimScale = pmove_WaterSwimScale.value;
pm_waterWadeScale = pmove_WaterWadeScale.value;
pm_weaponDropTime = pmove_WeaponDropTime.integer;
pm_weaponRaiseTime = pmove_WeaponRaiseTime.integer;
pm_wishSpeed = pmove_WishSpeed.value;
pm_airSteps = pmove_AirSteps.integer;
pm_airAccel = pmove_AirAccel.value;
pm_airStopAccel = pmove_AirStopAccel.value;
pm_airControl = pmove_AirControl.value;
pm_autoHopEnabled = pmove_AutoHop.integer;
pm_bunnyHop = pmove_BunnyHop.integer;
pm_stepJumpEnabled = pmove_StepJump.integer;
pm_crouchStepJump = pmove_CrouchStepJump.integer;
pm_rampJumpEnabled = pmove_RampJump.integer;
pm_noPlayerClip = pmove_noPlayerClip.integer;
pmove_rampJumpFlag = pmove_RampJump.integer;
pmove_stepJumpFlag = pmove_StepJump.integer;
// run cmds
moved = qfalse;
for ( cmdNum = current - CMD_BACKUP + 1 ; cmdNum <= current ; cmdNum++ ) {

View file

@ -46,6 +46,11 @@ typedef struct {
qboolean groundPlane;
trace_t groundTrace;
// QL additions between groundTrace and impactSpeed
int isJumppad; // set during crouch step jump
int wallContact; // PM_CheckWallContact result
int isStepJump; // set during normal step jump
float impactSpeed;
vec3_t previous_origin;
@ -70,9 +75,54 @@ extern float pm_flyaccelerate;
extern float pm_friction;
extern float pm_waterfriction;
extern float pm_flightfriction;
extern float pm_spectatorfriction;
extern int c_pmove;
// QL cached cvar globals
extern float pm_jumpVelocity;
extern float pm_jumpVelocityMax;
extern float pm_jumpVelocityScaleAdd;
extern float pm_jumpVelocityTimeThreshold;
extern float pm_jumpVelocityTimeThresholdOffset;
extern float pm_jumpTimeDeltaMin;
extern int pm_chainJump;
extern float pm_chainJumpVelocity;
extern float pm_stepJumpVelocity;
extern float pm_rampJumpScale;
extern float pm_stepHeight;
extern float pm_walkAccel;
extern float pm_walkFriction;
extern float pm_strafeAccel;
extern float pm_circleStrafeFriction;
extern float pm_crouchSlideFriction;
extern int pm_crouchSlideTime;
extern float pm_waterSwimScale;
extern float pm_waterWadeScale;
extern int pm_weaponDropTime;
extern int pm_weaponRaiseTime;
extern float pm_wishSpeed;
extern int pm_airSteps;
extern float pm_airStepFriction;
extern float pm_airAccel;
extern float pm_airStopAccel;
extern float pm_airControl;
extern int pm_autoHopEnabled;
extern int pm_bunnyHop;
extern int pm_stepJumpEnabled;
extern int pm_crouchStepJump;
extern int pm_rampJumpEnabled;
extern int pm_noPlayerClip;
extern float pm_velocityGh;
// QL extern flags
extern int pmove_globalFlag;
extern int pmove_rampJumpFlag;
extern int pmove_stepJumpFlag;
extern float _DAT_003cfe90;
extern int DAT_003cfe30;
// pmove functions
void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce );
void PM_AddTouchEnt( int entityNum );
void PM_AddEvent( int newEvent );
@ -80,4 +130,30 @@ void PM_AddEvent( int newEvent );
qboolean PM_SlideMove( qboolean gravity );
void PM_StepSlideMove( qboolean gravity );
// QL new functions
void PM_SetupPhysicsOverrides( void );
void PM_CheckWallContact( void );
void PM_CheckDuck( void );
void PM_DropTimers( void );
void PM_SetWaterLevel( void );
void PM_SetMovementDir( void );
void PM_Friction( void );
void PM_Accelerate( float wishspeed, float accel, vec3_t wishdir );
void PM_CmdScale( usercmd_t *cmd, float *scale );
int PM_BuildWishVelocity( usercmd_t *cmd, float *wishspeed, vec3_t wishdir );
void PM_Jump( void );
int PM_CheckJump( int checkDoubleJump );
int PM_CheckGrapple( void );
void PM_GrappleMove( void );
void PM_WaterJumpMove( void );
void PM_WaterMove( void );
void PM_AirMove( void );
void PM_AirControl( void );
void PM_FlyMove( void );
void PM_GroundTrace( void );
void PM_CrashLand( void );
int PM_FootstepForSurface( void );
void PM_ContinueLegsAnim( int anim );
void PM_ForceLegsAnim( int anim );
int PM_CanJump( void );
int PM_CanEdgeGrab( void );

File diff suppressed because it is too large Load diff

View file

@ -139,22 +139,35 @@ typedef enum {
WEAPON_FIRING
} weaponstate_t;
// pmove->pm_flags
#define PMF_DUCKED 1
#define PMF_JUMP_HELD 2
#define PMF_BACKWARDS_JUMP 8 // go into backwards land
#define PMF_BACKWARDS_RUN 16 // coast down to backwards run
#define PMF_TIME_LAND 32 // pm_time is time before rejump
#define PMF_TIME_KNOCKBACK 64 // pm_time is an air-accelerate only time
#define PMF_TIME_WATERJUMP 256 // pm_time is waterjump
#define PMF_RESPAWNED 512 // clear after attack and jump buttons come up
#define PMF_USE_ITEM_HELD 1024
#define PMF_GRAPPLE_PULL 2048 // pull towards grapple location
#define PMF_FOLLOW 4096 // spectate following another player
#define PMF_SCOREBOARD 8192 // spectate as a scoreboard
#define PMF_INVULEXPAND 16384 // invulnerability sphere set to full size
// pmove->pm_flags (QL remapped values — NOT the same as Q3/Q3TA!)
#define PMF_DUCKED 0x0001
#define PMF_JUMP_HELD 0x0002
#define PMF_ATTACK_HELD 0x0004 // QL: blocks weapon fire (warmup/transition)
#define PMF_BACKWARDS_JUMP 0x0008
#define PMF_BACKWARDS_RUN 0x0010
#define PMF_TIME_KNOCKBACK 0x0020 // pm_time is knockback stun
#define PMF_TIME_WATERJUMP 0x0040 // pm_time is waterjump
#define PMF_TIME_WATERJUMP_INIT 0x0080 // QL: waterjump initiation
#define PMF_USE_ITEM_HELD 0x0100 // freezes player (intermission)
#define PMF_RESPAWNED 0x0200 // clear after attack and jump buttons come up
#define PMF_GRAPPLE_PULL 0x0400 // grapple hook active
#define PMF_GRAPPLE_ACTIVE 0x0800 // QL: grapple point tracking
#define PMF_FOLLOW_SPECTATE 0x1000 // spectate following another player
#define PMF_GRAPPLE_TARGET 0x2000 // QL: player is grappled by another
#define PMF_INVUL_EXPAND 0x4000 // invulnerability sphere set to full size
#define PMF_GRAPPLE_RELEASED 0x8000 // QL: grapple just released (blocks fire)
#define PMF_PROMODE 0x10000 // QL: PQL air control / promode physics
#define PMF_DOUBLE_JUMP 0x20000 // QL: double jump enabled
#define PMF_AUTOHOP_HELD 0x40000 // QL: per-player autohop disabled (inverted)
#define PMF_CA_TEAM1 0x80000 // QL: Clan Arena team 1
#define PMF_CROUCH_SLIDE 0x100000 // QL: crouch slide mechanic enabled
#define PMF_ALL_TIMES (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK)
#define PMF_ALL_TIMES (PMF_TIME_WATERJUMP|PMF_TIME_KNOCKBACK|PMF_TIME_WATERJUMP_INIT)
// Q3TA compatibility aliases
#define PMF_FOLLOW PMF_FOLLOW_SPECTATE
#define PMF_INVULEXPAND PMF_INVUL_EXPAND
#define PMF_SCOREBOARD PMF_FOLLOW_SPECTATE // Q3TA used separate bit; QL merged into FOLLOW
#define MAXTOUCH 32
typedef struct {
@ -166,9 +179,7 @@ typedef struct {
int tracemask; // collide against these types of surfaces
int debugLevel; // if set, diagnostic output will be printed
qboolean noFootsteps; // if the game is setup for no footsteps by the server
qboolean gauntletHit; // true if a gauntlet attack would actually hit something
int framecount;
qboolean gauntletHit; // Q3TA compat: true if a gauntlet attack would actually hit something
// results (out)
int numtouch;
@ -181,14 +192,22 @@ typedef struct {
float xyspeed;
// for fixed msec Pmove
int pmove_fixed;
int pmove_msec;
// QL additions after xyspeed
float field_0dc; // step height delta
int field_0e0; // cmd.serverTime of step event
int field_0e4; // unconfirmed
// callbacks to test the world
// these will be different functions during game and cgame
void (*trace)( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentMask );
int (*pointcontents)( const vec3_t point, int passEntityNum );
int field_0f8; // QL: linked entity boolean
int pad_0fc;
// Q3TA compat fields (not in QL pmove_t but used by game code)
int pmove_fixed;
int pmove_msec;
} pmove_t;
// if a full pmove isn't done on the client, you can just update the angles

View file

@ -21,18 +21,17 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
//
// bg_slidemove.c -- part of bg_pmove functionality
//
// Reconstructed from Quake Live x86_64 binary.
// PM_SlideMove at 0x00155ed0, PM_StepSlideMove at 0x00156850.
#include "q_shared.h"
#include "bg_public.h"
#include "bg_local.h"
/*
input: origin, velocity, bounds, groundPlane, trace function
output: origin, velocity, impacts, stairup boolean
*/
extern float _DAT_003cfe90; // velocity damping factor for step-up
extern int DAT_003cfe30; // edge grab enabled
extern int pmove_stepJumpFlag; // step jump enabled
/*
==================
@ -43,33 +42,38 @@ Returns qtrue if the velocity was clipped in some way
*/
#define MAX_CLIP_PLANES 5
qboolean PM_SlideMove( qboolean gravity ) {
int bumpcount, numbumps;
vec3_t dir;
float d;
int bumpcount;
int numplanes;
vec3_t planes[MAX_CLIP_PLANES];
vec3_t primal_velocity;
vec3_t clipVelocity;
int i, j, k;
trace_t trace;
vec3_t endClipVelocity;
vec3_t endVelocity;
vec3_t end;
vec3_t dir;
trace_t trace;
float primal_vel_x, primal_vel_y, primal_vel_z;
float time_left;
float into;
vec3_t endVelocity;
vec3_t endClipVelocity;
float d;
int i, j, k;
numbumps = 4;
primal_vel_x = pm->ps->velocity[0];
primal_vel_y = pm->ps->velocity[1];
primal_vel_z = pm->ps->velocity[2];
VectorCopy (pm->ps->velocity, primal_velocity);
if ( gravity ) {
VectorCopy( pm->ps->velocity, endVelocity );
endVelocity[2] -= pm->ps->gravity * pml.frametime;
pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5;
primal_velocity[2] = endVelocity[2];
if ( !gravity ) {
endVelocity[0] = 0.0f;
endVelocity[1] = 0.0f;
endVelocity[2] = 0.0f;
} else {
endVelocity[0] = primal_vel_x;
endVelocity[1] = pm->ps->velocity[1];
primal_vel_z = pm->ps->velocity[2] - (float)pm->ps->gravity * pml.frametime;
pm->ps->velocity[2] = (pm->ps->velocity[2] + primal_vel_z) * 0.5f;
endVelocity[2] = primal_vel_z;
if ( pml.groundPlane ) {
// slide along the ground plane
PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
pm->ps->velocity, OVERCLIP );
}
}
@ -78,36 +82,35 @@ qboolean PM_SlideMove( qboolean gravity ) {
// never turn against the ground plane
if ( pml.groundPlane ) {
numplanes = 1;
numplanes = 2;
VectorCopy( pml.groundTrace.plane.normal, planes[0] );
VectorNormalize2( pm->ps->velocity, planes[1] );
} else {
numplanes = 0;
numplanes = 1;
VectorNormalize2( pm->ps->velocity, planes[0] );
}
// never turn against original velocity
VectorNormalize2( pm->ps->velocity, planes[numplanes] );
numplanes++;
for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {
for ( bumpcount = 0; bumpcount < 4; bumpcount++ ) {
// calculate position we are trying to move to
VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );
// see if we can make it there
pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask);
pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, end,
pm->ps->clientNum, pm->tracemask );
if (trace.allsolid) {
if ( trace.allsolid ) {
// entity is completely trapped in another solid
pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration
pm->ps->velocity[2] = 0.0f;
return qtrue;
}
if (trace.fraction > 0) {
if ( trace.fraction > 0.0f ) {
// actually covered some distance
VectorCopy (trace.endpos, pm->ps->origin);
VectorCopy( trace.endpos, pm->ps->origin );
}
if (trace.fraction == 1) {
if ( trace.fraction == 1.0f ) {
break; // moved the entire distance
}
@ -116,7 +119,7 @@ qboolean PM_SlideMove( qboolean gravity ) {
time_left -= time_left * trace.fraction;
if (numplanes >= MAX_CLIP_PLANES) {
if ( numplanes >= MAX_CLIP_PLANES ) {
// this shouldn't really happen
VectorClear( pm->ps->velocity );
return qtrue;
@ -127,8 +130,8 @@ qboolean PM_SlideMove( qboolean gravity ) {
// out along it, which fixes some epsilon issues with
// non-axial planes
//
for ( i = 0 ; i < numplanes ; i++ ) {
if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) {
for ( i = 0; i < numplanes; i++ ) {
if ( (double)DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) {
VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity );
break;
}
@ -136,7 +139,7 @@ qboolean PM_SlideMove( qboolean gravity ) {
if ( i < numplanes ) {
continue;
}
VectorCopy (trace.plane.normal, planes[numplanes]);
VectorCopy( trace.plane.normal, planes[numplanes] );
numplanes++;
//
@ -144,9 +147,9 @@ qboolean PM_SlideMove( qboolean gravity ) {
//
// find a plane that it enters
for ( i = 0 ; i < numplanes ; i++ ) {
for ( i = 0; i < numplanes; i++ ) {
into = DotProduct( pm->ps->velocity, planes[i] );
if ( into >= 0.1 ) {
if ( (double)into >= 0.1 ) {
continue; // move doesn't interact with the plane
}
@ -156,17 +159,17 @@ qboolean PM_SlideMove( qboolean gravity ) {
}
// slide along the plane
PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );
PM_ClipVelocity( pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );
// slide along the plane
PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );
PM_ClipVelocity( endVelocity, planes[i], endClipVelocity, OVERCLIP );
// see if there is a second plane that the new move enters
for ( j = 0 ; j < numplanes ; j++ ) {
for ( j = 0; j < numplanes; j++ ) {
if ( j == i ) {
continue;
}
if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
if ( (double)DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
continue; // move doesn't interact with the plane
}
@ -175,31 +178,31 @@ qboolean PM_SlideMove( qboolean gravity ) {
PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );
// see if it goes back into the first clip plane
if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {
if ( DotProduct( clipVelocity, planes[i] ) >= 0.0f ) {
continue;
}
// slide the original velocity along the crease
CrossProduct (planes[i], planes[j], dir);
CrossProduct( planes[i], planes[j], dir );
VectorNormalize( dir );
d = DotProduct( dir, pm->ps->velocity );
VectorScale( dir, d, clipVelocity );
CrossProduct (planes[i], planes[j], dir);
CrossProduct( planes[i], planes[j], dir );
VectorNormalize( dir );
d = DotProduct( dir, endVelocity );
VectorScale( dir, d, endClipVelocity );
// see if there is a third plane the the new move enters
for ( k = 0 ; k < numplanes ; k++ ) {
// see if there is a third plane the new move enters
for ( k = 0; k < numplanes; k++ ) {
if ( k == i || k == j ) {
continue;
}
if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
if ( (double)DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
continue; // move doesn't interact with the plane
}
// stop dead at a tripple plane interaction
// stop dead at a triple plane interaction
VectorClear( pm->ps->velocity );
return qtrue;
}
@ -218,7 +221,9 @@ qboolean PM_SlideMove( qboolean gravity ) {
// don't change velocity if in a timer (FIXME: is this correct?)
if ( pm->ps->pm_time ) {
VectorCopy( primal_velocity, pm->ps->velocity );
pm->ps->velocity[0] = primal_vel_x;
pm->ps->velocity[1] = primal_vel_y;
pm->ps->velocity[2] = primal_vel_z;
}
return ( bumpcount != 0 );
@ -228,98 +233,165 @@ qboolean PM_SlideMove( qboolean gravity ) {
==================
PM_StepSlideMove
QL version: significantly expanded from Q3 with air-step support,
step-jump logic, edge grab, and velocity damping on step-ups.
==================
*/
void PM_StepSlideMove( qboolean gravity ) {
vec3_t start_o, start_v;
vec3_t down_o, down_v;
trace_t trace;
// float down_dist, up_dist;
// vec3_t delta, delta2;
vec3_t start_o;
float start_vx, start_vy, start_vz;
vec3_t up, down;
vec3_t projected;
vec3_t stepStart, stepEnd;
vec3_t edgeMins, edgeMaxs, edgeEnd;
trace_t trace;
float stepSize;
float delta;
float dotNV;
VectorCopy (pm->ps->origin, start_o);
VectorCopy (pm->ps->velocity, start_v);
VectorCopy( pm->ps->origin, start_o );
start_vx = pm->ps->velocity[0];
start_vy = pm->ps->velocity[1];
start_vz = pm->ps->velocity[2];
if ( PM_SlideMove( gravity ) == 0 ) {
return; // we got exactly where we wanted to go first try
}
VectorCopy(start_o, down);
down[2] -= STEPSIZE;
pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
VectorSet(up, 0, 0, 1);
// project where we would have gone without obstruction
projected[0] = start_vx * pml.frametime + start_o[0];
projected[1] = start_vy * pml.frametime + start_o[1];
projected[2] = pml.frametime * start_vz + start_o[2];
if ( pm_airSteps == 0 ) {
// trace forward to projected position, then down to check for ground
pm->trace( &trace, start_o, pm->mins, pm->maxs, projected,
pm->ps->clientNum, pm->tracemask );
VectorCopy( trace.endpos, projected );
down[0] = trace.endpos[0];
down[1] = trace.endpos[1];
down[2] = trace.endpos[2] - (float)pm_stepHeight;
pm->trace( &trace, projected, pm->mins, pm->maxs, down,
pm->ps->clientNum, pm->tracemask );
// never step up when you still have up velocity
if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 ||
DotProduct(trace.plane.normal, up) < 0.7)) {
if ( start_vz > 0.0f ) {
if ( trace.fraction == 1.0f ) {
return;
}
if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) {
return;
}
}
}
VectorCopy (pm->ps->origin, down_o);
VectorCopy (pm->ps->velocity, down_v);
VectorCopy (start_o, up);
up[2] += STEPSIZE;
// try stepping up
up[0] = start_o[0];
up[1] = start_o[1];
up[2] = start_o[2] + (float)pm_stepHeight;
// test the player position if they were a stepheight higher
pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask);
pm->trace( &trace, start_o, pm->mins, pm->maxs, up,
pm->ps->clientNum, pm->tracemask );
if ( trace.allsolid ) {
if ( pm->debugLevel ) {
Com_Printf("%i:bend can't step\n", c_pmove);
Com_Printf( "%i:bend can't step\n", c_pmove );
}
return; // can't step up
}
stepSize = trace.endpos[2] - start_o[2];
// try slidemove from this position
VectorCopy (trace.endpos, pm->ps->origin);
VectorCopy (start_v, pm->ps->velocity);
VectorCopy( trace.endpos, pm->ps->origin );
pm->ps->velocity[0] = start_vx;
pm->ps->velocity[1] = start_vy;
pm->ps->velocity[2] = start_vz;
PM_SlideMove( gravity );
// push down the final amount
VectorCopy (pm->ps->origin, down);
VectorCopy( pm->ps->origin, down );
down[2] -= stepSize;
pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, down,
pm->ps->clientNum, pm->tracemask );
if ( !trace.allsolid ) {
VectorCopy (trace.endpos, pm->ps->origin);
VectorCopy( trace.endpos, pm->ps->origin );
}
if ( trace.fraction < 1.0 ) {
PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
if ( trace.fraction < 1.0f ) {
dotNV = DotProduct( trace.plane.normal, pm->ps->velocity );
if ( dotNV >= 0.0f && fabs( dotNV ) >= 0.001f ) {
// velocity is moving away from the surface, skip clipping
goto skipClip;
}
PM_ClipVelocity( pm->ps->velocity, trace.plane.normal,
pm->ps->velocity, OVERCLIP );
}
#if 0
// if the down trace can trace back to the original position directly, don't step
pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, start_o, pm->ps->clientNum, pm->tracemask);
if ( trace.fraction == 1.0 ) {
// use the original move
VectorCopy (down_o, pm->ps->origin);
VectorCopy (down_v, pm->ps->velocity);
if ( pm->debugLevel ) {
Com_Printf("%i:bend\n", c_pmove);
}
} else
#endif
{
// use the step move
float delta;
skipClip:
// trace from start to final position to check if we actually stepped
pm->trace( &trace, start_o, pm->mins, pm->maxs, pm->ps->origin,
pm->ps->clientNum, pm->tracemask );
if ( trace.fraction < 1.0f ) {
// didn't make it all the way -- use the step move result
delta = pm->ps->origin[2] - start_o[2];
if ( delta > 2 ) {
if ( delta < 7 ) {
PM_AddEvent( EV_STEP_4 );
} else if ( delta < 11 ) {
PM_AddEvent( EV_STEP_8 );
} else if ( delta < 15 ) {
PM_AddEvent( EV_STEP_12 );
} else {
PM_AddEvent( EV_STEP_16 );
if ( delta > 2.0f ) {
pm->field_0dc = delta;
pm->field_0e0 = pm->cmd.serverTime;
}
// apply velocity damping when stepping up while airborne
if ( !pml.groundPlane && delta > 0.0f && start_vz > 0.0f ) {
float dampFactor = 1.0f - _DAT_003cfe90;
pm->ps->velocity[0] *= dampFactor;
pm->ps->velocity[1] *= dampFactor;
}
// step jump / edge grab logic
if ( pmove_stepJumpFlag && pm->ps->pm_type == PM_NORMAL
&& delta > 0.0f && (int)pm->waterlevel < 2 ) {
if ( PM_CanJump() || ( DAT_003cfe30 && PM_CanEdgeGrab() ) ) {
// check if there is walkable ground at the projected position
stepStart[0] = projected[0];
stepStart[1] = projected[1];
stepStart[2] = projected[2] + (float)pm_stepHeight;
stepEnd[0] = projected[0];
stepEnd[1] = projected[1];
stepEnd[2] = projected[2] - (float)pm_stepHeight;
pm->trace( &trace, stepStart, pm->mins, pm->maxs, stepEnd,
pm->ps->clientNum, pm->tracemask );
if ( !trace.startsolid && !trace.allsolid
&& trace.plane.normal[2] >= MIN_WALK_NORMAL ) {
if ( PM_CanJump() ) {
// normal step jump
pml.isStepJump = 1;
PM_Jump();
pml.isStepJump = 0;
} else if ( DAT_003cfe30 && PM_CanEdgeGrab() ) {
// edge grab: check for open air below with shrunk bbox
edgeMins[0] = pm->mins[0] + 1.0f;
edgeMins[1] = pm->mins[1] + 1.0f;
edgeMins[2] = pm->mins[2];
edgeMaxs[0] = pm->maxs[0] - 1.0f;
edgeMaxs[1] = pm->maxs[1] - 1.0f;
edgeMaxs[2] = pm->maxs[2];
edgeEnd[0] = pm->ps->origin[0];
edgeEnd[1] = pm->ps->origin[1];
edgeEnd[2] = pm->ps->origin[2] - 64.0f;
pm->trace( &trace, pm->ps->origin, edgeMins, edgeMaxs, edgeEnd,
pm->ps->clientNum, pm->tracemask );
if ( trace.fraction == 1.0f ) {
// over an edge -- do a crouch step jump
pml.isJumppad = 1;
PM_Jump();
pml.isJumppad = 0;
}
}
}
}
}
if ( pm->debugLevel ) {
Com_Printf("%i:stepped\n", c_pmove);
Com_Printf( "%i:stepped %f\n", c_pmove, delta );
}
}
}

View file

@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#include "g_local.h"
#include "bg_local.h"
level_locals_t level;
@ -95,6 +96,42 @@ vmCvar_t g_enableBreath;
vmCvar_t g_proxMineTimeout;
#endif
// QL pmove cvars
vmCvar_t pmove_JumpVelocity;
vmCvar_t pmove_JumpVelocityMax;
vmCvar_t pmove_JumpVelocityScaleAdd;
vmCvar_t pmove_JumpVelocityTimeThreshold;
vmCvar_t pmove_JumpVelocityTimeThresholdOffset;
vmCvar_t pmove_JumpTimeDeltaMin;
vmCvar_t pmove_ChainJump;
vmCvar_t pmove_ChainJumpVelocity;
vmCvar_t pmove_StepJumpVelocity;
vmCvar_t pmove_RampJumpScale;
vmCvar_t pmove_StepHeight;
vmCvar_t pmove_WalkAccel;
vmCvar_t pmove_WalkFriction;
vmCvar_t pmove_StrafeAccel;
vmCvar_t pmove_CircleStrafeFriction;
vmCvar_t pmove_CrouchSlideFriction;
vmCvar_t pmove_CrouchSlideTime;
vmCvar_t pmove_WaterSwimScale;
vmCvar_t pmove_WaterWadeScale;
vmCvar_t pmove_WeaponDropTime;
vmCvar_t pmove_WeaponRaiseTime;
vmCvar_t pmove_WishSpeed;
vmCvar_t pmove_AirSteps;
vmCvar_t pmove_AirAccel;
vmCvar_t pmove_AirStopAccel;
vmCvar_t pmove_AirControl;
vmCvar_t pmove_AutoHop;
vmCvar_t pmove_BunnyHop;
vmCvar_t pmove_StepJump;
vmCvar_t pmove_CrouchStepJump;
vmCvar_t pmove_RampJump;
vmCvar_t pmove_DoubleJump;
vmCvar_t pmove_CrouchSlide;
vmCvar_t pmove_noPlayerClip;
// bk001129 - made static to avoid aliasing
static cvarTable_t gameCvarTable[] = {
// don't override the cheat state set by the system
@ -178,8 +215,43 @@ static cvarTable_t gameCvarTable[] = {
{ &pmove_fixed, "pmove_fixed", "0", CVAR_SYSTEMINFO, 0, qfalse},
{ &pmove_msec, "pmove_msec", "8", CVAR_SYSTEMINFO, 0, qfalse},
{ &g_rankings, "g_rankings", "0", 0, 0, qfalse}
{ &g_rankings, "g_rankings", "0", 0, 0, qfalse},
// QL pmove cvars
{ &pmove_JumpVelocity, "pmove_JumpVelocity", "270", 0, 0, qfalse },
{ &pmove_JumpVelocityMax, "pmove_JumpVelocityMax", "700", 0, 0, qfalse },
{ &pmove_JumpVelocityScaleAdd, "pmove_JumpVelocityScaleAdd", "0", 0, 0, qfalse },
{ &pmove_JumpVelocityTimeThreshold, "pmove_JumpVelocityTimeThreshold", "500", 0, 0, qfalse },
{ &pmove_JumpVelocityTimeThresholdOffset, "pmove_JumpVelocityTimeThresholdOffset", "0.5", 0, 0, qfalse },
{ &pmove_JumpTimeDeltaMin, "pmove_JumpTimeDeltaMin", "100", 0, 0, qfalse },
{ &pmove_ChainJump, "pmove_ChainJump", "1", 0, 0, qfalse },
{ &pmove_ChainJumpVelocity, "pmove_ChainJumpVelocity", "110", 0, 0, qfalse },
{ &pmove_StepJumpVelocity, "pmove_StepJumpVelocity", "48", 0, 0, qfalse },
{ &pmove_RampJumpScale, "pmove_RampJumpScale", "1", 0, 0, qfalse },
{ &pmove_StepHeight, "pmove_StepHeight", "22", 0, 0, qfalse },
{ &pmove_WalkAccel, "pmove_WalkAccel", "10", 0, 0, qfalse },
{ &pmove_WalkFriction, "pmove_WalkFriction", "6", 0, 0, qfalse },
{ &pmove_StrafeAccel, "pmove_StrafeAccel", "1", 0, 0, qfalse },
{ &pmove_CircleStrafeFriction, "pmove_CircleStrafeFriction", "6", 0, 0, qfalse },
{ &pmove_CrouchSlideFriction, "pmove_CrouchSlideFriction", "0.5", 0, 0, qfalse },
{ &pmove_CrouchSlideTime, "pmove_CrouchSlideTime", "2", 0, 0, qfalse },
{ &pmove_WaterSwimScale, "pmove_WaterSwimScale", "0.5", 0, 0, qfalse },
{ &pmove_WaterWadeScale, "pmove_WaterWadeScale", "0.7", 0, 0, qfalse },
{ &pmove_WeaponDropTime, "pmove_WeaponDropTime", "200", 0, 0, qfalse },
{ &pmove_WeaponRaiseTime, "pmove_WeaponRaiseTime", "250", 0, 0, qfalse },
{ &pmove_WishSpeed, "pmove_WishSpeed", "400", 0, 0, qfalse },
{ &pmove_AirSteps, "pmove_AirSteps", "1", 0, 0, qfalse },
{ &pmove_AirAccel, "pmove_AirAccel", "1", 0, 0, qfalse },
{ &pmove_AirStopAccel, "pmove_AirStopAccel", "1", 0, 0, qfalse },
{ &pmove_AirControl, "pmove_AirControl", "0", 0, 0, qfalse },
{ &pmove_AutoHop, "pmove_AutoHop", "1", 0, 0, qfalse },
{ &pmove_BunnyHop, "pmove_BunnyHop", "1", 0, 0, qfalse },
{ &pmove_StepJump, "pmove_StepJump", "1", 0, 0, qfalse },
{ &pmove_CrouchStepJump, "pmove_CrouchStepJump", "1", 0, 0, qfalse },
{ &pmove_RampJump, "pmove_RampJump", "0", 0, 0, qfalse },
{ &pmove_DoubleJump, "pmove_DoubleJump", "1", 0, 0, qfalse },
{ &pmove_CrouchSlide, "pmove_CrouchSlide", "0", 0, 0, qfalse },
{ &pmove_noPlayerClip, "pmove_noPlayerClip", "0", 0, 0, qfalse },
};
// bk001129 - made static to avoid aliasing
@ -397,6 +469,42 @@ void G_UpdateCvars( void ) {
if (remapped) {
G_RemapTeamShaders();
}
// sync pmove cvar globals
pm_jumpVelocity = pmove_JumpVelocity.value;
pm_jumpVelocityMax = pmove_JumpVelocityMax.value;
pm_jumpVelocityScaleAdd = pmove_JumpVelocityScaleAdd.value;
pm_jumpVelocityTimeThreshold = pmove_JumpVelocityTimeThreshold.value;
pm_jumpVelocityTimeThresholdOffset = pmove_JumpVelocityTimeThresholdOffset.value;
pm_jumpTimeDeltaMin = pmove_JumpTimeDeltaMin.value;
pm_chainJump = pmove_ChainJump.integer;
pm_chainJumpVelocity = pmove_ChainJumpVelocity.value;
pm_stepJumpVelocity = pmove_StepJumpVelocity.value;
pm_rampJumpScale = pmove_RampJumpScale.value;
pm_stepHeight = pmove_StepHeight.value;
pm_walkAccel = pmove_WalkAccel.value;
pm_walkFriction = pmove_WalkFriction.value;
pm_strafeAccel = pmove_StrafeAccel.value;
pm_circleStrafeFriction = pmove_CircleStrafeFriction.value;
pm_crouchSlideFriction = pmove_CrouchSlideFriction.value;
pm_crouchSlideTime = pmove_CrouchSlideTime.integer;
pm_waterSwimScale = pmove_WaterSwimScale.value;
pm_waterWadeScale = pmove_WaterWadeScale.value;
pm_weaponDropTime = pmove_WeaponDropTime.integer;
pm_weaponRaiseTime = pmove_WeaponRaiseTime.integer;
pm_wishSpeed = pmove_WishSpeed.value;
pm_airSteps = pmove_AirSteps.integer;
pm_airAccel = pmove_AirAccel.value;
pm_airStopAccel = pmove_AirStopAccel.value;
pm_airControl = pmove_AirControl.value;
pm_autoHopEnabled = pmove_AutoHop.integer;
pm_bunnyHop = pmove_BunnyHop.integer;
pm_stepJumpEnabled = pmove_StepJump.integer;
pm_crouchStepJump = pmove_CrouchStepJump.integer;
pm_rampJumpEnabled = pmove_RampJump.integer;
pm_noPlayerClip = pmove_noPlayerClip.integer;
pmove_rampJumpFlag = pmove_RampJump.integer;
pmove_stepJumpFlag = pmove_StepJump.integer;
}
/*

View file

@ -1186,8 +1186,14 @@ typedef struct playerState_s {
int externalEventTime;
int clientNum; // ranges from 0 to MAX_CLIENTS-1
// QL additions: 3 new fields inserted here (shifts weapon onward +12 bytes)
int field_08c; // team entity reference (team gametypes only)
int weapon; // copied to entityState_t->weapon
int field_094; // cmd.field_15 copy (weapon-like index, 1-14)
int weaponstate;
int field_09c; // cmd.field_16 copy (index, 10-136)
vec3_t viewangles; // for fixed views
int viewheight;
@ -1207,7 +1213,17 @@ typedef struct playerState_s {
int loopSound;
int jumppad_ent; // jumppad entity hit this frame
int lastJumpTime; // QL: last jump timestamp for chain jump timing
int jumped; // QL: double jump consumed flag
int field_1d4; // QL: crouch start time
int crouchSlideTimer; // QL: crouch slide charge/decay timer
// not communicated over the net at all
signed char forwardmove; // QL: copied from cmd each frame
signed char rightmove;
signed char upmove;
byte pad_1df;
int ping; // server to game info for scoreboard
int pmove_framecount; // FIXME: don't transmit over the network
int jumppad_frame;
@ -1249,8 +1265,12 @@ typedef struct usercmd_s {
int serverTime;
int angles[3];
int buttons;
byte weapon; // weapon
byte weapon;
byte field_15; // QL: weapon-like index (1-14), copied to ps->field_094
byte field_16; // QL: index (10-136), copied to ps->field_09c
signed char forwardmove, rightmove, upmove;
byte pad_1a;
byte pad_1b;
} usercmd_t;
//===================================================================

View file

@ -655,6 +655,8 @@ void MSG_WriteDeltaUsercmd( msg_t *msg, usercmd_t *from, usercmd_t *to ) {
MSG_WriteDelta( msg, from->upmove, to->upmove, 8 );
MSG_WriteDelta( msg, from->buttons, to->buttons, 16 );
MSG_WriteDelta( msg, from->weapon, to->weapon, 8 );
MSG_WriteDelta( msg, from->field_15, to->field_15, 8 );
MSG_WriteDelta( msg, from->field_16, to->field_16, 8 );
}
@ -677,6 +679,8 @@ void MSG_ReadDeltaUsercmd( msg_t *msg, usercmd_t *from, usercmd_t *to ) {
to->upmove = MSG_ReadDelta( msg, from->upmove, 8);
to->buttons = MSG_ReadDelta( msg, from->buttons, 16);
to->weapon = MSG_ReadDelta( msg, from->weapon, 8);
to->field_15 = MSG_ReadDelta( msg, from->field_15, 8);
to->field_16 = MSG_ReadDelta( msg, from->field_16, 8);
}
/*
@ -699,7 +703,9 @@ void MSG_WriteDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *
from->rightmove == to->rightmove &&
from->upmove == to->upmove &&
from->buttons == to->buttons &&
from->weapon == to->weapon) {
from->weapon == to->weapon &&
from->field_15 == to->field_15 &&
from->field_16 == to->field_16) {
MSG_WriteBits( msg, 0, 1 ); // no change
oldsize += 7;
return;
@ -714,6 +720,8 @@ void MSG_WriteDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *
MSG_WriteDeltaKey( msg, key, from->upmove, to->upmove, 8 );
MSG_WriteDeltaKey( msg, key, from->buttons, to->buttons, 16 );
MSG_WriteDeltaKey( msg, key, from->weapon, to->weapon, 8 );
MSG_WriteDeltaKey( msg, key, from->field_15, to->field_15, 8 );
MSG_WriteDeltaKey( msg, key, from->field_16, to->field_16, 8 );
}
@ -738,6 +746,8 @@ void MSG_ReadDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *t
to->upmove = MSG_ReadDeltaKey( msg, key, from->upmove, 8);
to->buttons = MSG_ReadDeltaKey( msg, key, from->buttons, 16);
to->weapon = MSG_ReadDeltaKey( msg, key, from->weapon, 8);
to->field_15 = MSG_ReadDeltaKey( msg, key, from->field_15, 8);
to->field_16 = MSG_ReadDeltaKey( msg, key, from->field_16, 8);
} else {
to->angles[0] = from->angles[0];
to->angles[1] = from->angles[1];
@ -747,6 +757,8 @@ void MSG_ReadDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *t
to->upmove = from->upmove;
to->buttons = from->buttons;
to->weapon = from->weapon;
to->field_15 = from->field_15;
to->field_16 = from->field_16;
}
}
@ -1119,7 +1131,7 @@ netField_t playerStateFields[] =
{ PSF(events[0]), 8 },
{ PSF(legsAnim), 8 },
{ PSF(events[1]), 8 },
{ PSF(pm_flags), 16 },
{ PSF(pm_flags), 21 },
{ PSF(groundEntityNum), GENTITYNUM_BITS },
{ PSF(weaponstate), 4 },
{ PSF(eFlags), 16 },
@ -1147,7 +1159,18 @@ netField_t playerStateFields[] =
{ PSF(grapplePoint[1]), 0 },
{ PSF(grapplePoint[2]), 0 },
{ PSF(jumppad_ent), 10 },
{ PSF(loopSound), 16 }
{ PSF(loopSound), 16 },
// QL additions
{ PSF(field_08c), 32 },
{ PSF(field_094), 8 },
{ PSF(field_09c), 8 },
{ PSF(lastJumpTime), 32 },
{ PSF(jumped), 1 },
{ PSF(field_1d4), 32 },
{ PSF(crouchSlideTimer), 32 },
{ PSF(forwardmove), 8 },
{ PSF(rightmove), 8 },
{ PSF(upmove), 8 },
};
/*