2
===========================================================================
3
Copyright (C) 1999-2005 Id Software, Inc.
5
This file is part of Quake III Arena source code.
7
Quake III Arena source code is free software; you can redistribute it
8
and/or modify it under the terms of the GNU General Public License as
9
published by the Free Software Foundation; either version 2 of the License,
10
or (at your option) any later version.
12
Quake III Arena source code is distributed in the hope that it will be
13
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with Quake III Arena source code; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
===========================================================================
23
// bg_pmove.c -- both games player movement code
24
// takes a playerstate and a usercmd as input and returns a modifed playerstate
26
#include "../qcommon/q_shared.h"
27
#include "bg_public.h"
33
// movement parameters
34
float pm_stopspeed = 100.0f;
35
float pm_duckScale = 0.25f;
36
float pm_swimScale = 0.50f;
37
float pm_wadeScale = 0.70f;
39
float pm_accelerate = 10.0f;
40
float pm_airaccelerate = 1.0f;
41
float pm_wateraccelerate = 4.0f;
42
float pm_flyaccelerate = 8.0f;
44
float pm_friction = 6.0f;
45
float pm_waterfriction = 1.0f;
46
float pm_flightfriction = 3.0f;
47
float pm_spectatorfriction = 5.0f;
58
void PM_AddEvent( int newEvent ) {
59
BG_AddPredictableEventToPlayerstate( newEvent, 0, pm->ps );
67
void PM_AddTouchEnt( int entityNum ) {
70
if ( entityNum == ENTITYNUM_WORLD ) {
73
if ( pm->numtouch == MAXTOUCH ) {
77
// see if it is already added
78
for ( i = 0 ; i < pm->numtouch ; i++ ) {
79
if ( pm->touchents[ i ] == entityNum ) {
85
pm->touchents[pm->numtouch] = entityNum;
94
static void PM_StartTorsoAnim( int anim ) {
95
if ( pm->ps->pm_type >= PM_DEAD ) {
98
pm->ps->torsoAnim = ( ( pm->ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
101
static void PM_StartLegsAnim( int anim ) {
102
if ( pm->ps->pm_type >= PM_DEAD ) {
105
if ( pm->ps->legsTimer > 0 ) {
106
return; // a high priority animation is running
108
pm->ps->legsAnim = ( ( pm->ps->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
112
static void PM_ContinueLegsAnim( int anim ) {
113
if ( ( pm->ps->legsAnim & ~ANIM_TOGGLEBIT ) == anim ) {
116
if ( pm->ps->legsTimer > 0 ) {
117
return; // a high priority animation is running
119
PM_StartLegsAnim( anim );
122
static void PM_ContinueTorsoAnim( int anim ) {
123
if ( ( pm->ps->torsoAnim & ~ANIM_TOGGLEBIT ) == anim ) {
126
if ( pm->ps->torsoTimer > 0 ) {
127
return; // a high priority animation is running
129
PM_StartTorsoAnim( anim );
132
static void PM_ForceLegsAnim( int anim ) {
133
pm->ps->legsTimer = 0;
134
PM_StartLegsAnim( anim );
142
Slide off of the impacting surface
145
void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ) {
150
backoff = DotProduct (in, normal);
153
backoff *= overbounce;
155
backoff /= overbounce;
158
for ( i=0 ; i<3 ; i++ ) {
159
change = normal[i]*backoff;
160
out[i] = in[i] - change;
169
Handles both ground friction and water friction
172
static void PM_Friction( void ) {
175
float speed, newspeed, control;
178
vel = pm->ps->velocity;
180
VectorCopy( vel, vec );
182
vec[2] = 0; // ignore slope movement
185
speed = VectorLength(vec);
188
vel[1] = 0; // allow sinking underwater
189
// FIXME: still have z friction underwater?
195
// apply ground friction
196
if ( pm->waterlevel <= 1 ) {
197
if ( pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) {
198
// if getting knocked back, no friction
199
if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) {
200
control = speed < pm_stopspeed ? pm_stopspeed : speed;
201
drop += control*pm_friction*pml.frametime;
206
// apply water friction even if just wading
207
if ( pm->waterlevel ) {
208
drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime;
211
// apply flying friction
212
if ( pm->ps->powerups[PW_FLIGHT]) {
213
drop += speed*pm_flightfriction*pml.frametime;
216
if ( pm->ps->pm_type == PM_SPECTATOR) {
217
drop += speed*pm_spectatorfriction*pml.frametime;
220
// scale the velocity
221
newspeed = speed - drop;
227
vel[0] = vel[0] * newspeed;
228
vel[1] = vel[1] * newspeed;
229
vel[2] = vel[2] * newspeed;
237
Handles user intended acceleration
240
static void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel ) {
244
float addspeed, accelspeed, currentspeed;
246
currentspeed = DotProduct (pm->ps->velocity, wishdir);
247
addspeed = wishspeed - currentspeed;
251
accelspeed = accel*pml.frametime*wishspeed;
252
if (accelspeed > addspeed) {
253
accelspeed = addspeed;
256
for (i=0 ; i<3 ; i++) {
257
pm->ps->velocity[i] += accelspeed*wishdir[i];
260
// proper way (avoids strafe jump maxspeed bug), but feels bad
266
VectorScale( wishdir, wishspeed, wishVelocity );
267
VectorSubtract( wishVelocity, pm->ps->velocity, pushDir );
268
pushLen = VectorNormalize( pushDir );
270
canPush = accel*pml.frametime*wishspeed;
271
if (canPush > pushLen) {
275
VectorMA( pm->ps->velocity, canPush, pushDir, pm->ps->velocity );
285
Returns the scale factor to apply to cmd movements
286
This allows the clients to use axial -127 to 127 values for all directions
287
without getting a sqrt(2) distortion in speed.
290
static float PM_CmdScale( usercmd_t *cmd ) {
295
max = abs( cmd->forwardmove );
296
if ( abs( cmd->rightmove ) > max ) {
297
max = abs( cmd->rightmove );
299
if ( abs( cmd->upmove ) > max ) {
300
max = abs( cmd->upmove );
306
total = sqrt( cmd->forwardmove * cmd->forwardmove
307
+ cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove );
308
scale = (float)pm->ps->speed * max / ( 127.0 * total );
318
Determine the rotation of the legs reletive
322
static void PM_SetMovementDir( void ) {
323
if ( pm->cmd.forwardmove || pm->cmd.rightmove ) {
324
if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove > 0 ) {
325
pm->ps->movementDir = 0;
326
} else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove > 0 ) {
327
pm->ps->movementDir = 1;
328
} else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove == 0 ) {
329
pm->ps->movementDir = 2;
330
} else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove < 0 ) {
331
pm->ps->movementDir = 3;
332
} else if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove < 0 ) {
333
pm->ps->movementDir = 4;
334
} else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove < 0 ) {
335
pm->ps->movementDir = 5;
336
} else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove == 0 ) {
337
pm->ps->movementDir = 6;
338
} else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove > 0 ) {
339
pm->ps->movementDir = 7;
342
// if they aren't actively going directly sideways,
343
// change the animation to the diagonal so they
344
// don't stop too crooked
345
if ( pm->ps->movementDir == 2 ) {
346
pm->ps->movementDir = 1;
347
} else if ( pm->ps->movementDir == 6 ) {
348
pm->ps->movementDir = 7;
359
static qboolean PM_CheckJump( void ) {
360
if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
361
return qfalse; // don't allow jump until all buttons are up
364
if ( pm->cmd.upmove < 10 ) {
369
// must wait for jump to be released
370
if ( pm->ps->pm_flags & PMF_JUMP_HELD ) {
371
// clear upmove so cmdscale doesn't lower running speed
376
pml.groundPlane = qfalse; // jumping away
377
pml.walking = qfalse;
378
pm->ps->pm_flags |= PMF_JUMP_HELD;
380
pm->ps->groundEntityNum = ENTITYNUM_NONE;
381
pm->ps->velocity[2] = JUMP_VELOCITY;
382
PM_AddEvent( EV_JUMP );
384
if ( pm->cmd.forwardmove >= 0 ) {
385
PM_ForceLegsAnim( LEGS_JUMP );
386
pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
388
PM_ForceLegsAnim( LEGS_JUMPB );
389
pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
400
static qboolean PM_CheckWaterJump( void ) {
405
if (pm->ps->pm_time) {
409
// check for water jump
410
if ( pm->waterlevel != 2 ) {
414
flatforward[0] = pml.forward[0];
415
flatforward[1] = pml.forward[1];
417
VectorNormalize (flatforward);
419
VectorMA (pm->ps->origin, 30, flatforward, spot);
421
cont = pm->pointcontents (spot, pm->ps->clientNum );
422
if ( !(cont & CONTENTS_SOLID) ) {
427
cont = pm->pointcontents (spot, pm->ps->clientNum );
433
VectorScale (pml.forward, 200, pm->ps->velocity);
434
pm->ps->velocity[2] = 350;
436
pm->ps->pm_flags |= PMF_TIME_WATERJUMP;
437
pm->ps->pm_time = 2000;
442
//============================================================================
449
Flying out of the water
452
static void PM_WaterJumpMove( void ) {
453
// waterjump has no control, but falls
455
PM_StepSlideMove( qtrue );
457
pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime;
458
if (pm->ps->velocity[2] < 0) {
459
// cancel as soon as we are falling down again
460
pm->ps->pm_flags &= ~PMF_ALL_TIMES;
471
static void PM_WaterMove( void ) {
479
if ( PM_CheckWaterJump() ) {
484
// jump = head for surface
485
if ( pm->cmd.upmove >= 10 ) {
486
if (pm->ps->velocity[2] > -300) {
487
if ( pm->watertype == CONTENTS_WATER ) {
488
pm->ps->velocity[2] = 100;
489
} else if (pm->watertype == CONTENTS_SLIME) {
490
pm->ps->velocity[2] = 80;
492
pm->ps->velocity[2] = 50;
499
scale = PM_CmdScale( &pm->cmd );
506
wishvel[2] = -60; // sink towards bottom
508
for (i=0 ; i<3 ; i++)
509
wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;
511
wishvel[2] += scale * pm->cmd.upmove;
514
VectorCopy (wishvel, wishdir);
515
wishspeed = VectorNormalize(wishdir);
517
if ( wishspeed > pm->ps->speed * pm_swimScale ) {
518
wishspeed = pm->ps->speed * pm_swimScale;
521
PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate);
523
// make sure we can go up slopes easily under water
524
if ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) {
525
vel = VectorLength(pm->ps->velocity);
526
// slide along the ground plane
527
PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
528
pm->ps->velocity, OVERCLIP );
530
VectorNormalize(pm->ps->velocity);
531
VectorScale(pm->ps->velocity, vel, pm->ps->velocity);
534
PM_SlideMove( qfalse );
540
PM_InvulnerabilityMove
542
Only with the invulnerability powerup
545
static void PM_InvulnerabilityMove( void ) {
546
pm->cmd.forwardmove = 0;
547
pm->cmd.rightmove = 0;
549
VectorClear(pm->ps->velocity);
557
Only with the flight powerup
560
static void PM_FlyMove( void ) {
570
scale = PM_CmdScale( &pm->cmd );
579
for (i=0 ; i<3 ; i++) {
580
wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;
583
wishvel[2] += scale * pm->cmd.upmove;
586
VectorCopy (wishvel, wishdir);
587
wishspeed = VectorNormalize(wishdir);
589
PM_Accelerate (wishdir, wishspeed, pm_flyaccelerate);
591
PM_StepSlideMove( qfalse );
601
static void PM_AirMove( void ) {
612
fmove = pm->cmd.forwardmove;
613
smove = pm->cmd.rightmove;
616
scale = PM_CmdScale( &cmd );
618
// set the movementDir so clients can rotate the legs for strafing
621
// project moves down to flat plane
624
VectorNormalize (pml.forward);
625
VectorNormalize (pml.right);
627
for ( i = 0 ; i < 2 ; i++ ) {
628
wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
632
VectorCopy (wishvel, wishdir);
633
wishspeed = VectorNormalize(wishdir);
636
// not on ground, so little effect on velocity
637
PM_Accelerate (wishdir, wishspeed, pm_airaccelerate);
639
// we may have a ground plane that is very steep, even
640
// though we don't have a groundentity
641
// slide along the steep plane
642
if ( pml.groundPlane ) {
643
PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
644
pm->ps->velocity, OVERCLIP );
648
//ZOID: If we are on the grapple, try stair-stepping
649
//this allows a player to use the grapple to pull himself
651
if (pm->ps->pm_flags & PMF_GRAPPLE_PULL)
652
PM_StepSlideMove ( qtrue );
654
PM_SlideMove ( qtrue );
657
PM_StepSlideMove ( qtrue );
666
static void PM_GrappleMove( void ) {
670
VectorScale(pml.forward, -16, v);
671
VectorAdd(pm->ps->grapplePoint, v, v);
672
VectorSubtract(v, pm->ps->origin, vel);
673
vlen = VectorLength(vel);
674
VectorNormalize( vel );
677
VectorScale(vel, 10 * vlen, vel);
679
VectorScale(vel, 800, vel);
681
VectorCopy(vel, pm->ps->velocity);
683
pml.groundPlane = qfalse;
692
static void PM_WalkMove( void ) {
703
if ( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) {
710
if ( PM_CheckJump () ) {
712
if ( pm->waterlevel > 1 ) {
722
fmove = pm->cmd.forwardmove;
723
smove = pm->cmd.rightmove;
726
scale = PM_CmdScale( &cmd );
728
// set the movementDir so clients can rotate the legs for strafing
731
// project moves down to flat plane
735
// project the forward and right directions onto the ground plane
736
PM_ClipVelocity (pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP );
737
PM_ClipVelocity (pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP );
739
VectorNormalize (pml.forward);
740
VectorNormalize (pml.right);
742
for ( i = 0 ; i < 3 ; i++ ) {
743
wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
745
// when going up or down slopes the wish velocity should Not be zero
748
VectorCopy (wishvel, wishdir);
749
wishspeed = VectorNormalize(wishdir);
752
// clamp the speed lower if ducking
753
if ( pm->ps->pm_flags & PMF_DUCKED ) {
754
if ( wishspeed > pm->ps->speed * pm_duckScale ) {
755
wishspeed = pm->ps->speed * pm_duckScale;
759
// clamp the speed lower if wading or walking on the bottom
760
if ( pm->waterlevel ) {
763
waterScale = pm->waterlevel / 3.0;
764
waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale;
765
if ( wishspeed > pm->ps->speed * waterScale ) {
766
wishspeed = pm->ps->speed * waterScale;
770
// when a player gets hit, they temporarily lose
771
// full control, which allows them to be moved a bit
772
if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {
773
accelerate = pm_airaccelerate;
775
accelerate = pm_accelerate;
778
PM_Accelerate (wishdir, wishspeed, accelerate);
780
//Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]);
781
//Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity));
783
if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {
784
pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime;
786
// don't reset the z velocity for slopes
787
// pm->ps->velocity[2] = 0;
790
vel = VectorLength(pm->ps->velocity);
792
// slide along the ground plane
793
PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
794
pm->ps->velocity, OVERCLIP );
796
// don't decrease velocity when going up or down a slope
797
VectorNormalize(pm->ps->velocity);
798
VectorScale(pm->ps->velocity, vel, pm->ps->velocity);
800
// don't do anything if standing still
801
if (!pm->ps->velocity[0] && !pm->ps->velocity[1]) {
805
PM_StepSlideMove( qfalse );
807
//Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity));
817
static void PM_DeadMove( void ) {
820
if ( !pml.walking ) {
826
forward = VectorLength (pm->ps->velocity);
828
if ( forward <= 0 ) {
829
VectorClear (pm->ps->velocity);
831
VectorNormalize (pm->ps->velocity);
832
VectorScale (pm->ps->velocity, forward, pm->ps->velocity);
842
static void PM_NoclipMove( void ) {
843
float speed, drop, friction, control, newspeed;
851
pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
855
speed = VectorLength (pm->ps->velocity);
858
VectorCopy (vec3_origin, pm->ps->velocity);
864
friction = pm_friction*1.5; // extra friction
865
control = speed < pm_stopspeed ? pm_stopspeed : speed;
866
drop += control*friction*pml.frametime;
868
// scale the velocity
869
newspeed = speed - drop;
874
VectorScale (pm->ps->velocity, newspeed, pm->ps->velocity);
878
scale = PM_CmdScale( &pm->cmd );
880
fmove = pm->cmd.forwardmove;
881
smove = pm->cmd.rightmove;
883
for (i=0 ; i<3 ; i++)
884
wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
885
wishvel[2] += pm->cmd.upmove;
887
VectorCopy (wishvel, wishdir);
888
wishspeed = VectorNormalize(wishdir);
891
PM_Accelerate( wishdir, wishspeed, pm_accelerate );
894
VectorMA (pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin);
897
//============================================================================
901
PM_FootstepForSurface
903
Returns an event number apropriate for the groundsurface
906
static int PM_FootstepForSurface( void ) {
907
if ( pml.groundTrace.surfaceFlags & SURF_NOSTEPS ) {
910
if ( pml.groundTrace.surfaceFlags & SURF_METALSTEPS ) {
911
return EV_FOOTSTEP_METAL;
921
Check for hard landings that generate sound events
924
static void PM_CrashLand( void ) {
931
// decide which landing animation to use
932
if ( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) {
933
PM_ForceLegsAnim( LEGS_LANDB );
935
PM_ForceLegsAnim( LEGS_LAND );
938
pm->ps->legsTimer = TIMER_LAND;
940
// calculate the exact velocity on landing
941
dist = pm->ps->origin[2] - pml.previous_origin[2];
942
vel = pml.previous_velocity[2];
943
acc = -pm->ps->gravity;
949
den = b * b - 4 * a * c;
953
t = (-b - sqrt( den ) ) / ( 2 * a );
955
delta = vel + t * acc;
956
delta = delta*delta * 0.0001;
958
// ducking while falling doubles damage
959
if ( pm->ps->pm_flags & PMF_DUCKED ) {
963
// never take falling damage if completely underwater
964
if ( pm->waterlevel == 3 ) {
968
// reduce falling damage if there is standing water
969
if ( pm->waterlevel == 2 ) {
972
if ( pm->waterlevel == 1 ) {
980
// create a local entity event to play the sound
982
// SURF_NODAMAGE is used for bounce pads where you don't ever
983
// want to take damage or play a crunch sound
984
if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) ) {
986
PM_AddEvent( EV_FALL_FAR );
987
} else if ( delta > 40 ) {
988
// this is a pain grunt, so don't play it if dead
989
if ( pm->ps->stats[STAT_HEALTH] > 0 ) {
990
PM_AddEvent( EV_FALL_MEDIUM );
992
} else if ( delta > 7 ) {
993
PM_AddEvent( EV_FALL_SHORT );
995
PM_AddEvent( PM_FootstepForSurface() );
999
// start footstep cycle over
1000
pm->ps->bobCycle = 0;
1009
void PM_CheckStuck(void) {
1012
pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask);
1013
if (trace.allsolid) {
1024
static int PM_CorrectAllSolid( trace_t *trace ) {
1028
if ( pm->debugLevel ) {
1029
Com_Printf("%i:allsolid\n", c_pmove);
1033
for (i = -1; i <= 1; i++) {
1034
for (j = -1; j <= 1; j++) {
1035
for (k = -1; k <= 1; k++) {
1036
VectorCopy(pm->ps->origin, point);
1037
point[0] += (float) i;
1038
point[1] += (float) j;
1039
point[2] += (float) k;
1040
pm->trace (trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
1041
if ( !trace->allsolid ) {
1042
point[0] = pm->ps->origin[0];
1043
point[1] = pm->ps->origin[1];
1044
point[2] = pm->ps->origin[2] - 0.25;
1046
pm->trace (trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
1047
pml.groundTrace = *trace;
1054
pm->ps->groundEntityNum = ENTITYNUM_NONE;
1055
pml.groundPlane = qfalse;
1056
pml.walking = qfalse;
1064
PM_GroundTraceMissed
1066
The ground trace didn't hit a surface, so we are in freefall
1069
static void PM_GroundTraceMissed( void ) {
1073
if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) {
1074
// we just transitioned into freefall
1075
if ( pm->debugLevel ) {
1076
Com_Printf("%i:lift\n", c_pmove);
1079
// if they aren't in a jumping animation and the ground is a ways away, force into it
1080
// if we didn't do the trace, the player would be backflipping down staircases
1081
VectorCopy( pm->ps->origin, point );
1084
pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
1085
if ( trace.fraction == 1.0 ) {
1086
if ( pm->cmd.forwardmove >= 0 ) {
1087
PM_ForceLegsAnim( LEGS_JUMP );
1088
pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
1090
PM_ForceLegsAnim( LEGS_JUMPB );
1091
pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
1096
pm->ps->groundEntityNum = ENTITYNUM_NONE;
1097
pml.groundPlane = qfalse;
1098
pml.walking = qfalse;
1107
static void PM_GroundTrace( void ) {
1111
point[0] = pm->ps->origin[0];
1112
point[1] = pm->ps->origin[1];
1113
point[2] = pm->ps->origin[2] - 0.25;
1115
pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
1116
pml.groundTrace = trace;
1118
// do something corrective if the trace starts in a solid...
1119
if ( trace.allsolid ) {
1120
if ( !PM_CorrectAllSolid(&trace) )
1124
// if the trace didn't hit anything, we are in free fall
1125
if ( trace.fraction == 1.0 ) {
1126
PM_GroundTraceMissed();
1127
pml.groundPlane = qfalse;
1128
pml.walking = qfalse;
1132
// check if getting thrown off the ground
1133
if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) {
1134
if ( pm->debugLevel ) {
1135
Com_Printf("%i:kickoff\n", c_pmove);
1137
// go into jump animation
1138
if ( pm->cmd.forwardmove >= 0 ) {
1139
PM_ForceLegsAnim( LEGS_JUMP );
1140
pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
1142
PM_ForceLegsAnim( LEGS_JUMPB );
1143
pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
1146
pm->ps->groundEntityNum = ENTITYNUM_NONE;
1147
pml.groundPlane = qfalse;
1148
pml.walking = qfalse;
1152
// slopes that are too steep will not be considered onground
1153
if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) {
1154
if ( pm->debugLevel ) {
1155
Com_Printf("%i:steep\n", c_pmove);
1157
// FIXME: if they can't slide down the slope, let them
1158
// walk (sharp crevices)
1159
pm->ps->groundEntityNum = ENTITYNUM_NONE;
1160
pml.groundPlane = qtrue;
1161
pml.walking = qfalse;
1165
pml.groundPlane = qtrue;
1166
pml.walking = qtrue;
1168
// hitting solid ground will end a waterjump
1169
if (pm->ps->pm_flags & PMF_TIME_WATERJUMP)
1171
pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND);
1172
pm->ps->pm_time = 0;
1175
if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {
1176
// just hit the ground
1177
if ( pm->debugLevel ) {
1178
Com_Printf("%i:Land\n", c_pmove);
1183
// don't do landing time if we were just going down a slope
1184
if ( pml.previous_velocity[2] < -200 ) {
1185
// don't allow another jump for a little while
1186
pm->ps->pm_flags |= PMF_TIME_LAND;
1187
pm->ps->pm_time = 250;
1191
pm->ps->groundEntityNum = trace.entityNum;
1193
// don't reset the z velocity for slopes
1194
// pm->ps->velocity[2] = 0;
1196
PM_AddTouchEnt( trace.entityNum );
1202
PM_SetWaterLevel FIXME: avoid this twice? certainly if not moving
1205
static void PM_SetWaterLevel( void ) {
1212
// get waterlevel, accounting for ducking
1217
point[0] = pm->ps->origin[0];
1218
point[1] = pm->ps->origin[1];
1219
point[2] = pm->ps->origin[2] + MINS_Z + 1;
1220
cont = pm->pointcontents( point, pm->ps->clientNum );
1222
if ( cont & MASK_WATER ) {
1223
sample2 = pm->ps->viewheight - MINS_Z;
1224
sample1 = sample2 / 2;
1226
pm->watertype = cont;
1228
point[2] = pm->ps->origin[2] + MINS_Z + sample1;
1229
cont = pm->pointcontents (point, pm->ps->clientNum );
1230
if ( cont & MASK_WATER ) {
1232
point[2] = pm->ps->origin[2] + MINS_Z + sample2;
1233
cont = pm->pointcontents (point, pm->ps->clientNum );
1234
if ( cont & MASK_WATER ){
1246
Sets mins, maxs, and pm->ps->viewheight
1249
static void PM_CheckDuck (void)
1253
if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
1254
if ( pm->ps->pm_flags & PMF_INVULEXPAND ) {
1255
// invulnerability sphere has a 42 units radius
1256
VectorSet( pm->mins, -42, -42, -42 );
1257
VectorSet( pm->maxs, 42, 42, 42 );
1260
VectorSet( pm->mins, -15, -15, MINS_Z );
1261
VectorSet( pm->maxs, 15, 15, 16 );
1263
pm->ps->pm_flags |= PMF_DUCKED;
1264
pm->ps->viewheight = CROUCH_VIEWHEIGHT;
1267
pm->ps->pm_flags &= ~PMF_INVULEXPAND;
1275
pm->mins[2] = MINS_Z;
1277
if (pm->ps->pm_type == PM_DEAD)
1280
pm->ps->viewheight = DEAD_VIEWHEIGHT;
1284
if (pm->cmd.upmove < 0)
1286
pm->ps->pm_flags |= PMF_DUCKED;
1289
{ // stand up if possible
1290
if (pm->ps->pm_flags & PMF_DUCKED)
1294
pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask );
1295
if (!trace.allsolid)
1296
pm->ps->pm_flags &= ~PMF_DUCKED;
1300
if (pm->ps->pm_flags & PMF_DUCKED)
1303
pm->ps->viewheight = CROUCH_VIEWHEIGHT;
1308
pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
1314
//===================================================================
1322
static void PM_Footsteps( void ) {
1328
// calculate speed and cycle to be used for
1329
// all cyclic walking effects
1331
pm->xyspeed = sqrt( pm->ps->velocity[0] * pm->ps->velocity[0]
1332
+ pm->ps->velocity[1] * pm->ps->velocity[1] );
1334
if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {
1336
if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
1337
PM_ContinueLegsAnim( LEGS_IDLECR );
1339
// airborne leaves position in cycle intact, but doesn't advance
1340
if ( pm->waterlevel > 1 ) {
1341
PM_ContinueLegsAnim( LEGS_SWIM );
1346
// if not trying to move
1347
if ( !pm->cmd.forwardmove && !pm->cmd.rightmove ) {
1348
if ( pm->xyspeed < 5 ) {
1349
pm->ps->bobCycle = 0; // start at beginning of cycle again
1350
if ( pm->ps->pm_flags & PMF_DUCKED ) {
1351
PM_ContinueLegsAnim( LEGS_IDLECR );
1353
PM_ContinueLegsAnim( LEGS_IDLE );
1362
if ( pm->ps->pm_flags & PMF_DUCKED ) {
1363
bobmove = 0.5; // ducked characters bob much faster
1364
if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
1365
PM_ContinueLegsAnim( LEGS_BACKCR );
1368
PM_ContinueLegsAnim( LEGS_WALKCR );
1370
// ducked characters never play footsteps
1372
} else if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
1373
if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {
1374
bobmove = 0.4; // faster speeds bob faster
1379
PM_ContinueLegsAnim( LEGS_BACK );
1382
if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {
1383
bobmove = 0.4f; // faster speeds bob faster
1384
if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
1385
PM_ContinueLegsAnim( LEGS_BACK );
1388
PM_ContinueLegsAnim( LEGS_RUN );
1392
bobmove = 0.3f; // walking bobs slow
1393
if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
1394
PM_ContinueLegsAnim( LEGS_BACKWALK );
1397
PM_ContinueLegsAnim( LEGS_WALK );
1402
// check for footstep / splash sounds
1403
old = pm->ps->bobCycle;
1404
pm->ps->bobCycle = (int)( old + bobmove * pml.msec ) & 255;
1406
// if we just crossed a cycle boundary, play an apropriate footstep event
1407
if ( ( ( old + 64 ) ^ ( pm->ps->bobCycle + 64 ) ) & 128 ) {
1408
if ( pm->waterlevel == 0 ) {
1409
// on ground will only play sounds if running
1410
if ( footstep && !pm->noFootsteps ) {
1411
PM_AddEvent( PM_FootstepForSurface() );
1413
} else if ( pm->waterlevel == 1 ) {
1415
PM_AddEvent( EV_FOOTSPLASH );
1416
} else if ( pm->waterlevel == 2 ) {
1417
// wading / swimming at surface
1418
PM_AddEvent( EV_SWIM );
1419
} else if ( pm->waterlevel == 3 ) {
1420
// no sound when completely underwater
1430
Generate sound events for entering and leaving water
1433
static void PM_WaterEvents( void ) { // FIXME?
1435
// if just entered a water volume, play a sound
1437
if (!pml.previous_waterlevel && pm->waterlevel) {
1438
PM_AddEvent( EV_WATER_TOUCH );
1442
// if just completely exited a water volume, play a sound
1444
if (pml.previous_waterlevel && !pm->waterlevel) {
1445
PM_AddEvent( EV_WATER_LEAVE );
1449
// check for head just going under water
1451
if (pml.previous_waterlevel != 3 && pm->waterlevel == 3) {
1452
PM_AddEvent( EV_WATER_UNDER );
1456
// check for head just coming out of water
1458
if (pml.previous_waterlevel == 3 && pm->waterlevel != 3) {
1459
PM_AddEvent( EV_WATER_CLEAR );
1466
PM_BeginWeaponChange
1469
static void PM_BeginWeaponChange( int weapon ) {
1470
if ( weapon <= WP_NONE || weapon >= WP_NUM_WEAPONS ) {
1474
if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
1478
if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
1482
PM_AddEvent( EV_CHANGE_WEAPON );
1483
pm->ps->weaponstate = WEAPON_DROPPING;
1484
pm->ps->weaponTime += 200;
1485
PM_StartTorsoAnim( TORSO_DROP );
1491
PM_FinishWeaponChange
1494
static void PM_FinishWeaponChange( void ) {
1497
weapon = pm->cmd.weapon;
1498
if ( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS ) {
1502
if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
1506
pm->ps->weapon = weapon;
1507
pm->ps->weaponstate = WEAPON_RAISING;
1508
pm->ps->weaponTime += 250;
1509
PM_StartTorsoAnim( TORSO_RAISE );
1519
static void PM_TorsoAnimation( void ) {
1520
if ( pm->ps->weaponstate == WEAPON_READY ) {
1521
if ( pm->ps->weapon == WP_GAUNTLET ) {
1522
PM_ContinueTorsoAnim( TORSO_STAND2 );
1524
PM_ContinueTorsoAnim( TORSO_STAND );
1535
Generates weapon events and modifes the weapon counter
1538
static void PM_Weapon( void ) {
1541
// don't allow attack until all buttons are up
1542
if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
1546
// ignore if spectator
1547
if ( pm->ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
1551
// check for dead player
1552
if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
1553
pm->ps->weapon = WP_NONE;
1557
// check for item using
1558
if ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) {
1559
if ( ! ( pm->ps->pm_flags & PMF_USE_ITEM_HELD ) ) {
1560
if ( bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_MEDKIT
1561
&& pm->ps->stats[STAT_HEALTH] >= (pm->ps->stats[STAT_MAX_HEALTH] + 25) ) {
1562
// don't use medkit if at max health
1564
pm->ps->pm_flags |= PMF_USE_ITEM_HELD;
1565
PM_AddEvent( EV_USE_ITEM0 + bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag );
1566
pm->ps->stats[STAT_HOLDABLE_ITEM] = 0;
1571
pm->ps->pm_flags &= ~PMF_USE_ITEM_HELD;
1575
// make weapon function
1576
if ( pm->ps->weaponTime > 0 ) {
1577
pm->ps->weaponTime -= pml.msec;
1580
// check for weapon change
1581
// can't change if weapon is firing, but can change
1582
// again if lowering or raising
1583
if ( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING ) {
1584
if ( pm->ps->weapon != pm->cmd.weapon ) {
1585
PM_BeginWeaponChange( pm->cmd.weapon );
1589
if ( pm->ps->weaponTime > 0 ) {
1593
// change weapon if time
1594
if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
1595
PM_FinishWeaponChange();
1599
if ( pm->ps->weaponstate == WEAPON_RAISING ) {
1600
pm->ps->weaponstate = WEAPON_READY;
1601
if ( pm->ps->weapon == WP_GAUNTLET ) {
1602
PM_StartTorsoAnim( TORSO_STAND2 );
1604
PM_StartTorsoAnim( TORSO_STAND );
1610
if ( ! (pm->cmd.buttons & BUTTON_ATTACK) ) {
1611
pm->ps->weaponTime = 0;
1612
pm->ps->weaponstate = WEAPON_READY;
1616
// start the animation even if out of ammo
1617
if ( pm->ps->weapon == WP_GAUNTLET ) {
1618
// the guantlet only "fires" when it actually hits something
1619
if ( !pm->gauntletHit ) {
1620
pm->ps->weaponTime = 0;
1621
pm->ps->weaponstate = WEAPON_READY;
1624
PM_StartTorsoAnim( TORSO_ATTACK2 );
1626
PM_StartTorsoAnim( TORSO_ATTACK );
1629
pm->ps->weaponstate = WEAPON_FIRING;
1631
// check for out of ammo
1632
if ( ! pm->ps->ammo[ pm->ps->weapon ] ) {
1633
PM_AddEvent( EV_NOAMMO );
1634
pm->ps->weaponTime += 500;
1638
// take an ammo away if not infinite
1639
if ( pm->ps->ammo[ pm->ps->weapon ] != -1 ) {
1640
pm->ps->ammo[ pm->ps->weapon ]--;
1644
PM_AddEvent( EV_FIRE_WEAPON );
1646
switch( pm->ps->weapon ) {
1660
case WP_GRENADE_LAUNCHER:
1663
case WP_ROCKET_LAUNCHER:
1675
case WP_GRAPPLING_HOOK:
1682
case WP_PROX_LAUNCHER:
1692
if( bg_itemlist[pm->ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
1696
if( bg_itemlist[pm->ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_AMMOREGEN ) {
1701
if ( pm->ps->powerups[PW_HASTE] ) {
1705
pm->ps->weaponTime += addTime;
1714
static void PM_Animate( void ) {
1715
if ( pm->cmd.buttons & BUTTON_GESTURE ) {
1716
if ( pm->ps->torsoTimer == 0 ) {
1717
PM_StartTorsoAnim( TORSO_GESTURE );
1718
pm->ps->torsoTimer = TIMER_GESTURE;
1719
PM_AddEvent( EV_TAUNT );
1722
} else if ( pm->cmd.buttons & BUTTON_GETFLAG ) {
1723
if ( pm->ps->torsoTimer == 0 ) {
1724
PM_StartTorsoAnim( TORSO_GETFLAG );
1725
pm->ps->torsoTimer = 600; //TIMER_GESTURE;
1727
} else if ( pm->cmd.buttons & BUTTON_GUARDBASE ) {
1728
if ( pm->ps->torsoTimer == 0 ) {
1729
PM_StartTorsoAnim( TORSO_GUARDBASE );
1730
pm->ps->torsoTimer = 600; //TIMER_GESTURE;
1732
} else if ( pm->cmd.buttons & BUTTON_PATROL ) {
1733
if ( pm->ps->torsoTimer == 0 ) {
1734
PM_StartTorsoAnim( TORSO_PATROL );
1735
pm->ps->torsoTimer = 600; //TIMER_GESTURE;
1737
} else if ( pm->cmd.buttons & BUTTON_FOLLOWME ) {
1738
if ( pm->ps->torsoTimer == 0 ) {
1739
PM_StartTorsoAnim( TORSO_FOLLOWME );
1740
pm->ps->torsoTimer = 600; //TIMER_GESTURE;
1742
} else if ( pm->cmd.buttons & BUTTON_AFFIRMATIVE ) {
1743
if ( pm->ps->torsoTimer == 0 ) {
1744
PM_StartTorsoAnim( TORSO_AFFIRMATIVE);
1745
pm->ps->torsoTimer = 600; //TIMER_GESTURE;
1747
} else if ( pm->cmd.buttons & BUTTON_NEGATIVE ) {
1748
if ( pm->ps->torsoTimer == 0 ) {
1749
PM_StartTorsoAnim( TORSO_NEGATIVE );
1750
pm->ps->torsoTimer = 600; //TIMER_GESTURE;
1762
static void PM_DropTimers( void ) {
1763
// drop misc timing counter
1764
if ( pm->ps->pm_time ) {
1765
if ( pml.msec >= pm->ps->pm_time ) {
1766
pm->ps->pm_flags &= ~PMF_ALL_TIMES;
1767
pm->ps->pm_time = 0;
1769
pm->ps->pm_time -= pml.msec;
1773
// drop animation counter
1774
if ( pm->ps->legsTimer > 0 ) {
1775
pm->ps->legsTimer -= pml.msec;
1776
if ( pm->ps->legsTimer < 0 ) {
1777
pm->ps->legsTimer = 0;
1781
if ( pm->ps->torsoTimer > 0 ) {
1782
pm->ps->torsoTimer -= pml.msec;
1783
if ( pm->ps->torsoTimer < 0 ) {
1784
pm->ps->torsoTimer = 0;
1793
This can be used as another entry point when only the viewangles
1794
are being updated isntead of a full move
1797
void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) {
1801
if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION) {
1802
return; // no view changes at all
1805
if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) {
1806
return; // no view changes at all
1809
// circularly clamp the angles with deltas
1810
for (i=0 ; i<3 ; i++) {
1811
temp = cmd->angles[i] + ps->delta_angles[i];
1813
// don't let the player look up or down more than 90 degrees
1814
if ( temp > 16000 ) {
1815
ps->delta_angles[i] = 16000 - cmd->angles[i];
1817
} else if ( temp < -16000 ) {
1818
ps->delta_angles[i] = -16000 - cmd->angles[i];
1822
ps->viewangles[i] = SHORT2ANGLE(temp);
1834
void trap_SnapVector( float *v );
1836
void PmoveSingle (pmove_t *pmove) {
1839
// this counter lets us debug movement problems with a journal
1840
// by setting a conditional breakpoint fot the previous frame
1848
if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
1849
pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies
1852
// make sure walking button is clear if they are running, to avoid
1853
// proxy no-footsteps cheats
1854
if ( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 ) {
1855
pm->cmd.buttons &= ~BUTTON_WALKING;
1858
// set the talk balloon flag
1859
if ( pm->cmd.buttons & BUTTON_TALK ) {
1860
pm->ps->eFlags |= EF_TALK;
1862
pm->ps->eFlags &= ~EF_TALK;
1865
// set the firing flag for continuous beam weapons
1866
if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION
1867
&& ( pm->cmd.buttons & BUTTON_ATTACK ) && pm->ps->ammo[ pm->ps->weapon ] ) {
1868
pm->ps->eFlags |= EF_FIRING;
1870
pm->ps->eFlags &= ~EF_FIRING;
1873
// clear the respawned flag if attack and use are cleared
1874
if ( pm->ps->stats[STAT_HEALTH] > 0 &&
1875
!( pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE) ) ) {
1876
pm->ps->pm_flags &= ~PMF_RESPAWNED;
1879
// if talk button is down, dissallow all other input
1880
// this is to prevent any possible intercept proxy from
1881
// adding fake talk balloons
1882
if ( pmove->cmd.buttons & BUTTON_TALK ) {
1883
// keep the talk button set tho for when the cmd.serverTime > 66 msec
1884
// and the same cmd is used multiple times in Pmove
1885
pmove->cmd.buttons = BUTTON_TALK;
1886
pmove->cmd.forwardmove = 0;
1887
pmove->cmd.rightmove = 0;
1888
pmove->cmd.upmove = 0;
1891
// clear all pmove local vars
1892
memset (&pml, 0, sizeof(pml));
1894
// determine the time
1895
pml.msec = pmove->cmd.serverTime - pm->ps->commandTime;
1896
if ( pml.msec < 1 ) {
1898
} else if ( pml.msec > 200 ) {
1901
pm->ps->commandTime = pmove->cmd.serverTime;
1903
// save old org in case we get stuck
1904
VectorCopy (pm->ps->origin, pml.previous_origin);
1906
// save old velocity for crashlanding
1907
VectorCopy (pm->ps->velocity, pml.previous_velocity);
1909
pml.frametime = pml.msec * 0.001;
1911
// update the viewangles
1912
PM_UpdateViewAngles( pm->ps, &pm->cmd );
1914
AngleVectors (pm->ps->viewangles, pml.forward, pml.right, pml.up);
1916
if ( pm->cmd.upmove < 10 ) {
1918
pm->ps->pm_flags &= ~PMF_JUMP_HELD;
1921
// decide if backpedaling animations should be used
1922
if ( pm->cmd.forwardmove < 0 ) {
1923
pm->ps->pm_flags |= PMF_BACKWARDS_RUN;
1924
} else if ( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) {
1925
pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN;
1928
if ( pm->ps->pm_type >= PM_DEAD ) {
1929
pm->cmd.forwardmove = 0;
1930
pm->cmd.rightmove = 0;
1934
if ( pm->ps->pm_type == PM_SPECTATOR ) {
1941
if ( pm->ps->pm_type == PM_NOCLIP ) {
1947
if (pm->ps->pm_type == PM_FREEZE) {
1948
return; // no movement at all
1951
if ( pm->ps->pm_type == PM_INTERMISSION || pm->ps->pm_type == PM_SPINTERMISSION) {
1952
return; // no movement at all
1955
// set watertype, and waterlevel
1957
pml.previous_waterlevel = pmove->waterlevel;
1959
// set mins, maxs, and viewheight
1965
if ( pm->ps->pm_type == PM_DEAD ) {
1972
if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
1973
PM_InvulnerabilityMove();
1976
if ( pm->ps->powerups[PW_FLIGHT] ) {
1977
// flight powerup doesn't allow jump and has different friction
1979
} else if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) {
1981
// We can wiggle a bit
1983
} else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) {
1985
} else if ( pm->waterlevel > 1 ) {
1988
} else if ( pml.walking ) {
1989
// walking on ground
1998
// set groundentity, watertype, and waterlevel
2006
PM_TorsoAnimation();
2008
// footstep events / legs animations
2011
// entering / leaving water splashes
2014
// snap some parts of playerstate to save network bandwidth
2015
trap_SnapVector( pm->ps->velocity );
2023
Can be called by either the server or the client
2026
void Pmove (pmove_t *pmove) {
2029
finalTime = pmove->cmd.serverTime;
2031
if ( finalTime < pmove->ps->commandTime ) {
2032
return; // should not happen
2035
if ( finalTime > pmove->ps->commandTime + 1000 ) {
2036
pmove->ps->commandTime = finalTime - 1000;
2039
pmove->ps->pmove_framecount = (pmove->ps->pmove_framecount+1) & ((1<<PS_PMOVEFRAMECOUNTBITS)-1);
2041
// chop the move up if it is too long, to prevent framerate
2042
// dependent behavior
2043
while ( pmove->ps->commandTime != finalTime ) {
2046
msec = finalTime - pmove->ps->commandTime;
2048
if ( pmove->pmove_fixed ) {
2049
if ( msec > pmove->pmove_msec ) {
2050
msec = pmove->pmove_msec;
2058
pmove->cmd.serverTime = pmove->ps->commandTime + msec;
2059
PmoveSingle( pmove );
2061
if ( pmove->ps->pm_flags & PMF_JUMP_HELD ) {
2062
pmove->cmd.upmove = 20;