summaryrefslogtreecommitdiff
path: root/src/game/bg_pmove.c
diff options
context:
space:
mode:
authorTim Angus <tim@ngus.net>2005-12-10 03:18:22 +0000
committerTim Angus <tim@ngus.net>2005-12-10 03:18:22 +0000
commitef5d1d446e3c078b81882c2eda6525aee7ccfa1e (patch)
tree16c1e9460317f2ca507f8e1888216816d05f251c /src/game/bg_pmove.c
parent3b447421efc76ba76fbdae62f893fc6916af5433 (diff)
* Moved existing src directory out the way whilst I merge ioq3
Diffstat (limited to 'src/game/bg_pmove.c')
-rw-r--r--src/game/bg_pmove.c3471
1 files changed, 0 insertions, 3471 deletions
diff --git a/src/game/bg_pmove.c b/src/game/bg_pmove.c
deleted file mode 100644
index 88432f81..00000000
--- a/src/game/bg_pmove.c
+++ /dev/null
@@ -1,3471 +0,0 @@
-// Copyright (C) 1999-2000 Id Software, Inc.
-//
-// bg_pmove.c -- both games player movement code
-// takes a playerstate and a usercmd as input and returns a modifed playerstate
-
-/*
- * Portions Copyright (C) 2000-2001 Tim Angus
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the OSML - Open Source Modification License v1.0 as
- * described in the file COPYING which is distributed with this source
- * code.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#include "q_shared.h"
-#include "bg_public.h"
-#include "bg_local.h"
-
-pmove_t *pm;
-pml_t pml;
-
-// movement parameters
-float pm_stopspeed = 100.0f;
-float pm_duckScale = 0.25f;
-float pm_swimScale = 0.50f;
-float pm_wadeScale = 0.70f;
-
-float pm_accelerate = 10.0f;
-float pm_airaccelerate = 1.0f;
-float pm_wateraccelerate = 4.0f;
-float pm_flyaccelerate = 4.0f;
-
-float pm_friction = 6.0f;
-float pm_waterfriction = 1.0f;
-float pm_flightfriction = 6.0f;
-float pm_spectatorfriction = 5.0f;
-
-int c_pmove = 0;
-
-/*
-===============
-PM_AddEvent
-
-===============
-*/
-void PM_AddEvent( int newEvent )
-{
- BG_AddPredictableEventToPlayerstate( newEvent, 0, pm->ps );
-}
-
-/*
-===============
-PM_AddTouchEnt
-===============
-*/
-void PM_AddTouchEnt( int entityNum )
-{
- int i;
-
- if( entityNum == ENTITYNUM_WORLD )
- return;
-
- if( pm->numtouch == MAXTOUCH )
- return;
-
- // see if it is already added
- for( i = 0 ; i < pm->numtouch ; i++ )
- {
- if( pm->touchents[ i ] == entityNum )
- return;
- }
-
- // add it
- pm->touchents[ pm->numtouch ] = entityNum;
- pm->numtouch++;
-}
-
-/*
-===================
-PM_StartTorsoAnim
-===================
-*/
-static void PM_StartTorsoAnim( int anim )
-{
- if( pm->ps->pm_type >= PM_DEAD )
- return;
-
- pm->ps->torsoAnim = ( ( pm->ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
- | anim;
-}
-
-/*
-===================
-PM_StartLegsAnim
-===================
-*/
-static void PM_StartLegsAnim( int anim )
-{
- if( pm->ps->pm_type >= PM_DEAD )
- return;
-
- //legsTimer is clamped too tightly for nonsegmented models
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- {
- if( pm->ps->legsTimer > 0 )
- return; // a high priority animation is running
- }
- else
- {
- if( pm->ps->torsoTimer > 0 )
- return; // a high priority animation is running
- }
-
- pm->ps->legsAnim = ( ( pm->ps->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
- | anim;
-}
-
-/*
-===================
-PM_ContinueLegsAnim
-===================
-*/
-static void PM_ContinueLegsAnim( int anim )
-{
- if( ( pm->ps->legsAnim & ~ANIM_TOGGLEBIT ) == anim )
- return;
-
- //legsTimer is clamped too tightly for nonsegmented models
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- {
- if( pm->ps->legsTimer > 0 )
- return; // a high priority animation is running
- }
- else
- {
- if( pm->ps->torsoTimer > 0 )
- return; // a high priority animation is running
- }
-
- PM_StartLegsAnim( anim );
-}
-
-/*
-===================
-PM_ContinueTorsoAnim
-===================
-*/
-static void PM_ContinueTorsoAnim( int anim )
-{
- if( ( pm->ps->torsoAnim & ~ANIM_TOGGLEBIT ) == anim )
- return;
-
- if( pm->ps->torsoTimer > 0 )
- return; // a high priority animation is running
-
- PM_StartTorsoAnim( anim );
-}
-
-/*
-===================
-PM_ForceLegsAnim
-===================
-*/
-static void PM_ForceLegsAnim( int anim )
-{
- //legsTimer is clamped too tightly for nonsegmented models
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- pm->ps->legsTimer = 0;
- else
- pm->ps->torsoTimer = 0;
-
- PM_StartLegsAnim( anim );
-}
-
-
-/*
-==================
-PM_ClipVelocity
-
-Slide off of the impacting surface
-==================
-*/
-void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce )
-{
- float backoff;
- float change;
- int i;
-
- backoff = DotProduct( in, normal );
-
- //Com_Printf( "%1.0f ", backoff );
-
- if( backoff < 0 )
- backoff *= overbounce;
- else
- backoff /= overbounce;
-
- for( i = 0; i < 3; i++ )
- {
- change = normal[ i ] * backoff;
- //Com_Printf( "%1.0f ", change );
- out[ i ] = in[ i ] - change;
- }
-
- //Com_Printf( " " );
-}
-
-
-/*
-==================
-PM_Friction
-
-Handles both ground friction and water friction
-==================
-*/
-static void PM_Friction( void )
-{
- vec3_t vec;
- float *vel;
- float speed, newspeed, control;
- float drop;
-
- vel = pm->ps->velocity;
-
- //TA: make sure vertical velocity is NOT set to zero when wall climbing
- VectorCopy( vel, vec );
- if( pml.walking && !( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) )
- vec[ 2 ] = 0; // ignore slope movement
-
- speed = VectorLength( vec );
-
- if( speed < 1 )
- {
- vel[ 0 ] = 0;
- vel[ 1 ] = 0; // allow sinking underwater
- // FIXME: still have z friction underwater?
- return;
- }
-
- drop = 0;
-
- // apply ground friction
- if( pm->waterlevel <= 1 )
- {
- if( ( pml.walking || pml.ladder ) && !( pml.groundTrace.surfaceFlags & SURF_SLICK ) )
- {
- // if getting knocked back, no friction
- if( !( pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) )
- {
- float stopSpeed = BG_FindStopSpeedForClass( pm->ps->stats[ STAT_PCLASS ] );
-
- control = speed < stopSpeed ? stopSpeed : speed;
- drop += control * BG_FindFrictionForClass( pm->ps->stats[ STAT_PCLASS ] ) * pml.frametime;
- }
- }
- }
-
- // apply water friction even if just wading
- if( pm->waterlevel )
- drop += speed * pm_waterfriction * pm->waterlevel * pml.frametime;
-
- // apply flying friction
- if( pm->ps->pm_type == PM_JETPACK )
- drop += speed * pm_flightfriction * pml.frametime;
-
- if( pm->ps->pm_type == PM_SPECTATOR )
- drop += speed * pm_spectatorfriction * pml.frametime;
-
- // scale the velocity
- newspeed = speed - drop;
- if( newspeed < 0 )
- newspeed = 0;
-
- newspeed /= speed;
-
- vel[ 0 ] = vel[ 0 ] * newspeed;
- vel[ 1 ] = vel[ 1 ] * newspeed;
- vel[ 2 ] = vel[ 2 ] * newspeed;
-}
-
-
-/*
-==============
-PM_Accelerate
-
-Handles user intended acceleration
-==============
-*/
-static void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel )
-{
-#if 1
- // q2 style
- int i;
- float addspeed, accelspeed, currentspeed;
-
- currentspeed = DotProduct( pm->ps->velocity, wishdir );
- addspeed = wishspeed - currentspeed;
- if( addspeed <= 0 )
- return;
-
- accelspeed = accel * pml.frametime * wishspeed;
- if( accelspeed > addspeed )
- accelspeed = addspeed;
-
- for( i = 0; i < 3; i++ )
- pm->ps->velocity[ i ] += accelspeed * wishdir[ i ];
-#else
- // proper way (avoids strafe jump maxspeed bug), but feels bad
- vec3_t wishVelocity;
- vec3_t pushDir;
- float pushLen;
- float canPush;
-
- VectorScale( wishdir, wishspeed, wishVelocity );
- VectorSubtract( wishVelocity, pm->ps->velocity, pushDir );
- pushLen = VectorNormalize( pushDir );
-
- canPush = accel * pml.frametime * wishspeed;
- if( canPush > pushLen )
- canPush = pushLen;
-
- VectorMA( pm->ps->velocity, canPush, pushDir, pm->ps->velocity );
-#endif
-}
-
-
-
-/*
-============
-PM_CmdScale
-
-Returns the scale factor to apply to cmd movements
-This allows the clients to use axial -127 to 127 values for all directions
-without getting a sqrt(2) distortion in speed.
-============
-*/
-static float PM_CmdScale( usercmd_t *cmd )
-{
- int max;
- float total;
- float scale;
- float modifier = 1.0f;
-
- if( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS && pm->ps->pm_type == PM_NORMAL )
- {
- if( pm->ps->stats[ STAT_STATE ] & SS_SPEEDBOOST )
- modifier *= HUMAN_SPRINT_MODIFIER;
- else
- modifier *= HUMAN_JOG_MODIFIER;
-
- if( cmd->forwardmove < 0 )
- {
- //can't run backwards
- modifier *= HUMAN_BACK_MODIFIER;
- }
- else if( cmd->rightmove )
- {
- //can't move that fast sideways
- modifier *= HUMAN_SIDE_MODIFIER;
- }
-
- //must have +ve stamina to jump
- if( pm->ps->stats[ STAT_STAMINA ] < 0 )
- cmd->upmove = 0;
-
- //slow down once stamina depletes
- if( pm->ps->stats[ STAT_STAMINA ] <= -500 )
- modifier *= (float)( pm->ps->stats[ STAT_STAMINA ] + 1000 ) / 500.0f;
-
- if( pm->ps->stats[ STAT_STATE ] & SS_CREEPSLOWED )
- {
- if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, pm->ps->stats ) ||
- BG_InventoryContainsUpgrade( UP_BATTLESUIT, pm->ps->stats ) )
- modifier *= CREEP_ARMOUR_MODIFIER;
- else
- modifier *= CREEP_MODIFIER;
- }
- }
-
- if( pm->ps->weapon == WP_ALEVEL4 && pm->ps->pm_flags & PMF_CHARGE )
- modifier *= ( 1.0f + ( pm->ps->stats[ STAT_MISC ] / (float)LEVEL4_CHARGE_TIME ) *
- ( LEVEL4_CHARGE_SPEED - 1.0f ) );
-
- //slow player if charging up for a pounce
- if( ( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG ) &&
- cmd->buttons & BUTTON_ATTACK2 )
- modifier *= LEVEL3_POUNCE_SPEED_MOD;
-
- //slow the player if slow locked
- if( pm->ps->stats[ STAT_STATE ] & SS_SLOWLOCKED )
- modifier *= ABUILDER_BLOB_SPEED_MOD;
-
- if( pm->ps->pm_type == PM_GRABBED )
- modifier = 0.0f;
-
- if( pm->ps->pm_type != PM_SPECTATOR && pm->ps->pm_type != PM_NOCLIP )
- {
- if( BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] ) == 0.0f )
- cmd->upmove = 0;
-
- //prevent speed distortions for non ducking classes
- if( !( pm->ps->pm_flags & PMF_DUCKED ) && pm->ps->pm_type != PM_JETPACK && cmd->upmove < 0 )
- cmd->upmove = 0;
- }
-
- max = abs( cmd->forwardmove );
- if( abs( cmd->rightmove ) > max )
- max = abs( cmd->rightmove );
-
- if( abs( cmd->upmove ) > max )
- max = abs( cmd->upmove );
-
- if( !max )
- return 0;
-
- total = sqrt( cmd->forwardmove * cmd->forwardmove
- + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove );
-
- scale = (float)pm->ps->speed * max / ( 127.0 * total ) * modifier;
-
- return scale;
-}
-
-
-/*
-================
-PM_SetMovementDir
-
-Determine the rotation of the legs reletive
-to the facing dir
-================
-*/
-static void PM_SetMovementDir( void )
-{
- if( pm->cmd.forwardmove || pm->cmd.rightmove )
- {
- if( pm->cmd.rightmove == 0 && pm->cmd.forwardmove > 0 )
- pm->ps->movementDir = 0;
- else if( pm->cmd.rightmove < 0 && pm->cmd.forwardmove > 0 )
- pm->ps->movementDir = 1;
- else if( pm->cmd.rightmove < 0 && pm->cmd.forwardmove == 0 )
- pm->ps->movementDir = 2;
- else if( pm->cmd.rightmove < 0 && pm->cmd.forwardmove < 0 )
- pm->ps->movementDir = 3;
- else if( pm->cmd.rightmove == 0 && pm->cmd.forwardmove < 0 )
- pm->ps->movementDir = 4;
- else if( pm->cmd.rightmove > 0 && pm->cmd.forwardmove < 0 )
- pm->ps->movementDir = 5;
- else if( pm->cmd.rightmove > 0 && pm->cmd.forwardmove == 0 )
- pm->ps->movementDir = 6;
- else if( pm->cmd.rightmove > 0 && pm->cmd.forwardmove > 0 )
- pm->ps->movementDir = 7;
- }
- else
- {
- // if they aren't actively going directly sideways,
- // change the animation to the diagonal so they
- // don't stop too crooked
- if( pm->ps->movementDir == 2 )
- pm->ps->movementDir = 1;
- else if( pm->ps->movementDir == 6 )
- pm->ps->movementDir = 7;
- }
-}
-
-
-/*
-=============
-PM_CheckCharge
-=============
-*/
-static void PM_CheckCharge( void )
-{
- if( pm->ps->weapon != WP_ALEVEL4 )
- return;
-
- if( pm->cmd.buttons & BUTTON_ATTACK2 &&
- !( pm->ps->stats[ STAT_STATE ] & SS_CHARGING ) )
- {
- pm->ps->pm_flags &= ~PMF_CHARGE;
- return;
- }
-
- if( pm->ps->stats[ STAT_MISC ] > 0 )
- pm->ps->pm_flags |= PMF_CHARGE;
- else
- pm->ps->pm_flags &= ~PMF_CHARGE;
-}
-
-/*
-=============
-PM_CheckPounce
-=============
-*/
-static qboolean PM_CheckPounce( void )
-{
- if( pm->ps->weapon != WP_ALEVEL3 &&
- pm->ps->weapon != WP_ALEVEL3_UPG )
- return qfalse;
-
- if( pm->cmd.buttons & BUTTON_ATTACK2 )
- {
- pm->ps->pm_flags &= ~PMF_CHARGE;
- return qfalse;
- }
-
- if( pm->ps->pm_flags & PMF_CHARGE )
- return qfalse;
-
- if( pm->ps->stats[ STAT_MISC ] == 0 )
- return qfalse;
-
- pml.groundPlane = qfalse; // jumping away
- pml.walking = qfalse;
-
- pm->ps->pm_flags |= PMF_CHARGE;
-
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
-
- VectorMA( pm->ps->velocity, pm->ps->stats[ STAT_MISC ], pml.forward, pm->ps->velocity );
-
- PM_AddEvent( EV_JUMP );
-
- if( pm->cmd.forwardmove >= 0 )
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ForceLegsAnim( LEGS_JUMP );
- else
- PM_ForceLegsAnim( NSPA_JUMP );
-
- pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
- }
- else
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ForceLegsAnim( LEGS_JUMPB );
- else
- PM_ForceLegsAnim( NSPA_JUMPBACK );
-
- pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
- }
-
- return qtrue;
-}
-
-/*
-=============
-PM_CheckWallJump
-=============
-*/
-static qboolean PM_CheckWallJump( void )
-{
- vec3_t dir, forward, right;
- vec3_t refNormal = { 0.0f, 0.0f, 1.0f };
- float normalFraction = 1.5f;
- float cmdFraction = 1.0f;
- float upFraction = 1.5f;
-
- 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
- return qfalse;
-
- if( pm->ps->pm_flags & PMF_TIME_WALLJUMP )
- return qfalse;
-
- // must wait for jump to be released
- if( pm->ps->pm_flags & PMF_JUMP_HELD &&
- pm->ps->grapplePoint[ 2 ] == 1.0f )
- {
- // clear upmove so cmdscale doesn't lower running speed
- pm->cmd.upmove = 0;
- return qfalse;
- }
-
- pm->ps->pm_flags |= PMF_TIME_WALLJUMP;
- pm->ps->pm_time = 200;
-
- pml.groundPlane = qfalse; // jumping away
- pml.walking = qfalse;
- pm->ps->pm_flags |= PMF_JUMP_HELD;
-
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
-
- ProjectPointOnPlane( forward, pml.forward, pm->ps->grapplePoint );
- ProjectPointOnPlane( right, pml.right, pm->ps->grapplePoint );
-
- VectorScale( pm->ps->grapplePoint, normalFraction, dir );
-
- if( pm->cmd.forwardmove > 0 )
- VectorMA( dir, cmdFraction, forward, dir );
- else if( pm->cmd.forwardmove < 0 )
- VectorMA( dir, -cmdFraction, forward, dir );
-
- if( pm->cmd.rightmove > 0 )
- VectorMA( dir, cmdFraction, right, dir );
- else if( pm->cmd.rightmove < 0 )
- VectorMA( dir, -cmdFraction, right, dir );
-
- VectorMA( dir, upFraction, refNormal, dir );
- VectorNormalize( dir );
-
- VectorMA( pm->ps->velocity, BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] ),
- dir, pm->ps->velocity );
-
- //for a long run of wall jumps the velocity can get pretty large, this caps it
- if( VectorLength( pm->ps->velocity ) > LEVEL2_WALLJUMP_MAXSPEED )
- {
- VectorNormalize( pm->ps->velocity );
- VectorScale( pm->ps->velocity, LEVEL2_WALLJUMP_MAXSPEED, pm->ps->velocity );
- }
-
- PM_AddEvent( EV_JUMP );
-
- if( pm->cmd.forwardmove >= 0 )
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ForceLegsAnim( LEGS_JUMP );
- else
- PM_ForceLegsAnim( NSPA_JUMP );
-
- pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
- }
- else
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ForceLegsAnim( LEGS_JUMPB );
- else
- PM_ForceLegsAnim( NSPA_JUMPBACK );
-
- pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
- }
-
- return qtrue;
-}
-
-/*
-=============
-PM_CheckJump
-=============
-*/
-static qboolean PM_CheckJump( void )
-{
- if( BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] ) == 0.0f )
- return qfalse;
-
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) )
- return PM_CheckWallJump( );
-
- //can't jump and pounce at the same time
- if( ( pm->ps->weapon == WP_ALEVEL3 ||
- pm->ps->weapon == WP_ALEVEL3_UPG ) &&
- pm->ps->stats[ STAT_MISC ] > 0 )
- return qfalse;
-
- //can't jump and charge at the same time
- if( ( pm->ps->weapon == WP_ALEVEL4 ) &&
- pm->ps->stats[ STAT_MISC ] > 0 )
- return qfalse;
-
- if( ( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS ) &&
- ( pm->ps->stats[ STAT_STAMINA ] < 0 ) )
- return qfalse;
-
- 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
- return qfalse;
-
- //can't jump whilst grabbed
- if( pm->ps->pm_type == PM_GRABBED )
- {
- pm->cmd.upmove = 0;
- return qfalse;
- }
-
- // must wait for jump to be released
- if( pm->ps->pm_flags & PMF_JUMP_HELD )
- {
- // clear upmove so cmdscale doesn't lower running speed
- pm->cmd.upmove = 0;
- return qfalse;
- }
-
- pml.groundPlane = qfalse; // jumping away
- pml.walking = qfalse;
- pm->ps->pm_flags |= PMF_JUMP_HELD;
-
- //TA: take some stamina off
- if( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS )
- pm->ps->stats[ STAT_STAMINA ] -= 500;
-
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
-
- //TA: jump away from wall
- if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
- {
- vec3_t normal = { 0, 0, -1 };
-
- if( !( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) )
- VectorCopy( pm->ps->grapplePoint, normal );
-
- VectorMA( pm->ps->velocity, BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] ),
- normal, pm->ps->velocity );
- }
- else
- pm->ps->velocity[ 2 ] = BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] );
-
- PM_AddEvent( EV_JUMP );
-
- if( pm->cmd.forwardmove >= 0 )
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ForceLegsAnim( LEGS_JUMP );
- else
- PM_ForceLegsAnim( NSPA_JUMP );
-
- pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
- }
- else
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ForceLegsAnim( LEGS_JUMPB );
- else
- PM_ForceLegsAnim( NSPA_JUMPBACK );
-
- pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
- }
-
- return qtrue;
-}
-
-/*
-=============
-PM_CheckWaterJump
-=============
-*/
-static qboolean PM_CheckWaterJump( void )
-{
- vec3_t spot;
- int cont;
- vec3_t flatforward;
-
- if( pm->ps->pm_time )
- return qfalse;
-
- // check for water jump
- if( pm->waterlevel != 2 )
- return qfalse;
-
- flatforward[ 0 ] = pml.forward[ 0 ];
- flatforward[ 1 ] = pml.forward[ 1 ];
- flatforward[ 2 ] = 0;
- VectorNormalize( flatforward );
-
- VectorMA( pm->ps->origin, 30, flatforward, spot );
- spot[ 2 ] += 4;
- cont = pm->pointcontents( spot, pm->ps->clientNum );
-
- if( !( cont & CONTENTS_SOLID ) )
- return qfalse;
-
- spot[ 2 ] += 16;
- cont = pm->pointcontents( spot, pm->ps->clientNum );
-
- if( cont )
- return qfalse;
-
- // jump out of water
- VectorScale( pml.forward, 200, pm->ps->velocity );
- pm->ps->velocity[ 2 ] = 350;
-
- pm->ps->pm_flags |= PMF_TIME_WATERJUMP;
- pm->ps->pm_time = 2000;
-
- return qtrue;
-}
-
-//============================================================================
-
-
-/*
-===================
-PM_WaterJumpMove
-
-Flying out of the water
-===================
-*/
-static void PM_WaterJumpMove( void )
-{
- // waterjump has no control, but falls
-
- PM_StepSlideMove( qtrue, qfalse );
-
- pm->ps->velocity[ 2 ] -= pm->ps->gravity * pml.frametime;
- if( pm->ps->velocity[ 2 ] < 0 )
- {
- // cancel as soon as we are falling down again
- pm->ps->pm_flags &= ~PMF_ALL_TIMES;
- pm->ps->pm_time = 0;
- }
-}
-
-/*
-===================
-PM_WaterMove
-
-===================
-*/
-static void PM_WaterMove( void )
-{
- int i;
- vec3_t wishvel;
- float wishspeed;
- vec3_t wishdir;
- float scale;
- float vel;
-
- if( PM_CheckWaterJump( ) )
- {
- PM_WaterJumpMove();
- return;
- }
-#if 0
- // jump = head for surface
- if ( pm->cmd.upmove >= 10 ) {
- if (pm->ps->velocity[2] > -300) {
- if ( pm->watertype == CONTENTS_WATER ) {
- pm->ps->velocity[2] = 100;
- } else if (pm->watertype == CONTENTS_SLIME) {
- pm->ps->velocity[2] = 80;
- } else {
- pm->ps->velocity[2] = 50;
- }
- }
- }
-#endif
- PM_Friction( );
-
- scale = PM_CmdScale( &pm->cmd );
- //
- // user intentions
- //
- if( !scale )
- {
- wishvel[ 0 ] = 0;
- wishvel[ 1 ] = 0;
- wishvel[ 2 ] = -60; // sink towards bottom
- }
- else
- {
- for( i = 0; i < 3; i++ )
- wishvel[ i ] = scale * pml.forward[ i ] * pm->cmd.forwardmove + scale * pml.right[ i ] * pm->cmd.rightmove;
-
- wishvel[ 2 ] += scale * pm->cmd.upmove;
- }
-
- VectorCopy( wishvel, wishdir );
- wishspeed = VectorNormalize( wishdir );
-
- if( wishspeed > pm->ps->speed * pm_swimScale )
- wishspeed = pm->ps->speed * pm_swimScale;
-
- PM_Accelerate( wishdir, wishspeed, pm_wateraccelerate );
-
- // make sure we can go up slopes easily under water
- if( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 )
- {
- vel = VectorLength( pm->ps->velocity );
- // slide along the ground plane
- PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
-
- VectorNormalize( pm->ps->velocity );
- VectorScale( pm->ps->velocity, vel, pm->ps->velocity );
- }
-
- PM_SlideMove( qfalse );
-}
-
-/*
-===================
-PM_JetPackMove
-
-Only with the jetpack
-===================
-*/
-static void PM_JetPackMove( void )
-{
- int i;
- vec3_t wishvel;
- float wishspeed;
- vec3_t wishdir;
- float scale;
-
- //normal slowdown
- PM_Friction( );
-
- scale = PM_CmdScale( &pm->cmd );
-
- // user intentions
- for( i = 0; i < 2; i++ )
- wishvel[ i ] = scale * pml.forward[ i ] * pm->cmd.forwardmove + scale * pml.right[ i ] * pm->cmd.rightmove;
-
- if( pm->cmd.upmove > 0.0f )
- wishvel[ 2 ] = JETPACK_FLOAT_SPEED;
- if( pm->cmd.upmove < 0.0f )
- wishvel[ 2 ] = -JETPACK_SINK_SPEED;
-
- VectorCopy( wishvel, wishdir );
- wishspeed = VectorNormalize( wishdir );
-
- PM_Accelerate( wishdir, wishspeed, pm_flyaccelerate );
-
- PM_StepSlideMove( qfalse, qfalse );
-
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ContinueLegsAnim( LEGS_LAND );
- else
- PM_ContinueLegsAnim( NSPA_LAND );
-}
-
-
-
-
-/*
-===================
-PM_FlyMove
-
-Only with the flight powerup
-===================
-*/
-static void PM_FlyMove( void )
-{
- int i;
- vec3_t wishvel;
- float wishspeed;
- vec3_t wishdir;
- float scale;
-
- // normal slowdown
- PM_Friction( );
-
- scale = PM_CmdScale( &pm->cmd );
- //
- // user intentions
- //
- if( !scale )
- {
- wishvel[ 0 ] = 0;
- wishvel[ 1 ] = 0;
- wishvel[ 2 ] = 0;
- }
- else
- {
- for( i = 0; i < 3; i++ )
- wishvel[ i ] = scale * pml.forward[ i ] * pm->cmd.forwardmove + scale * pml.right[ i ] * pm->cmd.rightmove;
-
- wishvel[ 2 ] += scale * pm->cmd.upmove;
- }
-
- VectorCopy( wishvel, wishdir );
- wishspeed = VectorNormalize( wishdir );
-
- PM_Accelerate( wishdir, wishspeed, pm_flyaccelerate );
-
- PM_StepSlideMove( qfalse, qfalse );
-}
-
-
-/*
-===================
-PM_AirMove
-
-===================
-*/
-static void PM_AirMove( void )
-{
- int i;
- vec3_t wishvel;
- float fmove, smove;
- vec3_t wishdir;
- float wishspeed;
- float scale;
- usercmd_t cmd;
-
- PM_Friction( );
-
- fmove = pm->cmd.forwardmove;
- smove = pm->cmd.rightmove;
-
- cmd = pm->cmd;
- scale = PM_CmdScale( &cmd );
-
- // set the movementDir so clients can rotate the legs for strafing
- PM_SetMovementDir( );
-
- // project moves down to flat plane
- pml.forward[ 2 ] = 0;
- pml.right[ 2 ] = 0;
- VectorNormalize( pml.forward );
- VectorNormalize( pml.right );
-
- for( i = 0; i < 2; i++ )
- wishvel[ i ] = pml.forward[ i ] * fmove + pml.right[ i ] * smove;
-
- wishvel[ 2 ] = 0;
-
- VectorCopy( wishvel, wishdir );
- wishspeed = VectorNormalize( wishdir );
- wishspeed *= scale;
-
- // not on ground, so little effect on velocity
- PM_Accelerate( wishdir, wishspeed,
- BG_FindAirAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] ) );
-
- // we may have a ground plane that is very steep, even
- // though we don't have a groundentity
- // slide along the steep plane
- if( pml.groundPlane )
- PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
-
- PM_StepSlideMove( qtrue, qfalse );
-}
-
-/*
-===================
-PM_ClimbMove
-
-===================
-*/
-static void PM_ClimbMove( void )
-{
- int i;
- vec3_t wishvel;
- float fmove, smove;
- vec3_t wishdir;
- float wishspeed;
- float scale;
- usercmd_t cmd;
- float accelerate;
- float vel;
-
- if( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 )
- {
- // begin swimming
- PM_WaterMove( );
- return;
- }
-
-
- if( PM_CheckJump( ) || PM_CheckPounce( ) )
- {
- // jumped away
- if( pm->waterlevel > 1 )
- PM_WaterMove( );
- else
- PM_AirMove( );
-
- return;
- }
-
- PM_Friction( );
-
- fmove = pm->cmd.forwardmove;
- smove = pm->cmd.rightmove;
-
- cmd = pm->cmd;
- scale = PM_CmdScale( &cmd );
-
- // set the movementDir so clients can rotate the legs for strafing
- PM_SetMovementDir( );
-
- // project the forward and right directions onto the ground plane
- PM_ClipVelocity( pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP );
- PM_ClipVelocity( pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP );
- //
- VectorNormalize( pml.forward );
- VectorNormalize( pml.right );
-
- for( i = 0; i < 3; i++ )
- wishvel[ i ] = pml.forward[ i ] * fmove + pml.right[ i ] * smove;
-
- // when going up or down slopes the wish velocity should Not be zero
-// wishvel[2] = 0;
-
- VectorCopy( wishvel, wishdir );
- wishspeed = VectorNormalize( wishdir );
- wishspeed *= scale;
-
- // clamp the speed lower if ducking
- if( pm->ps->pm_flags & PMF_DUCKED )
- {
- if( wishspeed > pm->ps->speed * pm_duckScale )
- wishspeed = pm->ps->speed * pm_duckScale;
- }
-
- // clamp the speed lower if wading or walking on the bottom
- if( pm->waterlevel )
- {
- float waterScale;
-
- waterScale = pm->waterlevel / 3.0;
- waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale;
- if( wishspeed > pm->ps->speed * waterScale )
- wishspeed = pm->ps->speed * waterScale;
- }
-
- // when a player gets hit, they temporarily lose
- // full control, which allows them to be moved a bit
- if( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK )
- accelerate = BG_FindAirAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] );
- else
- accelerate = BG_FindAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] );
-
- PM_Accelerate( wishdir, wishspeed, accelerate );
-
- if( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK )
- pm->ps->velocity[ 2 ] -= pm->ps->gravity * pml.frametime;
-
- vel = VectorLength( pm->ps->velocity );
-
- // slide along the ground plane
- PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
-
- // don't decrease velocity when going up or down a slope
- VectorNormalize( pm->ps->velocity );
- VectorScale( pm->ps->velocity, vel, pm->ps->velocity );
-
- // don't do anything if standing still
- if( !pm->ps->velocity[ 0 ] && !pm->ps->velocity[ 1 ] && !pm->ps->velocity[ 2 ] )
- return;
-
- PM_StepSlideMove( qfalse, qfalse );
-}
-
-
-/*
-===================
-PM_WalkMove
-
-===================
-*/
-static void PM_WalkMove( void )
-{
- int i;
- vec3_t wishvel;
- float fmove, smove;
- vec3_t wishdir;
- float wishspeed;
- float scale;
- usercmd_t cmd;
- float accelerate;
- float vel;
-
- if( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 )
- {
- // begin swimming
- PM_WaterMove( );
- return;
- }
-
-
- if( PM_CheckJump( ) || PM_CheckPounce( ) )
- {
- // jumped away
- if( pm->waterlevel > 1 )
- PM_WaterMove( );
- else
- PM_AirMove( );
-
- return;
- }
-
- //charging
- PM_CheckCharge( );
-
- PM_Friction( );
-
- fmove = pm->cmd.forwardmove;
- smove = pm->cmd.rightmove;
-
- cmd = pm->cmd;
- scale = PM_CmdScale( &cmd );
-
- // set the movementDir so clients can rotate the legs for strafing
- PM_SetMovementDir( );
-
- // project moves down to flat plane
- pml.forward[ 2 ] = 0;
- pml.right[ 2 ] = 0;
-
- // project the forward and right directions onto the ground plane
- PM_ClipVelocity( pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP );
- PM_ClipVelocity( pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP );
- //
- VectorNormalize( pml.forward );
- VectorNormalize( pml.right );
-
- for( i = 0; i < 3; i++ )
- wishvel[ i ] = pml.forward[ i ] * fmove + pml.right[ i ] * smove;
-
- // when going up or down slopes the wish velocity should Not be zero
-// wishvel[2] = 0;
-
- VectorCopy( wishvel, wishdir );
- wishspeed = VectorNormalize( wishdir );
- wishspeed *= scale;
-
- // clamp the speed lower if ducking
- if( pm->ps->pm_flags & PMF_DUCKED )
- {
- if( wishspeed > pm->ps->speed * pm_duckScale )
- wishspeed = pm->ps->speed * pm_duckScale;
- }
-
- // clamp the speed lower if wading or walking on the bottom
- if( pm->waterlevel )
- {
- float waterScale;
-
- waterScale = pm->waterlevel / 3.0;
- waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale;
- if( wishspeed > pm->ps->speed * waterScale )
- wishspeed = pm->ps->speed * waterScale;
- }
-
- // when a player gets hit, they temporarily lose
- // full control, which allows them to be moved a bit
- if( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK )
- accelerate = BG_FindAirAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] );
- else
- accelerate = BG_FindAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] );
-
- PM_Accelerate( wishdir, wishspeed, accelerate );
-
- //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]);
- //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity));
-
- if( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK )
- pm->ps->velocity[ 2 ] -= pm->ps->gravity * pml.frametime;
- else
- {
- // don't reset the z velocity for slopes
-// pm->ps->velocity[2] = 0;
- }
-
- vel = VectorLength( pm->ps->velocity );
-
- // slide along the ground plane
- PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
-
- // don't decrease velocity when going up or down a slope
- VectorNormalize( pm->ps->velocity );
- VectorScale( pm->ps->velocity, vel, pm->ps->velocity );
-
- // don't do anything if standing still
- if( !pm->ps->velocity[ 0 ] && !pm->ps->velocity[ 1 ] )
- return;
-
- PM_StepSlideMove( qfalse, qfalse );
-
- //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity));
-
-}
-
-
-/*
-===================
-PM_LadderMove
-
-Basically a rip of PM_WaterMove with a few changes
-===================
-*/
-static void PM_LadderMove( void )
-{
- int i;
- vec3_t wishvel;
- float wishspeed;
- vec3_t wishdir;
- float scale;
- float vel;
-
- PM_Friction( );
-
- scale = PM_CmdScale( &pm->cmd );
-
- for( i = 0; i < 3; i++ )
- wishvel[ i ] = scale * pml.forward[ i ] * pm->cmd.forwardmove + scale * pml.right[ i ] * pm->cmd.rightmove;
-
- wishvel[ 2 ] += scale * pm->cmd.upmove;
-
- VectorCopy( wishvel, wishdir );
- wishspeed = VectorNormalize( wishdir );
-
- if( wishspeed > pm->ps->speed * pm_swimScale )
- wishspeed = pm->ps->speed * pm_swimScale;
-
- PM_Accelerate( wishdir, wishspeed, pm_accelerate );
-
- //slanty ladders
- if( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0.0f )
- {
- vel = VectorLength( pm->ps->velocity );
-
- // slide along the ground plane
- PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
-
- VectorNormalize( pm->ps->velocity );
- VectorScale( pm->ps->velocity, vel, pm->ps->velocity );
- }
-
- PM_SlideMove( qfalse );
-}
-
-
-/*
-=============
-PM_CheckLadder
-
-Check to see if the player is on a ladder or not
-=============
-*/
-static void PM_CheckLadder( void )
-{
- vec3_t forward, end;
- trace_t trace;
-
- //test if class can use ladders
- if( !BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_CANUSELADDERS ) )
- {
- pml.ladder = qfalse;
- return;
- }
-
- VectorCopy( pml.forward, forward );
- forward[ 2 ] = 0.0f;
-
- VectorMA( pm->ps->origin, 1.0f, forward, end );
-
- pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, MASK_PLAYERSOLID );
-
- if( ( trace.fraction < 1.0f ) && ( trace.surfaceFlags & SURF_LADDER ) )
- pml.ladder = qtrue;
- else
- pml.ladder = qfalse;
-}
-
-
-/*
-==============
-PM_DeadMove
-==============
-*/
-static void PM_DeadMove( void )
-{
- float forward;
-
- if( !pml.walking )
- return;
-
- // extra friction
-
- forward = VectorLength( pm->ps->velocity );
- forward -= 20;
-
- if( forward <= 0 )
- VectorClear( pm->ps->velocity );
- else
- {
- VectorNormalize( pm->ps->velocity );
- VectorScale( pm->ps->velocity, forward, pm->ps->velocity );
- }
-}
-
-
-/*
-===============
-PM_NoclipMove
-===============
-*/
-static void PM_NoclipMove( void )
-{
- float speed, drop, friction, control, newspeed;
- int i;
- vec3_t wishvel;
- float fmove, smove;
- vec3_t wishdir;
- float wishspeed;
- float scale;
-
- pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
-
- // friction
-
- speed = VectorLength( pm->ps->velocity );
-
- if( speed < 1 )
- {
- VectorCopy( vec3_origin, pm->ps->velocity );
- }
- else
- {
- drop = 0;
-
- friction = pm_friction * 1.5; // extra friction
- control = speed < pm_stopspeed ? pm_stopspeed : speed;
- drop += control * friction * pml.frametime;
-
- // scale the velocity
- newspeed = speed - drop;
-
- if( newspeed < 0 )
- newspeed = 0;
-
- newspeed /= speed;
-
- VectorScale( pm->ps->velocity, newspeed, pm->ps->velocity );
- }
-
- // accelerate
- scale = PM_CmdScale( &pm->cmd );
-
- fmove = pm->cmd.forwardmove;
- smove = pm->cmd.rightmove;
-
- for( i = 0; i < 3; i++ )
- wishvel[ i ] = pml.forward[ i ] * fmove + pml.right[ i ] * smove;
-
- wishvel[ 2 ] += pm->cmd.upmove;
-
- VectorCopy( wishvel, wishdir );
- wishspeed = VectorNormalize( wishdir );
- wishspeed *= scale;
-
- PM_Accelerate( wishdir, wishspeed, pm_accelerate );
-
- // move
- VectorMA( pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin );
-}
-
-//============================================================================
-
-/*
-================
-PM_FootstepForSurface
-
-Returns an event number apropriate for the groundsurface
-================
-*/
-static int PM_FootstepForSurface( void )
-{
- //TA:
- if( pm->ps->stats[ STAT_STATE ] & SS_CREEPSLOWED )
- return EV_FOOTSTEP_SQUELCH;
-
- if( pml.groundTrace.surfaceFlags & SURF_NOSTEPS )
- return 0;
-
- if( pml.groundTrace.surfaceFlags & SURF_METALSTEPS )
- return EV_FOOTSTEP_METAL;
-
- return EV_FOOTSTEP;
-}
-
-
-/*
-=================
-PM_CrashLand
-
-Check for hard landings that generate sound events
-=================
-*/
-static void PM_CrashLand( void )
-{
- float delta;
- float dist;
- float vel, acc;
- float t;
- float a, b, c, den;
-
- // decide which landing animation to use
- if( pm->ps->pm_flags & PMF_BACKWARDS_JUMP )
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ForceLegsAnim( LEGS_LANDB );
- else
- PM_ForceLegsAnim( NSPA_LANDBACK );
- }
- else
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ForceLegsAnim( LEGS_LAND );
- else
- PM_ForceLegsAnim( NSPA_LAND );
- }
-
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- pm->ps->legsTimer = TIMER_LAND;
- else
- pm->ps->torsoTimer = TIMER_LAND;
-
- // calculate the exact velocity on landing
- dist = pm->ps->origin[ 2 ] - pml.previous_origin[ 2 ];
- vel = pml.previous_velocity[ 2 ];
- acc = -pm->ps->gravity;
-
- a = acc / 2;
- b = vel;
- c = -dist;
-
- den = b * b - 4 * a * c;
- if( den < 0 )
- return;
-
- t = (-b - sqrt( den ) ) / ( 2 * a );
-
- delta = vel + t * acc;
- delta = delta*delta * 0.0001;
-
- // ducking while falling doubles damage
- if( pm->ps->pm_flags & PMF_DUCKED )
- delta *= 2;
-
- // never take falling damage if completely underwater
- if( pm->waterlevel == 3 )
- return;
-
- // reduce falling damage if there is standing water
- if( pm->waterlevel == 2 )
- delta *= 0.25;
-
- if( pm->waterlevel == 1 )
- delta *= 0.5;
-
- if( delta < 1 )
- return;
-
- // create a local entity event to play the sound
-
- // SURF_NODAMAGE is used for bounce pads where you don't ever
- // want to take damage or play a crunch sound
- if( !( pml.groundTrace.surfaceFlags & SURF_NODAMAGE ) )
- {
- pm->ps->stats[ STAT_FALLDIST ] = delta;
-
- if( delta > AVG_FALL_DISTANCE )
- {
- PM_AddEvent( EV_FALL_FAR );
- }
- else if( delta > MIN_FALL_DISTANCE )
- {
- // this is a pain grunt, so don't play it if dead
- if( pm->ps->stats[STAT_HEALTH] > 0 )
- PM_AddEvent( EV_FALL_MEDIUM );
- }
- else
- {
- if( delta > 7 )
- PM_AddEvent( EV_FALL_SHORT );
- else
- PM_AddEvent( PM_FootstepForSurface( ) );
- }
- }
-
- // start footstep cycle over
- pm->ps->bobCycle = 0;
-}
-
-
-/*
-=============
-PM_CorrectAllSolid
-=============
-*/
-static int PM_CorrectAllSolid( trace_t *trace )
-{
- int i, j, k;
- vec3_t point;
-
- if( pm->debugLevel )
- Com_Printf("%i:allsolid\n", c_pmove);
-
- // jitter around
- for( i = -1; i <= 1; i++ )
- {
- for( j = -1; j <= 1; j++ )
- {
- for( k = -1; k <= 1; k++ )
- {
- VectorCopy( pm->ps->origin, point );
- point[ 0 ] += (float)i;
- point[ 1 ] += (float)j;
- point[ 2 ] += (float)k;
- pm->trace( trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
-
- if( !trace->allsolid )
- {
- point[ 0 ] = pm->ps->origin[ 0 ];
- point[ 1 ] = pm->ps->origin[ 1 ];
- point[ 2 ] = pm->ps->origin[ 2 ] - 0.25;
-
- pm->trace( trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
- pml.groundTrace = *trace;
- return qtrue;
- }
- }
- }
- }
-
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
- pml.groundPlane = qfalse;
- pml.walking = qfalse;
-
- return qfalse;
-}
-
-
-/*
-=============
-PM_GroundTraceMissed
-
-The ground trace didn't hit a surface, so we are in freefall
-=============
-*/
-static void PM_GroundTraceMissed( void )
-{
- trace_t trace;
- vec3_t point;
-
- if( pm->ps->groundEntityNum != ENTITYNUM_NONE )
- {
- // we just transitioned into freefall
- if( pm->debugLevel )
- Com_Printf( "%i:lift\n", c_pmove );
-
- // if they aren't in a jumping animation and the ground is a ways away, force into it
- // if we didn't do the trace, the player would be backflipping down staircases
- VectorCopy( pm->ps->origin, point );
- point[ 2 ] -= 64.0f;
-
- pm->trace( &trace, pm->ps->origin, NULL, NULL, point, pm->ps->clientNum, pm->tracemask );
- if( trace.fraction == 1.0f )
- {
- if( pm->cmd.forwardmove >= 0 )
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ForceLegsAnim( LEGS_JUMP );
- else
- PM_ForceLegsAnim( NSPA_JUMP );
-
- pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
- }
- else
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ForceLegsAnim( LEGS_JUMPB );
- else
- PM_ForceLegsAnim( NSPA_JUMPBACK );
-
- pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
- }
- }
- }
-
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_TAKESFALLDAMAGE ) )
- {
- if( pm->ps->velocity[ 2 ] < FALLING_THRESHOLD && pml.previous_velocity[ 2 ] >= FALLING_THRESHOLD )
- PM_AddEvent( EV_FALLING );
- }
-
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
- pml.groundPlane = qfalse;
- pml.walking = qfalse;
-}
-
-
-/*
-=============
-PM_GroundClimbTrace
-=============
-*/
-static void PM_GroundClimbTrace( void )
-{
- vec3_t surfNormal, movedir, lookdir, point;
- vec3_t refNormal = { 0.0f, 0.0f, 1.0f };
- vec3_t ceilingNormal = { 0.0f, 0.0f, -1.0f };
- vec3_t toAngles, surfAngles;
- trace_t trace;
- int i;
-
- //used for delta correction
- vec3_t traceCROSSsurf, traceCROSSref, surfCROSSref;
- float traceDOTsurf, traceDOTref, surfDOTref, rTtDOTrTsTt;
- float traceANGsurf, traceANGref, surfANGref;
- vec3_t horizontal = { 1.0f, 0.0f, 0.0f }; //arbituary vector perpendicular to refNormal
- vec3_t refTOtrace, refTOsurfTOtrace, tempVec;
- int rTtANGrTsTt;
- float ldDOTtCs, d;
- vec3_t abc;
-
- //TA: If we're on the ceiling then grapplePoint is a rotation normal.. otherwise its a surface normal.
- // would have been nice if Carmack had left a few random variables in the ps struct for mod makers
- if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
- VectorCopy( ceilingNormal, surfNormal );
- else
- VectorCopy( pm->ps->grapplePoint, surfNormal );
-
- //construct a vector which reflects the direction the player is looking wrt the surface normal
- ProjectPointOnPlane( movedir, pml.forward, surfNormal );
- VectorNormalize( movedir );
-
- VectorCopy( movedir, lookdir );
-
- if( pm->cmd.forwardmove < 0 )
- VectorNegate( movedir, movedir );
-
- //allow strafe transitions
- if( pm->cmd.rightmove )
- {
- VectorCopy( pml.right, movedir );
-
- if( pm->cmd.rightmove < 0 )
- VectorNegate( movedir, movedir );
- }
-
- for( i = 0; i <= 4; i++ )
- {
- switch ( i )
- {
- case 0:
- //we are going to step this frame so skip the transition test
- if( PM_PredictStepMove( ) )
- continue;
-
- //trace into direction we are moving
- VectorMA( pm->ps->origin, 0.25f, movedir, point );
- pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
- break;
-
- case 1:
- //trace straight down anto "ground" surface
- VectorMA( pm->ps->origin, -0.25f, surfNormal, point );
- pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
- break;
-
- case 2:
- if( pml.groundPlane != qfalse && PM_PredictStepMove( ) )
- {
- //step down
- VectorMA( pm->ps->origin, -STEPSIZE, surfNormal, point );
- pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
- }
- else
- continue;
- break;
-
- case 3:
- //trace "underneath" BBOX so we can traverse angles > 180deg
- if( pml.groundPlane != qfalse )
- {
- VectorMA( pm->ps->origin, -16.0f, surfNormal, point );
- VectorMA( point, -16.0f, movedir, point );
- pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
- }
- else
- continue;
- break;
-
- case 4:
- //fall back so we don't have to modify PM_GroundTrace too much
- VectorCopy( pm->ps->origin, point );
- point[ 2 ] = pm->ps->origin[ 2 ] - 0.25f;
- pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
- break;
- }
-
- //if we hit something
- if( trace.fraction < 1.0f && !( trace.surfaceFlags & ( SURF_SKY | SURF_SLICK ) ) &&
- !( trace.entityNum != ENTITYNUM_WORLD && i != 4 ) )
- {
- if( i == 2 || i == 3 )
- {
- if( i == 2 )
- PM_StepEvent( pm->ps->origin, trace.endpos, surfNormal );
-
- VectorCopy( trace.endpos, pm->ps->origin );
- }
-
- //calculate a bunch of stuff...
- CrossProduct( trace.plane.normal, surfNormal, traceCROSSsurf );
- VectorNormalize( traceCROSSsurf );
-
- CrossProduct( trace.plane.normal, refNormal, traceCROSSref );
- VectorNormalize( traceCROSSref );
-
- CrossProduct( surfNormal, refNormal, surfCROSSref );
- VectorNormalize( surfCROSSref );
-
- //calculate angle between surf and trace
- traceDOTsurf = DotProduct( trace.plane.normal, surfNormal );
- traceANGsurf = RAD2DEG( acos( traceDOTsurf ) );
-
- if( traceANGsurf > 180.0f )
- traceANGsurf -= 180.0f;
-
- //calculate angle between trace and ref
- traceDOTref = DotProduct( trace.plane.normal, refNormal );
- traceANGref = RAD2DEG( acos( traceDOTref ) );
-
- if( traceANGref > 180.0f )
- traceANGref -= 180.0f;
-
- //calculate angle between surf and ref
- surfDOTref = DotProduct( surfNormal, refNormal );
- surfANGref = RAD2DEG( acos( surfDOTref ) );
-
- if( surfANGref > 180.0f )
- surfANGref -= 180.0f;
-
- //if the trace result and old surface normal are different then we must have transided to a new
- //surface... do some stuff...
- if( !VectorCompare( trace.plane.normal, surfNormal ) )
- {
- //if the trace result or the old vector is not the floor or ceiling correct the YAW angle
- if( !VectorCompare( trace.plane.normal, refNormal ) && !VectorCompare( surfNormal, refNormal ) &&
- !VectorCompare( trace.plane.normal, ceilingNormal ) && !VectorCompare( surfNormal, ceilingNormal ) )
- {
- //behold the evil mindfuck from hell
- //it has fucked mind like nothing has fucked mind before
-
- //calculate reference rotated through to trace plane
- RotatePointAroundVector( refTOtrace, traceCROSSref, horizontal, -traceANGref );
-
- //calculate reference rotated through to surf plane then to trace plane
- RotatePointAroundVector( tempVec, surfCROSSref, horizontal, -surfANGref );
- RotatePointAroundVector( refTOsurfTOtrace, traceCROSSsurf, tempVec, -traceANGsurf );
-
- //calculate angle between refTOtrace and refTOsurfTOtrace
- rTtDOTrTsTt = DotProduct( refTOtrace, refTOsurfTOtrace );
- rTtANGrTsTt = ANGLE2SHORT( RAD2DEG( acos( rTtDOTrTsTt ) ) );
-
- if( rTtANGrTsTt > 32768 )
- rTtANGrTsTt -= 32768;
-
- CrossProduct( refTOtrace, refTOsurfTOtrace, tempVec );
- VectorNormalize( tempVec );
- if( DotProduct( trace.plane.normal, tempVec ) > 0.0f )
- rTtANGrTsTt = -rTtANGrTsTt;
-
- //phew! - correct the angle
- pm->ps->delta_angles[ YAW ] -= rTtANGrTsTt;
- }
-
- //construct a plane dividing the surf and trace normals
- CrossProduct( traceCROSSsurf, surfNormal, abc );
- VectorNormalize( abc );
- d = DotProduct( abc, pm->ps->origin );
-
- //construct a point representing where the player is looking
- VectorAdd( pm->ps->origin, lookdir, point );
-
- //check whether point is on one side of the plane, if so invert the correction angle
- if( ( abc[ 0 ] * point[ 0 ] + abc[ 1 ] * point[ 1 ] + abc[ 2 ] * point[ 2 ] - d ) > 0 )
- traceANGsurf = -traceANGsurf;
-
- //find the . product of the lookdir and traceCROSSsurf
- if( ( ldDOTtCs = DotProduct( lookdir, traceCROSSsurf ) ) < 0.0f )
- {
- VectorInverse( traceCROSSsurf );
- ldDOTtCs = DotProduct( lookdir, traceCROSSsurf );
- }
-
- //set the correction angle
- traceANGsurf *= 1.0f - ldDOTtCs;
-
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_WALLCLIMBINGFOLLOW ) )
- {
- //correct the angle
- pm->ps->delta_angles[ PITCH ] -= ANGLE2SHORT( traceANGsurf );
- }
-
- //transition from wall to ceiling
- //normal for subsequent viewangle rotations
- if( VectorCompare( trace.plane.normal, ceilingNormal ) )
- {
- CrossProduct( surfNormal, trace.plane.normal, pm->ps->grapplePoint );
- VectorNormalize( pm->ps->grapplePoint );
- pm->ps->stats[ STAT_STATE ] |= SS_WALLCLIMBINGCEILING;
- }
-
- //transition from ceiling to wall
- //we need to do some different angle correction here cos GPISROTVEC
- if( VectorCompare( surfNormal, ceilingNormal ) )
- {
- vectoangles( trace.plane.normal, toAngles );
- vectoangles( pm->ps->grapplePoint, surfAngles );
-
- pm->ps->delta_angles[ 1 ] -= ANGLE2SHORT( ( ( surfAngles[ 1 ] - toAngles[ 1 ] ) * 2 ) - 180.0f );
- }
- }
-
- pml.groundTrace = trace;
-
- //so everything knows where we're wallclimbing (ie client side)
- pm->ps->eFlags |= EF_WALLCLIMB;
-
- //if we're not stuck to the ceiling then set grapplePoint to be a surface normal
- if( !VectorCompare( trace.plane.normal, ceilingNormal ) )
- {
- //so we know what surface we're stuck to
- VectorCopy( trace.plane.normal, pm->ps->grapplePoint );
- pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBINGCEILING;
- }
-
- //IMPORTANT: break out of the for loop if we've hit something
- break;
- }
- else if( trace.allsolid )
- {
- // do something corrective if the trace starts in a solid...
- if( !PM_CorrectAllSolid( &trace ) )
- return;
- }
- }
-
- if( trace.fraction >= 1.0f )
- {
- // if the trace didn't hit anything, we are in free fall
- PM_GroundTraceMissed( );
- pml.groundPlane = qfalse;
- pml.walking = qfalse;
- pm->ps->eFlags &= ~EF_WALLCLIMB;
-
- //just transided from ceiling to floor... apply delta correction
- if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
- {
- vec3_t forward, rotated, angles;
-
- AngleVectors( pm->ps->viewangles, forward, NULL, NULL );
-
- RotatePointAroundVector( rotated, pm->ps->grapplePoint, forward, 180.0f );
- vectoangles( rotated, angles );
-
- pm->ps->delta_angles[ YAW ] -= ANGLE2SHORT( angles[ YAW ] - pm->ps->viewangles[ YAW ] );
- }
-
- pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBINGCEILING;
-
- //we get very bizarre effects if we don't do this :0
- VectorCopy( refNormal, pm->ps->grapplePoint );
- return;
- }
-
- pml.groundPlane = qtrue;
- pml.walking = qtrue;
-
- // hitting solid ground will end a waterjump
- if( pm->ps->pm_flags & PMF_TIME_WATERJUMP )
- {
- pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND);
- pm->ps->pm_time = 0;
- }
-
- pm->ps->groundEntityNum = trace.entityNum;
-
- // don't reset the z velocity for slopes
-// pm->ps->velocity[2] = 0;
-
- PM_AddTouchEnt( trace.entityNum );
-}
-
-
-/*
-=============
-PM_GroundTrace
-=============
-*/
-static void PM_GroundTrace( void )
-{
- vec3_t point;
- vec3_t movedir;
- vec3_t refNormal = { 0.0f, 0.0f, 1.0f };
- trace_t trace;
-
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) )
- {
- if( pm->ps->persistant[ PERS_STATE ] & PS_WALLCLIMBINGTOGGLE )
- {
- //toggle wall climbing if holding crouch
- if( pm->cmd.upmove < 0 && !( pm->ps->pm_flags & PMF_CROUCH_HELD ) )
- {
- if( !( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) )
- pm->ps->stats[ STAT_STATE ] |= SS_WALLCLIMBING;
- else if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
- pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBING;
-
- pm->ps->pm_flags |= PMF_CROUCH_HELD;
- }
- else if( pm->cmd.upmove >= 0 )
- pm->ps->pm_flags &= ~PMF_CROUCH_HELD;
- }
- else
- {
- if( pm->cmd.upmove < 0 )
- pm->ps->stats[ STAT_STATE ] |= SS_WALLCLIMBING;
- else if( pm->cmd.upmove >= 0 )
- pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBING;
- }
-
- if( pm->ps->pm_type == PM_DEAD )
- pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBING;
-
- if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
- {
- PM_GroundClimbTrace( );
- return;
- }
-
- //just transided from ceiling to floor... apply delta correction
- if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
- {
- vec3_t forward, rotated, angles;
-
- AngleVectors( pm->ps->viewangles, forward, NULL, NULL );
-
- RotatePointAroundVector( rotated, pm->ps->grapplePoint, forward, 180.0f );
- vectoangles( rotated, angles );
-
- pm->ps->delta_angles[ YAW ] -= ANGLE2SHORT( angles[ YAW ] - pm->ps->viewangles[ YAW ] );
- }
- }
-
- pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBING;
- pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBINGCEILING;
- pm->ps->eFlags &= ~EF_WALLCLIMB;
-
- point[ 0 ] = pm->ps->origin[ 0 ];
- point[ 1 ] = pm->ps->origin[ 1 ];
- point[ 2 ] = pm->ps->origin[ 2 ] - 0.25f;
-
- pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
-
- pml.groundTrace = trace;
-
- // do something corrective if the trace starts in a solid...
- if( trace.allsolid )
- if( !PM_CorrectAllSolid( &trace ) )
- return;
-
- //make sure that the surfNormal is reset to the ground
- VectorCopy( refNormal, pm->ps->grapplePoint );
-
- // if the trace didn't hit anything, we are in free fall
- if( trace.fraction == 1.0f )
- {
- qboolean steppedDown = qfalse;
-
- // try to step down
- if( pml.groundPlane != qfalse && PM_PredictStepMove( ) )
- {
- //step down
- point[ 0 ] = pm->ps->origin[ 0 ];
- point[ 1 ] = pm->ps->origin[ 1 ];
- point[ 2 ] = pm->ps->origin[ 2 ] - STEPSIZE;
- pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
-
- //if we hit something
- if( trace.fraction < 1.0f )
- {
- PM_StepEvent( pm->ps->origin, trace.endpos, refNormal );
- VectorCopy( trace.endpos, pm->ps->origin );
- steppedDown = qtrue;
- }
- }
-
- if( !steppedDown )
- {
- PM_GroundTraceMissed( );
- pml.groundPlane = qfalse;
- pml.walking = qfalse;
-
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) )
- {
- ProjectPointOnPlane( movedir, pml.forward, refNormal );
- VectorNormalize( movedir );
-
- if( pm->cmd.forwardmove < 0 )
- VectorNegate( movedir, movedir );
-
- //allow strafe transitions
- if( pm->cmd.rightmove )
- {
- VectorCopy( pml.right, movedir );
-
- if( pm->cmd.rightmove < 0 )
- VectorNegate( movedir, movedir );
- }
-
- //trace into direction we are moving
- VectorMA( pm->ps->origin, 0.25f, movedir, point );
- pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
-
- if( trace.fraction < 1.0f && !( trace.surfaceFlags & ( SURF_SKY | SURF_SLICK ) ) &&
- ( trace.entityNum == ENTITYNUM_WORLD ) )
- {
- if( !VectorCompare( trace.plane.normal, pm->ps->grapplePoint ) )
- {
- VectorCopy( trace.plane.normal, pm->ps->grapplePoint );
- PM_CheckWallJump( );
- }
- }
- }
-
- return;
- }
- }
-
- // check if getting thrown off the ground
- if( pm->ps->velocity[ 2 ] > 0.0f && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10.0f )
- {
- if( pm->debugLevel )
- Com_Printf( "%i:kickoff\n", c_pmove );
-
- // go into jump animation
- if( pm->cmd.forwardmove >= 0 )
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ForceLegsAnim( LEGS_JUMP );
- else
- PM_ForceLegsAnim( NSPA_JUMP );
-
- pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
- }
- else
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ForceLegsAnim( LEGS_JUMPB );
- else
- PM_ForceLegsAnim( NSPA_JUMPBACK );
-
- pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
- }
-
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
- pml.groundPlane = qfalse;
- pml.walking = qfalse;
- return;
- }
-
- // slopes that are too steep will not be considered onground
- if( trace.plane.normal[ 2 ] < MIN_WALK_NORMAL )
- {
- if( pm->debugLevel )
- Com_Printf( "%i:steep\n", c_pmove );
-
- // FIXME: if they can't slide down the slope, let them
- // walk (sharp crevices)
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
- pml.groundPlane = qtrue;
- pml.walking = qfalse;
- return;
- }
-
- pml.groundPlane = qtrue;
- pml.walking = qtrue;
-
- // hitting solid ground will end a waterjump
- if( pm->ps->pm_flags & PMF_TIME_WATERJUMP )
- {
- pm->ps->pm_flags &= ~( PMF_TIME_WATERJUMP | PMF_TIME_LAND );
- pm->ps->pm_time = 0;
- }
-
- if( pm->ps->groundEntityNum == ENTITYNUM_NONE )
- {
- // just hit the ground
- if( pm->debugLevel )
- Com_Printf( "%i:Land\n", c_pmove );
-
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_TAKESFALLDAMAGE ) )
- PM_CrashLand( );
-
- // don't do landing time if we were just going down a slope
- if( pml.previous_velocity[ 2 ] < -200 )
- {
- // don't allow another jump for a little while
- pm->ps->pm_flags |= PMF_TIME_LAND;
- pm->ps->pm_time = 250;
- }
- }
-
- pm->ps->groundEntityNum = trace.entityNum;
-
- // don't reset the z velocity for slopes
-// pm->ps->velocity[2] = 0;
-
- PM_AddTouchEnt( trace.entityNum );
-}
-
-
-/*
-=============
-PM_SetWaterLevel FIXME: avoid this twice? certainly if not moving
-=============
-*/
-static void PM_SetWaterLevel( void )
-{
- vec3_t point;
- int cont;
- int sample1;
- int sample2;
-
- //
- // get waterlevel, accounting for ducking
- //
- pm->waterlevel = 0;
- pm->watertype = 0;
-
- point[ 0 ] = pm->ps->origin[ 0 ];
- point[ 1 ] = pm->ps->origin[ 1 ];
- point[ 2 ] = pm->ps->origin[ 2 ] + MINS_Z + 1;
- cont = pm->pointcontents( point, pm->ps->clientNum );
-
- if( cont & MASK_WATER )
- {
- sample2 = pm->ps->viewheight - MINS_Z;
- sample1 = sample2 / 2;
-
- pm->watertype = cont;
- pm->waterlevel = 1;
- point[ 2 ] = pm->ps->origin[ 2 ] + MINS_Z + sample1;
- cont = pm->pointcontents( point, pm->ps->clientNum );
-
- if( cont & MASK_WATER )
- {
- pm->waterlevel = 2;
- point[ 2 ] = pm->ps->origin[ 2 ] + MINS_Z + sample2;
- cont = pm->pointcontents( point, pm->ps->clientNum );
-
- if( cont & MASK_WATER )
- pm->waterlevel = 3;
- }
- }
-}
-
-
-
-/*
-==============
-PM_CheckDuck
-
-Sets mins, maxs, and pm->ps->viewheight
-==============
-*/
-static void PM_CheckDuck (void)
-{
- trace_t trace;
- vec3_t PCmins, PCmaxs, PCcmaxs;
- int PCvh, PCcvh;
-
- BG_FindBBoxForClass( pm->ps->stats[ STAT_PCLASS ], PCmins, PCmaxs, PCcmaxs, NULL, NULL );
- BG_FindViewheightForClass( pm->ps->stats[ STAT_PCLASS ], &PCvh, &PCcvh );
-
- //TA: iD bug? you can still crouch when you're a spectator
- if( pm->ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR )
- PCcvh = PCvh;
-
- pm->mins[ 0 ] = PCmins[ 0 ];
- pm->mins[ 1 ] = PCmins[ 1 ];
-
- pm->maxs[ 0 ] = PCmaxs[ 0 ];
- pm->maxs[ 1 ] = PCmaxs[ 1 ];
-
- pm->mins[ 2 ] = PCmins[ 2 ];
-
- if( pm->ps->pm_type == PM_DEAD )
- {
- pm->maxs[ 2 ] = -8;
- pm->ps->viewheight = DEAD_VIEWHEIGHT;
- return;
- }
-
- //TA: If the standing and crouching viewheights are the same the class can't crouch
- if( ( pm->cmd.upmove < 0 ) && ( PCvh != PCcvh ) &&
- pm->ps->pm_type != PM_JETPACK &&
- !BG_InventoryContainsUpgrade( UP_BATTLESUIT, pm->ps->stats ) )
- {
- // duck
- pm->ps->pm_flags |= PMF_DUCKED;
- }
- else
- {
- // stand up if possible
- if( pm->ps->pm_flags & PMF_DUCKED )
- {
- // try to stand up
- pm->maxs[ 2 ] = PCmaxs[ 2 ];
- pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask );
- if( !trace.allsolid )
- pm->ps->pm_flags &= ~PMF_DUCKED;
- }
- }
-
- if( pm->ps->pm_flags & PMF_DUCKED )
- {
- pm->maxs[ 2 ] = PCcmaxs[ 2 ];
- pm->ps->viewheight = PCcvh;
- }
- else
- {
- pm->maxs[ 2 ] = PCmaxs[ 2 ];
- pm->ps->viewheight = PCvh;
- }
-}
-
-
-
-//===================================================================
-
-
-/*
-===============
-PM_Footsteps
-===============
-*/
-static void PM_Footsteps( void )
-{
- float bobmove;
- int old;
- qboolean footstep;
-
- //
- // calculate speed and cycle to be used for
- // all cyclic walking effects
- //
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) && ( pml.groundPlane ) )
- {
- //TA: FIXME: yes yes i know this is wrong
- pm->xyspeed = sqrt( pm->ps->velocity[ 0 ] * pm->ps->velocity[ 0 ]
- + pm->ps->velocity[ 1 ] * pm->ps->velocity[ 1 ]
- + pm->ps->velocity[ 2 ] * pm->ps->velocity[ 2 ] );
- }
- else
- pm->xyspeed = sqrt( pm->ps->velocity[ 0 ] * pm->ps->velocity[ 0 ]
- + pm->ps->velocity[ 1 ] * pm->ps->velocity[ 1 ] );
-
- if( pm->ps->groundEntityNum == ENTITYNUM_NONE )
- {
- // airborne leaves position in cycle intact, but doesn't advance
- if( pm->waterlevel > 1 )
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ContinueLegsAnim( LEGS_SWIM );
- else
- PM_ContinueLegsAnim( NSPA_SWIM );
- }
-
- return;
- }
-
- // if not trying to move
- if( !pm->cmd.forwardmove && !pm->cmd.rightmove )
- {
- if( pm->xyspeed < 5 )
- {
- pm->ps->bobCycle = 0; // start at beginning of cycle again
- if( pm->ps->pm_flags & PMF_DUCKED )
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ContinueLegsAnim( LEGS_IDLECR );
- else
- PM_ContinueLegsAnim( NSPA_STAND );
- }
- else
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ContinueLegsAnim( LEGS_IDLE );
- else
- PM_ContinueLegsAnim( NSPA_STAND );
- }
- }
- return;
- }
-
-
- footstep = qfalse;
-
- if( pm->ps->pm_flags & PMF_DUCKED )
- {
- bobmove = 0.5; // ducked characters bob much faster
-
- if( pm->ps->pm_flags & PMF_BACKWARDS_RUN )
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ContinueLegsAnim( LEGS_BACKCR );
- else
- {
- if( pm->cmd.rightmove > 0 && !pm->cmd.forwardmove )
- PM_ContinueLegsAnim( NSPA_WALKRIGHT );
- else if( pm->cmd.rightmove < 0 && !pm->cmd.forwardmove )
- PM_ContinueLegsAnim( NSPA_WALKLEFT );
- else
- PM_ContinueLegsAnim( NSPA_WALKBACK );
- }
- }
- else
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ContinueLegsAnim( LEGS_WALKCR );
- else
- {
- if( pm->cmd.rightmove > 0 && !pm->cmd.forwardmove )
- PM_ContinueLegsAnim( NSPA_WALKRIGHT );
- else if( pm->cmd.rightmove < 0 && !pm->cmd.forwardmove )
- PM_ContinueLegsAnim( NSPA_WALKLEFT );
- else
- PM_ContinueLegsAnim( NSPA_WALK );
- }
- }
-
- // ducked characters never play footsteps
- }
- else
- {
- if( !( pm->cmd.buttons & BUTTON_WALKING ) )
- {
- bobmove = 0.4f; // faster speeds bob faster
-
- if( pm->ps->weapon == WP_ALEVEL4 && pm->ps->pm_flags & PMF_CHARGE )
- PM_ContinueLegsAnim( NSPA_CHARGE );
- else if( pm->ps->pm_flags & PMF_BACKWARDS_RUN )
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ContinueLegsAnim( LEGS_BACK );
- else
- {
- if( pm->cmd.rightmove > 0 && !pm->cmd.forwardmove )
- PM_ContinueLegsAnim( NSPA_RUNRIGHT );
- else if( pm->cmd.rightmove < 0 && !pm->cmd.forwardmove )
- PM_ContinueLegsAnim( NSPA_RUNLEFT );
- else
- PM_ContinueLegsAnim( NSPA_RUNBACK );
- }
- }
- else
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ContinueLegsAnim( LEGS_RUN );
- else
- {
- if( pm->cmd.rightmove > 0 && !pm->cmd.forwardmove )
- PM_ContinueLegsAnim( NSPA_RUNRIGHT );
- else if( pm->cmd.rightmove < 0 && !pm->cmd.forwardmove )
- PM_ContinueLegsAnim( NSPA_RUNLEFT );
- else
- PM_ContinueLegsAnim( NSPA_RUN );
- }
- }
-
- footstep = qtrue;
- }
- else
- {
- bobmove = 0.3f; // walking bobs slow
- if( pm->ps->pm_flags & PMF_BACKWARDS_RUN )
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ContinueLegsAnim( LEGS_BACKWALK );
- else
- {
- if( pm->cmd.rightmove > 0 && !pm->cmd.forwardmove )
- PM_ContinueLegsAnim( NSPA_WALKRIGHT );
- else if( pm->cmd.rightmove < 0 && !pm->cmd.forwardmove )
- PM_ContinueLegsAnim( NSPA_WALKLEFT );
- else
- PM_ContinueLegsAnim( NSPA_WALKBACK );
- }
- }
- else
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_ContinueLegsAnim( LEGS_WALK );
- else
- {
- if( pm->cmd.rightmove > 0 && !pm->cmd.forwardmove )
- PM_ContinueLegsAnim( NSPA_WALKRIGHT );
- else if( pm->cmd.rightmove < 0 && !pm->cmd.forwardmove )
- PM_ContinueLegsAnim( NSPA_WALKLEFT );
- else
- PM_ContinueLegsAnim( NSPA_WALK );
- }
- }
- }
- }
-
- bobmove *= BG_FindBobCycleForClass( pm->ps->stats[ STAT_PCLASS ] );
-
- if( pm->ps->stats[ STAT_STATE ] & SS_SPEEDBOOST )
- bobmove *= HUMAN_SPRINT_MODIFIER;
-
- // check for footstep / splash sounds
- old = pm->ps->bobCycle;
- pm->ps->bobCycle = (int)( old + bobmove * pml.msec ) & 255;
-
- // if we just crossed a cycle boundary, play an apropriate footstep event
- if( ( ( old + 64 ) ^ ( pm->ps->bobCycle + 64 ) ) & 128 )
- {
- if( pm->waterlevel == 0 )
- {
- // on ground will only play sounds if running
- if( footstep && !pm->noFootsteps )
- PM_AddEvent( PM_FootstepForSurface( ) );
- }
- else if( pm->waterlevel == 1 )
- {
- // splashing
- PM_AddEvent( EV_FOOTSPLASH );
- }
- else if( pm->waterlevel == 2 )
- {
- // wading / swimming at surface
- PM_AddEvent( EV_SWIM );
- }
- else if( pm->waterlevel == 3 )
- {
- // no sound when completely underwater
- }
- }
-}
-
-/*
-==============
-PM_WaterEvents
-
-Generate sound events for entering and leaving water
-==============
-*/
-static void PM_WaterEvents( void )
-{
- // FIXME?
- //
- // if just entered a water volume, play a sound
- //
- if( !pml.previous_waterlevel && pm->waterlevel )
- PM_AddEvent( EV_WATER_TOUCH );
-
- //
- // if just completely exited a water volume, play a sound
- //
- if( pml.previous_waterlevel && !pm->waterlevel )
- PM_AddEvent( EV_WATER_LEAVE );
-
- //
- // check for head just going under water
- //
- if( pml.previous_waterlevel != 3 && pm->waterlevel == 3 )
- PM_AddEvent( EV_WATER_UNDER );
-
- //
- // check for head just coming out of water
- //
- if( pml.previous_waterlevel == 3 && pm->waterlevel != 3 )
- PM_AddEvent( EV_WATER_CLEAR );
-}
-
-
-/*
-===============
-PM_BeginWeaponChange
-===============
-*/
-static void PM_BeginWeaponChange( int weapon )
-{
- if( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS )
- return;
-
- if( !BG_InventoryContainsWeapon( weapon, pm->ps->stats ) && weapon != WP_NONE )
- return;
-
- if( pm->ps->weaponstate == WEAPON_DROPPING )
- return;
-
- PM_AddEvent( EV_CHANGE_WEAPON );
- pm->ps->weaponstate = WEAPON_DROPPING;
- pm->ps->weaponTime += 200;
- pm->ps->persistant[ PERS_NEWWEAPON ] = weapon;
-
- //reset build weapon
- pm->ps->stats[ STAT_BUILDABLE ] = BA_NONE;
-
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_StartTorsoAnim( TORSO_DROP );
-}
-
-
-/*
-===============
-PM_FinishWeaponChange
-===============
-*/
-static void PM_FinishWeaponChange( void )
-{
- int weapon;
-
- weapon = pm->ps->persistant[ PERS_NEWWEAPON ];
- if( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS )
- weapon = WP_NONE;
-
- if( !BG_InventoryContainsWeapon( weapon, pm->ps->stats ) )
- weapon = WP_NONE;
-
- pm->ps->weapon = weapon;
- pm->ps->weaponstate = WEAPON_RAISING;
- pm->ps->weaponTime += 250;
-
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- PM_StartTorsoAnim( TORSO_RAISE );
-}
-
-
-/*
-==============
-PM_TorsoAnimation
-
-==============
-*/
-static void PM_TorsoAnimation( void )
-{
- if( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL )
- return;
-
- if( pm->ps->weaponstate == WEAPON_READY )
- {
- if( pm->ps->weapon == WP_BLASTER )
- PM_ContinueTorsoAnim( TORSO_STAND2 );
- else
- PM_ContinueTorsoAnim( TORSO_STAND );
- }
-}
-
-
-/*
-==============
-PM_Weapon
-
-Generates weapon events and modifes the weapon counter
-==============
-*/
-static void PM_Weapon( void )
-{
- int addTime = 200; //default addTime - should never be used
- int ammo, clips, maxClips;
- qboolean attack1 = qfalse;
- qboolean attack2 = qfalse;
- qboolean attack3 = qfalse;
-
- // don't allow attack until all buttons are up
- if( pm->ps->pm_flags & PMF_RESPAWNED )
- return;
-
- // ignore if spectator
- if( pm->ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR )
- return;
-
- if( pm->ps->stats[ STAT_STATE ] & SS_INFESTING )
- return;
-
- if( pm->ps->stats[ STAT_STATE ] & SS_HOVELING )
- return;
-
- // check for dead player
- if( pm->ps->stats[ STAT_HEALTH ] <= 0 )
- {
- pm->ps->weapon = WP_NONE;
- return;
- }
-
- // make weapon function
- if( pm->ps->weaponTime > 0 )
- pm->ps->weaponTime -= pml.msec;
-
- // check for weapon change
- // can't change if weapon is firing, but can change
- // again if lowering or raising
- if( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING )
- {
- //TA: must press use to switch weapons
- if( pm->cmd.buttons & BUTTON_USE_HOLDABLE )
- {
- if( !( pm->ps->pm_flags & PMF_USE_ITEM_HELD ) )
- {
- if( pm->cmd.weapon <= 32 )
- {
- //if trying to select a weapon, select it
- if( pm->ps->weapon != pm->cmd.weapon )
- PM_BeginWeaponChange( pm->cmd.weapon );
- }
- else if( pm->cmd.weapon > 32 )
- {
- //if trying to toggle an upgrade, toggle it
- if( BG_InventoryContainsUpgrade( pm->cmd.weapon - 32, pm->ps->stats ) ) //sanity check
- {
- if( BG_UpgradeIsActive( pm->cmd.weapon - 32, pm->ps->stats ) )
- BG_DeactivateUpgrade( pm->cmd.weapon - 32, pm->ps->stats );
- else
- BG_ActivateUpgrade( pm->cmd.weapon - 32, pm->ps->stats );
- }
- }
- pm->ps->pm_flags |= PMF_USE_ITEM_HELD;
- }
- }
- else
- pm->ps->pm_flags &= ~PMF_USE_ITEM_HELD;
-
- //something external thinks a weapon change is necessary
- if( pm->ps->pm_flags & PMF_WEAPON_SWITCH )
- {
- pm->ps->pm_flags &= ~PMF_WEAPON_SWITCH;
- PM_BeginWeaponChange( pm->ps->persistant[ PERS_NEWWEAPON ] );
- }
- }
-
- if( pm->ps->weaponTime > 0 )
- return;
-
- // change weapon if time
- if( pm->ps->weaponstate == WEAPON_DROPPING )
- {
- PM_FinishWeaponChange( );
- return;
- }
-
- if( pm->ps->weaponstate == WEAPON_RAISING )
- {
- pm->ps->weaponstate = WEAPON_READY;
-
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- {
- if( pm->ps->weapon == WP_BLASTER )
- PM_ContinueTorsoAnim( TORSO_STAND2 );
- else
- PM_ContinueTorsoAnim( TORSO_STAND );
- }
-
- return;
- }
-
- // start the animation even if out of ammo
-
- BG_UnpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips );
- BG_FindAmmoForWeapon( pm->ps->weapon, NULL, &maxClips );
-
- // check for out of ammo
- if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) )
- {
- PM_AddEvent( EV_NOAMMO );
- pm->ps->weaponTime += 200;
- return;
- }
-
- //done reloading so give em some ammo
- if( pm->ps->weaponstate == WEAPON_RELOADING )
- {
- if( maxClips > 0 )
- {
- clips--;
- BG_FindAmmoForWeapon( pm->ps->weapon, &ammo, NULL );
- }
-
- if( BG_FindUsesEnergyForWeapon( pm->ps->weapon ) &&
- BG_InventoryContainsUpgrade( UP_BATTPACK, pm->ps->stats ) )
- ammo = (int)( (float)ammo * BATTPACK_MODIFIER );
-
- BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips );
-
- //allow some time for the weapon to be raised
- pm->ps->weaponstate = WEAPON_RAISING;
- PM_StartTorsoAnim( TORSO_RAISE );
- pm->ps->weaponTime += 250;
- return;
- }
-
- // check for end of clip
- if( ( !ammo || pm->ps->pm_flags & PMF_WEAPON_RELOAD ) && clips )
- {
- pm->ps->pm_flags &= ~PMF_WEAPON_RELOAD;
-
- pm->ps->weaponstate = WEAPON_RELOADING;
-
- //drop the weapon
- PM_StartTorsoAnim( TORSO_DROP );
-
- addTime = BG_FindReloadTimeForWeapon( pm->ps->weapon );
-
- pm->ps->weaponTime += addTime;
- return;
- }
-
- //check if non-auto primary/secondary attacks are permited
- switch( pm->ps->weapon )
- {
- case WP_ALEVEL0:
- //venom is only autohit
- attack1 = attack2 = attack3 = qfalse;
-
- if( !pm->autoWeaponHit[ pm->ps->weapon ] )
- {
- pm->ps->weaponTime = 0;
- pm->ps->weaponstate = WEAPON_READY;
- return;
- }
- break;
-
- case WP_ALEVEL3:
- case WP_ALEVEL3_UPG:
- //pouncing has primary secondary AND autohit procedures
- attack1 = pm->cmd.buttons & BUTTON_ATTACK;
- attack2 = pm->cmd.buttons & BUTTON_ATTACK2;
- attack3 = pm->cmd.buttons & BUTTON_USE_HOLDABLE;
-
- if( !pm->autoWeaponHit[ pm->ps->weapon ] && !attack1 && !attack2 && !attack3 )
- {
- pm->ps->weaponTime = 0;
- pm->ps->weaponstate = WEAPON_READY;
- return;
- }
- break;
-
- case WP_LUCIFER_CANNON:
- attack1 = pm->cmd.buttons & BUTTON_ATTACK;
- attack2 = pm->cmd.buttons & BUTTON_ATTACK2;
- attack3 = pm->cmd.buttons & BUTTON_USE_HOLDABLE;
-
- if( ( attack1 || pm->ps->stats[ STAT_MISC ] == 0 ) && !attack2 && !attack3 )
- {
- if( pm->ps->stats[ STAT_MISC ] < LCANNON_TOTAL_CHARGE )
- {
- pm->ps->weaponTime = 0;
- pm->ps->weaponstate = WEAPON_READY;
- return;
- }
- else
- attack1 = !attack1;
- }
-
- //erp this looks confusing
- if( pm->ps->stats[ STAT_MISC ] > 0 )
- attack1 = !attack1;
- break;
-
- default:
- //by default primary and secondary attacks are allowed
- attack1 = pm->cmd.buttons & BUTTON_ATTACK;
- attack2 = pm->cmd.buttons & BUTTON_ATTACK2;
- attack3 = pm->cmd.buttons & BUTTON_USE_HOLDABLE;
-
- if( !attack1 && !attack2 && !attack3 )
- {
- pm->ps->weaponTime = 0;
- pm->ps->weaponstate = WEAPON_READY;
- return;
- }
- break;
- }
-
- //TA: fire events for non auto weapons
- if( attack3 )
- {
- if( BG_WeaponHasThirdMode( pm->ps->weapon ) )
- {
- //hacky special case for slowblob
- if( pm->ps->weapon == WP_ALEVEL3_UPG && !ammo )
- {
- PM_AddEvent( EV_NOAMMO );
- pm->ps->weaponTime += 200;
- return;
- }
-
- pm->ps->generic1 = WPM_TERTIARY;
- PM_AddEvent( EV_FIRE_WEAPON3 );
- addTime = BG_FindRepeatRate3ForWeapon( pm->ps->weapon );
- }
- else
- {
- pm->ps->weaponTime = 0;
- pm->ps->weaponstate = WEAPON_READY;
- return;
- }
- }
- else if( attack2 )
- {
- if( BG_WeaponHasAltMode( pm->ps->weapon ) )
- {
- pm->ps->generic1 = WPM_SECONDARY;
- PM_AddEvent( EV_FIRE_WEAPON2 );
- addTime = BG_FindRepeatRate2ForWeapon( pm->ps->weapon );
- }
- else
- {
- pm->ps->weaponTime = 0;
- pm->ps->weaponstate = WEAPON_READY;
- return;
- }
- }
- else if( attack1 )
- {
- pm->ps->generic1 = WPM_PRIMARY;
- PM_AddEvent( EV_FIRE_WEAPON );
- addTime = BG_FindRepeatRate1ForWeapon( pm->ps->weapon );
- }
-
- //TA: fire events for autohit weapons
- if( pm->autoWeaponHit[ pm->ps->weapon ] )
- {
- switch( pm->ps->weapon )
- {
- case WP_ALEVEL0:
- pm->ps->generic1 = WPM_PRIMARY;
- PM_AddEvent( EV_FIRE_WEAPON );
- addTime = BG_FindRepeatRate1ForWeapon( pm->ps->weapon );
- break;
-
- case WP_ALEVEL3:
- case WP_ALEVEL3_UPG:
- pm->ps->generic1 = WPM_SECONDARY;
- PM_AddEvent( EV_FIRE_WEAPON2 );
- addTime = BG_FindRepeatRate2ForWeapon( pm->ps->weapon );
- break;
-
- default:
- break;
- }
- }
-
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- {
- //FIXME: this should be an option in the client weapon.cfg
- switch( pm->ps->weapon )
- {
- case WP_FLAMER:
- if( pm->ps->weaponstate == WEAPON_READY )
- {
- PM_StartTorsoAnim( TORSO_ATTACK );
- }
- break;
-
- case WP_BLASTER:
- PM_StartTorsoAnim( TORSO_ATTACK2 );
- break;
-
- default:
- PM_StartTorsoAnim( TORSO_ATTACK );
- break;
- }
- }
- else
- {
- if( pm->ps->weapon == WP_ALEVEL4 )
- {
- //hack to get random attack animations
- //FIXME: does pm->ps->weaponTime cycle enough?
- int num = abs( pm->ps->weaponTime ) % 3;
-
- if( num == 0 )
- PM_ForceLegsAnim( NSPA_ATTACK1 );
- else if( num == 1 )
- PM_ForceLegsAnim( NSPA_ATTACK2 );
- else if( num == 2 )
- PM_ForceLegsAnim( NSPA_ATTACK3 );
- }
- else
- {
- if( attack1 )
- PM_ForceLegsAnim( NSPA_ATTACK1 );
- else if( attack2 )
- PM_ForceLegsAnim( NSPA_ATTACK2 );
- else if( attack3 )
- PM_ForceLegsAnim( NSPA_ATTACK3 );
- }
-
- pm->ps->torsoTimer = TIMER_ATTACK;
- }
-
- pm->ps->weaponstate = WEAPON_FIRING;
-
- // take an ammo away if not infinite
- if( !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) )
- {
- //special case for lCanon
- if( pm->ps->weapon == WP_LUCIFER_CANNON && attack1 )
- {
- ammo -= (int)( ceil( ( (float)pm->ps->stats[ STAT_MISC ] / (float)LCANNON_TOTAL_CHARGE ) * 10.0f ) );
-
- //stay on the safe side
- if( ammo < 0 )
- ammo = 0;
- }
- else
- ammo--;
-
- BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips );
- }
- else if( pm->ps->weapon == WP_ALEVEL3_UPG && attack3 )
- {
- //special case for slowblob
- ammo--;
- BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips );
- }
-
- //FIXME: predicted angles miss a problem??
- if( pm->ps->weapon == WP_CHAINGUN )
- {
- if( pm->ps->pm_flags & PMF_DUCKED ||
- BG_InventoryContainsUpgrade( UP_BATTLESUIT, pm->ps->stats ) )
- {
- pm->ps->delta_angles[ PITCH ] -= ANGLE2SHORT( ( ( random() * 0.5 ) - 0.125 ) * ( 30 / (float)addTime ) );
- pm->ps->delta_angles[ YAW ] -= ANGLE2SHORT( ( ( random() * 0.5 ) - 0.25 ) * ( 30.0 / (float)addTime ) );
- }
- else
- {
- pm->ps->delta_angles[ PITCH ] -= ANGLE2SHORT( ( ( random() * 8 ) - 2 ) * ( 30.0 / (float)addTime ) );
- pm->ps->delta_angles[ YAW ] -= ANGLE2SHORT( ( ( random() * 8 ) - 4 ) * ( 30.0 / (float)addTime ) );
- }
- }
-
- pm->ps->weaponTime += addTime;
-}
-
-/*
-================
-PM_Animate
-================
-*/
-static void PM_Animate( void )
-{
- if( pm->cmd.buttons & BUTTON_GESTURE )
- {
- if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
- {
- if( pm->ps->torsoTimer == 0 )
- {
- PM_StartTorsoAnim( TORSO_GESTURE );
- pm->ps->torsoTimer = TIMER_GESTURE;
-
- PM_AddEvent( EV_TAUNT );
- }
- }
- else
- {
- if( pm->ps->torsoTimer == 0 )
- {
- PM_ForceLegsAnim( NSPA_GESTURE );
- pm->ps->torsoTimer = TIMER_GESTURE;
-
- PM_AddEvent( EV_TAUNT );
- }
- }
- }
-}
-
-
-/*
-================
-PM_DropTimers
-================
-*/
-static void PM_DropTimers( void )
-{
- // drop misc timing counter
- if( pm->ps->pm_time )
- {
- if( pml.msec >= pm->ps->pm_time )
- {
- pm->ps->pm_flags &= ~PMF_ALL_TIMES;
- pm->ps->pm_time = 0;
- }
- else
- pm->ps->pm_time -= pml.msec;
- }
-
- // drop animation counter
- if( pm->ps->legsTimer > 0 )
- {
- pm->ps->legsTimer -= pml.msec;
-
- if( pm->ps->legsTimer < 0 )
- pm->ps->legsTimer = 0;
- }
-
- if( pm->ps->torsoTimer > 0 )
- {
- pm->ps->torsoTimer -= pml.msec;
-
- if( pm->ps->torsoTimer < 0 )
- pm->ps->torsoTimer = 0;
- }
-}
-
-
-/*
-================
-PM_UpdateViewAngles
-
-This can be used as another entry point when only the viewangles
-are being updated instead of a full move
-================
-*/
-void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd )
-{
- short temp[ 3 ];
- int i;
- vec3_t axis[ 3 ], rotaxis[ 3 ];
- vec3_t tempang;
-
- if( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION )
- return; // no view changes at all
-
- if( ps->pm_type != PM_SPECTATOR && ps->stats[ STAT_HEALTH ] <= 0 )
- return; // no view changes at all
-
- // circularly clamp the angles with deltas
- for( i = 0; i < 3; i++ )
- {
- temp[ i ] = cmd->angles[ i ] + ps->delta_angles[ i ];
-
- if( i == PITCH )
- {
- // don't let the player look up or down more than 90 degrees
- if( temp[ i ] > 16000 )
- {
- ps->delta_angles[ i ] = 16000 - cmd->angles[ i ];
- temp[ i ] = 16000;
- }
- else if( temp[ i ] < -16000 )
- {
- ps->delta_angles[ i ] = -16000 - cmd->angles[ i ];
- temp[ i ] = -16000;
- }
- }
- tempang[ i ] = SHORT2ANGLE( temp[ i ] );
- }
-
- //convert viewangles -> axis
- AnglesToAxis( tempang, axis );
-
- if( !( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) ||
- !BG_RotateAxis( ps->grapplePoint, axis, rotaxis, qfalse,
- ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) )
- AxisCopy( axis, rotaxis );
-
- //convert the new axis back to angles
- AxisToAngles( rotaxis, tempang );
-
- //force angles to -180 <= x <= 180
- for( i = 0; i < 3; i++ )
- {
- while( tempang[ i ] > 180 )
- tempang[ i ] -= 360;
-
- while( tempang[ i ] < 180 )
- tempang[ i ] += 360;
- }
-
- //actually set the viewangles
- for( i = 0; i < 3; i++ )
- ps->viewangles[ i ] = tempang[ i ];
-
- //pull the view into the lock point
- if( ps->pm_type == PM_GRABBED && !BG_InventoryContainsUpgrade( UP_BATTLESUIT, ps->stats ) )
- {
- vec3_t dir, angles;
-
- ByteToDir( ps->stats[ STAT_VIEWLOCK ], dir );
- vectoangles( dir, angles );
-
- for( i = 0; i < 3; i++ )
- {
- float diff = AngleSubtract( ps->viewangles[ i ], angles[ i ] );
-
- while( diff > 180.0f )
- diff -= 360.0f;
- while( diff < -180.0f )
- diff += 360.0f;
-
- if( diff < -90.0f )
- ps->delta_angles[ i ] += ANGLE2SHORT( fabs( diff ) - 90.0f );
- else if( diff > 90.0f )
- ps->delta_angles[ i ] -= ANGLE2SHORT( fabs( diff ) - 90.0f );
-
- if( diff < 0.0f )
- ps->delta_angles[ i ] += ANGLE2SHORT( fabs( diff ) * 0.05f );
- else if( diff > 0.0f )
- ps->delta_angles[ i ] -= ANGLE2SHORT( fabs( diff ) * 0.05f );
- }
- }
-}
-
-
-/*
-================
-PmoveSingle
-
-================
-*/
-void trap_SnapVector( float *v );
-
-void PmoveSingle( pmove_t *pmove )
-{
- int ammo, clips;
-
- pm = pmove;
-
- BG_UnpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips );
-
- // this counter lets us debug movement problems with a journal
- // by setting a conditional breakpoint fot the previous frame
- c_pmove++;
-
- // clear results
- pm->numtouch = 0;
- pm->watertype = 0;
- pm->waterlevel = 0;
-
- if( pm->ps->stats[ STAT_HEALTH ] <= 0 )
- pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies
-
- // make sure walking button is clear if they are running, to avoid
- // proxy no-footsteps cheats
- if( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 )
- pm->cmd.buttons &= ~BUTTON_WALKING;
-
- // set the talk balloon flag
- if( pm->cmd.buttons & BUTTON_TALK )
- pm->ps->eFlags |= EF_TALK;
- else
- pm->ps->eFlags &= ~EF_TALK;
-
- // set the firing flag for continuous beam weapons
- if( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION &&
- ( pm->cmd.buttons & BUTTON_ATTACK ) &&
- ( ( ammo > 0 || clips > 0 ) || BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) )
- pm->ps->eFlags |= EF_FIRING;
- else
- pm->ps->eFlags &= ~EF_FIRING;
-
- // set the firing flag for continuous beam weapons
- if( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION &&
- ( pm->cmd.buttons & BUTTON_ATTACK2 ) &&
- ( ( ammo > 0 || clips > 0 ) || BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) )
- pm->ps->eFlags |= EF_FIRING2;
- else
- pm->ps->eFlags &= ~EF_FIRING2;
-
- // set the firing flag for continuous beam weapons
- if( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION &&
- ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) &&
- ( ( ammo > 0 || clips > 0 ) || BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) )
- pm->ps->eFlags |= EF_FIRING3;
- else
- pm->ps->eFlags &= ~EF_FIRING3;
-
-
- // clear the respawned flag if attack and use are cleared
- if( pm->ps->stats[STAT_HEALTH] > 0 &&
- !( pm->cmd.buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) )
- pm->ps->pm_flags &= ~PMF_RESPAWNED;
-
- // if talk button is down, dissallow all other input
- // this is to prevent any possible intercept proxy from
- // adding fake talk balloons
- if( pmove->cmd.buttons & BUTTON_TALK )
- {
- pmove->cmd.buttons = BUTTON_TALK;
- pmove->cmd.forwardmove = 0;
- pmove->cmd.rightmove = 0;
- pmove->cmd.upmove = 0;
- }
-
- // clear all pmove local vars
- memset( &pml, 0, sizeof( pml ) );
-
- // determine the time
- pml.msec = pmove->cmd.serverTime - pm->ps->commandTime;
-
- if( pml.msec < 1 )
- pml.msec = 1;
- else if( pml.msec > 200 )
- pml.msec = 200;
-
- pm->ps->commandTime = pmove->cmd.serverTime;
-
- // save old org in case we get stuck
- VectorCopy( pm->ps->origin, pml.previous_origin );
-
- // save old velocity for crashlanding
- VectorCopy( pm->ps->velocity, pml.previous_velocity );
-
- pml.frametime = pml.msec * 0.001;
-
- AngleVectors( pm->ps->viewangles, pml.forward, pml.right, pml.up );
-
- if( pm->cmd.upmove < 10 )
- {
- // not holding jump
- pm->ps->pm_flags &= ~PMF_JUMP_HELD;
- }
-
- // decide if backpedaling animations should be used
- if( pm->cmd.forwardmove < 0 )
- pm->ps->pm_flags |= PMF_BACKWARDS_RUN;
- else if( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) )
- pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN;
-
- if( pm->ps->pm_type >= PM_DEAD )
- {
- pm->cmd.forwardmove = 0;
- pm->cmd.rightmove = 0;
- pm->cmd.upmove = 0;
- }
-
- if( pm->ps->pm_type == PM_SPECTATOR )
- {
- // update the viewangles
- PM_UpdateViewAngles( pm->ps, &pm->cmd );
- PM_CheckDuck( );
- PM_FlyMove( );
- PM_DropTimers( );
- return;
- }
-
- if( pm->ps->pm_type == PM_NOCLIP )
- {
- PM_UpdateViewAngles( pm->ps, &pm->cmd );
- PM_NoclipMove( );
- PM_DropTimers( );
- return;
- }
-
- if( pm->ps->pm_type == PM_FREEZE)
- return; // no movement at all
-
- if( pm->ps->pm_type == PM_INTERMISSION || pm->ps->pm_type == PM_SPINTERMISSION )
- return; // no movement at all
-
- // set watertype, and waterlevel
- PM_SetWaterLevel( );
- pml.previous_waterlevel = pmove->waterlevel;
-
- // set mins, maxs, and viewheight
- PM_CheckDuck( );
-
- PM_CheckLadder( );
-
- // set groundentity
- PM_GroundTrace( );
-
- // update the viewangles
- PM_UpdateViewAngles( pm->ps, &pm->cmd );
-
- if( pm->ps->pm_type == PM_DEAD || pm->ps->pm_type == PM_GRABBED )
- PM_DeadMove( );
-
- PM_DropTimers( );
-
- if( pm->ps->pm_type == PM_JETPACK )
- PM_JetPackMove( );
- else if( pm->ps->pm_flags & PMF_TIME_WATERJUMP )
- PM_WaterJumpMove( );
- else if( pm->waterlevel > 1 )
- PM_WaterMove( );
- else if( pml.ladder )
- PM_LadderMove( );
- else if( pml.walking )
- {
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) &&
- ( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) )
- PM_ClimbMove( ); //TA: walking on any surface
- else
- PM_WalkMove( ); // walking on ground
- }
- else
- PM_AirMove( );
-
- PM_Animate( );
-
- // set groundentity, watertype, and waterlevel
- PM_GroundTrace( );
- //TA: must update after every GroundTrace() - yet more clock cycles down the drain :( (14 vec rotations/frame)
- // update the viewangles
- PM_UpdateViewAngles( pm->ps, &pm->cmd );
-
- PM_SetWaterLevel( );
-
- // weapons
- PM_Weapon( );
-
- // torso animation
- PM_TorsoAnimation( );
-
- // footstep events / legs animations
- PM_Footsteps( );
-
- // entering / leaving water splashes
- PM_WaterEvents( );
-
- // snap some parts of playerstate to save network bandwidth
- trap_SnapVector( pm->ps->velocity );
-}
-
-
-/*
-================
-Pmove
-
-Can be called by either the server or the client
-================
-*/
-void Pmove( pmove_t *pmove )
-{
- int finalTime;
-
- finalTime = pmove->cmd.serverTime;
-
- if( finalTime < pmove->ps->commandTime )
- return; // should not happen
-
- if( finalTime > pmove->ps->commandTime + 1000 )
- pmove->ps->commandTime = finalTime - 1000;
-
- pmove->ps->pmove_framecount = ( pmove->ps->pmove_framecount + 1 ) & ( ( 1 << PS_PMOVEFRAMECOUNTBITS ) - 1 );
-
- // chop the move up if it is too long, to prevent framerate
- // dependent behavior
- while( pmove->ps->commandTime != finalTime )
- {
- int msec;
-
- msec = finalTime - pmove->ps->commandTime;
-
- if( pmove->pmove_fixed )
- {
- if( msec > pmove->pmove_msec )
- msec = pmove->pmove_msec;
- }
- else
- {
- if( msec > 66 )
- msec = 66;
- }
-
-
- pmove->cmd.serverTime = pmove->ps->commandTime + msec;
- PmoveSingle( pmove );
-
- if( pmove->ps->pm_flags & PMF_JUMP_HELD )
- pmove->cmd.upmove = 20;
- }
-}