summaryrefslogtreecommitdiff
path: root/src/game/bg_pmove.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/bg_pmove.c')
-rw-r--r--src/game/bg_pmove.c1164
1 files changed, 716 insertions, 448 deletions
diff --git a/src/game/bg_pmove.c b/src/game/bg_pmove.c
index 542b585..c5f2293 100644
--- a/src/game/bg_pmove.c
+++ b/src/game/bg_pmove.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,15 +17,15 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
// bg_pmove.c -- both games player movement code
// takes a playerstate and a usercmd as input and returns a modifed playerstate
-#include "../qcommon/q_shared.h"
+#include "qcommon/q_shared.h"
#include "bg_public.h"
#include "bg_local.h"
@@ -35,10 +36,8 @@ pml_t pml;
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;
@@ -92,9 +91,9 @@ void PM_AddTouchEnt( int entityNum )
PM_StartTorsoAnim
===================
*/
-static void PM_StartTorsoAnim( int anim )
+void PM_StartTorsoAnim( int anim )
{
- if( pm->ps->pm_type >= PM_DEAD )
+ if( PM_Paralyzed( pm->ps->pm_type ) )
return;
pm->ps->torsoAnim = ( ( pm->ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
@@ -103,12 +102,26 @@ static void PM_StartTorsoAnim( int anim )
/*
===================
+PM_StartWeaponAnim
+===================
+*/
+static void PM_StartWeaponAnim( int anim )
+{
+ if( PM_Paralyzed( pm->ps->pm_type ) )
+ return;
+
+ pm->ps->weaponAnim = ( ( pm->ps->weaponAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
+ | anim;
+}
+
+/*
+===================
PM_StartLegsAnim
===================
*/
static void PM_StartLegsAnim( int anim )
{
- if( pm->ps->pm_type >= PM_DEAD )
+ if( PM_Paralyzed( pm->ps->pm_type ) )
return;
//legsTimer is clamped too tightly for nonsegmented models
@@ -170,6 +183,19 @@ static void PM_ContinueTorsoAnim( int anim )
/*
===================
+PM_ContinueWeaponAnim
+===================
+*/
+static void PM_ContinueWeaponAnim( int anim )
+{
+ if( ( pm->ps->weaponAnim & ~ANIM_TOGGLEBIT ) == anim )
+ return;
+
+ PM_StartWeaponAnim( anim );
+}
+
+/*
+===================
PM_ForceLegsAnim
===================
*/
@@ -192,29 +218,10 @@ PM_ClipVelocity
Slide off of the impacting surface
==================
*/
-void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce )
+void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out )
{
- 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( " " );
+ float t = -DotProduct( in, normal );
+ VectorMA( in, t, normal, out );
}
@@ -234,20 +241,15 @@ static void PM_Friction( void )
vel = pm->ps->velocity;
- //TA: make sure vertical velocity is NOT set to zero when wall climbing
+ // 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?
+ if( speed < 0.1 )
return;
- }
drop = 0;
@@ -259,10 +261,11 @@ static void PM_Friction( void )
// if getting knocked back, no friction
if( !( pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) )
{
- float stopSpeed = BG_FindStopSpeedForClass( pm->ps->stats[ STAT_PCLASS ] );
+ float stopSpeed = BG_Class( pm->ps->stats[ STAT_CLASS ] )->stopSpeed;
+ float friction = BG_Class( pm->ps->stats[ STAT_CLASS ] )->friction;
control = speed < stopSpeed ? stopSpeed : speed;
- drop += control * BG_FindFrictionForClass( pm->ps->stats[ STAT_PCLASS ] ) * pml.frametime;
+ drop += control * friction * pml.frametime;
}
}
}
@@ -346,16 +349,43 @@ 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 )
+static float PM_CmdScale( usercmd_t *cmd, qboolean zFlight )
{
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_TEAM ] == TEAM_HUMANS && pm->ps->pm_type == PM_NORMAL )
{
- if( pm->ps->stats[ STAT_STATE ] & SS_SPEEDBOOST )
+ qboolean wasSprinting;
+ qboolean sprint;
+ wasSprinting = sprint = pm->ps->stats[ STAT_STATE ] & SS_SPEEDBOOST;
+
+ if( pm->ps->persistant[ PERS_STATE ] & PS_SPRINTTOGGLE )
+ {
+ if( cmd->buttons & BUTTON_SPRINT &&
+ !( pm->ps->pm_flags & PMF_SPRINTHELD ) )
+ {
+ sprint = !sprint;
+ pm->ps->pm_flags |= PMF_SPRINTHELD;
+ }
+ else if( pm->ps->pm_flags & PMF_SPRINTHELD &&
+ !( cmd->buttons & BUTTON_SPRINT ) )
+ pm->ps->pm_flags &= ~PMF_SPRINTHELD;
+ }
+ else
+ sprint = cmd->buttons & BUTTON_SPRINT;
+
+ if( sprint )
+ pm->ps->stats[ STAT_STATE ] |= SS_SPEEDBOOST;
+ else if( wasSprinting && !sprint )
+ pm->ps->stats[ STAT_STATE ] &= ~SS_SPEEDBOOST;
+
+ // Walk overrides sprint. We keep the state that we want to be sprinting
+ // (above), but don't apply the modifier, and in g_active we skip taking
+ // the stamina too.
+ if( sprint && !( cmd->buttons & BUTTON_WALKING ) )
modifier *= HUMAN_SPRINT_MODIFIER;
else
modifier *= HUMAN_JOG_MODIFIER;
@@ -371,13 +401,16 @@ static float PM_CmdScale( usercmd_t *cmd )
modifier *= HUMAN_SIDE_MODIFIER;
}
- //must have +ve stamina to jump
- if( pm->ps->stats[ STAT_STAMINA ] < 0 )
- cmd->upmove = 0;
+ if( !zFlight )
+ {
+ //must have have stamina to jump
+ if( pm->ps->stats[ STAT_STAMINA ] < STAMINA_SLOW_LEVEL + STAMINA_JUMP_TAKE )
+ 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_STAMINA ] <= STAMINA_SLOW_LEVEL )
+ modifier *= (float)( pm->ps->stats[ STAT_STAMINA ] + STAMINA_MAX ) / (float)(STAMINA_SLOW_LEVEL + STAMINA_MAX);
if( pm->ps->stats[ STAT_STATE ] & SS_CREEPSLOWED )
{
@@ -387,11 +420,20 @@ static float PM_CmdScale( usercmd_t *cmd )
else
modifier *= CREEP_MODIFIER;
}
+ if( pm->ps->eFlags & EF_POISONCLOUDED )
+ {
+ if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, pm->ps->stats ) ||
+ BG_InventoryContainsUpgrade( UP_BATTLESUIT, pm->ps->stats ) )
+ modifier *= PCLOUD_ARMOUR_MODIFIER;
+ else
+ modifier *= PCLOUD_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 ) );
+ modifier *= 1.0f + ( pm->ps->stats[ STAT_MISC ] *
+ ( LEVEL4_TRAMPLE_SPEED - 1.0f ) /
+ LEVEL4_TRAMPLE_DURATION );
//slow player if charging up for a pounce
if( ( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG ) &&
@@ -405,28 +447,22 @@ static float PM_CmdScale( usercmd_t *cmd )
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 );
+ total = cmd->forwardmove * cmd->forwardmove + cmd->rightmove * cmd->rightmove;
- if( abs( cmd->upmove ) > max )
- max = abs( cmd->upmove );
+ if( zFlight )
+ {
+ if( abs( cmd->upmove ) > max )
+ max = abs( cmd->upmove );
+ total += cmd->upmove * cmd->upmove;
+ }
if( !max )
return 0;
- total = sqrt( cmd->forwardmove * cmd->forwardmove
- + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove );
+ total = sqrt( total );
scale = (float)pm->ps->speed * max / ( 127.0 * total ) * modifier;
@@ -438,7 +474,7 @@ static float PM_CmdScale( usercmd_t *cmd )
================
PM_SetMovementDir
-Determine the rotation of the legs reletive
+Determine the rotation of the legs relative
to the facing dir
================
*/
@@ -506,40 +542,49 @@ PM_CheckPounce
*/
static qboolean PM_CheckPounce( void )
{
+ int jumpMagnitude;
+
if( pm->ps->weapon != WP_ALEVEL3 &&
pm->ps->weapon != WP_ALEVEL3_UPG )
return qfalse;
- // we were pouncing, but we've landed
- if( pm->ps->groundEntityNum != ENTITYNUM_NONE
- && ( pm->ps->pm_flags & PMF_CHARGE ) )
+ // We were pouncing, but we've landed
+ if( pm->ps->groundEntityNum != ENTITYNUM_NONE &&
+ ( pm->ps->pm_flags & PMF_CHARGE ) )
{
- pm->ps->weaponTime += LEVEL3_POUNCE_TIME;
pm->ps->pm_flags &= ~PMF_CHARGE;
+ pm->ps->weaponTime += LEVEL3_POUNCE_REPEAT;
+ return qfalse;
}
- // we're building up for a pounce
+ // We're building up for a pounce
if( pm->cmd.buttons & BUTTON_ATTACK2 )
+ {
+ pm->ps->pm_flags &= ~PMF_CHARGE;
return qfalse;
+ }
- // already a pounce in progress
- if( pm->ps->pm_flags & PMF_CHARGE )
- return qfalse;
-
- if( pm->ps->stats[ STAT_MISC ] == 0 )
+ // Can't start a pounce
+ if( ( pm->ps->pm_flags & PMF_CHARGE ) ||
+ pm->ps->stats[ STAT_MISC ] < LEVEL3_POUNCE_TIME_MIN ||
+ pm->ps->groundEntityNum == ENTITYNUM_NONE )
return qfalse;
- pml.groundPlane = qfalse; // jumping away
+ // Give the player forward velocity and simulate a jump
+ pml.groundPlane = qfalse;
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 );
-
+ if( pm->ps->weapon == WP_ALEVEL3 )
+ jumpMagnitude = pm->ps->stats[ STAT_MISC ] *
+ LEVEL3_POUNCE_JUMP_MAG / LEVEL3_POUNCE_TIME;
+ else
+ jumpMagnitude = pm->ps->stats[ STAT_MISC ] *
+ LEVEL3_POUNCE_JUMP_MAG_UPG / LEVEL3_POUNCE_TIME_UPG;
+ VectorMA( pm->ps->velocity, jumpMagnitude, pml.forward, pm->ps->velocity );
PM_AddEvent( EV_JUMP );
+ // Play jumping animation
if( pm->cmd.forwardmove >= 0 )
{
if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
@@ -572,15 +617,47 @@ PM_CheckWallJump
*/
static qboolean PM_CheckWallJump( void )
{
- vec3_t dir, forward, right;
+ vec3_t dir, forward, right, movedir, point;
vec3_t refNormal = { 0.0f, 0.0f, 1.0f };
float normalFraction = 1.5f;
float cmdFraction = 1.0f;
float upFraction = 1.5f;
+ trace_t trace;
+
+ if( !( BG_Class( pm->ps->stats[ STAT_CLASS ] )->abilities & SCA_WALLJUMPER ) )
+ return qfalse;
+ 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.plane.normal[ 2 ] < MIN_WALK_NORMAL )
+ {
+ VectorCopy( trace.plane.normal, pm->ps->grapplePoint );
+ }
+ else
+ 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;
@@ -592,8 +669,6 @@ static qboolean PM_CheckWallJump( void )
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;
}
@@ -624,7 +699,7 @@ static qboolean PM_CheckWallJump( void )
VectorMA( dir, upFraction, refNormal, dir );
VectorNormalize( dir );
- VectorMA( pm->ps->velocity, BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] ),
+ VectorMA( pm->ps->velocity, BG_Class( pm->ps->stats[ STAT_CLASS ] )->jumpMagnitude,
dir, pm->ps->velocity );
//for a long run of wall jumps the velocity can get pretty large, this caps it
@@ -665,11 +740,13 @@ PM_CheckJump
*/
static qboolean PM_CheckJump( void )
{
- if( BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] ) == 0.0f )
+ vec3_t normal;
+
+ if( pm->ps->groundEntityNum == ENTITYNUM_NONE )
return qfalse;
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) )
- return PM_CheckWallJump( );
+ if( BG_Class( pm->ps->stats[ STAT_CLASS ] )->jumpMagnitude == 0.0f )
+ return qfalse;
//can't jump and pounce at the same time
if( ( pm->ps->weapon == WP_ALEVEL3 ||
@@ -682,8 +759,13 @@ static qboolean PM_CheckJump( void )
pm->ps->stats[ STAT_MISC ] > 0 )
return qfalse;
- if( ( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS ) &&
- ( pm->ps->stats[ STAT_STAMINA ] < 0 ) )
+ if( ( pm->ps->stats[ STAT_TEAM ] == TEAM_HUMANS ) &&
+ ( pm->ps->stats[ STAT_STAMINA ] < STAMINA_SLOW_LEVEL + STAMINA_JUMP_TAKE ) )
+ return qfalse;
+
+ //no bunny hopping off a dodge
+ if( pm->ps->stats[ STAT_TEAM ] == TEAM_HUMANS &&
+ pm->ps->pm_time )
return qfalse;
if( pm->ps->pm_flags & PMF_RESPAWNED )
@@ -695,42 +777,37 @@ static qboolean PM_CheckJump( void )
//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;
+
+ //don't allow walljump for a short while after jumping from the ground
+ if( BG_ClassHasAbility( pm->ps->stats[ STAT_CLASS ], SCA_WALLJUMPER ) )
+ {
+ 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;
- //TA: take some stamina off
- if( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS )
- pm->ps->stats[ STAT_STAMINA ] -= 500;
+ // take some stamina off
+ if( pm->ps->stats[ STAT_TEAM ] == TEAM_HUMANS )
+ pm->ps->stats[ STAT_STAMINA ] -= STAMINA_JUMP_TAKE;
pm->ps->groundEntityNum = ENTITYNUM_NONE;
- //TA: jump away from wall
- if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
- {
- vec3_t normal = { 0, 0, -1 };
+ // jump away from wall
+ BG_GetClientNormal( pm->ps, normal );
+
+ if( pm->ps->velocity[ 2 ] < 0 )
+ pm->ps->velocity[ 2 ] = 0;
- 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 ] );
+ VectorMA( pm->ps->velocity, BG_Class( pm->ps->stats[ STAT_CLASS ] )->jumpMagnitude,
+ normal, pm->ps->velocity );
PM_AddEvent( EV_JUMP );
@@ -802,6 +879,108 @@ static qboolean PM_CheckWaterJump( void )
return qtrue;
}
+
+/*
+==================
+PM_CheckDodge
+
+Checks the dodge key and starts a human dodge or sprint
+==================
+*/
+static qboolean PM_CheckDodge( void )
+{
+ vec3_t right, forward, velocity = { 0.0f, 0.0f, 0.0f };
+ float jump, sideModifier;
+ int i;
+
+ if( pm->ps->stats[ STAT_TEAM ] != TEAM_HUMANS )
+ return qfalse;
+
+ // Landed a dodge
+ if( ( pm->ps->pm_flags & PMF_CHARGE ) &&
+ pm->ps->groundEntityNum != ENTITYNUM_NONE )
+ {
+ pm->ps->pm_flags = ( pm->ps->pm_flags & ~PMF_CHARGE ) | PMF_TIME_LAND;
+ pm->ps->pm_time = HUMAN_DODGE_TIMEOUT;
+ }
+
+ // Reasons why we can't start a dodge or sprint
+ if( pm->ps->pm_type != PM_NORMAL || pm->ps->stats[ STAT_STAMINA ] < STAMINA_SLOW_LEVEL + STAMINA_DODGE_TAKE ||
+ ( pm->ps->pm_flags & PMF_DUCKED ) )
+ return qfalse;
+
+ // Can't dodge forward
+ if( pm->cmd.forwardmove > 0 )
+ return qfalse;
+
+ // Reasons why we can't start a dodge only
+ if( pm->ps->pm_flags & ( PMF_TIME_LAND | PMF_CHARGE ) ||
+ pm->ps->groundEntityNum == ENTITYNUM_NONE ||
+ !( pm->cmd.buttons & BUTTON_DODGE ) )
+ return qfalse;
+
+ // Dodge direction specified with movement keys
+ if( ( !pm->cmd.rightmove && !pm->cmd.forwardmove ) || pm->cmd.upmove )
+ return qfalse;
+
+ AngleVectors( pm->ps->viewangles, NULL, right, NULL );
+ forward[ 0 ] = -right[ 1 ];
+ forward[ 1 ] = right[ 0 ];
+ forward[ 2 ] = 0.0f;
+
+ // Dodge magnitude is based on the jump magnitude scaled by the modifiers
+ jump = BG_Class( pm->ps->stats[ STAT_CLASS ] )->jumpMagnitude;
+ if( pm->cmd.rightmove && pm->cmd.forwardmove )
+ jump *= ( 0.5f * M_SQRT2 );
+
+ // Weaken dodge if slowed
+ if( ( pm->ps->stats[ STAT_STATE ] & SS_SLOWLOCKED ) ||
+ ( pm->ps->stats[ STAT_STATE ] & SS_CREEPSLOWED ) ||
+ ( pm->ps->eFlags & EF_POISONCLOUDED ) )
+ sideModifier = HUMAN_DODGE_SLOWED_MODIFIER;
+ else
+ sideModifier = HUMAN_DODGE_SIDE_MODIFIER;
+
+ // The dodge sets minimum velocity
+ if( pm->cmd.rightmove )
+ {
+ if( pm->cmd.rightmove < 0 )
+ VectorNegate( right, right );
+ VectorMA( velocity, jump * sideModifier, right, velocity );
+ }
+
+ if( pm->cmd.forwardmove )
+ {
+ if( pm->cmd.forwardmove < 0 )
+ VectorNegate( forward, forward );
+ VectorMA( velocity, jump * sideModifier, forward, velocity );
+ }
+
+ velocity[ 2 ] = jump * HUMAN_DODGE_UP_MODIFIER;
+
+ // Make sure client has minimum velocity
+ for( i = 0; i < 3; i++ )
+ {
+ if( ( velocity[ i ] < 0.0f &&
+ pm->ps->velocity[ i ] > velocity[ i ] ) ||
+ ( velocity[ i ] > 0.0f &&
+ pm->ps->velocity[ i ] < velocity[ i ] ) )
+ pm->ps->velocity[ i ] = velocity[ i ];
+ }
+
+ // Jumped away
+ pml.groundPlane = qfalse;
+ pml.walking = qfalse;
+ pm->ps->groundEntityNum = ENTITYNUM_NONE;
+ pm->ps->pm_flags |= PMF_CHARGE;
+ pm->ps->stats[ STAT_STAMINA ] -= STAMINA_DODGE_TAKE;
+ pm->ps->legsAnim = ( ( pm->ps->legsAnim & ANIM_TOGGLEBIT ) ^
+ ANIM_TOGGLEBIT ) | LEGS_JUMP;
+ PM_AddEvent( EV_JUMP );
+
+ return qtrue;
+}
+
//============================================================================
@@ -863,23 +1042,15 @@ static void PM_WaterMove( void )
#endif
PM_Friction( );
- scale = PM_CmdScale( &pm->cmd );
+ scale = PM_CmdScale( &pm->cmd, qtrue );
//
// 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;
- }
+ 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 );
@@ -894,8 +1065,7 @@ static void PM_WaterMove( void )
{
vel = VectorLength( pm->ps->velocity );
// slide along the ground plane
- PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
+ PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity );
VectorNormalize( pm->ps->velocity );
VectorScale( pm->ps->velocity, vel, pm->ps->velocity );
@@ -922,7 +1092,7 @@ static void PM_JetPackMove( void )
//normal slowdown
PM_Friction( );
- scale = PM_CmdScale( &pm->cmd );
+ scale = PM_CmdScale( &pm->cmd, qfalse );
// user intentions
for( i = 0; i < 2; i++ )
@@ -969,7 +1139,7 @@ static void PM_FlyMove( void )
// normal slowdown
PM_Friction( );
- scale = PM_CmdScale( &pm->cmd );
+ scale = PM_CmdScale( &pm->cmd, qtrue );
//
// user intentions
//
@@ -1012,13 +1182,14 @@ static void PM_AirMove( void )
float scale;
usercmd_t cmd;
+ PM_CheckWallJump( );
PM_Friction( );
fmove = pm->cmd.forwardmove;
smove = pm->cmd.rightmove;
cmd = pm->cmd;
- scale = PM_CmdScale( &cmd );
+ scale = PM_CmdScale( &cmd, qfalse );
// set the movementDir so clients can rotate the legs for strafing
PM_SetMovementDir( );
@@ -1040,14 +1211,13 @@ static void PM_AirMove( void )
// not on ground, so little effect on velocity
PM_Accelerate( wishdir, wishspeed,
- BG_FindAirAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] ) );
+ BG_Class( pm->ps->stats[ STAT_CLASS ] )->airAcceleration );
// 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_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity );
PM_StepSlideMove( qtrue, qfalse );
}
@@ -1095,14 +1265,14 @@ static void PM_ClimbMove( void )
smove = pm->cmd.rightmove;
cmd = pm->cmd;
- scale = PM_CmdScale( &cmd );
+ scale = PM_CmdScale( &cmd, qfalse );
// 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 );
+ PM_ClipVelocity( pml.forward, pml.groundTrace.plane.normal, pml.forward );
+ PM_ClipVelocity( pml.right, pml.groundTrace.plane.normal, pml.right );
//
VectorNormalize( pml.forward );
VectorNormalize( pml.right );
@@ -1138,9 +1308,9 @@ static void PM_ClimbMove( void )
// 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 ] );
+ accelerate = BG_Class( pm->ps->stats[ STAT_CLASS ] )->airAcceleration;
else
- accelerate = BG_FindAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] );
+ accelerate = BG_Class( pm->ps->stats[ STAT_CLASS ] )->acceleration;
PM_Accelerate( wishdir, wishspeed, accelerate );
@@ -1150,8 +1320,7 @@ static void PM_ClimbMove( void )
vel = VectorLength( pm->ps->velocity );
// slide along the ground plane
- PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
+ PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity );
// don't decrease velocity when going up or down a slope
VectorNormalize( pm->ps->velocity );
@@ -1189,7 +1358,6 @@ static void PM_WalkMove( void )
return;
}
-
if( PM_CheckJump( ) || PM_CheckPounce( ) )
{
// jumped away
@@ -1210,7 +1378,7 @@ static void PM_WalkMove( void )
smove = pm->cmd.rightmove;
cmd = pm->cmd;
- scale = PM_CmdScale( &cmd );
+ scale = PM_CmdScale( &cmd, qfalse );
// set the movementDir so clients can rotate the legs for strafing
PM_SetMovementDir( );
@@ -1220,8 +1388,8 @@ static void PM_WalkMove( void )
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 );
+ PM_ClipVelocity( pml.forward, pml.groundTrace.plane.normal, pml.forward );
+ PM_ClipVelocity( pml.right, pml.groundTrace.plane.normal, pml.right );
//
VectorNormalize( pml.forward );
VectorNormalize( pml.right );
@@ -1257,9 +1425,9 @@ static void PM_WalkMove( void )
// 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 ] );
+ accelerate = BG_Class( pm->ps->stats[ STAT_CLASS ] )->airAcceleration;
else
- accelerate = BG_FindAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] );
+ accelerate = BG_Class( pm->ps->stats[ STAT_CLASS ] )->acceleration;
PM_Accelerate( wishdir, wishspeed, accelerate );
@@ -1275,8 +1443,7 @@ static void PM_WalkMove( void )
}
// slide along the ground plane
- PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
+ PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity );
// don't do anything if standing still
if( !pm->ps->velocity[ 0 ] && !pm->ps->velocity[ 1 ] )
@@ -1307,7 +1474,7 @@ static void PM_LadderMove( void )
PM_Friction( );
- scale = PM_CmdScale( &pm->cmd );
+ scale = PM_CmdScale( &pm->cmd, qtrue );
for( i = 0; i < 3; i++ )
wishvel[ i ] = scale * pml.forward[ i ] * pm->cmd.forwardmove + scale * pml.right[ i ] * pm->cmd.rightmove;
@@ -1328,8 +1495,7 @@ static void PM_LadderMove( void )
vel = VectorLength( pm->ps->velocity );
// slide along the ground plane
- PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
+ PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity );
VectorNormalize( pm->ps->velocity );
VectorScale( pm->ps->velocity, vel, pm->ps->velocity );
@@ -1352,7 +1518,7 @@ static void PM_CheckLadder( void )
trace_t trace;
//test if class can use ladders
- if( !BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_CANUSELADDERS ) )
+ if( !BG_ClassHasAbility( pm->ps->stats[ STAT_CLASS ], SCA_CANUSELADDERS ) )
{
pml.ladder = qfalse;
return;
@@ -1414,8 +1580,6 @@ static void PM_NoclipMove( void )
float wishspeed;
float scale;
- pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
-
// friction
speed = VectorLength( pm->ps->velocity );
@@ -1444,7 +1608,7 @@ static void PM_NoclipMove( void )
}
// accelerate
- scale = PM_CmdScale( &pm->cmd );
+ scale = PM_CmdScale( &pm->cmd, qtrue );
fmove = pm->cmd.forwardmove;
smove = pm->cmd.rightmove;
@@ -1475,7 +1639,6 @@ 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;
@@ -1543,10 +1706,6 @@ static void PM_CrashLand( void )
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;
@@ -1571,12 +1730,12 @@ static void PM_CrashLand( void )
if( delta > AVG_FALL_DISTANCE )
{
- PM_AddEvent( EV_FALL_FAR );
+ if( PM_Alive( pm->ps->pm_type ) )
+ 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 )
+ if( PM_Alive( pm->ps->pm_type ) )
PM_AddEvent( EV_FALL_MEDIUM );
}
else
@@ -1688,7 +1847,7 @@ static void PM_GroundTraceMissed( void )
}
}
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_TAKESFALLDAMAGE ) )
+ if( BG_ClassHasAbility( pm->ps->stats[ STAT_CLASS ], SCA_TAKESFALLDAMAGE ) )
{
if( pm->ps->velocity[ 2 ] < FALLING_THRESHOLD && pml.previous_velocity[ 2 ] >= FALLING_THRESHOLD )
PM_AddEvent( EV_FALLING );
@@ -1699,7 +1858,6 @@ static void PM_GroundTraceMissed( void )
pml.walking = qfalse;
}
-
/*
=============
PM_GroundClimbTrace
@@ -1707,12 +1865,13 @@ 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;
+ 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;
+ const float eps = 0.000001f;
//used for delta correction
vec3_t traceCROSSsurf, traceCROSSref, surfCROSSref;
@@ -1724,12 +1883,7 @@ static void PM_GroundClimbTrace( void )
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 );
+ BG_GetClientNormal( pm->ps, surfNormal );
//construct a vector which reflects the direction the player is looking wrt the surface normal
ProjectPointOnPlane( movedir, pml.forward, surfNormal );
@@ -1765,8 +1919,10 @@ static void PM_GroundClimbTrace( void )
case 1:
//trace straight down anto "ground" surface
+ //mask out CONTENTS_BODY to not hit other players and avoid the camera flipping out when
+ // wallwalkers touch
VectorMA( pm->ps->origin, -0.25f, surfNormal, point );
- pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
+ pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask & ~CONTENTS_BODY );
break;
case 2:
@@ -1801,7 +1957,7 @@ static void PM_GroundClimbTrace( void )
}
//if we hit something
- if( trace.fraction < 1.0f && !( trace.surfaceFlags & ( SURF_SKY | SURF_SLICK ) ) &&
+ if( trace.fraction < 1.0f && !( trace.surfaceFlags & ( SURF_SKY | SURF_SLICK ) ) &&
!( trace.entityNum != ENTITYNUM_WORLD && i != 4 ) )
{
if( i == 2 || i == 3 )
@@ -1811,7 +1967,7 @@ static void PM_GroundClimbTrace( void )
VectorCopy( trace.endpos, pm->ps->origin );
}
-
+
//calculate a bunch of stuff...
CrossProduct( trace.plane.normal, surfNormal, traceCROSSsurf );
VectorNormalize( traceCROSSsurf );
@@ -1845,11 +2001,11 @@ static void PM_GroundClimbTrace( void )
//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( !VectorCompareEpsilon( trace.plane.normal, surfNormal, eps ) )
{
//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 ) )
+ if( !VectorCompareEpsilon( trace.plane.normal, refNormal, eps ) && !VectorCompareEpsilon( surfNormal, refNormal, eps ) &&
+ !VectorCompareEpsilon( trace.plane.normal, ceilingNormal, eps ) && !VectorCompareEpsilon( surfNormal, ceilingNormal, eps ) )
{
//behold the evil mindfuck from hell
//it has fucked mind like nothing has fucked mind before
@@ -1907,16 +2063,16 @@ static void PM_GroundClimbTrace( void )
//transition from wall to ceiling
//normal for subsequent viewangle rotations
- if( VectorCompare( trace.plane.normal, ceilingNormal ) )
+ if( VectorCompareEpsilon( trace.plane.normal, ceilingNormal, eps ) )
{
CrossProduct( surfNormal, trace.plane.normal, pm->ps->grapplePoint );
VectorNormalize( pm->ps->grapplePoint );
- pm->ps->stats[ STAT_STATE ] |= SS_WALLCLIMBINGCEILING;
+ pm->ps->eFlags |= EF_WALLCLIMBCEILING;
}
//transition from ceiling to wall
//we need to do some different angle correction here cos GPISROTVEC
- if( VectorCompare( surfNormal, ceilingNormal ) )
+ if( VectorCompareEpsilon( surfNormal, ceilingNormal, eps ) )
{
vectoangles( trace.plane.normal, toAngles );
vectoangles( pm->ps->grapplePoint, surfAngles );
@@ -1931,11 +2087,11 @@ static void PM_GroundClimbTrace( void )
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 ) )
+ if( !VectorCompareEpsilon( trace.plane.normal, ceilingNormal, eps ) )
{
//so we know what surface we're stuck to
VectorCopy( trace.plane.normal, pm->ps->grapplePoint );
- pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBINGCEILING;
+ pm->ps->eFlags &= ~EF_WALLCLIMBCEILING;
}
//IMPORTANT: break out of the for loop if we've hit something
@@ -1958,7 +2114,7 @@ static void PM_GroundClimbTrace( void )
pm->ps->eFlags &= ~EF_WALLCLIMB;
//just transided from ceiling to floor... apply delta correction
- if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
+ if( pm->ps->eFlags & EF_WALLCLIMBCEILING )
{
vec3_t forward, rotated, angles;
@@ -1970,7 +2126,7 @@ static void PM_GroundClimbTrace( void )
pm->ps->delta_angles[ YAW ] -= ANGLE2SHORT( angles[ YAW ] - pm->ps->viewangles[ YAW ] );
}
- pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBINGCEILING;
+ pm->ps->eFlags &= ~EF_WALLCLIMBCEILING;
//we get very bizarre effects if we don't do this :0
VectorCopy( refNormal, pm->ps->grapplePoint );
@@ -1983,7 +2139,7 @@ static void PM_GroundClimbTrace( void )
// 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_flags &= ~PMF_TIME_WATERJUMP;
pm->ps->pm_time = 0;
}
@@ -1995,7 +2151,6 @@ static void PM_GroundClimbTrace( void )
PM_AddTouchEnt( trace.entityNum );
}
-
/*
=============
PM_GroundTrace
@@ -2004,11 +2159,10 @@ 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( BG_ClassHasAbility( pm->ps->stats[ STAT_CLASS ], SCA_WALLCLIMBER ) )
{
if( pm->ps->persistant[ PERS_STATE ] & PS_WALLCLIMBINGTOGGLE )
{
@@ -2043,7 +2197,7 @@ static void PM_GroundTrace( void )
}
//just transided from ceiling to floor... apply delta correction
- if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
+ if( pm->ps->eFlags & EF_WALLCLIMBCEILING )
{
vec3_t forward, rotated, angles;
@@ -2057,8 +2211,7 @@ static void PM_GroundTrace( void )
}
pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBING;
- pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBINGCEILING;
- pm->ps->eFlags &= ~EF_WALLCLIMB;
+ pm->ps->eFlags &= ~( EF_WALLCLIMB | EF_WALLCLIMBCEILING );
point[ 0 ] = pm->ps->origin[ 0 ];
point[ 1 ] = pm->ps->origin[ 1 ];
@@ -2105,38 +2258,6 @@ static void PM_GroundTrace( void )
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;
}
}
@@ -2193,7 +2314,7 @@ static void PM_GroundTrace( void )
// 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_flags &= ~PMF_TIME_WATERJUMP;
pm->ps->pm_time = 0;
}
@@ -2203,16 +2324,11 @@ static void PM_GroundTrace( void )
if( pm->debugLevel )
Com_Printf( "%i:Land\n", c_pmove );
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_TAKESFALLDAMAGE ) )
- PM_CrashLand( );
+ // communicate the fall velocity to the server
+ pm->pmext->fallVelocity = pml.previous_velocity[ 2 ];
- // 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;
- }
+ if( BG_ClassHasAbility( pm->ps->stats[ STAT_CLASS ], SCA_TAKESFALLDAMAGE ) )
+ PM_CrashLand( );
}
pm->ps->groundEntityNum = trace.entityNum;
@@ -2273,23 +2389,29 @@ static void PM_SetWaterLevel( void )
/*
==============
+PM_SetViewheight
+==============
+*/
+static void PM_SetViewheight( void )
+{
+ pm->ps->viewheight = ( pm->ps->pm_flags & PMF_DUCKED )
+ ? BG_ClassConfig( pm->ps->stats[ STAT_CLASS ] )->crouchViewheight
+ : BG_ClassConfig( pm->ps->stats[ STAT_CLASS ] )->viewheight;
+}
+
+/*
+==============
PM_CheckDuck
-Sets mins, maxs, and pm->ps->viewheight
+Sets mins and maxs, and calls PM_SetViewheight
==============
*/
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;
+ BG_ClassBoundingBox( pm->ps->stats[ STAT_CLASS ], PCmins, PCmaxs, PCcmaxs, NULL, NULL );
pm->mins[ 0 ] = PCmins[ 0 ];
pm->mins[ 1 ] = PCmins[ 1 ];
@@ -2302,14 +2424,13 @@ static void PM_CheckDuck (void)
if( pm->ps->pm_type == PM_DEAD )
{
pm->maxs[ 2 ] = -8;
- pm->ps->viewheight = DEAD_VIEWHEIGHT;
+ pm->ps->viewheight = PCmins[ 2 ] + 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 ) )
+ // If the standing and crouching bboxes are the same the class can't crouch
+ if( ( pm->cmd.upmove < 0 ) && !VectorCompare( PCmaxs, PCcmaxs ) &&
+ pm->ps->pm_type != PM_JETPACK )
{
// duck
pm->ps->pm_flags |= PMF_DUCKED;
@@ -2328,15 +2449,11 @@ static void PM_CheckDuck (void)
}
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_SetViewheight( );
}
@@ -2359,9 +2476,9 @@ static void PM_Footsteps( void )
// calculate speed and cycle to be used for
// all cyclic walking effects
//
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) && ( pml.groundPlane ) )
+ if( BG_ClassHasAbility( pm->ps->stats[ STAT_CLASS ], SCA_WALLCLIMBER ) && ( pml.groundPlane ) )
{
- //TA: FIXME: yes yes i know this is wrong
+ // 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 ] );
@@ -2519,7 +2636,7 @@ static void PM_Footsteps( void )
}
}
- bobmove *= BG_FindBobCycleForClass( pm->ps->stats[ STAT_PCLASS ] );
+ bobmove *= BG_Class( pm->ps->stats[ STAT_CLASS ] )->bobCycle;
if( pm->ps->stats[ STAT_STATE ] & SS_SPEEDBOOST )
bobmove *= HUMAN_SPRINT_MODIFIER;
@@ -2606,19 +2723,15 @@ static void PM_BeginWeaponChange( int weapon )
if( pm->ps->weaponstate == WEAPON_DROPPING )
return;
- //special case to prevent storing a charged up lcannon
- if( pm->ps->weapon == WP_LUCIFER_CANNON )
- pm->ps->stats[ STAT_MISC ] = 0;
-
// cancel a reload
pm->ps->pm_flags &= ~PMF_WEAPON_RELOAD;
if( pm->ps->weaponstate == WEAPON_RELOADING )
pm->ps->weaponTime = 0;
- // force this here to prevent flamer effect from continuing, among other issues
- pm->ps->generic1 = WPM_NOTFIRING;
+ //special case to prevent storing a charged up lcannon
+ if( pm->ps->weapon == WP_LUCIFER_CANNON )
+ pm->ps->stats[ STAT_MISC ] = 0;
- PM_AddEvent( EV_CHANGE_WEAPON );
pm->ps->weaponstate = WEAPON_DROPPING;
pm->ps->weaponTime += 200;
pm->ps->persistant[ PERS_NEWWEAPON ] = weapon;
@@ -2627,7 +2740,10 @@ static void PM_BeginWeaponChange( int weapon )
pm->ps->stats[ STAT_BUILDABLE ] = BA_NONE;
if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
+ {
PM_StartTorsoAnim( TORSO_DROP );
+ PM_StartWeaponAnim( WANIM_DROP );
+ }
}
@@ -2640,6 +2756,7 @@ static void PM_FinishWeaponChange( void )
{
int weapon;
+ PM_AddEvent( EV_CHANGE_WEAPON );
weapon = pm->ps->persistant[ PERS_NEWWEAPON ];
if( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS )
weapon = WP_NONE;
@@ -2652,7 +2769,10 @@ static void PM_FinishWeaponChange( void )
pm->ps->weaponTime += 250;
if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
+ {
PM_StartTorsoAnim( TORSO_RAISE );
+ PM_StartWeaponAnim( WANIM_RAISE );
+ }
}
@@ -2664,15 +2784,17 @@ 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 );
+ if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
+ {
+ if( pm->ps->weapon == WP_BLASTER )
+ PM_ContinueTorsoAnim( TORSO_STAND2 );
+ else
+ PM_ContinueTorsoAnim( TORSO_STAND );
+ }
+
+ PM_ContinueWeaponAnim( WANIM_IDLE );
}
}
@@ -2687,61 +2809,169 @@ 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;
+ qboolean attack1 = pm->cmd.buttons & BUTTON_ATTACK;
+ qboolean attack2 = pm->cmd.buttons & BUTTON_ATTACK2;
+ qboolean attack3 = pm->cmd.buttons & BUTTON_USE_HOLDABLE;
- // don't allow attack until all buttons are up
- if( pm->ps->pm_flags & PMF_RESPAWNED )
+ // Ignore weapons in some cases
+ if( pm->ps->persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
return;
- // ignore if spectator
- if( pm->ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR )
+ // Check for dead player
+ if( pm->ps->stats[ STAT_HEALTH ] <= 0 )
+ {
+ pm->ps->weapon = WP_NONE;
return;
+ }
- if( pm->ps->stats[ STAT_STATE ] & SS_INFESTING )
- return;
+ // Charging for a pounce or canceling a pounce
+ if( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG )
+ {
+ int max;
+
+ max = pm->ps->weapon == WP_ALEVEL3 ? LEVEL3_POUNCE_TIME :
+ LEVEL3_POUNCE_TIME_UPG;
+ if( pm->cmd.buttons & BUTTON_ATTACK2 )
+ pm->ps->stats[ STAT_MISC ] += pml.msec;
+ else
+ pm->ps->stats[ STAT_MISC ] -= pml.msec;
- if( pm->ps->stats[ STAT_STATE ] & SS_HOVELING )
- return;
+ if( pm->ps->stats[ STAT_MISC ] > max )
+ pm->ps->stats[ STAT_MISC ] = max;
+ else if( pm->ps->stats[ STAT_MISC ] < 0 )
+ pm->ps->stats[ STAT_MISC ] = 0;
+ }
- // check for dead player
- if( pm->ps->stats[ STAT_HEALTH ] <= 0 )
+ // Trample charge mechanics
+ if( pm->ps->weapon == WP_ALEVEL4 )
{
- pm->ps->weapon = WP_NONE;
+ // Charging up
+ if( !( pm->ps->stats[ STAT_STATE ] & SS_CHARGING ) )
+ {
+ // Charge button held
+ if( pm->ps->stats[ STAT_MISC ] < LEVEL4_TRAMPLE_CHARGE_TRIGGER &&
+ ( pm->cmd.buttons & BUTTON_ATTACK2 ) )
+ {
+ pm->ps->stats[ STAT_STATE ] &= ~SS_CHARGING;
+ if( pm->cmd.forwardmove > 0 )
+ {
+ int charge = pml.msec;
+ vec3_t dir,vel;
+
+ AngleVectors( pm->ps->viewangles, dir, NULL, NULL );
+ VectorCopy( pm->ps->velocity, vel );
+ vel[2] = 0;
+ dir[2] = 0;
+ VectorNormalize( vel );
+ VectorNormalize( dir );
+
+ charge *= DotProduct( dir, vel );
+
+ pm->ps->stats[ STAT_MISC ] += charge;
+ }
+ else
+ pm->ps->stats[ STAT_MISC ] = 0;
+ }
+
+ // Charge button released
+ else if( !( pm->ps->stats[ STAT_STATE ] & SS_CHARGING ) )
+ {
+ if( pm->ps->stats[ STAT_MISC ] > LEVEL4_TRAMPLE_CHARGE_MIN )
+ {
+ if( pm->ps->stats[ STAT_MISC ] > LEVEL4_TRAMPLE_CHARGE_MAX )
+ pm->ps->stats[ STAT_MISC ] = LEVEL4_TRAMPLE_CHARGE_MAX;
+ pm->ps->stats[ STAT_MISC ] = pm->ps->stats[ STAT_MISC ] *
+ LEVEL4_TRAMPLE_DURATION /
+ LEVEL4_TRAMPLE_CHARGE_MAX;
+ pm->ps->stats[ STAT_STATE ] |= SS_CHARGING;
+ PM_AddEvent( EV_LEV4_TRAMPLE_START );
+ }
+ else
+ pm->ps->stats[ STAT_MISC ] -= pml.msec;
+ }
+ }
+
+ // Discharging
+ else
+ {
+ if( pm->ps->stats[ STAT_MISC ] < LEVEL4_TRAMPLE_CHARGE_MIN )
+ pm->ps->stats[ STAT_MISC ] = 0;
+ else
+ pm->ps->stats[ STAT_MISC ] -= pml.msec;
+
+ // If the charger has stopped moving take a chunk of charge away
+ if( VectorLength( pm->ps->velocity ) < 64.0f || pm->cmd.rightmove )
+ pm->ps->stats[ STAT_MISC ] -= LEVEL4_TRAMPLE_STOP_PENALTY * pml.msec;
+ }
+
+ // Charge is over
+ if( pm->ps->stats[ STAT_MISC ] <= 0 || pm->cmd.forwardmove <= 0 )
+ {
+ pm->ps->stats[ STAT_MISC ] = 0;
+ pm->ps->stats[ STAT_STATE ] &= ~SS_CHARGING;
+ }
+ }
+
+ // Charging up a Lucifer Cannon
+ pm->ps->eFlags &= ~EF_WARN_CHARGE;
+
+ // don't allow attack until all buttons are up
+ if( pm->ps->pm_flags & PMF_RESPAWNED )
return;
+
+ if( pm->ps->weapon == WP_LUCIFER_CANNON )
+ {
+ // Charging up
+ if( !pm->ps->weaponTime &&
+ ( pm->cmd.buttons & BUTTON_ATTACK ) )
+ {
+ pm->ps->stats[ STAT_MISC ] += pml.msec;
+ if( pm->ps->stats[ STAT_MISC ] >= LCANNON_CHARGE_TIME_MAX )
+ pm->ps->stats[ STAT_MISC ] = LCANNON_CHARGE_TIME_MAX;
+ if( pm->ps->stats[ STAT_MISC ] > pm->ps->ammo * LCANNON_CHARGE_TIME_MAX /
+ LCANNON_CHARGE_AMMO )
+ pm->ps->stats[ STAT_MISC ] = pm->ps->ammo * LCANNON_CHARGE_TIME_MAX /
+ LCANNON_CHARGE_AMMO;
+ }
+
+ // Set overcharging flag so other players can hear the warning beep
+ if( pm->ps->stats[ STAT_MISC ] > LCANNON_CHARGE_TIME_WARN )
+ pm->ps->eFlags |= EF_WARN_CHARGE;
}
-
// no bite during pounce
- if( ( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG )
- && ( pm->cmd.buttons & BUTTON_ATTACK )
- && ( pm->ps->pm_flags & PMF_CHARGE ) )
- {
+ if( ( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG )
+ && ( pm->cmd.buttons & BUTTON_ATTACK )
+ && ( pm->ps->pm_flags & PMF_CHARGE ) )
return;
- }
+ // pump weapon delays (repeat times etc)
if( pm->ps->weaponTime > 0 )
pm->ps->weaponTime -= pml.msec;
+ if( pm->ps->weaponTime < 0 )
+ pm->ps->weaponTime = 0;
+
+ // no slash during charge
+ if( pm->ps->stats[ STAT_STATE ] & SS_CHARGING )
+ return;
// 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 )
+ if( BG_PlayerCanChangeWeapon( pm->ps ) )
{
- //TA: must press use to switch weapons
+ // 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( 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 )
+ else
{
//if trying to toggle an upgrade, toggle it
if( BG_InventoryContainsUpgrade( pm->cmd.weapon - 32, pm->ps->stats ) ) //sanity check
@@ -2762,7 +2992,16 @@ static void PM_Weapon( void )
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->weapon != WP_NONE )
+ {
+ // drop the current weapon
+ PM_BeginWeaponChange( pm->ps->persistant[ PERS_NEWWEAPON ] );
+ }
+ else
+ {
+ // no current weapon, so just raise the new one
+ PM_FinishWeaponChange( );
+ }
}
}
@@ -2776,10 +3015,10 @@ static void PM_Weapon( void )
return;
}
+ // Set proper animation
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 )
@@ -2788,19 +3027,21 @@ static void PM_Weapon( void )
PM_ContinueTorsoAnim( TORSO_STAND );
}
+ PM_ContinueWeaponAnim( WANIM_IDLE );
+
return;
}
- // start the animation even if out of ammo
- ammo = pm->ps->ammo;
- clips = pm->ps->clips;
- BG_FindAmmoForWeapon( pm->ps->weapon, NULL, &maxClips );
-
// check for out of ammo
- if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) )
+ if( !pm->ps->ammo && !pm->ps->clips && !BG_Weapon( pm->ps->weapon )->infiniteAmmo )
{
- PM_AddEvent( EV_NOAMMO );
- pm->ps->weaponTime += 200;
+ if( attack1 ||
+ ( BG_Weapon( pm->ps->weapon )->hasAltMode && attack2 ) ||
+ ( BG_Weapon( pm->ps->weapon )->hasThirdMode && attack3 ) )
+ {
+ PM_AddEvent( EV_NOAMMO );
+ pm->ps->weaponTime += 500;
+ }
if( pm->ps->weaponstate == WEAPON_FIRING )
pm->ps->weaponstate = WEAPON_READY;
@@ -2811,18 +3052,12 @@ static void PM_Weapon( void )
//done reloading so give em some ammo
if( pm->ps->weaponstate == WEAPON_RELOADING )
{
- if( maxClips > 0 )
- {
- clips--;
- BG_FindAmmoForWeapon( pm->ps->weapon, &ammo, NULL );
- }
+ pm->ps->clips--;
+ pm->ps->ammo = BG_Weapon( pm->ps->weapon )->maxAmmo;
- if( BG_FindUsesEnergyForWeapon( pm->ps->weapon ) &&
+ if( BG_Weapon( pm->ps->weapon )->usesEnergy &&
BG_InventoryContainsUpgrade( UP_BATTPACK, pm->ps->stats ) )
- ammo = (int)( (float)ammo * BATTPACK_MODIFIER );
-
- pm->ps->ammo = ammo;
- pm->ps->clips = clips;
+ pm->ps->ammo *= BATTPACK_MODIFIER;
//allow some time for the weapon to be raised
pm->ps->weaponstate = WEAPON_RAISING;
@@ -2832,19 +3067,18 @@ static void PM_Weapon( void )
}
// check for end of clip
- if( !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) &&
- ( !ammo || pm->ps->pm_flags & PMF_WEAPON_RELOAD ) && clips )
+ if( !BG_Weapon( pm->ps->weapon )->infiniteAmmo &&
+ ( pm->ps->ammo <= 0 || ( pm->ps->pm_flags & PMF_WEAPON_RELOAD ) ) &&
+ pm->ps->clips > 0 )
{
pm->ps->pm_flags &= ~PMF_WEAPON_RELOAD;
-
pm->ps->weaponstate = WEAPON_RELOADING;
//drop the weapon
PM_StartTorsoAnim( TORSO_DROP );
+ PM_StartWeaponAnim( WANIM_RELOAD );
- addTime = BG_FindReloadTimeForWeapon( pm->ps->weapon );
-
- pm->ps->weaponTime += addTime;
+ pm->ps->weaponTime += BG_Weapon( pm->ps->weapon )->reloadTime;
return;
}
@@ -2853,62 +3087,60 @@ static void PM_Weapon( void )
{
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;
+ return;
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;
+ // pounce is autohit
+ if( !attack1 && !attack2 && !attack3 )
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;
+ attack3 = qfalse;
- if( ( attack1 || pm->ps->stats[ STAT_MISC ] == 0 ) && !attack2 && !attack3 )
+ // Can't fire secondary while primary is charging
+ if( attack1 || pm->ps->stats[ STAT_MISC ] > 0 )
+ attack2 = qfalse;
+
+ if( ( attack1 || pm->ps->stats[ STAT_MISC ] == 0 ) && !attack2 )
{
- if( pm->ps->stats[ STAT_MISC ] < LCANNON_TOTAL_CHARGE )
+ pm->ps->weaponTime = 0;
+
+ // Charging
+ if( pm->ps->stats[ STAT_MISC ] < LCANNON_CHARGE_TIME_MAX )
{
- pm->ps->weaponTime = 0;
pm->ps->weaponstate = WEAPON_READY;
return;
}
- else
- attack1 = !attack1;
}
- //erp this looks confusing
- if( pm->ps->stats[ STAT_MISC ] > LCANNON_MIN_CHARGE )
- attack1 = !attack1;
+ if( pm->ps->stats[ STAT_MISC ] > LCANNON_CHARGE_TIME_MIN )
+ {
+ // Fire primary attack
+ attack1 = qtrue;
+ attack2 = qfalse;
+ }
else if( pm->ps->stats[ STAT_MISC ] > 0 )
{
+ // Not enough charge
pm->ps->stats[ STAT_MISC ] = 0;
pm->ps->weaponTime = 0;
pm->ps->weaponstate = WEAPON_READY;
return;
}
+ else if( !attack2 )
+ {
+ // Idle
+ pm->ps->weaponTime = 0;
+ pm->ps->weaponstate = WEAPON_READY;
+ return;
+ }
break;
case WP_MASS_DRIVER:
- attack1 = pm->cmd.buttons & BUTTON_ATTACK;
+ attack2 = attack3 = qfalse;
// attack2 is handled on the client for zooming (cg_view.c)
if( !attack1 )
@@ -2920,11 +3152,6 @@ static void PM_Weapon( void )
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;
@@ -2933,29 +3160,22 @@ static void PM_Weapon( void )
}
break;
}
-
- if ( pm->ps->weapon == WP_LUCIFER_CANNON && pm->ps->stats[ STAT_MISC ] > 0 && attack3 )
- {
- attack1 = qtrue;
- attack3 = qfalse;
- }
-
- //TA: fire events for non auto weapons
+
+ // fire events for non auto weapons
if( attack3 )
{
- if( BG_WeaponHasThirdMode( pm->ps->weapon ) )
+ if( BG_Weapon( pm->ps->weapon )->hasThirdMode )
{
//hacky special case for slowblob
- if( pm->ps->weapon == WP_ALEVEL3_UPG && !ammo )
+ if( pm->ps->weapon == WP_ALEVEL3_UPG && !pm->ps->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 );
+ addTime = BG_Weapon( pm->ps->weapon )->repeatRate3;
}
else
{
@@ -2967,11 +3187,11 @@ static void PM_Weapon( void )
}
else if( attack2 )
{
- if( BG_WeaponHasAltMode( pm->ps->weapon ) )
+ if( BG_Weapon( pm->ps->weapon )->hasAltMode )
{
pm->ps->generic1 = WPM_SECONDARY;
PM_AddEvent( EV_FIRE_WEAPON2 );
- addTime = BG_FindRepeatRate2ForWeapon( pm->ps->weapon );
+ addTime = BG_Weapon( pm->ps->weapon )->repeatRate2;
}
else
{
@@ -2985,10 +3205,10 @@ static void PM_Weapon( void )
{
pm->ps->generic1 = WPM_PRIMARY;
PM_AddEvent( EV_FIRE_WEAPON );
- addTime = BG_FindRepeatRate1ForWeapon( pm->ps->weapon );
+ addTime = BG_Weapon( pm->ps->weapon )->repeatRate1;
}
- //TA: fire events for autohit weapons
+ // fire events for autohit weapons
if( pm->autoWeaponHit[ pm->ps->weapon ] )
{
switch( pm->ps->weapon )
@@ -2996,14 +3216,14 @@ static void PM_Weapon( void )
case WP_ALEVEL0:
pm->ps->generic1 = WPM_PRIMARY;
PM_AddEvent( EV_FIRE_WEAPON );
- addTime = BG_FindRepeatRate1ForWeapon( pm->ps->weapon );
+ addTime = BG_Weapon( pm->ps->weapon )->repeatRate1;
break;
case WP_ALEVEL3:
case WP_ALEVEL3_UPG:
pm->ps->generic1 = WPM_SECONDARY;
PM_AddEvent( EV_FIRE_WEAPON2 );
- addTime = BG_FindRepeatRate2ForWeapon( pm->ps->weapon );
+ addTime = BG_Weapon( pm->ps->weapon )->repeatRate2;
break;
default:
@@ -3020,41 +3240,77 @@ static void PM_Weapon( void )
if( pm->ps->weaponstate == WEAPON_READY )
{
PM_StartTorsoAnim( TORSO_ATTACK );
+ PM_StartWeaponAnim( WANIM_ATTACK1 );
}
break;
case WP_BLASTER:
PM_StartTorsoAnim( TORSO_ATTACK2 );
+ PM_StartWeaponAnim( WANIM_ATTACK1 );
break;
default:
PM_StartTorsoAnim( TORSO_ATTACK );
+ PM_StartWeaponAnim( WANIM_ATTACK1 );
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;
+ int num = rand( );
- if( num == 0 )
- PM_ForceLegsAnim( NSPA_ATTACK1 );
- else if( num == 1 )
- PM_ForceLegsAnim( NSPA_ATTACK2 );
- else if( num == 2 )
- PM_ForceLegsAnim( NSPA_ATTACK3 );
- }
- else
+ //FIXME: it would be nice to have these hard coded policies in
+ // weapon.cfg
+ switch( pm->ps->weapon )
{
- if( attack1 )
- PM_ForceLegsAnim( NSPA_ATTACK1 );
- else if( attack2 )
- PM_ForceLegsAnim( NSPA_ATTACK2 );
- else if( attack3 )
- PM_ForceLegsAnim( NSPA_ATTACK3 );
+ case WP_ALEVEL1_UPG:
+ case WP_ALEVEL1:
+ if( attack1 )
+ {
+ num /= RAND_MAX / 6 + 1;
+ PM_ForceLegsAnim( NSPA_ATTACK1 );
+ PM_StartWeaponAnim( WANIM_ATTACK1 + num );
+ }
+ break;
+
+ case WP_ALEVEL2_UPG:
+ if( attack2 )
+ {
+ PM_ForceLegsAnim( NSPA_ATTACK2 );
+ PM_StartWeaponAnim( WANIM_ATTACK7 );
+ }
+ case WP_ALEVEL2:
+ if( attack1 )
+ {
+ num /= RAND_MAX / 6 + 1;
+ PM_ForceLegsAnim( NSPA_ATTACK1 );
+ PM_StartWeaponAnim( WANIM_ATTACK1 + num );
+ }
+ break;
+
+ case WP_ALEVEL4:
+ num /= RAND_MAX / 3 + 1;
+ PM_ForceLegsAnim( NSPA_ATTACK1 + num );
+ PM_StartWeaponAnim( WANIM_ATTACK1 + num );
+ break;
+
+ default:
+ if( attack1 )
+ {
+ PM_ForceLegsAnim( NSPA_ATTACK1 );
+ PM_StartWeaponAnim( WANIM_ATTACK1 );
+ }
+ else if( attack2 )
+ {
+ PM_ForceLegsAnim( NSPA_ATTACK2 );
+ PM_StartWeaponAnim( WANIM_ATTACK2 );
+ }
+ else if( attack3 )
+ {
+ PM_ForceLegsAnim( NSPA_ATTACK3 );
+ PM_StartWeaponAnim( WANIM_ATTACK3 );
+ }
+ break;
}
pm->ps->torsoTimer = TIMER_ATTACK;
@@ -3063,29 +3319,19 @@ static void PM_Weapon( void )
pm->ps->weaponstate = WEAPON_FIRING;
// take an ammo away if not infinite
- if( !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) )
+ if( !BG_Weapon( pm->ps->weapon )->infiniteAmmo ||
+ ( pm->ps->weapon == WP_ALEVEL3_UPG && attack3 ) )
{
- //special case for lCanon
+ // Special case for lcannon
if( pm->ps->weapon == WP_LUCIFER_CANNON && attack1 && !attack2 )
- {
- 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;
- }
+ pm->ps->ammo -= ( pm->ps->stats[ STAT_MISC ] * LCANNON_CHARGE_AMMO +
+ LCANNON_CHARGE_TIME_MAX - 1 ) / LCANNON_CHARGE_TIME_MAX;
else
- ammo--;
+ pm->ps->ammo--;
- pm->ps->ammo = ammo;
- pm->ps->clips = clips;
- }
- else if( pm->ps->weapon == WP_ALEVEL3_UPG && attack3 )
- {
- //special case for slowblob
- ammo--;
- pm->ps->ammo = ammo;
- pm->ps->clips = clips;
+ // Stay on the safe side
+ if( pm->ps->ammo < 0 )
+ pm->ps->ammo = 0;
}
//FIXME: predicted angles miss a problem??
@@ -3114,14 +3360,21 @@ PM_Animate
*/
static void PM_Animate( void )
{
+ if( PM_Paralyzed( pm->ps->pm_type ) )
+ return;
+
if( pm->cmd.buttons & BUTTON_GESTURE )
{
+ if( pm->ps->tauntTimer > 0 )
+ return;
+
if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
{
if( pm->ps->torsoTimer == 0 )
{
PM_StartTorsoAnim( TORSO_GESTURE );
pm->ps->torsoTimer = TIMER_GESTURE;
+ pm->ps->tauntTimer = TIMER_GESTURE;
PM_AddEvent( EV_TAUNT );
}
@@ -3132,6 +3385,7 @@ static void PM_Animate( void )
{
PM_ForceLegsAnim( NSPA_GESTURE );
pm->ps->torsoTimer = TIMER_GESTURE;
+ pm->ps->tauntTimer = TIMER_GESTURE;
PM_AddEvent( EV_TAUNT );
}
@@ -3175,6 +3429,16 @@ static void PM_DropTimers( void )
if( pm->ps->torsoTimer < 0 )
pm->ps->torsoTimer = 0;
}
+
+ if( pm->ps->tauntTimer > 0 )
+ {
+ pm->ps->tauntTimer -= pml.msec;
+
+ if( pm->ps->tauntTimer < 0 )
+ {
+ pm->ps->tauntTimer = 0;
+ }
+ }
}
@@ -3193,7 +3457,7 @@ void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd )
vec3_t axis[ 3 ], rotaxis[ 3 ];
vec3_t tempang;
- if( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION )
+ if( ps->pm_type == PM_INTERMISSION )
return; // no view changes at all
if( ps->pm_type != PM_SPECTATOR && ps->stats[ STAT_HEALTH ] <= 0 )
@@ -3202,7 +3466,21 @@ void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd )
// circularly clamp the angles with deltas
for( i = 0; i < 3; i++ )
{
- temp[ i ] = cmd->angles[ i ] + ps->delta_angles[ i ];
+ if( i == ROLL )
+ {
+ // Guard against speed hack
+ temp[ i ] = ps->delta_angles[ i ];
+
+#ifdef CGAME
+ // Assert here so that if cmd->angles[ i ] becomes non-zero
+ // for a legitimate reason we can tell where and why it's
+ // being ignored
+ assert( cmd->angles[ i ] == 0 );
+#endif
+
+ }
+ else
+ temp[ i ] = cmd->angles[ i ] + ps->delta_angles[ i ];
if( i == PITCH )
{
@@ -3226,7 +3504,7 @@ void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd )
if( !( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) ||
!BG_RotateAxis( ps->grapplePoint, axis, rotaxis, qfalse,
- ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) )
+ ps->eFlags & EF_WALLCLIMBCEILING ) )
AxisCopy( axis, rotaxis );
//convert the new axis back to angles
@@ -3238,7 +3516,7 @@ void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd )
while( tempang[ i ] > 180.0f )
tempang[ i ] -= 360.0f;
- while( tempang[ i ] < 180.0f )
+ while( tempang[ i ] < -180.0f )
tempang[ i ] += 360.0f;
}
@@ -3287,15 +3565,10 @@ void trap_SnapVector( float *v );
void PmoveSingle( pmove_t *pmove )
{
- int ammo, clips;
-
pm = pmove;
- ammo = pm->ps->ammo;
- clips = pm->ps->clips;
-
// this counter lets us debug movement problems with a journal
- // by setting a conditional breakpoint fot the previous frame
+ // by setting a conditional breakpoint for the previous frame
c_pmove++;
// clear results
@@ -3311,16 +3584,10 @@ void PmoveSingle( pmove_t *pmove )
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->ammo > 0 || pm->ps->clips > 0 ) || BG_Weapon( pm->ps->weapon )->infiniteAmmo ) )
pm->ps->eFlags |= EF_FIRING;
else
pm->ps->eFlags &= ~EF_FIRING;
@@ -3328,7 +3595,7 @@ void PmoveSingle( pmove_t *pmove )
// 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->ammo > 0 || pm->ps->clips > 0 ) || BG_Weapon( pm->ps->weapon )->infiniteAmmo ) )
pm->ps->eFlags |= EF_FIRING2;
else
pm->ps->eFlags &= ~EF_FIRING2;
@@ -3336,7 +3603,7 @@ void PmoveSingle( pmove_t *pmove )
// 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->ammo > 0 || pm->ps->clips > 0 ) || BG_Weapon( pm->ps->weapon )->infiniteAmmo ) )
pm->ps->eFlags |= EF_FIRING3;
else
pm->ps->eFlags &= ~EF_FIRING3;
@@ -3355,7 +3622,9 @@ void PmoveSingle( pmove_t *pmove )
pmove->cmd.buttons = BUTTON_TALK;
pmove->cmd.forwardmove = 0;
pmove->cmd.rightmove = 0;
- pmove->cmd.upmove = 0;
+
+ if( pmove->cmd.upmove > 0 )
+ pmove->cmd.upmove = 0;
}
// clear all pmove local vars
@@ -3393,7 +3662,7 @@ void PmoveSingle( pmove_t *pmove )
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 )
+ if( PM_Paralyzed( pm->ps->pm_type ) )
{
pm->cmd.forwardmove = 0;
pm->cmd.rightmove = 0;
@@ -3414,6 +3683,8 @@ void PmoveSingle( pmove_t *pmove )
{
PM_UpdateViewAngles( pm->ps, &pm->cmd );
PM_NoclipMove( );
+ PM_SetViewheight( );
+ PM_Weapon( );
PM_DropTimers( );
return;
}
@@ -3421,7 +3692,7 @@ void PmoveSingle( pmove_t *pmove )
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 )
+ if( pm->ps->pm_type == PM_INTERMISSION )
return; // no movement at all
// set watertype, and waterlevel
@@ -3443,6 +3714,7 @@ void PmoveSingle( pmove_t *pmove )
PM_DeadMove( );
PM_DropTimers( );
+ PM_CheckDodge( );
if( pm->ps->pm_type == PM_JETPACK )
PM_JetPackMove( );
@@ -3454,9 +3726,9 @@ void PmoveSingle( pmove_t *pmove )
PM_LadderMove( );
else if( pml.walking )
{
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) &&
+ if( BG_ClassHasAbility( pm->ps->stats[ STAT_CLASS ], SCA_WALLCLIMBER ) &&
( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) )
- PM_ClimbMove( ); //TA: walking on any surface
+ PM_ClimbMove( ); // walking on any surface
else
PM_WalkMove( ); // walking on ground
}
@@ -3467,7 +3739,7 @@ void PmoveSingle( pmove_t *pmove )
// 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 );
@@ -3530,11 +3802,7 @@ void Pmove( pmove_t *pmove )
msec = 66;
}
-
pmove->cmd.serverTime = pmove->ps->commandTime + msec;
PmoveSingle( pmove );
-
- if( pmove->ps->pm_flags & PMF_JUMP_HELD )
- pmove->cmd.upmove = 20;
}
}